--- AWSTemplateFormatVersion: '2010-09-09' Description: This workload template deploys a SqlFSx instance in an existing VPC. **IMPORTANT** This template creates EC2 instances and related resources. You will be billed for the AWS resources used if you create a stack from this template. (qs-1rqmju6dm) Metadata: cfn-lint: config: ignore_checks: - W9006 - E9101 QuickStartDocumentation: EntrypointName: "Parameters for deploying into an existing VPC with self-managed Active Directory" Order: "3" AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network configuration Parameters: - VPCID - VPCcidr - PrivateSubnet1ID - PrivateSubnet2ID - Label: default: Microsoft Active Directory configuration Parameters: - DomainDNSName - DomainNetBIOSName - DomainAdminUser - DomainAdminPassword - DomainMemberSGID - ADDnsIpAddresses - Label: default: Amazon EC2 configuration Parameters: - SqlFSxServerNetBIOSName1 - SqlFSxServerNetBIOSName2 - KeyPairName - WindowsVersion - WorkloadInstanceType - Label: default: Amazon FSx Windows file-share configuration Parameters: - FileShareVolumeSize - FileShareThroughputCapacity - Label: default: Microsoft SQL Server FCI configurations Parameters: - MSSQLMediaBucketName - MSSQLMediaPathKey - SqlFSxWSFCName - SqlFSxFCIName - SQLAdminAccounts - Label: default: Application Insights configuration Parameters: - EnableAppInsights - ApplicationName - ResourceGroupName - Label: default: AWS Quick Start configuration Parameters: - QSS3BucketName - QSS3BucketRegion - QSS3KeyPrefix ParameterLabels: ApplicationName: default: Application Insights application name EnableAppInsights: default: Enable Application Insights ResourceGroupName: default: Resource Group name KeyPairName: default: SSH key name PrivateSubnet1ID: default: Private subnet 1 ID PrivateSubnet2ID: default: Private subnet 2 ID QSS3BucketName: default: Quick Start S3 bucket name QSS3BucketRegion: default: Quick Start S3 bucket Region QSS3KeyPrefix: default: Quick Start S3 key prefix VPCID: default: VPC ID VPCcidr: default: 10.0.0.0/8 WorkloadInstanceType: default: Workload servers instance type DomainAdminPassword: default: Domain administrator password DomainAdminUser: default: Domain administrator user name DomainDNSName: default: Domain DNS name DomainMemberSGID: default: Security group ID for Active Directory domain members ADDnsIpAddresses: default: Active Directory DNS IP addresses MSSQLMediaBucketName: default: S3 bucket for SQL media MSSQLMediaPathKey: default: S3 key for SQL media path SqlFSxWSFCName: default: Windows Server Failover Cluster (WSFC) name SqlFSxFCIName: default: Failover cluster instance (FCI) name SQLAdminAccounts: default: SQL administrator account or accounts DomainNetBIOSName: default: Domain NetBIOS name SqlFSxServerNetBIOSName1: default: Server1 NetBIOS name SqlFSxServerNetBIOSName2: default: Server2 NetBIOS name WindowsVersion: default: Windows version FileShareVolumeSize: default: File-share volume size FileShareThroughputCapacity: default: File-share throughput capacity Parameters: ApplicationName: Default: MSSQL Description: Application Insights application name Type: String EnableAppInsights: Type: String Default: 'false' Description: Select whether to enable Application Insights AllowedValues: - 'true' - 'false' ResourceGroupName: Type: String Default: SQL Description: Application Resource Group name KeyPairName: Description: Name of an existing EC2 key pair. All instances will launch with this key pair. Type: AWS::EC2::KeyPair::KeyName FileShareVolumeSize: Default: 32 Description: Capacity (GB) of the volume used to store SQL Server files. Minimum value is 32 and maximum 65536. Type: Number MinValue: 32 MaxValue: 65536 FileShareThroughputCapacity: Default: 8 Description: File-share throughput capacity (MB/s) in 2 to the nth power increments, where 3 ≤ n ≤ 11, i.e. between 2^3 and 2^11. Type: Number AllowedValues: - 8 - 16 - 32 - 64 - 128 - 256 - 512 - 1024 - 2048 PrivateSubnet1ID: Description: ID of private subnet 1 in Availability Zone 1 for the workload (e.g., subnet-a0246dcd). Type: AWS::EC2::Subnet::Id PrivateSubnet2ID: Description: ID of private subnet 2 in Availability Zone 2 for the workload (e.g., subnet-a0246dcd). Type: AWS::EC2::Subnet::Id QSS3BucketName: AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" ConstraintDescription: The Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: Name of the S3 bucket for your copy of the Quick Start assets. Keep the default name unless you are customizing the template. Changing the name updates code references to point to a new Quick Start location. This name can include numbers, lowercase letters, uppercase letters, and hyphens, but do not start or end with a hyphen (-). See https://aws-quickstart.github.io/option1.html. Type: String QSS3BucketRegion: Default: us-east-1 Description: AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. Keep the default Region unless you are customizing the template. Changing this Region updates code references to point to a new Quick Start location. When using your own bucket, specify the Region. See https://aws-quickstart.github.io/option1.html. Type: String QSS3KeyPrefix: AllowedPattern: "^[0-9a-zA-Z-/]*$" ConstraintDescription: The Quick Start S3 key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/). The prefix should end with a forward slash (/). Default: quickstart-microsoft-sql-fci-fsx/ Description: S3 key prefix that is used to simulate a directory for your copy of the Quick Start assets. Keep the default prefix unless you are customizing the template. Changing this prefix updates code references to point to a new Quick Start location. This prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/). End with a forward slash. See https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html and https://aws-quickstart.github.io/option1.html. Type: String VPCID: Description: ID of your existing VPC for deployment Type: AWS::EC2::VPC::Id VPCcidr: 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 parameter must be in the form x.x.x.x/16-28. Default: 10.0.0.0/16 Description: CIDR block for the VPC. Type: String SqlFSxServerNetBIOSName1: AllowedPattern: "[a-zA-Z0-9\\-]+" Default: SqlFSx1 Description: NetBIOS name of the primary instance. You can use up to 15 characters. MaxLength: '15' MinLength: '1' Type: String SqlFSxServerNetBIOSName2: AllowedPattern: "[a-zA-Z0-9\\-]+" Default: SqlFSx2 Description: NetBIOS name of the secondary instance. You can use up to 15 characters. MaxLength: '15' MinLength: '1' Type: String SqlFSxWSFCName: AllowedPattern: "[a-zA-Z0-9\\-]+" Default: WSFC1 Description: Name of the Windows Server Failover Cluster (WSFC). You can use up to 15 characters. MaxLength: '15' MinLength: '1' Type: String SqlFSxFCIName: AllowedPattern: "[a-zA-Z0-9\\-]+" Default: SqlFCI Description: Name of the failover cluster instance (FCI). You can use up to 15 characters. MaxLength: '15' MinLength: '1' Type: String DomainAdminPassword: Description: Password for the domain administrator. MaxLength: '32' MinLength: '0' NoEcho: 'true' Type: String DomainAdminUser: AllowedPattern: "[a-zA-Z0-9]*" Default: StackAdmin Description: User name for the account that will be used as domain administrator. This is separate from the default "Administrator" account. MaxLength: '25' MinLength: '5' Type: String DomainDNSName: AllowedPattern: "[a-zA-Z0-9\\-]+\\..+" Default: example.com Description: Fully qualified domain name (FQDN). MaxLength: '255' MinLength: '2' Type: String ADDnsIpAddresses: Description: DNS IP addresses for Active Directory. Separate these with commas. MaxLength: '255' MinLength: '2' Type: String DomainMemberSGID: Description: ID of the domain member security group (e.g., sg-9cb7d0e5). Type: String #AWS::EC2::SecurityGroup::Id DomainNetBIOSName: AllowedPattern: "[a-zA-Z0-9\\-]+" Default: EXAMPLE Description: NetBIOS name of the domain for users of earlier versions of Windows. You can use up to 15 characters. MaxLength: '15' MinLength: '1' Type: String WindowsVersion: AllowedValues: - Windows_Server-2019-English-Full-Base* - Windows_Server-2016-English-Full-Base* ConstraintDescription: Must be one of the supported Windows versions. Default: Windows_Server-2019-English-Full-Base* Description: Select Windows version to run SQL Server. Type: String WorkloadInstanceType: AllowedValues: - t3a.2xlarge - t3.2xlarge - r5a.xlarge - r5a.2xlarge - r5a.4xlarge - r5a.8xlarge - r5.large - r5.xlarge - r5.2xlarge - r5.4xlarge - r5.8xlarge - r4.xlarge - r4.2xlarge - r4.4xlarge - r4.8xlarge - z1d.large - z1d.xlarge ConstraintDescription: Must contain a valid instance type. Default: r5.2xlarge Description: Type of EC2 instance for the workload instances. Type: String MSSQLMediaBucketName: AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" ConstraintDescription: You can use lowercase letters, uppercase letters, and hyphens (-). Do not start or end with a hyphen (-). Default: ss-experiments Description: Name of the S3 bucket from which MSSQL media can be downloaded. You can use lowercase letters, uppercase letters, and hyphens (-). Do not start or end with a hyphen (-). Type: String MSSQLMediaPathKey: Default: quickstart-microsoft-SqlFSx/sql-installation-media/en_sql_server_2019_developer_x64_dvd_baea4195.iso Description: Key for the S3 bucket from which MSSQL media can be downloaded. You can use numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/). Type: String SQLAdminAccounts: Default: "contoso\\Administrator" Description: Comma-separated user names are used as MSSQL DB administrators. It could be Active Directory domain administrators or other local or domain users. MaxLength: '25' MinLength: '5' Type: String Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] EnableAppInsightForSQLHA: !Equals [!Ref 'EnableAppInsights', 'true'] Rules: KeyPairsNotEmpty: Assertions: - Assert: Fn::Not: - Fn::EachMemberEquals: - Fn::RefAll: AWS::EC2::KeyPair::KeyName - '' AssertDescription: All key pair parameters must not be empty SubnetsInVPC: Assertions: - Assert: Fn::EachMemberIn: - Fn::ValueOfAll: - AWS::EC2::Subnet::Id - VpcId - Fn::RefAll: AWS::EC2::VPC::Id AssertDescription: All subnets must in the VPC Resources: ADAdminSecrets: Type: AWS::SecretsManager::Secret Properties: Name: !Sub 'AWSQuickStart/${AWS::StackName}/ADAdminSecrets' Description: Active Directory administrator Credentials for Quick Start SecretString: !Sub '{ "username" : "${DomainAdminUser}", "password" : "${DomainAdminPassword}" }' QuickStartLogs: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' RetentionInDays: 30 WindowsBaseAMIInfo: Type: Custom::WindowsBaseAMIInfo Properties: ServiceToken: Fn::GetAtt: - AMIInfoFunction - Arn Region: Ref: AWS::Region AMIName: !Ref WindowsVersion AMIInfoFunction: Type: AWS::Lambda::Function Properties: Code: ZipFile: Fn::Join: - '' - - "/**\n" - "* A Lambda function that looks up the latest AMI ID for a given region and architecture.\n" - "**/\n" - 'var aws = require("aws-sdk");' - 'exports.handler = function(event, context) {' - ' console.log("REQUEST RECEIVED:\n" + JSON.stringify(event));' - " // For Delete requests, immediately send a SUCCESS response.\n" - ' if (event.RequestType == "Delete") {' - ' sendResponse(event, context, "SUCCESS");' - " return;\n" - " }\n" - ' var responseStatus = "FAILED";' - " var responseData = {};\n" - " var ec2 = new aws.EC2({region: event.ResourceProperties.Region});\n" - " var describeImagesParams = {\n" - ' Filters: [{ Name: "name", Values: [event.ResourceProperties.AMIName]}],' - ' Owners: ["amazon"]' - " };\n" - " // Get AMI IDs with the specified name pattern and owner\n" - " ec2.describeImages(describeImagesParams, function(err, describeImagesResult) {\n" - " if (err) {\n" - ' responseData = {Error: "DescribeImages call failed"};' - ' console.log(responseData.Error + ":\n", err);' - " }\n" - " else {\n" - " var images = describeImagesResult.Images;\n" - " // Sort images by name in decscending order. The names contain the AMI version, formatted as YYYY.MM.Ver.\n" - " images.sort(function(x, y) { return y.CreationDate.localeCompare(x.CreationDate); });\n" - " for (var j = 0; j < images.length; j++) {\n" - " if (isBeta(images[j].Name)) continue;\n" - ' responseStatus = "SUCCESS";' - ' responseData["Id"] = images[j].ImageId;' - " break;\n" - " }\n" - " }\n" - " sendResponse(event, context, responseStatus, responseData);\n" - " });\n" - "};\n" - "\n" - "// Check if the image is a beta or rc image. The Lambda function won't return any of those images.\n" - 'function isBeta(imageName) {' - ' return imageName.toLowerCase().indexOf("beta") > -1 || imageName.toLowerCase().indexOf(".rc") > -1;' - "}\n" - "// Send response to the pre-signed S3 URL \n" - 'function sendResponse(event, context, responseStatus, responseData) {' - " var responseBody = JSON.stringify({\n" - " Status: responseStatus,\n" - ' Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,' - " PhysicalResourceId: context.logStreamName,\n" - " StackId: event.StackId,\n" - " RequestId: event.RequestId,\n" - " LogicalResourceId: event.LogicalResourceId,\n" - " Data: responseData\n" - " });\n" - ' console.log("RESPONSE BODY:\n", responseBody);' - ' var https = require("https");' - ' var url = require("url");' - " var parsedUrl = url.parse(event.ResponseURL);\n" - " var options = {\n" - " hostname: parsedUrl.hostname,\n" - " port: 443,\n" - " path: parsedUrl.path,\n" - ' method: "PUT",' - " headers: {\n" - ' "content-type": "",' - ' "content-length": responseBody.length' - " }\n" - " };\n" - ' console.log("SENDING RESPONSE...\n");' - " var request = https.request(options, function(response) {\n" - ' console.log("STATUS: " + response.statusCode);' - ' console.log("HEADERS: " + JSON.stringify(response.headers));' - " // Tell AWS Lambda that the function execution is done \n" - " context.done();\n" - " });\n" - ' request.on("error", function(error) {' - ' console.log("sendResponse Error:" + error);' - " // Tell AWS Lambda that the function execution is done \n" - " context.done();\n" - " });\n" - " // write data to request body\n" - " request.write(responseBody);\n" - " request.end();\n" - "}" Handler: index.handler Role: Fn::GetAtt: - AMIInfoFunctionLambdaExecutionRole - Arn Runtime: nodejs12.x Timeout: 30 AMIInfoFunctionLambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: !Sub 'arn:${AWS::Partition}:logs:*:*:*' - Effect: Allow Action: - ec2:DescribeImages Resource: "*" AWSQuickstartSqlFSxRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyWildcardResource - EIAMPolicyActionWildcard Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:GetObject - s3:ListBucket Resource: - !Sub ['arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}*', S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]] - !Sub ['arn:${AWS::Partition}:s3:::${S3Bucket}', S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]] Effect: Allow PolicyName: aws-quick-start-s3-policy - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - cloudformation:SignalResource Resource: !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}/*' - Effect: Allow Action: - ec2:DescribeInstances - ec2:DescribeInstanceStatus - ec2:StopInstances - ec2:StartInstances - ec2:DescribeNetworkInterfaces - ec2:DescribeSubnets - ssm:* - fsx:Describe* - fsx:ListTagsForResource Resource: '*' PolicyName: SqlFSx-SSM-AutomationExecution Path: / AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Principal: Service: - ec2.amazonaws.com - ssm.amazonaws.com Effect: Allow Version: '2012-10-17' SqlFSxAutomation: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: schemaVersion: "0.3" description: Deploy SqlFSx with SSM Automation # Role that is utilized to perform the steps within the Automation Document. assumeRole: "{{AutomationAssumeRole}}" # Gathering parameters needed to configure DCs in the Quick Start parameters: DomainDNSName: default: !Sub "${DomainDNSName}" description: "Fully qualified domain name (FQDN) of the forest root domain." type: "String" DomainNetBIOSName: default: !Sub "${DomainNetBIOSName}" description: NetBIOS name of the domain for users of earlier versions of Windows. You can use up to 15 characters. type: "String" MSSQLMediaBucketName: default: !Sub "${MSSQLMediaBucketName}" description: "Name of the S3 bucket from which MSSQL media can be downloaded. You can use lowercase letters, uppercase letters, and hyphens (-). Do not start or end with a hyphen (-)." type: "String" MSSQLMediaPathKey: default: !Sub "${MSSQLMediaPathKey}" description: "Key for the S3 bucket from which MSSQL media can be downloaded. You can use numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/)." type: "String" ClusterName: default: !Sub "${SqlFSxWSFCName}" description: "NetBIOS name of the cluster (up to 15 characters)." type: "String" SqlFSxFCIName: default: !Sub "${SqlFSxFCIName}" description: "NetBIOS name of the failover cluster instance (up to 15 characters)." type: "String" SQLAdminAccounts: default: !Sub "${SQLAdminAccounts}" description: "MSSQL administrator accounts" type: "String" AdminSecrets: default: !Sub "${ADAdminSecrets}" description: "Domain admin credentials" type: "String" SqlFSxInstanceId: default: "" description: "ID of the SqlFSx instance" type: "String" StackName: default: !Sub "${AWS::StackName}" description: "CloudFormation stack name" type: "String" SqlFSxServerNetBIOSName1: default: !Sub "${SqlFSxServerNetBIOSName1}" description: "CloudFormation stack name" type: "String" AutomationAssumeRole: default: "" description: "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf." type: "String" WindowsVersion: default: !Sub "${WindowsVersion}" description: "The AMI used to deploy SqlFSx instance." type: "String" URLSuffix: description: "AWS URL suffix" type: "String" QSS3BucketName: default: "aws-quickstart" description: "S3 bucket name for the Quick Start assets. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-)." type: "String" QSS3KeyPrefix: default: "quickstart-microsoft-sql/" description: "S3 key prefix for the Quick Start assets. Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/)." type: "String" mainSteps: #Getting cluster infrastructure resources - name: FindFSxVolDnsAddress action: 'aws:executeScript' onFailure: "step:signalfailure" inputs: Runtime: PowerShell Core 6.0 Script: | Install-Module AWS.Tools.FSx -Force Import-Module AWS.Tools.FSx $fsList = Get-FSXFileSystem; $fsList.forEach{ $tags = $_.Tags; foreach ($tag in $tags) { if ($tag.key -eq "Name" -And $tag.value -eq "SqlFSxFileSystem") { $dnsName = $_.DNSName; $psEndpoint = $_.WindowsConfiguration.RemoteAdministrationEndpoint break; } } }; $resultStr = "{0};{1}" -f $dnsName, $psEndpoint Write-Host $dnsName return @{message=$resultStr} outputs: - Name: FSxDnsAddress Selector: $.Payload.message Type: String - name: GetAllClusterNodes action: 'aws:executeAwsApi' outputs: - Name: InstanceIds Selector: $.Reservations..Instances..InstanceId Type: StringList inputs: Service: ec2 Api: DescribeInstances Filters: - Name: 'tag:FCIName' Values: - Ref: SqlFSxFCIName - Name: instance-state-name Values: - running description: Get instances - name: GetClusterNode1 action: 'aws:executeAwsApi' outputs: - Name: InstanceIds Selector: $.Reservations..Instances..InstanceId Type: StringList inputs: Service: ec2 Api: DescribeInstances Filters: - Name: 'tag:Name' Values: - Ref: SqlFSxServerNetBIOSName1 - Name: instance-state-name Values: - running description: Get instances - name: GetClusterNode2 action: 'aws:executeAwsApi' outputs: - Name: InstanceIds Selector: $.Reservations..Instances..InstanceId Type: StringList inputs: Service: ec2 Api: DescribeInstances Filters: - Name: 'tag:Name' Values: - Ref: SqlFSxServerNetBIOSName2 - Name: instance-state-name Values: - running description: Get instances - name: FindSecondaryIpAddresses action: 'aws:executeScript' onFailure: "step:signalfailure" inputs: Runtime: PowerShell Core 6.0 Script: | $inputPayload = $env:InputPayload | ConvertFrom-Json; Install-Module AWS.Tools.EC2 -Force Import-Module AWS.Tools.EC2 #Function to find Subnet function Get-SubnetMask($i) { $instance = $i $subnetid = $instance.instances[0].NetworkInterfaces.SubnetId $subnet = get-ec2subnet -SubnetId $subnetid $cidr = $subnet.CidrBlock $cidr_mask = $cidr.split('/')[1] $A = 0 $A_Index = 8 $B = 0 $B_Index = 16 $C = 0 $C_Index = 24 $D = 0 $D_Index = 32 for ($i = 1; $i -le $cidr_mask; $i++) { if ($i -le $A_Index) { $A += ([Math]::Pow(2, 8 - $i)) } elseif ($i -le $B_Index) { $B += ([Math]::Pow(2, 8 - $i + $A_Index)) } elseif ($i -le $C_Index) { $C += ([Math]::Pow(2, 8 - $i + $B_Index)) } elseif ($i -le $D_Index) { $D += ([Math]::Pow(2, 8 - $i + $C_Index)) } } $subnet_mask = "{0}.{1}.{2}.{3}" -f $A, $B, $C, $D return $subnet_mask } $instanceIds = $inputPayload.parameter $resultStr = "" $subnetMaskStr = "" #Finding secondary IP addresses of the primary instance foreach ($i in $instanceIds) { $instance = get-ec2instance -InstanceId $i $tags = $instance.instances[0].Tags foreach ($t in $tags) { if ($t.Key -eq "FCIRole" -And $t.Value -eq "Primary") { $IPs = $instance.instances[0].NetworkInterfaces.PrivateIpAddresses $ip1 = $IPs[1].PrivateIpAddress $ip2 = $IPs[2].PrivateIpAddress $resultStr = "{0};{1}" -f $ip1, $ip2 $subnetMaskStr = Get-SubnetMask($instance) break; } } if ([System.String]::IsNullOrEmpty($resultStr) -Eq $False) { break; } } #Finding secondary IP addresses of the secondary instance foreach ($i in $instanceIds) { $instance = get-ec2instance -InstanceId $i $tags = $instance.instances[0].Tags foreach ($t in $tags) { if ($t.Key -eq "FCIRole" -And $t.Value -eq "Secondary") { $IPs = $instance.instances[0].NetworkInterfaces.PrivateIpAddresses $ip1 = $IPs[1].PrivateIpAddress $ip2 = $IPs[2].PrivateIpAddress $resultStr = "{0};{1};{2}" -f $resultStr, $ip1, $ip2 $subnetMask = Get-SubnetMask($instance) $subnetMaskStr = "{0};{1}" -f $subnetMaskStr, $subnetMask break; } } } $resultStr = "{0};{1}" -f $resultStr, $subnetMaskStr Write-Host $dnsName return @{message=$resultStr} InputPayload: parameter: '{{GetAllClusterNodes.InstanceIds}}' outputs: - Name: SecondaryPrivateIpAddresses Selector: $.Payload.message Type: String #Preparing requisites - name: "UpdateSSMAgent" action: "aws:runCommand" timeoutSeconds: 300 onFailure: "Continue" inputs: DocumentName: AWS-UpdateSSMAgent InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' - name: "InitializeDisk" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: commands: - | C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1 - name: "InstallDSCModules" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/install-dsc-modules.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./install-dsc-modules.ps1" - name: "wsfcnLCMConfig" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/LCM-Config.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./LCM-Config.ps1" #Joining to AD - name: "CreateDomainJoinMOF" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/DomainJoin.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./DomainJoin.ps1 -DomainNetBIOSName '{{DomainNetBIOSName}}' -DomainDNSName '{{DomainDNSName}}' -AdminSecret '{{AdminSecrets}}' -InstanceName $(Get-Content -Path C:\\log\\hostname.txt)" - name: "RunDomainJoinMOF" action: aws:runCommand onFailure: "step:signalfailure" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: commands: - | function DscStatusCheck () { $LCMState = (Get-DscLocalConfigurationManager).LCMState if ($LCMState -eq 'PendingConfiguration' -Or $LCMState -eq 'PendingReboot') { 'returning 3010, should continue after reboot' exit 3010 } else { 'Completed' } } Start-DscConfiguration 'C:\AWSQuickstart\DomainJoin' -Wait -Verbose -Force DscStatusCheck - name: "EnableCredSSP" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/enable-CredSSP.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./enable-CredSSP.ps1 -DomainDNSName '{{DomainDNSName}}'" #Creating continuously available SMB share on FSx file system - name: "CreateCAShare" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetClusterNode1.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/create-ca-share.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./create-ca-share.ps1 -DomainNetBIOSName '{{DomainNetBIOSName}}' -AdminSecret '{{AdminSecrets}}' -FSxRemoteAdminEndpoint '{{FindFSxVolDnsAddress.FSxDnsAddress}}'.split(';')[1]" #Creating WSFC - name: "CreateNode1WsfcMOF" action: "aws:runCommand" onFailure: "step:signalfailure" #nextStep: inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetClusterNode1.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Node1Config.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Node1Config.ps1 -DomainNetBIOSName {{DomainNetBIOSName}} -DomainDNSName {{DomainDNSName}} -WSFCNode1PrivateIP2 '{{FindSecondaryIpAddresses.SecondaryPrivateIpAddresses}}'.split(';')[0] -ClusterName {{ClusterName}} -AdminSecret {{AdminSecrets}} -FileServerNetBIOSName '{{FindFSxVolDnsAddress.FSxDnsAddress}}'.split(';')[0]" - name: "RunNode1WsfcMOF" action: aws:runCommand onFailure: "step:signalfailure" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: '{{GetClusterNode1.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: commands: - | function DscStatusCheck () { $LCMState = (Get-DscLocalConfigurationManager).LCMState if ($LCMState -eq 'PendingConfiguration' -Or $LCMState -eq 'PendingReboot') { 'returning 3010, should continue after reboot' exit 3010 } else { 'Completed' } } Start-DscConfiguration 'C:\AWSQuickstart\WSFCNode1Config' -Wait -Verbose -Force DscStatusCheck - name: "CreateNode2WsfcMOF" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{GetClusterNode2.InstanceIds}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/AdditionalNodeConfig.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./AdditionalNodeConfig.ps1 -DomainNetBIOSName {{DomainNetBIOSName}} -WSFCNodePrivateIP2 '{{FindSecondaryIpAddresses.SecondaryPrivateIpAddresses}}'.split(';')[2] -ClusterName {{ClusterName}} -AdminSecret {{AdminSecrets}}" - name: "RunNode2WsfcMOF" action: aws:runCommand onFailure: "step:signalfailure" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - "{{GetClusterNode2.InstanceIds}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: commands: - | function DscStatusCheck () { $LCMState = (Get-DscLocalConfigurationManager).LCMState if ($LCMState -eq 'PendingConfiguration' -Or $LCMState -eq 'PendingReboot') { 'returning 3010, should continue after reboot' exit 3010 } else { 'Completed' } } Start-DscConfiguration 'C:\AWSQuickstart\AdditionalWSFCNode' -Wait -Verbose -Force DscStatusCheck #Installing MSSQL FCI - name: "PrepareFCI" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetAllClusterNodes.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/prepare-fci.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./prepare-fci.ps1 -AdminSecret '{{AdminSecrets}}' -DomainNetBIOSName {{DomainNetBIOSName}} -SqlUserSecret {{AdminSecrets}} -MSSQLMediaBucket '{{MSSQLMediaBucketName}}' -MSSQLMediaKey '{{MSSQLMediaPathKey}}'" - name: "CompleteFCI" action: "aws:runCommand" onFailure: "step:signalfailure" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: '{{GetClusterNode1.InstanceIds}}' CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Ref 'QuickStartLogs' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/complete-fci.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./complete-fci.ps1 -AdminSecret '{{AdminSecrets}}' -DomainNetBIOSName {{DomainNetBIOSName}} -FileServerPath '{{FindFSxVolDnsAddress.FSxDnsAddress}}'.split(';')[0] -Node1FciIp '{{FindSecondaryIpAddresses.SecondaryPrivateIpAddresses}}'.split(';')[1] -Node1SubnetMask '{{FindSecondaryIpAddresses.SecondaryPrivateIpAddresses}}'.split(';')[4] -Node2FciIp '{{FindSecondaryIpAddresses.SecondaryPrivateIpAddresses}}'.split(';')[3] -Node2SubnetMask '{{FindSecondaryIpAddresses.SecondaryPrivateIpAddresses}}'.split(';')[5] -FCIName {{SqlFSxFCIName}} -SQLAdminAccounts '{{SQLAdminAccounts}}'" #End of deployment workflow # Determines if CFN Needs to be Signaled or if Workflow should just end - name: CFNSignalEnd action: aws:branch inputs: Choices: - NextStep: signalsuccess Not: Variable: "{{StackName}}" StringEquals: "" - NextStep: sleepend Variable: "{{StackName}}" StringEquals: "" # If all steps complete successfully signals CFN of Success - name: "signalsuccess" action: "aws:executeAwsApi" isEnd: True inputs: Service: cloudformation Api: SignalResource LogicalResourceId: "SSMWaitCondition" StackName: "{{StackName}}" Status: SUCCESS UniqueId: "{{SqlFSxInstanceId}}" # If CFN Signl Not Needed this sleep ends work flow - name: "sleepend" action: "aws:sleep" isEnd: True inputs: Duration: PT1S # If any steps fails signals CFN of Failure - name: "signalfailure" action: "aws:executeAwsApi" inputs: Service: cloudformation Api: SignalResource LogicalResourceId: "SSMWaitCondition" StackName: "{{StackName}}" Status: FAILURE UniqueId: "{{SqlFSxInstanceId}}" SqlFSxSSMPassRolePolicy: Type: AWS::IAM::Policy Properties: PolicyName: SqlFsx-SSM-PassRole PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:PassRole Resource: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AWSQuickstartSqlFSxRole}' Roles: - !Ref 'AWSQuickstartSqlFSxRole' SqlFSxInstance1: Type: AWS::EC2::Instance DependsOn: FSxWindowsFileSystem Properties: ImageId: Fn::GetAtt: - WindowsBaseAMIInfo - Id IamInstanceProfile: Ref: SqlFSxProfile InstanceType: Ref: WorkloadInstanceType NetworkInterfaces: - DeleteOnTermination: true DeviceIndex: '0' SubnetId: Ref: PrivateSubnet1ID SecondaryPrivateIpAddressCount: 2 GroupSet: - Ref: DomainMemberSGID - Ref: WorkloadSecurityGroup Tags: - Key: Name Value: Ref: SqlFSxServerNetBIOSName1 - Key: FCIName Value: Ref: SqlFSxFCIName - Key: FCIRole Value: Primary - Key: ResourceGroup Value: !Ref ResourceGroupName BlockDeviceMappings: - DeviceName: "/dev/sda1" Ebs: VolumeSize: 100 VolumeType: gp2 KeyName: Ref: KeyPairName UserData: !Base64 Fn::Join: - '' - - "\n" - "New-Item -Path C:\\ -Name log -ItemType Directory \n" - "$transcriptPath = 'C:\\log\\user-data-transcript.txt' \n" - "Start-Transcript $transcriptPath \n" - !Sub 'Set-Content -Value "${SqlFSxServerNetBIOSName1}" -Path C:\log\hostname.txt' - "\n" - !Sub 'Rename-Computer -NewName "${SqlFSxServerNetBIOSName1}"' - "\n" - "$instanceId = (New-Object System.Net.WebClient).DownloadString('http://169.254.169.254/latest/meta-data/instance-id')\n" - 'Start-SSMAutomationExecution -DocumentName ' - !Sub '"${SqlFSxAutomation}"' - ' -Parameter @{' - '"SqlFSxInstanceId"=' - "$instanceId" - ';"URLSuffix"=' - !Sub '"${AWS::URLSuffix}"' - ';"QSS3BucketName"=' - !Sub '"${QSS3BucketName}"' - ';"QSS3KeyPrefix"=' - !Sub '"${QSS3KeyPrefix}"' - ';"AutomationAssumeRole"=' - !Sub '"arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AWSQuickstartSqlFSxRole}"' - '}' - "\n" - "\n" SqlFSxInstance2: Type: AWS::EC2::Instance Properties: ImageId: Fn::GetAtt: - WindowsBaseAMIInfo - Id IamInstanceProfile: Ref: SqlFSxProfile InstanceType: Ref: WorkloadInstanceType NetworkInterfaces: - DeleteOnTermination: true DeviceIndex: '0' SubnetId: Ref: PrivateSubnet2ID SecondaryPrivateIpAddressCount: 2 GroupSet: - Ref: DomainMemberSGID - Ref: WorkloadSecurityGroup Tags: - Key: Name Value: Ref: SqlFSxServerNetBIOSName2 - Key: FCIName Value: Ref: SqlFSxFCIName - Key: FCIRole Value: Secondary - Key: ResourceGroup Value: !Ref ResourceGroupName BlockDeviceMappings: - DeviceName: "/dev/sda1" Ebs: VolumeSize: 100 VolumeType: gp2 KeyName: Ref: KeyPairName UserData: !Base64 Fn::Join: - '' - - "\n" - "New-Item -Path C:\\ -Name log -ItemType Directory \n" - !Sub 'Set-Content -Value "${SqlFSxServerNetBIOSName2}" -Path C:\log\hostname.txt' - "\n" - !Sub 'Rename-Computer -NewName "${SqlFSxServerNetBIOSName2}"' - "\n" - "\n" SqlFSxRole: Type: AWS::IAM::Role Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyWildcardResource - EIAMPolicyActionWildcard Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:GetObject Resource: - !Sub ['arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}*', S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]] Effect: Allow - Action: - s3:* Resource: "*" Effect: Allow PolicyName: aws-quick-start-s3-policy - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue - secretsmanager:DescribeSecret Resource: - !Ref 'ADAdminSecrets' - Effect: Allow Action: - ssm:StartAutomationExecution Resource: '*' PolicyName: QS-SqlFSx-SSM - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - iam:PassRole Resource: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AWSQuickstartSqlFSxRole}' PolicyName: QS-SqlFSx-SSM-PassRole ManagedPolicyArns: - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore" Path: "/" AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Principal: Service: - ec2.amazonaws.com Effect: Allow Version: '2012-10-17' SqlFSxProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - Ref: SqlFSxRole Path: "/" SSMWaitHandle: Type: AWS::CloudFormation::WaitConditionHandle SSMWaitCondition: Type: AWS::CloudFormation::WaitCondition CreationPolicy: ResourceSignal: Timeout: PT120M Count: 1 DependsOn: "SqlFSxInstance1" Properties: Handle: Ref: "SSMWaitHandle" Timeout: "7200" Count: 1 WorkloadSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow access to the Workload instances VpcId: Ref: VPCID SecurityGroupIngress: - IpProtocol: '-1' FromPort: -1 ToPort: -1 CidrIp: Ref: VPCcidr FSxWindowsFileSystem: Type: 'AWS::FSx::FileSystem' Properties: FileSystemType: WINDOWS StorageCapacity: Ref: FileShareVolumeSize StorageType: SSD SubnetIds: - Ref: PrivateSubnet1ID - Ref: PrivateSubnet2ID SecurityGroupIds: - Ref: WorkloadSecurityGroup - Ref: DomainMemberSGID Tags: - Key: Name Value: SqlFSxFileSystem WindowsConfiguration: ThroughputCapacity: Ref: FileShareThroughputCapacity WeeklyMaintenanceStartTime: '4:16:30' DailyAutomaticBackupStartTime: '01:00' AutomaticBackupRetentionDays: 30 CopyTagsToBackups: false DeploymentType: MULTI_AZ_1 PreferredSubnetId: Ref: PrivateSubnet1ID SelfManagedActiveDirectoryConfiguration: DnsIps: - !Select - 0 - !Split - ',' - Ref: ADDnsIpAddresses DomainName: Ref: DomainDNSName FileSystemAdministratorsGroup: "Domain Admins" UserName: !Sub '${DomainAdminUser}' Password: !Sub '${DomainAdminPassword}' ResourceGroup: Type: AWS::ResourceGroups::Group Properties: Name: !Ref 'ResourceGroupName' Description: "A resource group for SQL servers" ResourceQuery: Type: "TAG_FILTERS_1_0" Query: ResourceTypeFilters: - "AWS::EC2::Instance" TagFilters: - Key: ResourceGroup Values: - !Ref ResourceGroupName AppInsightsForSQLHA: Condition: EnableAppInsightForSQLHA DependsOn: SSMWaitCondition Type: AWS::ApplicationInsights::Application Properties: ResourceGroupName: !Ref 'ResourceGroupName' AutoConfigurationEnabled: false CustomComponents: - ComponentName: !Sub 'SQLHAClusterInstances-${ApplicationName}' ResourceList: - !Sub 'arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:instance/${SqlFSxInstance1}' - !Sub 'arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:instance/${SqlFSxInstance2}' ComponentMonitoringSettings: - ComponentName: !Sub 'SQLHAClusterInstances-${ApplicationName}' Tier: SQL_SERVER_ALWAYSON_AVAILABILITY_GROUP ComponentConfigurationMode: DEFAULT_WITH_OVERWRITE DefaultOverwriteComponentConfiguration: SubComponentTypeConfigurations: - SubComponentType: AWS::EC2::Instance SubComponentConfigurationDetails: Logs: - LogGroupName: !Sub 'SQL_SERVER-${ResourceGroupName}' LogType: SQL_SERVER LogPath: C:\Program Files\Microsoft SQL Server\MSSQL**.MSSQLSERVER\MSSQL\Log\ERRORLOG Tags: - Key: SourceTemplate Value: AWSQuickStart Outputs: InstanceIP: Description: "Private IP address of SqlFSx instance." Value: !GetAtt SqlFSxInstance1.PrivateIp Postdeployment: Value: https://fwd.aws/5XG6A Description: See the deployment guide for post-deployment steps.