package com.sequenceiq.cloudbreak.cloud.aws;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.GetConsoleOutputRequest;
import com.amazonaws.services.ec2.model.GetConsoleOutputResult;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.sequenceiq.cloudbreak.cloud.InstanceConnector;
import com.sequenceiq.cloudbreak.cloud.aws.view.AwsCredentialView;
import com.sequenceiq.cloudbreak.cloud.context.AuthenticatedContext;
import com.sequenceiq.cloudbreak.cloud.exception.CloudOperationNotSupportedException;
import com.sequenceiq.cloudbreak.cloud.model.CloudInstance;
import com.sequenceiq.cloudbreak.cloud.model.CloudResource;
import com.sequenceiq.cloudbreak.cloud.model.CloudVmInstanceStatus;
import com.sequenceiq.cloudbreak.cloud.model.InstanceStatus;
@Service
public class AwsInstanceConnector implements InstanceConnector {
private static final Logger LOGGER = LoggerFactory.getLogger(AwsInstanceConnector.class);
@Inject
private AwsClient awsClient;
@Value("${cb.aws.hostkey.verify:}")
private boolean verifyHostKey;
@Override
public String getConsoleOutput(AuthenticatedContext authenticatedContext, CloudInstance vm) {
if (!verifyHostKey) {
throw new CloudOperationNotSupportedException("Host key verification is disabled on AWS");
}
AmazonEC2Client amazonEC2Client = awsClient.createAccess(new AwsCredentialView(authenticatedContext.getCloudCredential()),
authenticatedContext.getCloudContext().getLocation().getRegion().value());
GetConsoleOutputRequest getConsoleOutputRequest = new GetConsoleOutputRequest().withInstanceId(vm.getInstanceId());
GetConsoleOutputResult getConsoleOutputResult = amazonEC2Client.getConsoleOutput(getConsoleOutputRequest);
try {
if (getConsoleOutputResult.getOutput() == null) {
return "";
} else {
return getConsoleOutputResult.getDecodedOutput();
}
} catch (Exception ex) {
LOGGER.debug(ex.getMessage(), ex);
return "";
}
}
@Override
public List<CloudVmInstanceStatus> start(AuthenticatedContext ac, List<CloudResource> resources, List<CloudInstance> vms) {
List<CloudVmInstanceStatus> statuses = new ArrayList<>();
AmazonEC2Client amazonEC2Client = awsClient.createAccess(new AwsCredentialView(ac.getCloudCredential()),
ac.getCloudContext().getLocation().getRegion().value());
for (String group : getGroups(vms)) {
Collection<String> instances = new ArrayList<>();
Collection<CloudInstance> cloudInstances = new ArrayList<>();
for (CloudInstance vm : vms) {
if (vm.getTemplate().getGroupName().equals(group)) {
instances.add(vm.getInstanceId());
cloudInstances.add(vm);
}
}
try {
instances = removeInstanceIdsWhichAreNotInCorrectState(instances, amazonEC2Client, "Running");
if (instances.size() > 0) {
amazonEC2Client.startInstances(new StartInstancesRequest().withInstanceIds(instances));
}
for (CloudInstance cloudInstance : cloudInstances) {
statuses.add(new CloudVmInstanceStatus(cloudInstance, InstanceStatus.IN_PROGRESS));
}
} catch (Exception e) {
for (CloudInstance cloudInstance : cloudInstances) {
statuses.add(new CloudVmInstanceStatus(cloudInstance, InstanceStatus.FAILED, e.getMessage()));
}
}
}
return statuses;
}
@Override
public List<CloudVmInstanceStatus> stop(AuthenticatedContext ac, List<CloudResource> resources, List<CloudInstance> vms) {
List<CloudVmInstanceStatus> statuses = new ArrayList<>();
AmazonEC2Client amazonEC2Client = awsClient.createAccess(new AwsCredentialView(ac.getCloudCredential()),
ac.getCloudContext().getLocation().getRegion().value());
for (String group : getGroups(vms)) {
Collection<String> instances = new ArrayList<>();
Collection<CloudInstance> cloudInstances = new ArrayList<>();
for (CloudInstance vm : vms) {
if (vm.getTemplate().getGroupName().equals(group)) {
instances.add(vm.getInstanceId());
cloudInstances.add(vm);
}
}
try {
instances = removeInstanceIdsWhichAreNotInCorrectState(instances, amazonEC2Client, "Stopped");
if (instances.size() > 0) {
amazonEC2Client.stopInstances(new StopInstancesRequest().withInstanceIds(instances));
}
for (CloudInstance cloudInstance : cloudInstances) {
statuses.add(new CloudVmInstanceStatus(cloudInstance, InstanceStatus.IN_PROGRESS));
}
} catch (Exception e) {
for (CloudInstance cloudInstance : cloudInstances) {
statuses.add(new CloudVmInstanceStatus(cloudInstance, InstanceStatus.FAILED, e.getMessage()));
}
}
}
return statuses;
}
@Override
public List<CloudVmInstanceStatus> check(AuthenticatedContext ac, List<CloudInstance> vms) {
List<CloudVmInstanceStatus> cloudVmInstanceStatuses = new ArrayList<>();
for (CloudInstance vm : vms) {
DescribeInstancesResult result = awsClient.createAccess(new AwsCredentialView(ac.getCloudCredential()),
ac.getCloudContext().getLocation().getRegion().value())
.describeInstances(new DescribeInstancesRequest().withInstanceIds(vm.getInstanceId()));
for (Reservation reservation : result.getReservations()) {
for (Instance instance : reservation.getInstances()) {
if ("Stopped".equalsIgnoreCase(instance.getState().getName())) {
LOGGER.info("AWS instance is in Stopped state, polling stack.");
cloudVmInstanceStatuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.STOPPED));
} else if ("Running".equalsIgnoreCase(instance.getState().getName())) {
LOGGER.info("AWS instance is in Started state, polling stack.");
cloudVmInstanceStatuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.STARTED));
} else if ("Terminated".equalsIgnoreCase(instance.getState().getName())) {
LOGGER.info("AWS instance is in Terminated state, polling stack.");
cloudVmInstanceStatuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.TERMINATED));
} else {
cloudVmInstanceStatuses.add(new CloudVmInstanceStatus(vm, InstanceStatus.IN_PROGRESS));
}
}
}
}
return cloudVmInstanceStatuses;
}
private Collection<String> removeInstanceIdsWhichAreNotInCorrectState(Collection<String> instances, AmazonEC2Client amazonEC2Client, String state) {
DescribeInstancesResult describeInstances = amazonEC2Client.describeInstances(
new DescribeInstancesRequest().withInstanceIds(instances));
for (Reservation reservation : describeInstances.getReservations()) {
for (Instance instance : reservation.getInstances()) {
if (state.equalsIgnoreCase(instance.getState().getName())) {
instances.remove(instance.getInstanceId());
}
}
}
return instances;
}
private Set<String> getGroups(List<CloudInstance> vms) {
Set<String> groups = new HashSet<>();
for (CloudInstance vm : vms) {
if (!groups.contains(vm.getTemplate().getGroupName())) {
groups.add(vm.getTemplate().getGroupName());
}
}
return groups;
}
}