package com.sequenceiq.cloudbreak.service.stack.connector.adapter;
import static com.sequenceiq.cloudbreak.cloud.model.AvailabilityZone.availabilityZone;
import static com.sequenceiq.cloudbreak.cloud.model.Location.location;
import static com.sequenceiq.cloudbreak.cloud.model.Region.region;
import static java.lang.String.format;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.sequenceiq.cloudbreak.cloud.context.CloudContext;
import com.sequenceiq.cloudbreak.cloud.event.CloudPlatformRequest;
import com.sequenceiq.cloudbreak.cloud.event.instance.CollectMetadataRequest;
import com.sequenceiq.cloudbreak.cloud.event.instance.CollectMetadataResult;
import com.sequenceiq.cloudbreak.cloud.event.resource.GetInstancesStateRequest;
import com.sequenceiq.cloudbreak.cloud.event.resource.GetInstancesStateResult;
import com.sequenceiq.cloudbreak.cloud.model.CloudCredential;
import com.sequenceiq.cloudbreak.cloud.model.CloudInstance;
import com.sequenceiq.cloudbreak.cloud.model.CloudResource;
import com.sequenceiq.cloudbreak.cloud.model.CloudVmMetaDataStatus;
import com.sequenceiq.cloudbreak.cloud.model.InstanceStatus;
import com.sequenceiq.cloudbreak.cloud.model.Location;
import com.sequenceiq.cloudbreak.converter.spi.CredentialToCloudCredentialConverter;
import com.sequenceiq.cloudbreak.converter.spi.InstanceMetaDataToCloudInstanceConverter;
import com.sequenceiq.cloudbreak.converter.spi.ResourceToCloudResourceConverter;
import com.sequenceiq.cloudbreak.converter.spi.StackToCloudStackConverter;
import com.sequenceiq.cloudbreak.domain.InstanceGroup;
import com.sequenceiq.cloudbreak.domain.InstanceMetaData;
import com.sequenceiq.cloudbreak.domain.Stack;
import com.sequenceiq.cloudbreak.service.stack.connector.OperationException;
import com.sequenceiq.cloudbreak.service.stack.flow.InstanceSyncState;
import reactor.bus.Event;
import reactor.bus.EventBus;
@Component
public class ServiceProviderMetadataAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceProviderMetadataAdapter.class);
@Inject
private EventBus eventBus;
@Inject
private StackToCloudStackConverter cloudStackConverter;
@Inject
private InstanceMetaDataToCloudInstanceConverter metadataConverter;
@Inject
private CredentialToCloudCredentialConverter credentialConverter;
@Inject
private ResourceToCloudResourceConverter cloudResourceConverter;
public List<CloudVmMetaDataStatus> collectMetadata(Stack stack) {
Location location = location(region(stack.getRegion()), availabilityZone(stack.getAvailabilityZone()));
CloudContext cloudContext = new CloudContext(stack.getId(), stack.getName(), stack.cloudPlatform(), stack.getOwner(), stack.getPlatformVariant(),
location);
CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
List<CloudInstance> cloudInstances = cloudStackConverter.buildInstances(stack);
List<CloudResource> cloudResources = cloudResourceConverter.convert(stack.getResources());
CollectMetadataRequest cmr = new CollectMetadataRequest(cloudContext, cloudCredential, cloudResources, cloudInstances);
LOGGER.info("Triggering event: {}", cmr);
eventBus.notify(CloudPlatformRequest.selector(CollectMetadataRequest.class), Event.wrap(cmr));
try {
CollectMetadataResult res = cmr.await();
LOGGER.info("Result: {}", res);
if (res.getErrorDetails() != null) {
LOGGER.error("Failed to collect metadata", res.getErrorDetails());
return Collections.emptyList();
}
return res.getResults();
} catch (InterruptedException e) {
LOGGER.error(format("Error while executing collectMetadata, stack: %s", cloudContext), e);
throw new OperationException(e);
}
}
public InstanceSyncState getState(Stack stack, InstanceGroup instanceGroup, String instanceId) {
Location location = location(region(stack.getRegion()), availabilityZone(stack.getAvailabilityZone()));
CloudContext cloudContext = new CloudContext(stack.getId(), stack.getName(), stack.cloudPlatform(), stack.getOwner(), stack.getPlatformVariant(),
location);
CloudCredential cloudCredential = credentialConverter.convert(stack.getCredential());
InstanceGroup ig = stack.getInstanceGroupByInstanceGroupName(instanceGroup.getGroupName());
CloudInstance instance = null;
for (InstanceMetaData metaData : ig.getAllInstanceMetaData()) {
if (instanceId.equalsIgnoreCase(metaData.getInstanceId())) {
instance = metadataConverter.convert(metaData);
break;
}
}
if (instance != null) {
GetInstancesStateRequest<GetInstancesStateResult> stateRequest =
new GetInstancesStateRequest<>(cloudContext, cloudCredential, Collections.singletonList(instance));
LOGGER.info("Triggering event: {}", stateRequest);
eventBus.notify(stateRequest.selector(), Event.wrap(stateRequest));
try {
GetInstancesStateResult res = stateRequest.await();
LOGGER.info("Result: {}", res);
if (res.isFailed()) {
LOGGER.error("Failed to retrieve instance state", res.getErrorDetails());
throw new OperationException(res.getErrorDetails());
}
return transform(res.getStatuses().get(0).getStatus());
} catch (InterruptedException e) {
LOGGER.error(format("Error while retrieving instance state of: %s", cloudContext), e);
throw new OperationException(e);
}
} else {
return InstanceSyncState.DELETED;
}
}
private InstanceSyncState transform(InstanceStatus instanceStatus) {
switch (instanceStatus) {
case IN_PROGRESS:
return InstanceSyncState.IN_PROGRESS;
case STARTED:
return InstanceSyncState.RUNNING;
case STOPPED:
return InstanceSyncState.STOPPED;
case CREATED:
return InstanceSyncState.RUNNING;
case FAILED:
return InstanceSyncState.DELETED;
case TERMINATED:
return InstanceSyncState.DELETED;
default:
return InstanceSyncState.UNKNOWN;
}
}
}