From 78d747211f6d05872df737c7b12aaf9ff781e167 Mon Sep 17 00:00:00 2001 From: Justin Field Date: Mon, 15 Apr 2019 16:24:27 -0700 Subject: [PATCH] Multi-Region CMS Support (hot standby / pilot light) (#134) * Work in progress of multi-region pilot light cms update. * Fix find bugs issue * Merge master, update arg mapper tests, add missing license headers * Update CompositeOperation.java * Update WhitelistCidrForVpcAccessOperation.java --- .../com/nike/cerberus/cli/CerberusRunner.java | 6 +- .../cli/EnvironmentConfigToArgsMapper.java | 154 ++++++++++-------- .../command/cms/UpdateCmsConfigCommand.java | 2 +- .../CreateCmsResourcesForRegionCommand.java | 55 +++++++ .../CreateAlbLogAthenaDbAndTableCommand.java | 13 ++ .../core/CreateEdgeDomainRecordCommand.java | 12 ++ .../command/core/DeleteStackCommand.java | 5 +- .../WhitelistCidrForVpcAccessCommand.java | 11 ++ .../command/rds/CreateDatabaseCommand.java | 2 +- .../CloudFormationParametersDelegate.java | 13 ++ .../domain/cloudformation/CmsParameters.java | 10 +- .../domain/input/EnvironmentConfig.java | 13 +- .../CreateAuditAthenaDbAndTableOperation.java | 4 +- .../cms/CreateCmsClusterOperation.java | 42 +++-- .../operation/composite/ChainableCommand.java | 24 ++- .../composite/CompositeOperation.java | 2 +- .../CreateCmsResourcesForRegionOperation.java | 66 ++++++++ .../composite/DeleteEnvironmentOperation.java | 3 +- ...CreateAlbLogAthenaDbAndTableOperation.java | 12 +- .../core/CreateEdgeDomainRecordOperation.java | 12 +- .../core/CreateLoadBalancerOperation.java | 20 ++- .../core/CreateRoute53Operation.java | 33 ++-- .../core/CreateSecurityGroupsOperation.java | 14 +- .../operation/core/CreateVpcOperation.java | 17 +- .../WhitelistCidrForVpcAccessOperation.java | 19 ++- .../rds/CreateDatabaseOperation.java | 28 +++- .../nike/cerberus/service/AthenaService.java | 13 +- .../nike/cerberus/service/Route53Service.java | 24 +-- .../com/nike/cerberus/store/ConfigStore.java | 7 +- .../resources/cloudformation/cms-cluster.yaml | 6 +- .../EnvironmentConfigToArgsMapperTest.java | 3 + 31 files changed, 467 insertions(+), 178 deletions(-) create mode 100644 src/main/java/com/nike/cerberus/command/composite/CreateCmsResourcesForRegionCommand.java create mode 100644 src/main/java/com/nike/cerberus/operation/composite/CreateCmsResourcesForRegionOperation.java diff --git a/src/main/java/com/nike/cerberus/cli/CerberusRunner.java b/src/main/java/com/nike/cerberus/cli/CerberusRunner.java index d4777b03..43cab56c 100644 --- a/src/main/java/com/nike/cerberus/cli/CerberusRunner.java +++ b/src/main/java/com/nike/cerberus/cli/CerberusRunner.java @@ -36,15 +36,12 @@ import com.nike.cerberus.command.cms.CreateCmsClusterCommand; import com.nike.cerberus.command.cms.CreateCmsConfigCommand; import com.nike.cerberus.command.cms.UpdateCmsConfigCommand; -import com.nike.cerberus.command.composite.CreateEnvironmentCommand; -import com.nike.cerberus.command.composite.DeleteEnvironmentCommand; +import com.nike.cerberus.command.composite.*; import com.nike.cerberus.command.certificates.GenerateAndRotateCertificatesCommand; -import com.nike.cerberus.command.composite.PrintAllStackInformationCommand; import com.nike.cerberus.command.certificates.RotateCertificatesCommand; import com.nike.cerberus.command.core.CreateAlbLogAthenaDbAndTableCommand; import com.nike.cerberus.command.core.InitializeEnvironmentCommand; import com.nike.cerberus.command.core.SyncConfigCommand; -import com.nike.cerberus.command.composite.UpdateAllStackTagsCommand; import com.nike.cerberus.command.rds.CleanUpRdsSnapshotsCommand; import com.nike.cerberus.command.rds.CopyRdsSnapshotsCommand; import com.nike.cerberus.command.rds.CreateDatabaseCommand; @@ -242,6 +239,7 @@ private void registerAllCommands() { registerCommand(new UpdateAllStackTagsCommand()); registerCommand(new SyncConfigCommand()); registerCommand(new CreateAlbLogAthenaDbAndTableCommand()); + registerCommand(new CreateCmsResourcesForRegionCommand()); } /** diff --git a/src/main/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapper.java b/src/main/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapper.java index 81f4f9a7..b710498a 100644 --- a/src/main/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapper.java +++ b/src/main/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapper.java @@ -24,20 +24,12 @@ import com.nike.cerberus.command.cms.UpdateCmsConfigCommand; import com.nike.cerberus.command.certificates.GenerateAndRotateCertificatesCommand; import com.nike.cerberus.command.certificates.RotateCertificatesCommand; -import com.nike.cerberus.command.core.InitializeEnvironmentCommand; +import com.nike.cerberus.command.composite.CreateCmsResourcesForRegionCommand; +import com.nike.cerberus.command.core.*; import com.nike.cerberus.command.composite.UpdateAllStackTagsCommand; import com.nike.cerberus.command.rds.CreateDatabaseCommand; -import com.nike.cerberus.command.core.CreateEdgeDomainRecordCommand; -import com.nike.cerberus.command.core.CreateLoadBalancerCommand; -import com.nike.cerberus.command.core.CreateRoute53Command; -import com.nike.cerberus.command.core.CreateSecurityGroupsCommand; -import com.nike.cerberus.command.core.CreateVpcCommand; -import com.nike.cerberus.command.core.CreateWafCommand; -import com.nike.cerberus.command.core.GenerateCertificateFilesCommand; -import com.nike.cerberus.command.core.GenerateCertificateFilesCommandParametersDelegate; import com.nike.cerberus.command.certificates.UploadCertificateFilesCommand; import com.nike.cerberus.command.certificates.UploadCertificateFilesCommandParametersDelegate; -import com.nike.cerberus.command.core.WhitelistCidrForVpcAccessCommand; import com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate; import com.nike.cerberus.domain.input.EnvironmentConfig; import com.nike.cerberus.domain.input.ManagementServiceInput; @@ -47,18 +39,20 @@ import org.apache.commons.lang3.StringUtils; import org.slf4j.LoggerFactory; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; +import java.util.*; -public class EnvironmentConfigToArgsMapper { +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; - public static final String STACK_NAME_KEY = "--stack-name"; +public class EnvironmentConfigToArgsMapper { private EnvironmentConfigToArgsMapper() { } + /** + * removes the prefix args for the args array ex: -e demo -r us-west-2 commandName --some-other-arg foo will + * return an array with ['commandName', '--some-other-arg', 'foo'] + */ public static String[] getArgs(EnvironmentConfig environmentConfig, String[] passedArgs) { List args = new LinkedList<>(); String commandName = null; @@ -86,13 +80,36 @@ public static String[] getArgs(EnvironmentConfig environmentConfig, String[] pas } // convert to string array and return - return args.toArray(new String[args.size()]); + return args.toArray(new String[0]); } public static List getArgsForCommand(EnvironmentConfig environmentConfig, String commandName, String[] passedArgs) { if (environmentConfig == null) { return Lists.newArrayList(passedArgs); } + return getArgsForCommand(environmentConfig, commandName, passedArgs, environmentConfig.getPrimaryRegion()); + } + + public static List getArgsForCommand(EnvironmentConfig environmentConfig, String commandName, String[] passedArgs, Optional region) { + if (environmentConfig == null) { + return Lists.newArrayList(passedArgs); + } + + if (region.isPresent()) { + return getArgsForCommand(environmentConfig, commandName, passedArgs, region.get()); + } else { + return getArgsForCommand(environmentConfig, commandName, passedArgs, environmentConfig.getPrimaryRegion()); + } + } + + public static List getArgsForCommand(EnvironmentConfig environmentConfig, + String commandName, + String[] passedArgs, + String stackRegion) { + + if (environmentConfig == null) { + return Lists.newArrayList(passedArgs); + } List args = new LinkedList<>(); switch (commandName) { @@ -103,10 +120,10 @@ public static List getArgsForCommand(EnvironmentConfig environmentConfig args = getUploadCertFilesCommandArgs(environmentConfig, passedArgs); break; case CreateCmsClusterCommand.COMMAND_NAME: - args = getCreateCmsClusterCommandArgs(environmentConfig); + args = getCreateCmsClusterCommandArgs(environmentConfig, stackRegion); break; case WhitelistCidrForVpcAccessCommand.COMMAND_NAME: - args = getWhitelistCidrForVpcAccessCommandArgs(environmentConfig); + args = getWhitelistCidrForVpcAccessCommandArgs(environmentConfig, stackRegion); break; case CreateCmsConfigCommand.COMMAND_NAME: args = getCreateCmsConfigCommandArgs(environmentConfig, passedArgs); @@ -115,19 +132,19 @@ public static List getArgsForCommand(EnvironmentConfig environmentConfig args = getCreateCmsConfigCommandArgs(environmentConfig, passedArgs); break; case CreateVpcCommand.COMMAND_NAME: - args = getCreateVpcCommandArgs(environmentConfig); + args = getCreateVpcCommandArgs(environmentConfig, stackRegion); break; case CreateSecurityGroupsCommand.COMMAND_NAME: - args = getCreateSecurityGroupsCommandArgs(environmentConfig); + args = getCreateSecurityGroupsCommandArgs(environmentConfig, stackRegion); break; case CreateDatabaseCommand.COMMAND_NAME: - args = getCreateDatabaseCommandArgs(environmentConfig); + args = getCreateDatabaseCommandArgs(environmentConfig, stackRegion); break; case CreateLoadBalancerCommand.COMMAND_NAME: - args = getCreateLoadBalancerCommandArgs(environmentConfig); + args = getCreateLoadBalancerCommandArgs(environmentConfig, stackRegion); break; case CreateRoute53Command.COMMAND_NAME: - args = getCreateRoute53CommandArgs(environmentConfig); + args = getCreateRoute53CommandArgs(environmentConfig, stackRegion); break; case CreateWafCommand.COMMAND_NAME: args = getCreateWafCommandArgs(environmentConfig); @@ -148,7 +165,13 @@ public static List getArgsForCommand(EnvironmentConfig environmentConfig args = getCreateAuditLoggingStackCommandArgs(environmentConfig); break; case UpdateAllStackTagsCommand.COMMAND_NAME: - args = getUpdateAllStackTagsCommandArgs(environmentConfig); + args = getUpdateAllStackTagsCommandArgs(environmentConfig, stackRegion); + break; + case CreateAlbLogAthenaDbAndTableCommand.COMMAND_NAME: + args = getCreateAlbLogAthenaDbAndTableCommandArg(environmentConfig, stackRegion); + break; + case CreateCmsResourcesForRegionCommand.COMMAND_NAME: + args = Arrays.asList(passedArgs); break; default: break; @@ -160,6 +183,12 @@ public static List getArgsForCommand(EnvironmentConfig environmentConfig return args; } + private static List getCreateAlbLogAthenaDbAndTableCommandArg(EnvironmentConfig config, String region) { + return ArgsBuilder.create() + .addOption(STACK_REGION, region) + .build(); + } + private static List getCreateAuditLoggingStackCommandArgs(EnvironmentConfig environmentConfig) { return ArgsBuilder.create() .addOption(CreateAuditLoggingStackCommand.ADMIN_ROLE_ARN_LONG_ARG, environmentConfig.getAdminRoleArn()) @@ -182,9 +211,7 @@ private static List getCreateCmsConfigCommandArgs(EnvironmentConfig envi ArgsBuilder args = ArgsBuilder.create(); ManagementServiceInput managementService = environmentConfig.getManagementService(); args.addOption(CreateCmsConfigCommand.ADMIN_GROUP_LONG_ARG, managementService.getAdminGroup()); - managementService.getProperties().forEach(property -> { - args.addOption(CreateCmsConfigCommand.PROPERTY_SHORT_ARG, property); - }); + managementService.getProperties().forEach(property -> args.addOption(CreateCmsConfigCommand.PROPERTY_SHORT_ARG, property)); if (Arrays.stream(passedArgs).anyMatch(s -> s.equals(UpdateCmsConfigCommand.OVERWRITE_LONG_ARG))) { args.addFlag(UpdateCmsConfigCommand.OVERWRITE_LONG_ARG); @@ -193,28 +220,24 @@ private static List getCreateCmsConfigCommandArgs(EnvironmentConfig envi return args.build(); } - private static List getWhitelistCidrForVpcAccessCommandArgs(EnvironmentConfig environmentConfig) { - ArgsBuilder args = ArgsBuilder.create(); + private static List getWhitelistCidrForVpcAccessCommandArgs(EnvironmentConfig environmentConfig, String region) { + ArgsBuilder args = ArgsBuilder.create() + .addOption(STACK_REGION, region); VpcAccessWhitelistInput vpcAccessWhitelist = environmentConfig.getVpcAccessWhitelist(); - - vpcAccessWhitelist.getCidrs().forEach(cidr -> { - args.addOption(WhitelistCidrForVpcAccessCommand.CIDR_LONG_ARG, cidr); - }); - - vpcAccessWhitelist.getPorts().forEach(port -> { - args.addOption(WhitelistCidrForVpcAccessCommand.PORT_LONG_ARG, port); - }); + vpcAccessWhitelist.getCidrs().forEach(cidr -> args.addOption(WhitelistCidrForVpcAccessCommand.CIDR_LONG_ARG, cidr)); + vpcAccessWhitelist.getPorts().forEach(port -> args.addOption(WhitelistCidrForVpcAccessCommand.PORT_LONG_ARG, port)); return args.build(); } - private static List getCreateCmsClusterCommandArgs(EnvironmentConfig config) { - RegionSpecificConfigurationInput primaryRegion = config.getPrimaryRegionConfig(); - ManagementServiceRegionSpecificInput cmsConfig = primaryRegion.getManagementService().orElseThrow(() -> - new RuntimeException("management service config not defined in primary region config")); + private static List getCreateCmsClusterCommandArgs(EnvironmentConfig config, String region) { + RegionSpecificConfigurationInput regionConfig = config.getRegionConfig(region); + ManagementServiceRegionSpecificInput cmsConfig = regionConfig.getManagementService().orElseThrow(() -> + new RuntimeException("management service config not defined in config for region: " + region)); return ArgsBuilder.create() + .addOption(STACK_REGION, region) .addOption(StackDelegate.AMI_ID_LONG_ARG, cmsConfig.getAmiId()) .addOption(StackDelegate.INSTANCE_SIZE_LONG_ARG, cmsConfig.getInstanceSize()) .addOption(StackDelegate.KEY_PAIR_NAME_LONG_ARG, cmsConfig.getKeyPairName()) @@ -254,21 +277,26 @@ private static List getInitializeEnvironmentCommandArgs(EnvironmentConfi return args.build(); } - private static List getCreateVpcCommandArgs(EnvironmentConfig config) { - return getGlobalTags(config); + private static List getCreateVpcCommandArgs(EnvironmentConfig config, String region) { + return ArgsBuilder.create() + .addOption(STACK_REGION, region) + .addAll(getGlobalTags(config)).build(); } - private static List getCreateSecurityGroupsCommandArgs(EnvironmentConfig config) { - return getGlobalTags(config); + private static List getCreateSecurityGroupsCommandArgs(EnvironmentConfig config, String region) { + return ArgsBuilder.create() + .addOption(STACK_REGION, region) + .addAll(getGlobalTags(config)).build(); } - private static List getCreateDatabaseCommandArgs(EnvironmentConfig config) { - ArgsBuilder args = ArgsBuilder.create(); - if (config.getPrimaryRegionConfig().getRds().isPresent()) { + private static List getCreateDatabaseCommandArgs(EnvironmentConfig config, String region) { + ArgsBuilder args = ArgsBuilder.create().addOption(STACK_REGION, region); + + if (config.getRegionConfig(region).getRds().isPresent()) { args.addOption(CreateDatabaseCommand.INSTANCE_CLASS_LONG_ARG, - config.getPrimaryRegionConfig().getRds().get().getSize()); + config.getRegionConfig(region).getRds().get().getSize()); - String snapshotIdentifier = config.getPrimaryRegionConfig().getRds().get().getDbClusterIdentifier(); + String snapshotIdentifier = config.getRegionConfig(region).getRds().get().getDbClusterIdentifier(); if (StringUtils.isNotBlank(snapshotIdentifier)) { args.addOption(CreateDatabaseCommand.RESTORE_FROM_SNAPSHOT, snapshotIdentifier); } @@ -277,8 +305,8 @@ private static List getCreateDatabaseCommandArgs(EnvironmentConfig confi return args.build(); } - private static List getCreateLoadBalancerCommandArgs(EnvironmentConfig config) { - ArgsBuilder args = ArgsBuilder.create(); + private static List getCreateLoadBalancerCommandArgs(EnvironmentConfig config, String region) { + ArgsBuilder args = ArgsBuilder.create().addOption(STACK_REGION, region); if (StringUtils.isNotBlank(config.getLoadBalancerSslPolicyOverride())) { args.addOption(CreateLoadBalancerCommand.LOAD_BALANCER_SSL_POLICY_OVERRIDE_LONG_ARG, config.getLoadBalancerSslPolicyOverride()); @@ -288,8 +316,9 @@ private static List getCreateLoadBalancerCommandArgs(EnvironmentConfig c return args.build(); } - private static List getCreateRoute53CommandArgs(EnvironmentConfig config) { + private static List getCreateRoute53CommandArgs(EnvironmentConfig config, String region) { ArgsBuilder args = ArgsBuilder.create() + .addOption(STACK_REGION, region) .addOption(CreateRoute53Command.BASE_DOMAIN_NAME_LONG_ARG, config.getBaseDomainName()) .addOption(CreateRoute53Command.HOSTED_ZONE_ID_LONG_ARG, config.getHostedZoneId()); @@ -298,9 +327,9 @@ private static List getCreateRoute53CommandArgs(EnvironmentConfig config args.addOption(CreateRoute53Command.ORIGIN_DOMAIN_NAME_OVERRIDE, config.getOriginDomainNameOverride()); } - if (config.getPrimaryRegionConfig().getLoadBalancerDomainNameOverride().isPresent()) { + if (config.getRegionConfig(region).getLoadBalancerDomainNameOverride().isPresent()) { args.addOption(CreateRoute53Command.LOAD_BALANCER_DOMAIN_NAME_OVERRIDE, - config.getPrimaryRegionConfig().getLoadBalancerDomainNameOverride().orElse(null)); + config.getRegionConfig(region).getLoadBalancerDomainNameOverride().orElse(null)); } return args.build(); @@ -346,16 +375,9 @@ private static List getGenerateCertificatesCommandArgs(EnvironmentConfig return args.build(); } - private static List getUpdateAllStackTagsCommandArgs(EnvironmentConfig config) { - return getGlobalTags(config); - } - - private static String getStackName(String[] passedArgs) { - for (int i = 0; i < passedArgs.length; i++) { - if (StringUtils.equals(passedArgs[i], STACK_NAME_KEY)) { - return passedArgs[i + 1]; - } - } - return null; + private static List getUpdateAllStackTagsCommandArgs(EnvironmentConfig config, String region) { + return ArgsBuilder.create() + .addOption(STACK_REGION, region) + .addAll(getGlobalTags(config)).build(); } } diff --git a/src/main/java/com/nike/cerberus/command/cms/UpdateCmsConfigCommand.java b/src/main/java/com/nike/cerberus/command/cms/UpdateCmsConfigCommand.java index 5de72fbb..c32fe50f 100644 --- a/src/main/java/com/nike/cerberus/command/cms/UpdateCmsConfigCommand.java +++ b/src/main/java/com/nike/cerberus/command/cms/UpdateCmsConfigCommand.java @@ -51,7 +51,7 @@ public class UpdateCmsConfigCommand implements Command { @Parameter(names = FORCE_ARG, description = "Force allow overwriting of system generated property. This may break your configuration.") private boolean force = false; - @Parameter(names = IGNORE_DEFAULT_CONFIGURATIONS_ARGUMENT, description = "Ignores default configurations of the CMS. ") + @Parameter(names = IGNORE_DEFAULT_CONFIGURATIONS_ARGUMENT, description = "Ignores default configurations of the CMS.") private boolean ignoreDefaultConfigurations = false; public String getAdminGroup() { diff --git a/src/main/java/com/nike/cerberus/command/composite/CreateCmsResourcesForRegionCommand.java b/src/main/java/com/nike/cerberus/command/composite/CreateCmsResourcesForRegionCommand.java new file mode 100644 index 00000000..6a81a5b3 --- /dev/null +++ b/src/main/java/com/nike/cerberus/command/composite/CreateCmsResourcesForRegionCommand.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Nike, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nike.cerberus.command.composite; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import com.nike.cerberus.command.Command; +import com.nike.cerberus.operation.Operation; +import com.nike.cerberus.operation.composite.CreateCmsResourcesForRegionOperation; + +import static com.nike.cerberus.command.composite.CreateEnvironmentCommand.COMMAND_NAME; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION_DESCRIPTION; + +@Parameters( + commandNames = { + COMMAND_NAME + }, + commandDescription = "Stands up the resources needed to have CMS running in a given region" +) +public class CreateCmsResourcesForRegionCommand implements Command { + + public static final String COMMAND_NAME = "create-resources-for-secondary-region"; + + @Parameter(names = STACK_REGION, description = STACK_REGION_DESCRIPTION, required = true) + private String stackRegion; + + public String getStackRegion() { + return stackRegion; + } + + @Override + public String getCommandName() { + return COMMAND_NAME; + } + + @Override + public Class> getOperationClass() { + return CreateCmsResourcesForRegionOperation.class; + } +} diff --git a/src/main/java/com/nike/cerberus/command/core/CreateAlbLogAthenaDbAndTableCommand.java b/src/main/java/com/nike/cerberus/command/core/CreateAlbLogAthenaDbAndTableCommand.java index d93235d4..365d7a18 100644 --- a/src/main/java/com/nike/cerberus/command/core/CreateAlbLogAthenaDbAndTableCommand.java +++ b/src/main/java/com/nike/cerberus/command/core/CreateAlbLogAthenaDbAndTableCommand.java @@ -16,12 +16,18 @@ package com.nike.cerberus.command.core; +import com.amazonaws.regions.Regions; +import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.nike.cerberus.command.Command; import com.nike.cerberus.operation.Operation; import com.nike.cerberus.operation.core.CreateAlbLogAthenaDbAndTableOperation; +import java.util.Optional; + import static com.nike.cerberus.command.audit.CreateAuditAthenaDbAndTableCommand.COMMAND_NAME; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION_DESCRIPTION; @Parameters( commandNames = COMMAND_NAME, @@ -31,6 +37,13 @@ public class CreateAlbLogAthenaDbAndTableCommand implements Command { public static final String COMMAND_NAME = "create-alb-log-athena-db-and-table"; + @Parameter(names = STACK_REGION, description = STACK_REGION_DESCRIPTION) + private String stackRegion; + + public Optional getStackRegion() { + return stackRegion == null ? Optional.empty() : Optional.of(Regions.fromName(stackRegion)); + } + @Override public String getCommandName() { return COMMAND_NAME; diff --git a/src/main/java/com/nike/cerberus/command/core/CreateEdgeDomainRecordCommand.java b/src/main/java/com/nike/cerberus/command/core/CreateEdgeDomainRecordCommand.java index fb8e519e..72bab8e7 100644 --- a/src/main/java/com/nike/cerberus/command/core/CreateEdgeDomainRecordCommand.java +++ b/src/main/java/com/nike/cerberus/command/core/CreateEdgeDomainRecordCommand.java @@ -16,13 +16,18 @@ package com.nike.cerberus.command.core; +import com.amazonaws.regions.Regions; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.nike.cerberus.command.Command; import com.nike.cerberus.operation.Operation; import com.nike.cerberus.operation.core.CreateEdgeDomainRecordOperation; +import java.util.Optional; + import static com.nike.cerberus.command.core.CreateEdgeDomainRecordCommand.COMMAND_NAME; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION_DESCRIPTION; /** * Command to create the edge domain Route53 record for Cerberus. @@ -39,6 +44,9 @@ public class CreateEdgeDomainRecordCommand implements Command { public static final String EDGE_DOMAIN_NAME_OVERRIDE = "--edge-domain-name-override"; + @Parameter(names = STACK_REGION, description = STACK_REGION_DESCRIPTION) + private String stackRegion; + @Parameter(names = BASE_DOMAIN_NAME_LONG_ARG, description = "The base domain name for Cerberus (e.g. url: https://env.cerberus.example.com => base hostname: cerberus.example.com)", required = true) @@ -53,6 +61,10 @@ public class CreateEdgeDomainRecordCommand implements Command { required = true) private String hostedZoneId; + public Optional getStackRegion() { + return stackRegion == null ? Optional.empty() : Optional.of(Regions.fromName(stackRegion)); + } + public String getBaseDomainName() { return baseDomainName; } diff --git a/src/main/java/com/nike/cerberus/command/core/DeleteStackCommand.java b/src/main/java/com/nike/cerberus/command/core/DeleteStackCommand.java index d5d9c5b0..af72f164 100644 --- a/src/main/java/com/nike/cerberus/command/core/DeleteStackCommand.java +++ b/src/main/java/com/nike/cerberus/command/core/DeleteStackCommand.java @@ -25,6 +25,7 @@ import com.nike.cerberus.util.StackConverter; import static com.nike.cerberus.command.core.DeleteStackCommand.COMMAND_NAME; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; @Parameters( commandNames = { @@ -38,8 +39,6 @@ public class DeleteStackCommand implements Command { public static final String STACK_NAME_LONG_ARG = "--stack-name"; - public static final String REGION_LONG_ARG = "--region"; - @Parameter( names = {STACK_NAME_LONG_ARG}, required = true, @@ -48,7 +47,7 @@ public class DeleteStackCommand implements Command { private Stack stack; @Parameter( - names = {REGION_LONG_ARG}, + names = {STACK_REGION}, description = "Region to delete stack in, defaults to primary region" ) private String region; diff --git a/src/main/java/com/nike/cerberus/command/core/WhitelistCidrForVpcAccessCommand.java b/src/main/java/com/nike/cerberus/command/core/WhitelistCidrForVpcAccessCommand.java index 3bfd3204..3eaca403 100644 --- a/src/main/java/com/nike/cerberus/command/core/WhitelistCidrForVpcAccessCommand.java +++ b/src/main/java/com/nike/cerberus/command/core/WhitelistCidrForVpcAccessCommand.java @@ -16,6 +16,7 @@ package com.nike.cerberus.command.core; +import com.amazonaws.regions.Regions; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.nike.cerberus.command.Command; @@ -24,8 +25,11 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static com.nike.cerberus.command.core.WhitelistCidrForVpcAccessCommand.COMMAND_NAME; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION_DESCRIPTION; /** * Command for granting CIDRs ingress to specific ports within the Cerberus VPC. @@ -43,6 +47,9 @@ public class WhitelistCidrForVpcAccessCommand implements Command { @Parameter(names = PORT_LONG_ARG, description = "The ports to grant ingress on within the Cerberus VPC.") private List ports = new ArrayList<>(); + @Parameter(names = STACK_REGION, description = STACK_REGION_DESCRIPTION) + private String stackRegion; + public List getCidrs() { return cidrs; } @@ -51,6 +58,10 @@ public List getPorts() { return ports; } + public Optional getStackRegion() { + return stackRegion == null ? Optional.empty() : Optional.of(Regions.fromName(stackRegion)); + } + @Override public String getCommandName() { return COMMAND_NAME; diff --git a/src/main/java/com/nike/cerberus/command/rds/CreateDatabaseCommand.java b/src/main/java/com/nike/cerberus/command/rds/CreateDatabaseCommand.java index ca7dfafa..d30aabdf 100644 --- a/src/main/java/com/nike/cerberus/command/rds/CreateDatabaseCommand.java +++ b/src/main/java/com/nike/cerberus/command/rds/CreateDatabaseCommand.java @@ -60,7 +60,7 @@ public String getInstanceClass() { description = "option for setting a snapshot identifier on the RDS stack to restore from the snapshot " + "while standing up the new RDS cluster via cloudformation" ) - String snapshotIdentifier; + private String snapshotIdentifier; public String getSnapshotIdentifier() { return snapshotIdentifier; diff --git a/src/main/java/com/nike/cerberus/domain/cloudformation/CloudFormationParametersDelegate.java b/src/main/java/com/nike/cerberus/domain/cloudformation/CloudFormationParametersDelegate.java index 4060585a..6a957d0b 100644 --- a/src/main/java/com/nike/cerberus/domain/cloudformation/CloudFormationParametersDelegate.java +++ b/src/main/java/com/nike/cerberus/domain/cloudformation/CloudFormationParametersDelegate.java @@ -16,10 +16,13 @@ package com.nike.cerberus.domain.cloudformation; +import com.amazonaws.regions.Regions; import com.beust.jcommander.DynamicParameter; +import com.beust.jcommander.Parameter; import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** * CloudFormation input parameters common to all Cerberus CloudFormation stacks. @@ -29,6 +32,9 @@ public class CloudFormationParametersDelegate { public static final String TAG_LONG_ARG = "--TAG"; public static final String TAG_SHORT_ARG = "-T"; + public static final String STACK_REGION = "--stack-region"; + public static final String STACK_REGION_DESCRIPTION = "The region for the stack, ex: us-west-2, will default to the primary region."; + @DynamicParameter( names = { TAG_LONG_ARG, @@ -38,10 +44,17 @@ public class CloudFormationParametersDelegate { ) private Map tags = new HashMap<>(); + @Parameter(names = STACK_REGION, description = STACK_REGION_DESCRIPTION) + private String stackRegion; + public Map getTags() { return tags; } + public Optional getStackRegion() { + return stackRegion == null ? Optional.empty() : Optional.of(Regions.fromName(stackRegion)); + } + public String[] getArgs(){ return tags.entrySet() .stream() diff --git a/src/main/java/com/nike/cerberus/domain/cloudformation/CmsParameters.java b/src/main/java/com/nike/cerberus/domain/cloudformation/CmsParameters.java index 88d26e59..240ff614 100644 --- a/src/main/java/com/nike/cerberus/domain/cloudformation/CmsParameters.java +++ b/src/main/java/com/nike/cerberus/domain/cloudformation/CmsParameters.java @@ -23,7 +23,7 @@ */ public class CmsParameters implements LaunchConfigParameters { - private String baseStackName; + private String cmsIamRoleName; private String loadBalancerStackName; @@ -38,12 +38,12 @@ public class CmsParameters implements LaunchConfigParameters { @JsonUnwrapped private LaunchConfigParametersDelegate launchConfigParameters = new LaunchConfigParametersDelegate(); - public String getBaseStackName() { - return baseStackName; + public String getCmsIamRoleName() { + return cmsIamRoleName; } - public CmsParameters setBaseStackName(String baseStackName) { - this.baseStackName = baseStackName; + public CmsParameters setCmsIamRoleName(String cmsIamRoleName) { + this.cmsIamRoleName = cmsIamRoleName; return this; } diff --git a/src/main/java/com/nike/cerberus/domain/input/EnvironmentConfig.java b/src/main/java/com/nike/cerberus/domain/input/EnvironmentConfig.java index 4156885f..d8daa968 100644 --- a/src/main/java/com/nike/cerberus/domain/input/EnvironmentConfig.java +++ b/src/main/java/com/nike/cerberus/domain/input/EnvironmentConfig.java @@ -19,6 +19,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; + +import static com.google.common.collect.MoreCollectors.onlyElement; /** * Stores all YAML data for a given Cerberus environment @@ -193,13 +196,19 @@ public RegionSpecificConfigurationInput getPrimaryRegionConfig() { return getPrimaryEntry().getValue(); } + public RegionSpecificConfigurationInput getRegionConfig(String region) { + return Optional.ofNullable(getRegionSpecificConfiguration().get(region)) + .orElseThrow(() -> new RuntimeException(String + .format("Failed to find region config for %s in region specific config", region))); + } + public String getPrimaryRegion() { return getPrimaryEntry().getKey(); } private Map.Entry getPrimaryEntry() { return regionSpecificConfiguration.entrySet().stream() - .filter(entry -> entry.getValue() != null && entry.getValue().isPrimary()).findFirst() - .orElseThrow(() -> new RuntimeException("Failed to find primary region in region specific config")); + .filter(entry -> entry.getValue() != null && entry.getValue().isPrimary()) + .collect(onlyElement()); } } diff --git a/src/main/java/com/nike/cerberus/operation/audit/CreateAuditAthenaDbAndTableOperation.java b/src/main/java/com/nike/cerberus/operation/audit/CreateAuditAthenaDbAndTableOperation.java index 333ad995..d0283a91 100644 --- a/src/main/java/com/nike/cerberus/operation/audit/CreateAuditAthenaDbAndTableOperation.java +++ b/src/main/java/com/nike/cerberus/operation/audit/CreateAuditAthenaDbAndTableOperation.java @@ -80,7 +80,7 @@ public void run(CreateAuditAthenaDbAndTableCommand command) { log.info("Creating Athena DB"); String createDb = "CREATE DATABASE IF NOT EXISTS " + databaseName + ";"; - log.info(athenaService.executeAthenaQuery(createDb, bucketName).toString()); + log.info(athenaService.executeAthenaQuery(createDb, bucketName, configStore.getPrimaryRegion()).toString()); log.info("Creating table"); String createAuditTable; try { @@ -91,7 +91,7 @@ public void run(CreateAuditAthenaDbAndTableCommand command) { } catch (IOException e) { throw new RuntimeException("failed to load create athena table template", e); } - log.info(athenaService.executeAthenaQuery(createAuditTable, bucketName).toString()); + log.info(athenaService.executeAthenaQuery(createAuditTable, bucketName, configStore.getPrimaryRegion()).toString()); } @Override diff --git a/src/main/java/com/nike/cerberus/operation/cms/CreateCmsClusterOperation.java b/src/main/java/com/nike/cerberus/operation/cms/CreateCmsClusterOperation.java index 0277105f..6f8d6222 100644 --- a/src/main/java/com/nike/cerberus/operation/cms/CreateCmsClusterOperation.java +++ b/src/main/java/com/nike/cerberus/operation/cms/CreateCmsClusterOperation.java @@ -16,6 +16,7 @@ package com.nike.cerberus.operation.cms; +import com.amazonaws.regions.Regions; import com.nike.cerberus.command.cms.CreateCmsClusterCommand; import com.nike.cerberus.domain.cloudformation.CmsParameters; import com.nike.cerberus.domain.cloudformation.VpcOutputs; @@ -70,7 +71,10 @@ public CreateCmsClusterOperation(CloudFormationService cloudFormationService, @Override public void run(CreateCmsClusterCommand command) { - VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(); + Regions region = command.getStackDelegate().getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(region); List certInfoListForStack = configStore.getCertificationInformationList(); Map tags = command.getStackDelegate().getCloudFormationParametersDelegate().getTags(); @@ -79,11 +83,13 @@ public void run(CreateCmsClusterCommand command) { throw new IllegalStateException("Certificate for cerberus environment has not been uploaded!"); } + String cmsIamRoleName = configStore.getCmsIamRoleOutputs(configStore.getPrimaryRegion()).getCmsIamRoleName(); + CmsParameters cmsParameters = new CmsParameters() .setVpcSubnetIdForAz1(vpcOutputs.getVpcSubnetIdForAz1()) .setVpcSubnetIdForAz2(vpcOutputs.getVpcSubnetIdForAz2()) .setVpcSubnetIdForAz3(vpcOutputs.getVpcSubnetIdForAz3()) - .setBaseStackName(Stack.IAM_ROLES.getFullName(environmentName)) + .setCmsIamRoleName(cmsIamRoleName) .setLoadBalancerStackName(Stack.LOAD_BALANCER.getFullName(environmentName)) .setSgStackName(Stack.SECURITY_GROUPS.getFullName(environmentName)); @@ -91,7 +97,7 @@ public void run(CreateCmsClusterCommand command) { cmsParameters.getLaunchConfigParameters().setInstanceSize(command.getStackDelegate().getInstanceSize()); cmsParameters.getLaunchConfigParameters().setKeyPairName(command.getStackDelegate().getKeyPairName()); cmsParameters.getLaunchConfigParameters().setUserData(ec2UserDataService.getUserData( - configStore.getPrimaryRegion(), Stack.CMS, + region, Stack.CMS, Optional.ofNullable(tags.getOrDefault("ownerGroup", null)))); Map parameters = cloudFormationObjectMapper.convertValue(cmsParameters); @@ -100,7 +106,7 @@ public void run(CreateCmsClusterCommand command) { parameters.putAll(command.getStackDelegate().getDynamicParameters()); cloudFormationService.createStackAndWait( - configStore.getPrimaryRegion(), + region, Stack.CMS, parameters, true, tags); @@ -108,17 +114,31 @@ public void run(CreateCmsClusterCommand command) { @Override public boolean isRunnable(CreateCmsClusterCommand command) { + Regions region = command.getStackDelegate().getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + boolean isRunnable = true; + try { - cloudFormationService.getStackId(configStore.getPrimaryRegion(), Stack.LOAD_BALANCER.getFullName(environmentName)); - cloudFormationService.getStackId(configStore.getPrimaryRegion(), Stack.SECURITY_GROUPS.getFullName(environmentName)); + cloudFormationService.getStackId(region, Stack.LOAD_BALANCER.getFullName(environmentName)); + cloudFormationService.getStackId(region, Stack.SECURITY_GROUPS.getFullName(environmentName)); cloudFormationService.getStackId(configStore.getPrimaryRegion(), Stack.IAM_ROLES.getFullName(environmentName)); - } catch (IllegalArgumentException iae) { + } catch (Exception e) { logger.error("Could not create the CMS cluster." + - "Make sure the load balancer, security group, and base stacks have all been created.", iae); - return false; + "Make sure the load balancer, security group, and base stacks have all been created.", e); + isRunnable = false; + } + + if (!configStore.getCmsEnvConfig().isPresent()) { + logger.error("Cannot create CMS cluster before create cms config command has been ran"); + isRunnable = false; + } + + if (cloudFormationService.isStackPresent(region, Stack.CMS.getFullName(environmentName))) { + logger.error("The cms cluster already exists"); + isRunnable = false; } - return configStore.getCmsEnvConfig().isPresent() && - !cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), Stack.CMS.getFullName(environmentName)); + return isRunnable; } } diff --git a/src/main/java/com/nike/cerberus/operation/composite/ChainableCommand.java b/src/main/java/com/nike/cerberus/operation/composite/ChainableCommand.java index 0d4d63cf..8a12b5d1 100644 --- a/src/main/java/com/nike/cerberus/operation/composite/ChainableCommand.java +++ b/src/main/java/com/nike/cerberus/operation/composite/ChainableCommand.java @@ -17,11 +17,12 @@ package com.nike.cerberus.operation.composite; import com.nike.cerberus.command.Command; -import com.nike.cerberus.operation.Operation; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Optional; @SuppressFBWarnings( value = "EI_EXPOSE_REP", @@ -36,6 +37,7 @@ public class ChainableCommand { private Command command; private String[] additionalArgs = new String[]{}; + private String stackRegion; public ChainableCommand() { @@ -45,6 +47,11 @@ public ChainableCommand(Command command) { this.command = command; } + public ChainableCommand(Command command, String stackRegion) { + this.command = command; + this.stackRegion = stackRegion; + } + public ChainableCommand(Command command, String[] additionalArgs) { this.command = command; this.additionalArgs = additionalArgs; @@ -58,9 +65,14 @@ public String[] getAdditionalArgs() { return additionalArgs; } + public Optional getStackRegion() { + return Optional.ofNullable(stackRegion); + } + public static final class Builder { private Command command; private List additionalArgs = new LinkedList<>(); + private String stackRegion; private Builder() { } @@ -80,9 +92,7 @@ public Builder withAdditionalArg(String additionalArg) { } public Builder withAdditionalArg(String ...additionalArg) { - for(String arg: additionalArg) { - additionalArgs.add(arg); - } + additionalArgs.addAll(Arrays.asList(additionalArg)); return this; } @@ -92,10 +102,16 @@ public Builder withOption(String key, String value) { return this; } + public Builder withStackRegion(String stackRegion) { + this.stackRegion = stackRegion; + return this; + } + public ChainableCommand build() { ChainableCommand chainableCommand = new ChainableCommand(); chainableCommand.command = this.command; chainableCommand.additionalArgs = this.additionalArgs.toArray(new String[additionalArgs.size()]); + chainableCommand.stackRegion = this.stackRegion; return chainableCommand; } } diff --git a/src/main/java/com/nike/cerberus/operation/composite/CompositeOperation.java b/src/main/java/com/nike/cerberus/operation/composite/CompositeOperation.java index 6519d043..8949e30f 100644 --- a/src/main/java/com/nike/cerberus/operation/composite/CompositeOperation.java +++ b/src/main/java/com/nike/cerberus/operation/composite/CompositeOperation.java @@ -76,7 +76,7 @@ public void run(T compositeCommand) { // Parse the yaml and additional args to get args to pass to jcommander List argsList = EnvironmentConfigToArgsMapper.getArgsForCommand( - environmentConfig, chainedCommand.getCommandName(), additionalArgs); + environmentConfig, chainedCommand.getCommandName(), additionalArgs, chainableCommand.getStackRegion()); // If the mapper doesn't have a mapping for a given command it will return an empty list // in this case we will just use the args manually provided by the chainable command diff --git a/src/main/java/com/nike/cerberus/operation/composite/CreateCmsResourcesForRegionOperation.java b/src/main/java/com/nike/cerberus/operation/composite/CreateCmsResourcesForRegionOperation.java new file mode 100644 index 00000000..13937dff --- /dev/null +++ b/src/main/java/com/nike/cerberus/operation/composite/CreateCmsResourcesForRegionOperation.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 Nike, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nike.cerberus.operation.composite; + +import com.google.common.collect.Lists; +import com.nike.cerberus.command.cms.CreateCmsClusterCommand; +import com.nike.cerberus.command.cms.UpdateCmsConfigCommand; +import com.nike.cerberus.command.composite.CreateCmsResourcesForRegionCommand; +import com.nike.cerberus.command.core.*; +import com.nike.cerberus.command.rds.CreateDatabaseCommand; + +import java.util.List; + +public class CreateCmsResourcesForRegionOperation extends CompositeOperation { + + @Override + protected List getCompositeCommandChain(CreateCmsResourcesForRegionCommand compositeCommand) { + return Lists.newArrayList( + new ChainableCommand(new CreateVpcCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new CreateSecurityGroupsCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new WhitelistCidrForVpcAccessCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new CreateDatabaseCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new CreateLoadBalancerCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new UpdateCmsConfigCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new CreateCmsClusterCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new CreateAlbLogAthenaDbAndTableCommand(), compositeCommand.getStackRegion()), + new ChainableCommand(new CreateRoute53Command(), compositeCommand.getStackRegion()) + ); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isRunnable(CreateCmsResourcesForRegionCommand command) { + // Always return true and depend on isRunnable of the chained commands to skip commands that cannot be re-ran + // we want this command to be able to be run more than once to complete an environment for example say temporary + // aws creds expire half way through environment creation + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean skipOnNotRunnable() { + // Since we always return true for isRunnable on this command sub of the sub commands may have already been run + // we want this command to be able to be run more than once to complete an environment for example say temporary + // aws creds expire half way through environment creation + return true; + } +} diff --git a/src/main/java/com/nike/cerberus/operation/composite/DeleteEnvironmentOperation.java b/src/main/java/com/nike/cerberus/operation/composite/DeleteEnvironmentOperation.java index ddd80330..eeeb5823 100644 --- a/src/main/java/com/nike/cerberus/operation/composite/DeleteEnvironmentOperation.java +++ b/src/main/java/com/nike/cerberus/operation/composite/DeleteEnvironmentOperation.java @@ -27,6 +27,7 @@ import java.util.LinkedList; import java.util.List; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; import static com.nike.cerberus.domain.environment.Stack.*; import static com.nike.cerberus.module.CerberusModule.ENV_NAME; @@ -78,7 +79,7 @@ protected List getCompositeCommandChain(DeleteEnvironmentComma chainableCommandList.add(ChainableCommand.Builder.create() .withCommand(new DeleteStackCommand()) .withOption(DeleteStackCommand.STACK_NAME_LONG_ARG, CONFIG.getName()) - .withOption(DeleteStackCommand.REGION_LONG_ARG, region.getName()) + .withOption(STACK_REGION, region.getName()) .build()); }); diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateAlbLogAthenaDbAndTableOperation.java b/src/main/java/com/nike/cerberus/operation/core/CreateAlbLogAthenaDbAndTableOperation.java index c8864b36..78d92c94 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateAlbLogAthenaDbAndTableOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateAlbLogAthenaDbAndTableOperation.java @@ -16,6 +16,7 @@ package com.nike.cerberus.operation.core; +import com.amazonaws.regions.Regions; import com.nike.cerberus.ConfigConstants; import com.nike.cerberus.command.core.CreateAlbLogAthenaDbAndTableCommand; import com.nike.cerberus.domain.cloudformation.LoadBalancerOutputs; @@ -62,8 +63,10 @@ public CreateAlbLogAthenaDbAndTableOperation(CloudFormationService cloudFormatio @Override public void run(CreateAlbLogAthenaDbAndTableCommand command) { + Regions region = command.getStackRegion().orElse(configStore.getPrimaryRegion()); + LoadBalancerOutputs outputs = - configStore.getStackOutputs(configStore.getPrimaryRegion(), + configStore.getStackOutputs(region, Stack.LOAD_BALANCER.getFullName(environmentName), LoadBalancerOutputs.class); String bucketName = outputs.getLoadBalancerAccessLogBucket(); @@ -71,7 +74,7 @@ public void run(CreateAlbLogAthenaDbAndTableCommand command) { log.info("Creating Athena DB"); String createDb = "CREATE DATABASE IF NOT EXISTS " + databaseName + ";"; - log.info(athenaService.executeAthenaQuery(createDb, bucketName).toString()); + log.info(athenaService.executeAthenaQuery(createDb, bucketName, region).toString()); log.info("Creating table"); String createAuditTable; try { @@ -83,14 +86,15 @@ public void run(CreateAlbLogAthenaDbAndTableCommand command) { } catch (IOException e) { throw new RuntimeException("failed to load create athena table template", e); } - log.info(athenaService.executeAthenaQuery(createAuditTable, bucketName).toString()); + log.info(athenaService.executeAthenaQuery(createAuditTable, bucketName, region).toString()); } @Override public boolean isRunnable(CreateAlbLogAthenaDbAndTableCommand command) { + Regions region = command.getStackRegion().orElse(configStore.getPrimaryRegion()); boolean isRunnable = true; - if (! cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), Stack.LOAD_BALANCER.getFullName(environmentName))) { + if (! cloudFormationService.isStackPresent(region, Stack.LOAD_BALANCER.getFullName(environmentName))) { log.error("You must create the audit stack using create-alb-log-athena-db-and-table command"); isRunnable = false; } diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateEdgeDomainRecordOperation.java b/src/main/java/com/nike/cerberus/operation/core/CreateEdgeDomainRecordOperation.java index b958566c..d6570eb7 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateEdgeDomainRecordOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateEdgeDomainRecordOperation.java @@ -16,6 +16,7 @@ package com.nike.cerberus.operation.core; +import com.amazonaws.regions.Regions; import com.amazonaws.services.route53.model.RRType; import com.amazonaws.services.route53.model.ResourceRecord; import com.amazonaws.services.route53.model.ResourceRecordSet; @@ -72,29 +73,32 @@ public CreateEdgeDomainRecordOperation(CloudFormationService cloudFormationServi @Override public void run(CreateEdgeDomainRecordCommand command) { - String recordValue = configStore.getRoute53StackOutputs().getOriginDomainName(); + Regions region = command.getStackRegion().orElse(configStore.getPrimaryRegion()); + String recordValue = configStore.getRoute53StackOutputs(region).getOriginDomainName(); String recordSetName = getEdgeDomainName(command.getBaseDomainName(), command.getEdgeDomainNameOverride()); route53Service.createRoute53RecordSet(command.getHostedZoneId(), recordSetName, recordValue, RRType.CNAME, - RESOURCE_RECORD_TTL); + RESOURCE_RECORD_TTL, + region); } @Override public boolean isRunnable(CreateEdgeDomainRecordCommand command) { + Regions region = command.getStackRegion().orElse(configStore.getPrimaryRegion()); String recordSetName = getEdgeDomainName(command.getBaseDomainName(), command.getEdgeDomainNameOverride()); boolean isRunnable = true; - if (!cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), Stack.ROUTE53.getFullName(environmentName))) { + if (!cloudFormationService.isStackPresent(region, Stack.ROUTE53.getFullName(environmentName))) { logger.error("The route53 stack must be present"); return false; } Optional edgeRecordOptional = route53Service - .getRecordSetByName(recordSetName, command.getHostedZoneId()); + .getRecordSetByName(recordSetName, command.getHostedZoneId(), region); if (edgeRecordOptional.isPresent()) { String msg = String.format( diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateLoadBalancerOperation.java b/src/main/java/com/nike/cerberus/operation/core/CreateLoadBalancerOperation.java index f18414c6..5f803edb 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateLoadBalancerOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateLoadBalancerOperation.java @@ -88,18 +88,19 @@ public CreateLoadBalancerOperation(@Named(ENV_NAME) String environmentName, @Override public void run(CreateLoadBalancerCommand command) { - Regions loadBalancerRegion = configStore.getPrimaryRegion(); + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); - VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(); + VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(region); // Use latest cert, if there happens to be more than one for some reason String sslCertificateArn = configStore.getCertificationInformationList() .getLast().getIdentityManagementCertificateArn(); - if (!regionToAwsElbAccountIdMap.containsKey(loadBalancerRegion.getName())) { + if (!regionToAwsElbAccountIdMap.containsKey(region.getName())) { throw new RuntimeException( String.format("The region: %s was not in the region to AWS ELB Account Id map: [ %s ]", - loadBalancerRegion.getName(), + region.getName(), regionToAwsElbAccountIdMap.entrySet().stream() .map(entry -> entry.getKey() + "->" + entry.getValue()) .collect(joining(", "))) @@ -113,7 +114,7 @@ public void run(CreateLoadBalancerCommand command) { .setVpcSubnetIdForAz1(vpcOutputs.getVpcSubnetIdForAz1()) .setVpcSubnetIdForAz2(vpcOutputs.getVpcSubnetIdForAz2()) .setVpcSubnetIdForAz3(vpcOutputs.getVpcSubnetIdForAz3()) - .setElasticLoadBalancingAccountId(regionToAwsElbAccountIdMap.get(loadBalancerRegion.getName())); + .setElasticLoadBalancingAccountId(regionToAwsElbAccountIdMap.get(region.getName())); if (StringUtils.isNotBlank(command.getLoadBalancerSslPolicyOverride())) { @@ -123,7 +124,7 @@ public void run(CreateLoadBalancerCommand command) { Map parameters = cloudFormationObjectMapper.convertValue(loadBalancerParameters); cloudFormationService.createStackAndWait( - loadBalancerRegion, + region, Stack.LOAD_BALANCER, parameters, true, @@ -132,9 +133,12 @@ public void run(CreateLoadBalancerCommand command) { @Override public boolean isRunnable(CreateLoadBalancerCommand command) { + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + boolean isRunnable = true; - if (!cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), + if (!cloudFormationService.isStackPresent(region, Stack.SECURITY_GROUPS.getFullName(environmentName))) { logger.error("The security group stack must exist to create the load balancer!"); isRunnable = false; @@ -145,7 +149,7 @@ public boolean isRunnable(CreateLoadBalancerCommand command) { isRunnable = false; } - if (cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), + if (cloudFormationService.isStackPresent(region, Stack.LOAD_BALANCER.getFullName(environmentName))) { logger.error("The load balancer stack already exists"); isRunnable = false; diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateRoute53Operation.java b/src/main/java/com/nike/cerberus/operation/core/CreateRoute53Operation.java index bd322316..147b77f6 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateRoute53Operation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateRoute53Operation.java @@ -16,6 +16,7 @@ package com.nike.cerberus.operation.core; +import com.amazonaws.regions.Regions; import com.nike.cerberus.command.core.CreateRoute53Command; import com.nike.cerberus.domain.cloudformation.Route53Parameters; import com.nike.cerberus.domain.environment.Stack; @@ -67,16 +68,19 @@ public CreateRoute53Operation(@Named(ENV_NAME) String environmentName, @Override public void run(CreateRoute53Command command) { + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + Route53Parameters route53Parameters = new Route53Parameters() .setHostedZoneId(command.getHostedZoneId()) - .setLoadBalancerDomainName(getLoadBalancerDomainName(command.getBaseDomainName(), command.getLoadBalancerDomainNameOverride())) + .setLoadBalancerDomainName(getLoadBalancerDomainName(command.getBaseDomainName(), command.getLoadBalancerDomainNameOverride(), region)) .setLoadBalancerStackName(Stack.LOAD_BALANCER.getFullName(environmentName)) - .setOriginDomainName(getOriginDomainName(command.getBaseDomainName(), command.getOriginDomainNameOverride())); + .setOriginDomainName(getOriginDomainName(command.getBaseDomainName(), command.getOriginDomainNameOverride(), region)); Map parameters = cloudFormationObjectMapper.convertValue(route53Parameters); cloudFormationService.createStackAndWait( - configStore.getPrimaryRegion(), + region, Stack.ROUTE53, parameters, true, @@ -85,25 +89,27 @@ public void run(CreateRoute53Command command) { @Override public boolean isRunnable(CreateRoute53Command command) { - String loadBalancerDomainName = getLoadBalancerDomainName(command.getBaseDomainName(), command.getLoadBalancerDomainNameOverride()); - String originDomainName = getOriginDomainName(command.getBaseDomainName(), command.getOriginDomainNameOverride()); + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + String loadBalancerDomainName = getLoadBalancerDomainName(command.getBaseDomainName(), command.getLoadBalancerDomainNameOverride(), region); + String originDomainName = getOriginDomainName(command.getBaseDomainName(), command.getOriginDomainNameOverride(), region); boolean isRunnable = true; - if (!cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), + if (!cloudFormationService.isStackPresent(region, Stack.LOAD_BALANCER.getFullName(environmentName))) { logger.error("The load balancer stack must exist to create the Route53 record!"); isRunnable = false; } - if (cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), + if (cloudFormationService.isStackPresent(region, Stack.ROUTE53.getFullName(environmentName))) { logger.error("Route53 stack already exists."); isRunnable = false; } - if (route53Service.getRecordSetByName(loadBalancerDomainName, command.getHostedZoneId()).isPresent()) { + if (route53Service.getRecordSetByName(loadBalancerDomainName, command.getHostedZoneId(), region).isPresent()) { logger.error("The load balancer name is already registered"); isRunnable = false; } - if (route53Service.getRecordSetByName(originDomainName, command.getHostedZoneId()).isPresent()) { + if (route53Service.getRecordSetByName(originDomainName, command.getHostedZoneId(), region).isPresent()) { logger.error("The origin name is already registered"); isRunnable = false; } @@ -111,18 +117,19 @@ public boolean isRunnable(CreateRoute53Command command) { return isRunnable; } - private String getLoadBalancerDomainName(String baseDomainName, String loadBalancerDomainNameOverride) { + private String getLoadBalancerDomainName(String baseDomainName, String loadBalancerDomainNameOverride, Regions region) { String defaultLoadBalancerDomainName = String.format("%s.%s.%s", environmentName, - configStore.getPrimaryRegion().getName(), + region.getName(), baseDomainName); return StringUtils.isBlank(loadBalancerDomainNameOverride) ? defaultLoadBalancerDomainName : loadBalancerDomainNameOverride; } - private String getOriginDomainName(String baseDomainName, String originDomainNameOverride) { - String defaultOriginDomainName = String.format("origin.%s.%s", + private String getOriginDomainName(String baseDomainName, String originDomainNameOverride, Regions region) { + String defaultOriginDomainName = String.format("origin.%s.%s.%s", + region.getName(), environmentName, baseDomainName); diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateSecurityGroupsOperation.java b/src/main/java/com/nike/cerberus/operation/core/CreateSecurityGroupsOperation.java index d0e1fc0c..b57bc9e9 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateSecurityGroupsOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateSecurityGroupsOperation.java @@ -16,6 +16,7 @@ package com.nike.cerberus.operation.core; +import com.amazonaws.regions.Regions; import com.nike.cerberus.command.core.CreateSecurityGroupsCommand; import com.nike.cerberus.domain.cloudformation.SecurityGroupParameters; import com.nike.cerberus.domain.cloudformation.VpcOutputs; @@ -53,6 +54,7 @@ public CreateSecurityGroupsOperation(@Named(ENV_NAME) String environmentName, CloudFormationService cloudFormationService, ConfigStore configStore, CloudFormationObjectMapper cloudFormationObjectMapper) { + this.environmentName = environmentName; this.cloudFormationService = cloudFormationService; this.configStore = configStore; @@ -61,7 +63,10 @@ public CreateSecurityGroupsOperation(@Named(ENV_NAME) String environmentName, @Override public void run(CreateSecurityGroupsCommand command) { - VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(); + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(region); SecurityGroupParameters securityGroupParameters = new SecurityGroupParameters() .setVpcId(vpcOutputs.getVpcId()); @@ -69,7 +74,7 @@ public void run(CreateSecurityGroupsCommand command) { Map parameters = cloudFormationObjectMapper.convertValue(securityGroupParameters); cloudFormationService.createStackAndWait( - configStore.getPrimaryRegion(), + region, Stack.SECURITY_GROUPS, parameters, true, @@ -78,7 +83,10 @@ public void run(CreateSecurityGroupsCommand command) { @Override public boolean isRunnable(CreateSecurityGroupsCommand command) { - return !cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + return !cloudFormationService.isStackPresent(region, Stack.SECURITY_GROUPS.getFullName(environmentName)); } diff --git a/src/main/java/com/nike/cerberus/operation/core/CreateVpcOperation.java b/src/main/java/com/nike/cerberus/operation/core/CreateVpcOperation.java index 994a3d43..2596f776 100644 --- a/src/main/java/com/nike/cerberus/operation/core/CreateVpcOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/CreateVpcOperation.java @@ -16,6 +16,7 @@ package com.nike.cerberus.operation.core; +import com.amazonaws.regions.Regions; import com.beust.jcommander.internal.Maps; import com.nike.cerberus.command.core.CreateVpcCommand; import com.nike.cerberus.domain.cloudformation.VpcParameters; @@ -69,7 +70,10 @@ public CreateVpcOperation(@Named(ENV_NAME) String environmentName, @Override public void run(CreateVpcCommand command) { - Map azByIdentifier = mapAvailabilityZones(); + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + Map azByIdentifier = mapAvailabilityZones(region); VpcParameters vpcParameters = new VpcParameters() .setAz1(azByIdentifier.get(1)) @@ -80,7 +84,7 @@ public void run(CreateVpcCommand command) { Map parameters = cloudFormationObjectMapper.convertValue(vpcParameters); cloudFormationService.createStackAndWait( - configStore.getPrimaryRegion(), + region, Stack.VPC, parameters, true, @@ -89,12 +93,15 @@ public void run(CreateVpcCommand command) { @Override public boolean isRunnable(CreateVpcCommand command) { - return !cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + return !cloudFormationService.isStackPresent(region, Stack.VPC.getFullName(environmentName)); } - private Map mapAvailabilityZones() { - List zones = ec2Service.getAvailabilityZones(); + private Map mapAvailabilityZones(Regions region) { + List zones = ec2Service.getAvailabilityZones(region); if (zones.size() < MINIMUM_AZS) { throw new IllegalStateException("Not enough availability zones for the selected region."); diff --git a/src/main/java/com/nike/cerberus/operation/core/WhitelistCidrForVpcAccessOperation.java b/src/main/java/com/nike/cerberus/operation/core/WhitelistCidrForVpcAccessOperation.java index 338ce59e..e4199c66 100644 --- a/src/main/java/com/nike/cerberus/operation/core/WhitelistCidrForVpcAccessOperation.java +++ b/src/main/java/com/nike/cerberus/operation/core/WhitelistCidrForVpcAccessOperation.java @@ -16,7 +16,7 @@ package com.nike.cerberus.operation.core; -import com.amazonaws.services.ec2.AmazonEC2; +import com.amazonaws.regions.Regions; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest; import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest; @@ -51,7 +51,7 @@ public class WhitelistCidrForVpcAccessOperation implements Operation amazonS3ClientFactory; private final String environmentName; @@ -63,13 +63,16 @@ public WhitelistCidrForVpcAccessOperation(CloudFormationService cloudFormationSe this.cloudFormationService = cloudFormationService; this.configStore = configStore; - this.ec2Client = amazonS3ClientFactory.getClient(configStore.getPrimaryRegion()); + this.amazonS3ClientFactory = amazonS3ClientFactory; this.environmentName = environmentName; } @Override public void run(WhitelistCidrForVpcAccessCommand command) { - SecurityGroupOutputs securityGroupOutputs = configStore.getSecurityGroupStackOutputs(); + Regions region = command.getStackRegion().orElse(configStore.getPrimaryRegion()); + AmazonEC2Client ec2Client = amazonS3ClientFactory.getClient(region); + + SecurityGroupOutputs securityGroupOutputs = configStore.getSecurityGroupStackOutputs(region); logger.info("Revoking the previous ingress rules..."); DescribeSecurityGroupsResult securityGroupsResult = ec2Client.describeSecurityGroups( @@ -105,11 +108,11 @@ public void run(WhitelistCidrForVpcAccessCommand command) { @Override public boolean isRunnable(WhitelistCidrForVpcAccessCommand command) { + Regions region = command.getStackRegion().orElse(configStore.getPrimaryRegion()); try { - cloudFormationService.getStackId(configStore.getPrimaryRegion(), Stack.IAM_ROLES.getFullName(environmentName)); - } catch (IllegalArgumentException iae) { - logger.error("Could not create the CMS cluster." + - "Make sure the load balancer, security group, and base stacks have all been created.", iae); + cloudFormationService.getStackId(region, Stack.SECURITY_GROUPS.getFullName(environmentName)); + } catch (Exception e) { + logger.error("The security group stack must exist before you can white list ingress to the VPC Ingress SG.", e); return false; } diff --git a/src/main/java/com/nike/cerberus/operation/rds/CreateDatabaseOperation.java b/src/main/java/com/nike/cerberus/operation/rds/CreateDatabaseOperation.java index 03b9a720..abeff47a 100644 --- a/src/main/java/com/nike/cerberus/operation/rds/CreateDatabaseOperation.java +++ b/src/main/java/com/nike/cerberus/operation/rds/CreateDatabaseOperation.java @@ -67,11 +67,19 @@ public CreateDatabaseOperation(@Named(ENV_NAME) String environmentName, @Override public void run(CreateDatabaseCommand command) { - Regions region = configStore.getPrimaryRegion(); - - VpcParameters vpcParameters = configStore.getVpcStackParameters(); - VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(); - String databasePassword = passwordGenerator.get(); + Regions region = command.getCloudFormationParametersDelegate().getStackRegion() + .orElse(configStore.getPrimaryRegion()); + + VpcParameters vpcParameters = configStore.getVpcStackParameters(region); + VpcOutputs vpcOutputs = configStore.getVpcStackOutputs(region); + + String databasePassword; + if (region == configStore.getPrimaryRegion()) { + databasePassword = passwordGenerator.get(); + } else { + databasePassword = configStore.getCmsDatabasePassword() + .orElseThrow(() -> new RuntimeException("Expected the database password to exists before a secondary stack was created!")); + } DatabaseParameters databaseParameters = new DatabaseParameters() .setCmsDbMasterPassword(databasePassword) @@ -102,18 +110,24 @@ public void run(CreateDatabaseCommand command) { @Override public boolean isRunnable(CreateDatabaseCommand command) { + Regions region = command.getCloudFormationParametersDelegate().getStackRegion().orElse(configStore.getPrimaryRegion()); boolean isRunnable = true; - if (!cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), Stack.SECURITY_GROUPS.getFullName(environmentName))) { + if (!cloudFormationService.isStackPresent(region, Stack.SECURITY_GROUPS.getFullName(environmentName))) { isRunnable = false; logger.error("The security group stack must exist to create the the data base stack!"); } - if (cloudFormationService.isStackPresent(configStore.getPrimaryRegion(), Stack.DATABASE.getFullName(environmentName))) { + if (cloudFormationService.isStackPresent(region, Stack.DATABASE.getFullName(environmentName))) { isRunnable = false; logger.error("The database stack already exists, use update-stack"); } + if (region != configStore.getPrimaryRegion() && !configStore.getCmsDatabasePassword().isPresent()) { + isRunnable = false; + logger.error("Expected the database password to exists before a secondary stack was created!"); + } + return isRunnable; } } diff --git a/src/main/java/com/nike/cerberus/service/AthenaService.java b/src/main/java/com/nike/cerberus/service/AthenaService.java index 39e857e8..cf521e8b 100644 --- a/src/main/java/com/nike/cerberus/service/AthenaService.java +++ b/src/main/java/com/nike/cerberus/service/AthenaService.java @@ -16,6 +16,7 @@ package com.nike.cerberus.service; +import com.amazonaws.regions.Regions; import com.amazonaws.services.athena.AmazonAthenaClient; import com.amazonaws.services.athena.model.GetQueryExecutionRequest; import com.amazonaws.services.athena.model.GetQueryResultsRequest; @@ -36,21 +37,19 @@ public class AthenaService { private final Logger log = LoggerFactory.getLogger(getClass()); - private AmazonAthenaClient athena; - - + private AwsClientFactory athenaClientFactory; @Inject - public AthenaService(AwsClientFactory athenaClientFactory, - ConfigStore configStore) { + public AthenaService(AwsClientFactory athenaClientFactory) { - this.athena = athenaClientFactory.getClient(configStore.getPrimaryRegion()); + this.athenaClientFactory = athenaClientFactory; } /** * Executes an Athena query and waits for it to finish returning the results */ - public GetQueryResultsResult executeAthenaQuery(String query, String bucketName) { + public GetQueryResultsResult executeAthenaQuery(String query, String bucketName, Regions region) { + AmazonAthenaClient athena = athenaClientFactory.getClient(region); StartQueryExecutionResult result = athena .startQueryExecution(new StartQueryExecutionRequest() .withQueryString(query) diff --git a/src/main/java/com/nike/cerberus/service/Route53Service.java b/src/main/java/com/nike/cerberus/service/Route53Service.java index cf043adc..f399bc91 100644 --- a/src/main/java/com/nike/cerberus/service/Route53Service.java +++ b/src/main/java/com/nike/cerberus/service/Route53Service.java @@ -17,7 +17,6 @@ package com.nike.cerberus.service; import com.amazonaws.regions.Regions; -import com.amazonaws.services.route53.AmazonRoute53; import com.amazonaws.services.route53.AmazonRoute53Client; import com.amazonaws.services.route53.model.Change; import com.amazonaws.services.route53.model.ChangeAction; @@ -32,11 +31,8 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; -import javax.inject.Named; import java.util.Optional; -import static com.nike.cerberus.module.CerberusModule.CONFIG_REGION; - /** * Service wrapper for AWS CloudFormation. */ @@ -44,21 +40,22 @@ public class Route53Service { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final AmazonRoute53 route53Client; + private final AwsClientFactory route53ClientFactory; @Inject - public Route53Service(AwsClientFactory route53ClientFactory, - @Named(CONFIG_REGION) String configRegion) { + public Route53Service(AwsClientFactory route53ClientFactory) { // not region specific config region works - this.route53Client = route53ClientFactory.getClient(Regions.fromName(configRegion)); + this.route53ClientFactory = route53ClientFactory; } public void createRoute53RecordSet(String hostedZoneId, String recordSetName, String recordValue, RRType recordSetType, - String resourceRecordTtl) { + String resourceRecordTtl, + Regions region) { + logger.info("Creating Route53 record name: {}, value: {}", recordSetName, recordValue); ResourceRecord record = new ResourceRecord().withValue(recordValue); @@ -73,13 +70,16 @@ public void createRoute53RecordSet(String hostedZoneId, .withAction(ChangeAction.UPSERT) .withResourceRecordSet(recordSet)); - route53Client.changeResourceRecordSets(new ChangeResourceRecordSetsRequest() + route53ClientFactory.getClient(region).changeResourceRecordSets(new ChangeResourceRecordSetsRequest() .withHostedZoneId(hostedZoneId) .withChangeBatch(recordSetChangeBatch)); } - public Optional getRecordSetByName(String recordSetName, String hostedZoneId) { - ListResourceRecordSetsResult recordSets = route53Client.listResourceRecordSets( + public Optional getRecordSetByName(String recordSetName, + String hostedZoneId, + Regions region) { + + ListResourceRecordSetsResult recordSets = route53ClientFactory.getClient(region).listResourceRecordSets( new ListResourceRecordSetsRequest() .withHostedZoneId(hostedZoneId)); diff --git a/src/main/java/com/nike/cerberus/store/ConfigStore.java b/src/main/java/com/nike/cerberus/store/ConfigStore.java index c1b5c503..79d3dad3 100644 --- a/src/main/java/com/nike/cerberus/store/ConfigStore.java +++ b/src/main/java/com/nike/cerberus/store/ConfigStore.java @@ -254,9 +254,10 @@ public Optional getCertPart(String certName, String part) { public void storeCmsEnvConfig(Properties cmsConfigMap) { StringBuilder cmsConfigContents = new StringBuilder(); - cmsConfigMap.keySet().forEach(key -> { - cmsConfigContents.append(key).append('=').append(cmsConfigMap.get(key)).append('\n'); - }); + cmsConfigMap.keySet() + .stream() + .sorted() + .forEach(key -> cmsConfigContents.append(key).append('=').append(cmsConfigMap.get(key)).append('\n')); encryptAndSaveObject(ConfigConstants.CMS_ENV_CONFIG_PATH, cmsConfigContents.toString(), getDecryptedEnvironmentData()); } diff --git a/src/main/resources/cloudformation/cms-cluster.yaml b/src/main/resources/cloudformation/cms-cluster.yaml index a8ae817a..7e8801e4 100644 --- a/src/main/resources/cloudformation/cms-cluster.yaml +++ b/src/main/resources/cloudformation/cms-cluster.yaml @@ -8,8 +8,8 @@ Outputs: cmsInstanceProfileName: Value: !Ref 'CmsInstanceProfile' Parameters: - baseStackName: - Description: The name of the Cerberus base CloudFormation stack + cmsIamRoleName: + Description: The name of CMS Iam Role from the IAM role stack in the primary region. Type: String amiId: Description: The AMI ID for the CMS instances @@ -86,7 +86,7 @@ Resources: Properties: Path: / Roles: - - Fn::ImportValue: !Sub "${baseStackName}-cmsIamRoleName" + - !Ref 'cmsIamRoleName' Type: AWS::IAM::InstanceProfile CmsLaunchConfiguration: Properties: diff --git a/src/test/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapperTest.java b/src/test/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapperTest.java index 20da0beb..35690dad 100644 --- a/src/test/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapperTest.java +++ b/src/test/java/com/nike/cerberus/cli/EnvironmentConfigToArgsMapperTest.java @@ -34,6 +34,7 @@ import java.io.InputStream; +import static com.nike.cerberus.domain.cloudformation.CloudFormationParametersDelegate.STACK_REGION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -154,6 +155,7 @@ public void test_create_management_service_cluster() { String[] expected = { "-f", "/path/to/environment.yaml", commandName, + STACK_REGION, "us-west-2", StackDelegate.AMI_ID_LONG_ARG, "ami-3333", StackDelegate.INSTANCE_SIZE_LONG_ARG, "m3.medium", StackDelegate.KEY_PAIR_NAME_LONG_ARG, "cerberus-test", @@ -176,6 +178,7 @@ public void test_vpc_access_whitelist() { String[] expected = { "-f", "/path/to/environment.yaml", commandName, + STACK_REGION, "us-west-2", WhitelistCidrForVpcAccessCommand.CIDR_LONG_ARG, "50.39.106.150/32", WhitelistCidrForVpcAccessCommand.PORT_LONG_ARG, "8443", WhitelistCidrForVpcAccessCommand.PORT_LONG_ARG, "22"