{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Description" : "AWS CloudFormation Sample Template Insoshi_Multi_AZ: Insoshi is an open source social networking platform in Ruby on Rails. This template installs a highly-available, scalable Insoshi deployment using a multi-az Amazon RDS database instance for storage and using an S3 bucket for photos and thumbnails. It demonstrates using the AWS CloudFormation bootstrap scripts to install the packages and files necessary to deploy Insoshi, Rails, MySQL and all dependent packages at instance launch time. **WARNING** This template creates one or more Amazon EC2 instances, an S3 bucket, and Amazon RDS database instance and other AWS resources. You will be billed for the AWS resources used if you create a stack from this template.",

  "Parameters" : {

    "KeyName": {
      "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "255",
      "AllowedPattern" : "[\\x20-\\x7E]*",
      "ConstraintDescription" : "can contain only ASCII characters."
    },

    "DBName": {
      "Default": "insoshi",
      "Description" : "MySQL database name",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "64",
      "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
      "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
    },

    "DBUsername": {
      "NoEcho": "true",
      "Description" : "Username for MySQL database access",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "16",
      "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
      "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
    },

    "DBPassword": {
      "NoEcho": "true",
      "Description" : "Password MySQL database access",
      "Type": "String",
      "MinLength": "8",
      "MaxLength": "41",
      "AllowedPattern" : "[a-zA-Z0-9]*",
      "ConstraintDescription" : "must contain only alphanumeric characters."
    },


    "MultiAZDatabase": {
      "Default": "true",
      "Description" : "Create a multi-AZ MySQL Amazon RDS database instance",
      "Type": "String",
      "AllowedValues" : [ "true", "false" ],
      "ConstraintDescription" : "must be either true or false."
    },

    "WebServerCapacity": {
      "Default": "2",
      "Description" : "The initial number of WebServer instances",
      "Type": "Number",
      "MinValue": "1",
      "MaxValue": "5",
      "ConstraintDescription" : "must be between 1 and 5 EC2 instances."
    },

    "InstanceType" : {
      "Description" : "WebServer EC2 instance type",
      "Type" : "String",
      "Default" : "m1.small",
      "AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","m3.xlarge","m3.2xlarge","c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
      "ConstraintDescription" : "must be a valid EC2 instance type."
    },

    "DBClass" : {
      "Default" : "db.m1.small",
      "Description" : "Database instance class",
      "Type" : "String",
      "AllowedValues" : [ "db.m1.small", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge" ],
      "ConstraintDescription" : "must select a valid database instance type."
    },

    "DBAllocatedStorage" : {
      "Default": "5",
      "Description" : "The size of the database (Gb)",
      "Type": "Number",
      "MinValue": "5",
      "MaxValue": "1024",
      "ConstraintDescription" : "must be between 5 and 1024Gb."
    },
    "SSHLocation" : {
      "Description" : "The IP address range that can be used to SSH to the EC2 instances",
      "Type": "String",
      "MinLength": "9",
      "MaxLength": "18",
      "Default": "0.0.0.0/0",
      "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
      "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
    }
  },

  "Mappings" : {
    "AWSInstanceType2Arch" : {
      "t1.micro"    : { "Arch" : "64" },
      "m1.small"    : { "Arch" : "64" },
      "m1.medium"   : { "Arch" : "64" },
      "m1.large"    : { "Arch" : "64" },
      "m1.xlarge"   : { "Arch" : "64" },
      "m2.xlarge"   : { "Arch" : "64" },
      "m2.2xlarge"  : { "Arch" : "64" },
      "m2.4xlarge"  : { "Arch" : "64" },
      "m3.xlarge"   : { "Arch" : "64" },
      "m3.2xlarge"  : { "Arch" : "64" },
      "c1.medium"   : { "Arch" : "64" },
      "c1.xlarge"   : { "Arch" : "64" },
      "cc1.4xlarge" : { "Arch" : "64HVM" },
      "cc2.8xlarge" : { "Arch" : "64HVM" },
      "cg1.4xlarge" : { "Arch" : "64HVM" }
    },

    "AWSRegionArch2AMI" : {
      "us-east-1"      : { "32" : "ami-31814f58", "64" : "ami-1b814f72", "64HVM" : "ami-0da96764" },
      "us-west-2"      : { "32" : "ami-38fe7308", "64" : "ami-30fe7300", "64HVM" : "NOT_YET_SUPPORTED" },
      "us-west-1"      : { "32" : "ami-11d68a54", "64" : "ami-1bd68a5e", "64HVM" : "NOT_YET_SUPPORTED" },
      "eu-west-1"      : { "32" : "ami-973b06e3", "64" : "ami-953b06e1", "64HVM" : "NOT_YET_SUPPORTED" },
      "ap-southeast-1" : { "32" : "ami-b4b0cae6", "64" : "ami-beb0caec", "64HVM" : "NOT_YET_SUPPORTED" },
      "ap-southeast-2" : { "32" : "ami-b3990e89", "64" : "ami-bd990e87", "64HVM" : "NOT_YET_SUPPORTED" },
      "ap-northeast-1" : { "32" : "ami-0644f007", "64" : "ami-0a44f00b", "64HVM" : "NOT_YET_SUPPORTED" },
      "sa-east-1"      : { "32" : "ami-3e3be423", "64" : "ami-3c3be421", "64HVM" : "NOT_YET_SUPPORTED" }
    }
  },

  "Resources" : {

    "S3User" : {
      "Type" : "AWS::IAM::User"
    },

    "S3Keys" : {
      "Type" : "AWS::IAM::AccessKey",
      "Properties" : {
        "UserName" : {"Ref": "S3User"}
      }
    },

    "S3Content" : {
      "Type" : "AWS::S3::Bucket",
      "Properties" : {
        "AccessControl" : "PublicRead"
      }
    },

    "BucketPolicy" : {
      "Type" : "AWS::S3::BucketPolicy",
      "Properties" : {
        "PolicyDocument": {
          "Version"      : "2008-10-17",
          "Id"           : "WriteContentPolicy",
          "Statement"    : [{
            "Sid"        : "WriteAccess",
            "Action"     : ["s3:GetObject","s3:PutObject", "s3:PutObjectACL"],
            "Effect"     : "Allow",
            "Resource"   : { "Fn::Join" : ["", ["arn:aws:s3:::", {"Ref" : "S3Content"} , "/*"]]},
            "Principal"  : { "AWS": {"Fn::GetAtt" : ["S3User", "Arn"]} }
          }]
        },
        "Bucket" : {"Ref" : "S3Content"}
      }
    },

    "ElasticLoadBalancer" : {
      "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
      "Metadata" : {
        "Comment" : "Configure the Load Balancer with a simple health check and cookie-based stickiness"
      },
      "Properties" : {
        "AvailabilityZones" : { "Fn::GetAZs" : "" },
        "LBCookieStickinessPolicy" : [ {
          "PolicyName" : "CookieBasedPolicy",
          "CookieExpirationPeriod" : "30"
        } ],
        "Listeners" : [ {
          "LoadBalancerPort" : "80",
          "InstancePort" : "80",
          "Protocol" : "HTTP",
          "PolicyNames" : [ "CookieBasedPolicy" ]
        } ],
        "HealthCheck" : {
          "Target" : "HTTP:80/",
          "HealthyThreshold" : "2",
          "UnhealthyThreshold" : "5",
          "Interval" : "10",
          "Timeout" : "5"
        }
      }
    },

    "WebServerGroup" : {
      "Type" : "AWS::AutoScaling::AutoScalingGroup",
      "Properties" : {
        "AvailabilityZones" : { "Fn::GetAZs" : "" },
        "LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
        "MinSize" : "1",
        "MaxSize" : "5",
        "DesiredCapacity" : { "Ref" : "WebServerCapacity" },
        "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ]
      }
    },

    "LaunchConfig": {
      "Type" : "AWS::AutoScaling::LaunchConfiguration",
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "configSets" : { "full_install" : [ "install_prereqs", "setup_rubygems", "install_insoshi" ] },

          "install_prereqs" : {
            "packages" : {
              "yum" : {
                "git"               : [],
                "gcc-c++"           : [],
                "make"              : [],
                "ruby-devel"        : [],
                "ruby18-rdoc"       : [],
                "rubygems"          : [],
                "mysql"             : [],
                "mysql-devel"       : [],
                "mysql-libs"        : [],
                "libjpeg-devel"     : [],
                "libpng-devel"      : [],
                "libtiff-devel"     : [],
                "freetype-devel"    : [],
                "ghostscript-devel" : [],
                "ImageMagick-devel" : []
              }
            }
          },

          "setup_rubygems" : {
            "commands" : {
              "01_install_version_142" : {
                "command" : "gem update --system 1.4.2 &> /var/log/gem_update.log"
              }
            }
          },

          "install_insoshi" : {
            "packages" : {
              "rubygems" : {
                "mysql"           : ["2.9.1"],
                "rake"            : ["0.8.7"],
                "rails"           : ["2.3.15"],
                "chronic"         : ["0.9.1"],
                "rdiscount"       : ["2.0.7.3"],
                "rmagick"         : ["2.13.2"],
                "aws-s3"          : []
              }
            },

            "sources" : {
              "/home/ec2-user/sphinx"      : "http://sphinxsearch.com/files/sphinx-2.0.6-release.tar.gz",
              "/home/ec2-user/insoshi"     : "http://github.com/insoshi/insoshi/tarball/master"
            },

            "files" : {

              "/home/ec2-user/insoshi/config/database.yml" : {
                "content" : { "Fn::Join" : ["", [
                  "development:\n",
                  "  adapter: mysql\n",
                  "  database: ", { "Ref" : "DBName" }, "\n",
                  "  host: ", {"Fn::GetAtt" : ["DBInstance", "Endpoint.Address"]}, "\n",
                  "  username: ", { "Ref" : "DBUsername" }, "\n",
                  "  password: ", { "Ref" : "DBPassword" }, "\n",
                  "  timeout: 5000\n"
                  ]]},
                "mode"  : "000600",
                "owner" : "root",
                "group" : "root"
              },


              "/home/ec2-user/insoshi/config/amazon_s3.yml" : {
                "content" : { "Fn::Join" : ["", [
                  "development:\n",
                  "  bucket_name: ", { "Ref" : "S3Content" }, "\n",
                  "  access_key_id: ", { "Ref" : "S3Keys" }, "\n",
                  "  secret_access_key: ", {"Fn::GetAtt": ["S3Keys", "SecretAccessKey"]}, "\n"
                  ]]},
                "mode"  : "000600",
                "owner" : "root",
                "group" : "root"
              },

              "/home/ec2-user/build_sphinx" : {
                "content" : { "Fn::Join" : ["", [
                  "# Build search indexer\n",
                  "./configure\n",
                  "make\n",
                  "make install\n"
                  ]]},
                "mode"  : "000700",
                "owner" : "root",
                "group" : "root"
              },

              "/home/ec2-user/configure_insoshi" : {
                "content" : { "Fn::Join" : ["", [
                  "# Install Insoshi with search indexer configured\n",
                  "export PATH=$PATH:/usr/local/bin\n",
                  "script/install\n",
                  "rake ultrasphinx:configure\n",
                  "rake ultrasphinx:index\n",
                  "rake ultrasphinx:daemon:start\n",
                  "# Fixup configuration to use S3 for photos and thumbnails\n",
                  "sed -i 's/file_system/s3/' app/models/photo.rb\n",
                  "sed -i 's/file_system/s3/' app/models/thumbnail.rb\n",
                  "script/server -d -p 80\n"
                  ]]},
                "mode"  : "000700",
                "owner" : "root",
                "group" : "root"
              }
            },

            "commands" : {
              "01_build_sphinx" : {
                "command" : "/home/ec2-user/build_sphinx &> /var/log/build_sphinx.log",
                "cwd" : "/home/ec2-user/sphinx/sphinx-2.0.6-release"
              },
              "02_configure_insoshi" : {
                "command" : "/home/ec2-user/configure_insoshi &> /var/log/configure_insoshi.log",
                "cwd" : "/home/ec2-user/insoshi"
              },
              "03_cleanup" : {
                "command" : "rm -Rf build_sphinx configure_insoshi sphinx",
                "cwd" : "/home/ec2-user"
              }
            }
          }
        }
      },
      "Properties": {
        "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
                          { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
        "InstanceType"   : { "Ref" : "InstanceType" },
        "SecurityGroups" : [ {"Ref" : "WebServerSecurityGroup"} ],
        "KeyName"        : { "Ref" : "KeyName" },
        "UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
          "#!/bin/bash -v\n",
          "yum update -y aws-cfn-bootstrap\n",

          "# Install packages\n",
          "/opt/aws/bin/cfn-init --stack ", { "Ref" : "AWS::StackId" },
          "                      --resource LaunchConfig ",
          "                      --configsets full_install ",
          "                      --region ", { "Ref" : "AWS::Region" }, "\n",


          "# Signal completion\n",
          "/opt/aws/bin/cfn-signal -e $? -r \"Failed to run cfn-init\" '", { "Ref" : "WaitHandle" }, "'\n"
        ]]}}
      }
    },

    "WaitHandle" : {
      "Type" : "AWS::CloudFormation::WaitConditionHandle"
    },

    "WaitCondition" : {
      "Type" : "AWS::CloudFormation::WaitCondition",
      "DependsOn" : "WebServerGroup",
      "Properties" : {
        "Handle" : {"Ref" : "WaitHandle"},
        "Timeout" : "1500"
      }
    },

    "DBInstance" : {
      "Type": "AWS::RDS::DBInstance",
      "Properties": {
        "DBName"            : { "Ref" : "DBName" },
        "Engine"            : "MySQL",
        "MasterUsername"    : { "Ref" : "DBUsername" },
        "MultiAZ"           : { "Ref" : "MultiAZDatabase" },
        "DBInstanceClass"   : { "Ref" : "DBClass" },
        "DBSecurityGroups"  : [{ "Ref" : "DBSecurityGroup" }],
        "AllocatedStorage"  : { "Ref" : "DBAllocatedStorage" },
        "MasterUserPassword": { "Ref" : "DBPassword" }
      }
    },

    "DBSecurityGroup": {
      "Type": "AWS::RDS::DBSecurityGroup",
      "Properties": {
        "DBSecurityGroupIngress": { "EC2SecurityGroupName": { "Ref": "WebServerSecurityGroup"} },
        "GroupDescription"      : "Frontend Access"
      }
    },

    "WebServerSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Enable HTTP access via port 80, the indexer port plus SSH access",
        "SecurityGroupIngress" : [
          {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupOwnerId" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias"]},"SourceSecurityGroupName" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.GroupName"]}},
          {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"}}
        ]
      }
    }
  },

  "Outputs" : {
    "WebsiteURL" : {
      "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ]}]] },
      "Description" : "URL for Insoshi"
    }
  }
}
