package com.sequenceiq.cloudbreak.cloud.gcp; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.inject.Inject; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.services.compute.model.Operation; import com.sequenceiq.cloudbreak.cloud.CloudPlatformAware; import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext; import com.sequenceiq.cloudbreak.cloud.context.CloudContext; import com.sequenceiq.cloudbreak.cloud.exception.CloudConnectorException; import com.sequenceiq.cloudbreak.cloud.gcp.context.GcpContext; import com.sequenceiq.cloudbreak.cloud.gcp.service.GcpResourceNameService; import com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil; 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.Location; import com.sequenceiq.cloudbreak.cloud.model.Platform; import com.sequenceiq.cloudbreak.cloud.model.ResourceStatus; import com.sequenceiq.cloudbreak.cloud.model.Variant; import com.sequenceiq.cloudbreak.cloud.model.generic.DynamicModel; import com.sequenceiq.cloudbreak.common.type.ResourceType; public abstract class AbstractGcpResourceBuilder implements CloudPlatformAware { protected static final String OPERATION_ID = "opid"; private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGcpResourceBuilder.class); @Inject private GcpResourceNameService resourceNameService; @Override public Platform platform() { return GcpConstants.GCP_PLATFORM; } @Override public Variant variant() { return GcpConstants.GCP_VARIANT; } public GcpResourceNameService getResourceNameService() { return resourceNameService; } protected List<CloudResourceStatus> checkResources(ResourceType type, GcpContext context, AuthenticatedContext auth, List<CloudResource> resources) { List<CloudResourceStatus> result = new ArrayList<>(); for (CloudResource resource : resources) { LOGGER.info("Check {} resource: {}", type, resource); try { Operation operation = check(context, resource); boolean finished = operation == null || GcpStackUtil.analyzeOperation(operation); ResourceStatus successStatus = context.isBuild() ? ResourceStatus.CREATED : ResourceStatus.DELETED; result.add(new CloudResourceStatus(resource, finished ? successStatus : ResourceStatus.IN_PROGRESS)); if (finished) { if (successStatus == ResourceStatus.CREATED) { LOGGER.info("Creation of {} was successful", resource); } else { LOGGER.info("Deletion of {} was successful", resource); } } } catch (Exception e) { CloudContext cloudContext = auth.getCloudContext(); throw new GcpResourceException("Error during status check", type, cloudContext.getName(), cloudContext.getId(), resource.getName(), e); } } return result; } protected Operation check(GcpContext context, DynamicModel resource) throws IOException { String operation = resource.getStringParameter(OPERATION_ID); if (operation == null) { return null; } try { Operation execute = GcpStackUtil.globalOperations(context.getCompute(), context.getProjectId(), operation).execute(); checkError(execute); return execute; } catch (GoogleJsonResponseException e) { if (e.getDetails().get("code").equals(HttpStatus.SC_NOT_FOUND)) { Location location = context.getLocation(); try { Operation execute = GcpStackUtil.regionOperations(context.getCompute(), context.getProjectId(), operation, location.getRegion()).execute(); checkError(execute); return execute; } catch (GoogleJsonResponseException e1) { if (e1.getDetails().get("code").equals(HttpStatus.SC_NOT_FOUND)) { Operation execute = GcpStackUtil.zoneOperations(context.getCompute(), context.getProjectId(), operation, location.getAvailabilityZone()).execute(); checkError(execute); return execute; } else { throw e1; } } } else { throw e; } } } protected void checkError(Operation execute) { if (execute.getError() != null) { String msg = null; StringBuilder error = new StringBuilder(); if (execute.getError().getErrors() != null) { for (Operation.Error.Errors errors : execute.getError().getErrors()) { error.append(String.format("code: %s -> message: %s %s", errors.getCode(), errors.getMessage(), System.lineSeparator())); } msg = error.toString(); } throw new CloudConnectorException(msg); } } protected String checkException(GoogleJsonResponseException execute) { return execute.getDetails().getMessage(); } protected CloudResource createNamedResource(ResourceType type, String name) { return new CloudResource.Builder().type(type).name(name).build(); } protected CloudResource createOperationAwareCloudResource(CloudResource resource, Operation operation) { return new CloudResource.Builder() .cloudResource(resource) .params(Collections.singletonMap(OPERATION_ID, operation.getName())) .persistent(false) .build(); } protected CloudInstance createOperationAwareCloudInstance(CloudInstance instance, Operation operation) { return new CloudInstance(instance.getInstanceId(), instance.getTemplate(), Collections.singletonMap(OPERATION_ID, operation.getName())); } protected void exceptionHandler(GoogleJsonResponseException ex, String name, ResourceType resourceType) { if (ex.getDetails().get("code").equals(HttpStatus.SC_NOT_FOUND)) { LOGGER.info("Resource {} not found: {}", resourceType, name); } else { throw new GcpResourceException(ex.getDetails().getMessage(), ex); } } }