package com.sequenceiq.cloudbreak.cloud.template.compute;
import static com.sequenceiq.cloudbreak.cloud.scheduler.PollGroup.CANCELLED;
import static java.lang.String.format;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext;
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.Image;
import com.sequenceiq.cloudbreak.cloud.model.ResourceStatus;
import com.sequenceiq.cloudbreak.cloud.notification.PersistenceNotifier;
import com.sequenceiq.cloudbreak.cloud.scheduler.CancellationException;
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.ComputeResourceBuilder;
import com.sequenceiq.cloudbreak.cloud.template.context.ResourceBuilderContext;
import com.sequenceiq.cloudbreak.cloud.template.init.ResourceBuilders;
import com.sequenceiq.cloudbreak.cloud.template.task.ResourcePollTaskFactory;
@Component(ResourceCreateThread.NAME)
@Scope(value = "prototype")
public class ResourceCreateThread implements Callable<ResourceRequestResult<List<CloudResourceStatus>>> {
public static final String NAME = "resourceCreateThread";
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceCreateThread.class);
@Inject
private ResourceBuilders resourceBuilders;
@Inject
private SyncPollingScheduler<List<CloudResourceStatus>> syncPollingScheduler;
@Inject
private ResourcePollTaskFactory resourcePollTaskFactory;
@Inject
private PersistenceNotifier resourceNotifier;
private final long privateId;
private final Group group;
private final ResourceBuilderContext context;
private final AuthenticatedContext auth;
private final Image image;
private final Map<String, String> tags;
public ResourceCreateThread(long privateId, Group group, ResourceBuilderContext context, AuthenticatedContext auth, Image image,
Map<String, String> tags) {
this.privateId = privateId;
this.group = group;
this.context = context;
this.auth = auth;
this.image = image;
this.tags = tags;
}
@Override
public ResourceRequestResult<List<CloudResourceStatus>> call() throws Exception {
List<CloudResourceStatus> results = new ArrayList<>();
List<CloudResource> buildableResources = new ArrayList<>();
try {
for (ComputeResourceBuilder builder : resourceBuilders.compute(auth.getCloudContext().getPlatform())) {
LOGGER.info("Building {} resources of {} instance group", builder.resourceType(), group.getName());
List<CloudResource> list = builder.create(context, privateId, auth, group, image);
if (!list.isEmpty()) {
buildableResources.addAll(list);
createResource(auth, list);
PollGroup pollGroup = InMemoryStateStore.getStack(auth.getCloudContext().getId());
if (pollGroup != null && CANCELLED.equals(pollGroup)) {
throw new CancellationException(format("Building of %s has been cancelled", list));
}
List<CloudResource> resources = builder.build(context, privateId, auth, group, image, list, tags);
updateResource(auth, resources);
context.addComputeResources(privateId, resources);
PollTask<List<CloudResourceStatus>> task = resourcePollTaskFactory.newPollResourceTask(builder, auth, resources, context, true);
List<CloudResourceStatus> pollerResult = syncPollingScheduler.schedule(task);
for (CloudResourceStatus resourceStatus : pollerResult) {
resourceStatus.setPrivateId(privateId);
}
results.addAll(pollerResult);
}
}
} catch (CancellationException e) {
throw e;
} catch (Exception e) {
LOGGER.error("", e);
results.clear();
for (CloudResource buildableResource : buildableResources) {
results.add(new CloudResourceStatus(buildableResource, ResourceStatus.FAILED, e.getMessage(), privateId));
}
return new ResourceRequestResult<>(FutureResult.FAILED, results);
}
return new ResourceRequestResult<>(FutureResult.SUCCESS, results);
}
private List<CloudResource> createResource(AuthenticatedContext auth, List<CloudResource> cloudResources) {
for (CloudResource cloudResource : cloudResources) {
if (cloudResource.isPersistent()) {
resourceNotifier.notifyAllocation(cloudResource, auth.getCloudContext());
}
}
return cloudResources;
}
private List<CloudResource> updateResource(AuthenticatedContext auth, List<CloudResource> cloudResources) {
for (CloudResource cloudResource : cloudResources) {
if (cloudResource.isPersistent()) {
resourceNotifier.notifyUpdate(cloudResource, auth.getCloudContext());
}
}
return cloudResources;
}
}