11 | * The constructs in this package will use this descriptor when naming AWS resources so that they
12 | * can be deployed into multiple environments at the same time without conflicts.
13 | */
14 | public class ApplicationEnvironment {
15 |
16 | private final String applicationName;
17 | private final String environmentName;
18 |
19 | /**
20 | * Constructor.
21 | *
22 | * @param applicationName the name of the application that you want to deploy.
23 | * @param environmentName the name of the environment the application shall be deployed into.
24 | */
25 | public ApplicationEnvironment(String applicationName, String environmentName) {
26 | this.applicationName = applicationName;
27 | this.environmentName = environmentName;
28 | }
29 |
30 | public String getApplicationName() {
31 | return applicationName;
32 | }
33 |
34 | public String getEnvironmentName() {
35 | return environmentName;
36 | }
37 |
38 | /**
39 | * Strips non-alphanumeric characters from a String since some AWS resources don't cope with
40 | * them when using them in resource names.
41 | */
42 | private String sanitize(String environmentName) {
43 | return environmentName.replaceAll("[^a-zA-Z0-9-]", "");
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return sanitize(environmentName + "-" + applicationName);
49 | }
50 |
51 | /**
52 | * Prefixes a string with the application name and environment name.
53 | */
54 | public String prefix(String string) {
55 | return this + "-" + string;
56 | }
57 |
58 | /**
59 | * Prefixes a string with the application name and environment name. Returns only the last characterLimit
60 | * characters from the name.
61 | */
62 | public String prefix(String string, int characterLimit) {
63 | String name = this + "-" + string;
64 | if (name.length() <= characterLimit) {
65 | return name;
66 | }
67 | return name.substring(name.length() - characterLimit);
68 | }
69 |
70 | public void tag(IConstruct construct) {
71 | Tags.of(construct).add("environment", environmentName);
72 | Tags.of(construct).add("application", applicationName);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/dev/stratospheric/cdk/DockerRepository.java:
--------------------------------------------------------------------------------
1 | package dev.stratospheric.cdk;
2 |
3 | import java.util.Collections;
4 | import java.util.Objects;
5 |
6 | import software.amazon.awscdk.Environment;
7 | import software.amazon.awscdk.RemovalPolicy;
8 | import software.amazon.awscdk.services.ecr.IRepository;
9 | import software.amazon.awscdk.services.ecr.LifecycleRule;
10 | import software.amazon.awscdk.services.ecr.Repository;
11 | import software.amazon.awscdk.services.iam.AccountPrincipal;
12 | import software.constructs.Construct;
13 |
14 | /**
15 | * Provisions an ECR repository for Docker images. Every user in the given account will have access
16 | * to push and pull images.
17 | */
18 | public class DockerRepository extends Construct {
19 |
20 | private final IRepository ecrRepository;
21 |
22 | public DockerRepository(
23 | final Construct scope,
24 | final String id,
25 | final Environment awsEnvironment,
26 | final DockerRepositoryInputParameters dockerRepositoryInputParameters) {
27 | super(scope, id);
28 |
29 | this.ecrRepository = Repository.Builder.create(this, "ecrRepository")
30 | .repositoryName(dockerRepositoryInputParameters.dockerRepositoryName)
31 | .removalPolicy(dockerRepositoryInputParameters.retainRegistryOnDelete ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY)
32 | .lifecycleRules(Collections.singletonList(LifecycleRule.builder()
33 | .rulePriority(1)
34 | .description("limit to " + dockerRepositoryInputParameters.maxImageCount + " images")
35 | .maxImageCount(dockerRepositoryInputParameters.maxImageCount)
36 | .build()))
37 | .build();
38 |
39 | // grant pull and push to all users of the account
40 | ecrRepository.grantPullPush(new AccountPrincipal(dockerRepositoryInputParameters.accountId));
41 | }
42 |
43 | public IRepository getEcrRepository() {
44 | return ecrRepository;
45 | }
46 |
47 | public static class DockerRepositoryInputParameters {
48 | private final String dockerRepositoryName;
49 | private final String accountId;
50 | private final int maxImageCount;
51 | private final boolean retainRegistryOnDelete;
52 |
53 | /**
54 | * @param dockerRepositoryName the name of the docker repository to create.
55 | * @param accountId ID of the AWS account which shall have permission to push and pull the Docker repository.
56 | */
57 | public DockerRepositoryInputParameters(String dockerRepositoryName, String accountId) {
58 | this.dockerRepositoryName = dockerRepositoryName;
59 | this.accountId = accountId;
60 | this.maxImageCount = 10;
61 | this.retainRegistryOnDelete = true;
62 | }
63 |
64 | /**
65 | * @param dockerRepositoryName the name of the docker repository to create.
66 | * @param accountId ID of the AWS account which shall have permission to push and pull the Docker repository.
67 | * @param maxImageCount the maximum number of images to be held in the repository before old images get deleted.
68 | */
69 | public DockerRepositoryInputParameters(String dockerRepositoryName, String accountId, int maxImageCount) {
70 | Objects.requireNonNull(accountId, "accountId must not be null");
71 | Objects.requireNonNull(dockerRepositoryName, "dockerRepositoryName must not be null");
72 | this.accountId = accountId;
73 | this.maxImageCount = maxImageCount;
74 | this.dockerRepositoryName = dockerRepositoryName;
75 | this.retainRegistryOnDelete = true;
76 | }
77 |
78 | /**
79 | * @param dockerRepositoryName the name of the docker repository to create.
80 | * @param accountId ID of the AWS account which shall have permission to push and pull the Docker repository.
81 | * @param maxImageCount the maximum number of images to be held in the repository before old images get deleted.
82 | * @param retainRegistryOnDelete indicating whether or not the container registry should be destroyed or retained on deletion.
83 | */
84 | public DockerRepositoryInputParameters(String dockerRepositoryName, String accountId, int maxImageCount, boolean retainRegistryOnDelete) {
85 | Objects.requireNonNull(accountId, "accountId must not be null");
86 | Objects.requireNonNull(dockerRepositoryName, "dockerRepositoryName must not be null");
87 | this.accountId = accountId;
88 | this.maxImageCount = maxImageCount;
89 | this.dockerRepositoryName = dockerRepositoryName;
90 | this.retainRegistryOnDelete = retainRegistryOnDelete;
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/dev/stratospheric/cdk/JumpHost.java:
--------------------------------------------------------------------------------
1 | package dev.stratospheric.cdk;
2 |
3 | import java.util.Objects;
4 |
5 | import software.amazon.awscdk.CfnOutput;
6 | import software.amazon.awscdk.Environment;
7 | import software.amazon.awscdk.services.ec2.CfnInstance;
8 | import software.amazon.awscdk.services.ec2.CfnSecurityGroup;
9 | import software.amazon.awscdk.services.ec2.CfnSecurityGroupIngress;
10 | import software.constructs.Construct;
11 |
12 | import static java.util.Collections.singletonList;
13 |
14 | /**
15 | * A stack that deploys an EC2 instance to use as a jump host (or "bastion host") to create an SSH tunnel to the RDS instance.
16 | * The jump host is placed into the public subnets of a given VPC and it will have access the database's security group.
17 | *
18 | * The following parameters need to exist in the SSM parameter store for this stack to successfully deploy: 19 | *
26 | * The stack creates its public IP address as output, so you can look up its IP address in the CloudFormation AWS console 27 | * when you need it to access it via SSH. 28 | */ 29 | public class JumpHost extends Construct { 30 | 31 | private final ApplicationEnvironment applicationEnvironment; 32 | 33 | public JumpHost( 34 | final Construct scope, 35 | final String id, 36 | final Environment environment, 37 | final ApplicationEnvironment applicationEnvironment, 38 | final JumpHostInputParameters jumpHostInputParameters, 39 | final PostgresDatabase.DatabaseOutputParameters databaseOutputParameters) { 40 | 41 | super(scope, id); 42 | 43 | this.applicationEnvironment = applicationEnvironment; 44 | 45 | Network.NetworkOutputParameters networkOutputParameters = Network.getOutputParametersFromParameterStore(this, applicationEnvironment.getEnvironmentName()); 46 | 47 | CfnSecurityGroup jumpHostSecurityGroup = CfnSecurityGroup.Builder.create(this, "securityGroup") 48 | .groupName(applicationEnvironment.prefix("jumpHostSecurityGroup")) 49 | .groupDescription("SecurityGroup containing the jump host") 50 | .vpcId(networkOutputParameters.getVpcId()) 51 | .build(); 52 | 53 | String databaseSecurityGroupId = databaseOutputParameters.getDatabaseSecurityGroupId(); 54 | 55 | allowAccessToJumpHost(jumpHostSecurityGroup); 56 | allowAccessToDatabase(jumpHostSecurityGroup, databaseSecurityGroupId); 57 | 58 | CfnInstance instance = createEc2Instance( 59 | jumpHostInputParameters.keyName, 60 | jumpHostSecurityGroup, 61 | networkOutputParameters); 62 | 63 | CfnOutput publicIpOutput = CfnOutput.Builder.create(this, "publicIp") 64 | .value(instance.getAttrPublicIp()) 65 | .build(); 66 | 67 | applicationEnvironment.tag(this); 68 | 69 | } 70 | 71 | private CfnInstance createEc2Instance( 72 | String keyName, 73 | CfnSecurityGroup jumpHostSecurityGroup, 74 | Network.NetworkOutputParameters networkOutputParameters) { 75 | 76 | return CfnInstance.Builder.create(this, "jumpHostInstance") 77 | .instanceType("t2.nano") 78 | .securityGroupIds(singletonList(jumpHostSecurityGroup.getAttrGroupId())) 79 | .imageId("ami-0f96495a064477ffb") 80 | .subnetId(networkOutputParameters.getPublicSubnets().get(0)) 81 | .keyName(keyName) 82 | .build(); 83 | 84 | } 85 | 86 | private void allowAccessToDatabase(CfnSecurityGroup fromSecurityGroup, String toSecurityGroupId) { 87 | CfnSecurityGroupIngress dbSecurityGroupIngress = CfnSecurityGroupIngress.Builder.create(this, "IngressFromJumpHost") 88 | .sourceSecurityGroupId(fromSecurityGroup.getAttrGroupId()) 89 | .groupId(toSecurityGroupId) 90 | .fromPort(5432) 91 | .toPort(5432) 92 | .ipProtocol("TCP") 93 | .build(); 94 | } 95 | 96 | private void allowAccessToJumpHost(CfnSecurityGroup jumpHostSecurityGroup) { 97 | CfnSecurityGroupIngress jumpHostSecurityGroupIngress = CfnSecurityGroupIngress.Builder.create(this, "IngressFromOutside") 98 | .groupId(jumpHostSecurityGroup.getAttrGroupId()) 99 | .fromPort(22) 100 | .toPort(22) 101 | .ipProtocol("TCP") 102 | .cidrIp("0.0.0.0/0") 103 | .build(); 104 | } 105 | 106 | public static class JumpHostInputParameters { 107 | private final String keyName; 108 | 109 | /** 110 | * @param keyName the name of the key pair that will be installed in the jump host EC2 instance so you can 111 | * access it via SSH. This key pair must be created via the EC2 console beforehand. 112 | */ 113 | public JumpHostInputParameters(String keyName) { 114 | Objects.requireNonNull(keyName, "parameter 'keyName' cannot be null"); 115 | this.keyName = keyName; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/dev/stratospheric/cdk/Network.java: -------------------------------------------------------------------------------- 1 | package dev.stratospheric.cdk; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Objects; 6 | import java.util.Optional; 7 | import java.util.stream.Collectors; 8 | 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | import software.amazon.awscdk.Duration; 12 | import software.amazon.awscdk.Environment; 13 | import software.amazon.awscdk.Tags; 14 | import software.amazon.awscdk.services.ec2.CfnSecurityGroupIngress; 15 | import software.amazon.awscdk.services.ec2.ISecurityGroup; 16 | import software.amazon.awscdk.services.ec2.ISubnet; 17 | import software.amazon.awscdk.services.ec2.IVpc; 18 | import software.amazon.awscdk.services.ec2.SecurityGroup; 19 | import software.amazon.awscdk.services.ec2.SubnetConfiguration; 20 | import software.amazon.awscdk.services.ec2.SubnetType; 21 | import software.amazon.awscdk.services.ec2.Vpc; 22 | import software.amazon.awscdk.services.ecs.Cluster; 23 | import software.amazon.awscdk.services.ecs.ICluster; 24 | import software.amazon.awscdk.services.elasticloadbalancingv2.*; 25 | import software.amazon.awscdk.services.ssm.StringParameter; 26 | import software.constructs.Construct; 27 | 28 | import static java.util.Arrays.asList; 29 | 30 | /** 31 | * Creates a base network for an application served by ECS. The network stack contains a VPC, 32 | * two public and two isolated subnets, an ECS cluster, and an internet-facing load balancer with an HTTP and 33 | * an optional HTTPS listener. The listeners can be used in other stacks to attach to an ECS service, 34 | * for instance. 35 | *
36 | * The construct exposes some output parameters to be used by other constructs. You can access them by: 37 | *
21 | * The following parameters need to exist in the SSM parameter store for this stack to successfully deploy: 22 | *
30 | * The stack exposes the following output parameters in the SSM parameter store to be used in other stacks: 31 | *
245 | * Default: 20. 246 | */ 247 | public DatabaseInputParameters withStorageInGb(int storageInGb) { 248 | this.storageInGb = storageInGb; 249 | return this; 250 | } 251 | 252 | /** 253 | * The class of the database instance. 254 | *
255 | * Default: "db.t2.micro". 256 | */ 257 | public DatabaseInputParameters withInstanceClass(String instanceClass) { 258 | Objects.requireNonNull(instanceClass); 259 | this.instanceClass = instanceClass; 260 | return this; 261 | } 262 | 263 | /** 264 | * The version of the PostGres database. 265 | *
266 | * Default: "11.5".
267 | */
268 | public DatabaseInputParameters withPostgresVersion(String postgresVersion) {
269 | Objects.requireNonNull(postgresVersion);
270 | this.postgresVersion = postgresVersion;
271 | return this;
272 | }
273 |
274 | }
275 |
276 | public static class DatabaseOutputParameters {
277 | private final String endpointAddress;
278 | private final String endpointPort;
279 | private final String dbName;
280 | private final String databaseSecretArn;
281 | private final String databaseSecurityGroupId;
282 | private final String instanceId;
283 |
284 | public DatabaseOutputParameters(
285 | String endpointAddress,
286 | String endpointPort,
287 | String dbName,
288 | String databaseSecretArn,
289 | String databaseSecurityGroupId,
290 | String instanceId) {
291 | this.endpointAddress = endpointAddress;
292 | this.endpointPort = endpointPort;
293 | this.dbName = dbName;
294 | this.databaseSecretArn = databaseSecretArn;
295 | this.databaseSecurityGroupId = databaseSecurityGroupId;
296 | this.instanceId = instanceId;
297 | }
298 |
299 | /**
300 | * The URL of the Postgres instance.
301 | */
302 | public String getEndpointAddress() {
303 | return endpointAddress;
304 | }
305 |
306 |
307 | /**
308 | * The port of the Postgres instance.
309 | */
310 | public String getEndpointPort() {
311 | return endpointPort;
312 | }
313 |
314 | /**
315 | * The database name of the Postgres instance.
316 | */
317 | public String getDbName() {
318 | return dbName;
319 | }
320 |
321 | /**
322 | * The secret containing username and password.
323 | */
324 | public String getDatabaseSecretArn() {
325 | return databaseSecretArn;
326 | }
327 |
328 | /**
329 | * The database's security group.
330 | */
331 | public String getDatabaseSecurityGroupId() {
332 | return databaseSecurityGroupId;
333 | }
334 |
335 | /**
336 | * The database's identifier.
337 | */
338 | public String getInstanceId() {
339 | return instanceId;
340 | }
341 | }
342 | }
343 |
--------------------------------------------------------------------------------
/src/main/java/dev/stratospheric/cdk/Service.java:
--------------------------------------------------------------------------------
1 | package dev.stratospheric.cdk;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.Collections;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.Objects;
9 | import java.util.Optional;
10 |
11 | import software.amazon.awscdk.CfnCondition;
12 | import software.amazon.awscdk.Environment;
13 | import software.amazon.awscdk.Fn;
14 | import software.amazon.awscdk.RemovalPolicy;
15 | import software.amazon.awscdk.services.ec2.CfnSecurityGroup;
16 | import software.amazon.awscdk.services.ec2.CfnSecurityGroupIngress;
17 | import software.amazon.awscdk.services.ecr.IRepository;
18 | import software.amazon.awscdk.services.ecr.Repository;
19 | import software.amazon.awscdk.services.ecs.CfnService;
20 | import software.amazon.awscdk.services.ecs.CfnTaskDefinition;
21 | import software.amazon.awscdk.services.elasticloadbalancingv2.CfnListenerRule;
22 | import software.amazon.awscdk.services.elasticloadbalancingv2.CfnTargetGroup;
23 | import software.amazon.awscdk.services.iam.Effect;
24 | import software.amazon.awscdk.services.iam.PolicyDocument;
25 | import software.amazon.awscdk.services.iam.PolicyStatement;
26 | import software.amazon.awscdk.services.iam.Role;
27 | import software.amazon.awscdk.services.iam.ServicePrincipal;
28 | import software.amazon.awscdk.services.logs.LogGroup;
29 | import software.amazon.awscdk.services.logs.RetentionDays;
30 | import software.constructs.Construct;
31 |
32 | import static java.util.Collections.singletonList;
33 |
34 | /**
35 | * Creates an ECS service on top of a {@link Network}. Loads Docker images from a {@link DockerImageSource}
36 | * and places them into ECS task. Creates a log group for each ECS task. Creates a target group for the ECS tasks
37 | * that is attached to the load balancer from the {@link Network}.
38 | */
39 | public class Service extends Construct {
40 |
41 | public Service(
42 | final Construct scope,
43 | final String id,
44 | final Environment awsEnvironment,
45 | final ApplicationEnvironment applicationEnvironment,
46 | final ServiceInputParameters serviceInputParameters,
47 | final Network.NetworkOutputParameters networkOutputParameters) {
48 | super(scope, id);
49 |
50 | List
375 | * Default: 15.
376 | */
377 | public ServiceInputParameters withHealthCheckIntervalSeconds(int healthCheckIntervalSeconds) {
378 | this.healthCheckIntervalSeconds = healthCheckIntervalSeconds;
379 | return this;
380 | }
381 |
382 | /**
383 | * The path of the health check URL.
384 | *
385 | * Default: "/actuator/health".
386 | */
387 | public ServiceInputParameters withHealthCheckPath(String healthCheckPath) {
388 | Objects.requireNonNull(healthCheckPath);
389 | this.healthCheckPath = healthCheckPath;
390 | return this;
391 | }
392 |
393 | /**
394 | * The port the application listens on within the container.
395 | *
396 | * Default: 8080.
397 | */
398 | public ServiceInputParameters withContainerPort(int containerPort) {
399 | Objects.requireNonNull(containerPort);
400 | this.containerPort = containerPort;
401 | return this;
402 | }
403 |
404 | /**
405 | * The protocol to access the application within the container. Default: "HTTP".
406 | */
407 | public ServiceInputParameters withContainerProtocol(String containerProtocol) {
408 | Objects.requireNonNull(containerProtocol);
409 | this.containerProtocol = containerProtocol;
410 | return this;
411 | }
412 |
413 | /**
414 | * The number of seconds to wait for a response until a health check is deemed unsuccessful.
415 | *
416 | * Default: 5.
417 | */
418 | public ServiceInputParameters withHealthCheckTimeoutSeconds(int healthCheckTimeoutSeconds) {
419 | this.healthCheckTimeoutSeconds = healthCheckTimeoutSeconds;
420 | return this;
421 | }
422 |
423 | /**
424 | * The number of consecutive successful health checks after which an instance is declared healthy.
425 | *
426 | * Default: 2.
427 | */
428 | public ServiceInputParameters withHealthyThresholdCount(int healthyThresholdCount) {
429 | this.healthyThresholdCount = healthyThresholdCount;
430 | return this;
431 | }
432 |
433 | /**
434 | * The number of consecutive unsuccessful health checks after which an instance is declared unhealthy.
435 | *
436 | * Default: 8.
437 | */
438 | public ServiceInputParameters withUnhealthyThresholdCount(int unhealthyThresholdCount) {
439 | this.unhealthyThresholdCount = unhealthyThresholdCount;
440 | return this;
441 | }
442 |
443 | /**
444 | * The number of CPU units allocated to each instance of the application. See
445 | * the docs
446 | * for a table of valid values.
447 | *
448 | * Default: 256 (0.25 CPUs).
449 | */
450 | public ServiceInputParameters withCpu(int cpu) {
451 | this.cpu = cpu;
452 | return this;
453 | }
454 |
455 | /**
456 | * The memory allocated to each instance of the application in megabytes. See
457 | * the docs
458 | * for a table of valid values.
459 | *
460 | * Default: 512.
461 | */
462 | public ServiceInputParameters withMemory(int memory) {
463 | this.memory = memory;
464 | return this;
465 | }
466 |
467 | /**
468 | * The duration the logs of the application should be retained.
469 | *
470 | * Default: 1 week.
471 | */
472 | public ServiceInputParameters withLogRetention(RetentionDays logRetention) {
473 | Objects.requireNonNull(logRetention);
474 | this.logRetention = logRetention;
475 | return this;
476 | }
477 |
478 | /**
479 | * The number of instances that should run in parallel behind the load balancer.
480 | *
481 | * Default: 2.
482 | */
483 | public ServiceInputParameters withDesiredInstances(int desiredInstances) {
484 | this.desiredInstancesCount = desiredInstances;
485 | return this;
486 | }
487 |
488 | /**
489 | * The maximum percentage in relation to the desired instances that may be running at the same time
490 | * (for example during deployments).
491 | *
492 | * Default: 200.
493 | */
494 | public ServiceInputParameters withMaximumInstancesPercent(int maximumInstancesPercent) {
495 | this.maximumInstancesPercent = maximumInstancesPercent;
496 | return this;
497 | }
498 |
499 | /**
500 | * The minimum percentage in relation to the desired instances that must be running at the same time
501 | * (for example during deployments).
502 | *
503 | * Default: 50.
504 | */
505 | public ServiceInputParameters withMinimumHealthyInstancesPercent(int minimumHealthyInstancesPercent) {
506 | this.minimumHealthyInstancesPercent = minimumHealthyInstancesPercent;
507 | return this;
508 | }
509 |
510 | /**
511 | * The list of PolicyStatement objects that define which operations this service can perform on other
512 | * AWS resources (for example ALLOW sqs:GetQueueUrl for all SQS queues).
513 | *
514 | * Default: none (empty list).
515 | */
516 | public ServiceInputParameters withTaskRolePolicyStatements(List
524 | * Default: false.
525 | */
526 | public ServiceInputParameters withStickySessionsEnabled(boolean stickySessionsEnabled) {
527 | this.stickySessionsEnabled = stickySessionsEnabled;
528 | return this;
529 | }
530 |
531 | /**
532 | * The format of the date time used in log entries. The awslogs driver will use this pattern to extract
533 | * the timestamp from a log event and also to distinguish between multiple multi-line log events.
534 | *
535 | * Default: %Y-%m-%dT%H:%M:%S.%f%z (to work with JSON formatted logs created with awslogs JSON Encoder).
536 | *
537 | * See also: awslogs driver
538 | */
539 | public ServiceInputParameters withAwsLogsDateTimeFormat(String awsLogsDateTimeFormat) {
540 | this.awslogsDateTimeFormat = awsLogsDateTimeFormat;
541 | return this;
542 | }
543 |
544 | /**
545 | * The priority for the HTTP listener of the loadbalancer. The priority of two listeners must not be the same
546 | * so you need to choose different priorities for different services.
547 | */
548 | public ServiceInputParameters withHttpListenerPriority(int priority) {
549 | this.httpListenerPriority = priority;
550 | return this;
551 | }
552 |
553 | }
554 | }
555 |
--------------------------------------------------------------------------------
/src/main/java/dev/stratospheric/cdk/SpringBootApplicationStack.java:
--------------------------------------------------------------------------------
1 | package dev.stratospheric.cdk;
2 |
3 | import java.util.Collections;
4 |
5 | import software.amazon.awscdk.CfnOutput;
6 | import software.amazon.awscdk.CfnOutputProps;
7 | import software.amazon.awscdk.Environment;
8 | import software.amazon.awscdk.Stack;
9 | import software.amazon.awscdk.StackProps;
10 | import software.constructs.Construct;
11 |
12 | /**
13 | * This stack creates a {@link Network} and a {@link Service} that deploys a given Docker image. The {@link Service} is
14 | * pre-configured for a Spring Boot application.
15 | *
16 | * This construct is for demonstration purposes since it's not configurable and thus of little practical use.
17 | */
18 | public class SpringBootApplicationStack extends Stack {
19 |
20 | public SpringBootApplicationStack(
21 | final Construct scope,
22 | final String id,
23 | final Environment environment,
24 | final String dockerImageUrl) {
25 | super(scope, id, StackProps.builder()
26 | .stackName("SpringBootApplication")
27 | .env(environment)
28 | .build());
29 |
30 |
31 | Network network = new Network(this, "network", environment, "prod", new Network.NetworkInputParameters());
32 | Service service = new Service(this, "Service", environment, new ApplicationEnvironment("SpringBootApplication", "prod"),
33 | new Service.ServiceInputParameters(
34 | new Service.DockerImageSource(dockerImageUrl),
35 | Collections.emptyList(),
36 | Collections.emptyMap()),
37 | network.getOutputParameters());
38 |
39 | CfnOutput httpsListenerOutput = new CfnOutput(this, "loadbalancerDnsName", CfnOutputProps.builder()
40 | .exportName("loadbalancerDnsName")
41 | .value(network.getLoadBalancer().getLoadBalancerDnsName())
42 | .build());
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/dev/stratospheric/cdk/ApplicationEnvironmentTest.java:
--------------------------------------------------------------------------------
1 | package dev.stratospheric.cdk;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.assertj.core.api.Assertions.assertThat;
6 |
7 | class ApplicationEnvironmentTest {
8 |
9 | @Test
10 | void prefix(){
11 | ApplicationEnvironment env = new ApplicationEnvironment("myapp", "prod");
12 | assertThat(env.prefix("foo")).isEqualTo("prod-myapp-foo");
13 | }
14 |
15 | @Test
16 | void longPrefix(){
17 | ApplicationEnvironment env = new ApplicationEnvironment("my-long-application-name", "my-long-env-name");
18 | assertThat(env.prefix("my-long-prefix", 20)).isEqualTo("-name-my-long-prefix");
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------