diff --git a/javav2/example_code/autoscale/pom.xml b/javav2/example_code/autoscale/pom.xml index 4697cbbe0a1..cb8abe17bdf 100644 --- a/javav2/example_code/autoscale/pom.xml +++ b/javav2/example_code/autoscale/pom.xml @@ -8,9 +8,9 @@ 1.0-SNAPSHOT UTF-8 - 21 - 21 - 21 + 17 + 17 + 17 @@ -26,14 +26,7 @@ software.amazon.awssdk bom - 2.31.8 - pom - import - - - org.apache.logging.log4j - log4j-bom - 2.23.1 + 2.29.45 pom import @@ -50,14 +43,9 @@ software.amazon.awssdk secretsmanager - - com.google.code.gson - gson - 2.10.1 - software.amazon.awssdk - autoscaling + cloudformation software.amazon.awssdk @@ -65,32 +53,28 @@ software.amazon.awssdk - auth + netty-nio-client - software.amazon.awssdk - sso + com.google.code.gson + gson + 2.10.1 software.amazon.awssdk - ssooidc - - - org.apache.logging.log4j - log4j-core + autoscaling - org.slf4j - slf4j-api - 2.0.13 + software.amazon.awssdk + auth - org.apache.logging.log4j - log4j-slf4j2-impl + software.amazon.awssdk + sso - org.apache.logging.log4j - log4j-1.2-api + software.amazon.awssdk + ssooidc \ No newline at end of file diff --git a/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/AutoScalingScenario.java b/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/AutoScalingScenario.java index 14b7ca01af3..0e86bd18fea 100644 --- a/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/AutoScalingScenario.java +++ b/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/AutoScalingScenario.java @@ -29,8 +29,21 @@ import software.amazon.awssdk.services.autoscaling.model.TerminateInstanceInAutoScalingGroupRequest; import software.amazon.awssdk.services.autoscaling.model.DescribeAutoScalingInstancesRequest; import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.CreateLaunchTemplateVersionRequest; +import software.amazon.awssdk.services.ec2.model.CreateLaunchTemplateVersionResponse; +import software.amazon.awssdk.services.ec2.model.DescribeSubnetsRequest; +import software.amazon.awssdk.services.ec2.model.DescribeSubnetsResponse; +import software.amazon.awssdk.services.ec2.model.DescribeVpcsRequest; +import software.amazon.awssdk.services.ec2.model.DescribeVpcsResponse; +import software.amazon.awssdk.services.ec2.model.Ec2Exception; +import software.amazon.awssdk.services.ec2.model.Filter; +import software.amazon.awssdk.services.ec2.model.ModifyLaunchTemplateRequest; +import software.amazon.awssdk.services.ec2.model.RequestLaunchTemplateData; +import software.amazon.awssdk.services.ec2.model.ResponseLaunchTemplateData; +import software.amazon.awssdk.services.ec2.model.Vpc; import java.util.List; +import java.util.Map; // snippet-end:[autoscale.java2.create_scaling_scenario.import] // snippet-start:[autoscale.java2.create_scaling_scenario.main] @@ -65,41 +78,34 @@ public class AutoScalingScenario { public static final String DASHES = new String(new char[80]).replace("\0", "-"); - + private static final String ROLES_STACK = "MyCdkAutoScaleStack"; public static void main(String[] args) throws InterruptedException { - final String usage = """ - - Usage: - - - Where: - groupName - The name of the Auto Scaling group. - launchTemplateName - The name of the launch template.\s - vpcZoneId - A subnet Id for a virtual private cloud (VPC) where instances in the Auto Scaling group can be created. - """; - - //if (args.length != 3) { - // System.out.println(usage); - // System.exit(1); - // } - - String groupName = "Scott250" ; //rgs[0]; - String launchTemplateName = "MyTemplate5" ;//args[1]; - String vpcZoneId = "subnet-0ddc451b8a8a1aa44" ; //args[2]; - + // The name of the Auto Scaling group. + String groupName = "MyAutoScalingGroup2"; AutoScalingClient autoScalingClient = AutoScalingClient.builder() - .region(Region.US_EAST_1) + .region(Region.US_WEST_2) .build(); - Ec2Client ec2 = Ec2Client.create(); + Ec2Client ec2 = Ec2Client.builder() + .region(Region.US_WEST_2) + .build(); System.out.println(DASHES); System.out.println("Welcome to the Amazon EC2 Auto Scaling example scenario."); System.out.println(DASHES); System.out.println(DASHES); + System.out.println("First, we will create a launch template using a CloudFormation script"); + CloudFormationHelper.deployCloudFormationStack(ROLES_STACK); + Map stackOutputs = CloudFormationHelper.getStackOutputsAsync(ROLES_STACK).join(); + String launchTemplateName = stackOutputs.get("LaunchTemplateNameOutput"); + String vpcZoneId = getVPC(ec2); + updateTemlate(ec2, launchTemplateName ); + System.out.println("The VPC zone id created by the CloudFormation stack is"+vpcZoneId); + System.out.println("1. Create an Auto Scaling group named " + groupName); - createAutoScalingGroup(autoScalingClient, groupName, launchTemplateName, vpcZoneId); + createAutoScalingGroup(autoScalingClient, ec2, groupName, launchTemplateName, vpcZoneId); + System.out.println( "Wait 1 min for the resources, including the instance. Otherwise, an empty instance Id is returned"); Thread.sleep(60000); @@ -170,7 +176,8 @@ public static void main(String[] args) throws InterruptedException { System.out.println(DASHES); System.out.println(DASHES); - System.out.println("13. Delete the Auto Scaling group"); + System.out.println("13. Delete the Auto Scaling group and cloud formation resources"); + CloudFormationHelper.destroyCloudFormationStack(ROLES_STACK); deleteAutoScalingGroup(autoScalingClient, groupName); System.out.println(DASHES); @@ -181,6 +188,56 @@ public static void main(String[] args) throws InterruptedException { autoScalingClient.close(); } + public static String getVPC(Ec2Client ec2) { + try { + DescribeVpcsRequest request = DescribeVpcsRequest.builder() + .filters(f -> f.name("isDefault").values("true")) + .build(); + + DescribeVpcsResponse response = ec2.describeVpcs(request); + + if (!response.vpcs().isEmpty()) { + Vpc defaultVpc = response.vpcs().get(0); + System.out.println("Default VPC ID: " + defaultVpc.vpcId()); + return defaultVpc.vpcId(); + } else { + System.out.println("No default VPC found."); + return null; // Return null if no default VPC is found + } + + } catch (Ec2Exception e) { + System.err.println("EC2 error: " + e.awsErrorDetails().errorMessage()); + return null; // Return null in case of an error + } + } + + + public static void updateTemlate(Ec2Client ec2, String launchTemplateName ) { + // Step 1: Create new launch template version + String newAmiId = "ami-0025f0db847eb6254"; + RequestLaunchTemplateData launchTemplateData = RequestLaunchTemplateData.builder() + .imageId(newAmiId) + .build(); + + CreateLaunchTemplateVersionRequest createVersionRequest = CreateLaunchTemplateVersionRequest.builder() + .launchTemplateName(launchTemplateName) + .versionDescription("Updated with valid AMI") + .sourceVersion("1") + .launchTemplateData(launchTemplateData) + .build(); + + CreateLaunchTemplateVersionResponse createResponse = ec2.createLaunchTemplateVersion(createVersionRequest); + int newVersionNumber = createResponse.launchTemplateVersion().versionNumber().intValue(); + + // Step 2: Modify default version + ModifyLaunchTemplateRequest modifyRequest = ModifyLaunchTemplateRequest.builder() + .launchTemplateName(launchTemplateName) + .defaultVersion(String.valueOf(newVersionNumber)) + .build(); + + ec2.modifyLaunchTemplate(modifyRequest); + System.out.println("Updated launch template to version " + newVersionNumber + " with AMI " + newAmiId); + } // snippet-start:[autoscale.java2.describe_scaling_activites.main] @@ -224,42 +281,61 @@ public static void setDesiredCapacity(AutoScalingClient autoScalingClient, Strin } // snippet-end:[autoscale.java2.set_capacity.main] - // snippet-start:[autoscale.java2.create_autoscalinggroup.main] + // snippet-start:[autoscale.java2.create_scaling_group.main] public static void createAutoScalingGroup(AutoScalingClient autoScalingClient, - String groupName, - String launchTemplateName, - String vpcZoneId) { + Ec2Client ec2Client, + String groupName, + String launchTemplateName, + String vpcId) { try { - AutoScalingWaiter waiter = autoScalingClient.waiter(); + // Step 1: Get one subnet ID in the given VPC + DescribeSubnetsRequest subnetRequest = DescribeSubnetsRequest.builder() + .filters(Filter.builder().name("vpc-id").values(vpcId).build()) + .build(); + + DescribeSubnetsResponse subnetResponse = ec2Client.describeSubnets(subnetRequest); + + if (subnetResponse.subnets().isEmpty()) { + throw new RuntimeException("No subnets found in VPC: " + vpcId); + } + + String subnetId = subnetResponse.subnets().get(0).subnetId(); // Use first subnet + System.out.println("Using subnet: " + subnetId); + + // Step 2: Create launch template reference LaunchTemplateSpecification templateSpecification = LaunchTemplateSpecification.builder() .launchTemplateName(launchTemplateName) .build(); + // Step 3: Create Auto Scaling group CreateAutoScalingGroupRequest request = CreateAutoScalingGroupRequest.builder() .autoScalingGroupName(groupName) - .availabilityZones("us-east-1a") .launchTemplate(templateSpecification) - .maxSize(1) .minSize(1) - .vpcZoneIdentifier(vpcZoneId) + .maxSize(1) + .vpcZoneIdentifier(subnetId) // Correct: subnet ID, not VPC ID .build(); autoScalingClient.createAutoScalingGroup(request); + + // Step 4: Wait until group is created + AutoScalingWaiter waiter = autoScalingClient.waiter(); DescribeAutoScalingGroupsRequest groupsRequest = DescribeAutoScalingGroupsRequest.builder() .autoScalingGroupNames(groupName) .build(); - WaiterResponse waiterResponse = waiter - .waitUntilGroupExists(groupsRequest); + WaiterResponse waiterResponse = + waiter.waitUntilGroupExists(groupsRequest); + waiterResponse.matched().response().ifPresent(System.out::println); System.out.println("Auto Scaling Group created"); - } catch (AutoScalingException e) { - System.err.println(e.awsErrorDetails().errorMessage()); + } catch (Ec2Exception | AutoScalingException e) { + System.err.println("Error: " + e.awsErrorDetails().errorMessage()); System.exit(1); } } - // snippet-end:[autoscale.java2.create_autoscalinggroup.main] + // snippet-end:[autoscale.java2.create_scaling_group.main] // snippet-start:[autoscale.java2.describe_autoscalinggroup.main] public static void describeAutoScalingInstance(AutoScalingClient autoScalingClient, String id) { @@ -437,7 +513,7 @@ public static void terminateInstanceInAutoScalingGroup(AutoScalingClient autoSca } // snippet-end:[autoscale.java2.terminate_instance.main] - // snippet-start:[autoscale.java2.del_group.main] + // snippet-start:[autoscale.java2.del_scaling_group.main] public static void deleteAutoScalingGroup(AutoScalingClient autoScalingClient, String groupName) { try { DeleteAutoScalingGroupRequest deleteAutoScalingGroupRequest = DeleteAutoScalingGroupRequest.builder() @@ -453,6 +529,6 @@ public static void deleteAutoScalingGroup(AutoScalingClient autoScalingClient, S System.exit(1); } } - // snippet-end:[autoscale.java2.del_group.main] + // snippet-end:[autoscale.java2.del_scaling_group.main] } // snippet-end:[autoscale.java2.create_scaling_scenario.main] diff --git a/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/CloudFormationHelper.java b/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/CloudFormationHelper.java new file mode 100644 index 00000000000..07783c260d1 --- /dev/null +++ b/javav2/example_code/autoscale/src/main/java/com/example/autoscaling/scenario/CloudFormationHelper.java @@ -0,0 +1,161 @@ +package com.example.autoscaling.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 = "launchtemplate.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) + .overrideConfiguration(overrideConfig) + .region(Region.US_WEST_2) + .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 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> 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 outputs = new HashMap<>(); + for (Output output : stack.outputs()) { + outputs.put(output.outputKey(), output.outputValue()); + } + + return outputs; + }); + } +} diff --git a/javav2/example_code/autoscale/src/main/resources/launchtemplate.yaml b/javav2/example_code/autoscale/src/main/resources/launchtemplate.yaml new file mode 100644 index 00000000000..7df9bb328ac --- /dev/null +++ b/javav2/example_code/autoscale/src/main/resources/launchtemplate.yaml @@ -0,0 +1,26 @@ +Resources: + MyLaunchTemplate: + Type: AWS::EC2::LaunchTemplate + Properties: + LaunchTemplateData: + ImageId: ami-08962a4068733a2b6 + InstanceType: t3.micro + LaunchTemplateName: MyLaunchTemplate + Metadata: + aws:cdk:path: MyCdkAutoScaleStack/MyLaunchTemplate + CDKMetadata: + Type: AWS::CDK::Metadata + Properties: + Analytics: v2:deflate64:H4sIAAAAAAAA/zPSM7Qw0zNQTCwv1k1OydbNyUzSqw4uSUzO1kksL45PTTbSc07L80kszUvOCEnNLchJLEnVcU7L8y8tKSgtqdXxSixL1Dcy1DPQM1PMKs7M1C0qzSvJzE3VC4LQAEchUclgAAAA + Metadata: + aws:cdk:path: MyCdkAutoScaleStack/CDKMetadata/Default +Outputs: + LaunchTemplateNameOutput: + Description: The name of the launch template + Value: MyLaunchTemplate +Parameters: + BootstrapVersion: + Type: AWS::SSM::Parameter::Value + Default: /cdk-bootstrap/hnb659fds/version + Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip] + diff --git a/javav2/example_code/autoscale/src/test/java/AutoScaleTest.java b/javav2/example_code/autoscale/src/test/java/AutoScaleTest.java index 9d7b174a733..2231d6f7506 100644 --- a/javav2/example_code/autoscale/src/test/java/AutoScaleTest.java +++ b/javav2/example_code/autoscale/src/test/java/AutoScaleTest.java @@ -3,22 +3,28 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertFalse; - import com.example.autoscaling.scenario.AutoScalingScenario; import com.example.autoscaling.CreateAutoScalingGroup; import com.example.autoscaling.DeleteAutoScalingGroup; import com.example.autoscaling.DescribeAutoScalingInstances; import com.example.autoscaling.DetachInstances; +import com.example.autoscaling.scenario.CloudFormationHelper; import com.google.gson.Gson; -import org.junit.jupiter.api.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestMethodOrder; import software.amazon.awssdk.services.autoscaling.AutoScalingClient; - import java.io.IOException; +import java.util.Map; import java.util.Random; - import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse; @@ -30,40 +36,43 @@ @TestInstance(TestInstance.Lifecycle.PER_METHOD) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class AutoScaleTest { - private static final Logger logger = LoggerFactory.getLogger(AutoScaleTest.class); private static AutoScalingClient autoScalingClient; - private static String groupName = ""; + + private static Ec2Client ec2; private static String groupNameSc = ""; - private static String instanceId = ""; - private static String instanceId2 = ""; private static String launchTemplateName = ""; private static String vpcZoneId = ""; + private static final String ROLES_STACK = "MyCdkAutoScaleStack"; @BeforeAll public static void setUp() throws IOException { autoScalingClient = AutoScalingClient.builder() - .region(Region.US_EAST_1) + .region(Region.US_WEST_2) + .build(); + + ec2 = Ec2Client.builder() + .region(Region.US_WEST_2) .build(); Random random = new Random(); - int randomNum = random.nextInt((10000 - 1) + 1) + 1; + int randomNum = random.nextInt((1000 - 1) + 1) + 1; + + CloudFormationHelper.deployCloudFormationStack(ROLES_STACK); + Map stackOutputs = CloudFormationHelper.getStackOutputsAsync(ROLES_STACK).join(); + launchTemplateName = stackOutputs.get("LaunchTemplateNameOutput"); // Get the values to run these tests from AWS Secrets Manager. - Gson gson = new Gson(); - TestValues myValues = gson.fromJson(String.valueOf(getSecretValues()), TestValues.class); - groupName = myValues.getGroupName() + randomNum; - launchTemplateName = myValues.getLaunchTemplateName(); - vpcZoneId = myValues.getVpcZoneId(); - groupNameSc = myValues.getGroupNameSc() + randomNum; + groupNameSc = "MyAutoScalingGroup" + randomNum; + vpcZoneId = AutoScalingScenario.getVPC(ec2); } @Test @Tag("IntegrationTest") @Order(1) public void autoScalingScenario() throws InterruptedException { - System.out.println("**** Create an Auto Scaling group named " + groupName); - AutoScalingScenario.createAutoScalingGroup(autoScalingClient, groupNameSc, launchTemplateName, vpcZoneId); - + AutoScalingScenario.updateTemlate(ec2, launchTemplateName ); + System.out.println("**** Create an Auto Scaling group named " + groupNameSc); + AutoScalingScenario.createAutoScalingGroup(autoScalingClient, ec2, groupNameSc, launchTemplateName, vpcZoneId); System.out.println( "Wait 1 min for the resources, including the instance. Otherwise, an empty instance Id is returned"); Thread.sleep(60000); @@ -108,50 +117,6 @@ public void autoScalingScenario() throws InterruptedException { System.out.println("**** Delete the Auto Scaling group"); AutoScalingScenario.deleteAutoScalingGroup(autoScalingClient, groupNameSc); - logger.info("Test 1 passed"); - } - - private static String getSecretValues() { - SecretsManagerClient secretClient = SecretsManagerClient.builder() - .region(Region.US_EAST_1) - .build(); - String secretName = "test/autoscale"; - - GetSecretValueRequest valueRequest = GetSecretValueRequest.builder() - .secretId(secretName) - .build(); - - GetSecretValueResponse valueResponse = secretClient.getSecretValue(valueRequest); - return valueResponse.secretString(); - } - - @Nested - @DisplayName("A class used to get test values from test/autoscale (an AWS Secrets Manager secret)") - class TestValues { - private String groupName; - private String groupNameSc; - - private String launchTemplateName; - - private String vpcZoneId; - - TestValues() { - } - - String getGroupName() { - return this.groupName; - } - - String getGroupNameSc() { - return this.groupNameSc; - } - - String getLaunchTemplateName() { - return this.launchTemplateName; - } - - String getVpcZoneId() { - return this.vpcZoneId; - } + CloudFormationHelper.destroyCloudFormationStack(ROLES_STACK); } } diff --git a/javav2/example_code/ec2/ec2Key.pem b/javav2/example_code/ec2/ec2Key.pem new file mode 100644 index 00000000000..0518581690b --- /dev/null +++ b/javav2/example_code/ec2/ec2Key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAxkvDHdMCqKWGHLs4DeJmk4XiGlY+5NA3ADqA9rrwPBlvohGI +8Zo24wAoGhFbqavd9FYfopAF4WfbdzeslKOzXitBlHH769yd6pZ9hwQNdyuAtN9l +6snaZNPE9ky5uQ8tiZhJHJi1428+tujjUAi7jtkLLcLLc7ge3LOmhn06fu/BsbxP +yNt9H28ntRvB8JEt5w1f2/vwuoLdxgoC7Gaw9D7xtr4YLJ/isffVysO2XA64ZM67 +dd8OGa18+a3Oj+3Bjdel9tZC35qoRco8vaEijnSAmDGZB3gu1wC8OiwDzUl53PDq +KS9ZmwyL7/4uzrLQPxZOG1ngm+PNgjEn0eSpoQIDAQABAoIBAQC7cVZpVNOIk57o +fdkI1uBbxwzqFGizZlb3clYB5Me+J9UsgCLRLxN/FODTc2EQTBQtKVQSGM5WOhRs +50XN48hj1cPSDMU0OYFVBRh3jk8kPQ0W7K2seU5mTQA8Sl6tHjnPfRJvY7Nb4AaK +ZC6rsvWInIZCpYYoRv11ZqSdMLcg0NpXvGTQV93zDU3hOgCypilmxTO5Qwgss6qh +PqtgcnNdLl1Mb4gVt2h5ub/6s8+VNj7mncsfjwf+GIhJTSE52vn7JOHPt9m2B4rn +UmZXqKAUcFUm1lPBGuf83Hcl8SXq6vCWklvfSffdc63+RSochYykDc8tDibXqytf +8ss0t+F5AoGBAPjhfAXDpgY1RXiVfzDkGmq5P3KPe0B7CzuwIJMyMzqkYPCLfsLP +wPfnqxQ4r1UoPvNrRLB0gSYHgWqvlp/xqntvBJ909I5L2+vx92wD6o+Mhx24jxCc +QDP8fCiAda/2uVV7QGozvEi561PUzj0X6CUA6ZWt2Hf8sUKD6vep3adfAoGBAMv3 +2kiYhD4h2GvhI5RcMs9CE0Y1eVoKJNkd3YyXaD/wmc1SK7xR0qsD0CqjZSQ2dP9Y +UPfEiauNTmKQv4YyCyg1uOnG09KvoAUi2X6flZlb1E3xRAX0Qv4FGqoc5360/xcC +45tqaZ9yyguLARkfHmcArMs5+CxbL9pDkKHMZE7/AoGBAL63o9+S7u4A8oyWGxKv +KaMw8/LpCqz93TzPGhdSN7mvb23Fp8zHgXs3d30Wdx2NqrfEMq35iWJIDB9iEM3e +ViMijutWp3VHom6rTEvksGFycbQP0uoKopRz3fz3e7ftHFbqDRGVNaqRdkkWYTil +0kpQ6a6+uowwAvISvwMsk2OHAoGAeuDUlkubz7qgIU2/G4/35DjQV8m7U+0sicie +Qias3WhboABS7N72ZaSkciuBsTFFhtdz3/B9Z+Z3RJYja/sWEaFbxyrLTfAUHUQD +d284tu1Fl7cz3cpr2ZDFoZpMNF9iFkDdUjHnc/G5mv6hKLtAm5kigERqKH6+82Uk +6vSxsY0CgYB5o2Gwucm6/CM0oDdPKjQddwlbJlKZRSkbWRi8yfUpMmkq09L9UmXv +NJgCD6T62feMWizu5zvokX3yn6fvop3BuDkxnFeCuXSkz+Lf+yTlNLr5pEAXHTfP +kW6Q/QmwJ9DcdwX8USRdizIF8n/nmkL1jRA+jD2rptld69zfZCS+5A== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/javav2/example_code/ec2/src/test/java/EC2Test.java b/javav2/example_code/ec2/src/test/java/EC2Test.java index 5e822d951a3..f663cef4649 100644 --- a/javav2/example_code/ec2/src/test/java/EC2Test.java +++ b/javav2/example_code/ec2/src/test/java/EC2Test.java @@ -50,7 +50,7 @@ public static void setUp() { Gson gson = new Gson(); String json = getSecretValues(); SecretValues values = gson.fromJson(json, SecretValues.class); - keyName = values.getKeyNameSc(); + keyName = values.getKeyNameSc(); groupName = values.getGroupName() + java.util.UUID.randomUUID(); groupDesc = values.getGroupDesc(); keyNameSc = values.getKeyNameSc() + java.util.UUID.randomUUID(); diff --git a/scenarios/basics/fleetwise/SPECIFICATION.md b/scenarios/basics/fleetwise/SPECIFICATION.md new file mode 100644 index 00000000000..d189021eb09 --- /dev/null +++ b/scenarios/basics/fleetwise/SPECIFICATION.md @@ -0,0 +1,314 @@ +# AWS IoT Fleetwise Service Scenario Specification + +## Overview +This SDK Basics scenario demonstrates how to interact with AWS IoT Fleetwise using an AWS SDK. +It demonstrates various tasks such as creating a Fleetwise catelog, creating an fleet, +creating a vehicle, and so on. Finally this scenario demonstrates how +to clean up resources. Its purpose is to demonstrate how to get up and running with +AWS Fleetwise and an AWS SDK. + +## Resources +This Basics scenario does not require any additional AWS resources. + +## Hello AWS Fleetwise +This program is intended for users not familiar with the AWS IoT Fleetwise Service to easily get up and running. The program uses a `listSignalCatalogsPaginator` to demonstrate how you can read through catalog information. If there are no catalogs, print out a message to inform the user. + +## Basics Scenario Program Flow +The AWS IoT Fleetwise Basics scenario executes the following operations. + +1. **Create an AWS FleetWise collection**: + - Description: Creates an AWS Fleetwise collection by invoking `createSignalCatalog`. + - Exception Handling: Check to see if a `ValidationException` is thrown. + If it is thrown, if so, display the message and end the program. + +2. **Create an IoT Fleetwise fleet**: + - Description: Creates an AWS Fleetwise fleet by invoking `createFleet`. + - Exception Handling: Check to see if a `ResourceNotFoundException` is thrown. If it is thrown, if so, display the message and end the program. + +3. **Create a model manifest**: + - Description: Creates a model manifest by invoking `listSignalCatalogNodes` to retrieve a list of nodes. This node list is passed to `createModelManifest()`. + - Exception Handling: Check to see if an `InvalidSignalsException` is thrown. If so, display the message and end the program. + +4. **Create a decoder manifest**: + - Description: Creates a decoder manifest by invoking `createDecoderManifest`. + - Exception Handling: Check to see if a `DecoderManifestValidationException` is thrown. If so, display the message and end the program. + +5. **Check the status of the model manifest**: + - Description: Checks the status of the model manifest by invoking `updateModelManifest`and `getModelManifest`. + - Exception Handling: Check to see if a `ResourceNotFoundException` is thrown. If so, display the message and end the program. + +6. **Check the status of the decoder**: + - Description: Checks the status of the decoder manifest by invoking `updateDecoderManifest`and `getDecoderManifest`. + - Exception Handling: Check to see if a `ResourceNotFoundException` is thrown. If so, display the message and end the program. + + +7. **Create an IoT Thing**: + - Description: Creates an IoT Thing which is required to create a vehicle by invoking `createThing`. + - Exception Handling: Check to see if a `ResourceAlreadyExistsException` is thrown. If so, display the message and end the program. + +8. **Create a vehicle**: + - Description: Creates a vehicle by invoking `createVehicle`. + - Exception Handling: Check to see if an `ResourceNotFoundException` is thrown. If so, display the message and end the program. + +9. **Display vehicle details**: + - Description: Describes the vehicle by invoking `getVehicle`. + - Exception Handling: Check to see if a `ResourceNotFoundException` is thrown. If so, display the message and end the program. + +10. **Delete the AWS IoT Fleetwise Assets**: + - The `delete` methods are called to clean up the resources. + - Exception Handling: Check to see if a `ResourceNotFoundException` is thrown. If so, display the message and end the program." + +### Program execution +The following shows the output of the AWS IoT Fleetwise Basics scenario. + +``` + WS IoT FleetWise is a managed service that simplifies the + process of collecting, organizing, and transmitting vehicle + data to the cloud in near real-time. Designed for automakers + and fleet operators, it allows you to define vehicle models, + specify the exact data you want to collect (such as engine + temperature, speed, or battery status), and send this data to + AWS for analysis. By using intelligent data collection + techniques, IoT FleetWise reduces the volume of data + transmitted by filtering and transforming it at the edge, + helping to minimize bandwidth usage and costs. + +At its core, AWS IoT FleetWise helps organizations build +scalable systems for vehicle data management and analytics, +supporting a wide variety of vehicles and sensor configurations. +You can define signal catalogs and decoder manifests that describe +how raw CAN bus signals are translated into readable data, making +the platform highly flexible and extensible. This allows +manufacturers to optimize vehicle performance, improve safety, +and reduce maintenance costs by gaining real-time visibility +into fleet operations. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +1. Creates a collection of standardized signals that can be reused to create vehicle models +The collection ARN is arn:aws:iotfleetwise:us-east-1:814548047983:signal-catalog/catalog60 + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +2. Create a fleet that represents a group of vehicles +Creating an IoT FleetWise fleet allows you to efficiently collect, +organize, and transfer vehicle data to the cloud, enabling real-time +insights into vehicle performance and health. + +It helps reduce data costs by allowing you to filter and prioritize +only the most relevant vehicle signals, supporting advanced analytics +and predictive maintenance use cases. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +The fleet Id is fleet60 + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +3. Create a model manifest +An AWS IoT FleetWise manifest defines the structure and +relationships of vehicle data. The model manifest specifies +which signals to collect and how they relate to vehicle systems, +while the decoder manifest defines how to decode raw vehicle data +into meaningful signals. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +The manifest ARN is arn:aws:iotfleetwise:us-east-1:814548047983:model-manifest/manifest60 + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +4. Create a decoder manifest +A decoder manifest in AWS IoT FleetWise defines how raw vehicle +data (such as CAN signals) should be interpreted and decoded +into meaningful signals. It acts as a translation layer +that maps vehicle-specific protocols to standardized data formats +using decoding rules. This is crucial for extracting usable +data from different vehicle models, even when their data +formats vary. + + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +The decoder manifest ARN is arn:aws:iotfleetwise:us-east-1:814548047983:decoder-manifest/decManifest60 + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +5. Check the status of the model manifest +The model manifest must be in an ACTIVE state before it can be used +to create or update a vehicle. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +Elapsed: 0s | Status: DRAFT +Elapsed: 1s | Status: DRAFT +Elapsed: 2s | Status: DRAFT +Elapsed: 3s | Status: DRAFT +Elapsed: 4s | Status: DRAFT +Elapsed: 5s | Status: ACTIVE + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +6. Check the status of the decoder +The decoder manifest must be in an ACTIVE state before it can be used +to create or update a vehicle. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + + Elapsed: 0s | Decoder Status: DRAFT + Elapsed: 1s | Decoder Status: DRAFT + Elapsed: 2s | Decoder Status: DRAFT + Elapsed: 3s | Decoder Status: DRAFT + Elapsed: 4s | Decoder Status: DRAFT + Elapsed: 5s | Decoder Status: ACTIVE + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +7. Create an IoT Thing +AWS IoT FleetWise expects an existing AWS IoT Thing with the same +name as the vehicle name you are passing to createVehicle method. +Before calling createVehicle(), you must create an AWS IoT Thing +with the same name using the AWS IoT Core service. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +IoT Thing created: vehicle60 + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +8. Create a vehicle +Creating a vehicle in AWS IoT FleetWise allows you to digitally +represent and manage a physical vehicle within the AWS ecosystem. +This enables efficient ingestion, transformation, and transmission +of vehicle telemetry data to the cloud for analysis. + + +Enter 'c' followed by to continue: +c +Continuing with the program... + +Vehicle 'vehicle60' created successfully. + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +9. Display vehicle details + +Enter 'c' followed by to continue: +c +Continuing with the program... + +Vehicle Details: +• modelManifestArn : arn:aws:iotfleetwise:us-east-1:814548047983:model-manifest/manifest60 +• vehicleName : vehicle60 +• creationTime : 2025-04-29T16:00:02.147Z +• lastModificationTime : 2025-04-29T16:00:02.147Z +• decoderManifestArn : arn:aws:iotfleetwise:us-east-1:814548047983:decoder-manifest/decManifest60 +• attributes : {} +• arn : arn:aws:iotfleetwise:us-east-1:814548047983:vehicle/vehicle60 + +Enter 'c' followed by to continue: +c +Continuing with the program... + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +10. Delete the AWS IoT Fleetwise Assets +Would you like to delete the IoT Fleetwise Assets? (y/n) +y +vehicle60 was successfully deleted +decManifest60 was successfully deleted +manifest60 was successfully deleted +fleet60 was successfully deleted +catalog60 was successfully deleted +-------------------------------------------------------------------------------- +Thank you for checking out the AWS IoT Fleetwise Service Use demo. We hope you +learned something new, or got some inspiration for your own apps today. +For more AWS code examples, have a look at: +https://docs.aws.amazon.com/code-library/latest/ug/what-is-code-library.html + +-------------------------------------------------------------------------------- +``` + +## SOS Tags + +The following table describes the metadata used in this Basics Scenario. + + +| action | metadata file | metadata key | +|------------------------|----------------------------|------------------------------------- | +|`createSignalCatalog` |iot_fleetwise_metadata.yaml |iotfleetwise_CreateSignalCatalog | +|`createFleet` |iot_fleetwise_metadata.yaml |iotfleetwise_CreateFleet | +|`createGateway ` |iot_fleetwise_metadata.yaml |iotfleetwise_CreateGateway | +|`createModelManifest` iot_fleetwise_metadata.yaml |iotfleetwise_CreateModelManifest | +|`createDecoderManifest` |iot_fleetwise_metadata.yaml |iotfleetwise_CreateDecoderManifest | +|`updateModelManifest` |iot_fleetwise_metadata.yaml |iotfleetwise_UpdateModelManifest | +| `createPortal` |iot_fleetwise_metadata.yaml |iotfleetwise_CreatePortal | +|`waitForModelManifest` |iot_fleetwise_metadata.yaml |iotfleetwise_WaitForModelManifest | +|`updateDecoderManifest` |iot_fleetwise_metadata.yaml |iotfleetwise_updateDecoder | +| `describeAssetModel` |iot_fleetwise_metadata.yaml |iotfleetwise_DescribeAssetModel | +| `waitForDecoder ` |iot_fleetwise_metadata.yaml |iotfleetwise_WaitForDecoder | +| `createVehicle` |iot_fleetwise_metadata.yaml |iotfleetwise_CreateVehicle | +| `getVehicle` |iot_fleetwise_metadata.yaml |iotfleetwise_GetVehicle | +| `deleteVehicle ` |iot_fleetwise_metadata.yaml |iotfleetwise_DeleteVehicle | +|`deleteDecoderManifest` |iot_fleetwise_metadata.yaml |iotfleetwise_DeleteDecoder | +| `deleteFleet ` |iot_fleetwise_metadata.yaml |iotfleetwise_DeleteFleet | +| `deleteModel` |iot_fleetwise_metadata.yaml |iotfleetwise_DeleteModel | +| `deleteSignal ` |iot_fleetwise_metadata.yaml |iotfleetwise_DeleteSignal | +| `scenario` |iot_fleetwise_metadata.yaml |iotfleetwise_Scenario | +| `hello` |iot_fleetwise_metadata.yaml |iotfleetwise_Hello | + + +