package com.sequenceiq.cloudbreak.service.blueprint;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
import com.sequenceiq.ambari.client.AmbariClient;
import com.sequenceiq.cloudbreak.common.type.APIResourceType;
import com.sequenceiq.cloudbreak.common.type.CbUserRole;
import com.sequenceiq.cloudbreak.common.type.ResourceStatus;
import com.sequenceiq.cloudbreak.controller.BadRequestException;
import com.sequenceiq.cloudbreak.controller.NotFoundException;
import com.sequenceiq.cloudbreak.domain.Blueprint;
import com.sequenceiq.cloudbreak.domain.CbUser;
import com.sequenceiq.cloudbreak.repository.BlueprintRepository;
import com.sequenceiq.cloudbreak.repository.ClusterRepository;
import com.sequenceiq.cloudbreak.service.DuplicateKeyValueException;
import com.sequenceiq.cloudbreak.util.NameUtil;
@Service
@Transactional
public class BlueprintService {
private static final Logger LOGGER = LoggerFactory.getLogger(BlueprintService.class);
@Inject
private BlueprintRepository blueprintRepository;
@Inject
private ClusterRepository clusterRepository;
public Set<Blueprint> retrievePrivateBlueprints(CbUser user) {
return blueprintRepository.findForUser(user.getUserId());
}
public Set<Blueprint> retrieveAccountBlueprints(CbUser user) {
if (user.getRoles().contains(CbUserRole.ADMIN)) {
return blueprintRepository.findAllInAccount(user.getAccount());
} else {
return blueprintRepository.findPublicInAccountForUser(user.getUserId(), user.getAccount());
}
}
@PostAuthorize("hasPermission(returnObject,'read')")
public Blueprint get(Long id) {
Blueprint blueprint = blueprintRepository.findOne(id);
if (blueprint == null) {
throw new NotFoundException(String.format("Blueprint '%s' not found.", id));
}
return blueprint;
}
@PostAuthorize("hasPermission(returnObject,'read')")
public Blueprint getByName(String name, CbUser user) {
Blueprint blueprint = blueprintRepository.findByNameInAccount(name, user.getAccount(), user.getUsername());
if (blueprint == null) {
throw new NotFoundException(String.format("Blueprint '%s' not found.", name));
}
return blueprint;
}
@Transactional(Transactional.TxType.NEVER)
public Blueprint create(CbUser user, Blueprint blueprint, List<Map<String, Map<String, String>>> properties) {
LOGGER.debug("Creating blueprint: [User: '{}', Account: '{}']", user.getUsername(), user.getAccount());
Blueprint savedBlueprint;
blueprint.setOwner(user.getUserId());
blueprint.setAccount(user.getAccount());
if (properties != null && properties.size() != 0) {
LOGGER.info("Extend blueprint with the following properties: {}", properties);
Map<String, Map<String, String>> configs = new HashMap<>();
for (Map<String, Map<String, String>> property : properties) {
for (String key : property.keySet()) {
Map<String, String> configValues = configs.get(key);
if (configValues != null) {
configValues.putAll(property.get(key));
} else {
configs.put(key, property.get(key));
}
}
}
String extendedBlueprint = new AmbariClient().extendBlueprintGlobalConfiguration(blueprint.getBlueprintText(), configs);
LOGGER.info("Extended blueprint result: {}", extendedBlueprint);
blueprint.setBlueprintText(extendedBlueprint);
}
try {
savedBlueprint = blueprintRepository.save(blueprint);
} catch (DataIntegrityViolationException ex) {
throw new DuplicateKeyValueException(APIResourceType.BLUEPRINT, blueprint.getName(), ex);
}
return savedBlueprint;
}
public void delete(Long id, CbUser user) {
Blueprint blueprint = blueprintRepository.findByIdInAccount(id, user.getAccount());
if (blueprint == null) {
throw new NotFoundException(String.format("Blueprint '%s' not found.", id));
}
delete(blueprint, user);
}
public Blueprint getPublicBlueprint(String name, CbUser user) {
Blueprint blueprint = blueprintRepository.findOneByName(name, user.getAccount());
if (blueprint == null) {
throw new NotFoundException(String.format("Blueprint '%s' not found.", name));
}
return blueprint;
}
public Blueprint getPrivateBlueprint(String name, CbUser user) {
Blueprint blueprint = blueprintRepository.findByNameInUser(name, user.getUserId());
if (blueprint == null) {
throw new NotFoundException(String.format("Blueprint '%s' not found.", name));
}
return blueprint;
}
public void delete(String name, CbUser user) {
Blueprint blueprint = blueprintRepository.findByNameInAccount(name, user.getAccount(), user.getUserId());
if (blueprint == null) {
throw new NotFoundException(String.format("Blueprint '%s' not found.", name));
}
delete(blueprint, user);
}
@Transactional(Transactional.TxType.NEVER)
public Iterable<Blueprint> save(Iterable<Blueprint> entities) {
return blueprintRepository.save(entities);
}
private void delete(Blueprint blueprint, CbUser user) {
if (clusterRepository.findAllClustersByBlueprint(blueprint.getId()).isEmpty()) {
if (!user.getUserId().equals(blueprint.getOwner()) && !user.getRoles().contains(CbUserRole.ADMIN)) {
throw new BadRequestException("Blueprints can only be deleted by account admins or owners.");
}
if (ResourceStatus.USER_MANAGED.equals(blueprint.getStatus())) {
blueprintRepository.delete(blueprint);
} else {
blueprint.setName(NameUtil.postfixWithTimestamp(blueprint.getName()));
blueprint.setStatus(ResourceStatus.DEFAULT_DELETED);
blueprintRepository.save(blueprint);
}
} else {
throw new BadRequestException(String.format(
"There are clusters associated with blueprint '%s'. Please remove these before deleting the blueprint.", blueprint.getId()));
}
}
}