---
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-1rqmju6ap)
Metadata:
  cfn-lint:
    config:
      ignore_checks:
        - W9006
        - E9101
  QuickStartDocumentation:
    EntrypointName: "Parameters for deploying into an existing VPC with AWS Managed Microsoft AD"
    Order: "2"
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: Network configuration
      Parameters:
      - VPCID
      - PrivateSubnet1ID
      - PrivateSubnet2ID
      - VPCcidr
    - Label:
        default: Microsoft Active Directory configuration
      Parameters:
      - DomainDNSName
      - DomainNetBIOSName
      - DomainAdminUser
      - DomainAdminPassword
      - DomainMemberSGID
      - ADDnsIpAddresses
      - DirectoryId
    - 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
      VPCcidr:
        default: VPC CIDR
      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
      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
      DomainNetBIOSName:
        default: Domain NetBIOS name 
      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
      ADDnsIpAddresses: 
        default: Active Directory DNS IP addresses  
      DirectoryId: 
        default: ID of the AWS Directory Service directory     
      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: MSSQLFCI
    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
  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
  DirectoryId:
    Description: The ID of the AWS Directory Service directory.
    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 will be used as MSSQL DB administrators. It could be Active Directory domain administrators or other local or domain users.
    MaxLength: '25'
    MinLength: '5'
    Type: String
  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
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"
          DirectoryId:
            default: !Sub "${DirectoryId}"
            description: "The ID of the AWS Directory Service directory (e.g., d-97672886b5)."
            type: "String"
          ADDnsIpAddresses:
            default: !Sub "${ADDnsIpAddresses}"
            description: "The IP addresses of the DNS servers in the directory. Required when DHCP is not configured."
            type: "String"
          MSSQLMediaBucketName:
            default: !Sub "${MSSQLMediaBucketName}"
            description: "The S3 bucket from which MSSQL media can be downloaded."
            type: "String"  
          MSSQLMediaPathKey:
            default: !Sub "${MSSQLMediaPathKey}"
            description: "The key for the S3 bucket from which MSSQL media can be downloaded."
            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 administrator 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: "JoinAD"
          action: "aws:runCommand"
          onFailure: "step:signalfailure"
          inputs:
            DocumentName: "AWS-JoinDirectoryServiceDomain"
            InstanceIds: '{{GetAllClusterNodes.InstanceIds}}'
            CloudWatchOutputConfig:
              CloudWatchOutputEnabled: "true"
              CloudWatchLogGroupName: !Ref 'QuickStartLogs'
            Parameters:
              directoryId: "{{DirectoryId}}"
              directoryName: "{{DomainDNSName}}"
              dnsIpAddresses: !Select [0, !Split [",", !Ref ADDnsIpAddresses]]
        - 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   
        - name: "ConfigurePermissionsOnMAD"
          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/Configure-MAD-Permissions.ps1"}'
                  - S3Bucket: !If 
                      - UsingDefaultBucket
                      - !Sub '${QSS3BucketName}-${AWS::Region}'
                      - !Ref QSS3BucketName
                    S3Region: !If 
                      - UsingDefaultBucket
                      - !Ref AWS::Region
                      - !Ref QSS3BucketRegion
              commandLine: "./Configure-MAD-Permissions.ps1 -AdminSecret {{AdminSecrets}} -DomainNetBIOSName '{{DomainNetBIOSName}}' -wsfcName '{{ClusterName}}'"
        #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:
          - ''
          - - "<powershell>\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"
            - "</powershell>\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:
          - ''
          - - "<powershell>\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"
            - "</powershell>\n"            
  SqlFSxRole:
    Type: AWS::IAM::Role
    Metadata:
      cfn-lint:
        config:
          ignore_checks:
            - EIAMPolicyActionWildcard
            - EIAMPolicyWildcardResource
    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:
                - ds:*
              Resource: 
                - "*"
        PolicyName: QS-SqlFSx-DS
      - 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
        ActiveDirectoryId: !Sub '${DirectoryId}'
  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.