AWSTemplateFormatVersion: 2010-09-09 Description: >- Mozart data service stack. The stack name is implicitly used as the name of the EKS cluster and the MSK cluster created by the stack. Parameters: S3Bucket: Description: S3 bucket name, which must be 3 to 63 characters long Type: String AllowedPattern: '[a-zA-Z0-9][a-zA-Z0-9-\.]{2,62}' DesktopRemoteAccessCIDR: Description: Remote access Ip V4 CIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String DesktopType: Description: Graphical desktop, or headless desktop Default: "Graphical" Type: String AllowedValues: - "Graphical" - "Headless" DataClientType: Description: Kafka and RosBridge support, or RosBridge support only. Default: "KafkaAndRosBridge" Type: String AllowedValues: - "KafkaAndRosBridge" - "RosBridge" VpcCIDR: Default: 172.30.0.0/16 Description: (Advanced) Vpc CIDR. Do not use 192.168.0.0 range. AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String VpcPublicSubnet1CIDR: Default: 172.30.0.0/24 Description: (Advanced) Public Subnet1 CIDR inside VpcCIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String VpcPublicSubnet2CIDR: Default: 172.30.1.0/24 Description: (Advanced) Public Subnet2 CIDR inside VpcCIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String VpcPublicSubnet3CIDR: Default: 172.30.2.0/24 Description: (Advanced) Public Subnet3 CIDR inside VpcCIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String VpcPrivateSubnet1CIDR: Default: 172.30.64.0/18 Description: (Advanced) Private Subnet1 CIDR inside VpcCIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String VpcPrivateSubnet2CIDR: Default: 172.30.128.0/18 Description: (Advanced) Private Subnet2 CIDR inside VpcCIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String VpcPrivateSubnet3CIDR: Default: 172.30.192.0/18 Description: (Advanced) Private Subnet2 CIDR inside VpcCIDR AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})' Type: String RedshiftDatabaseName: Description: Redshift database name Type: String Default: mozart AllowedPattern: "([a-z]|[0-9])+" RedshiftServerlessBaseCapacity: Description: Redshift serverless base capacity in RPUs Type: Number Default: 128 MinValue: 128 RedshiftWorkgroup: Description: Redshift serverless workgroup Type: String Default: "mozart" AllowedPattern: "([a-z]|[0-9])+" RedshiftNamespace: Description: Redshift serverless namespace Type: String Default: "mozart" AllowedPattern: "([a-z]|[0-9])+" RedshiftMasterUsername: Description: The user name that is associated with the master user account for the Redshift cluster that is being created Type: String Default: admin AllowedPattern: "([a-z])([a-z]|[0-9])*" RedshiftMasterUserPassword: AllowedPattern: "(?=^.{8,}$)(?=.*\\d)(?=.*[A-Z])(?=.*[a-z]).*$" Description: "Resdhift master password: Atleast length 8, lower case, upper case and digits." NoEcho: "true" Type: String MSKBrokerNodeType: Description: The type of node to be provisioned for MSK Broker Type: String Default: kafka.m5.large AllowedValues: - kafka.m5.large - kafka.m5.2xlarge - kafka.m5.4xlarge MSKNumberOfNodes: Description: The number of MSK Broker nodes, must be >= 3 Type: Number Default: 3 MinValue: 3 FSxForLustre: Description: >- Option to enable, disable FSx for Lustre file system. If enabled, the FSx for Lustre file system automatically imports data from s3://S3bucket/FSxS3ImportPrefix. See S3Bucket and FSxS3ImportPrefix parameters. Type: String Default: 'enabled' AllowedValues: - 'enabled' - 'disabled' FSxStorageCapacityGiB: Description: FSx Storage capacity in multiples of 2400 GiB Type: Number MinValue: 2400 Default: 7200 FSxS3ImportPrefix: Description: (Optional) FSx S3 prefix for importing data Type: String AllowedPattern: '^(?!/)[a-zA-Z0-9-_\./]*' Default: "" EKSEncryptSecretsKmsKeyArn: Description: Encrypt EKS Secrets Key ARN (Leave blank to create) Type: String Default: "" KubernetesVersion: Description: Kubernetes Version Type: String AllowedValues: [ "1.27" ] Default: "1.27" KubectlVersion: Description: Kubectl Version Type: String AllowedValues: [ "1.27.1/2023-04-19" ] Default: "1.27.1/2023-04-19" EKSNodeVolumeSizeGiB: Description: EKS Node volume size GiB Type: Number MinValue: 200 Default: 200 EKSNodeGroupMinSize: Description: EKS Node group minimum size Type: Number MinValue: 1 Default: 1 EKSNodeGroupMaxSize: Description: EKS Node group maximum size Type: Number MinValue: 2 Default: 10 EKSNodeGroupDesiredSize: Description: EKS Node group desired size Type: Number MinValue: 1 Default: 2 EKSNodeGroupInstanceType: Description: EKS Node group instance type Type: String Default: "m5n.8xlarge" AllowedValues: - m5n.2xlarge - m5n.4xlarge - m5n.8xlarge - r5n.8xlarge - r5n.12xlarge - r5n.16xlarge - r5n.24xlarge UbuntuAMI: Description: >- Advanced option to override Ubuntu AMI. ROS1 'noetic' requires Ubuntu 20.04, and ROS2 'humble' requires Ubuntu 22.04. Type: String AllowedPattern: '(ami-[0-9a-z]{17})?' DesktopInstanceType: Description: >- EC2 instance type for desktop. Type: String Default: g4dn.xlarge AllowedValues: - m5n.xlarge - m5n.2xlarge - m5n.4xlarge - g3s.xlarge - g3.4xlarge - g3.8xlarge - g3.16xlarge - g4dn.xlarge - g4dn.2xlarge - g4dn.4xlarge - g4dn.8xlarge - g4dn.12xlarge - g4dn.16xlarge ConstraintDescription: Must be a valid GPU EC2 instance type. DesktopEbsVolumeSize: Description: Desktop EBS volume size (GiB) Type: Number MinValue: 200 Default: 200 DesktopEbsVolumeType: Default: 'gp3' Description: Desktop EBS volume type Type: String AllowedValues: - 'gp2' - 'gp3' KeyPairName: Description: EC2 SSH KeyPair Name Type: 'AWS::EC2::KeyPair::KeyName' AllowedPattern: '^[\x00-\x7F]{1,255}[^.\s]$' DesktopHasPublicIpAddress: Description: Should a Public Ip Address be associated with the Desktop? Type: String Default: "true" AllowedValues: - "true" - "false" RosVersion: Description: >- ROS version. For ROS1, use 'noetic'. For ROS2, use 'humble'. Type: String Default: "noetic" AllowedValues: - "noetic" - "humble" FargateComputeMax: Description: Maximum size of compute environment in vCpus Type: Number Default: 1024 FargateComputeType: Description: Fargate compute type Type: String Default: "FARGATE" AllowedValues: - "FARGATE_SPOT" - "FARGATE" Conditions: CreateEksKey: !Equals [ !Ref EKSEncryptSecretsKmsKeyArn, "" ] OverrideAMI: !Not - !Equals - !Ref UbuntuAMI - '' MSKEnabled: !Equals [ !Ref DataClientType, "KafkaAndRosBridge" ] FSxForLustreEnabled: !Equals [ !Ref FSxForLustre, 'enabled' ] Mappings: noetic: us-east-1: AMI: ami-007ccac74cc85cb43 us-east-2: AMI: ami-099e81f8d52ddb352 us-west-2: AMI: ami-0f48fa756eb8ae717 eu-west-1: AMI: ami-06e7d4ed8752ea1a1 eu-central-1: AMI: ami-0ebdbdc3009d263a1 ap-southeast-1: AMI: ami-09b43c6a9d2db239d ap-southeast-2: AMI: ami-093ee8ca5cccbd9dd ap-south-1: AMI: ami-0c281c09ef103f5c3 ap-northeast-1: AMI: ami-0734a013c43b8d8a2 ap-northeast-2: AMI: ami-08accefb19e265cff humble: us-east-1: AMI: ami-072755cb2af0b2c13 us-east-2: AMI: ami-01a3123d0e7829c54 us-west-2: AMI: ami-02ecfea07453e311e eu-west-1: AMI: ami-0ab1412ff270d506a eu-central-1: AMI: ami-06de26b0113440e5e ap-southeast-1: AMI: ami-06aa28baff54cc6c6 ap-southeast-2: AMI: ami-018c717da05ea192a ap-south-1: AMI: ami-03039714a69449cd3 ap-northeast-1: AMI: ami-09e362d8226e42c1a ap-northeast-2: AMI: ami-02c262c46f2c3817e Resources: Vpc: Type: 'AWS::EC2::VPC' Properties: CidrBlock: !Ref VpcCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-data-service' InternetGateway: Type: 'AWS::EC2::InternetGateway' Properties: Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' GatewayToInternet: Type: 'AWS::EC2::VPCGatewayAttachment' Properties: VpcId: !Ref Vpc InternetGatewayId: !Ref InternetGateway PublicSubnet1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref Vpc AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" CidrBlock: !Ref VpcPublicSubnet1CIDR MapPublicIpOnLaunch: false Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' - Key: 'kubernetes.io/role/elb' Value: '1' - Key: !Sub 'kubernetes.io/cluster/${AWS::StackName}' Value: 'shared' PublicSubnet2: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref Vpc AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: "" CidrBlock: !Ref VpcPublicSubnet2CIDR MapPublicIpOnLaunch: false Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' - Key: 'kubernetes.io/role/elb' Value: '1' - Key: !Sub 'kubernetes.io/cluster/${AWS::StackName}' Value: 'shared' PublicSubnet3: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref Vpc AvailabilityZone: Fn::Select: - 2 - Fn::GetAZs: "" CidrBlock: !Ref VpcPublicSubnet3CIDR MapPublicIpOnLaunch: false Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' - Key: 'kubernetes.io/role/elb' Value: '1' - Key: !Sub 'kubernetes.io/cluster/${AWS::StackName}' Value: 'shared' PrivateSubnet1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref Vpc AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" CidrBlock: !Ref VpcPrivateSubnet1CIDR Tags: - Key: Network Value: Private - Key: Name Value: !Ref 'AWS::StackName' - Key: 'kubernetes.io/role/internal-elb' Value: '1' - Key: !Sub 'kubernetes.io/cluster/${AWS::StackName}' Value: 'shared' PrivateSubnet2: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref Vpc AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: "" CidrBlock: !Ref VpcPrivateSubnet2CIDR Tags: - Key: Network Value: Private - Key: Name Value: !Ref 'AWS::StackName' - Key: 'kubernetes.io/role/internal-elb' Value: '1' - Key: !Sub 'kubernetes.io/cluster/${AWS::StackName}' Value: 'shared' PrivateSubnet3: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref Vpc AvailabilityZone: Fn::Select: - 2 - Fn::GetAZs: "" CidrBlock: !Ref VpcPrivateSubnet3CIDR Tags: - Key: Network Value: Private - Key: Name Value: !Ref 'AWS::StackName' - Key: 'kubernetes.io/role/internal-elb' Value: '1' - Key: !Sub 'kubernetes.io/cluster/${AWS::StackName}' Value: 'shared' NATGatewayEIP: Type: 'AWS::EC2::EIP' Properties: Domain: vpc NATGateway: Type: 'AWS::EC2::NatGateway' DependsOn: GatewayToInternet Properties: AllocationId: !GetAtt - NATGatewayEIP - AllocationId SubnetId: !Ref PublicSubnet1 PublicRouteTable: Type: 'AWS::EC2::RouteTable' DependsOn: GatewayToInternet Properties: VpcId: !Ref Vpc Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' PublicRoute: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ PublicRoute ] Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable PublicSubnet2RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ PublicRoute ] Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable PublicSubnet3RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ PublicRoute ] Properties: SubnetId: !Ref PublicSubnet3 RouteTableId: !Ref PublicRouteTable PrivateRouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref Vpc Tags: - Key: Network Value: Private - Key: Name Value: !Ref 'AWS::StackName' PrivateRoute: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref PrivateRouteTable DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NATGateway PrivatePeeringRoute: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref PrivateRouteTable DestinationCidrBlock: "192.168.0.0/22" VpcPeeringConnectionId: !Ref BatchFargateVpcPeering PrivateSubnet1RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ PrivateRoute ] Properties: SubnetId: !Ref PrivateSubnet1 RouteTableId: !Ref PrivateRouteTable PrivateSubnet2RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ PrivateRoute ] Properties: SubnetId: !Ref PrivateSubnet2 RouteTableId: !Ref PrivateRouteTable PrivateSubnet3RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ PrivateRoute ] Properties: SubnetId: !Ref PrivateSubnet3 RouteTableId: !Ref PrivateRouteTable VpcS3Endpoint: Type: AWS::EC2::VPCEndpoint Properties: PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "s3:Get*" - "s3:List*" - "s3:PutObject*" - "s3:DeleteObject*" Resource: "*" RouteTableIds: - !Ref PrivateRouteTable - !Ref PublicRouteTable ServiceName: !Sub com.amazonaws.${AWS::Region}.s3 VpcId: !Ref Vpc VpcEcrApiEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecr:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.api VpcEndpointType: 'Interface' VpcId: !Ref Vpc VpcEcrDkrEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecr:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.dkr VpcEndpointType: 'Interface' VpcId: !Ref Vpc VpcSecretsManagerEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "secretsmanager:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.secretsmanager VpcEndpointType: 'Interface' VpcId: !Ref Vpc VpcDynamodbEndpoint: Type: AWS::EC2::VPCEndpoint Properties: RouteTableIds: - !Ref PrivateRouteTable ServiceName: !Sub com.amazonaws.${AWS::Region}.dynamodb VpcId: !Ref Vpc VpcSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: VPC security group VpcId: !Ref Vpc Tags: - Key: Name Value: !Ref 'AWS::StackName' VpcSecurityGroupIngressFSx1: Condition: FSxForLustreEnabled Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group for FSx GroupId: !GetAtt VpcSecurityGroup.GroupId IpProtocol: tcp FromPort: 988 ToPort: 988 SourceSecurityGroupId: !GetAtt VpcSecurityGroup.GroupId VpcSecurityGroupCIDRIngressFSx1: Condition: FSxForLustreEnabled Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group CIDR for FSx GroupId: !GetAtt VpcSecurityGroup.GroupId CidrIp: !Ref VpcCIDR IpProtocol: tcp FromPort: 988 ToPort: 988 VpcSecurityGroupIngressFSx2: Condition: FSxForLustreEnabled Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group for FSx GroupId: !GetAtt VpcSecurityGroup.GroupId IpProtocol: tcp FromPort: 1021 ToPort: 1023 SourceSecurityGroupId: !GetAtt VpcSecurityGroup.GroupId VpcSecurityGroupCIDRIngressFSx2: Condition: FSxForLustreEnabled Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group CIDR for FSx GroupId: !GetAtt VpcSecurityGroup.GroupId CidrIp: !Ref VpcCIDR IpProtocol: tcp FromPort: 1021 ToPort: 1023 VpcSecurityGroupIngressEfs: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group for Efs GroupId: !GetAtt VpcSecurityGroup.GroupId IpProtocol: tcp FromPort: 2049 ToPort: 2049 SourceSecurityGroupId: !GetAtt VpcSecurityGroup.GroupId VpcSecurityGroupCIDRIngressEfs: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group CIDR for Efs GroupId: !GetAtt VpcSecurityGroup.GroupId CidrIp: !Ref VpcCIDR IpProtocol: tcp FromPort: 2049 ToPort: 2049 VpcSecurityGroupIngressRosBridge: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group for Ros bridge GroupId: !GetAtt VpcSecurityGroup.GroupId IpProtocol: tcp FromPort: 9090 ToPort: 9090 SourceSecurityGroupId: !GetAtt VpcSecurityGroup.GroupId VpcSecurityGroupCIDRIngressRosBridge: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group CIDR for Ros bridge GroupId: !GetAtt VpcSecurityGroup.GroupId CidrIp: !Ref VpcCIDR IpProtocol: tcp FromPort: 9090 ToPort: 9090 VpcSecurityGroupCIDREgress: Type: 'AWS::EC2::SecurityGroupEgress' Properties: Description: Egress rule for out bound traffic GroupId: !GetAtt VpcSecurityGroup.GroupId IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: '0.0.0.0/0' DesktopSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Desktop security group VpcId: !Ref Vpc Tags: - Key: Name Value: !Ref 'AWS::StackName' DesktopSecurityGroupCIDRIngress1: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from CIDR for NICE-DCV access to graphics desktop GroupId: !GetAtt DesktopSecurityGroup.GroupId CidrIp: !Ref DesktopRemoteAccessCIDR IpProtocol: tcp FromPort: 8443 ToPort: 8443 DesktopSecurityGroupCIDRIngress2: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from CIDR for SSH access to graphics desktop GroupId: !GetAtt DesktopSecurityGroup.GroupId CidrIp: !Ref DesktopRemoteAccessCIDR IpProtocol: tcp FromPort: 22 ToPort: 22 DesktopSecurityGroupCIDREgress: Type: 'AWS::EC2::SecurityGroupEgress' Properties: Description: Egress rule for out bound traffic GroupId: !GetAtt DesktopSecurityGroup.GroupId IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: '0.0.0.0/0' RedshiftClusterRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: redshift.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:ListBucket" Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' - Effect: Allow Action: - "athena:GetDatabase" - "athena:GetTableMetadata" Resource: - !Sub 'arn:aws:athena:${AWS::Region}:${AWS::AccountId}:datacatalog/*' - Effect: Allow Action: - "athena:GetQueryExecution" - "athena:GetQueryResults" - "athena:StartQueryExecution" Resource: - !Sub 'arn:aws:athena:${AWS::Region}:${AWS::AccountId}:workgroup/*' PolicyName: 'RedshiftClusterPolicy' RedshiftMasterUserPasswordSecret: Type: AWS::SecretsManager::Secret Properties: Description: "Redshift database master user password" SecretString: !Ref RedshiftMasterUserPassword RedshiftServerlessNamespace: Type: AWS::RedshiftServerless::Namespace Properties: DbName: !Ref RedshiftDatabaseName AdminUsername: !Ref RedshiftMasterUsername AdminUserPassword: !Ref RedshiftMasterUserPassword DefaultIamRoleArn: !GetAtt RedshiftClusterRole.Arn IamRoles: - !GetAtt RedshiftClusterRole.Arn NamespaceName: !Ref RedshiftNamespace RedshiftServerlessWorkgroup: Type: AWS::RedshiftServerless::Workgroup DependsOn: [PrivateSubnet1RouteAssociation, PrivateSubnet2RouteAssociation, PrivateSubnet3RouteAssociation] Properties: BaseCapacity: !Ref RedshiftServerlessBaseCapacity NamespaceName: !Ref RedshiftServerlessNamespace PubliclyAccessible: false ConfigParameters: - ParameterKey: enable_user_activity_logging ParameterValue: 'true' SecurityGroupIds: - !GetAtt RedshiftSecurityGroup.GroupId SubnetIds: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 WorkgroupName: !Ref RedshiftWorkgroup RedshiftSecurityGroup: DependsOn: [VpcSecurityGroup] Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Redshift Security group VpcId: !Ref Vpc Tags: - Key: Name Value: !Ref 'AWS::StackName' RedshiftSecurityGroupIngress: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from VPC security group to RedShift database GroupId: !GetAtt RedshiftSecurityGroup.GroupId IpProtocol: tcp FromPort: 5439 ToPort: 5439 SourceSecurityGroupId: !GetAtt VpcSecurityGroup.GroupId RedshiftSecurityGroupBatchFargateIngress: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from batch fargate VPC security group to RedShift database GroupId: !GetAtt RedshiftSecurityGroup.GroupId IpProtocol: tcp FromPort: 5439 ToPort: 5439 SourceSecurityGroupId: !GetAtt BatchFargateSecurityGroup.GroupId RedshiftSecurityGroupCIDRIngress: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from from VPC CIDR to RedShift database GroupId: !GetAtt RedshiftSecurityGroup.GroupId CidrIp: !Ref VpcCIDR IpProtocol: tcp FromPort: 5439 ToPort: 5439 RedshiftSecurityGroupCIDREgress: Type: 'AWS::EC2::SecurityGroupEgress' Properties: Description: Egress rule for out bound traffic GroupId: !GetAtt RedshiftSecurityGroup.GroupId IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: '0.0.0.0/0' MSKClusterLogGroup: Condition: MSKEnabled Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "${AWS::StackName}-msk" RetentionInDays: 30 MSKCluster: Condition: MSKEnabled Type: 'AWS::MSK::Cluster' DependsOn: [PrivateSubnet1RouteAssociation, PrivateSubnet2RouteAssociation, PrivateSubnet3RouteAssociation] Properties: ClusterName: !Sub '${AWS::StackName}' KafkaVersion: 2.2.1 NumberOfBrokerNodes: !Ref MSKNumberOfNodes LoggingInfo: BrokerLogs: CloudWatchLogs: Enabled: true LogGroup: !Ref MSKClusterLogGroup EncryptionInfo: EncryptionInTransit: ClientBroker: "TLS_PLAINTEXT" InCluster: false BrokerNodeGroupInfo: InstanceType: !Ref MSKBrokerNodeType ClientSubnets: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 SecurityGroups: - Ref: MSKSecurityGroup MSKSecurityGroup: Condition: MSKEnabled DependsOn: [VpcSecurityGroup] Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: MSK Security group VpcId: !Ref Vpc Tags: - Key: Name Value: !Ref 'AWS::StackName' MSKSecurityGroupIngress: Condition: MSKEnabled Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from VPC security group to MSK cluster endpoint GroupId: !GetAtt MSKSecurityGroup.GroupId IpProtocol: tcp FromPort: 9092 ToPort: 9094 SourceSecurityGroupId: !GetAtt VpcSecurityGroup.GroupId MSKSecurityGroupCIDRIngress: Condition: MSKEnabled Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from VPC CIDR to MSK cluster endpoint GroupId: !GetAtt MSKSecurityGroup.GroupId CidrIp: !Ref VpcCIDR IpProtocol: tcp FromPort: 9092 ToPort: 9094 MSKSecurityGroupCIDREgress: Condition: MSKEnabled Type: 'AWS::EC2::SecurityGroupEgress' Properties: Description: Egress rule for out bound traffic GroupId: !GetAtt MSKSecurityGroup.GroupId IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: '0.0.0.0/0' EksControlPlaneRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - eks.amazonaws.com - ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonEKSClusterPolicy' - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonEKSServicePolicy' KMSKey: Condition: CreateEksKey Type: "AWS::KMS::Key" Properties: EnableKeyRotation: true KeyPolicy: { "Version": "2012-10-17", "Id": "key-default-1", "Statement": [ { "Sid": "Enable IAM User Permissions", "Effect": "Allow", "Principal": { "AWS": !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:root" }, "Action": "kms:*", "Resource": "*" } ] } EksControlPlane: Type: "AWS::EKS::Cluster" DependsOn: [PrivateSubnet1RouteAssociation, PrivateSubnet2RouteAssociation, PrivateSubnet3RouteAssociation] Properties: Name: !Ref AWS::StackName ResourcesVpcConfig: SecurityGroupIds: - !GetAtt VpcSecurityGroup.GroupId SubnetIds: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 EncryptionConfig: - Resources: [ secrets ] Provider: KeyArn: !If [ CreateEksKey, !GetAtt KMSKey.Arn, !Ref EKSEncryptSecretsKmsKeyArn ] RoleArn: !GetAtt EksControlPlaneRole.Arn Version: !Ref KubernetesVersion EksNodeRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "autoscaling:DescribeAutoScalingGroups" - "autoscaling:DescribeAutoScalingInstances" - "autoscaling:DescribeLaunchConfigurations" - "autoscaling:DescribeTags" - "autoscaling:SetDesiredCapacity" - "autoscaling:TerminateInstanceInAutoScalingGroup" - "ec2:DescribeLaunchTemplateVersions" Resource: '*' PolicyName: 'EKSNodeAutoScalerPolicy' - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "iam:CreateServiceLinkedRole" Resource: "*" Condition: StringLike: iam:AWSServiceName: - "fsx.amazonaws.com" - Effect: Allow Action: - "iam:CreateServiceLinkedRole" - "iam:AttachRolePolicy" - "iam:PutRolePolicy" Resource: "arn:aws:iam::*:role/aws-service-role/s3.data-source.lustre.fsx.amazonaws.com/*" - Effect: Allow Action: - "s3:ListBucket" Resource: '*' - Effect: Allow Action: - "fsx:CreateFileSystem" - "fsx:DeleteFileSystem" - "fsx:DescribeFileSystems" - "fsx:TagResource" Resource: "*" PolicyName: 'EKSNodeFSxCNIPolicy' ManagedPolicyArns: - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKSWorkerNodePolicy" - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKS_CNI_Policy" - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" Path: / EksPodServiceAccountRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: !Sub - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${ClusterOIDCPath}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${ClusterOIDCPath}:aud": "sts.amazonaws.com" } } } ] } - ClusterOIDCPath: !Join - '' - - 'oidc.eks.' - !Ref 'AWS::Region' - '.amazonaws.com/id/' - !Select [0, !Split ['.', !Select [1, !Split ['//', !GetAtt EksControlPlane.Endpoint]]]] Policies: - PolicyName: 'eks-sa-role-poliicy' PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:Get*" - "s3:List*" - "s3:PutObject*" - "s3:DeleteObject*" Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' - PolicyName: eks-pod-secretsmanager-policy PolicyDocument: Statement: - Effect: Allow Action: - "secretsmanager:GetSecretValue" Resource: - !Ref RedshiftMasterUserPasswordSecret - PolicyName: eks-pod-dynamodb-policy PolicyDocument: Statement: - Effect: Allow Action: - "dynamodb:*" Resource: - !GetAtt DataRequestTable.Arn EKSNodeGroupPrivate: Type: AWS::EKS::Nodegroup Properties: AmiType: "AL2_x86_64" ClusterName: !Ref EksControlPlane DiskSize: !Ref EKSNodeVolumeSizeGiB InstanceTypes: - !Ref EKSNodeGroupInstanceType NodegroupName: 'private-nodegroup' NodeRole: !GetAtt EksNodeRole.Arn RemoteAccess: Ec2SshKey: !Ref KeyPairName ScalingConfig: DesiredSize: !Ref EKSNodeGroupDesiredSize MaxSize: !Ref EKSNodeGroupMaxSize MinSize: !Ref EKSNodeGroupMinSize Labels: nodegroup: 'mozart-data-service' Subnets: - Ref: PrivateSubnet1 - Ref: PrivateSubnet2 - Ref: PrivateSubnet3 EksClusterAutoscalerServiceAccountRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: !Sub - | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/${ClusterOIDCPath}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${ClusterOIDCPath}:aud": "sts.amazonaws.com" } } } ] } - ClusterOIDCPath: !Join - '' - - 'oidc.eks.' - !Ref 'AWS::Region' - '.amazonaws.com/id/' - !Select [0, !Split ['.', !Select [1, !Split ['//', !GetAtt EksControlPlane.Endpoint]]]] Policies: - PolicyName: 'eks-autoscaler-sa-role-poliicy' PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "autoscaling:DescribeAutoScalingGroups" - "autoscaling:DescribeAutoScalingInstances" - "autoscaling:DescribeLaunchConfigurations" - "autoscaling:DescribeTags" - "autoscaling:SetDesiredCapacity" - "autoscaling:TerminateInstanceInAutoScalingGroup" - "ec2:DescribeLaunchTemplateVersions" - "ec2:DescribeInstanceTypes" Resource: - '*' FSxFileSystem: Condition: FSxForLustreEnabled Type: AWS::FSx::FileSystem DependsOn: [ PrivateSubnet1RouteAssociation, VpcSecurityGroupIngressFSx1, VpcSecurityGroupIngressFSx2] Properties: FileSystemType: 'LUSTRE' LustreConfiguration: ImportPath: !Sub 's3://${S3Bucket}/${FSxS3ImportPrefix}' DeploymentType: SCRATCH_2 ImportedFileChunkSize: 512000 AutoImportPolicy: "NEW_CHANGED" SecurityGroupIds: - !GetAtt VpcSecurityGroup.GroupId StorageCapacity: !Ref FSxStorageCapacityGiB StorageType: 'SSD' SubnetIds: - Ref: PrivateSubnet1 Tags: - Key: Name Value: !Ref 'AWS::StackName' EFSFileSystem: Type: 'AWS::EFS::FileSystem' DeletionPolicy: Delete UpdateReplacePolicy: Delete Properties: Encrypted : true PerformanceMode: generalPurpose FileSystemTags: - Key: Name Value: !Sub '${AWS::StackName}-data-service' MountTarget1: Type: 'AWS::EFS::MountTarget' DependsOn: [ PrivateSubnet1RouteAssociation, VpcSecurityGroupIngressEfs ] Properties: FileSystemId: !Ref EFSFileSystem SubnetId: !Ref PrivateSubnet1 SecurityGroups: - !Ref VpcSecurityGroup MountTarget2: Type: 'AWS::EFS::MountTarget' DependsOn: [ PrivateSubnet2RouteAssociation, VpcSecurityGroupIngressEfs ] Properties: FileSystemId: !Ref EFSFileSystem SubnetId: !Ref PrivateSubnet2 SecurityGroups: - !Ref VpcSecurityGroup MountTarget3: Type: 'AWS::EFS::MountTarget' DependsOn: [ PrivateSubnet3RouteAssociation, VpcSecurityGroupIngressEfs ] Properties: FileSystemId: !Ref EFSFileSystem SubnetId: !Ref PrivateSubnet3 SecurityGroups: - !Ref VpcSecurityGroup GlueJobRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - glue.amazonaws.com Action: - "sts:AssumeRole" ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole' Policies: - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:Get*" - "s3:List*" - "s3:PutObject*" Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' PolicyName: 'glue-job-role-s3-poliicy' BatchFargateVpc: Type: 'AWS::EC2::VPC' Properties: CidrBlock: "192.168.0.0/22" EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-batch-fargate' BatchFargateVpcPeering: Type: AWS::EC2::VPCPeeringConnection Properties: PeerVpcId: !Ref Vpc VpcId: !Ref BatchFargateVpc BatchFargateInternetGateway: Type: 'AWS::EC2::InternetGateway' Properties: Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' BatchFargateGatewayToInternet: Type: 'AWS::EC2::VPCGatewayAttachment' Properties: VpcId: !Ref BatchFargateVpc InternetGatewayId: !Ref BatchFargateInternetGateway BatchFargatePublicSubnet: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref BatchFargateVpc AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" CidrBlock: "192.168.0.0/24" BatchFargatePublicRouteTable: Type: 'AWS::EC2::RouteTable' DependsOn: BatchFargateGatewayToInternet Properties: VpcId: !Ref BatchFargateVpc Tags: - Key: Network Value: Public - Key: Name Value: !Ref 'AWS::StackName' BatchFargatePublicRoute: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref BatchFargatePublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref BatchFargateInternetGateway BatchFargatePublicSubnetRouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ BatchFargatePublicRoute ] Properties: SubnetId: !Ref BatchFargatePublicSubnet RouteTableId: !Ref BatchFargatePublicRouteTable BatchFargateNATGatewayEIP: Type: 'AWS::EC2::EIP' Properties: Domain: vpc BatchFargateNATGateway: Type: 'AWS::EC2::NatGateway' DependsOn: BatchFargateGatewayToInternet Properties: AllocationId: !GetAtt - BatchFargateNATGatewayEIP - AllocationId SubnetId: !Ref BatchFargatePublicSubnet BatchFargatePrivateRouteTable: Type: 'AWS::EC2::RouteTable' Properties: VpcId: !Ref BatchFargateVpc Tags: - Key: Network Value: Private - Key: Name Value: !Ref 'AWS::StackName' BatchFargatePrivateRoute: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref BatchFargatePrivateRouteTable DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref BatchFargateNATGateway BatchFargatePrivatePeeringRoute: Type: 'AWS::EC2::Route' Properties: RouteTableId: !Ref BatchFargatePrivateRouteTable DestinationCidrBlock: !Ref VpcCIDR VpcPeeringConnectionId: !Ref BatchFargateVpcPeering BatchFargatePrivateSubnet1: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref BatchFargateVpc AvailabilityZone: Fn::Select: - 0 - Fn::GetAZs: "" CidrBlock: "192.168.1.0/24" BatchFargatePrivateSubnet1RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ BatchFargatePrivateRoute ] Properties: SubnetId: !Ref BatchFargatePrivateSubnet1 RouteTableId: !Ref BatchFargatePrivateRouteTable BatchFargatePrivateSubnet2: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref BatchFargateVpc AvailabilityZone: Fn::Select: - 1 - Fn::GetAZs: "" CidrBlock: "192.168.2.0/24" BatchFargatePrivateSubnet2RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ BatchFargatePrivateRoute ] Properties: SubnetId: !Ref BatchFargatePrivateSubnet2 RouteTableId: !Ref BatchFargatePrivateRouteTable BatchFargatePrivateSubnet3: Type: 'AWS::EC2::Subnet' Properties: VpcId: !Ref BatchFargateVpc AvailabilityZone: Fn::Select: - 2 - Fn::GetAZs: "" CidrBlock: "192.168.3.0/24" BatchFargatePrivateSubnet3RouteAssociation: Type: 'AWS::EC2::SubnetRouteTableAssociation' DependsOn: [ BatchFargatePrivateRoute ] Properties: SubnetId: !Ref BatchFargatePrivateSubnet3 RouteTableId: !Ref BatchFargatePrivateRouteTable BatchFargateSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: Batch Fargate security group VpcId: !Ref BatchFargateVpc Tags: - Key: Name Value: !Ref 'AWS::StackName' BatchFargateSecurityGroupIngress: Type: 'AWS::EC2::SecurityGroupIngress' Properties: Description: Ingress from within the VPC security group GroupId: !GetAtt BatchFargateSecurityGroup.GroupId IpProtocol: tcp FromPort: 2049 ToPort: 2049 SourceSecurityGroupId: !GetAtt BatchFargateSecurityGroup.GroupId BatchFargateSecurityGroupCIDREgress: Type: 'AWS::EC2::SecurityGroupEgress' Properties: Description: Egress rule for out bound traffic GroupId: !GetAtt BatchFargateSecurityGroup.GroupId IpProtocol: tcp FromPort: 0 ToPort: 65535 CidrIp: '0.0.0.0/0' BatchFargateEcrApiEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: BatchFargatePrivateSubnet1 - Ref: BatchFargatePrivateSubnet2 - Ref: BatchFargatePrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecr:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.api VpcEndpointType: 'Interface' VpcId: !Ref BatchFargateVpc BatchFargateEcrDkrEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: BatchFargatePrivateSubnet1 - Ref: BatchFargatePrivateSubnet2 - Ref: BatchFargatePrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecr:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.dkr VpcEndpointType: 'Interface' VpcId: !Ref BatchFargateVpc BatchFargateEcsEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: BatchFargatePrivateSubnet1 - Ref: BatchFargatePrivateSubnet2 - Ref: BatchFargatePrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecs:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecs VpcEndpointType: 'Interface' VpcId: !Ref BatchFargateVpc BatchFargateEcsAgentEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: BatchFargatePrivateSubnet1 - Ref: BatchFargatePrivateSubnet2 - Ref: BatchFargatePrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecs:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecs-agent VpcEndpointType: 'Interface' VpcId: !Ref BatchFargateVpc BatchFargateEcsTelemetryEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: BatchFargatePrivateSubnet1 - Ref: BatchFargatePrivateSubnet2 - Ref: BatchFargatePrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "ecs:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.ecs-telemetry VpcEndpointType: 'Interface' VpcId: !Ref BatchFargateVpc BatchFargateSecretsManagerEndpoint: Type: AWS::EC2::VPCEndpoint Properties: SubnetIds: - Ref: BatchFargatePrivateSubnet1 - Ref: BatchFargatePrivateSubnet2 - Ref: BatchFargatePrivateSubnet3 PolicyDocument: Version: 2012-10-17 Statement: - Effect: "Allow" Principal: "*" Action: - "secretsmanager:*" Resource: "*" ServiceName: !Sub com.amazonaws.${AWS::Region}.secretsmanager VpcEndpointType: 'Interface' VpcId: !Ref BatchFargateVpc BatchFargateEfsFileSystem: Type: 'AWS::EFS::FileSystem' DeletionPolicy: Delete UpdateReplacePolicy: Delete Properties: Encrypted : true PerformanceMode: generalPurpose FileSystemTags: - Key: Name Value: !Sub '${AWS::StackName}-batch-fargate' BatchFargateEfsAccessPoint: Type: AWS::EFS::AccessPoint Properties: FileSystemId: !Ref BatchFargateEfsFileSystem BatchFargateMountTarget1: Type: 'AWS::EFS::MountTarget' DependsOn: - BatchFargatePrivateSubnet1RouteAssociation - BatchFargateSecurityGroupIngress Properties: FileSystemId: !Ref BatchFargateEfsFileSystem SubnetId: !Ref BatchFargatePrivateSubnet1 SecurityGroups: - !Ref BatchFargateSecurityGroup BatchFargateMountTarget2: Type: 'AWS::EFS::MountTarget' DependsOn: - BatchFargatePrivateSubnet2RouteAssociation - BatchFargateSecurityGroupIngress Properties: FileSystemId: !Ref BatchFargateEfsFileSystem SubnetId: !Ref BatchFargatePrivateSubnet2 SecurityGroups: - !Ref BatchFargateSecurityGroup BatchFargateMountTarget3: Type: 'AWS::EFS::MountTarget' DependsOn: - BatchFargatePrivateSubnet3RouteAssociation - BatchFargateSecurityGroupIngress Properties: FileSystemId: !Ref BatchFargateEfsFileSystem SubnetId: !Ref BatchFargatePrivateSubnet3 SecurityGroups: - !Ref BatchFargateSecurityGroup BatchServiceRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - batch.amazonaws.com Action: - "sts:AssumeRole" ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole' BatchExecutionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: - "sts:AssumeRole" ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy' Policies: - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "elasticfilesystem:ClientMount" - "elasticfilesystem:ClientWrite" Resource: - !GetAtt BatchFargateEfsFileSystem.Arn Condition: StringEquals: "elasticfilesystem:AccessPointArn": !GetAtt BatchFargateEfsAccessPoint.Arn PolicyName: 'batch-execution-efs-policy' StepFunctionsRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - states.amazonaws.com Action: - "sts:AssumeRole" ManagedPolicyArns: - 'arn:aws:iam::aws:policy/AmazonEventBridgeFullAccess' Policies: - PolicyName: steps-batch-policy PolicyDocument: Statement: - Effect: Allow Action: - "batch:SubmitJob" Resource: - !Ref FargateJobQueue - !Sub 'arn:aws:batch:${AWS::Region}:${AWS::AccountId}:job-definition/*' - Effect: Allow Action: - "batch:DescribeJobs" Resource: - "*" BatchJobRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: 'batch-job-s3-policy' PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:Get*" - "s3:List*" - "s3:PutObject*" - "s3:DeleteObject*" Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' - Effect: Allow Action: - "s3:Get*" - "s3:List*" Resource: - 'arn:aws:s3:::aev-autonomous-driving-dataset' - 'arn:aws:s3:::aev-autonomous-driving-dataset/*' - 'arn:aws:s3:::ford-multi-av-seasonal' - 'arn:aws:s3:::ford-multi-av-seasonal/*' - PolicyName: batch-job-batch-policy PolicyDocument: Statement: - Effect: Allow Action: - "batch:SubmitJob" Resource: - !Ref FargateJobQueue - !Sub 'arn:aws:batch:${AWS::Region}:${AWS::AccountId}:job-definition/*' - Effect: Allow Action: - "batch:TerminateJob" Resource: - !Sub 'arn:aws:batch:${AWS::Region}:${AWS::AccountId}:job/*' - Effect: Allow Action: - "batch:DescribeJobs" Resource: - "*" - PolicyName: batch-job-glue-policy PolicyDocument: Statement: - Effect: Allow Action: - "glue:CreateDatabase" - "glue:DeleteDatabase" - "glue:GetDatabase" - "glue:GetDatabases" - "glue:UpdateDatabase" - "glue:CreateTable" - "glue:DeleteTable" - "glue:BatchDeleteTable" - "glue:UpdateTable" - "glue:GetTable" - "glue:GetTables" - "glue:BatchCreatePartition" - "glue:CreatePartition" - "glue:DeletePartition" - "glue:BatchDeletePartition" - "glue:UpdatePartition" - "glue:GetPartition" - "glue:GetPartitions" - "glue:BatchGetPartition" Resource: - !Sub 'arn:aws:glue:${AWS::Region}:${AWS::AccountId}:catalog' - !Sub 'arn:aws:glue:${AWS::Region}:${AWS::AccountId}:database/*' - !Sub 'arn:aws:glue:${AWS::Region}:${AWS::AccountId}:table/*' - !Sub 'arn:aws:glue:${AWS::Region}:${AWS::AccountId}:userDefinedFunction/*' - Effect: Allow Action: - "glue:CreateJob" - "glue:StartJobRun" - "glue:GetJob*" Resource: - "*" - Effect: Allow Action: - iam:PassRole Resource: - !GetAtt GlueJobRole.Arn - PolicyName: batch-job-athena-policy PolicyDocument: Statement: - Effect: Allow Action: - "athena:GetQueryExecution" - "athena:GetQueryResults" - "athena:StartQueryExecution" Resource: - !Sub 'arn:aws:athena:${AWS::Region}:${AWS::AccountId}:workgroup/*' - PolicyName: batch-job-secretsmanager-policy PolicyDocument: Statement: - Effect: Allow Action: - "secretsmanager:GetSecretValue" Resource: - !Ref RedshiftMasterUserPasswordSecret FargateComputeEnvironment: Type: AWS::Batch::ComputeEnvironment Properties: ComputeEnvironmentName: !Sub '${AWS::StackName}-fargate' Type: MANAGED State: ENABLED ComputeResources: Type: !Ref FargateComputeType MaxvCpus: !Ref FargateComputeMax Subnets: - !Ref BatchFargatePrivateSubnet1 - !Ref BatchFargatePrivateSubnet2 - !Ref BatchFargatePrivateSubnet3 SecurityGroupIds: - !GetAtt BatchFargateSecurityGroup.GroupId ServiceRole: !GetAtt BatchServiceRole.Arn Tags: Name: !Ref AWS::StackName FargateJobQueue: Type: AWS::Batch::JobQueue Properties: JobQueueName: !Sub '${AWS::StackName}-fargate' ComputeEnvironmentOrder: - Order: 1 ComputeEnvironment: !Ref FargateComputeEnvironment Priority: 1 State: ENABLED PythonFromS3JobDefinition: Type: AWS::Batch::JobDefinition Properties: JobDefinitionName: !Sub '${AWS::StackName}-pythonfroms3' Type: container PlatformCapabilities: - FARGATE ContainerProperties: Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/pythonfroms3:focal' FargatePlatformConfiguration: PlatformVersion: "1.4.0" ExecutionRoleArn: !GetAtt BatchExecutionRole.Arn JobRoleArn: !GetAtt BatchJobRole.Arn ResourceRequirements: - Type: "VCPU" Value: "4" - Type: "MEMORY" Value: "8192" Volumes: - EfsVolumeConfiguration: FileSystemId: !Ref BatchFargateEfsFileSystem AuthorizationConfig: AccessPointId: !Ref BatchFargateEfsAccessPoint Iam: "ENABLED" RootDirectory: "/" TransitEncryption: "ENABLED" Name: "efs" MountPoints: - ContainerPath: "/efs" SourceVolume: "efs" Ros1PythonFromS3JobDefinition: Type: AWS::Batch::JobDefinition Properties: JobDefinitionName: !Sub '${AWS::StackName}-ros1-pythonfroms3' Type: container PlatformCapabilities: - FARGATE ContainerProperties: Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/pythonfroms3:noetic' FargatePlatformConfiguration: PlatformVersion: "1.4.0" ExecutionRoleArn: !GetAtt BatchExecutionRole.Arn JobRoleArn: !GetAtt BatchJobRole.Arn ResourceRequirements: - Type: "VCPU" Value: "4" - Type: "MEMORY" Value: "8192" Volumes: - EfsVolumeConfiguration: FileSystemId: !Ref BatchFargateEfsFileSystem AuthorizationConfig: AccessPointId: !Ref BatchFargateEfsAccessPoint Iam: "ENABLED" RootDirectory: "/" TransitEncryption: "ENABLED" Name: "efs" MountPoints: - ContainerPath: "/efs" SourceVolume: "efs" DataRequestTable: Type: AWS::DynamoDB::Table Properties: BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: request_hash AttributeType: S - AttributeName: request_index AttributeType: S KeySchema: - AttributeName: request_hash KeyType: HASH - AttributeName: request_index KeyType: RANGE DesktopRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - "sts:AssumeRole" ManagedPolicyArns: - "arn:aws:iam::aws:policy/AmazonFSxReadOnlyAccess" Policies: - PolicyName: desktop-cloudformation-policy PolicyDocument: Statement: - Effect: Allow Action: - 'cloudformation:DescribeStacks' Resource: - !Sub 'arn:aws:cloudformation:::stack/${AWS::StackName}/*' - PolicyName: desktop-kafka-policy PolicyDocument: Statement: - Effect: Allow Action: - "kafka:DescribeCluster" - "kafka:DescribeConfiguration" - "kafka:DescribeConfigurationRevision" - "kafka:CreateConfiguration" - "kafka:UpdateClusterConfiguration" - "kafka:GetBootstrapBrokers" - "kafka:ListConfigurations" Resource: - "*" - PolicyName: desktop-batch-policy PolicyDocument: Statement: - Effect: Allow Action: - "batch:SubmitJob" Resource: - !Ref FargateJobQueue - !Sub 'arn:aws:batch:${AWS::Region}:${AWS::AccountId}:job-definition/*' - Effect: Allow Action: - "batch:DescribeJobs" Resource: - "*" - PolicyName: desktop-sfn-policy PolicyDocument: Statement: - Effect: Allow Action: - states:CreateStateMachine - states:StartExecution - states:StopExecution - states:DescribeStateMachine* - states:DescribeExecution - states:ListStateMachines - states:ListExecutions Resource: - '*' - Effect: Allow Action: - iam:PassRole Resource: - !GetAtt StepFunctionsRole.Arn - PolicyName: desktop-ecr-policy PolicyDocument: Statement: - Effect: Allow Action: - "ecr:GetAuthorizationToken" - "ecr:BatchCheckLayerAvailability" - "ecr:GetDownloadUrlForLayer" - "ecr:GetRepositoryPolicy" - "ecr:DescribeRepositories" - "ecr:ListImages" - "ecr:DescribeImages" - "ecr:BatchGetImage" - "ecr:InitiateLayerUpload" - "ecr:UploadLayerPart" - "ecr:CompleteLayerUpload" - "ecr:PutImage" - "ecr:CreateRepository" Resource: "*" - PolicyName: desktop-dcv-license-s3 PolicyDocument: Statement: - Effect: Allow Action: - 's3:GetObject' Resource: - !Sub 'arn:aws:s3:::dcv-license.${AWS::Region}/*' - PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:Get*" - "s3:List*" - "s3:PutObject*" - "s3:DeleteObject*" Resource: - !Sub 'arn:aws:s3:::${S3Bucket}' - !Sub 'arn:aws:s3:::${S3Bucket}/*' - Effect: Allow Action: - "s3:Get*" - "s3:List*" Resource: - 'arn:aws:s3:::aev-autonomous-driving-dataset' - 'arn:aws:s3:::aev-autonomous-driving-dataset/*' - 'arn:aws:s3:::ford-multi-av-seasonal' - 'arn:aws:s3:::ford-multi-av-seasonal/*' PolicyName: 'DesktopS3Policy' - PolicyName: desktop-ssm PolicyDocument: Statement: - Effect: Allow Action: - 'ssm:GetParametersByPath' Resource: - !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${AWS::StackName}/*' - PolicyName: eks-policy PolicyDocument: Statement: - Effect: Allow Action: - 'eks:DescribeCluster' Resource: - !GetAtt EksControlPlane.Arn DesktopInstanceProfile: Type: "AWS::IAM::InstanceProfile" Properties: Path: "/" Roles: - Ref: "DesktopRole" DesktopLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateData: MetadataOptions: HttpTokens: "required" HttpEndpoint: "enabled" DesktopInstance: Type: 'AWS::EC2::Instance' Properties: LaunchTemplate: LaunchTemplateId: !Ref DesktopLaunchTemplate Version: !GetAtt DesktopLaunchTemplate.LatestVersionNumber ImageId: !If - OverrideAMI - !Ref UbuntuAMI - !FindInMap - !Ref RosVersion - !Ref 'AWS::Region' - AMI InstanceType: !Ref DesktopInstanceType EbsOptimized: true IamInstanceProfile: !Ref DesktopInstanceProfile BlockDeviceMappings: - DeviceName: "/dev/sda1" Ebs: VolumeSize: !Ref DesktopEbsVolumeSize VolumeType: !Ref DesktopEbsVolumeType Encrypted: true DeleteOnTermination: true NetworkInterfaces: - AssociatePublicIpAddress: !Ref DesktopHasPublicIpAddress DeviceIndex: "0" GroupSet: - !Ref DesktopSecurityGroup SubnetId: !Ref PublicSubnet1 KeyName: !Ref KeyPairName Tags: - Key: "Name" Value: !Sub '${AWS::StackName}-desktop' UserData: Fn::Base64: 'Fn::Join': - '' - - !Sub | Content-Type: multipart/mixed; boundary="//" MIME-Version: 1.0 --// Content-Type: text/cloud-config; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="cloud-config.txt" #cloud-config cloud_final_modules: - [scripts-user, always] --// Content-Type: text/x-shellscript; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="userdata.txt" #!/bin/bash -xe echo "Cloud init in progress!" > /etc/motd # Find Ubuntu Version VERSION=$(lsb_release -a | grep Release | awk -F ":" '{print $2}' | sed -E -e 's/[[:blank:]]+//g') echo "Detected Ubuntu $VERSION" # setup graphics desktop export DEBIAN_FRONTEND=noninteractive export DEBCONF_NONINTERACTIVE_SEEN=true # check if we have a GPU and if Nvidia drivers and CUDA need to be installed [[ "${DesktopType}" == "Graphical" ]] && \ [[ ! -z $(lspci -v | grep NVIDIA) ]] && \ [[ ! -x "$(command -v nvidia-smi)" ]] && \ apt-get -y install linux-headers-$(uname -r) && \ ( ( [[ $VERSION == "20.04" ]] && \ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin && \ mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600 && \ apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/3bf863cc.pub && \ add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /" ) || \ ( [[ $VERSION == "22.04" ]] && \ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-ubuntu2204.pin && \ mv cuda-ubuntu2204.pin /etc/apt/preferences.d/cuda-repository-pin-600 && \ apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/3bf863cc.pub && \ add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/ /" ) ) && \ apt-get update && apt-get -y purge cuda && apt-get -y purge nvidia-* && apt-get -y autoremove && \ apt-get -y install cuda-11-8 && \ apt-get -y install libcudnn8=8.6.0.163-1+cuda11.8 && \ apt-get -y install libcudnn8-dev=8.6.0.163-1+cuda11.8 && \ echo "export PATH=/usr/local/cuda-11.8/bin:$PATH" >> /home/ubuntu/.bashrc && \ echo "export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH" >> /home/ubuntu/.bashrc && \ reboot # setup software repo for docker curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - apt-key fingerprint 0EBFCD88 add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" # add key for fsx-lustre client wget -O - https://fsx-lustre-client-repo-public-keys.s3.amazonaws.com/fsx-ubuntu-public-key.asc | apt-key add - # add key for NICE-DCV wget https://d1uj6qtbmh3dt5.cloudfront.net/NICE-GPG-KEY gpg --import NICE-GPG-KEY # update and install required packages apt-get update apt-get install -y git tar apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common # install docker if it is not installed if [ ! -x "$(command -v docker)" ]; then apt-get install -y docker-ce docker-ce-cli containerd.io usermod -aG docker ubuntu # install nvidia container toolkit if we have a nvidia GPU if [[ -x "$(command -v nvidia-smi)" ]] then curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | apt-key add - distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list | \ tee /etc/apt/sources.list.d/nvidia-container-runtime.list apt-get update apt-get -y install nvidia-container-toolkit fi fi apt-get install -y tzdata apt-get install -y keyboard-configuration apt-get install -y gnupg2 apt-get install -y lsb-core # install DCV server if [[ "${DesktopType}" == "Graphical" ]] then echo "install DCV server..." apt-get install -y ubuntu-desktop fi ROS=${RosVersion} if [[ $VERSION == "20.04" ]] then [[ $ROS != 'noetic' ]] && echo "RosVersion must be 'noetic' for Ubuntu $VERSION" && exit 1 bash -c 'echo "deb https://fsx-lustre-client-repo.s3.amazonaws.com/ubuntu focal main" > /etc/apt/sources.list.d/fsxlustreclientrepo.list && apt-get update' # setup software repo for ros sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 apt-get update if [[ "${DesktopType}" == "Graphical" ]] && [[ ! -x "$(command -v dcv)" ]] then apt-get -y install gdm3 apt-get -y upgrade echo "/usr/sbin/gdm3" > /etc/X11/default-display-manager dpkg-reconfigure gdm3 sed -i -e "s/#WaylandEnable=false/WaylandEnable=false/g" /etc/gdm3/custom.conf systemctl restart gdm3 apt-get -y install mesa-utils if [[ -x "$(command -v nvidia-xconfig)" ]] && [[ -x "$(command -v nvidia-smi)" ]] then nvidia-xconfig --preserve-busid --enable-all-gpus fi #restart X server echo "restart X-server" systemctl set-default graphical.target systemctl isolate graphical.target wget https://d1uj6qtbmh3dt5.cloudfront.net/2020.2/Servers/nice-dcv-2020.2-9662-ubuntu2004-x86_64.tgz tar -xvzf nice-dcv-2020.2-9662-ubuntu2004-x86_64.tgz cd nice-dcv-2020.2-9662-ubuntu2004-x86_64 apt-get -y install ./nice-dcv-server_2020.2.9662-1_amd64.ubuntu2004.deb/ reboot fi elif [[ $VERSION == "22.04" ]] then [[ $ROS != 'humble' ]] && echo "RosVersion must be 'humble' for Ubuntu $VERSION" && exit 1 bash -c 'echo "deb https://fsx-lustre-client-repo.s3.amazonaws.com/ubuntu jammy main" > /etc/apt/sources.list.d/fsxlustreclientrepo.list && apt-get update' add-apt-repository universe curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu jammy main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null apt-get update if [[ "${DesktopType}" == "Graphical" ]] && [[ ! -x "$(command -v dcv)" ]] then apt-get -y install gdm3 apt-get -y upgrade || echo "ignoring upgrade error" echo "/usr/sbin/gdm3" > /etc/X11/default-display-manager dpkg-reconfigure gdm3 sed -i -e "s/#WaylandEnable=false/WaylandEnable=false/g" /etc/gdm3/custom.conf systemctl restart gdm3 apt-get -y install mesa-utils if [[ -x "$(command -v nvidia-xconfig)" ]] && [[ -x "$(command -v nvidia-smi)" ]] then nvidia-xconfig --preserve-busid --enable-all-gpus fi #restart X server echo "restart X-server" systemctl set-default graphical.target systemctl isolate graphical.target wget https://d1uj6qtbmh3dt5.cloudfront.net/2022.1/Servers/nice-dcv-2022.1-13300-ubuntu2204-x86_64.tgz tar -xvzf nice-dcv-2022.1-13300-ubuntu2204-x86_64.tgz cd nice-dcv-2022.1-13300-ubuntu2204-x86_64 apt-get -y install ./nice-dcv-server_2022.1.13300-1_amd64.ubuntu2204.deb/ reboot fi else echo "Ubuntu $VERSION is not supported; must be one of 20.04, or 22.04" exit 1 fi if [[ "${DesktopType}" == "Graphical" ]] then #restart X server systemctl set-default graphical.target systemctl isolate graphical.target # Create DCV server configuration file [[ -d /opt/dcv-session-store ]] || mkdir /opt/dcv-session-store echo "[license]" >> dcv.conf echo "[log]" >> dcv.conf echo "[session-management]" >> dcv.conf echo "create-session = true" >> dcv.conf echo "[session-management/defaults]" >> dcv.conf echo "[session-management/automatic-console-session]" >> dcv.conf echo "owner=ubuntu" >> dcv.conf echo "storage-root=\"/opt/dcv-session-store/\"" >> dcv.conf echo "[display]" >> dcv.conf echo "[connectivity]" >> dcv.conf echo "[security]" >> dcv.conf echo "authentication=\"system\"" >> dcv.conf echo "[clipboard]" >> dcv.conf echo "primary-selection-copy=true" >> dcv.conf echo "primary-selection-paste=true" >> dcv.conf mv dcv.conf /etc/dcv/dcv.conf # Create DCV session permissions files rm -f /home/ubuntu/dcv.perms echo "[permissions]" >> /home/ubuntu/dcv.perms echo "%owner% allow builtin" >> /home/ubuntu/dcv.perms # Enable DCV server systemctl enable dcvserver systemctl restart dcvserver echo "install DCV server complete" snap install foxglove-studio fi # install nfs-common apt-get install -y nfs-common apt-get install -y python3-minimal python3-pip test -f /usr/bin/python || ln -s `which python3` /usr/bin/python pip3 install --upgrade pip pip3 install boto3 pip3 install kafka-python pip3 install redshift_connector pip3 install --upgrade awscli pip3 install jupyterlab pip3 install pyquaternion pip3 install --ignore-installed open3d # install ros echo "install ros $ROS ..." apt-get install -y ros-$ROS-desktop-full echo "source /opt/ros/$ROS/setup.bash" >> /home/ubuntu/.bashrc apt-get install -y python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential if [[ ! -d /etc/ros/rosdep/sources.list.d ]] then rosdep init fi sudo -u ubuntu rosdep update if [[ $ROS == 'humble' ]] then apt-get install -y python3-colcon-common-extensions apt-get install -y ros-humble-rosbag2-storage-mcap apt-get install -y ros-humble-rosbridge-server fi # Create roscore startup script if [[ ! -f /usr/local/bin/start-roscore.sh ]] then echo "#!/bin/bash" >> /usr/local/bin/start-roscore.sh echo "source /opt/ros/$ROS/setup.bash" >> /usr/local/bin/start-roscore.sh echo "roscore" >> /usr/local/bin/start-roscore.sh chmod a+x /usr/local/bin/start-roscore.sh fi if [[ ! -f /etc/systemd/system/roscore.service ]] then echo "[Unit]" >> /etc/systemd/system/roscore.service echo "Description=roscore service" >> /etc/systemd/system/roscore.service echo "" >> /etc/systemd/system/roscore.service echo "[Service]" >> /etc/systemd/system/roscore.service echo "User=ubuntu" >> /etc/systemd/system/roscore.service echo "ExecStart=/usr/local/bin/start-roscore.sh" >> /etc/systemd/system/roscore.service echo "Restart=on-abort" >> /etc/systemd/system/roscore.service echo "" >> /etc/systemd/system/roscore.service echo "[Install]" >> /etc/systemd/system/roscore.service echo "WantedBy=graphical.target" >> /etc/systemd/system/roscore.service fi systemctl enable roscore echo "install Ros $ROS complete" # clone repository [[ ! -d /home/ubuntu/amazon-eks-autonomous-driving-data-service ]] && cd /home/ubuntu && \ git clone https://github.com/aws-samples/amazon-eks-autonomous-driving-data-service.git export DIR=/home/ubuntu/amazon-eks-autonomous-driving-data-service chown -R ubuntu:ubuntu $DIR # update /home/ubuntu/.bashrc echo "export cfn_stack_name=${AWS::StackName}" >> /home/ubuntu/.bashrc # Create EFS mount script cat >/usr/local/bin/mount-efs.sh </home/ubuntu/.aws/config < /etc/motd else echo "NICE DCV server is disabled!" > /etc/motd fi - AWS_REGION= - !Ref AWS::Region - |+ - FSX_ENABLED= - !If - FSxForLustreEnabled - "true" - "false" - |+ - FSX_FS_ID= - !If - FSxForLustreEnabled - !Ref FSxFileSystem - '' - |+ - FSX_MOUNT_NAME= - !If - FSxForLustreEnabled - !GetAtt FSxFileSystem.LustreMountName - '' - |+ - | # Create FSx mount script cat >/usr/local/bin/mount-fsx.sh <