package com.sequenceiq.cloudbreak.cloud.template.group; import static com.sequenceiq.cloudbreak.cloud.scheduler.PollGroup.CANCELLED; import static java.util.Arrays.asList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import com.google.common.collect.Ordering; import com.google.common.primitives.Ints; import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext; import com.sequenceiq.cloudbreak.cloud.context.CloudContext; import com.sequenceiq.cloudbreak.cloud.model.CloudResource; import com.sequenceiq.cloudbreak.cloud.model.CloudResourceStatus; import com.sequenceiq.cloudbreak.cloud.model.Group; import com.sequenceiq.cloudbreak.cloud.model.Network; import com.sequenceiq.cloudbreak.cloud.model.Platform; import com.sequenceiq.cloudbreak.cloud.model.Security; import com.sequenceiq.cloudbreak.cloud.notification.PersistenceNotifier; import com.sequenceiq.cloudbreak.cloud.scheduler.PollGroup; import com.sequenceiq.cloudbreak.cloud.scheduler.SyncPollingScheduler; import com.sequenceiq.cloudbreak.cloud.store.InMemoryStateStore; import com.sequenceiq.cloudbreak.cloud.task.PollTask; import com.sequenceiq.cloudbreak.cloud.template.GroupResourceBuilder; import com.sequenceiq.cloudbreak.cloud.template.NetworkResourceBuilder; import com.sequenceiq.cloudbreak.cloud.template.ResourceNotNeededException; import com.sequenceiq.cloudbreak.cloud.template.context.ResourceBuilderContext; import com.sequenceiq.cloudbreak.cloud.template.init.ResourceBuilders; import com.sequenceiq.cloudbreak.cloud.template.task.ResourcePollTaskFactory; import com.sequenceiq.cloudbreak.common.type.CommonStatus; import com.sequenceiq.cloudbreak.common.type.ResourceType; @Service public class GroupResourceService { private static final Logger LOGGER = LoggerFactory.getLogger(GroupResourceService.class); @Inject private ResourceBuilders resourceBuilders; @Inject private SyncPollingScheduler<List<CloudResourceStatus>> syncPollingScheduler; @Inject private ResourcePollTaskFactory statusCheckFactory; @Inject private PersistenceNotifier resourceNotifier; public List<CloudResourceStatus> buildResources(ResourceBuilderContext context, AuthenticatedContext auth, List<Group> groups, Network network, Security security) throws Exception { CloudContext cloudContext = auth.getCloudContext(); List<CloudResourceStatus> results = new ArrayList<>(); for (GroupResourceBuilder builder : resourceBuilders.group(cloudContext.getPlatform())) { PollGroup pollGroup = InMemoryStateStore.getStack(auth.getCloudContext().getId()); if (pollGroup != null && CANCELLED.equals(pollGroup)) { break; } for (Group group : getOrderedCopy(groups)) { try { CloudResource buildableResource = builder.create(context, auth, group, network); createResource(auth, buildableResource); CloudResource resource = builder.build(context, auth, group, network, group.getSecurity(), buildableResource); updateResource(auth, resource); PollTask<List<CloudResourceStatus>> task = statusCheckFactory.newPollResourceTask(builder, auth, asList(resource), context, true); List<CloudResourceStatus> pollerResult = syncPollingScheduler.schedule(task); context.addGroupResources(group.getName(), Arrays.asList(resource)); results.addAll(pollerResult); } catch (ResourceNotNeededException e) { LOGGER.warn("Skipping resource creation: {}", e.getMessage()); } } } return results; } public List<CloudResourceStatus> deleteResources(ResourceBuilderContext context, AuthenticatedContext auth, List<CloudResource> resources, Network network, boolean cancellable) throws Exception { CloudContext cloudContext = auth.getCloudContext(); List<CloudResourceStatus> results = new ArrayList<>(); List<GroupResourceBuilder> builderChain = resourceBuilders.group(cloudContext.getPlatform()); for (int i = builderChain.size() - 1; i >= 0; i--) { GroupResourceBuilder builder = builderChain.get(i); List<CloudResource> specificResources = getResources(resources, builder.resourceType()); for (CloudResource resource : specificResources) { if (resource.getStatus() == CommonStatus.CREATED) { CloudResource deletedResource = builder.delete(context, auth, resource, network); if (deletedResource != null) { PollTask<List<CloudResourceStatus>> task = statusCheckFactory.newPollResourceTask( builder, auth, asList(deletedResource), context, cancellable); List<CloudResourceStatus> pollerResult = syncPollingScheduler.schedule(task); results.addAll(pollerResult); } } resourceNotifier.notifyDeletion(resource, cloudContext); } } return results; } public List<CloudResourceStatus> update(ResourceBuilderContext context, AuthenticatedContext auth, Network network, Security security, List<CloudResource> groupResources) throws Exception { List<CloudResourceStatus> results = new ArrayList<>(); CloudContext cloudContext = auth.getCloudContext(); for (NetworkResourceBuilder builder : resourceBuilders.network(cloudContext.getPlatform())) { List<CloudResource> resources = getResources(groupResources, builder.resourceType()); for (CloudResource resource : resources) { CloudResourceStatus status = builder.update(context, auth, network, security, resource); if (status != null) { PollTask<List<CloudResourceStatus>> task = statusCheckFactory.newPollResourceTask( builder, auth, asList(status.getCloudResource()), context, true); List<CloudResourceStatus> pollerResult = syncPollingScheduler.schedule(task); results.addAll(pollerResult); } } } return results; } public List<CloudResource> getGroupResources(Platform platform, List<CloudResource> resources) { List<ResourceType> types = new ArrayList<>(); for (GroupResourceBuilder builder : resourceBuilders.group(platform)) { types.add(builder.resourceType()); } return getResources(resources, types); } protected CloudResource createResource(AuthenticatedContext auth, CloudResource buildableResource) throws Exception { if (buildableResource.isPersistent()) { resourceNotifier.notifyAllocation(buildableResource, auth.getCloudContext()); } return buildableResource; } protected CloudResource updateResource(AuthenticatedContext auth, CloudResource buildableResource) throws Exception { if (buildableResource.isPersistent()) { resourceNotifier.notifyUpdate(buildableResource, auth.getCloudContext()); } return buildableResource; } private List<CloudResource> getResources(List<CloudResource> resources, ResourceType type) { return getResources(resources, Arrays.asList(type)); } private List<CloudResource> getResources(List<CloudResource> resources, List<ResourceType> types) { List<CloudResource> filtered = new ArrayList<>(); for (CloudResource resource : resources) { if (types.contains(resource.getType())) { filtered.add(resource); } } return filtered; } private List<Group> getOrderedCopy(List<Group> groups) { Ordering<Group> byLengthOrdering = new Ordering<Group>() { public int compare(Group left, Group right) { return Ints.compare(left.getInstancesSize(), right.getInstancesSize()); } }; return byLengthOrdering.sortedCopy(groups); } }