CloudFormation使って負荷試験「fullbokにしてやんぜ！」

## やりたいこと
* CloudFormationテンプレートを実行するだけでテストシナリオを実行するためのMaster（Windows）とSlave（Amazon Linux）が構築されます。(後々CentOSに変わりますw)  
* そのため **単一のJMeterマシンではかけられないような負荷を簡単にかけることが出来ます。**


![fullbok.001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/97564/54edac42-34ec-7b6f-06ea-7da82c8415c7.jpeg)





## classmethod様のfullbokを使う
https://github.com/classmethod-aws/fullbok

## 参考資料
http://dev.classmethod.jp/cloud/aws/aws-cfn-advent-calendar-2013-fullbok/
http://dev.classmethod.jp/study_meeting/cm-regrowth-2014-fullbok/



## 1.cloudformation準備
* s3に [fullbok](https://github.com/classmethod-aws/fullbok)からテンプレートを追加

## 2.実行するjenkinsの準備
実行するjobを作成

```
## Jenkins shell
#!/bin/bash -xv

set -eu

# power user
export AWS_ACCESS_KEY_ID=xxxxxxxxxxx
export AWS_SECRET_ACCESS_xxxxxxxxxxxxxxxxxx

export AWS_DEFAULT_REGION=ap-northeast-1


aws cloudformation create-stack --stack-name gozuqi-fullbok \
	--template-url https://s3-ap-northeast-1.amazonaws.com/fullbok/fullbok.template \
	--parameters \
	ParameterKey=AvailabilityZone,ParameterValue=ap-northeast-1a \
	ParameterKey=KeyName,ParameterValue=local.pem \
	ParameterKey=MasterInstanceAMI,ParameterValue=ami-ff435e91 \
	ParameterKey=MasterInstanceType,ParameterValue=t2.medium \
	ParameterKey=SlaveCapacity,ParameterValue=2 \
	ParameterKey=SlaveInstanceType,ParameterValue=c3.large \
	ParameterKey=SlaveSpotPrice,ParameterValue=0.5 \
	ParameterKey=SSHFrom,ParameterValue=0.0.0.0/0 \
	--capabilities CAPABILITY_IAM

aws cloudformation wait stack-create-complete --stack-name gozuqi-fullbok
```

## 3.実行
ん？ 動かない。。。。
unboundのインストールに失敗しているようだ。。。
調べてみると、
http://kiq.biz/news/post175.html
みたいなようだ。
ならAmazonLinuxってCentOSだしCentOSで動くようにレシピを修正

## できあがったレシピがこちら

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description" : "fullbok - JMeter cluster CloudFormation template file.",
  "Parameters": {
    "KeyName": {
      "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "64",
      "AllowedPattern": "[-_ a-zA-Z0-9]*",
      "ConstraintDescription": "can contain only alphanumeric characters, spaces, dashes and underscores."
    },
    "AvailabilityZone": {
      "Default" : "ap-northeast-1a",
      "Description" : "Availability zone of Jmeter subnet.",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "64",
      "AllowedPattern": "[-_ a-zA-Z0-9]*"
    },
    "SSHFrom" : {
      "Default" : "0.0.0.0/0",
      "Description" : "Lockdown SSH/RDP access to the bastion host (default can be accessed from anywhere)",
      "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 CIDR range of the form x.x.x.x/x."
    },
    "MasterInstanceAMI" : {
      "Description" : "AMI ID of Master instance (Microsoft Windows Server 2012 RTM 64-bit)",
      "Type" : "String",
      "MinLength": "12",
      "MaxLength": "12",
      "AllowedPattern" : "ami-[a-zA-Z0-9]*"
    },
    "MasterInstanceType": {
      "Default": "m1.medium",
      "Description": "JMeter master EC2 instance type",
      "Type": "String",
      "ConstraintDescription": "must be a valid EC2 instance type."
    },
    "SlaveInstanceType": {
      "Default": "m1.small",
      "Description": "JMeter slave EC2 instance type",
      "Type": "String",
      "ConstraintDescription": "must be a valid EC2 instance type."
    },
    "SlaveCapacity" : {
      "Default" : "2",
      "Description" : "Number of EC2 instances to launch for the jmeter slave.",
      "Type" : "Number",
      "MinValue": "1"
    },
    "SlaveSpotPrice" : {
      "Default" : "0",
      "Description" : "Spot price for the jmeter slave.",
      "Type" : "Number"
    }
  },
  "Mappings": {
    "AWSAmazonLinuxAMI": {
      "us-east-1":      { "name":"Virginia",   "64": "ami-35792c5c" , "64HVM" : "ami-69792c00" },
      "us-west-2":      { "name":"Oregon",     "64": "ami-d03ea1e0" , "64HVM" : "ami-e43ea1d4" },
      "us-west-1":      { "name":"California", "64": "ami-687b4f2d" , "64HVM" : "ami-4e7b4f0b" },
      "eu-west-1":      { "name":"Ireland",    "64": "ami-149f7863" , "64HVM" : "ami-209f7857" },
      "ap-southeast-1": { "name":"Singapole",  "64": "ami-14f2b946" , "64HVM" : "ami-6af2b938" },
      "ap-southeast-2": { "name":"Sydney",     "64": "ami-a148d59b" , "64HVM" : "ami-a948d593" },
      "ap-northeast-1": { "name":"Tokyo",      "64": "ami-507f9631" , "64HVM" : "ami-600ae001" },
      "sa-east-1":      { "name":"SaoPaulo",   "64": "ami-9f6ec982" , "64HVM" : "ami-9d6ec980" }
    },
    "StackConfig" : {
      "VPC"               : { "CIDR" : "10.0.0.0/16" },
      "JMeterSubnet"      : { "CIDR" : "10.0.0.0/24" },
      "JMeter"            : { "URL": "http://archive.apache.org/dist/jmeter/binaries/apache-jmeter-2.10.tgz" }
    },
    "SlaveInstanceSetting": {
        "m3.medium":     { "type": "64HVM" , "HEAP": "-Xms2G -Xmx2G"     ,"NEW": "-XX:NewSize=512m -XX:MaxNewSize=1G"   },
        "m3.large":      { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m3.xlarge":     { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m3.2xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "r3.large":      { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "r3.xlarge":     { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "r3.2xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "r3.4xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "r3.8xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m1.small":      { "type": "64"    , "HEAP": "-Xms1G -Xmx1G"     ,"NEW": "-XX:NewSize=256m -XX:MaxNewSize=512m" },
        "m1.medium":     { "type": "64"    , "HEAP": "-Xms2G -Xmx2G"     ,"NEW": "-XX:NewSize=512m -XX:MaxNewSize=1G"   },
        "m1.large":      { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m1.xlarge":     { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "c3.large":      { "type": "64HVM" , "HEAP": "-Xms2G -Xmx2G"     ,"NEW": "-XX:NewSize=512m -XX:MaxNewSize=1G"   },
        "c3.xlarge":     { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "c3.2xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "c3.4xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "c3.8xlarge":    { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "c1.medium":     { "type": "64"    , "HEAP": "-Xms1G -Xmx1G"     ,"NEW": "-XX:NewSize=256m -XX:MaxNewSize=512m" },
        "c1.xlarge":     { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "cc2.8xlarge":   { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m2.xlarge":     { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m2.2xlarge":    { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "m2.4xlarge":    { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "cr1.8xlarge":   { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "hi1.4xlarge":   { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "hs1.8xlarge":   { "type": "64HVM" , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "t1.micro":      { "type": "64"    , "HEAP": "-Xms256M -Xmx256M" ,"NEW": "-XX:NewSize=128m -XX:MaxNewSize=128m" },
        "g2.2xlarge":    { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   },
        "cg1.4xlarge":   { "type": "64"    , "HEAP": "-Xms4G -Xmx4G"     ,"NEW": "-XX:NewSize=1G   -XX:MaxNewSize=2G"   }
    }
  },
  "Conditions" : {
    "UseSpotInstance" : { "Fn::Not": [ { "Fn::Equals" : [ {"Ref" : "SlaveSpotPrice"}, "0" ] } ] }
  },
  "Resources": {
    "PowerUserRole" : {
      "Type" : "AWS::IAM::Role",
      "Properties" : {
        "AssumeRolePolicyDocument" : {
          "Statement": [ {
            "Effect": "Allow",
              "Principal": {
                "Service": [ "ec2.amazonaws.com" ]
              },
              "Action": [ "sts:AssumeRole" ]
          } ]
        },
        "Path" : "/",
        "Policies" :[ {
          "PolicyName" : "PowerUserPolicy",
          "PolicyDocument" : {
            "Statement": [ {
              "Sid": "PowerUserStmt",
              "Effect": "Allow",
              "NotAction": "iam:*",
              "Resource": "*"
            } ]
          }
        }]
      }
    },
    "PowerUserProfile" : {
      "Type" : "AWS::IAM::InstanceProfile",
      "Properties" : {
        "Path": "/",
        "Roles" : [ { "Ref" : "PowerUserRole" } ]
      }
    },

    "VPC" : {
      "Type" : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock" : { "Fn::FindInMap" : [ "StackConfig", "VPC", "CIDR" ]},
        "EnableDnsHostnames" : "true",
        "InstanceTenancy" : "default",
        "Tags" : [
          {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId" } },
          {"Key" : "Network", "Value" : "Public" }
        ]
      }
    },
    "InternetGateway" : {
      "Type" : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags" : [
          {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId" } },
          {"Key" : "Network", "Value" : "Public" }
        ]
      }
    },
    "AttachGateway" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
      "Properties" : {
        "VpcId" : {"Ref" : "VPC"},
        "InternetGatewayId" : {"Ref" : "InternetGateway"}
      }
    },

    "PublicRouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
      "DependsOn" : "AttachGateway",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "Tags" : [
          {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} },
          {"Key" : "Network", "Value" : "Public" }
        ]
      }
    },
    "PublicRoute" : {
      "Type" : "AWS::EC2::Route",
      "DependsOn" : "AttachGateway",
      "Properties" : {
        "RouteTableId" : { "Ref" : "PublicRouteTable" },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "GatewayId" : { "Ref" : "InternetGateway" }
      }
    },

    "JMeterSubnet": {
      "Type": "AWS::EC2::Subnet",
      "DependsOn" : "AttachGateway",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "AvailabilityZone": { "Ref": "AvailabilityZone" },
        "CidrBlock": { "Fn::FindInMap" : [ "StackConfig", "JMeterSubnet", "CIDR" ]},
        "Tags" : [
          {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId" } },
          {"Key" : "Network", "Value" : "Public" }
        ]
      }
    },
    "JMeterSubnetRouteTableAssociation" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "JMeterSubnet" },
        "RouteTableId" : { "Ref" : "PublicRouteTable" }
      }
    },

    "VPCDefaultSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "GroupDescription" : "Allow all communications in VPC",
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : { "Fn::FindInMap" : [ "StackConfig", "VPC", "CIDR" ]} },
          { "IpProtocol" : "udp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : { "Fn::FindInMap" : [ "StackConfig", "VPC", "CIDR" ]} },
          { "IpProtocol" : "icmp", "FromPort" : "-1", "ToPort" : "-1",  "CidrIp" : { "Fn::FindInMap" : [ "StackConfig", "VPC", "CIDR" ]} }
        ]
      }
    },
    "SSHSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "GroupDescription" : "Enable SSH access via port 22",
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp", "FromPort" : "22",  "ToPort" : "22",  "CidrIp" : { "Ref" : "SSHFrom" }}
        ]
      }
    },
    "RDPSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "GroupDescription" : "Enable RDP",
        "SecurityGroupIngress" : [
          {"IpProtocol" : "tcp", "FromPort" : "3389", "ToPort" : "3389", "CidrIp" : { "Ref" : "SSHFrom" }}
        ]
      }
    },

    "SlaveFleet" : {
      "Type" : "AWS::AutoScaling::AutoScalingGroup",
      "Properties" : {
        "AvailabilityZones" : [
          { "Ref" : "AvailabilityZone" }
        ],
        "VPCZoneIdentifier" : [
          { "Ref" : "JMeterSubnet" }
        ],
        "LaunchConfigurationName" : { "Ref" : "SlaveInstanceLaunchConfig"  },
        "MinSize" : { "Ref" : "SlaveCapacity" },
        "MaxSize" : { "Ref" : "SlaveCapacity" },
        "DesiredCapacity" : { "Ref" : "SlaveCapacity" },
        "Tags" : [
          { "Key" : "Name", "Value" : "JMeterSlave", "PropagateAtLaunch" : "true" },
          { "Key" : "Network", "Value" : "Public", "PropagateAtLaunch" : "true" }
        ]
      }
    },
    "SlaveInstanceLaunchConfig"  : {
      "Type" : "AWS::AutoScaling::LaunchConfiguration",
      "Properties" : {
        "InstanceType": { "Ref" : "SlaveInstanceType" },
        "SpotPrice" : { "Fn::If" : [ "UseSpotInstance", {"Ref" : "SlaveSpotPrice"},  { "Ref" : "AWS::NoValue" } ] },
        "KeyName": { "Ref" : "KeyName" },
        "ImageId": { "Fn::FindInMap": [ "AWSAmazonLinuxAMI", { "Ref": "AWS::Region" }, { "Fn::FindInMap": [ "SlaveInstanceSetting", { "Ref": "SlaveInstanceType" }, "type" ]} ]},
        "SecurityGroups": [
          { "Ref" : "SSHSecurityGroup" },
          { "Ref" : "VPCDefaultSecurityGroup" }
        ],
        "IamInstanceProfile": { "Ref" : "PowerUserProfile" },
        "InstanceMonitoring" : "false",
        "AssociatePublicIpAddress" : "true",
        "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
          "#! /bin/bash -v\n",
          "yum update -y\n",
          "yum install -y epel-release python-pip wget gcc make zlib-devel openssl-devel\n",
          
            
          "python -V\n",
          "export PATH=$PATH:/opt/aws/bin\n",
          "export PATH\n",
          
          
          "# Install aws-cli\n",
          "pip install pystache\n",
          "pip install argparse\n",
          "pip install python-daemon\n",
          "pip install requests\n",
          "pip install awscli\n",
          "yum -y update\n",
          "cd /opt\n",
          "curl -O https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
          "tar -xvpf aws-cfn-bootstrap-latest.tar.gz\n",
          "cd aws-cfn-bootstrap-1.4/\n",
          "python setup.py build\n",
          "python setup.py install\n",
          "chmod 775 /opt/aws-cfn-bootstrap-1.4/bin/*\n",
          "cd /opt\n",
          "mkdir aws\n",
          "cd aws\n",
          "ln -s /opt/aws-cfn-bootstrap-1.4/bin /opt/aws/\n",
          
          
          "# Continuous Release Repository setting for unbound\n",
          "yum install -y java-1.7.0-openjdk\n",
          "yum install -y java-1.7.0-openjdk-devel\n", 
          "# Install local dns resolver\n",
          "yum install -y unbound\n",
          "sed -i 's/val-permissive-mode: .*/val-permissive-mode: yes/g' /etc/unbound/unbound.conf\n",
          "echo -e 'forward-zone:\n\tname: ", { "Ref": "AWS::Region" } ,".compute.internal\n\tforward-addr: 10.0.0.2' >> /etc/unbound/unbound.conf\n",
          "service unbound start\n",
          "chkconfig unbound on\n",
          "sed -i 's/PEERDNS=yes/PEERDNS=no/g' /etc/sysconfig/network-scripts/ifcfg-eth0\n",
          "sed -i 's/nameserver .*/nameserver 127.0.0.1/g' /etc/resolv.conf\n",

          "# Helper function\n",
          "function error_exit\n",
          "{\n",
          "  /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", { "Ref" : "SlaveWaitHandle" }, "'\n",
          "  exit 1\n",
          "}\n",

          "# Install packages\n",
          "/opt/aws/bin/cfn-init -v -s ", { "Ref" : "AWS::StackId" }, " -r SlaveInstanceLaunchConfig ",
          "    --region ", { "Ref" : "AWS::Region" }, "\n",

          "sysctl -p\n",

          "echo \"/opt/apache-jmeter-2.10/bin/jmeter-server | logger -p daemon.info &\" >>/etc/rc.local\n",
          "sh /opt/apache-jmeter-2.10/bin/jmeter -s -n &",

          "# All is well so signal success\n",
          "/opt/aws/bin/cfn-signal -e $? -r \"SlaveInstanceLaunchConfig setup complete\" '", { "Ref" : "SlaveWaitHandle" }, "'\n"
        ]]}}
      },
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "config" : {
            "packages" : {
              "yum" : {
              }
            },
            "sources" : {
              "/opt" : { "Fn::FindInMap" : [ "StackConfig", "JMeter", "URL" ]}
            },
            "files" : {
              "/etc/security/limits.conf" : {
                "content" : { "Fn::Join" : ["", [
                  "# /etc/security/limits.conf\n",
                  "#\n",
                  "#Each line describes a limit for a user in the form:\n",
                  "#\n",
                  "#\n",
                  "#<domain>      <type>  <item>         <value>\n",
                  "#\n",
                  "\n",
                  "#*               soft    core            0\n",
                  "#*               hard    rss             10000\n",
                  "#@student        hard    nproc           20\n",
                  "#@faculty        soft    nproc           20\n",
                  "#@faculty        hard    nproc           50\n",
                  "#ftp             hard    nproc           0\n",
                  "#@student        -       maxlogins       4\n",
                  "\n",
                  "\n",
                  "*                hard   nofile           65536\n",
                  "*                soft   nofile           65536\n",
                  "*                hard   nproc            8192\n",
                  "*                soft   nproc            8192\n",
                  "\n",
                  "\n",
                  "\n",
                  "# End of file\n"
                ]]},
                "mode"  : "000644",
                "owner" : "root",
                "group" : "root"
              }
            },
            "commands" : {
              "00-use_java7" : {
                "command" : "alternatives --set java /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java"
              },
              "01-create_hosts_entry-on_boot" : {
                "command" : "echo \"`curl -s curl http://169.254.169.254/latest/meta-data/local-ipv4` `hostname`\" >>/etc/hosts",
                "test" : "test ! -f .create_hosts_entry-semaphore"
              },
              "02-signal_startup_complete" : {
                "command" : "touch .create_hosts_entry-semaphore"
              },
              "03-set_listen_address" : {
                "command" : { "Fn::Join" : ["", [
                  "sed -i -e \"s/^#RMI_HOST_DEF=-Djava.rmi.server.hostname=.*$/RMI_HOST_DEF=-Djava.rmi.server.hostname=$(curl -s http://169.254.169.254/latest/meta-data/local-hostname)/\" /opt/apache-jmeter-2.10/bin/jmeter-server"
                ]]}
              },
              "03-set_heap" : {
                "command" : { "Fn::Join" : ["", [
                  "sed -i -e \"s/^HEAP/#HEAP/ \" -e \" /^#HEAP/i HEAP=\\\"" , { "Fn::FindInMap": [ "SlaveInstanceSetting", { "Ref": "SlaveInstanceType" }, "HEAP" ]} , "\\\" \" /opt/apache-jmeter-2.10/bin/jmeter"
                ]]}
              },
              "03-set_new" : {
                "command" : { "Fn::Join" : ["", [
                  "sed -i -e \"s/^NEW/#NEW/ \" -e \" /^#NEW/i NEW=\\\"" , { "Fn::FindInMap": [ "SlaveInstanceSetting", { "Ref": "SlaveInstanceType" }, "NEW" ]} , "\\\" \" /opt/apache-jmeter-2.10/bin/jmeter"
                ]]}
              },
              "03-add_disabling_dns_caching" : {
                "command" : "sed -i -e \" /^java/i JVM_ARGS=\\\"\\$JVM_ARGS -Dsun.net.inetaddr.ttl=0\\\"\" /opt/apache-jmeter-2.10/bin/jmeter"
              },
              "04-tcp_param_tcp_tw_recycle" : {
                "command" : "echo \"net.ipv4.tcp_tw_recycle = 1\" >> /etc/sysctl.conf"
              },
              "04-tcp_param_tcp_fin_timeout" : {
                "command" : "echo \"net.ipv4.tcp_fin_timeout = 1\" >> /etc/sysctl.conf"
              },
              "05-nproc_limit" : {
                "command" : "sed -i -e \"s/ nproc     1024/ nproc     8192/\" /etc/security/limits.d/90-nproc.conf"
              }
            }
          }
        }
      }
    },
    "SlaveWaitHandle" : {
      "Type" : "AWS::CloudFormation::WaitConditionHandle"
    },
    "SlaveWaitCondition" : {
      "Type" : "AWS::CloudFormation::WaitCondition",
      "DependsOn" : "SlaveFleet",
      "Properties" : {
        "Handle" : {"Ref" : "SlaveWaitHandle"},
        "Timeout" : "3600",
        "Count"   : { "Ref" : "SlaveCapacity" }
      }
    },

    "MasterInstance": {
      "Type" : "AWS::EC2::Instance",
      "Properties": {
        "InstanceType" : { "Ref" : "MasterInstanceType" },
        "ImageId" : { "Ref": "MasterInstanceAMI" },
        "NetworkInterfaces": [{
          "DeviceIndex" : "0",
          "AssociatePublicIpAddress" : true,
          "DeleteOnTermination" : true,
          "SubnetId" : { "Ref" : "JMeterSubnet" },
          "GroupSet" : [
            { "Ref" : "RDPSecurityGroup" },
            { "Ref" : "VPCDefaultSecurityGroup" }
          ]
        }],
        "KeyName" : { "Ref" : "KeyName" },
        "IamInstanceProfile": { "Ref" : "PowerUserProfile" },
        "Monitoring" : "false",
        "Tags" : [
          { "Key" : "Name", "Value" : "JMeterMaster" },
          { "Key" : "Network", "Value" : "Public" }
        ],
        "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
          "<powershell>\n",
          "cfn-init.exe -v -s ", { "Ref" : "AWS::StackId" }, " -r MasterInstance -c create --region ", { "Ref" : "AWS::Region" }, "\n",
          "cfn-signal.exe -e $lastexitcode ", { "Fn::Base64" : { "Ref" : "MasterWaitHandle" }}, "\n",
          "</powershell>"
        ]]}}
      },
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "configSets" : {
            "create" : [
              "setup_cfn_hup",
              "place_scripts",
              "install_jdk",
              "disable_firewall",
              "install_jmeter",
              "setup_jmeter"
            ],
            "update" : [
              "setup_jmeter"
            ]
          },
          "setup_cfn_hup" : {
            "files" : {
              "c:\\cfn\\cfn-hup.conf" : {
                "content" : { "Fn::Join" : ["", [
                  "[main]\n",
                  "stack=", { "Ref" : "AWS::StackId" }, "\n",
                  "region=", { "Ref" : "AWS::Region" }, "\n"
                ]]}
              },
              "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf" : {
                "content": { "Fn::Join" : ["", [
                  "[cfn-auto-reloader-hook]\n",
                  "triggers=post.update\n",
                  "path=Resources.MasterInstance.Metadata.AWS::CloudFormation::Init\n",
                  "action=cfn-init.exe -v -s ", { "Ref" : "AWS::StackId" }, " -r MasterInstance -c update --region ", { "Ref" : "AWS::Region" }, "\n"
                ]]}
              }
            },
            "services" : {
              "windows" : {
                "cfn-hup" : {
                  "enabled" : "true",
                  "ensureRunning" : "true",
                  "files" : [
                    "c:\\cfn\\cfn-hup.conf",
                    "c:\\cfn\\hooks.d\\cfn-auto-reloader.conf"
                  ]
                }
              }
            }
          },
          "place_scripts" : {
            "files" : {
              "c:\\install_jdk.ps1" : {
                "content": { "Fn::Join" : ["", [
                  "$client = new-object System.Net.WebClient\n",
                  "$client.Headers.add(\"Cookie\", \"oraclelicense=accept-securebackup-cookie\")\n",
                  "$client.DownloadFile(\"http://download.oracle.com/otn-pub/java/jdk/7u45-b18/jdk-7u45-windows-x64.exe\", \"C:\\Users\\Administrator\\jdk.exe\")\n",
                  "C:\\Users\\Administrator\\jdk.exe /s /lang=1041 INSTALLDIR=C:\\java\\jdk1.7.45\n",
                  "$env:PATH = $env:PATH + \";C:\\java\\jdk1.7.45\\bin\""
                ]]}
              },
              "c:\\create_shortcut.ps1" : {
                "content": { "Fn::Join" : ["", [
                  "$WshShell = New-Object -comObject WScript.Shell\n",
                  "$shortcut = $WshShell.CreateShortcut(\"C:\\Users\\Administrator\\Desktop\\JMeter.lnk\")\n",
                  "$shortcut.TargetPath = \"C:\\jmeter\\apache-jmeter-2.10\\bin\\jmeterw.cmd\"\n",
                  "$shortcut.WorkingDirectory = \"C:\\jmeter\\apache-jmeter-2.10\\bin\"\n",
                  "$shortcut.Save()\n"
                ]]}
              },
              "c:\\setupjmetercluster.ps1" : {
                "content": { "Fn::Join" : ["", [
                  "Set-DefaultAWSRegion ", { "Ref" : "AWS::Region" }, "\n",
                  "$slaves = (Get-ASAutoScalingInstance",
                  " | ? {$_.AutoScalingGroupName -eq \"", { "Ref" : "SlaveFleet" }, "\"}",
                  " | select -ExpandProperty InstanceId",
                  " | Get-EC2Instance",
                  " | select -ExpandProperty RunningInstance",
                  " | select -ExpandProperty PrivateIpAddress) -join ','\n",
                  "(Get-Content \"C:\\jmeter\\apache-jmeter-2.10\\bin\\jmeter.properties\")",
                  " | Foreach-Object {$_ -replace '^remote_hosts=.*$', (\"remote_hosts=\" + $slaves)}",
                  " | Set-Content \"C:\\jmeter\\apache-jmeter-2.10\\bin\\jmeter.properties\""
                ]]}
              },
              "c:\\updatejmeter.ps1" : {
                "content": { "Fn::Join" : ["", [
                  "(Get-Content \"C:\\jmeter\\apache-jmeter-2.10\\bin\\jmeter.bat\") ",
                  " | Foreach-Object {$_ -replace '^set HEAP=.*$', (\"set HEAP=" , { "Fn::FindInMap": [ "SlaveInstanceSetting", { "Ref": "SlaveInstanceType" }, "HEAP" ]} , "\")} ",
                  " | Foreach-Object {$_ -replace '^set NEW=.*$', (\"set NEW=" , { "Fn::FindInMap": [ "SlaveInstanceSetting", { "Ref": "SlaveInstanceType" }, "NEW" ]} , "\")} ",
                  " | Set-Content \"C:\\jmeter\\apache-jmeter-2.10\\bin\\jmeter.bat\""
                ]]}
              }
            }
          },
          "install_jdk" : {
            "commands" : {
              "install_jdk" : {
                "command" : "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File c:\\install_jdk.ps1"
              }
            }
          },
          "disable_firewall" : {
            "commands" : {
              "disable_firewall" : {
                "command" : "netsh advfirewall set allprofiles state off"
              }
            }
          },
          "install_jmeter" : {
            "sources" : {
              "c:\\jmeter" : { "Fn::FindInMap" : [ "StackConfig", "JMeter", "URL" ]}
            },
            "commands" : {
              "create_shortcut" : {
                "command" : "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File c:\\create_shortcut.ps1"
              }
            }
          },
          "setup_jmeter" : {
            "commands" : {
              "setup_jmeter_cluster" : {
                "command" : "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File c:\\setupjmetercluster.ps1"
              }
            }
          },
          "setup_jmeter_jvm" : {
            "commands" : {
              "setup_jmeter_jvm_param" : {
                "command" : "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File c:\\updatejmeter.ps1"
              }
            }
          }
        }
      }
    },
    "MasterWaitHandle" : {
      "Type" : "AWS::CloudFormation::WaitConditionHandle"
    },
    "MasterWaitCondition" : {
      "Type" : "AWS::CloudFormation::WaitCondition",
      "DependsOn" : "MasterInstance",
      "Properties" : {
        "Handle" : {"Ref" : "MasterWaitHandle"},
        "Timeout" : "3600"
      }
    }
  },

  "Outputs": {
    "SSHToSlaveInstances": {
      "Value": { "Fn::Join":["", [
        "ssh -i /path/to/", { "Ref": "KeyName" }, ".pem ec2-user@<ip/hostname>"
      ]]},
      "Description": "SSH command to connect to the JMeter slave instances."
    },
    "RDPToMasterInstance": {
      "Value": { "Fn::Join":["", [
        "remotedesktop://", { "Fn::GetAtt" : [ "MasterInstance", "PublicDnsName" ]}
      ]]},
      "Description": "RDP connection to the JMeter master."
    }
  }
}
```

## 再度実行
* Status CREATE_COMPLETE  
出来上がったみたいですね。


## 準備
自分はELBにぶら下がった集団ガイルに対して負荷をかけたかったのでELBの設定。
Masterはwindowsなのでmac使ってる人はRemoteDesctopかなんかでログインしてテスト書いて実行


## Test実行
windowsで実行
slaveからテストサーバに流れてるか確認する


## 掃除用Jenkins
環境削除jobを作成

```
#!/bin/bash -xv
set -eu
export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxx
export AWS_DEFAULT_REGION=ap-northeast-1
aws cloudformation delete-stack --stack-name gozuqi-fullbok
aws cloudformation wait stack-delete-complete --stack-name gozuqi-fullbok

```