{
	"AWSTemplateFormatVersion": "2010-09-09",
	"Description": "ArcGIS CloudFormation Template: Provisions an ArcGIS Mission Server site on EC2 instances running Windows Server 2019. **WARNING** You will be billed by AWS for the AWS resources if you create a stack from this template.",
	"Metadata": {
		"AWS::CloudFormation::Interface": {
			"ParameterGroups": [{
					"Label": {
						"default": "Network Configuration"
					},
					"Parameters": [
						"VPCId",
						"Subnet",
						"SiteEIPAllocationID",
						"SiteDomain",
						"SSLCertificateFile",
						"SSLCertPassword"
					]
				},
				{
					"Label": {
						"default": "Amazon EC2 Configuration"
					},
					"Parameters": [
						"BaseAMI",
						"InstanceType",
						"DriveSizeRoot",
						"KeyName"
					]
				},
				{
					"Label": {
						"default": "ArcGIS Enterprise Configuration"
					},
					"Parameters": [
						"DeploymentBucket",
						"ServerLicenseFile",
						"SiteAdmin",
						"SiteAdminPassword",
						"RunAsUserPassword"
					]
				}
			]
		}
	},
	"Parameters": {
		"DeploymentBucket": {
			"Type": "String",
			"Description": "S3 bucket with ArcGIS Server authorization file",
			"AllowedPattern": "^([a-z]|(\\d(?!\\d{0,2}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})))([a-z\\d]|(\\.(?!(\\.|-)))|(-(?!\\.))){1,61}[a-z\\d\\.]$",
			"ConstraintDescription": "A Bucket's name can be between 6 and 63 characters long, containing lowercase characters, numbers, periods, and dashes and it must start with a lowercase letter or number."
		},
		"DriveSizeRoot": {
			"Type": "Number",
			"Default": 100,
			"Description": "Size of root drive in GB.",
			"MinValue": 100,
			"MaxValue": 1024,
			"ConstraintDescription": "Must be between 100 and 1024 GB."
		},
		"InstanceType": {
			"Type": "String",
			"Description": "ArcGIS Mission Server EC2 instance type",
			"Default": "c5.2xlarge",
			"AllowedValues": [
				"c4.2xlarge",
				"c4.4xlarge",
				"c4.8xlarge",
				"c5.2xlarge",
				"c5.4xlarge",
				"c5.9xlarge",
				"c5.18xlarge",
				"c5.xlarge",
				"c5d.2xlarge",
				"c5d.4xlarge",
				"c5d.9xlarge",
				"c5d.18xlarge",
				"c5n.2xlarge",
				"c5n.4xlarge",
				"c5n.9xlarge",
				"c5n.18xlarge",
				"m4.xlarge",
				"m4.2xlarge",
				"m4.4xlarge",
				"m4.10xlarge",
				"m5.xlarge",
				"m5.2xlarge",
				"m5.4xlarge",
				"m5.12xlarge",
				"m5.24xlarge",
				"m5.metal",
				"m5d.xlarge",
				"m5d.2xlarge",
				"m5d.4xlarge",
				"m5d.12xlarge",
				"m5d.24xlarge",
				"m5d.metal",
				"m5a.xlarge",
				"m5a.2xlarge",
				"m5a.4xlarge",
				"m5a.12xlarge",
				"m5a.24xlarge",
				"m4.xlarge",
				"m4.2xlarge",
				"m4.4xlarge",
				"m4.10xlarge",
				"m4.16xlarge",
				"p3.2xlarge",
				"p3.8xlarge",
				"p3.16xlarge",
				"r4.xlarge",
				"r4.2xlarge",
				"r4.4xlarge",
				"r4.8xlarge",
				"r4.16xlarge",
				"r5.large",
				"r5.xlarge",
				"r5.2xlarge",
				"r5.4xlarge",
				"r5.12xlarge",
				"r5.24xlarge",
				"r5.metal",
				"r5a.large",
				"r5a.xlarge",
				"r5a.2xlarge",
				"r5a.4xlarge",
				"r5a.12xlarge",
				"r5a.24xlarge",
				"t2.xlarge",
				"t2.2xlarge",
				"t3.xlarge",
				"t3.2xlarge",
				"t3a.xlarge",
				"t3a.2xlarge",
				"x1.16xlarge",
				"x1.32xlarge",
				"x1e.xlarge",
				"x1e.2xlarge",
				"x1e.4xlarge",
				"x1e.8xlarge",
				"x1e.16xlarge",
				"x1e.32xlarge"
			]
		},
		"KeyName": {
			"Type": "AWS::EC2::KeyPair::KeyName",
			"Description": "EC2 Key Pair to allow RemoteDesktop access to the instances"
		},
		"ServerLicenseFile": {
			"Type": "String",
			"Description": "ArcGIS Mission Server authorization file (must be uploaded to DeploymentBucket)",
			"AllowedPattern": "^([/\\w\\-\\.]+)+\\.(ecp|prvc)$",
			"ConstraintDescription": "License file name must be alphanumeric. It can contain dash ('-'), dot ('.'), and underscore ('_') characters. The file name must end with '.ecp' or '.prvc'."
		},
		"SiteAdmin": {
			"Type": "String",
			"Default": "siteadmin",
			"Description": "User name of ArcGIS Mission Server primary site administrator",
			"AllowedPattern": "^[a-zA-Z][a-zA-Z0-9_]{6,}$",
			"ConstraintDescription": "User name must be 6 or more alphanumeric or underscore (_) characters and must start with a letter."
		},
		"SiteAdminPassword": {
			"Type": "String",
			"Description": "Password of ArcGIS Mission Server primary site administrator",
			"NoEcho": true,
			"AllowedPattern": "^[a-zA-Z0-9_\\.@]{8,}$",
			"ConstraintDescription": "Password must be 8 or more alphanumeric, underscore (_), at ('@'), or dot (.) characters."
		},
		"SSLCertificateFile": {
			"Type": "String",
			"Description": "SSL certificate file issued to the site domain (must be uploaded to DeploymentBucket)",
			"AllowedPattern": "^([/\\w\\-\\.]+)+\\.(pfx)$",
			"ConstraintDescription": "Certificate file name must be alphanumeric. It can contain slash ('/'), dash ('-'), dot ('.'), and underscore ('_') characters. The file name must end with '.pfx'"
		},
		"SSLCertPassword": {
			"Type": "String",
			"Description": "SSL certificate file password",
			"NoEcho": true,
			"AllowedPattern": "[^\\\"]{1,128}",
			"ConstraintDescription": "Password must be between 1 and 128 characters and must not contain backslashes (\\) or quotation marks (\")."
		},
		"RunAsUserPassword": {
			"Description": "Password for ArcGIS Mission Server account",
			"Type": "String",
			"NoEcho": "true",
			"AllowedPattern": "(?!.*arcgis)(?!.*Arc)(?!.*GIS)(?!.*user)(?!.*account)^((?=.*[a-z])(?=.*[A-Z])(?=.*\\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*[^A-Za-z0-9])|(?=.*[a-z])(?=.*\\d)(?=.*[^A-Za-z0-9])|(?=.*[A-Z])(?=.*\\d)(?=.*[^A-Za-z0-9]))([A-Za-z\\d@#$%&�*\\-_+=\\[\\]{}|:\\',?~();!]|\\.(?!@)){8,}$",
			"ConstraintDescription": "Password must be at least eight characters in length and must contain characters from three of the following four categories: English uppercase characters (A through Z), English lowercase characters (a through z), digits (0 through 9), non-alphabetic characters (for example, !, $, #, %). Password must not contain backslashes (\\) or quotation marks (\"). Password must not contain the user's account name (arcgis) or parts of the user's full name (ArcGIS user account) that exceed two consecutive characters."
		},
		"VPCId": {
			"Type": "AWS::EC2::VPC::Id",
			"Description": "VPC ID"
		},
		"Subnet": {
			"Type": "AWS::EC2::Subnet::Id",
			"Description": "VPC Subnet"
		},
		"SiteEIPAllocationID": {
			"Type": "String",
			"Default": "",
			"Description": "Allocation ID of Elastic IP address for VPC (eipalloc-XXXXXXXX)",
			"AllowedPattern": "^$|eipalloc-.*"
		},
		"SiteDomain": {
			"Type": "String",
			"Description": "Domain name of ArcGIS Mission Server site",
			"AllowedPattern": "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([a-zA-Z]|[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9])$",
			"ConstraintDescription": "The domain name is invalid."
		},
		"BaseAMI": {
			"Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
			"Default": "/aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base",
			"Description": "Name of the Systems Manager parameter that contains EC2 AMI Id"
		},
		"PostInstallationScript": {
			"Type": "String",
			"Default": "none",
			"Description": "(Optional) ZIP archive file with custom post installation script",
			"AllowedPattern": "[^\"]{1,1024}",
			"ConstraintDescription": "S3 object key name must be between 1 and 1024 characters."
		}
	},
	"Mappings": {
		"Repositories": {
			"ap-south-1": {
				"bucket": "arcgisstore1081-ap-south-1",
				"region": "ap-south-1"
			},
			"eu-north-1": {
				"bucket": "arcgisstore1081-eu-north-1",
				"region": "eu-north-1"
			},
			"eu-west-3": {
				"bucket": "arcgisstore1081-eu-west-3",
				"region": "eu-west-3"
			},
			"eu-west-2": {
				"bucket": "arcgisstore1081-eu-west-2",
				"region": "eu-west-2"
			},
			"eu-west-1": {
				"bucket": "arcgisstore1081-eu-west-1",
				"region": "eu-west-1"
			},
			"ap-northeast-2": {
				"bucket": "arcgisstore1081-ap-northeast-2",
				"region": "ap-northeast-2"
			},
			"ap-northeast-1": {
				"bucket": "arcgisstore1081-ap-northeast-1",
				"region": "ap-northeast-1"
			},
			"sa-east-1": {
				"bucket": "arcgisstore1081-sa-east-1",
				"region": "sa-east-1"
			},
			"ca-central-1": {
				"bucket": "arcgisstore1081-ca-central-1",
				"region": "ca-central-1"
			},
			"ap-southeast-1": {
				"bucket": "arcgisstore1081-ap-southeast-1",
				"region": "ap-southeast-1"
			},
			"ap-southeast-2": {
				"bucket": "arcgisstore1081-ap-southeast-2",
				"region": "ap-southeast-2"
			},
			"eu-central-1": {
				"bucket": "arcgisstore1081-eu-central-1",
				"region": "eu-central-1"
			},
			"us-east-1": {
				"bucket": "arcgisstore1081-us-east-1",
				"region": "us-east-1"
			},
			"us-east-2": {
				"bucket": "arcgisstore1081-us-east-2",
				"region": "us-east-2"
			},
			"us-west-1": {
				"bucket": "arcgisstore1081-us-west-1",
				"region": "us-west-1"
			},
			"us-west-2": {
				"bucket": "arcgisstore1081-us-west-2",
				"region": "us-west-2"
			},
			"us-gov-east-1": {
				"bucket": "arcgisstore1081-us-gov-east-1",
				"region": "us-gov-east-1"
			},
			"us-gov-west-1": {
				"bucket": "arcgisstore1081-us-gov-west-1",
				"region": "us-gov-west-1"
			}
		}
	},
	"Conditions": {
		"AttachEIP": {
			"Fn::Not": [{
				"Fn::Equals": [{
						"Ref": "SiteEIPAllocationID"
					},
					""
				]
			}]
		}
	},
	"Resources": {
		"SiteAdminPasswordSecret": {
			"Type": "AWS::SecretsManager::Secret",
			"Properties": {
				"Description": "Password of ArcGIS Mission Server primary site administrator",
				"SecretString": {
					"Ref": "SiteAdminPassword"
				}
			}
		},
		"SSLCertPasswordSecret": {
			"Type": "AWS::SecretsManager::Secret",
			"Properties": {
				"Description": "SSL certificate file password",
				"SecretString": {
					"Ref": "SSLCertPassword"
				}
			}
		},
		"RunAsUserPasswordSecret": {
			"Type": "AWS::SecretsManager::Secret",
			"Properties": {
				"Description": "Password for ArcGIS Mission Server account",
				"SecretString": {
					"Ref": "RunAsUserPassword"
				}
			}
		},
		"StopStackFunction": {
			"Type": "AWS::Lambda::Function",
			"DependsOn": "IAMRole",
			"Properties": {
				"Code": {
					"S3Bucket": {"Fn::Join" : ["", ["arcgisstore1081", "-", {"Ref": "AWS::Region"}]]},
					"S3Key": "14362/lambda/arcgis-cfn-lambda-python3.zip"
				},
				"Environment": {
					"Variables": {
						"StackName": {
							"Ref": "AWS::StackName"
						}
					}
				},
				"Handler": "stop_start.stop_mission_server_stack",
				"Runtime": "python3.8",
				"Timeout": "300",
				"Role": {
					"Fn::GetAtt": ["LambdaExecutionRole", "Arn"]
				},
				"Description": "Stops all EC2 instances of the CloudFormation stack"
			}
		},
		"StartStackFunction": {
			"Type": "AWS::Lambda::Function",
			"DependsOn": "IAMRole",
			"Properties": {
				"Code": {
					"S3Bucket": {"Fn::Join" : ["", ["arcgisstore1081", "-", {"Ref": "AWS::Region"}]]},
					"S3Key": "14362/lambda/arcgis-cfn-lambda-python3.zip"
				},
				"Environment": {
					"Variables": {
						"StackName": {
							"Ref": "AWS::StackName"
						}
					}
				},
				"Handler": "stop_start.start_mission_server_stack",
				"Runtime": "python3.8",
				"Timeout": "300",
				"Role": {
					"Fn::GetAtt": ["LambdaExecutionRole", "Arn"]
				},
				"Description": "Starts all EC2 instances of the CloudFormation stack"
			}
		},
		"LambdaExecutionRole": {
			"Type": "AWS::IAM::Role",
			"Properties": {
				"AssumeRolePolicyDocument": {
					"Version": "2012-10-17",
					"Statement": [{
						"Effect": "Allow",
						"Principal": {
							"Service": ["lambda.amazonaws.com"]
						},
						"Action": ["sts:AssumeRole"]
					}]
				},
				"Path": "/"
			}
		},
		"LambdaExecutionPolicy": {
			"Type": "AWS::IAM::Policy",
			"Properties": {
				"PolicyName": "ArcGISMissionServerLambda",
				"PolicyDocument": {
					"Statement": [{
							"Effect": "Allow",
							"Action": ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"],
							"Resource": "*"
						},
						{
							"Effect": "Allow",
							"Action": [
								"ec2:DescribeInstances",
								"ec2:StartInstances",
								"ec2:DescribeTags",
								"ec2:DescribeRegions",
								"ec2:StopInstances",
								"ec2:DescribeInstanceStatus"
							],
							"Resource": "*"
						},
						{
							"Effect": "Allow",
							"Action": [
								"cloudformation:DescribeStacks",
								"cloudformation:DescribeStackResources",
								"cloudformation:DescribeStackResource"
							],
							"Resource": "*"
						}
					]
				},
				"Roles": [{
					"Ref": "LambdaExecutionRole"
				}]
			}
		},
		"IAMRole": {
			"Type": "AWS::IAM::Role",
			"Properties": {
				"AssumeRolePolicyDocument": {
					"Statement": [{
						"Effect": "Allow",
						"Principal": {
							"Service": [
								"ec2.amazonaws.com",
								"ssm.amazonaws.com"
							]
						},
						"Action": [
							"sts:AssumeRole"
						]
					}]
				},
				"Path": "/"
			}
		},
		"IAMPolicy": {
			"Type": "AWS::IAM::Policy",
			"Properties": {
				"PolicyName": "ArcGISMissionServer",
				"PolicyDocument": {
					"Statement": [{
							"Action": [
								"cloudformation:DescribeStacks",
								"cloudformation:DescribeStackResources",
								"cloudformation:DescribeStackResource",
								"cloudformation:SignalResource"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"logs:DescribeLogGroups",
								"logs:DescribeLogStreams",
								"logs:PutLogEvents",
								"logs:PutMetricFilter",
								"logs:CreateLogGroup",
								"logs:CreateLogStream"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"ssm:DeleteAssociation",
								"ssm:DescribeAssociation",
								"ssm:DescribeInstanceInformation",
								"ssm:GetDeployablePatchSnapshotForInstance",
								"ssm:GetDocument",
								"ssm:DescribeDocument",
								"ssm:GetManifest",
								"ssm:GetParameter",
								"ssm:GetParameters",
								"ssm:ListAssociations",
								"ssm:ListCommands",
								"ssm:ListCommandInvocations",
								"ssm:ListInstanceAssociations",
								"ssm:PutInventory",
								"ssm:PutComplianceItems",
								"ssm:PutConfigurePackageResult",
								"ssm:SendCommand",
								"ssm:UpdateAssociationStatus",
								"ssm:UpdateInstanceAssociationStatus",
								"ssm:UpdateInstanceInformation"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
            {
							"Action": [
								"ec2:DescribeTags",
								"ec2:DescribeInstances",
								"ec2:ModifyInstanceMetadataOptions"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"ec2messages:AcknowledgeMessage",
								"ec2messages:DeleteMessage",
								"ec2messages:FailMessage",
								"ec2messages:GetEndpoint",
								"ec2messages:GetMessages",
								"ec2messages:SendReply"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"ssmmessages:CreateControlChannel",
								"ssmmessages:CreateDataChannel",
								"ssmmessages:OpenControlChannel",
								"ssmmessages:OpenDataChannel"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"s3:*"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"secretsmanager:GetSecretValue"
							],
							"Effect": "Allow",
							"Resource": [{
									"Ref": "SiteAdminPasswordSecret"
								},
								{
									"Ref": "SSLCertPasswordSecret"
								},
								{
									"Ref": "RunAsUserPasswordSecret"
								}
							]
						}
					]
				},
				"Roles": [{
					"Ref": "IAMRole"
				}]
			}
		},
		"IAMInstanceProfile": {
			"Type": "AWS::IAM::InstanceProfile",
			"Properties": {
				"Path": "/",
				"Roles": [{
					"Ref": "IAMRole"
				}]
			}
		},
		"SecurityGroup": {
			"Type": "AWS::EC2::SecurityGroup",
			"Properties": {
				"GroupDescription": "Allow HTTP and HTTPS for all client IPs",
				"VpcId": {
					"Ref": "VPCId"
				},
				"SecurityGroupIngress": [{
						"IpProtocol": "tcp",
						"FromPort": 80,
						"ToPort": 80,
						"CidrIp": "0.0.0.0/0"
					},
					{
						"IpProtocol": "tcp",
						"FromPort": 443,
						"ToPort": 443,
						"CidrIp": "0.0.0.0/0"
					}
				]
			}
		},
		"SecurityGroupIngress": {
			"Type": "AWS::EC2::SecurityGroupIngress",
			"Properties": {
				"GroupId": {
					"Ref": "SecurityGroup"
				},
				"IpProtocol": "tcp",
				"FromPort": 0,
				"ToPort": 65535,
				"SourceSecurityGroupId": {
					"Ref": "SecurityGroup"
				}
			}
		},
		"EC2InstanceLaunchTemplate": {
      "Type": "AWS::EC2::LaunchTemplate",
      "Properties": {
        "LaunchTemplateData": {
          "ImageId": {
            "Ref": "BaseAMI"
          },
          "InstanceType": {
            "Ref": "InstanceType"
          },
          "KeyName": {
            "Ref": "KeyName"
          },
          "IamInstanceProfile": {
            "Arn": {
              "Fn::GetAtt": [
                "IAMInstanceProfile",
                "Arn"
              ]
            }
          },
          "MetadataOptions": {
            "HttpEndpoint": "enabled",
            "HttpTokens": "required"
          },
          "BlockDeviceMappings": [{
            "DeviceName": "/dev/sda1",
            "Ebs": {
              "VolumeSize": {
                "Ref": "DriveSizeRoot"
              },
              "DeleteOnTermination": true,
              "VolumeType": "gp2"
            }
          }],
          "NetworkInterfaces": [{
            "AssociatePublicIpAddress": true,
            "DeleteOnTermination": true,
            "DeviceIndex": "0",
            "Groups": [{
              "Ref": "SecurityGroup"
            }],
            "SubnetId": {
              "Ref": "Subnet"
            }
          }]
        }
      }
    },
    "PrimaryEC2Instance": {
			"Type": "AWS::EC2::Instance",
			"Properties": {
        "Monitoring": true,
        "LaunchTemplate": {
          "LaunchTemplateId": {
            "Ref": "EC2InstanceLaunchTemplate"
          },
          "Version": {
            "Fn::GetAtt": [
              "EC2InstanceLaunchTemplate",
              "LatestVersionNumber"
            ]
          }
        },
				"Tags": [{
						"Key": "Name",
						"Value": {
							"Fn::Sub": "${AWS::StackName}-primary"
						}
					},
					{
						"Key": "arcgis:role",
						"Value": "mission-server-primary"
					}
				]
			}
		},
		"EIPAssociation": {
			"Type": "AWS::EC2::EIPAssociation",
			"Condition": "AttachEIP",
			"Properties": {
				"AllocationId": {
					"Ref": "SiteEIPAllocationID"
				},
				"InstanceId": {
					"Ref": "PrimaryEC2Instance"
				}
			}
		},
		"PrimaryInstanceRecoveryAlarm": {
			"Type": "AWS::CloudWatch::Alarm",
			"Properties": {
				"AlarmDescription": "Trigger a recovery when instance status check fails for 5 consecutive minutes.",
				"MetricName": "StatusCheckFailed_System",
				"Namespace": "AWS/EC2",
				"Statistic": "Minimum",
				"Period": 60,
				"EvaluationPeriods": 5,
				"Threshold": 0,
				"ComparisonOperator": "GreaterThanThreshold",
				"AlarmActions": [{
					"Fn::Sub": "arn:${AWS::Partition}:automate:${AWS::Region}:ec2:recover"
				}],
				"Dimensions": [{
					"Name": "InstanceId",
					"Value": {
						"Ref": "PrimaryEC2Instance"
					}
				}]
			}
		},
		"DeploymentLogs": {
			"Type": "AWS::Logs::LogGroup",
			"Properties": {
				"LogGroupName": {
					"Fn::Sub": [
						"/ESRI/MissionServerWindows/${LogName}",
						{
							"LogName": {
								"Ref": "AWS::StackName"
							}
						}
					]
				}
			}
		},
		"InstallMissionServerCommand": {
			"Type": "AWS::SSM::Document",
			"Properties": {
				"DocumentType": "Command",
				"Content": {
					"schemaVersion": "2.2",
					"description": "Installs and configures ArcGIS Mission Server",
					"parameters": {
						"chefClientS3Key": {
							"type": "String",
							"default": "chefclient/chef-client-14.14.29-1-x64.msi",
							"description": "S3 key of Chef Client package in the repositoryBucket"
						},
						"cookbooksUrl": {
							"type": "String",
							"default": "https://arcgisstore1081.s3.amazonaws.com/14362/cookbooks/arcgis-3.6.0-cookbooks.tar.gz",
							"description": "ArcGIS Chef cookbooks URL"
						},
						"region": {
							"type": "String",
							"default": {
								"Ref": "AWS::Region"
							},
							"description": "AWS region"
						},
						"arcgisVersion": {
							"type": "String",
							"default": "10.8.1",
							"description": "ArcGIS Mission Server version"
						},
						"machineRole": {
							"type": "String",
							"description": "ArcGIS Mission machine role",
							"allowedValues": [
								"mission-server-primary"
							]
						},
						"repositoryBucket": {
							"type": "String",
							"default": {
								"Fn::FindInMap": [
									"Repositories",
									{
										"Ref": "AWS::Region"
									},
									"bucket"
								]
							},
							"description": "ArcGIS software repository S3 bucket"
						},
						"repositoryBucketRegion": {
							"type": "String",
							"default": {
								"Fn::FindInMap": [
									"Repositories",
									{
										"Ref": "AWS::Region"
									},
									"region"
								]
							},
							"description": "Region of ArcGIS software repository  S3 bucket"
						},
						"deploymentBucket": {
							"type": "String",
							"default": {
								"Ref": "DeploymentBucket"
							},
							"description": "S3 bucket with authorization files and SSL certificates"
						},
						"licenseFile": {
							"type": "String",
							"default": {
								"Ref": "ServerLicenseFile"
							},
							"description": "S3 key of ArcGIS Mission Server software authorization file"
						},
						"certificateFile": {
							"type": "String",
							"default": {
								"Ref": "SSLCertificateFile"
							},
							"description": "S3 key of SSL certificate file in PKSC12 format"
						},
						"certificatePasswordSecretId": {
							"type": "String",
							"default": {
								"Ref": "SSLCertPasswordSecret"
							},
							"description": "Secret ID of SSL certificate file password"
						},
						"siteAdmin": {
							"type": "String",
							"default": {
								"Ref": "SiteAdmin"
							},
							"description": "ArcGIS Mission Server primary site administrator username"
						},
						"siteAdminPasswordSecretId": {
							"type": "String",
							"default": {
								"Ref": "SiteAdminPasswordSecret"
							},
							"description": "Secret ID of ArcGIS Mission Server primary site administrator password"
						},
						"runAsUserPasswordSecretId": {
							"type": "String",
							"default": {
								"Ref": "RunAsUserPasswordSecret"
							},
							"description": "Secret ID of ArcGIS Mission Server account password"
						},
						"siteDomain": {
							"type": "String",
							"default": {
								"Ref": "SiteDomain"
							},
							"description": "Domain name of ArcGIS Mission Server site"
						}
					},
					"mainSteps": [{
						"action": "aws:runPowerShellScript",
						"name": "InstallMissionServeronWindows",
						"inputs": {
							"runCommand": [
								"try",
								"{",
								"  Write-Output \"Downloading Chef client...\"",
								"  $chefSetup = \"C:\\Temp\\chef-client.msi\"",
								"  Read-S3Object -BucketName {{repositoryBucket}} -Key {{chefClientS3Key}} -File $chefSetup -Region {{repositoryBucketRegion}}",
								"  Write-Output \"Installing Chef Client...\"",
								"  $process = Start-Process msiexec -PassThru -Wait -ArgumentList (\"/qn\", \"/i\", $chefSetup)",
								"  if (($process.ExitCode -ne 0) -and ($process.ExitCode -ne 1603)) {",
								"    throw \"Chef client installation failed. Exit code: $($process.ExitCode)\"",
								"  }",
								"  $env:Path = [System.Environment]::GetEnvironmentVariable(\"Path\",\"Machine\")",
								"  $cookbooks = \"C:\\Temp\\cookbooks.tar.gz\"",
								"  Remove-Item $chefSetup",
								"  Write-Output \"Downloading Chef cookbooks...\"",
								"  Invoke-WebRequest -Uri {{cookbooksUrl}} -OutFile $cookbooks",
								"  Write-Output \"Extracting Chef cookbooks from the archive...\"",
								"  tar -C C:\\chef -xzf $cookbooks ",
								"  Remove-Item $cookbooks",
								"  Write-Output \"Get files from the deployment S3 bucket...\"",
								"  $licenseFile = \"C:\\Temp\\{{licenseFile}}\"",
								"  $deploymentbucketregion = (Get-S3BucketLocation -BucketName {{deploymentBucket}} -Region {{region}}).Value",
								"  if (([string]::IsNullOrEmpty($deploymentbucketregion))) {",
								"     $deploymentbucketregion = \"us-east-1\"",
								"  }",
								"  Read-S3Object -BucketName {{deploymentBucket}} -Key {{licenseFile}} -File $licenseFile -Region $deploymentbucketregion",
								"  $certificateFile = \"C:\\Temp\\{{certificateFile}}\"",
								"  Read-S3Object -BucketName {{deploymentBucket}} -Key {{certificateFile}} -File $certificateFile -Region $deploymentbucketregion",
								"  Write-Output \"Get secrets from AWS Secret Manager...\"",
								"  $runAsUserPassword = (Get-SECSecretValue -SecretId {{runAsUserPasswordSecretId}} -Region {{region}}).SecretString",
								"  $certificatePassword = (Get-SECSecretValue -SecretId {{certificatePasswordSecretId}} -Region {{region}}).SecretString",
								"  $siteAdminPassword = (Get-SECSecretValue -SecretId {{siteAdminPasswordSecretId}}).SecretString",
								"  $templatejson = \"C:\\chef\\templates/arcgis-mission-server/{{arcgisVersion}}/windows/{{machineRole}}.json\"",
								"  $nodejson = \"C:\\Temp\\mission-server.json\"",
								"  Write-Output \"Replace attribute values in the Chef deployment template...\"",
								"  $attributes = Get-Content -Path $templatejson | ConvertFrom-Json",
								"  $attributes.arcgis.run_as_password = $runAsUserPassword",
								"  $attributes.arcgis.iis.keystore_file = $certificateFile",
								"  $attributes.arcgis.iis.keystore_password = $certificatePassword",
								"  $attributes.arcgis.repository.server.s3bucket = \"{{repositoryBucket}}\"",
								"  $attributes.arcgis.repository.server.region = \"{{repositoryBucketRegion}}\"",
								"  $attributes.arcgis.mission_server.authorization_file = $licenseFile",
								"  $attributes.arcgis.mission_server.system_properties.WebSocketContextURL = \"wss://{{siteDomain}}/mission\"",
								"  $attributes.arcgis.mission_server.admin_username = \"{{siteAdmin}}\"",
								"  $attributes.arcgis.mission_server.admin_password = $siteAdminPassword",
								"  $json = $attributes | ConvertTo-Json -Depth 10",
								"  Set-Content -Path $nodejson -Value $json",
								"  Write-Output \"Run Chef...\"",
								"  Set-Location C:\\chef",
								"  chef-client -z -j $nodejson -L chef-run.log -l info",
								"  if ($LASTEXITCODE -ne 0) {",
								"    throw \"Chef run failed. Exit code: $LASTEXITCODE\"",
								"  }",
								"  Write-Output \"Clean up temporary files...\"",
								"  Remove-Item C:\\Temp\\* -Recurse -Force",
								"  Write-Output \"ArcGIS Mission Server installation complete.\"",
								"}",
								"catch",
								"{",
								"  Write-Error $_.Exception | format-list -force",
                "  Write-Error 'Error occured while creating deployment' -ErrorAction Stop",
								"}"
							]
						}
					}]
				}
			}
		},
		"InstallMissionServerAutomation": {
			"Type": "AWS::SSM::Document",
			"Properties": {
				"Content": {
					"schemaVersion": "0.3",
					"description": "Installs and configure ArcGIS Mission Server.",
					"assumeRole": {
						"Fn::GetAtt": [
							"IAMRole",
							"Arn"
						]
					},
					"parameters": {
						"InstanceId": {
							"type": "String",
							"description": "(Required) EC2 instance id"
						},
						"MachineRole": {
							"type": "String",
							"description": "(Required) Machine role for ArcGIS Mission server deployment"
						},
						"WaitCondition": {
							"type": "String",
							"description": "(Required) Wait condition for CloudFormation template",
							"default": ""
						}
					},
					"mainSteps": [
						{
						"name": "RunInstallMissionServerCommand",
						"action": "aws:runCommand",
						"onFailure": "step:SignalFailure",
						"nextStep": "SignalSuccess",
						"timeoutSeconds": 3600,
						"inputs": {
							"DocumentName": {
								"Ref": "InstallMissionServerCommand"
							},
							"InstanceIds": [
								"{{InstanceId}}"
							],
							"CloudWatchOutputConfig": {
								"CloudWatchOutputEnabled": "true",
								"CloudWatchLogGroupName": {
									"Ref": "DeploymentLogs"
								}
							},
							"Parameters": {
								"machineRole": "{{MachineRole}}"
							}
						}
						},
						{
							"name": "SignalFailure",
							"action": "aws:executeScript",
							"isEnd": true,
							"inputs": {
								"Runtime": "PowerShell Core 6.0",
								"Script": "Write-Host $env:InputPayload; \n$inputPayload = $env:InputPayload | ConvertFrom-Json; \n<#$parameter = $inputPayload.events.parameter;#>\n\nInstall-Module AWS.Tools.CloudFormation -Force\n\n$StackName = $inputPayload.StackName;\n$WaitCondition = $inputPayload.WaitCondition;\n$UniqueId = $inputPayload.UniqueId;\n$Status = $inputPayload.Status;\n\nif (!([string]::IsNullOrEmpty($WaitCondition))) {\n  try\n  {\n    $stackstatus=((Get-CFNStack -StackName $StackName).StackStatus).Value\n    Write-Output $stackstatus\n    if ($stackstatus -eq \"CREATE_IN_PROGRESS\") {\n      Send-CFNResourceSignal -StackName $StackName -LogicalResourceId $WaitCondition -Status $Status -UniqueId $UniqueId\n    }\n  }\n  catch\n  {\n    Write-Error $_.Exception | format-list -force\n  }\n}\n",
								"InputPayload": {
									"StackName": {
										"Ref": "AWS::StackName"
									},
									"UniqueId": "{{InstanceId}}",
									"WaitCondition": "{{WaitCondition}}",
									"Status": "FAILURE"
								}
							}
						},
						{
							"name": "SignalSuccess",
							"action": "aws:executeScript",
							"isEnd": true,
							"inputs": {
								"Runtime": "PowerShell Core 6.0",
								"Script": "Write-Host $env:InputPayload; \n$inputPayload = $env:InputPayload | ConvertFrom-Json; \n<#$parameter = $inputPayload.events.parameter;#>\n\nInstall-Module AWS.Tools.CloudFormation -Force\n\n$StackName = $inputPayload.StackName;\n$WaitCondition = $inputPayload.WaitCondition;\n$UniqueId = $inputPayload.UniqueId;\n$Status = $inputPayload.Status;\n\nif (!([string]::IsNullOrEmpty($WaitCondition))) {\n  try\n  {\n    $stackstatus=((Get-CFNStack -StackName $StackName).StackStatus).Value\n    Write-Output $stackstatus\n    if ($stackstatus -eq \"CREATE_IN_PROGRESS\") {\n      Send-CFNResourceSignal -StackName $StackName -LogicalResourceId $WaitCondition -Status $Status -UniqueId $UniqueId\n    }\n  }\n  catch\n  {\n    Write-Error $_.Exception | format-list -force\n  }\n}\n",
								"InputPayload": {
									"StackName": {
										"Ref": "AWS::StackName"
									},
									"UniqueId": "{{InstanceId}}",
									"WaitCondition": "{{WaitCondition}}",
									"Status": "SUCCESS"
								}
							}
						}
						]
				},
				"DocumentType": "Automation"
			}
		},
		"InstallMissionServerPrimary": {
			"Type": "AWS::SSM::Association",
			"DependsOn": [
				"PrimaryEC2Instance"
			],
			"Properties": {
				"Name": {
					"Ref": "InstallMissionServerAutomation"
				},
				"Parameters": {
					"InstanceId": [{
						"Ref": "PrimaryEC2Instance"
					}],
					"MachineRole": [
						"mission-server-primary"
					],
					"WaitCondition": [
						"InstallMissionServerPrimaryWaitCondition"
					]
				}
			}
		},
		"InstallMissionServerPrimaryWaitCondition": {
			"Type": "AWS::CloudFormation::WaitCondition",
			"DependsOn": [
				"PrimaryEC2Instance"
			],
			"CreationPolicy": {
				"ResourceSignal": {
					"Timeout": "PT1H",
					"Count": "1"
				}
			}
		}
	},
	"Outputs": {
		"AdminURL": {
			"Description": "ArcGIS Mission Server admin services URL",
			"Value": {
				"Fn::Sub": "https://${SiteDomain}/mission/admin/"
			}
		},
		"StopStackFunction": {
			"Value": {
				"Fn::Join": ["", ["https://console.aws.amazon.com/lambda/home?region=", {
					"Ref": "AWS::Region"
				}, "#/functions/", {
					"Ref": "StopStackFunction"
				}]]
			},
			"Description": "Lambda function used to stop all EC2 instances in the stack."
		},
		"StartStackFunction": {
			"Value": {
				"Fn::Join": ["", ["https://console.aws.amazon.com/lambda/home?region=", {
					"Ref": "AWS::Region"
				}, "#/functions/", {
					"Ref": "StartStackFunction"
				}]]
			},
			"Description": "Lambda function used to start all EC2 instances in the stack."
		}
	}
}