aws / copilot-cli

The AWS Copilot CLI is a tool for developers to build, release and operate production ready containerized applications on AWS App Runner or Amazon ECS on AWS Fargate.
https://aws.github.io/copilot-cli/
Apache License 2.0
3.53k stars 417 forks source link

Database Cluster failed to deploy #2598

Closed mikelhamer closed 3 years ago

mikelhamer commented 3 years ago

I added an Aurora serverless postgres db, but my service is failing with this error.

Embedded stack arn:aws:cloudformation:us-east-2:384930474045:stack/my-test-api-AddonsStack-N2ISKDJ48GTC/2aed4980-e343-039l-dkc4-021c9dk39j3e was not successfully created: The following resource(s) failed to create: [myapiDBCluster].

this is the only error I can see in the CF events.

I have no idea how to continue researching where or why it failed. Any advice is greatly appreciated!

efekarakus commented 3 years ago

Hi @mikelhamer !

Was the addon created with copilot storage init? If there is nothing sensitive, you can also copy/paste the addon template here for us to troubleshoot.

One way to get additional details on the failure is triggering the deployment again, then going to the AWS CloudFormation console and checking the events there for the addon stack during creation.

mikelhamer commented 3 years ago

Thanks @efekarakus! Yes it was generated with copilot storage init.

Here is the addon template, the only thing I modified was enabling the http endpoint and deletion protection.

Parameters:
  App:
    Type: String
    Description: Your application's name.
  Env:
    Type: String
    Description: The environment name your service, job, or workflow is being deployed to.
  Name:
    Type: String
    Description: The name of the service, job, or workflow being deployed.
  # Customize your Aurora Serverless cluster by setting the default value of the following parameters.
  myapiDBName:
    Type: String
    Description: The name of the initial database to be created in the DB cluster.
    Default: my_api
    # Cannot have special characters
    # Naming constraints: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints
  myapiDBAutoPauseSeconds:
    Type: Number
    Description: The duration in seconds before the cluster pauses.
    Default: 1000
  myapiDBEnableHttpEndpoint:
    Type: String
    Description: The DB cluster has HTTP endpoint enabled
    Default: "true"
    "AllowedValues": [
        "true",
        "false"
    ]
  myapiDBDeletionProtection:
    Type: String
    Description: The DB cluster has deletion protection enabled
    Default: "true"
    "AllowedValues": [
        "true",
        "false"
    ]
Conditions:
  HttpEndpointEnabled: !Equals
    - !Ref myapiDBEnableHttpEndpoint
    - "true"
  DeletionProtectionEnabled: !Equals
    - !Ref myapiDBDeletionProtection
    - "true"
Mappings:
  myapiEnvScalingConfigurationMap: 
    test:
      "DBMinCapacity": 2 # AllowedValues: [2, 4, 8, 16, 32, 64, 192, 384]
      "DBMaxCapacity": 8 # AllowedValues: [2, 4, 8, 16, 32, 64, 192, 384]

    All:
      "DBMinCapacity": 2 # AllowedValues: [2, 4, 8, 16, 32, 64, 192, 384]
      "DBMaxCapacity": 8 # AllowedValues: [2, 4, 8, 16, 32, 64, 192, 384]

Resources:
  myapiDBSubnetGroup:
    Type: 'AWS::RDS::DBSubnetGroup'
    Properties:
      DBSubnetGroupDescription: Group of Copilot private subnets for Aurora cluster.
      SubnetIds:
        !Split [',', { 'Fn::ImportValue': !Sub '${App}-${Env}-PrivateSubnets' }]
  myapiSecurityGroup:
    Metadata:
      'aws:copilot:description': 'A security group for your workload to access the DB cluster myapi'
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: !Sub 'The Security Group for ${Name} to access DB cluster myapi.'
      VpcId:
        Fn::ImportValue:
          !Sub '${App}-${Env}-VpcId'
      Tags:
        - Key: Name
          Value: !Sub 'copilot-${App}-${Env}-${Name}-Aurora'
  myapiDBClusterSecurityGroup:
    Metadata:
      'aws:copilot:description': 'A security group for your DB cluster myapi'
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: The Security Group for the database cluster.
      SecurityGroupIngress:
        - ToPort: 5432
          FromPort: 5432
          IpProtocol: tcp
          Description: !Sub 'From the Aurora Security Group of the workload ${Name}.'
          SourceSecurityGroupId: !Ref myapiSecurityGroup
      VpcId:
        Fn::ImportValue:
          !Sub '${App}-${Env}-VpcId'
  myapiAuroraSecret:
    Metadata:
      'aws:copilot:description': 'A Secrets Manager secret to store your DB credentials'
    Type: AWS::SecretsManager::Secret
    Properties:
      Description: !Sub Aurora main user secret for ${AWS::StackName}
      GenerateSecretString:
        SecretStringTemplate: '{"username": "postgres"}'
        GenerateStringKey: "password"
        ExcludePunctuation: true
        IncludeSpace: false
        PasswordLength: 16
  myapiDBClusterParameterGroup:
    Metadata:
      'aws:copilot:description': 'A DB parameter group for engine configuration values'
    Type: 'AWS::RDS::DBClusterParameterGroup'
    Properties:
      Description: !Ref 'AWS::StackName'
      Family: 'aurora-postgresql10'
      Parameters:
        client_encoding: 'UTF8'
  myapiDBCluster:
    Metadata:
      'aws:copilot:description': 'The myapi Aurora Serverless database cluster'
    Type: 'AWS::RDS::DBCluster'
    Properties:
      MasterUsername:
        !Join [ "",  [ '{{resolve:secretsmanager:', !Ref myapiAuroraSecret, ":SecretString:username}}" ]]
      MasterUserPassword:
        !Join [ "",  [ '{{resolve:secretsmanager:', !Ref myapiAuroraSecret, ":SecretString:password}}" ]]
      DatabaseName: !Ref myapiDBName
      Engine: 'aurora-postgresql'
      EngineVersion: '10.12'
      EngineMode: serverless
      DBClusterParameterGroupName: !Ref myapiDBClusterParameterGroup
      DBSubnetGroupName: !Ref myapiDBSubnetGroup
      VpcSecurityGroupIds:
        - !Ref myapiDBClusterSecurityGroup
      ScalingConfiguration:
        AutoPause: true
        # Replace "All" below with "!Ref Env" to set different autoscaling limits per environment.
        MinCapacity: !FindInMap [myapiEnvScalingConfigurationMap, All, DBMinCapacity]
        MaxCapacity: !FindInMap [myapiEnvScalingConfigurationMap, All, DBMaxCapacity]
        SecondsUntilAutoPause: !Ref myapiDBAutoPauseSeconds
        EnableHttpEndpoint: !If [ HttpEndpointEnabled, true, false ]
        DeletionProtection: !If [ DeletionProtectionEnabled, true, false ]
  myapiSecretAuroraClusterAttachment:
    Type: AWS::SecretsManager::SecretTargetAttachment
    Properties:
      SecretId: !Ref myapiAuroraSecret
      TargetId: !Ref myapiDBCluster
      TargetType: AWS::RDS::DBCluster
Outputs:
  myapiSecret: # injected as myapi_SECRET environment variable by Copilot.
    Description: "The JSON secret that holds the database username and password. Fields are 'host', 'port', 'dbname', 'username', 'password', 'dbClusterIdentifier' and 'engine'"
    Value: !Ref myapiAuroraSecret
  myapiSecurityGroup:
    Description: "The security group to attach to the workload."
    Value: !Ref myapiSecurityGroup

I will try watching the addon stack during another deploy.

mikelhamer commented 3 years ago

Doh! These two lines were indented one level too far.

        EnableHttpEndpoint: !If [ HttpEndpointEnabled, true, false ]
        DeletionProtection: !If [ DeletionProtectionEnabled, true, false ]

Looking at the addon stack helped me find the issue. Thanks!

efekarakus commented 3 years ago

Yay I am glad you got it working 🥳 !!