---
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.