Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions javav2/example_code/ssm/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>cloudformation</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.example.scenario;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient;
import software.amazon.awssdk.services.cloudformation.model.Capability;
import software.amazon.awssdk.services.cloudformation.model.CloudFormationException;
import software.amazon.awssdk.services.cloudformation.model.DescribeStacksRequest;
import software.amazon.awssdk.services.cloudformation.model.DescribeStacksResponse;
import software.amazon.awssdk.services.cloudformation.model.Output;
import software.amazon.awssdk.services.cloudformation.model.Stack;
import software.amazon.awssdk.services.cloudformation.waiters.CloudFormationAsyncWaiter;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class CloudFormationHelper {
private static final String CFN_TEMPLATE = "ec2-stack.yaml";
private static final Logger logger = LoggerFactory.getLogger(CloudFormationHelper.class);

private static CloudFormationAsyncClient cloudFormationClient;

private static CloudFormationAsyncClient getCloudFormationClient() {
if (cloudFormationClient == null) {
SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
.maxConcurrency(100)
.connectionTimeout(Duration.ofSeconds(60))
.readTimeout(Duration.ofSeconds(60))
.writeTimeout(Duration.ofSeconds(60))
.build();

ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder()
.apiCallTimeout(Duration.ofMinutes(2))
.apiCallAttemptTimeout(Duration.ofSeconds(90))
.retryStrategy(RetryMode.STANDARD)
.build();

cloudFormationClient = CloudFormationAsyncClient.builder()
.httpClient(httpClient)
.region(Region.US_WEST_2)
.overrideConfiguration(overrideConfig)
.build();
}
return cloudFormationClient;
}

public static void deployCloudFormationStack(String stackName) {
String templateBody;
boolean doesExist = describeStack(stackName);
if (!doesExist) {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Path filePath = Paths.get(classLoader.getResource(CFN_TEMPLATE).toURI());
templateBody = Files.readString(filePath);
} catch (IOException | URISyntaxException e) {
throw new RuntimeException(e);
}

getCloudFormationClient().createStack(b -> b.stackName(stackName)
.templateBody(templateBody)
.capabilities(Capability.CAPABILITY_IAM))
.whenComplete((csr, t) -> {
if (csr != null) {
System.out.println("Stack creation requested, ARN is " + csr.stackId());
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
waiter.waitUntilStackCreateComplete(request -> request.stackName(stackName))
.whenComplete((dsr, th) -> {
if (th != null) {
System.out.println("Error waiting for stack creation: " + th.getMessage());
} else {
dsr.matched().response().orElseThrow(() -> new RuntimeException("Failed to deploy"));
System.out.println("Stack created successfully");
}
}).join();
}
} else {
System.out.format("Error creating stack: " + t.getMessage(), t);
throw new RuntimeException(t.getCause().getMessage(), t);
}
}).join();
} else {
logger.info("{} stack already exists", CFN_TEMPLATE);
}
}

// Check to see if the Stack exists before deploying it
public static Boolean describeStack(String stackName) {
try {
CompletableFuture<?> future = getCloudFormationClient().describeStacks();
DescribeStacksResponse stacksResponse = (DescribeStacksResponse) future.join();
List<Stack> stacks = stacksResponse.stacks();
for (Stack myStack : stacks) {
if (myStack.stackName().compareTo(stackName) == 0) {
return true;
}
}
} catch (CloudFormationException e) {
System.err.println(e.getMessage());
}
return false;
}

public static void destroyCloudFormationStack(String stackName) {
getCloudFormationClient().deleteStack(b -> b.stackName(stackName))
.whenComplete((dsr, t) -> {
if (dsr != null) {
System.out.println("Delete stack requested ....");
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
waiter.waitUntilStackDeleteComplete(request -> request.stackName(stackName))
.whenComplete((waiterResponse, throwable) ->
System.out.println("Stack deleted successfully."))
.join();
}
} else {
System.out.format("Error deleting stack: " + t.getMessage(), t);
throw new RuntimeException(t.getCause().getMessage(), t);
}
}).join();
}

public static CompletableFuture<Map<String, String>> getStackOutputsAsync(String stackName) {
CloudFormationAsyncClient cloudFormationAsyncClient = getCloudFormationClient();

DescribeStacksRequest describeStacksRequest = DescribeStacksRequest.builder()
.stackName(stackName)
.build();

return cloudFormationAsyncClient.describeStacks(describeStacksRequest)
.handle((describeStacksResponse, throwable) -> {
if (throwable != null) {
throw new RuntimeException("Failed to get stack outputs for: " + stackName, throwable);
}

// Process the result
if (describeStacksResponse.stacks().isEmpty()) {
throw new RuntimeException("Stack not found: " + stackName);
}

Stack stack = describeStacksResponse.stacks().get(0);
Map<String, String> outputs = new HashMap<>();
for (Output output : stack.outputs()) {
outputs.put(output.outputKey(), output.outputValue());
}

return outputs;
});
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private static SsmAsyncClient getAsyncClient() {
.build();

ssmAsyncClient = SsmAsyncClient.builder()
.region(Region.US_EAST_1)
.region(Region.US_WEST_2)
.httpClient(httpClient)
.overrideConfiguration(overrideConfig)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,34 @@
import software.amazon.awssdk.services.ssm.model.DocumentAlreadyExistsException;
import software.amazon.awssdk.services.ssm.model.SsmException;

import java.util.Map;
import java.util.Scanner;
public class SSMScenario {
public static final String DASHES = new String(new char[80]).replace("\0", "-");
private static final String ROLES_STACK = "SsmStack3`1";

public static void main(String[] args) {
String usage = """
Usage:
<instanceId> <title> <source> <category> <severity>
<title> <source> <category> <severity>

Where:
instanceId - The Amazon EC2 Linux/UNIX instance Id that AWS Systems Manager uses (ie, i-0149338494ed95f06).
title - The title of the parameter (default is Disk Space Alert).
source - The source of the parameter (default is EC2).
category - The category of the parameter. Valid values are 'Availability', 'Cost', 'Performance', 'Recovery', 'Security' (default is Performance).
severity - The severity of the parameter. Severity should be a number from 1 to 4 (default is 2).
""";

if (args.length != 1) {
System.out.println(usage);
System.exit(1);
}

Scanner scanner = new Scanner(System.in);
SSMActions actions = new SSMActions();
String documentName;
String windowName;
String instanceId = args[0];

System.out.println("Use AWS CloudFormation to create the EC2 instance that is required for this scenario.");
CloudFormationHelper.deployCloudFormationStack(ROLES_STACK);
Map<String, String> stackOutputs = CloudFormationHelper.getStackOutputsAsync(ROLES_STACK).join();
String instanceId = stackOutputs.get("InstanceId");
System.out.println("The Instance ID: " + instanceId +" was created.");
String title = "Disk Space Alert" ;
String source = "EC2" ;
String category = "Availability" ;
Expand Down Expand Up @@ -230,7 +231,7 @@ This Java program demonstrates how to interact with AWS Systems Manager using th
System.out.println("The AWS Systems Manager resources will not be deleted");
}
System.out.println(DASHES);

CloudFormationHelper.destroyCloudFormationStack(ROLES_STACK);
System.out.println("This concludes the AWS Systems Manager SDK Basics scenario.");
System.out.println(DASHES);
}
Expand Down
89 changes: 89 additions & 0 deletions javav2/example_code/ssm/src/main/resources/ec2-stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
Resources:
SSMEC2Role116353F9:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: ec2.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- :iam::aws:policy/AmazonSSMManagedInstanceCore
Metadata:
aws:cdk:path: SsmStack3/SSMEC2Role/Resource
EC2SecurityGroup05DEE054:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH and SSM access
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: "-1"
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
Description: Allow SSH Access
FromPort: 22
IpProtocol: tcp
ToPort: 22
VpcId: vpc-573b5f2f
Metadata:
aws:cdk:path: SsmStack3/EC2SecurityGroup/Resource
SSMInstanceInstanceProfileCEDAF98B:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- Ref: SSMEC2Role116353F9
Metadata:
aws:cdk:path: SsmStack3/SSMInstance/InstanceProfile
SSMInstance0FC4E7D0:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: us-west-2a
IamInstanceProfile:
Ref: SSMInstanceInstanceProfileCEDAF98B
ImageId:
Ref: SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter
InstanceType: t2.micro
SecurityGroupIds:
- Fn::GetAtt:
- EC2SecurityGroup05DEE054
- GroupId
SubnetId: subnet-206a9c58
Tags:
- Key: Name
Value: SsmStack3/SSMInstance
UserData:
Fn::Base64: |-
#!/bin/bash
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent
DependsOn:
- SSMEC2Role116353F9
Metadata:
aws:cdk:path: SsmStack3/SSMInstance/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/22QTWvDMAyGf0t9HG7WFjZGbtkGI7u0tLuFMlRH7bQ6cuaPlmLy30e+WAs7GFkv0qtHWiTzp4dkNoGzm6ryONW0S+LGgzrKNToTrMJC3An5z9tKOLvPSFAlcW00FlGAc6HC8vki0ihqS6yoBp0pZQJ7kXaNfU3bkClPhju5kaIChgOWK6NJETqRFvFGu2R2qN02W/my59aijTk7D6xwZc2eNDYS1SKJG1TBkr+8WRPqIopTrUYArc0503oZ/M4ELkXqbUApSnTKUn3FFAWUZc4Hi86tg8aOSQHnrImxV/peZZixW8cNUwLTT8C8HK2a7mQ9+Q2bHPmLKGj4flxqHHwqUF/EmFdwGKW/VazRo+iuPUcGh/YVPAxnuz5W07TZCixU6NG2yTL4OvhGvsMJ7hfzZJY8Tr4d0dQG9lRhsu7jLxfV5p8zAgAA
Metadata:
aws:cdk:path: SsmStack3/CDKMetadata/Default
Parameters:
SsmParameterValueawsserviceamiamazonlinuxlatestamzn2amihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Outputs:
InstanceId:
Description: EC2 Instance ID (SSM-ready, safe to delete stack)
Value:
Ref: SSMInstance0FC4E7D0

Loading
Loading