diff --git a/perspective-aws/src/main/java/org/meridor/perspective/aws/Api.java b/perspective-aws/src/main/java/org/meridor/perspective/aws/Api.java index 84e523d1..8d80fc1f 100644 --- a/perspective-aws/src/main/java/org/meridor/perspective/aws/Api.java +++ b/perspective-aws/src/main/java/org/meridor/perspective/aws/Api.java @@ -1,4 +1,17 @@ package org.meridor.perspective.aws; public interface Api { + + boolean rebootInstance(String instanceId); + + boolean hardRebootInstance(String instanceId); + + boolean startInstance(String instanceId); + + boolean shutdownInstance(String instanceId); + + boolean deleteInstance(String instanceId); + + void close(); + } diff --git a/perspective-aws/src/main/java/org/meridor/perspective/aws/ApiProviderImpl.java b/perspective-aws/src/main/java/org/meridor/perspective/aws/ApiProviderImpl.java index 5761e4f8..48b7469a 100644 --- a/perspective-aws/src/main/java/org/meridor/perspective/aws/ApiProviderImpl.java +++ b/perspective-aws/src/main/java/org/meridor/perspective/aws/ApiProviderImpl.java @@ -1,34 +1,55 @@ package org.meridor.perspective.aws; +import com.amazonaws.AmazonWebServiceResult; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.regions.Regions; import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; +import com.amazonaws.services.ec2.model.RebootInstancesRequest; +import com.amazonaws.services.ec2.model.StartInstancesRequest; +import com.amazonaws.services.ec2.model.StopInstancesRequest; +import com.amazonaws.services.ec2.model.TerminateInstancesRequest; import org.meridor.perspective.config.Cloud; import org.springframework.stereotype.Component; +import javax.annotation.PreDestroy; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.function.BiConsumer; @Component public class ApiProviderImpl implements ApiProvider { + private final Map> apiCache = new HashMap<>(); + @Override public Api getApi(Cloud cloud, Regions region) { - return new ApiImpl(cloud, region); + apiCache.putIfAbsent(cloud, new HashMap<>()); + apiCache.get(cloud).putIfAbsent(region, new ApiImpl(cloud, region)); + return apiCache.get(cloud).get(region); } @Override public void forEachRegion(Cloud cloud, BiConsumer action) throws Exception { - Arrays.stream(Regions.values()).forEach(r -> action.accept(r.getName(), new ApiImpl(cloud, r))); + Arrays.stream(Regions.values()).forEach(r -> action.accept(r.getName(), getApi(cloud, r))); + } + + @PreDestroy + public void onDestroy() { + apiCache.keySet().forEach(c -> { + Map regionsMap = apiCache.get(c); + regionsMap.keySet().forEach(r -> regionsMap.get(r).close()); + }); } private class ApiImpl implements Api { private final AmazonEC2 client; - public ApiImpl(Cloud cloud, Regions region) { + ApiImpl(Cloud cloud, Regions region) { this.client = createClient(cloud, region); } @@ -43,5 +64,47 @@ private AmazonEC2 createClient(Cloud cloud, Regions region) { )) .build(); } + + @Override + public boolean rebootInstance(String instanceId) { + RebootInstancesRequest request = new RebootInstancesRequest(Collections.singletonList(instanceId)); + return isResponseSuccessful(client.rebootInstances(request)); + } + + @Override + public boolean hardRebootInstance(String instanceId) { + //TODO: to be implemented!!! + throw new UnsupportedOperationException(); + } + + @Override + public boolean startInstance(String instanceId) { + StartInstancesRequest request = new StartInstancesRequest(Collections.singletonList(instanceId)); + return isResponseSuccessful(client.startInstances(request)); + } + + @Override + public boolean shutdownInstance(String instanceId) { + StopInstancesRequest request = new StopInstancesRequest(Collections.singletonList(instanceId)); + return isResponseSuccessful(client.stopInstances(request)); + } + + @Override + public boolean deleteInstance(String instanceId) { + TerminateInstancesRequest terminateInstancesRequest = new TerminateInstancesRequest(Collections.singletonList(instanceId)); + return isResponseSuccessful(client.terminateInstances(terminateInstancesRequest)); + } + + private boolean isResponseSuccessful(AmazonWebServiceResult response) { + //TODO: to be implemented! + return true; + } + + @Override + public void close() { + client.shutdown(); + } + + } } diff --git a/perspective-aws/src/main/java/org/meridor/perspective/aws/DeleteInstanceOperation.java b/perspective-aws/src/main/java/org/meridor/perspective/aws/DeleteInstanceOperation.java new file mode 100644 index 00000000..77d5043f --- /dev/null +++ b/perspective-aws/src/main/java/org/meridor/perspective/aws/DeleteInstanceOperation.java @@ -0,0 +1,37 @@ +package org.meridor.perspective.aws; + +import org.meridor.perspective.beans.Instance; +import org.meridor.perspective.config.OperationType; +import org.springframework.stereotype.Component; + +import java.util.function.BiFunction; + +@Component +public class DeleteInstanceOperation extends BaseInstanceOperation { + + @Override + protected BiFunction getAction() { + return (api, instance) -> { + try { + return api.deleteInstance(instance.getRealId()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + + @Override + protected String getSuccessMessage(Instance instance) { + return String.format("Deleted instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + protected String getErrorMessage(Instance instance) { + return String.format("Failed to delete instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + public OperationType[] getTypes() { + return new OperationType[]{OperationType.DELETE_INSTANCE}; + } +} diff --git a/perspective-aws/src/main/java/org/meridor/perspective/aws/RebootInstanceOperation.java b/perspective-aws/src/main/java/org/meridor/perspective/aws/RebootInstanceOperation.java new file mode 100644 index 00000000..a2f6a730 --- /dev/null +++ b/perspective-aws/src/main/java/org/meridor/perspective/aws/RebootInstanceOperation.java @@ -0,0 +1,39 @@ +package org.meridor.perspective.aws; + +import org.meridor.perspective.beans.Instance; +import org.meridor.perspective.config.OperationType; +import org.springframework.stereotype.Component; + +import java.util.function.BiFunction; + +import static org.meridor.perspective.config.OperationType.REBOOT_INSTANCE; + +@Component +public class RebootInstanceOperation extends BaseInstanceOperation { + + @Override + protected BiFunction getAction() { + return (api, instance) -> { + try { + return api.rebootInstance(instance.getRealId()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + + @Override + protected String getSuccessMessage(Instance instance) { + return String.format("Rebooted instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + protected String getErrorMessage(Instance instance) { + return String.format("Failed to reboot instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + public OperationType[] getTypes() { + return new OperationType[]{REBOOT_INSTANCE}; + } +} diff --git a/perspective-aws/src/main/java/org/meridor/perspective/aws/ShutdownInstanceOperation.java b/perspective-aws/src/main/java/org/meridor/perspective/aws/ShutdownInstanceOperation.java new file mode 100644 index 00000000..43fdce61 --- /dev/null +++ b/perspective-aws/src/main/java/org/meridor/perspective/aws/ShutdownInstanceOperation.java @@ -0,0 +1,40 @@ +package org.meridor.perspective.aws; + +import org.meridor.perspective.beans.Instance; +import org.meridor.perspective.config.OperationType; +import org.springframework.stereotype.Component; + +import java.util.function.BiFunction; + +import static org.meridor.perspective.config.OperationType.SHUTDOWN_INSTANCE; + +@Component +public class ShutdownInstanceOperation extends BaseInstanceOperation { + + @Override + protected BiFunction getAction() { + return (api, instance) -> { + try { + return api.shutdownInstance(instance.getRealId()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + + @Override + protected String getSuccessMessage(Instance instance) { + return String.format("Shut down instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + protected String getErrorMessage(Instance instance) { + return String.format("Failed to shut down instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + public OperationType[] getTypes() { + return new OperationType[]{SHUTDOWN_INSTANCE}; + } + +} diff --git a/perspective-aws/src/main/java/org/meridor/perspective/aws/StartInstanceOperation.java b/perspective-aws/src/main/java/org/meridor/perspective/aws/StartInstanceOperation.java new file mode 100644 index 00000000..309592b8 --- /dev/null +++ b/perspective-aws/src/main/java/org/meridor/perspective/aws/StartInstanceOperation.java @@ -0,0 +1,40 @@ +package org.meridor.perspective.aws; + +import org.meridor.perspective.beans.Instance; +import org.meridor.perspective.config.OperationType; +import org.springframework.stereotype.Component; + +import java.util.function.BiFunction; + +import static org.meridor.perspective.config.OperationType.START_INSTANCE; + +@Component +public class StartInstanceOperation extends BaseInstanceOperation { + + @Override + protected BiFunction getAction() { + return (api, instance) -> { + try { + return api.startInstance(instance.getRealId()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } + + @Override + protected String getSuccessMessage(Instance instance) { + return String.format("Started instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + protected String getErrorMessage(Instance instance) { + return String.format("Failed to start instance %s (%s)", instance.getName(), instance.getId()); + } + + @Override + public OperationType[] getTypes() { + return new OperationType[]{START_INSTANCE}; + } + +}