package com.sequenceiq.cloudbreak.cloud.gcp;
import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.buildCompute;
import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.buildStorage;
import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.getBucket;
import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.getImageName;
import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.getProjectId;
import static com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil.getTarName;
import java.io.IOException;
import javax.inject.Inject;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.model.Image;
import com.google.api.services.compute.model.ImageList;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.model.Bucket;
import com.google.api.services.storage.model.StorageObject;
import com.sequenceiq.cloudbreak.cloud.Setup;
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.model.CloudCredential;
import com.sequenceiq.cloudbreak.cloud.model.CloudStack;
import com.sequenceiq.cloudbreak.cloud.model.FileSystem;
import com.sequenceiq.cloudbreak.cloud.notification.PersistenceNotifier;
import com.sequenceiq.cloudbreak.cloud.scheduler.SyncPollingScheduler;
import com.sequenceiq.cloudbreak.common.type.ImageStatus;
import com.sequenceiq.cloudbreak.common.type.ImageStatusResult;
@Service
public class GcpProvisionSetup implements Setup {
private static final Logger LOGGER = LoggerFactory.getLogger(GcpProvisionSetup.class);
private static final String READY = "READY";
@Inject
private SyncPollingScheduler<Boolean> syncPollingScheduler;
@Override
public void prepareImage(AuthenticatedContext authenticatedContext, CloudStack stack, com.sequenceiq.cloudbreak.cloud.model.Image image) {
CloudCredential credential = authenticatedContext.getCloudCredential();
CloudContext cloudContext = authenticatedContext.getCloudContext();
try {
String projectId = getProjectId(credential);
String imageName = image.getImageName();
Compute compute = buildCompute(credential);
ImageList list = compute.images().list(projectId).execute();
if (!containsSpecificImage(list, imageName)) {
Storage storage = buildStorage(credential, cloudContext.getName());
Bucket bucket = new Bucket();
bucket.setName(String.format("%s-%s-%d", projectId, cloudContext.getName(), cloudContext.getId()));
bucket.setStorageClass("STANDARD");
try {
Storage.Buckets.Insert ins = storage.buckets().insert(projectId, bucket);
ins.execute();
} catch (GoogleJsonResponseException ex) {
if (ex.getStatusCode() != HttpStatus.SC_CONFLICT) {
throw ex;
}
}
String tarName = getTarName(imageName);
Storage.Objects.Copy copy = storage.objects().copy(getBucket(imageName), tarName, bucket.getName(), tarName, new StorageObject());
copy.execute();
Image gcpApiImage = new Image();
gcpApiImage.setName(getImageName(imageName));
Image.RawDisk rawDisk = new Image.RawDisk();
rawDisk.setSource(String.format("http://storage.googleapis.com/%s/%s", bucket.getName(), tarName));
gcpApiImage.setRawDisk(rawDisk);
Compute.Images.Insert ins = compute.images().insert(projectId, gcpApiImage);
ins.execute();
}
} catch (Exception e) {
Long stackId = cloudContext.getId();
String msg = String.format("Error occurred on %s stack during the setup: %s", stackId, e.getMessage());
LOGGER.error(msg, e);
throw new CloudConnectorException(msg, e);
}
}
@Override
public ImageStatusResult checkImageStatus(AuthenticatedContext authenticatedContext, CloudStack stack, com.sequenceiq.cloudbreak.cloud.model.Image image) {
CloudCredential credential = authenticatedContext.getCloudCredential();
String projectId = getProjectId(credential);
String imageName = image.getImageName();
try {
Image gcpApiImage = new Image();
gcpApiImage.setName(getImageName(imageName));
Compute compute = buildCompute(credential);
Compute.Images.Get getImages = compute.images().get(projectId, gcpApiImage.getName());
String status = getImages.execute().getStatus();
LOGGER.info("Status of image {} copy: {}", gcpApiImage.getName(), status);
if (READY.equals(status)) {
return new ImageStatusResult(ImageStatus.CREATE_FINISHED, ImageStatusResult.COMPLETED);
}
} catch (IOException e) {
LOGGER.warn("Failed to retrieve image copy status", e);
return new ImageStatusResult(ImageStatus.CREATE_FAILED, 0);
}
return new ImageStatusResult(ImageStatus.IN_PROGRESS, ImageStatusResult.HALF);
}
@Override
public void prerequisites(AuthenticatedContext authenticatedContext, CloudStack stack, PersistenceNotifier persistenceNotifier) {
LOGGER.debug("setup has been executed");
}
@Override
public void validateFileSystem(CloudCredential credential, FileSystem fileSystem) throws Exception {
}
private boolean containsSpecificImage(ImageList imageList, String imageUrl) {
try {
for (Image image : imageList.getItems()) {
if (image.getName().equals(getImageName(imageUrl))) {
return true;
}
}
} catch (NullPointerException ex) {
return false;
}
return false;
}
}