cloudformation/database/serverless-database.yaml (311 lines of code) (raw):
AWSTemplateFormatVersion: 2010-09-09
Description: AWS ParallelCluster Slurm Accounting Database
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Database Cluster Configuration"
Parameters:
- ClusterName
- ClusterAdmin
- AdminPasswordSecretString
- MinCapacity
- MaxCapacity
- Label:
default: "Network Configuration"
Parameters:
- Vpc
- DatabaseClusterSubnetOne
- DatabaseClusterSubnetTwo
- Subnet1CidrBlock
- Subnet2CidrBlock
ParameterLabels:
Vpc:
default: "The VPC to use for the database cluster."
ClusterName:
default: "The name of the database cluster"
ClusterAdmin:
default: "The database administrator user name."
AdminPasswordSecretString:
default: "The administrator password."
MinCapacity:
default: "The minimum scaling capacity of the database cluster."
MaxCapacity:
default: "The maximum scaling capacity of the database cluster."
DatabaseClusterSubnetOne:
default: "The first subnet to use for the database cluster."
DatabaseClusterSubnetTwo:
default: "The second subnet to use for the database cluster."
Subnet1CidrBlock:
default: "The CIDR block to be used for the first Subnet if its creation is requested."
Subnet2CidrBlock:
default: "The CIDR block to be used for the second Subnet if its creation is requested."
cfn-lint:
config:
ignore_checks:
- E3690
Parameters:
ClusterName:
Description: Database Cluster Name
Type: String
Default: "slurm-accounting-cluster"
MinLength: 1
MaxLength: 63
AllowedPattern: ^[a-z][-a-z0-9]{0,62}$
ConstraintDescription: >-
Cluster name must be between 1 and 63 characters, start with a lower case character, and be followed by a mix of
lower case characters, digits, and - (hyphens).
AdminPasswordSecretString:
Description: >-
Password must be at least 8 characters long and contain at least 1 upper case, 1 lower case, 1 digit, and 1
non-alphanumeric character. It must not contain any of the following: # (hash), / (slash), ' (single quote), " (double quote)
or @ (at sign).
Type: String
NoEcho: true
MinLength: 8
# Only allow 'Medium' or better strength passwords according to https://dev.mysql.com/doc/refman/8.0/en/validate-password.html
AllowedPattern: (?=^.{8,}$)(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[^\w\s])(?!.*[@/'"#])^.*
ConstraintDescription: >-
Password must be at least 8 characters with at least one uppercase letter, one lower case letter, one numeric
digit, and one special (non-alphanumeric) character. It can not contain any of the following: # (hash), / (slash), ' (single quote), " (double quote) and @ (at sign).
ClusterAdmin:
Description: Administrator user name.
Type: String
Default: clusteradmin
MinLength: 3
MaxLength: 64
Vpc:
Description: VPC ID.
Type: AWS::EC2::VPC::Id
DatabaseClusterSubnetOne:
Description: First Subnet ID (leave BLANK to create a new subnet).
Type: String
# Type: AWS::EC2::Subnet::Id
Default: ''
DatabaseClusterSubnetTwo:
Description: Second subnet ID (leave BLANK to create a new subnet). This subnet must be in different availability zone from the first subnet.
Type: String
# Type: AWS::EC2::Subnet::Id
Default: ''
Subnet1CidrBlock:
Description: CIDR block for first Subnet (used only if creation is requested - IN THIS CASE THE DEFAULT VALUE MUST BE CHANGED).
Type: String
Default: '0.0.0.0/24'
AllowedPattern: >-
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$
ConstraintDescription: >-
The CIDR block must be formatted as W.X.Y.Z/prefix , where prefix must be between 16 and 28.
Subnet2CidrBlock:
Description: CIDR block for the second Subnet (used only if creation is requested - IN THIS CASE THE DEFAULT VALUE MUST BE CHANGED).
Type: String
Default: '0.0.0.0/24'
AllowedPattern: >-
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$
ConstraintDescription: >-
The CIDR block must be formatted as W.X.Y.Z/prefix , where prefix must be between 16 and 28.
MinCapacity:
Description: Must be less than the maximum capacity.
Type: Number
Default: 1
MinValue: .5
MaxValue: 127.5
MaxCapacity:
Description: Must be greater than or equal to the minimum capacity.
Type: Number
Default: 4
MinValue: 1
MaxValue: 128
Transform: AWS::Serverless-2016-10-31
Conditions:
CreateSubnets: !Or [!Equals [!Ref DatabaseClusterSubnetOne, ''], !Equals [!Ref DatabaseClusterSubnetTwo, '']]
InUsIsobEast1: !Equals [ !Ref AWS::Region, 'us-isob-east-1' ]
InUsIsoEast1: !Equals [ !Ref AWS::Region, 'us-iso-east-1' ]
UseServerlessDatabase: !Not [!Or [Condition: InUsIsobEast1, Condition: InUsIsoEast1]]
Rules:
BadSubnetsCidrsAssertion:
RuleCondition: !Or
- !Equals
- !Ref DatabaseClusterSubnetOne
- ''
- !Equals
- !Ref DatabaseClusterSubnetTwo
- ''
Assertions:
- Assert: !Not
- !Equals
- !Ref Subnet1CidrBlock
- '0.0.0.0/24'
AssertDescription: The default CIDR block for the first subnet must be changed if the subnet creation is requested.
- Assert: !Not
- !Equals
- !Ref Subnet2CidrBlock
- '0.0.0.0/24'
AssertDescription: The default CIDR block for the second subnet must be changed if the subnet creation is requested.
Resources:
#
# Optional Networking
#
AccountingClusterSubnet1:
Type: 'AWS::EC2::Subnet'
Condition: CreateSubnets
Properties:
VpcId: !Ref Vpc
AvailabilityZone: !Sub
- "${AWS::Region}${AzLetter}"
- { AzLetter: !If [ InUsIsobEast1, 'c', 'a'] }
CidrBlock: !Ref Subnet1CidrBlock
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: AccountingClusterSubnet1
- Key: 'parallelcluster:infrastructure'
Value: 'slurm accounting'
AccountingClusterSubnet1RouteTable:
Type: 'AWS::EC2::RouteTable'
Condition: CreateSubnets
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: AccountingClusterSubnet1
- Key: 'parallelcluster:infrastructure'
Value: 'slurm accounting'
AccountingClusterSubnet1RouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Condition: CreateSubnets
Properties:
RouteTableId: !Ref AccountingClusterSubnet1RouteTable
SubnetId: !Ref AccountingClusterSubnet1
AccountingClusterSubnet2:
Type: 'AWS::EC2::Subnet'
Condition: CreateSubnets
Properties:
VpcId: !Ref Vpc
AvailabilityZone: !Sub '${AWS::Region}b'
CidrBlock: !Ref Subnet2CidrBlock
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: AccountingClusterSubnet2
- Key: 'parallelcluster:infrastructure'
Value: 'slurm accounting'
AccountingClusterSubnet2RouteTable:
Type: 'AWS::EC2::RouteTable'
Condition: CreateSubnets
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: AccountingClusterSubnet2
- Key: 'parallelcluster:infrastructure'
Value: 'slurm accounting'
AccountingClusterSubnet2RouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Condition: CreateSubnets
Properties:
RouteTableId: !Ref AccountingClusterSubnet2RouteTable
SubnetId: !Ref AccountingClusterSubnet2
#
# Database Cluster
#
AccountingClusterParameterGroup:
Type: 'AWS::RDS::DBClusterParameterGroup'
Properties:
Description: Cluster parameter group for aurora-mysql
Family: aurora-mysql8.0
Parameters:
require_secure_transport: 'ON'
innodb_lock_wait_timeout: '900'
Tags:
- Key: 'parallelcluster:usecase'
Value: 'slurm accounting'
AccountingClusterSubnetGroup:
Type: 'AWS::RDS::DBSubnetGroup'
Properties:
DBSubnetGroupDescription: !Sub 'Subnets for AccountingCluster-${AWS::Region} database'
SubnetIds:
- !If [CreateSubnets, !Ref AccountingClusterSubnet1, !Ref DatabaseClusterSubnetOne]
- !If [CreateSubnets, !Ref AccountingClusterSubnet2, !Ref DatabaseClusterSubnetTwo]
Tags:
- Key: 'parallelcluster:usecase'
Value: 'slurm accounting'
AccountingClusterSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: RDS security group
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: '-1'
Tags:
- Key: 'parallelcluster:usecase'
Value: 'slurm accounting'
VpcId: !Ref Vpc
AccountingClusterSecurityGroupInboundRule:
Type: 'AWS::EC2::SecurityGroupIngress'
Properties:
IpProtocol: tcp
Description: Allow incoming connections from client security group
FromPort: !GetAtt
- AccountingCluster
- Endpoint.Port
GroupId: !GetAtt
- AccountingClusterSecurityGroup
- GroupId
SourceSecurityGroupId: !GetAtt
- AccountingClusterClientSecurityGroup
- GroupId
ToPort: !GetAtt
- AccountingCluster
- Endpoint.Port
AccountingClusterAdminSecret:
Type: 'AWS::SecretsManager::Secret'
Properties:
Description: 'Serverless Database Cluster Administrator Password'
SecretString: !Ref AdminPasswordSecretString
Tags:
- Key: 'parallelcluster:usecase'
Value: 'slurm accounting'
AccountingCluster:
Type: 'AWS::RDS::DBCluster'
Properties:
DBClusterIdentifier: !Ref ClusterName
Engine: "aurora-mysql"
EngineVersion: "8.0"
CopyTagsToSnapshot: true
DBClusterParameterGroupName: !Ref AccountingClusterParameterGroup
DBSubnetGroupName: !Ref AccountingClusterSubnetGroup
EnableHttpEndpoint: false
MasterUsername: !Ref ClusterAdmin
MasterUserPassword: !Ref AdminPasswordSecretString
ServerlessV2ScalingConfiguration: !If
- UseServerlessDatabase
- MaxCapacity: !Ref MaxCapacity
MinCapacity: !Ref MinCapacity
- !Ref AWS::NoValue
StorageEncrypted: true
Tags:
- Key: 'parallelcluster:usecase'
Value: 'slurm accounting'
VpcSecurityGroupIds:
- !GetAtt
- AccountingClusterSecurityGroup
- GroupId
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
AccountingClusterInstance1:
Type: 'AWS::RDS::DBInstance'
Properties:
DBInstanceClass: !If [UseServerlessDatabase, 'db.serverless', 'db.r5.large']
DBClusterIdentifier: !Ref AccountingCluster
DBInstanceIdentifier: !Sub '${ClusterName}-instance-1'
Engine: "aurora-mysql"
PubliclyAccessible: false
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
AccountingClusterInstance2:
Type: 'AWS::RDS::DBInstance'
Properties:
DBInstanceClass: !If [UseServerlessDatabase, 'db.serverless', 'db.r5.large']
DBClusterIdentifier: !Ref AccountingCluster
DBInstanceIdentifier: !Sub '${ClusterName}-instance-2'
Engine: "aurora-mysql"
PubliclyAccessible: false
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
AccountingClusterClientSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Security Group to allow connection to Serverless DB Cluster
Tags:
- Key: 'parallel-cluster:usecase'
Value: 'slurm accounting'
VpcId: !Ref Vpc
AccountingClusterClientSecurityGroupOutboundRule:
Type: 'AWS::EC2::SecurityGroupEgress'
Properties:
GroupId: !GetAtt
- AccountingClusterClientSecurityGroup
- GroupId
IpProtocol: tcp
Description: Allow incoming connections from PCluster
DestinationSecurityGroupId: !GetAtt
- AccountingClusterSecurityGroup
- GroupId
FromPort: !GetAtt
- AccountingCluster
- Endpoint.Port
ToPort: !GetAtt
- AccountingCluster
- Endpoint.Port
Outputs:
ClusterName:
Value: !Ref ClusterName
DatabaseHost:
Value: !GetAtt
- AccountingCluster
- Endpoint.Address
Export:
Name: !Sub ${AWS::StackName}-DatabaseHost
DatabasePort:
Value: !GetAtt
- AccountingCluster
- Endpoint.Port
Export:
Name: !Sub ${AWS::StackName}-DatabasePort
DatabaseAdminUser:
Value: !Ref ClusterAdmin
Export:
Name: !Sub ${AWS::StackName}-DatabaseAdminUser
DatabaseSecretArn:
Value: !Ref AccountingClusterAdminSecret
Export:
Name: !Sub ${AWS::StackName}-DatabaseSecretArn
DatabaseVpcId:
Value: !Ref Vpc
DatabaseClusterSecurityGroup:
Value: !GetAtt
- AccountingClusterSecurityGroup
- GroupId
Export:
Name: !Sub ${AWS::StackName}-DatabaseClusterSecurityGroup
DatabaseClusterSubnet1:
Value: !If [CreateSubnets, !Ref AccountingClusterSubnet1, !Ref DatabaseClusterSubnetOne]
DatabaseClusterSubnet2:
Value: !If [CreateSubnets, !Ref AccountingClusterSubnet2, !Ref DatabaseClusterSubnetTwo]
DatabaseClientSecurityGroup:
Value: !GetAtt
- AccountingClusterClientSecurityGroup
- GroupId