{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "MongoDB Replica Set Stack 20130621-01", "Parameters" : { "KeyName" : { "Description" :"Name of an existing EC2 KeyPair to enable SSH access", "Type" : "String" }, "ClientIpAddress" : { "Description" : "IP accessing SSH and MongoDB ports (in CIDR format, e.g.: 126.23.2.1/24)", "Type" :"String", "MinLength":"9", "MaxLength":"18", "AllowedPattern":"^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/(\\d{1,2})$", "ConstraintDescription":"Must be a valid IP in CIDR notation .", "Default" :"0.0.0.0/24" }, "InstanceType" : { "Type" : "String", "Default" : "m1.large", "AllowedValues" : [ "m1.small", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "c1.xlarge", "cc1.4xlarge" ], "Description" : "EC2 instance type (e.g.: m1.large, m1.xlarge, m2.xlarge)" }, "VolumeSize" : { "Description" : "Volume size for each EBS volume", "Type" : "Number", "Default" : "10" }, "ReplicaSetName" : { "Description" : "Name for the MongoDB Replica Set", "Type" : "String", "Default" : "ReplicaSet" } }, "Mappings" : { "InstanceTypeArch" : { "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" }, "c1.medium" : { "Arch" : "64" }, "c1.xlarge" : { "Arch" : "64" }, "cc1.4xlarge" : { "Arch" : "64HVM" } }, "RegionImageZone" : { "us-east-1" : { "64" : "ami-a73758ce", "64HVM" : "ami-a73758ce" }, "us-west-2" : { "64" : "ami-0358ce33", "64HVM" : "ami-d75bcde7" }, "us-west-1" : { "64" : "ami-3ffed17a", "64HVM" : "ami-47fed102" }, "eu-west-1" : { "64" : "ami-c7c0d6b3", "64HVM" : "ami-d1c0d6a5" }, "ap-southeast-1": { "64" : "ami-fade91a8", "64HVM" : "ami-18de914a" }, "ap-southeast-2": { "64" : "ami-39b23d38", "64HVM" : "ami-2db33c2c" }, "ap-northeast-1": { "64" : "ami-d16bfbeb", "64HVM" : "ami-876bfbbd" }, "sa-east-1" : { "64" : "ami-5253894f", "64HVM" : "ami-38538925" } }, "RegionZone" : { "us-east-1" : {"AZ1" : "us-east-1a", "AZ2" : "us-east-1b", "AZ3" : "us-east-1b", "AZ4" : "us-east-1d", "AZ5" : "us-east-1e"}, "us-west-1" : {"AZ1" : "us-west-1a", "AZ2" : "us-west-1b", "AZ3" : "us-west-1c"}, "us-west-2" : {"AZ1" : "us-west-2a", "AZ2" : "us-west-2b"}, "eu-west-1" : {"AZ1" : "eu-west-1a", "AZ2" : "eu-west-1b", "AZ3" : "eu-west-1c"}, "ap-southeast-1": {"AZ1" : "ap-southeast-1a", "AZ2" : "ap-southeast-1b"}, "ap-southeast-2": {"AZ1" : "ap-southeast-2a", "AZ2" : "ap-southeast-2b"}, "ap-northeast-1": {"AZ1" : "ap-northeast-1a", "AZ2" : "ap-northeast-1b"}, "sa-east-1" : {"AZ1" : "sa-east-1a", "AZ2" : "sa-east-1b"} } }, "Resources" : { "MongoSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "ReplicaSet Security Group", "SecurityGroupIngress" : [ {"IpProtocol" : "tcp", "FromPort" : "27017", "ToPort" : "27017", "CidrIp" : { "Ref": "ClientIpAddress" } }, {"IpProtocol" : "tcp", "FromPort" : "28017", "ToPort" : "28017", "CidrIp" : { "Ref": "ClientIpAddress" } }, {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref": "ClientIpAddress" } } ] } }, "MongoSecurityGroupIngress" : { "Type" : "AWS::EC2::SecurityGroupIngress", "Properties" : { "GroupName" : { "Ref" : "MongoSecurityGroup" }, "IpProtocol" : "tcp", "FromPort" : "27017", "ToPort" : "27017", "SourceSecurityGroupName" : { "Ref" : "MongoSecurityGroup" } } }, "StatusIngress" : { "Type" : "AWS::EC2::SecurityGroupIngress", "Properties" : { "GroupName" : { "Ref" : "MongoSecurityGroup" }, "IpProtocol" : "tcp", "FromPort" : "28017", "ToPort" : "28017", "SourceSecurityGroupName" : { "Ref" : "MongoSecurityGroup" } } }, "CfnUser" : { "Type" : "AWS::IAM::User", "Properties" : { "Path": "/", "Policies": [ { "PolicyName": "root", "PolicyDocument": { "Statement": [ { "Effect":"Allow", "Action":"cloudformation:DescribeStackResource", "Resource":"*" } ] } } ] } }, "AccessKey" : { "Type" : "AWS::IAM::AccessKey", "Properties" : { "UserName" : { "Ref" : "CfnUser" } } }, "ReplicaSetMember1" : { "Type" : "AWS::CloudFormation::Stack", "Properties" : { "TemplateURL" : "https://s3-eu-west-1.amazonaws.com/mongodb-clngs/MongoNodeCLNGS-2.cftemplate", "Parameters" : { "KeyName" : { "Ref" : "KeyName" }, "InstanceType" : { "Ref" : "InstanceType" }, "VolumeSize" : { "Ref" : "VolumeSize" }, "AccessKeyId" : { "Ref" : "AccessKey" }, "SecretAccessKey" : {"Fn::GetAtt": ["AccessKey", "SecretAccessKey"]}, "ReplicaSetName" : { "Ref" : "ReplicaSetName" }, "SecurityGroupName" : { "Ref" : "MongoSecurityGroup" }, "InstanceZone" : { "Fn::FindInMap" : ["RegionZone", { "Ref" : "AWS::Region"}, "AZ1"] } } } }, "ReplicaSetMember2" : { "Type" : "AWS::CloudFormation::Stack", "DependsOn" : "ReplicaSetMember1", "Properties" : { "TemplateURL" : "https://s3-eu-west-1.amazonaws.com/mongodb-clngs/MongoNodeCLNGS-2.cftemplate", "Parameters" : { "KeyName" : { "Ref" : "KeyName" }, "InstanceType" : { "Ref" : "InstanceType" }, "VolumeSize" : { "Ref" : "VolumeSize" }, "AccessKeyId" : { "Ref" : "AccessKey" }, "SecretAccessKey" : {"Fn::GetAtt": ["AccessKey", "SecretAccessKey"]}, "ReplicaSetName" : { "Ref" : "ReplicaSetName" }, "SecurityGroupName" : { "Ref" : "MongoSecurityGroup" }, "InstanceZone" : { "Fn::FindInMap" : ["RegionZone", { "Ref" : "AWS::Region"}, "AZ3"] } } } }, "MongoInstanceP1" : { "Type" : "AWS::EC2::Instance", "Metadata" : { "AWS::CloudFormation::Init" : { "config" : { "packages" : { "yum" : { "mdadm" : [], "sysstat" : [], "xfsprogs" : [], "ntp" : [] } }, "files" : { "/etc/yum.repos.d/10gen.repo" : { "content" : { "Fn::Join" : ["", [ "[10gen]\n", "name=10gen Repository\n", "baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64\n", "gpgcheck=0\n" ] ] }, "mode" : "000644", "owner" : "root", "group" : "root" }, "/etc/rc.local" : { "content" : { "Fn::Join" : ["", [ "#!/bin/sh\n", "#\n", "# This script will be executed *after* all the other init scripts.\n", "# You can put your own initialization stuff in here if you don't\n", "# want to do the full Sys V style init stuff.\n", "# \n", "# See http://docs.mongodb.org/manual/faq/diagnostics/#does-tcp-keepalive-time-affect-sharded-clusters-and-replica-sets\n", "echo 300 > /proc/sys/net/ipv4/tcp_keepalive_time\n", "touch /var/lock/subsys/local\n" ] ] }, "mode" : "000644", "owner" : "root", "group" : "root" } }, "services" : { "sysvinit" : { "ntpd" : { "enabled" : "true", "ensureRunning" : "true" } } } } } }, "DependsOn" : "ReplicaSetMember2", "Properties" : { "InstanceType" : { "Ref" : "InstanceType" }, "ImageId" : { "Fn::FindInMap" : [ "RegionImageZone", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "InstanceTypeArch", { "Ref" : "InstanceType" }, "Arch" ] } ] }, "Tags" : [{ "Key" : "Name", "Value" : "MongoPrimary" }], "SecurityGroups" : [ { "Ref" : "MongoSecurityGroup" } ], "KeyName" : { "Ref" : "KeyName" }, "AvailabilityZone" : { "Fn::FindInMap" : ["RegionZone", { "Ref" : "AWS::Region"}, "AZ1"] }, "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash\n", "# Sending all output to /tmp/install.log\n", "exec 2> /tmp/install.log\n", "exec >> /tmp/install.log\n", "# CloudFormation: Updating scripts\n", "#\n", "yum update -y aws-cfn-bootstrap\n", "# Error reporting helper function\n", "function error_exit\n", "{\n", "/opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", { "Ref" : "WaitHandleP1" }, "'\n", "exit 1\n", "}\n", "# CloudFormation: Initialize\n", "/opt/aws/bin/cfn-init -v -s ", { "Ref" : "AWS::StackName" }, " -r MongoInstanceP1", " --access-key ", { "Ref" : "AccessKey" }, " --secret-key ", {"Fn::GetAtt": ["AccessKey", "SecretAccessKey"]}, " --region ", { "Ref" : "AWS::Region" }, " > /tmp/cfn-init.log 2>&1 || error_exit $(> /etc/fstab\n", "/dev/vg0/mongo /var/lib/mongo xfs noatime,nodiratime,logbufs=8,nodev,noexec 0 0\n", "END\n", "#\n", "# Mounting all new resources\n", "#\n", "mount -av\n", "#\n", "# Minimum performance tuning: Set limits for mongod user\n", "#\n", "cat << END > /etc/security/limits.conf\n", "mongod soft nofile 64000\n", "mongod soft nproc 32000\n", "mongos soft nofile 64000\n", "mongos soft nproc 32000\n", "END\n", "#\n", "# Updating RPMs and Installing MongoDB\n", "#\n", "yum update -y\n", "yum install mongo-10gen-server -y\n", "#\n", "# Create MongoDB config\n", "#\n", "cat << END > /etc/mongod.conf\n", "# mongod.conf\n", "dbpath=/var/lib/mongo\n", "logpath=/var/log/mongo/mongod.log\n", "logappend=true\n", "fork=true\n", "replSet=", {"Ref" : "ReplicaSetName"}, "\n", "# Enable webserver REST\n", "rest = true\n", "END\n", "#\n", "# Fixing mongod permission on /var/lib/mongo\n", "#\n", "chown -Rv mongod:mongod /var/lib/mongo\n", "#\n", "# Updating system config and starting MongoDB\n", "#\n", "chkconfig mongod on\n", "service mongod start\n", "#\n", "# Waiting until MongoDB is UP and Running...\n", "# Workaround to avoid comparison and therefor using parentheses in sentence\n", "while [ -z $(echo \"db.serverStatus()\" | mongo 127.0.0.1/test 2>&1 | awk ' /uptimeMillis/ { print $3}') ]; do echo -e \"Waiting to connect to mongod\n\"; sleep 10; done\n", "# Create replica set configuration on the PRIMARY\n", "/usr/bin/curl -s --fail http://169.254.169.254/latest/meta-data/public-hostname ; VPC=$? \n", "if [ \"$VPC\" -eq \"0\" ]; then MASTER=$(wget -O- -q http://169.254.169.254/latest/meta-data/public-hostname) \n", "# Since in Default VPC we do not have PublicHostName we use EC2 Internal IPV4 for PRIMARY to avoid rs.initiate() issues with EC2 Public IPV4.\n", "else MASTER=$(wget -O- -q http://169.254.169.254/latest/meta-data/local-ipv4); fi \n", "cat < /tmp/replicaSetConfigInit.js\n", "config = {_id: \"", { "Ref" : "ReplicaSetName" } ,"\", members : [", "{_id : 0, host:\"$MASTER:27017\"},", "{_id : 1, host:\"", { "Fn::GetAtt" : ["ReplicaSetMember1", "Outputs.ReplicaSetMemberName"] },":27017\"},", "{_id : 2, host:\"", { "Fn::GetAtt" : ["ReplicaSetMember2", "Outputs.ReplicaSetMemberName"] },":27017\"}", "]};\n", "rs.initiate(config);\n", "EOF\n", "/usr/bin/mongo /tmp/replicaSetConfigInit.js > /tmp/replica-setup.log\n", "# CLNGS UserData End\n", "# CloudFormation signal that setup is complete\n", "/opt/aws/bin/cfn-signal -e 0 -r \"MongoInstanceP1 setup complete\" '", { "Ref" : "WaitHandleP1" }, "'\n" ] ] } } } }, "MongoVolume1P1" : { "Type" : "AWS::EC2::Volume", "Properties" : { "Size" : { "Ref" : "VolumeSize" }, "Tags" : [{ "Key" : "Name", "Value" : "Mongo_P1_Volume" }], "AvailabilityZone" : { "Fn::GetAtt" : [ "MongoInstanceP1", "AvailabilityZone" ]} } }, "MongoVolume2P1" : { "Type" : "AWS::EC2::Volume", "Properties" : { "Size" : { "Ref" : "VolumeSize" }, "Tags" : [{ "Key" : "Name", "Value" : "Mongo_P1_Volume" }], "AvailabilityZone" : { "Fn::GetAtt" : [ "MongoInstanceP1", "AvailabilityZone" ]} } }, "MongoVolume3P1" : { "Type" : "AWS::EC2::Volume", "Properties" : { "Size" : { "Ref" : "VolumeSize" }, "Tags" : [{ "Key" : "Name", "Value" : "Mongo_P1_Volume" }], "AvailabilityZone" : { "Fn::GetAtt" : [ "MongoInstanceP1", "AvailabilityZone" ]} } }, "MongoVolume4P1" : { "Type" : "AWS::EC2::Volume", "Properties" : { "Size" : { "Ref" : "VolumeSize" }, "Tags" : [{ "Key" : "Name", "Value" : "Mongo_P1_Volumee" }], "AvailabilityZone" : { "Fn::GetAtt" : [ "MongoInstanceP1", "AvailabilityZone" ]} } }, "MongoVolumeMount1P1" : { "Type" : "AWS::EC2::VolumeAttachment", "Properties" : { "InstanceId" : { "Ref" : "MongoInstanceP1" }, "VolumeId" : { "Ref" : "MongoVolume1P1" }, "Device" : "/dev/sdh1" } }, "MongoVolumeMount2P1" : { "Type" : "AWS::EC2::VolumeAttachment", "Properties" : { "InstanceId" : { "Ref" : "MongoInstanceP1" }, "VolumeId" : { "Ref" : "MongoVolume2P1" }, "Device" : "/dev/sdh2" } }, "MongoVolumeMount3P1" : { "Type" : "AWS::EC2::VolumeAttachment", "Properties" : { "InstanceId" : { "Ref" : "MongoInstanceP1" }, "VolumeId" : { "Ref" : "MongoVolume3P1" }, "Device" : "/dev/sdh3" } }, "MongoVolumeMount4P1" : { "Type" : "AWS::EC2::VolumeAttachment", "Properties" : { "InstanceId" : { "Ref" : "MongoInstanceP1" }, "VolumeId" : { "Ref" : "MongoVolume4P1" }, "Device" : "/dev/sdh4" } }, "WaitHandleP1" : { "Type" : "AWS::CloudFormation::WaitConditionHandle", "Properties" : {} }, "WaitConditionP1" : { "Type" : "AWS::CloudFormation::WaitCondition", "DependsOn" : "MongoInstanceP1", "Properties" : { "Handle" : { "Ref" : "WaitHandleP1" }, "Timeout" : "600" } } }, "Outputs" : { "ReplicaSetMemberName1" : { "Value" : { "Fn::GetAtt" : [ "MongoInstanceP1", "PublicDnsName" ] }, "Description" : "Public DNS name of the MongoDB Replica Set endpoint (node 1 : PRIMARY)" }, "ReplicaSetMemberName2" : { "Value" : { "Fn::GetAtt" : [ "ReplicaSetMember1", "Outputs.ReplicaSetMemberName" ] }, "Description" : "Public DNS name of the MongoDB Replica Set node 2" }, "ReplicaSetMemberName3" : { "Value" : { "Fn::GetAtt" : [ "ReplicaSetMember2", "Outputs.ReplicaSetMemberName" ] }, "Description" : "Public DNS name of the MongoDB Replica Set node 3" } } }