diff --git a/source/cdk/cdk_slurm_stack.py b/source/cdk/cdk_slurm_stack.py index 6f62ea57..3feeb220 100644 --- a/source/cdk/cdk_slurm_stack.py +++ b/source/cdk/cdk_slurm_stack.py @@ -275,11 +275,9 @@ def check_config(self): logger.warning(f"ErrorSnsTopicArn not set. Provide error-sns-topic-arn on the command line or ErrorSnsTopicArn in the config file to get error notifications.") self.config['ErrorSnsTopicArn'] = '' - if 'Domain' not in self.config and 'HostedZoneId' not in self.config: + if 'Domain' not in self.config: self.config['Domain'] = f"{self.stack_name}.local" - if 'Domain' in self.config and 'HostedZoneId' in self.config: - logger.error(f"Cannot specify both Domain({self.config['Domain']}) and HostedZoneId{self.config['HostedZoneId']}") - sys.exist(1) + logger.info(f"Domain defaulted to {self.config['Domain']}") if 'ClusterName' not in self.config['slurm']: self.config['slurm']['ClusterName'] = self.stack_name @@ -492,25 +490,30 @@ def create_vpc(self): logger.info(f"Subnet set to {self.config['SubnetId']}") logger.info(f"availability zone: {self.subnet.availability_zone}") + remote_vpcs = {} + for region_dict in self.config['slurm']['InstanceConfig']['Regions']: + if region_dict['Region'] == self.config['Region']: + continue + remote_vpcs[region_dict['Region']] = ec2.Vpc.from_lookup( + self, f"Vpc{region_dict['Region']}", + region = region_dict['Region'], + vpc_id = region_dict['VpcId']) + # Can't create query logging for private hosted zone. if 'HostedZoneId' in self.config: - self.hosted_zone = route53.HostedZone.from_hosted_zone_id(self, "PrivateDns", hosted_zone_id=self.config['HostedZoneId']) - self.config['Domain'] = self.hosted_zone.zone_name + self.hosted_zone = route53.HostedZone.from_hosted_zone_attributes( + self, "PrivateDns", + hosted_zone_id = self.config['HostedZoneId'], + zone_name = self.config['Domain'] + ) else: self.hosted_zone = route53.HostedZone(self, "PrivateDns", vpcs = [self.vpc], zone_name = self.config['Domain'] ) - remote_vpcs = {} - for region_dict in self.config['slurm']['InstanceConfig']['Regions']: - if region_dict['Region'] == self.config['Region']: - continue - remote_vpcs[region_dict['Region']] = ec2.Vpc.from_lookup( - self, f"Vpc{region_dict['Region']}", - region = region_dict['Region'], - vpc_id = region_dict['VpcId']) - # BUG: CDK isn't creating the correct region for the vpcs even though cdk_context.json has it right. - #self.hosted_zone.add_vpc(remote_vpcs[region_dict['Region']]) + # BUG: CDK isn't creating the correct region for the vpcs even though cdk_context.json has it right. + # for remote_region, remote_vpc in remote_vpcs.items(): + # self.hosted_zone.add_vpc(remote_vpc) def create_lambdas(self): dnsLookupLambdaAsset = s3_assets.Asset(self, "DnsLookupLambdaAsset", path="resources/lambdas/DnsLookup") @@ -558,19 +561,30 @@ def create_lambdas(self): ) ) - createRoute53ZoneLambdaAsset = s3_assets.Asset(self, "CreateRoute53ZoneLambdaAsset", path="resources/lambdas/CreateRoute53Zone") - self.create_route53_zone_lambda = aws_lambda.Function( - self, "CreateRoute53ZoneLambda", - function_name=f"{self.stack_name}-CreateRoute53Zone", - description="Create Route53 zone in other region", + routeRoute53ZoneAddVpcLambdaAsset = s3_assets.Asset(self, "Route53HostedZoneAddVpcLambdaAsset", path="resources/lambdas/Route53HostedZoneAddVpc") + self.route53_hosted_zone_add_vpc_lambda = aws_lambda.Function( + self, "Route53HostedZoneAddVpcLambda", + function_name=f"{self.stack_name}-Route53HostedZoneAddVpc", + description="Associated VPC with Route53 hosted zone", memory_size=128, runtime=aws_lambda.Runtime.PYTHON_3_7, timeout=Duration.minutes(3), log_retention=logs.RetentionDays.INFINITE, - handler="CreateRoute53Zone.lambda_handler", - code=aws_lambda.Code.from_bucket(createRoute53ZoneLambdaAsset.bucket, createRoute53ZoneLambdaAsset.s3_object_key) + handler="Route53HostedZoneAddVpc.lambda_handler", + code=aws_lambda.Code.from_bucket(routeRoute53ZoneAddVpcLambdaAsset.bucket, routeRoute53ZoneAddVpcLambdaAsset.s3_object_key) ) + self.route53_hosted_zone_add_vpc_lambda.add_to_role_policy( + statement=iam.PolicyStatement( + effect=iam.Effect.ALLOW, + actions=[ + "route53:AssociateVpcWithHostedZone", + "route53:DissociateVpcFromHostedZone", + ], + resources=['*'] + ) + ) + getOntapSvmDNSNameLambdaAsset = s3_assets.Asset(self, "GetOntapSvmDNSNameLambdaAsset", path="resources/lambdas/GetOntapSvmDNSName") self.get_ontap_svm_dnsname_lambda = aws_lambda.Function( self, "GetOntapSvmDNSNameLambda", diff --git a/source/cdk/config_schema.py b/source/cdk/config_schema.py index eb0183c2..4c10ca58 100644 --- a/source/cdk/config_schema.py +++ b/source/cdk/config_schema.py @@ -115,15 +115,14 @@ # Domain: # Domain name for the Route 53 private hosted zone that will be used # by the slurm cluster for DNS. + # Alternately, provide HostedZoneId of an existing Route53 hosted zone to use and + # the zone name of the HostedZoneId. # By default will be {StackName}.local - # Alternately, provide HostedZoneId of an existing Route53 hosted zone to use. - # Cannot specify both Domain and HostedZoneId. Optional('Domain'): str, # # HostedZoneId: # ID of an existing hosted zone that will be used by the slurm cluster for DNS. - # Alternately, provide Domain name to use for a new Route53 hosted zone to use. - # Cannot specify both Domain and HostedZoneId. + # You must provide the Domain name of the HostedZone if it is different than the default. Optional('HostedZoneId'): str, Optional('TimeZone', default='US/Central'): str, 'slurm': { diff --git a/source/resources/lambdas/CreateRoute53Zone/CreateRoute53Zone.py b/source/resources/lambdas/Route53HostedZoneAddVpc/Route53HostedZoneAddVpc.py similarity index 61% rename from source/resources/lambdas/CreateRoute53Zone/CreateRoute53Zone.py rename to source/resources/lambdas/Route53HostedZoneAddVpc/Route53HostedZoneAddVpc.py index c48ab12b..66bee4bf 100644 --- a/source/resources/lambdas/CreateRoute53Zone/CreateRoute53Zone.py +++ b/source/resources/lambdas/Route53HostedZoneAddVpc/Route53HostedZoneAddVpc.py @@ -19,16 +19,18 @@ ''' Create/delete route53 zone in another region. ''' -import cfnresponse + import boto3 +import cfnresponse import logging + logging.getLogger().setLevel(logging.INFO) def lambda_handler(event, context): try: logging.info(f"event:\n{json.dumps(event, indent=4)}") properties = event['ResourceProperties'] - required_properties = ['Region', 'VpcId', 'Domain'] + required_properties = ['HostedZoneId', 'VpcId', 'VpcRegion'] error_message = "" for property in required_properties: try: @@ -38,19 +40,36 @@ def lambda_handler(event, context): if error_message: raise KeyError(error_message) - route53_client = boto3.client('route53', region_name=properties['Region']) - hosted_zone_id = route53_client.create_hosted_zone( - Name = properties['Domain'], - VPC = { - 'VPCRegion': properties['Region'], - 'VPCId': properties['VpcId'], - }, - HostedZoneConfig = {'PrivateZone': True} - )['HostedZone']['Id'] + requestType = event['RequestType'] + + route53_client = boto3.client('route53') + + if requestType in ['Update', 'Delete']: + try: + route53_client.disassociate_vpc_from_hosted_zone( + HostedZoneId = properties['HostedZoneId'], + VPC = { + 'VPCRegion': properties['VpcRegion'], + 'VPCId': properties['VpcId'], + }, + HostedZoneConfig = {'PrivateZone': True} + ) + except: + pass + + if requestType in ['Create', 'Update']: + route53_client.associate_vpc_with_hosted_zone( + HostedZoneId = properties['HostedZoneId'], + VPC = { + 'VPCRegion': properties['VpcRegion'], + 'VPCId': properties['VpcId'], + }, + HostedZoneConfig = {'PrivateZone': True} + ) except Exception as e: logging.exception(str(e)) cfnresponse.send(event, context, cfnresponse.FAILED, {'error': str(e)}, str(e)) raise - cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, "{} {}.{} {}".format(properties['Type'], properties['Hostname'], properties['Domain'], properties['Value'])) + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, "") diff --git a/source/resources/lambdas/CreateRoute53Zone/cfnresponse.py b/source/resources/lambdas/Route53HostedZoneAddVpc/cfnresponse.py similarity index 100% rename from source/resources/lambdas/CreateRoute53Zone/cfnresponse.py rename to source/resources/lambdas/Route53HostedZoneAddVpc/cfnresponse.py