package com.sequenceiq.cloudbreak.cloud.gcp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.model.AccessConfig;
import com.google.api.services.compute.model.Instance;
import com.sequenceiq.cloudbreak.cloud.MetadataCollector;
import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext;
import com.sequenceiq.cloudbreak.cloud.context.CloudContext;
import com.sequenceiq.cloudbreak.cloud.gcp.util.GcpStackUtil;
import com.sequenceiq.cloudbreak.cloud.model.CloudCredential;
import com.sequenceiq.cloudbreak.cloud.model.CloudInstance;
import com.sequenceiq.cloudbreak.cloud.model.CloudInstanceMetaData;
import com.sequenceiq.cloudbreak.cloud.model.CloudResource;
import com.sequenceiq.cloudbreak.cloud.model.CloudVmInstanceStatus;
import com.sequenceiq.cloudbreak.cloud.model.CloudVmMetaDataStatus;
import com.sequenceiq.cloudbreak.cloud.model.InstanceStatus;
import com.sequenceiq.cloudbreak.common.type.ResourceType;
@Service
public class GcpMetadataCollector implements MetadataCollector {
private static final Logger LOGGER = LoggerFactory.getLogger(GcpMetadataCollector.class);
@Override
public List<CloudVmMetaDataStatus> collect(AuthenticatedContext authenticatedContext, List<CloudResource> resources, List<CloudInstance> vms) {
List<CloudVmMetaDataStatus> instanceMetaData = new ArrayList<>();
Map<String, CloudResource> instanceNameMap = groupByInstanceName(resources);
Map<Long, CloudResource> privateIdMap = groupByPrivateId(resources);
for (CloudInstance cloudInstance : vms) {
String instanceId = cloudInstance.getInstanceId();
CloudResource cloudResource;
if (instanceId != null) {
cloudResource = instanceNameMap.get(instanceId);
} else {
cloudResource = privateIdMap.get(cloudInstance.getTemplate().getPrivateId());
}
CloudVmMetaDataStatus cloudVmMetaDataStatus = getCloudVmMetaDataStatus(authenticatedContext, cloudResource, cloudInstance);
instanceMetaData.add(cloudVmMetaDataStatus);
}
return instanceMetaData;
}
private CloudVmMetaDataStatus getCloudVmMetaDataStatus(AuthenticatedContext authenticatedContext, CloudResource cloudResource,
CloudInstance matchedInstance) {
CloudVmMetaDataStatus cloudVmMetaDataStatus;
if (cloudResource != null) {
CloudInstance cloudInstance = new CloudInstance(cloudResource.getName(), matchedInstance.getTemplate());
try {
CloudCredential credential = authenticatedContext.getCloudCredential();
CloudContext cloudContext = authenticatedContext.getCloudContext();
Compute compute = GcpStackUtil.buildCompute(credential);
Instance executeInstance = getInstance(cloudContext, credential, compute, cloudResource.getName());
String privateIp = executeInstance.getNetworkInterfaces().get(0).getNetworkIP();
String publicIp = null;
List<AccessConfig> acl = executeInstance.getNetworkInterfaces().get(0).getAccessConfigs();
if (acl != null && acl.get(0) != null) {
publicIp = executeInstance.getNetworkInterfaces().get(0).getAccessConfigs().get(0).getNatIP();
}
CloudInstanceMetaData metaData = new CloudInstanceMetaData(privateIp, publicIp);
CloudVmInstanceStatus status = new CloudVmInstanceStatus(cloudInstance, InstanceStatus.CREATED);
cloudVmMetaDataStatus = new CloudVmMetaDataStatus(status, metaData);
} catch (IOException e) {
LOGGER.warn(String.format("Instance %s is not reachable", cloudResource.getName()), e);
CloudVmInstanceStatus status = new CloudVmInstanceStatus(cloudInstance, InstanceStatus.UNKNOWN);
cloudVmMetaDataStatus = new CloudVmMetaDataStatus(status, CloudInstanceMetaData.EMPTY_METADATA);
}
} else {
CloudVmInstanceStatus status = new CloudVmInstanceStatus(matchedInstance, InstanceStatus.TERMINATED);
cloudVmMetaDataStatus = new CloudVmMetaDataStatus(status, CloudInstanceMetaData.EMPTY_METADATA);
}
return cloudVmMetaDataStatus;
}
private Map<String, CloudResource> groupByInstanceName(List<CloudResource> resources) {
Map<String, CloudResource> instanceNameMap = new HashMap<>();
for (CloudResource resource : resources) {
if (ResourceType.GCP_INSTANCE == resource.getType()) {
String resourceName = resource.getName();
instanceNameMap.put(resourceName, resource);
}
}
return instanceNameMap;
}
private Map<Long, CloudResource> groupByPrivateId(List<CloudResource> resources) {
Map<Long, CloudResource> privateIdMap = new HashMap<>();
for (CloudResource resource : resources) {
if (ResourceType.GCP_INSTANCE == resource.getType()) {
String resourceName = resource.getName();
Long privateId = GcpStackUtil.getPrivateId(resourceName);
if (privateId != null) {
privateIdMap.put(privateId, resource);
}
}
}
return privateIdMap;
}
private Instance getInstance(CloudContext context, CloudCredential credential, Compute compute, String instanceName) throws IOException {
return compute.instances().get(GcpStackUtil.getProjectId(credential),
context.getLocation().getAvailabilityZone().value(), instanceName).execute();
}
}