package com.sequenceiq.cloudbreak.cloud.template; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.inject.Inject; import com.sequenceiq.cloudbreak.api.model.AdjustmentType; import com.sequenceiq.cloudbreak.cloud.ResourceConnector; import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext; import com.sequenceiq.cloudbreak.cloud.context.CloudContext; import com.sequenceiq.cloudbreak.cloud.model.CloudInstance; import com.sequenceiq.cloudbreak.cloud.model.CloudResource; import com.sequenceiq.cloudbreak.cloud.model.CloudResourceStatus; import com.sequenceiq.cloudbreak.cloud.model.CloudStack; import com.sequenceiq.cloudbreak.cloud.model.Group; import com.sequenceiq.cloudbreak.cloud.model.InstanceStatus; import com.sequenceiq.cloudbreak.cloud.model.InstanceTemplate; import com.sequenceiq.cloudbreak.cloud.model.Platform; import com.sequenceiq.cloudbreak.cloud.notification.PersistenceNotifier; import com.sequenceiq.cloudbreak.cloud.template.compute.ComputeResourceService; import com.sequenceiq.cloudbreak.cloud.template.context.ResourceBuilderContext; import com.sequenceiq.cloudbreak.cloud.template.group.GroupResourceService; import com.sequenceiq.cloudbreak.cloud.template.init.ContextBuilders; import com.sequenceiq.cloudbreak.cloud.template.network.NetworkResourceService; /** * Abstract base implementation of {@link ResourceConnector} for cloud provider which do not have template based deployments. It provides the * functionality to call the resource builders in order starting from the {@link NetworkResourceBuilder} and continueing with the * {@link ComputeResourceBuilder}. Before calling any resource builder it constructs a generic {@link ResourceBuilderContext}. This context object * will be extended with the created resources as the builder finish creating them. The resources are grouped by private id. * <p/> * Compute resource can be rolled back based on the different failure policies configured. Network resource failure immediately results in a failing deployment. */ public abstract class AbstractResourceConnector implements ResourceConnector<List<CloudResource>> { @Inject private NetworkResourceService networkResourceService; @Inject private GroupResourceService groupResourceService; @Inject private ComputeResourceService computeResourceService; @Inject private ContextBuilders contextBuilders; @Override public List<CloudResourceStatus> launch(AuthenticatedContext auth, CloudStack stack, PersistenceNotifier notifier, AdjustmentType adjustmentType, Long threshold) throws Exception { CloudContext cloudContext = auth.getCloudContext(); Platform platform = cloudContext.getPlatform(); //context ResourceBuilderContext context = contextBuilders.get(platform).contextInit(cloudContext, auth, stack.getNetwork(), null, true); //network List<CloudResourceStatus> networkStatuses = networkResourceService.buildResources(context, auth, stack.getNetwork(), stack.getCloudSecurity()); context.addNetworkResources(getCloudResources(networkStatuses)); //group List<CloudResourceStatus> groupStatuses = groupResourceService.buildResources(context, auth, stack.getGroups(), stack.getNetwork(), stack.getCloudSecurity()); networkStatuses.addAll(groupStatuses); //compute List<CloudResourceStatus> computeStatuses = computeResourceService.buildResourcesForLaunch(context, auth, stack.getGroups(), stack.getImage(), stack.getTags(), adjustmentType, threshold); networkStatuses.addAll(computeStatuses); return networkStatuses; } @Override public List<CloudResourceStatus> terminate(AuthenticatedContext auth, CloudStack stack, List<CloudResource> cloudResources) throws Exception { CloudContext cloudContext = auth.getCloudContext(); Platform platform = cloudContext.getPlatform(); //context ResourceBuilderContext context = contextBuilders.get(platform).contextInit(cloudContext, auth, stack.getNetwork(), cloudResources, false); //compute List<CloudResourceStatus> computeStatuses = computeResourceService.deleteResources(context, auth, cloudResources, false); //group List<CloudResourceStatus> groupStatuses = groupResourceService.deleteResources(context, auth, cloudResources, stack.getNetwork(), false); computeStatuses.addAll(groupStatuses); //network List<CloudResourceStatus> networkStatuses = networkResourceService.deleteResources(context, auth, cloudResources, stack.getNetwork(), false); computeStatuses.addAll(networkStatuses); return computeStatuses; } @Override public List<CloudResourceStatus> upscale(AuthenticatedContext auth, CloudStack stack, List<CloudResource> resources) throws Exception { CloudContext cloudContext = auth.getCloudContext(); Platform platform = cloudContext.getPlatform(); //context ResourceBuilderContext context = contextBuilders.get(platform).contextInit(cloudContext, auth, stack.getNetwork(), resources, true); //network context.addNetworkResources(networkResourceService.getNetworkResources(platform, resources)); Group scalingGroup = getScalingGroup(getGroup(stack.getGroups(), getGroupName(stack))); //group context.addGroupResources(scalingGroup.getName(), groupResourceService.getGroupResources(platform, resources)); //compute return computeResourceService.buildResourcesForUpscale(context, auth, Collections.singletonList(scalingGroup), stack.getImage(), stack.getTags()); } @Override public List<CloudResource> collectResourcesToRemove(AuthenticatedContext authenticatedContext, CloudStack stack, List<CloudResource> resources, List<CloudInstance> vms) { return getDeleteResources(resources, vms); } @Override public List<CloudResourceStatus> downscale(AuthenticatedContext auth, CloudStack stack, List<CloudResource> resources, List<CloudInstance> vms, List<CloudResource> resourcesToRemove) { CloudContext cloudContext = auth.getCloudContext(); Platform platform = cloudContext.getPlatform(); //context ResourceBuilderContext context = contextBuilders.get(platform).contextInit(cloudContext, auth, stack.getNetwork(), resources, false); //compute return computeResourceService.deleteResources(context, auth, resourcesToRemove, true); } @Override public List<CloudResourceStatus> update(AuthenticatedContext auth, CloudStack stack, List<CloudResource> resources) throws Exception { CloudContext cloudContext = auth.getCloudContext(); Platform platform = cloudContext.getPlatform(); //context ResourceBuilderContext context = contextBuilders.get(platform).contextInit(cloudContext, auth, stack.getNetwork(), resources, true); //group List<CloudResource> groupResources = groupResourceService.getGroupResources(platform, resources); List<CloudResourceStatus> groupStatuses = groupResourceService.update(context, auth, stack.getNetwork(), stack.getCloudSecurity(), groupResources); //network List<CloudResource> networkResources = networkResourceService.getNetworkResources(platform, resources); List<CloudResourceStatus> networkStatuses = networkResourceService.update(context, auth, stack.getNetwork(), stack.getCloudSecurity(), networkResources); groupStatuses.addAll(networkStatuses); return groupStatuses; } @Override public List<CloudResourceStatus> check(AuthenticatedContext authenticatedContext, List<CloudResource> resources) { throw new UnsupportedOperationException(); } private List<CloudResource> getCloudResources(List<CloudResourceStatus> resourceStatuses) { List<CloudResource> resources = new ArrayList<>(); for (CloudResourceStatus status : resourceStatuses) { resources.add(status.getCloudResource()); } return resources; } private Group getScalingGroup(Group scalingGroup) { List<CloudInstance> instances = new ArrayList<>(scalingGroup.getInstances()); Iterator<CloudInstance> iterator = instances.iterator(); while (iterator.hasNext()) { if (InstanceStatus.CREATE_REQUESTED != iterator.next().getTemplate().getStatus()) { iterator.remove(); } } return new Group(scalingGroup.getName(), scalingGroup.getType(), instances, scalingGroup.getSecurity(), null); } private Group getGroup(List<Group> groups, String groupName) { Group resultGroup = null; for (Group group : groups) { if (groupName.equalsIgnoreCase(group.getName())) { resultGroup = group; break; } } return resultGroup; } private String getGroupName(CloudStack stack) { for (Group group : stack.getGroups()) { for (CloudInstance instance : group.getInstances()) { InstanceTemplate instanceTemplate = instance.getTemplate(); if (InstanceStatus.CREATE_REQUESTED == instanceTemplate.getStatus()) { return instanceTemplate.getGroupName(); } } } return null; } private List<CloudResource> getDeleteResources(List<CloudResource> resources, List<CloudInstance> instances) { List<CloudResource> result = new ArrayList<>(); for (CloudInstance instance : instances) { String instanceId = instance.getInstanceId(); for (CloudResource resource : resources) { if (instanceId.equalsIgnoreCase(resource.getName())) { result.add(resource); } } } return result; } }