From edfed31fc7927f6ddffa5b4a1ea47580fcf873b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wrzeszcz?= Date: Thu, 28 Mar 2019 14:30:19 +0100 Subject: [PATCH] Changed structure of organization handler return data as CloudFormation seems to not support complex structures for custom resources. --- .../src/site/markdown/guide/usage.md | 2 +- .../lambda/cform/organization/Handler.java | 4 +- .../model/OrganizationResponse.java | 32 ++++++++ .../model/OrganizationWithRoot.java | 31 ------- .../service/OrganizationManager.java | 13 ++- .../src/site/markdown/guide/usage.md | 16 ++-- .../cform/organization/HandlerTest.java | 12 +-- .../service/OrganizationManagerTest.java | 81 ++++++++++++------- 8 files changed, 110 insertions(+), 81 deletions(-) create mode 100644 lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationResponse.java delete mode 100644 lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationWithRoot.java diff --git a/lambda-cform/lambda-cform-organization-unit/src/site/markdown/guide/usage.md b/lambda-cform/lambda-cform-organization-unit/src/site/markdown/guide/usage.md index 9ed6111fb..776d9b561 100644 --- a/lambda-cform/lambda-cform-organization-unit/src/site/markdown/guide/usage.md +++ b/lambda-cform/lambda-cform-organization-unit/src/site/markdown/guide/usage.md @@ -103,5 +103,5 @@ object. ServiceToken: !GetAtt "OrganizationUnitManager.Arn" name: "internal services" # assume Organization is a resource created by lambda-cform-organization handler - parentId: !GetAtt "Organization.Root.Id" + parentId: !GetAtt "Organization.rootId" ``` diff --git a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/Handler.java b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/Handler.java index a29c95318..5cc86402b 100644 --- a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/Handler.java +++ b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/Handler.java @@ -13,7 +13,7 @@ import com.sunrun.cfnresponse.CfnRequest; import pl.wrzasq.commons.aws.cloudformation.CustomResourceHandler; import pl.wrzasq.lambda.cform.organization.model.OrganizationRequest; -import pl.wrzasq.lambda.cform.organization.model.OrganizationWithRoot; +import pl.wrzasq.lambda.cform.organization.model.OrganizationResponse; import pl.wrzasq.lambda.cform.organization.service.OrganizationManager; /** @@ -26,7 +26,7 @@ public class Handler /** * CloudFormation response handler. */ - private static CustomResourceHandler handler; + private static CustomResourceHandler handler; static { AWSOrganizations organizations = AWSOrganizationsClientBuilder.defaultClient(); diff --git a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationResponse.java b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationResponse.java new file mode 100644 index 000000000..357911a80 --- /dev/null +++ b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationResponse.java @@ -0,0 +1,32 @@ +/* + * This file is part of the pl.wrzasq.lambda. + * + * @license http://mit-license.org/ The MIT license + * @copyright 2019 © by Rafał Wrzeszcz - Wrzasq.pl. + */ + +package pl.wrzasq.lambda.cform.organization.model; + +import lombok.Data; + +/** + * Organization data response model. + */ +@Data +public class OrganizationResponse +{ + /** + * Organization ID. + */ + private String id; + + /** + * Organization ARN. + */ + private String arn; + + /** + * Root organizational unit ID. + */ + private String rootId; +} diff --git a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationWithRoot.java b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationWithRoot.java deleted file mode 100644 index af24e8494..000000000 --- a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/model/OrganizationWithRoot.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the pl.wrzasq.lambda. - * - * @license http://mit-license.org/ The MIT license - * @copyright 2019 © by Rafał Wrzeszcz - Wrzasq.pl. - */ - -package pl.wrzasq.lambda.cform.organization.model; - -import com.amazonaws.services.organizations.model.Organization; -import com.amazonaws.services.organizations.model.Root; -import lombok.AllArgsConstructor; -import lombok.Data; - -/** - * Extended Organization model that contains root ID. - */ -@Data -@AllArgsConstructor -public class OrganizationWithRoot -{ - /** - * Organization data. - */ - private Organization organization; - - /** - * Root organizational unit. - */ - private Root root; -} diff --git a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/service/OrganizationManager.java b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/service/OrganizationManager.java index 6fd3c18e6..bfcd213d9 100644 --- a/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/service/OrganizationManager.java +++ b/lambda-cform/lambda-cform-organization/src/main/java/pl/wrzasq/lambda/cform/organization/service/OrganizationManager.java @@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory; import pl.wrzasq.commons.aws.cloudformation.CustomResourceResponse; import pl.wrzasq.lambda.cform.organization.model.OrganizationRequest; -import pl.wrzasq.lambda.cform.organization.model.OrganizationWithRoot; +import pl.wrzasq.lambda.cform.organization.model.OrganizationResponse; /** * Organizations API implementation. @@ -59,7 +59,7 @@ public OrganizationManager(AWSOrganizations organizations) * @param physicalResourceId Physical ID of existing resource (if present). * @return Data about published version. */ - public CustomResourceResponse sync(OrganizationRequest input, String physicalResourceId) + public CustomResourceResponse sync(OrganizationRequest input, String physicalResourceId) { Organization organization; try { @@ -94,7 +94,12 @@ public CustomResourceResponse sync(OrganizationRequest inp Root root = this.organizations.listRoots(new ListRootsRequest()).getRoots().get(0); - return new CustomResourceResponse<>(new OrganizationWithRoot(organization, root), organization.getId()); + OrganizationResponse organizationResponse = new OrganizationResponse(); + organizationResponse.setId(organization.getId()); + organizationResponse.setArn(organization.getArn()); + organizationResponse.setRootId(root.getId()); + + return new CustomResourceResponse<>(organizationResponse, organization.getId()); } /** @@ -104,7 +109,7 @@ public CustomResourceResponse sync(OrganizationRequest inp * @param physicalResourceId Physical ID of existing resource (if present). * @return Empty response. */ - public CustomResourceResponse delete(OrganizationRequest input, String physicalResourceId) + public CustomResourceResponse delete(OrganizationRequest input, String physicalResourceId) { Organization organization = this.organizations.describeOrganization( new DescribeOrganizationRequest() diff --git a/lambda-cform/lambda-cform-organization/src/site/markdown/guide/usage.md b/lambda-cform/lambda-cform-organization/src/site/markdown/guide/usage.md index 2b76171f0..cd56a814c 100644 --- a/lambda-cform/lambda-cform-organization/src/site/markdown/guide/usage.md +++ b/lambda-cform/lambda-cform-organization/src/site/markdown/guide/usage.md @@ -35,21 +35,19 @@ Specifies set of features enabled for accounts in organization. Can be either `C # Output values -Deploy handler exposes structure with two elements: +Deploy handler exposes following data structure: ```json { - "organization": object, - "root": object + "id": string, + "arn": string, + "rootId": stirng } ``` -- `organization`: entire -[Organization](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/iam/model/Organization.html) -object; -- `root`: entire -[Root](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/organizations/model/Root.html) -object. +- `id`: organization ID; +- `arn`: organization ARN; +- `rootId`: root organizational unit ID. **Note:** Custom resource physical ID is set as created organization ID. diff --git a/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/HandlerTest.java b/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/HandlerTest.java index 767f193ea..1974555ee 100644 --- a/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/HandlerTest.java +++ b/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/HandlerTest.java @@ -21,18 +21,18 @@ import pl.wrzasq.commons.aws.cloudformation.CustomResourceHandler; import pl.wrzasq.lambda.cform.organization.Handler; import pl.wrzasq.lambda.cform.organization.model.OrganizationRequest; -import pl.wrzasq.lambda.cform.organization.model.OrganizationWithRoot; +import pl.wrzasq.lambda.cform.organization.model.OrganizationResponse; @ExtendWith(MockitoExtension.class) public class HandlerTest { @Mock - private CustomResourceHandler handler; + private CustomResourceHandler handler; @Mock private Context context; - private CustomResourceHandler originalHandler; + private CustomResourceHandler originalHandler; @BeforeEach public void setUp() throws NoSuchFieldException, IllegalAccessException @@ -58,14 +58,14 @@ public void handle() Mockito.verify(this.handler).handle(request, this.context); } - private CustomResourceHandler setHandler( - CustomResourceHandler sender + private CustomResourceHandler setHandler( + CustomResourceHandler sender ) throws NoSuchFieldException, IllegalAccessException { Field hack = Handler.class.getDeclaredField("handler"); hack.setAccessible(true); - CustomResourceHandler original + CustomResourceHandler original = CustomResourceHandler.class.cast(hack.get(null)); hack.set(null, sender); return original; diff --git a/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/service/OrganizationManagerTest.java b/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/service/OrganizationManagerTest.java index 4cdc1aa4e..11deb5bf0 100644 --- a/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/service/OrganizationManagerTest.java +++ b/lambda-cform/lambda-cform-organization/src/test/java/test/pl/wrzasq/lambda/cform/organization/service/OrganizationManagerTest.java @@ -29,7 +29,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import pl.wrzasq.commons.aws.cloudformation.CustomResourceResponse; import pl.wrzasq.lambda.cform.organization.model.OrganizationRequest; -import pl.wrzasq.lambda.cform.organization.model.OrganizationWithRoot; +import pl.wrzasq.lambda.cform.organization.model.OrganizationResponse; import pl.wrzasq.lambda.cform.organization.service.OrganizationManager; @ExtendWith(MockitoExtension.class) @@ -41,6 +41,10 @@ public class OrganizationManagerTest private static final String PHYSICAL_ID_2 = "o-another"; + private static final String ARN = "arn:aws:test"; + + private static final String ROOT_ID = "r-root"; + @Mock private AWSOrganizations organizations; @@ -51,8 +55,10 @@ public class OrganizationManagerTest public void sync() { Organization organization = new Organization() - .withId(OrganizationManagerTest.PHYSICAL_ID_1); - Root root = new Root(); + .withId(OrganizationManagerTest.PHYSICAL_ID_1) + .withArn(OrganizationManagerTest.ARN); + Root root = new Root() + .withId(OrganizationManagerTest.ROOT_ID); OrganizationManager manager = new OrganizationManager(this.organizations); @@ -75,7 +81,7 @@ public void sync() .withRoots(root) ); - CustomResourceResponse result = manager.sync(input, null); + CustomResourceResponse result = manager.sync(input, null); Mockito.verify(this.organizations).describeOrganization(Mockito.any(DescribeOrganizationRequest.class)); Mockito.verify(this.organizations).createOrganization(Mockito.any(CreateOrganizationRequest.class)); @@ -85,15 +91,20 @@ public void sync() this.createRequest.getValue().getFeatureSet(), "OrganizationManager.sync() should pass specified feature set for created organization." ); + Assertions.assertEquals( + OrganizationManagerTest.PHYSICAL_ID_1, + result.getData().getId(), + "OrganizationManager.sync() should return ID of created organization." + ); Assertions.assertSame( - organization, - result.getData().getOrganization(), - "OrganizationManager.sync() should return organization data of created organization." + OrganizationManagerTest.ARN, + result.getData().getArn(), + "OrganizationManager.sync() should return ARN of created organization." ); Assertions.assertSame( - root, - result.getData().getRoot(), - "OrganizationManager.sync() should return organization root of created organization." + OrganizationManagerTest.ROOT_ID, + result.getData().getRootId(), + "OrganizationManager.sync() should return ID of created organization root unit." ); Assertions.assertEquals( OrganizationManagerTest.PHYSICAL_ID_1, @@ -106,8 +117,10 @@ public void sync() public void syncAlreadyExists() { Organization organization = new Organization() - .withId(OrganizationManagerTest.PHYSICAL_ID_1); - Root root = new Root(); + .withId(OrganizationManagerTest.PHYSICAL_ID_1) + .withArn(OrganizationManagerTest.ARN); + Root root = new Root() + .withId(OrganizationManagerTest.ROOT_ID); OrganizationManager manager = new OrganizationManager(this.organizations); @@ -126,7 +139,7 @@ public void syncAlreadyExists() .withRoots(root) ); - CustomResourceResponse result = manager.sync( + CustomResourceResponse result = manager.sync( input, OrganizationManagerTest.PHYSICAL_ID_1 ); @@ -134,15 +147,20 @@ public void syncAlreadyExists() Mockito.verify(this.organizations).describeOrganization(Mockito.any(DescribeOrganizationRequest.class)); Mockito.verify(this.organizations, Mockito.never()).createOrganization(Mockito.any()); + Assertions.assertEquals( + OrganizationManagerTest.PHYSICAL_ID_1, + result.getData().getId(), + "OrganizationManager.sync() should return ID of existing organization." + ); Assertions.assertSame( - organization, - result.getData().getOrganization(), - "OrganizationManager.sync() should return organization data of existing organization." + OrganizationManagerTest.ARN, + result.getData().getArn(), + "OrganizationManager.sync() should return ARN of existing organization." ); Assertions.assertSame( - root, - result.getData().getRoot(), - "OrganizationManager.sync() should return organization root of existing organization." + OrganizationManagerTest.ROOT_ID, + result.getData().getRootId(), + "OrganizationManager.sync() should return ID of existing organization root unit." ); Assertions.assertEquals( OrganizationManagerTest.PHYSICAL_ID_1, @@ -155,8 +173,10 @@ public void syncAlreadyExists() public void syncAlreadyExistsOutOfSync() { Organization organization = new Organization() - .withId(OrganizationManagerTest.PHYSICAL_ID_1); - Root root = new Root(); + .withId(OrganizationManagerTest.PHYSICAL_ID_1) + .withArn(OrganizationManagerTest.ARN); + Root root = new Root() + .withId(OrganizationManagerTest.ROOT_ID); OrganizationManager manager = new OrganizationManager(this.organizations); @@ -175,7 +195,7 @@ public void syncAlreadyExistsOutOfSync() .withRoots(root) ); - CustomResourceResponse result = manager.sync( + CustomResourceResponse result = manager.sync( input, OrganizationManagerTest.PHYSICAL_ID_2 ); @@ -183,15 +203,20 @@ public void syncAlreadyExistsOutOfSync() Mockito.verify(this.organizations).describeOrganization(Mockito.any(DescribeOrganizationRequest.class)); Mockito.verify(this.organizations, Mockito.never()).createOrganization(Mockito.any()); + Assertions.assertEquals( + OrganizationManagerTest.PHYSICAL_ID_1, + result.getData().getId(), + "OrganizationManager.sync() should return ID of existing organization." + ); Assertions.assertSame( - organization, - result.getData().getOrganization(), - "OrganizationManager.sync() should return organization data of existing organization." + OrganizationManagerTest.ARN, + result.getData().getArn(), + "OrganizationManager.sync() should return ARN of existing organization." ); Assertions.assertSame( - root, - result.getData().getRoot(), - "OrganizationManager.sync() should return organization root of existing organization." + OrganizationManagerTest.ROOT_ID, + result.getData().getRootId(), + "OrganizationManager.sync() should return ID of existing organization root unit." ); Assertions.assertEquals( OrganizationManagerTest.PHYSICAL_ID_1,