{
	"AWSTemplateFormatVersion": "2010-09-09",
	
	"Description" : "My Stack. Stack description only",
	"Parameters": {
		"DBKeyName": {
			"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the database instance",
			"Type": "String"
		},
		"DBInstanceType": {
			"Default": "t1.micro",
			"Description" : "The type of EC2 instance used for the database server",
			"Type": "String",
			"AllowedPattern" : "[a-zA-Z0-9\\.]+"
		},
		"WebServerKeyName": {
			"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the web server instances",
			"Type": "String"
		},
		"WebServerInstanceType": {
			"Default": "t1.micro",
			"Description" : "The type of EC2 instances used for the web servers",
			"Type": "String",
			"AllowedPattern" : "[a-zA-Z0-9\\.]+"
		},
		"WebServerDefaultGroupSize": {
			"Default": "1",
			"Description" : "The default number of web server EC2 instances",
			"Type": "Number",
			"MinValue": "1"
		},
		"NotificationEmailAddress": {
			"Description": "Email address to notify if there are any operational issues",
			"Type": "String"
		},
		"ChefServerURL" : {
			"Description" : "URL of Chef Server",
			"Type": "String"
		},
		"ChefServerPrivateKeyBucket" : {
			"Description" : "S3 bucket containing validation private key for Chef Server",
			"Type": "String"
		},
		"ChefServerPrivateKeyLocation" : {
			"Description" : "Location of the validation key within the Private Key S3 bucket. This needs to include the name of the file",
			"Type": "String"
		}
	},
	"Mappings" : {
		"AWSInstanceType2Arch" : {
			"t1.micro"    : { "Arch" : "64" },
			"m1.small"    : { "Arch" : "32" },
			"m1.large"    : { "Arch" : "64" },
			"m1.xlarge"   : { "Arch" : "64" },
			"m2.xlarge"   : { "Arch" : "64" },
			"m2.2xlarge"  : { "Arch" : "64" },
			"m2.4xlarge"  : { "Arch" : "64" },
			"c1.medium"   : { "Arch" : "32" },
			"c1.xlarge"   : { "Arch" : "64" },
			"cc1.4xlarge" : { "Arch" : "64" }
		},
		"AWSRegionArch2AMI" : {
			"us-east-1" : { "32" : "ami-ab36fbc2", "64" : "ami-ad36fbc4" },
			"us-west-1" : { "32" : "ami-eb227eae", "64" : "ami-f5227eb0" },
			"us-west-2" : { "32" : "ami-defe73ee", "64" : "ami-c4fe73f4" },
			"eu-west-1" : { "32" : "ami-c00e3cb4", "64" : "ami-cc0e3cb8" },
			"ap-southeast-1" : { "32" : "ami-ea205ab8", "64" : "ami-e8205aba" },
			"ap-northeast-1" : { "32" : "ami-78b40079", "64" : "ami-7ab4007b" }
		}
	},
	"Resources": {
		"ChefClientUser" : {
			"Type" : "AWS::IAM::User",
			"Properties" : {
				"Path": "/",
				"Policies": [{
					"PolicyName": "root",
					"PolicyDocument": { 
						"Statement":[{
							"Action": [
								"cloudformation:DescribeStackResource"
							],
							"Effect": "Allow",
							"Resource": "*"
						},
						{
							"Action": [
								"s3:GetObject"
							],
							"Effect": "Allow",
							"Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref" : "ChefServerPrivateKeyBucket"} , "/*"]]}
						}]
					}
				}]
			}
		},
		"HostKeys" : {
			"Type" : "AWS::IAM::AccessKey",
			"Properties" : {
				"UserName" : {"Ref": "ChefClientUser"}
			}
		},
		"DBServer" : {
			"Type" : "AWS::EC2::Instance",
			"Properties" : {
				"KeyName" : { "Ref" : "DBKeyName" },
				"SecurityGroups" : [ { "Ref" : "DBSecurityGroup" } ],
				"InstanceType" : { "Ref": "DBInstanceType" },
				"ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "DBInstanceType" }, "Arch" ] } ] },
				"Tags" : [ { "Key" : "Name", "Value" : "Database Server" } ],
				"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
					"#!/bin/bash -v\n",
					"function error_exit\n",
					"{\n",
					"  cfn-signal -e 1 -r \"$1\" '", { "Ref" : "DBChefClientWaitHandle" }, "'\n",
					"  exit 1\n",
					"}\n",
					"apt-get -y install python-setuptools\n",
					"easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-1.0-6.tar.gz\n",
					"apt-get update\n",
					"cfn-init --region ", { "Ref" : "AWS::Region" },
					"    -s ", { "Ref" : "AWS::StackName" }, " -r DBServer ",
					"         --access-key ", { "Ref" : "HostKeys" },
					"         --secret-key ", {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]},
					"         --region     ", { "Ref" : "AWS::Region" }, " || error_exit 'Failed to run cfn-init'\n",
					"# Fixup path and links for the bootstrap script\n",
					"export PATH=$PATH:/var/lib/gems/1.8/bin\n",
					"# Bootstrap chef\n",
					"chef-solo -c /etc/chef/solo.rb -j /etc/chef/chef.json -r http://s3.amazonaws.com/chef-solo/bootstrap-latest.tar.gz  > /tmp/chef_solo.log 2>&1 || error_exit 'Failed to bootstrap chef client'\n",
					"# Fixup the server URL in client.rb\n",
					"s3cmd -c /home/ubuntu/.s3cfg get s3://", { "Ref" : "ChefServerPrivateKeyBucket" }, "/", { "Ref" : "ChefServerPrivateKeyLocation" }, " /etc/chef/validation.pem > /tmp/get_validation_key.log 2>&1 || error_exit 'Failed to get Chef Server validation key'\n",
					"sed -i 's|http://localhost:4000|", { "Ref" : "ChefServerURL" }, "|g' /etc/chef/client.rb\n",
					"chef-client -j /etc/chef/roles.json > /tmp/initialize_client.log 2>&1 || error_exit 'Failed to initialize host via chef client' \n",
					"# If all went well, signal success\n",
					"cfn-signal -e $? -r 'Chef Server configuration' '", { "Ref" : "DBChefClientWaitHandle" }, "'\n"
				]]}}
			},
			"DependsOn" : "HostKeys",
			"Metadata" : {
				"AWS::CloudFormation::Init" : {
					"config" : {
						"packages" : {
							"rubygems" : {
								"chef" : [],
								"ohai" : ["0.6.4"]
							},
							"apt" : {
								"ruby"            : [],
								"ruby-dev"        : [],
								"libopenssl-ruby" : [],
								"rdoc"            : [],
								"ri"              : [],
								"irb"             : [],
								"build-essential" : [],
								"wget"            : [],
								"ssl-cert"        : [],
								"rubygems"        : [],
								"s3cmd"           : []
							}
						},
						"files" : {
							"/etc/chef/solo.rb" : {
								"content" : { "Fn::Join" : ["\n", [
									"file_cache_path \"/tmp/chef-solo\"",
									"cookbook_path \"/tmp/chef-solo/cookbooks\""
								]]},
								"mode"  : "000644",
								"owner" : "root",
								"group" : "root"
							},
							"/etc/chef/chef.json" : {
								"content" : {
									"chef_client": {
										"server_url": { "Ref" : "ChefServerURL" },
										"validation_client_name" : "toyertech-validator"
									},
									"run_list": [ "recipe[chef-client::config]", "recipe[chef-client::service]" ]
								},
								"mode"  : "000644",
								"owner" : "root",
								"group" : "root"
							},
							"/etc/chef/roles.json" : {
								"content" : {
									"run_list": [ "role[linux]" ]
								},
								"mode"  : "000644",
								"owner" : "root",
								"group" : "root"
							},
							"/home/ubuntu/.s3cfg" : {
								"content" : { "Fn::Join" : ["", [
									"[default]\n",
									"access_key = ", { "Ref" : "HostKeys" }, "\n",
									"secret_key = ", {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]}, "\n",
									"use_https = True\n"
								]]},
								"mode"   : "000644",
								"owner"  : "ubuntu",
								"group"  : "ubuntu"
							},
							"/var/lib/gems/1.8/gems/ohai-0.6.4/lib/ohai/plugins/cfn.rb" : {
								"source" : "https://s3.amazonaws.com/cloudformation-examples/cfn.rb",
								"mode"   : "000644",
								"owner"  : "root",
								"group"  : "root"
							}
						}
					}
				}
			}
		},
		"DBChefClientWaitHandle" : {
			"Type" : "AWS::CloudFormation::WaitConditionHandle"
		},
		"DBChefClientWaitCondition" : {
			"Type" : "AWS::CloudFormation::WaitCondition",
			"DependsOn" : "DBServer",
			"Properties" : {
				"Handle"  : { "Ref" : "DBChefClientWaitHandle" },
				"Timeout" : "1200"
			}
		},
		"DBSecurityGroup" : {
			"Type" : "AWS::EC2::SecurityGroup",
			"Properties" : {
				"SecurityGroupIngress" : [
					{
						"FromPort" : "22",
						"CidrIp" : "0.0.0.0/0",
						"ToPort" : "22",
						"IpProtocol" : "tcp"
					},
					{
						"IpProtocol" : "tcp",
						"FromPort" : "3306",
						"ToPort" : "3306",
						"SourceSecurityGroupName" : { "Ref" : "WebServerSecurityGroup" }
					}
				],
				"GroupDescription": "MySQL access from web servers and SSH access to the server"
			}
		},
		"DBServerEIP" : {
			"Type" : "AWS::EC2::EIP",
			"Properties" : {
				"InstanceId" : { "Ref" : "DBServer" }
			}
		},
		"WebServerGroup" : {
			"Type": "AWS::AutoScaling::AutoScalingGroup",
			"DependsOn" : "WebServerLaunchConfig",
			"Properties" : {
				"AvailabilityZones" : { "Fn::GetAZs" : { "Ref" : "AWS::Region" } },
				"DesiredCapacity" : { "Ref": "WebServerDefaultGroupSize" },
				"LaunchConfigurationName": { "Ref" : "WebServerLaunchConfig" },
				"LoadBalancerNames" : [ { "Ref": "WebServerELB" } ],
				"MaxSize" : "4",
				"MinSize" : "1",
				"NotificationConfiguration" : {
					"TopicARN" : { "Ref" : "WebsitesAlarmTopic" },
					"NotificationTypes" : [ "autoscaling:EC2_INSTANCE_LAUNCH",
											"autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
											"autoscaling:EC2_INSTANCE_TERMINATE", 
											"autoscaling:EC2_INSTANCE_TERMINATE_ERROR"]
				}          
			}
		},
		"WebServerLaunchConfig" : {
			"Type": "AWS::AutoScaling::LaunchConfiguration",
			"DependsOn" : "WebChefClientWaitHandle",
			"Properties" : {
				"SecurityGroups" : [ { "Ref": "WebServerSecurityGroup" } ],
				"ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "WebServerInstanceType" }, "Arch" ] } ] },
				"KeyName" : { "Ref" : "WebServerKeyName" }, 
				"InstanceType" : { "Ref" : "WebServerInstanceType" },
				"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
					"#!/bin/bash -v\n",
					"function error_exit\n",
					"{\n",
					"  cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WebChefClientWaitHandle" }, "'\n",
					"  exit 1\n",
					"}\n",
					"apt-get -y install python-setuptools\n",
					"easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-1.0-6.tar.gz\n",
					"apt-get update\n",
					"cfn-init --region ", { "Ref" : "AWS::Region" },
					"    -s ", { "Ref" : "AWS::StackName" }, " -r DBServer ",
					"         --access-key ", { "Ref" : "HostKeys" },
					"         --secret-key ", {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]},
					"         --region     ", { "Ref" : "AWS::Region" }, " || error_exit 'Failed to run cfn-init'\n",
					"# Fixup path and links for the bootstrap script\n",
					"export PATH=$PATH:/var/lib/gems/1.8/bin\n",
					"# Bootstrap chef\n",
					"chef-solo -c /etc/chef/solo.rb -j /etc/chef/chef.json -r http://s3.amazonaws.com/chef-solo/bootstrap-latest.tar.gz  > /tmp/chef_solo.log 2>&1 || error_exit 'Failed to bootstrap chef client'\n",
					"# Fixup the server URL in client.rb\n",
					"s3cmd -c /home/ubuntu/.s3cfg get s3://", { "Ref" : "ChefServerPrivateKeyBucket" }, "/", { "Ref" : "ChefServerPrivateKeyLocation" }, " /etc/chef/validation.pem > /tmp/get_validation_key.log 2>&1 || error_exit 'Failed to get Chef Server validation key'\n",
					"sed -i 's|http://localhost:4000|", { "Ref" : "ChefServerURL" }, "|g' /etc/chef/client.rb\n",
					"chef-client -j /etc/chef/roles.json > /tmp/initialize_client.log 2>&1 || error_exit 'Failed to initialize host via chef client' \n",
					"# If all went well, signal success\n",
					"cfn-signal -e $? -r 'Chef Server configuration' '", { "Ref" : "WebChefClientWaitHandle" }, "'\n"
				]]}}
			},
			"Metadata" : {
				"AWS::CloudFormation::Init" : {
					"config" : {
						"packages" : {
							"rubygems" : {
								"chef" : [],
								"ohai" : ["0.6.4"]
							},
							"apt" : {
								"ruby"            : [],
								"ruby-dev"        : [],
								"libopenssl-ruby" : [],
								"rdoc"            : [],
								"ri"              : [],
								"irb"             : [],
								"build-essential" : [],
								"wget"            : [],
								"ssl-cert"        : [],
								"rubygems"        : [],
								"s3cmd"           : []
							}
						},
						"files" : {
							"/etc/chef/solo.rb" : {
								"content" : { "Fn::Join" : ["\n", [
									"file_cache_path \"/tmp/chef-solo\"",
									"cookbook_path \"/tmp/chef-solo/cookbooks\""
								]]},
								"mode"  : "000644",
								"owner" : "root",
								"group" : "root"
							},
							"/etc/chef/chef.json" : {
								"content" : {
									"chef_client": {
										"server_url": { "Ref" : "ChefServerURL" },
										"validation_client_name" : "toyertech-validator"
									},
									"run_list": [ "recipe[chef-client::config]", "recipe[chef-client::service]" ]
								},
								"mode"  : "000644",
								"owner" : "root",
								"group" : "root"
							},
							"/etc/chef/roles.json" : {
								"content" : {
									"run_list": [ "role[linux]" ]
								},
								"mode"  : "000644",
								"owner" : "root",
								"group" : "root"
							},
							"/home/ubuntu/.s3cfg" : {
								"content" : { "Fn::Join" : ["", [
									"[default]\n",
									"access_key = ", { "Ref" : "HostKeys" }, "\n",
									"secret_key = ", {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]}, "\n",
									"use_https = True\n"
								]]},
								"mode"   : "000644",
								"owner"  : "ubuntu",
								"group"  : "ubuntu"
							},
							"/var/lib/gems/1.8/gems/ohai-0.6.4/lib/ohai/plugins/cfn.rb" : {
								"source" : "https://s3.amazonaws.com/cloudformation-examples/cfn.rb",
								"mode"   : "000644",
								"owner"  : "root",
								"group"  : "root"
							}
						}
					}
				}
			}
		},
		"WebChefClientWaitHandle" : {
			"Type" : "AWS::CloudFormation::WaitConditionHandle",
			"DependsOn" : "DBChefClientWaitCondition"
		},
		"WebChefClientWaitCondition" : {
			"Type" : "AWS::CloudFormation::WaitCondition",
			"DependsOn" : "WebServerGroup",
			"Properties" : {
				"Handle"  : { "Ref" : "WebChefClientWaitHandle" },
				"Timeout" : "1200"
			}
		},
		"WebServerTrigger" : {
			"Type" : "AWS::AutoScaling::Trigger",
			"Properties" : {
				"MetricName" : "Latency",
				"Namespace" : "AWS/ELB",
				"Statistic" : "Average",
				"Period" : "60",
				"UpperBreachScaleIncrement" : "1",
				"LowerBreachScaleIncrement" : "-1",
				"AutoScalingGroupName" : { "Ref" : "WebServerGroup" },
				"BreachDuration" : "180",
				"UpperThreshold" : "10",
				"LowerThreshold" : "5",
				"Dimensions" : [ { "Name": "LoadBalancerName", "Value": { "Ref": "WebServerELB" } } ]
			}
		},
		"WebServerSecurityGroup" : {
			"Type": "AWS::EC2::SecurityGroup",
			"Properties" : {
				"SecurityGroupIngress" : [
					{
						"FromPort" : "22",
						"CidrIp" : "0.0.0.0/0",
						"ToPort" : "22",
						"IpProtocol" : "tcp"
					},
					{
						"IpProtocol" : "tcp",
						"FromPort" : "80",
						"ToPort" : "80",
						"SourceSecurityGroupOwnerId" : { "Fn::GetAtt" : [ "WebServerELB", "SourceSecurityGroup.OwnerAlias" ] },
						"SourceSecurityGroupName" : { "Fn::GetAtt" : [ "WebServerELB", "SourceSecurityGroup.GroupName" ] }
					}
				],
				"GroupDescription": "HTTP and SSH access to the server"
			}
		},
		"WebServerELB": {
			"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
			"Properties": {
				"Listeners": [
					{
						"InstancePort": "80",
						"Protocol": "HTTP",
						"LoadBalancerPort": "80"
					}
				],
				"HealthCheck" : {
					"HealthyThreshold" : "3",
					"Timeout" : "5",
					"Interval" : "9",
					"UnhealthyThreshold" : "3",
					"Target" : "HTTP:80/index.html"
				},
				"AvailabilityZones": {
					"Fn::GetAZs": {
						"Ref": "AWS::Region"
					}
				}
			}
		},
		"WebsitesAlarmTopic": {
			"Type": "AWS::SNS::Topic",
			"Properties": {
				"Subscription": [
					{
						"Endpoint": { "Ref": "NotificationEmailAddress" },
						"Protocol": "email"
					}
				]
			}
		},
		"DBServerCPUAlarmHigh" : {
			"Type" : "AWS::CloudWatch::Alarm",
			"Properties" : {
				"EvaluationPeriods": "2",
				"Statistic" : "Average",
				"Threshold" : "50",
				"AlarmDescription" : "Alarm if Database Server CPU too high or metric disappears indicating instance is down",
				"Period" : "60",
				"AlarmActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Namespace" : "AWS/EC2",
				"InsufficientDataActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Dimensions" : [ { "Name" : "InstanceId", "Value" : { "Ref" : "DBServer" } } ],
				"ComparisonOperator" : "GreaterThanThreshold",
				"MetricName" : "CPUUtilization"
			}
		},
		"WebServerCPUAlarmHigh" : {
			"Type" : "AWS::CloudWatch::Alarm",
			"Properties" : {
				"EvaluationPeriods": "3",
				"Statistic" : "Average",
				"Threshold" : "50",
				"AlarmDescription" : "Alarm if a Website Server CPU too high or metric disappears indicating instance is down",
				"Period" : "60",
				"AlarmActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Namespace" : "AWS/EC2",
				"InsufficientDataActions" : [ { "Ref": "WebsitesAlarmTopic" } ],        
				"Dimensions" : [ { "Name" : "AutoScalingGroupName", "Value" : { "Ref": "WebServerGroup" } } ],
				"ComparisonOperator": "GreaterThanThreshold",
				"MetricName": "CPUUtilization"
			}
		},
		"TooManyUnhealthyWebServerHostsAlarm": {
			"Type" : "AWS::CloudWatch::Alarm",
			"Properties" : {
				"EvaluationPeriods" : "1",
				"Statistic" : "Average",
				"Threshold" : "0",
				"AlarmDescription" : "Alarm if there are too many unhealthy web server hosts.",
				"Period" : "60",
				"AlarmActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Namespace" : "AWS/ELB",
				"InsufficientDataActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Dimensions" : [ { "Name": "LoadBalancerName", "Value": { "Ref": "WebServerELB" } } ],
				"ComparisonOperator" : "GreaterThanThreshold",
				"MetricName" : "UnHealthyHostCount"
			}
		},
		"WebServerRequestLatencyAlarmHigh": {
			"Type" : "AWS::CloudWatch::Alarm",
			"Properties" : {
				"EvaluationPeriods" : "2",
				"Statistic" : "Average",
				"Threshold" : "10",
				"AlarmDescription" : "Alarm if there aren't any requests coming through",
				"Period" : "60",
				"AlarmActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Namespace" : "AWS/ELB",
				"InsufficientDataActions" : [ { "Ref": "WebsitesAlarmTopic" } ],
				"Dimensions" : [ { "Name": "LoadBalancerName", "Value": { "Ref": "WebServerELB" } } ],
				"ComparisonOperator" : "GreaterThanThreshold",
				"MetricName" : "Latency"
			}
		}
	},
	"Outputs" : {
		"WebServerELBURL" : {
			"Description" : "URL of the web server ELB",
			"Value" :  { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt" : [ "WebServerELB", "DNSName" ]}]]}
		},
		"DBServerURL" : {
			"Description" : "URL of the DB server URL",
			"Value" :  { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt" : [ "DBServer", "PublicDnsName" ]}]]}
		},
		"DBServerIP" : {
			"Description" : "URL of the sample website",
			"Value" :  { "Ref" : "DBServerEIP" }
		}
	}
}