{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Description" : "Builds a S3 bucket, a VPC w/ 1 public subnet, an IGW, route tables, ACL, 2 EC2 instances, CodeDeploy and CodePipeline bits.",

  "Parameters" : {
    "KeyName" : {
      "Description" : "Name of an existing EC2 KeyPair for SSH access to the instances.",
      "Type" : "AWS::EC2::KeyPair::KeyName"
    },

    "AppName": {
      "Type" : "String",
      "Description" : "Name of the application.",
      "MinLength": "2",
      "MaxLength": "15",
      "Default" : "app-name",
      "AllowedPattern" : "[a-z0-9][-. a-z0-9]*",
      "ConstraintDescription": "Must be between 2 and 15 characters long, lowercase and may contain alphanumeric characters, hyphens (-), and dots (.), but must start with alphanumeric."
    },

    "AppSourceType": {
      "Type" : "String",
      "Default" : "S3",
      "AllowedValues" : ["S3", "GitHub"],
      "Description" : "Source of your application's code"
    },

    "S3ArtifactObject": {
      "Type" : "String",
      "Default" : "samples/latest/aws-codedeploy-sample-tomcat.zip",
      "Description" : "Application artfiact name in S3."
    },

    "S3ArtifactBucket": {
      "Type" : "String",
      "Default" : "aws-codedeploy-samples-us-east-1",
      "Description" : "Name of the bucket that the application artifact will be based in."
    },

    "GitHubUser":{
      "Type" : "String",
      "Default" : "aGitHubUser",
      "Description" : "Your GitHub username"
    },

    "GitHubToken":{
      "Type" : "String",
      "NoEcho" : "true",
      "Default" : "oauthtoken1234",
      "Description" : "Go to https://github.com/settings/tokens to create/find a token for your account"
    },

    "GitHubRepoName":{
      "Type" : "String",
      "Default" : "aws-codedeploy-sample-tomcat",
      "Description" : "Name of the repository that your application is in. Not the Url."
    },

    "GitHubBranchName":{
      "Type" : "String",
      "Default" : "master",
      "Description" : "Name of the branch that you want to pull from. Not the Url."
    },

    "YourIP": {
      "Description": "IP address to connect to SSH from. Check http://checkip.amazonaws.com/ to find yours.",
      "Type": "String",
      "Default" : "999.999.999.999/32",
      "MinLength": "10",
      "MaxLength": "18",
      "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."
    }
  },

  "Metadata" : {
    "AWS::CloudFormation::Interface" : {
      "ParameterGroups" : [
        {
          "Label" : { "default" : "Application" },
          "Parameters" : [ "AppName", "AppSourceType" ]
        },
        {
          "Label" : { "default" : "Application Source - S3" },
          "Parameters" : [ "S3ArtifactBucket", "S3ArtifactObject"]
        },
        {
          "Label" : { "default" : "Application Source - GitHub" },
          "Parameters" : [ "GitHubUser", "GitHubToken", "GitHubRepoName", "GitHubBranchName"]
        },
        {
          "Label" : { "default" : "SSH & HTTP Configuration" },
          "Parameters" : [ "KeyName", "YourIP" ]
        }
      ]
    }
  },

  "Conditions" : {
    "S3AsSource" : {"Fn::Equals" : [{"Ref" : "AppSourceType"}, "S3"]},
    "GitHubAsSource" : {"Fn::Equals" : [{"Ref" : "AppSourceType"}, "GitHub"]}
  },

  "Mappings" : {
    "VPCIpSpace" : {
      "us-east-1" : {"RANGE" : "10.42"},
      "us-west-2" : {"RANGE" : "10.43"}
    },

    "SubnetTypeIpRanges" : {
      "public" : {"RANGE" : "0.0/17"}
    },

    "publicSubnetConfig" : {
      "publicSubnet01" : { "CIDR" : "10.0/24" }
    },

    "instancesTypes" : {
      "Demo" : { "INST" : "t2.small" }
    },

    "AWSInstanceType2Virt": {
      "t2.micro": {"Virt": "HVM"},
      "t2.small": {"Virt": "HVM"},
      "t2.medium": {"Virt": "HVM"},
      "t2.large": {"Virt": "HVM"}
    },

    "AWSInstanceType2EBSOpt": {
      "t2.micro": {"EBSOpt": "false"},
      "t2.small": {"EBSOpt": "false"},
      "t2.medium": {"EBSOpt": "false"},
      "t2.large": {"EBSOpt": "false"}
    },

    "AWSRegionVirt2AMI": {
      "us-east-1": {"HVM": "ami-8fcee4e5"},
      "us-west-2": {"HVM": "ami-63b25203"}
    }
  },

  "Resources" : {
    "MyVPC" : {
      "Type" : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", "0.0/16"]]},
        "EnableDnsSupport" : "true",
        "EnableDnsHostnames" : "true",
        "Tags" : [
          {"Key" : "Name", "Value" : "CodeStarDemo-VPC" }
        ]
      }
    },

    "publicSubnet01" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", { "Fn::FindInMap" : [ "publicSubnetConfig", "publicSubnet01", "CIDR" ]}]]},
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }]},
        "Tags" : [
          {"Key" : "SubnetType", "Value" : "Public" },
          {"Key" : "Name", "Value" : "publicSubnet01" }
        ]
      }
    },
   
    "InternetGateway" : {
      "Type" : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags" : [
          {"Key" : "Name", "Value" : "DemoVPCIGW" }
        ]
      }
    },

    "AttachGateway" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
      "Properties" : {
         "VpcId" : { "Ref" : "MyVPC" },
         "InternetGatewayId" : { "Ref" : "InternetGateway" }
      }
    },

    "PublicRouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
      "Properties" : {
        "VpcId" : {"Ref" : "MyVPC"},
        "Tags" : [
          {"Key" : "Name", "Value" : "PublicRouteTable" }
        ]
      }
    },

    "PublicRoute" : {
      "Type" : "AWS::EC2::Route",
      "Properties" : {
        "RouteTableId" : { "Ref" : "PublicRouteTable" },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "GatewayId" : { "Ref" : "InternetGateway" }
      }
    },

    "PublicSubnetRTAssociation01" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "publicSubnet01" },
        "RouteTableId" : { "Ref" : "PublicRouteTable" }
      }
    },

    "PublicNetworkAcl" : {
      "Type" : "AWS::EC2::NetworkAcl",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "Tags" : [
          {"Key" : "Name", "Value" : "NetworkAcl" }
        ]
      }
    },

    "InboundPublicNAclEntry" : {
      "Type" : "AWS::EC2::NetworkAclEntry",
      "Properties" : {
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
        "RuleNumber" : "2000",
        "Protocol" : "-1",
        "RuleAction" : "allow",
        "Egress" : "false",
        "CidrBlock" : "0.0.0.0/0",
        "PortRange" : { "From" : "0", "To" : "65535" }
      }
    },

    "OutboundPublicNetworkAclEntry" : {
      "Type" : "AWS::EC2::NetworkAclEntry",
      "Properties" : {
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
        "RuleNumber" : "2000",
        "Protocol" : "-1",
        "RuleAction" : "allow",
        "Egress" : "true",
        "CidrBlock" : "0.0.0.0/0",
        "PortRange" : { "From" : "0", "To" : "65535" }
      }
    },

    "publicSubnetNetworkAclAssociation01" : {
      "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "publicSubnet01" },
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
      }
    },

    "S3Bucket": {
      "DeletionPolicy" : "Retain",
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName" : { "Fn::Join" : ["", [ "demo-", { "Ref": "AWS::Region" } , "-", {"Ref" : "AWS::AccountId"}, "-", {"Ref" : "AppName"} ]] },
        "VersioningConfiguration" : {
          "Status" : "Enabled"
        },
        "Tags" : [
          {"Key" : "Name", "Value" : "CodeStarDemo-S3Bucket" }
        ]
      }
    },

    "WebAppRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Sid": "",
              "Effect": "Allow",
              "Principal": {
                "Service": "ec2.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "ManagedPolicyArns" : [ "arn:aws:iam::aws:policy/AWSCodeDeployReadOnlyAccess", "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess" ],
        "Path": "/"
      }
    },

    "WebAppRolePolicies": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "BackendRole",
        "PolicyDocument": {
          "Statement": [
            {
              "Effect":"Allow",
              "Action":"cloudformation:DescribeStackResources",
              "Resource" : [
                { "Fn::Join" : ["", [ "arn:aws:cloudformation:", { "Ref" : "AWS::Region" }, ":", {"Ref":"AWS::AccountId"}, ":stack/", { "Ref": "AWS::StackName" }, "/*"]]}
              ]
            },
            {
              "Effect": "Allow",
              "Action": [
                "autoscaling:Describe*",
                "autoscaling:EnterStandby",
                "autoscaling:ExitStandby",
                "autoscaling:UpdateAutoScalingGroup"
              ],
              "Resource" : "*"
            },
            {
              "Effect": "Allow",
              "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceStatus"
              ],
              "Resource": "*"
            },
            {
              "Effect": "Allow",
              "Action": [
                "elasticloadbalancing:Describe*",
                "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                "elasticloadbalancing:RegisterInstancesWithLoadBalancer"
              ],
              "Resource" : "*"
            },
            {
              "Effect": "Allow",
              "Action": [
                "s3:Get*",
                "s3:List*"
              ],
              "Resource": [
                { "Fn::Join" : ["", [ "arn:aws:s3:::demo-", { "Ref": "AWS::Region" } , "-", {"Ref" : "AWS::AccountId"}, "-", {"Ref" : "AppName"} ]] },
                { "Fn::Join" : ["", [ "arn:aws:s3:::demo-", { "Ref": "AWS::Region" } , "-", {"Ref" : "AWS::AccountId"}, "-", {"Ref" : "AppName"}, "/*" ]] }
              ]
            }
          ]
        },
        "Roles": [{"Ref": "WebAppRole"}]
      }
    },

    "WebAppInstanceProfile": {
      "Type": "AWS::IAM::InstanceProfile",
      "Properties": {
        "Path": "/",
        "Roles": [{"Ref": "WebAppRole"}]
      }
    },

    "WebAppSG" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Enable HTTP access on port 80",
        "VpcId" : { "Ref" : "MyVPC" },
        "SecurityGroupIngress" : [ 
          { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", "0.0/16"]]}},
          { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"}
        ],
        "SecurityGroupEgress" : [
          { "IpProtocol" : "tcp", "FromPort" : "80",  "ToPort" : "80",  "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "udp", "FromPort" : "123", "ToPort" : "123", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "udp", "FromPort" : "9418", "ToPort" : "9418", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "icmp", "FromPort" : "-1",  "ToPort" : "-1",  "CidrIp" : "0.0.0.0/0" }
        ],
        "Tags" : [
          {"Key" : "Name", "Value" : "WebAppSG" }
        ]
      }
    },

    "DevWebApp01" : {
      "Type" : "AWS::EC2::Instance",
      "Properties": {
        "ImageId" : { "Fn::FindInMap" : [ "AWSRegionVirt2AMI", { "Ref" : "AWS::Region" }, {"Fn::FindInMap": ["AWSInstanceType2Virt", { "Fn::FindInMap" : [ "instancesTypes", "Demo", "INST" ]}, "Virt"]} ]},
        "InstanceType" : { "Fn::FindInMap" : [ "instancesTypes", "Demo", "INST" ]},
        "KeyName" : { "Ref" : "KeyName" },
        "IamInstanceProfile" : {"Ref":"WebAppInstanceProfile"},
        "EbsOptimized" : {"Fn::FindInMap": ["AWSInstanceType2EBSOpt", { "Fn::FindInMap" : [ "instancesTypes", "Demo", "INST" ]}, "EBSOpt"]},
        "NetworkInterfaces" : [{
          "SubnetId" : { "Ref" : "publicSubnet01" },
          "GroupSet" : [{ "Ref" : "WebAppSG" }],
          "AssociatePublicIpAddress" : "true",
          "DeviceIndex" : "0"
        }],
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [ "", [ "#!/bin/bash -ex\n",
                "yum install -y aws-cli\n",
                "cd /home/ec2-user/\n",
                "wget https://aws-codedeploy-",{ "Ref": "AWS::Region" },".s3.amazonaws.com/latest/codedeploy-agent.noarch.rpm\n",
                "yum -y install codedeploy-agent.noarch.rpm\n",
                "service codedeploy-agent start\n",
                "\n"
              ]
            ]
          }
        },
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-DevWebApp"]]}},
          {"Key" : "Name", "Value" : "DevWebApp01" }
        ]
      }
    },

    "ProdWebApp01" : {
      "Type" : "AWS::EC2::Instance",
      "Properties": {
        "ImageId" : { "Fn::FindInMap" : [ "AWSRegionVirt2AMI", { "Ref" : "AWS::Region" }, {"Fn::FindInMap": ["AWSInstanceType2Virt", { "Fn::FindInMap" : [ "instancesTypes", "Demo", "INST" ]}, "Virt"]} ]},
        "InstanceType" : { "Fn::FindInMap" : [ "instancesTypes", "Demo", "INST" ]},
        "KeyName" : { "Ref" : "KeyName" },
        "IamInstanceProfile" : {"Ref":"WebAppInstanceProfile"},
        "EbsOptimized" : {"Fn::FindInMap": ["AWSInstanceType2EBSOpt", { "Fn::FindInMap" : [ "instancesTypes", "Demo", "INST" ]}, "EBSOpt"]},
        "NetworkInterfaces" : [{
          "SubnetId" : { "Ref" : "publicSubnet01" },
          "GroupSet" : [{ "Ref" : "WebAppSG" }],
          "AssociatePublicIpAddress" : "true",
          "DeviceIndex" : "0"
        }],
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [ "", [ "#!/bin/bash -ex\n",
                "yum install -y aws-cli\n",
                "cd /home/ec2-user/\n",
                "wget https://aws-codedeploy-",{ "Ref": "AWS::Region" },".s3.amazonaws.com/latest/codedeploy-agent.noarch.rpm\n",
                "yum -y install codedeploy-agent.noarch.rpm\n",
                "service codedeploy-agent start\n",
                "\n"
              ]
            ]
          }
        },
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-ProdWebApp"]]}},
          {"Key" : "Name", "Value" : "ProdWebApp01" }
        ]
      }
    },

    "JenkinsRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Sid": "",
              "Effect": "Allow",
              "Principal": {
                "Service": "ec2.amazonaws.com"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "Path": "/"
      }
    },

    "JenkinsRolePolicies": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "JenkinsRole",
        "PolicyDocument": {
          "Statement": [
            {
              "Action": [
                "codepipeline:AcknowledgeJob",
                "codepipeline:GetJobDetails",
                "codepipeline:PollForJobs",
                "codepipeline:PutJobFailureResult",
                "codepipeline:PutJobSuccessResult"
              ],
              "Effect": "Allow",
              "Resource": "*"
            }
          ]
        },
        "Roles": [{"Ref": "JenkinsRole"}]
      }
    },

    "JenkinsInstanceProfile": {
      "Type": "AWS::IAM::InstanceProfile",
      "Properties": {
        "Path": "/",
        "Roles": [{"Ref": "JenkinsRole"}]
      }
    },

    "JenkinsSG" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "GroupDescription" : "Enable HTTP access on port 80",
        "VpcId" : { "Ref" : "MyVPC" },
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : {"Ref" : "YourIP"}},
          { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : {"Ref" : "YourIP"}}
        ],
        "SecurityGroupEgress" : [
          { "IpProtocol" : "tcp", "FromPort" : "80",  "ToPort" : "80",  "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "udp", "FromPort" : "123", "ToPort" : "123", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "udp", "FromPort" : "9418", "ToPort" : "9418", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "icmp", "FromPort" : "-1",  "ToPort" : "-1",  "CidrIp" : "0.0.0.0/0" }
        ],
        "Tags" : [
          {"Key" : "Name", "Value" : "JenkinsSG" }
        ]
      }
    },

    "JenkinsServer": {
      "Type": "AWS::EC2::Instance",
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "config" : {
            "packages" : {
              "yum" : {
                "java-1.7.0-openjdk" : [],
                "java-1.7.0-openjdk-devel" : []
              }
            },
            "files" : {
              "/tmp/config.xml" : {
                "source" : "https://s3.amazonaws.com/aws-codedeploy-samples-us-east-1/templates/latest/Jenkins_Helper_Scripts/config.xml",
                "mode" : "644"
              },
              "/tmp/hudson.tasks.Maven.xml" : {
                "source" : "https://s3.amazonaws.com/aws-codedeploy-samples-us-east-1/templates/latest/Jenkins_Helper_Scripts/hudson.tasks.Maven.xml",
                "mode" : "644"
              },
              "/tmp/jenkins.mvn.GlobalMavenConfig.xml" : {
                "source" : "https://s3.amazonaws.com/aws-codedeploy-samples-us-east-1/templates/latest/Jenkins_Helper_Scripts/jenkins.mvn.GlobalMavenConfig.xml",
                "mode" : "644"
              }
            }
          }
        }
      },
      "Properties": {
        "KeyName" : { "Ref" : "KeyName" },
        "ImageId" : { "Fn::FindInMap" : [ "AWSRegionVirt2AMI", { "Ref" : "AWS::Region" }, {"Fn::FindInMap": ["AWSInstanceType2Virt", "t2.large", "Virt"]} ]},
        "NetworkInterfaces" : [{
          "SubnetId" : { "Ref" : "publicSubnet01" },
          "GroupSet" : [{ "Ref" : "JenkinsSG" }],
          "AssociatePublicIpAddress" : "true",
          "DeviceIndex" : "0"
        }],
        "EbsOptimized" : {"Fn::FindInMap": ["AWSInstanceType2EBSOpt", "t2.large", "EBSOpt"]},
        "InstanceType": "t2.large",
        "IamInstanceProfile": {"Ref": "JenkinsInstanceProfile"},
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [ "", [ "#!/bin/bash -ex\n",
                "yum update -y aws-cfn-bootstrap\n",
                "# Update the AWS CLI to the latest version\n",
                "yum install -y aws-cli\n",

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

                "/opt/aws/bin/cfn-init -v -s ", { "Ref": "AWS::StackName" },
                " -r JenkinsServer --region ", {  "Ref": "AWS::Region" },"\n",

                "# Install Maven\n",
                "cd /tmp/\n",
                "MAVEN_VERSION=3.3.9\n",
                "wget https://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz\n",
                "tar xzvf apache-maven-$MAVEN_VERSION-bin.tar.gz -C /opt/\n",
                "ln -s /opt/apache-maven-$MAVEN_VERSION /opt/apache-maven\n",
                "rm /tmp/apache-maven-$MAVEN_VERSION-bin.tar.gz\n",

                "# Install Jenkins\n",
                "wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo\n",
                "rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key\n",
                "yum install -y http://pkg.jenkins-ci.org/redhat/jenkins-1.658-1.1.noarch.rpm\n",
                "service jenkins start\n",
                "chkconfig jenkins on\n",
                "# Wait 30 seconds to allow Jenkins to startup\n",
                "echo \"Waiting 30 seconds for Jenkins to start.....\"\n",
                "sleep 30\n",

                "# Install the required plugins\n",
                "cd /var/lib/jenkins/plugins\n",
                "curl -O -L https://updates.jenkins-ci.org/latest/aws-codepipeline.hpi\n",
                "chown jenkins:jenkins *.hpi\n",
                "mv /tmp/hudson.tasks.Maven.xml /var/lib/jenkins/\n",
                "mv /tmp/jenkins.mvn.GlobalMavenConfig.xml /var/lib/jenkins/\n",
                "chown jenkins:jenkins /var/lib/jenkins/*.xml\n",

                "# Restarting Jenkins\n",
                "service jenkins restart\n",
                "echo \"Waiting 30 seconds for Jenkins to start.....\"\n",
                "sleep 30\n",

                "# configure our job\n",
                "/bin/sed -i \"s/APPNAME/",{"Ref" : "AppName"},"/g\" /tmp/config.xml\n",
                "/bin/sed -i \"s/REGION/",{"Ref": "AWS::Region"},"/g\" /tmp/config.xml\n",
                "/usr/bin/java -jar /var/cache/jenkins/war/WEB-INF/jenkins-cli.jar -s http://localhost:8080 create-job ", {"Ref" : "AppName"} ,"< /tmp/config.xml\n",
                "rm /tmp/config.xml\n",

                "# Set up port forwarding\n",
                "iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080\n",
                "iptables-save > /etc/sysconfig/iptables\n",

                "# If all went well, signal success\n",
                "/opt/aws/bin/cfn-signal -e $? -r 'Instance configuration complete' '", { "Ref" : "JenkinsHostWaitHandle" }, "'\n",
                "\n"
              ]
            ]
          }
        },
        "Tags" : [
          {"Key" : "Name", "Value" : "JenkinsServer" }
        ]
      }
    },

    "JenkinsHostWaitHandle" : {
      "Type" : "AWS::CloudFormation::WaitConditionHandle"
    },

    "JenkinsHostWaitCondition" : {
      "Type" : "AWS::CloudFormation::WaitCondition",
      "DependsOn" : "JenkinsServer",
      "Properties" : {
        "Handle"  : { "Ref" : "JenkinsHostWaitHandle" },
        "Timeout" : "600"
      }
    },

    "CodeDeployTrustRole": {
      "Type" : "AWS::IAM::Role",
      "Properties" : {
        "AssumeRolePolicyDocument" : {
          "Statement" : [
            {
              "Sid" : "",
              "Effect" : "Allow",
              "Principal" : {
                "Service": [
                    "codedeploy.amazonaws.com"
                ]
              },
              "Action" : "sts:AssumeRole"
            }
          ]
        },
        "ManagedPolicyArns" : [ "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole" ],
        "Path" : "/"
      }
    },

    "MyApp" : {
      "Type" : "AWS::CodeDeploy::Application",
      "Properties" : {
        "ApplicationName" : {"Ref" : "AppName"}
      }
    },

    "DevDeploymentGroup" : {
      "DependsOn" : "CodeDeployTrustRole",
      "Type" : "AWS::CodeDeploy::DeploymentGroup",
      "Properties" : {
        "ApplicationName" : {"Ref" : "MyApp"},
        "DeploymentGroupName" : {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-DevEnv"]]},
        "DeploymentConfigName" : "CodeDeployDefault.OneAtATime",
        "ServiceRoleArn" : {"Fn::GetAtt" : ["CodeDeployTrustRole", "Arn"]},
        "Ec2TagFilters" : [{
          "Key" : "Environment",
          "Value" : {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-DevWebApp"]]},
          "Type" : "KEY_AND_VALUE"
        }]
      }
    },

    "ProdDeploymentGroup" : {
      "DependsOn" : "CodeDeployTrustRole",
      "Type" : "AWS::CodeDeploy::DeploymentGroup",
      "Properties" : {
        "ApplicationName" : {"Ref" : "MyApp"},
        "DeploymentGroupName" : {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-ProdEnv"]]},
        "DeploymentConfigName" : "CodeDeployDefault.OneAtATime",
        "ServiceRoleArn" : {"Fn::GetAtt" : ["CodeDeployTrustRole", "Arn"]},
        "Ec2TagFilters" : [{
          "Key" : "Environment",
          "Value" : {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-ProdWebApp"]]},
          "Type" : "KEY_AND_VALUE"
        }]
      }
    },

    "CodePipelineTrustRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [
            {
              "Sid": "1",
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "codepipeline.amazonaws.com"
                ]
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "Path": "/"
      }
    },

    "CodePipelineRolePolicies": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "CodePipelinePolicy",
        "PolicyDocument": {
          "Statement": [
            {
              "Action": [
                "s3:*"
              ],
              "Resource": ["*"],
              "Effect": "Allow"
            },
            {
              "Action": [
                "s3:PutBucketPolicy",
                "s3:PutObject"
              ],
              "Resource": [
                { "Fn::Join" : ["", [ "arn:aws:s3:::demo-", { "Ref": "AWS::Region" } , "-", {"Ref" : "AWS::AccountId"}, "-", {"Ref" : "AppName"} ]] }
              ],
              "Effect": "Allow"
            },
            {
            "Action": [
                "codecommit:GetBranch",
                "codecommit:GetCommit",
                "codecommit:UploadArchive",
                "codecommit:GetUploadArchiveStatus",
                "codecommit:CancelUploadArchive"
              ],
              "Resource": "*",
              "Effect": "Allow"
            },
            {
              "Action": [
                "codepipeline:*",
                "iam:ListRoles",
                "iam:PassRole",
                "codedeploy:CreateDeployment",
                "codedeploy:GetApplicationRevision",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentConfig",
                "codedeploy:RegisterApplicationRevision",
                "elasticbeanstalk:DescribeApplications",
                "elasticbeanstalk:DescribeEnvironments",
                "lambda:GetFunctionConfiguration",
                "lambda:ListFunctions"
              ],
              "Resource": "*",
              "Effect": "Allow"
            }
          ]
        },
        "Roles": [{ "Ref": "CodePipelineTrustRole"}]
      }
    },

    "CustomJenkinsActionType": {
      "Type": "AWS::CodePipeline::CustomActionType",
      "DependsOn" : "JenkinsHostWaitCondition",
      "Properties": {
        "Category": "Build",
        "Provider": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-Jenkins"]]},
        "Version": "1",
        "ConfigurationProperties": [
          {
            "Key": "true",
            "Name":  "ProjectName",
            "Queryable": "true",
            "Required": "true",
            "Secret": "false",
            "Type": "String"
          }
        ],
        "InputArtifactDetails": {
          "MaximumCount": 5,
          "MinimumCount": 0
        },
        "OutputArtifactDetails": {
          "MaximumCount": 5,
          "MinimumCount": 0
        },
        "Settings": {
          "EntityUrlTemplate": {"Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "JenkinsServer", "PublicIp" ]}, "/job/{Config:ProjectName}"]]},
          "ExecutionUrlTemplate": {"Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "JenkinsServer", "PublicIp" ]}, "/job/{Config:ProjectName}/{ExternalExecutionId}"]]}
        }
      }
    },

    "MyPipeline": {
      "Type": "AWS::CodePipeline::Pipeline",
      "DependsOn" : "CustomJenkinsActionType",
      "Properties": {
        "Name": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-Pipeline"]]},
        "RoleArn": {"Fn::GetAtt" : ["CodePipelineTrustRole", "Arn"]},
        "Stages": [
          {
            "Name": "Source",
            "Actions": [
              {
                "Name": "ApplicationSource",
                "InputArtifacts": [],
                "ActionTypeId": {
                  "Version": "1",
                  "Category": "Source",
                  "Owner" : { 
                    "Fn::If": ["S3AsSource", "AWS", "ThirdParty"]
                  },
                  "Provider": { 
                    "Fn::If": ["S3AsSource", "S3", "GitHub"]
                  }
                },
                "OutputArtifacts": [
                  {
                    "Name": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-SourceArtifact"]]}
                  }
                ],
                "Configuration": {
                  "Fn::If": [
                    "S3AsSource",
                    {
                      "S3Bucket": {"Ref" : "S3ArtifactBucket"},
                      "S3ObjectKey": {"Ref" : "S3ArtifactObject"}
                    },
                    {
                      "Owner" : {"Ref" : "GitHubUser"},
                      "Repo" : {"Ref" : "GitHubRepoName"},
                      "Branch" : {"Ref" : "GitHubBranchName"},
                      "OAuthToken" : {"Ref" : "GitHubToken"}
                    }
                  ]
                },
                "RunOrder": 1
              }
            ]
          },
          {
            "Name": "Build",
            "Actions": [
              {
                "Name": "ApplicationBuild",
                "InputArtifacts": [
                  {
                    "Name": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-SourceArtifact"]]}
                  }
                ],
                "ActionTypeId": {
                  "Category": "Build",
                  "Owner": "Custom",
                  "Version": "1",
                  "Provider": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-Jenkins"]]}
                },
                "OutputArtifacts": [
                  {
                    "Name": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-BuiltArtifact"]]}
                  }
                ],
                "Configuration": {
                  "ProjectName": {"Ref" : "AppName"}
                },
                "RunOrder": 1
              }
            ]
          },
          {
            "Name": "Beta",
            "Actions": [
              {
                "Name": "BetaDeploy",
                "InputArtifacts": [
                  {
                    "Name": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-BuiltArtifact"]]}
                  }
                ],
                "ActionTypeId": {
                  "Category": "Deploy",
                  "Owner": "AWS",
                  "Version": "1",
                  "Provider": "CodeDeploy"
                },
                "Configuration": {
                  "ApplicationName": {"Ref" : "MyApp"},
                  "DeploymentGroupName": {"Ref" : "DevDeploymentGroup"}
                },
                "RunOrder": 1
              }
            ]
          },
          {
            "Name": "Prod",
            "Actions": [
              {
                "Name": "ProdDeploy",
                "InputArtifacts": [
                  {
                    "Name": {"Fn::Join" : ["", [{"Ref" : "AppName"}, "-BuiltArtifact"]]}
                  }
                ],
                "ActionTypeId": {
                  "Category": "Deploy",
                  "Owner": "AWS",
                  "Version": "1",
                  "Provider": "CodeDeploy"
                },
                "Configuration": {
                  "ApplicationName": {"Ref" : "MyApp"},
                  "DeploymentGroupName": {"Ref" : "ProdDeploymentGroup"}
                },
                "RunOrder": 1
              }
            ]
          }
        ],
        "ArtifactStore": {
          "Type": "S3",
          "Location": { "Fn::Join" : ["", [ "demo-", { "Ref": "AWS::Region" } , "-", {"Ref" : "AWS::AccountId"}, "-", {"Ref" : "AppName"} ]] }
        }
      }
    }
  },

  "Outputs" : {
    "VpcId" : {
      "Value" : {"Ref" : "MyVPC"},
      "Description" : "VPC ID of newly created VPC"
    },

    "IGWId" : {
      "Value" : {"Ref" : "InternetGateway"},
      "Description" : "Internet Gateway ID"
    },

    "PublicSubnetA" : {
      "Value" : {"Ref" : "publicSubnet01"},
      "Description" : "Public Subnet in AZ A"
    },

    "DevInstanceID" : {
      "Value" : {"Ref": "DevWebApp01"},
      "Description" : "DevWebApp01 Instance ID"
    },

    "DevWebApp01PublicIP" : {
      "Value" : { "Fn::GetAtt" : [ "DevWebApp01", "PublicIp" ] },
      "Description" : "DevWebApp01 Public IP Address"
    },

    "ProdWebApp01InstanceID" : {
      "Value" : {"Ref": "ProdWebApp01"},
      "Description" : "ProdWebApp01 Instance ID"
    },

    "ProdWebApp01PublicIP" : {
      "Value" : { "Fn::GetAtt" : [ "ProdWebApp01", "PublicIp" ] },
      "Description" : "ProdWebApp01 Public IP Address"
    },

    "JenkinsInstanceID" : {
      "Value" : {"Ref": "JenkinsServer"},
      "Description" : "Jenkins Instance ID"
    },

    "JenkinsPublicIP" : {
      "Value" : { "Fn::GetAtt" : [ "JenkinsServer", "PublicIp" ] },
      "Description" : "Jenkins Public IP Address"
    },

    "AppSourceType" : {
      "Value" : {"Ref" : "AppSourceType"},
      "Description" : "The source type of the application"
    },

    "ApplicationSource" : {
      "Value" : {
        "Fn::If": [
          "S3AsSource",
          {
            "Fn::Join" : ["", ["https://s3.amazonaws.com/", {"Ref" : "S3ArtifactBucket"}, "/", {"Ref" : "S3ArtifactObject"}] ]
          },
          {
            "Fn::Join" : ["", ["https://github.com/", {"Ref" : "GitHubUser"}, "/", {"Ref" : "GitHubRepoName"}, "/tree/", {"Ref" : "GitHubBranchName"}] ]
          }
        ]
      },
      "Description" : "The source location of the application"
    }
  }
}