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

    "Description" : "CloudFormation template to create a micro MapR cluster using Docker in a single AWS VM",

    "Parameters" : {
  
       "ClusterNodeType" : {
           "Type" : "String",
           "Default" : "m4.4xlarge",
           "Description" : "Instance Type for MapR Cluster nodes; select m3/m4 or i2 instance types for us-west-1 and sa-east-1",
           "AllowedValues" : [ "m4.2xlarge", "m4.4xlarge", "r3.2xlarge", "r3.4xlarge", "r4.2xlarge", "r4.4xlarge", "d2.2xlarge", "d2.4xlarge", "d2.8xlarge", "i2.xlarge", "i2.2xlarge" ]
,
            "ConstraintDescription" : "Must be a valid EC2 instance type."
        },

        "InstanceSpotPrice": 
        {
            "Type": "String",
            "Default" : "0.00",
            "Description": "Spot Price to bid for requested instances (0.00 will result in using on-demand instances)",
            "AllowedPattern" : "([0-9]{1}[.]{1}[0-9]{2})",
            "ConstraintDescription" : "Must be decimal numeric value"
        },

        "PersistentStorage": {
          "Type": "Number",
          "Default": "5",
          "Description" : "Allocated EBS storage for each block device (in GB; 5 drives)",
          "MinValue": "2",
          "MaxValue": "8",
          "ConstraintDescription" : "No more than 10 GB per device."
        },

        "KeyName": 
        {
            "Type": "AWS::EC2::KeyPair::KeyName",
            "Description": "Name of an existing EC2 KeyPair within the AWS account; all instances will launch with this KeyPair",
            "MinLength": "1"
        },

        "MapRVersion" :
        {
            "Type" : "String",
            "Default" : "5.2.0",
            "Description" : "MapR Converge Data Platform version 5.2.0, MEP-1.1",
            "AllowedValues" : [ "5.2.0" ],
            "ConstraintDescription" : "Supported versions of MapR within AWS Marketplace"
        },

        "VpcSubnetId" :
        {
          "Type" : "String",
          "Default" : "subnet-00000000",
          "Description" : "VPC Subnet for cluster deployment; specifying subnet-00000000 will result in new VPC being created",
          "AllowedPattern" : "subnet-(\\w{8})",
          "ConstraintDescription" : "must be a valid AWS subnet (subnet-xxxxxxx}"
        },

        "RemoteAccessCIDR" :
        {
          "Type" : "String",
          "Default" : "0.0.0.0/0",
          "Description" : "For newly created VPC's, allow inbound network traffic from this address range (0.0.0.0/0 will allow all)",
          "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"
        }
   
    },

    "Mappings" : 
    {
        "MapRVersion2Vindex" : {
          "5.2.0"       : { "Vindex" : "520"  }
        },

        "AWSRegionVindex2AMI" : {
          "us-east-1"      : { "520" : "ami-7a8f986d" },
          "us-west-2"      : { "520" : "ami-0d73c46d" },
          "eu-central-1"   : { "520" : "ami-947bbbfb" },
          "eu-west-1"      : { "520" : "ami-03173470" },
          "ap-southeast-2" : { "520" : "ami-358bb056" },
          "ap-northeast-1" : { "520" : "ami-561a7031" }
        },

        "SubnetConfig" : 
        {
          "VPC"         : { "CIDR" : "10.9.0.0/16" },
          "Public"      : { "CIDR" : "10.9.1.0/24" },
          "MySQLDB"     : { "CIDR" : "10.9.2.0/24" }
        }
    },
  
    "Conditions" : {
       "EnableWaitConditions" : { "Fn::Equals" : [ "1" , "1" ] },
       "EphemeralStorage" : { "Fn::Equals" : [ { "Ref" : "PersistentStorage" } , "0" ] },
       "OnDemandInstances" : { "Fn::Equals" : [ { "Ref" : "InstanceSpotPrice" } , "0.00" ] },
       "NewPrivateVPC" : { "Fn::Equals" : [ { "Ref" : "VpcSubnetId" } , "subnet-00000000" ] }
    },

    "Resources" : {

      "VPC" : 
      {
        "Type" : "AWS::EC2::VPC",
        "Condition" : "NewPrivateVPC",
        "Properties" : 
        {
          "CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]},
          "EnableDnsHostnames" : "true",
          "EnableDnsSupport" : "true",
          "Tags" : [ {"Key" : "Application", "Value" : "MapR Marketplace Deploymnent"  } ]
        }
      },

      "InternetGateway" : 
      {
        "Type" : "AWS::EC2::InternetGateway",
        "Condition" : "NewPrivateVPC"
      },

      "AttachGateway" : 
      {
        "Type" : "AWS::EC2::VPCGatewayAttachment",
        "Condition" : "NewPrivateVPC",
        "Properties" : 
        {
          "VpcId" : { "Ref" : "VPC" },
          "InternetGatewayId" : { "Ref" : "InternetGateway" }
        }
      },

      "PublicSubnet" : 
      {
        "Type" : "AWS::EC2::Subnet",
        "Condition" : "NewPrivateVPC",
        "Properties" : 
        {
            "VpcId" : { "Ref" : "VPC" },
            "CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "Public", "CIDR" ]},
            "Tags" : [
              {"Key" : "Application", "Value" : "MapR" },
              {"Key" : "Network", "Value" : "Public" }
            ]
        }
      },

      "PublicRouteTable" : {
        "Type" : "AWS::EC2::RouteTable",
        "Condition" : "NewPrivateVPC",
        "Properties" : {
          "VpcId" : { "Ref" : "VPC" }
        }
      },

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

      "PublicSubnetRouteTableAssociation" : {
        "Type" : "AWS::EC2::SubnetRouteTableAssociation",
        "Condition" : "NewPrivateVPC",
        "Properties" : {
          "SubnetId" : { "Ref" : "PublicSubnet" },
          "RouteTableId" : { "Ref" : "PublicRouteTable" }
        }
      },

      "DefaultSecurityGroup" : {
        "Type" : "AWS::EC2::SecurityGroup",
        "Condition" : "NewPrivateVPC",
        "Properties" : {
          "GroupDescription" : "Default Security group for all the Nodes",
          "VpcId" : {"Ref" : "VPC"},
          "SecurityGroupIngress" : [
            { "IpProtocol" : "icmp", "FromPort" : "-1", "ToPort" : "-1", "CidrIp" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]} },
            { "IpProtocol" : "tcp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]} },
            { "IpProtocol" : "udp", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]} },
            { "IpProtocol" : "tcp", "FromPort" : "8443", "ToPort" : "8443", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "8088", "ToPort" : "8088", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "8042", "ToPort" : "8042", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "19888", "ToPort" : "19888", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "8047", "ToPort" : "8047", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "31010", "ToPort" : "31010", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "10000", "ToPort" : "10000", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "9443", "ToPort" : "9443", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "2049", "ToPort" : "2049", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "111", "ToPort" : "111", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "udp", "FromPort" : "111", "ToPort" : "111", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } },
            { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "RemoteAccessCIDR" } } 
          ]
        }
      },

    "InstanceIAMRole": {
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Statement": [{
            "Action": [ "sts:AssumeRole" ], 
            "Effect": "Allow", 
            "Principal": { "Service": [ "ec2.amazonaws.com" ] }
          }], 
          "Version": "2012-10-17"
        }, 
        "Path": "/", 
        "Policies": [{
          "PolicyDocument": {
            "Statement": [{
              "Action": [ 
                "ec2:CreateTags", 
                "ec2:DescribeInstances", 
                "cloudformation:DescribeStackResources", 
                "s3:Get*" , 
                "s3:List*" 
              ], 
              "Effect": "Allow", 
              "Resource": "*"
            }]
          }, 
          "PolicyName": "DescribeAccessEC2andCFN"
        }]
      }, 
      "Type": "AWS::IAM::Role"
    },

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

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

    "ClusterCompleteCondition" : {
        "Type" : "AWS::CloudFormation::WaitCondition",
        "DependsOn" : "ClusterNodes",
        "Properties" : {
           "Handle"  : { "Ref" : "ClusterCompleteHandle" },
           "Timeout" : "600",
           "Count"   : "1"
        }
    },

    "ClusterNodes" : {
      "Type" : "AWS::AutoScaling::AutoScalingGroup",
      "Properties" : {
        "VPCZoneIdentifier" : [ { "Fn::If" : [ "NewPrivateVPC", { "Ref" : "PublicSubnet" }, {"Ref" : "VpcSubnetId"} ] } ],
        "LaunchConfigurationName" : { "Ref" : "ClusterNodeLaunchConfig" },
        "MinSize" : 1,
        "MaxSize" : 1,
        "DesiredCapacity" : 1
      },
      "CreationPolicy": {
        "ResourceSignal": {
          "Count": "1",
          "Timeout": "PT90M"
        }
      }       
    },
    
    "ClusterNodeLaunchConfig"  : {
        "Type" : "AWS::AutoScaling::LaunchConfiguration",
        "Properties" : {
          "BlockDeviceMappings" : {"Fn::If" : ["EphemeralStorage",[
            { "DeviceName" : "/dev/sdb", "VirtualName": "ephemeral0" },
            { "DeviceName" : "/dev/sdc", "VirtualName": "ephemeral1" },
            { "DeviceName" : "/dev/sdd", "VirtualName": "ephemeral2" },
            { "DeviceName" : "/dev/sde", "VirtualName": "ephemeral3" },
            { "DeviceName" : "/dev/sdf", "VirtualName": "ephemeral4" },
            { "DeviceName" : "/dev/sdg", "VirtualName": "ephemeral5" },
            { "DeviceName" : "/dev/sdh", "VirtualName": "ephemeral6" },
            { "DeviceName" : "/dev/sdi", "VirtualName": "ephemeral7" },
            { "DeviceName" : "/dev/sdj", "VirtualName": "ephemeral8" },
            { "DeviceName" : "/dev/sdk", "VirtualName": "ephemeral9" },
            { "DeviceName" : "/dev/sdl", "VirtualName": "ephemeral10" },
            { "DeviceName" : "/dev/sdm", "VirtualName": "ephemeral11" }
          ],[ 
            { "DeviceName" : "/dev/xvdb", 
              "Ebs" : { "VolumeSize" : {"Ref" : "PersistentStorage"}, "DeleteOnTermination" : "True" } },
            { "DeviceName" : "/dev/xvdc", 
              "Ebs" : { "VolumeSize" : {"Ref" : "PersistentStorage"}, "DeleteOnTermination" : "True" } },
            { "DeviceName" : "/dev/xvdd", 
              "Ebs" : { "VolumeSize" : {"Ref" : "PersistentStorage"}, "DeleteOnTermination" : "True" } },
            { "DeviceName" : "/dev/xvde", 
              "Ebs" : { "VolumeSize" : {"Ref" : "PersistentStorage"}, "DeleteOnTermination" : "True" } },
            { "DeviceName" : "/dev/xvdf", 
              "Ebs" : { "VolumeSize" : {"Ref" : "PersistentStorage"}, "DeleteOnTermination" : "True" } }
          ]]},
          "ImageId"        : { "Fn::FindInMap" : [ "AWSRegionVindex2AMI", { "Ref" : "AWS::Region" },
                { "Fn::FindInMap" : [ "MapRVersion2Vindex", { "Ref" : "MapRVersion" }, "Vindex" ] } ] },
          "SecurityGroups" : [ { "Fn::If" : [ "NewPrivateVPC", { "Ref" : "DefaultSecurityGroup" }, {"Ref" : "AWS::NoValue"} ] } ] ,
          "InstanceType"   : { "Ref" : "ClusterNodeType" },
          "SpotPrice" : { "Fn::If" : [ "OnDemandInstances", {"Ref" : "AWS::NoValue"}, { "Ref" : "InstanceSpotPrice" } ] },
          "KeyName"        : { "Ref" : "KeyName" },
          "AssociatePublicIpAddress" : "true",
          "IamInstanceProfile" : { "Ref" : "InstanceProfile" },
          "UserData": {
            "Fn::Base64": { "Fn::Join": ["",[
              "#!/bin/bash\n",
              "\n", 
              "## Signal that the node is up\n",
               "/opt/aws/bin/cfn-signal -e 0 --stack ", {"Ref":"AWS::StackName"}, " --region ", {"Ref": "AWS::Region"}, " --resource ClusterNodes\n",
              "\n", 
              "## Tag the instance (now that we're sure of launch index\n",
              "instance_id=$(curl -f http://169.254.169.254/latest/meta-data/instance-id)\n",
              "if [ -n \"$instance_id\" ] ; then\n",
              "  instance_tag=mapr520_docker\n",
              "  aws ec2 create-tags", " --region ", {"Ref": "AWS::Region"}, " --resources $instance_id --tags Key=Name,Value=$instance_tag\n",
              "fi\n",
              "## If all went well, signal success (must be done by ALL nodes)\n",
              "/opt/aws/bin/cfn-signal -e 0 -r 'MapR Installation complete' '", { "Ref" : "ClusterCompleteHandle" }, "'\n",
              "\n", 
              "## Wait for all nodes to issue the signal\n",
              "resourceStatus=$(aws cloudformation describe-stack-resources ",
              "--region ", {"Ref": "AWS::Region"}, " ",
              "--stack-name ", {"Ref":"AWS::StackName"}, " --logical-resource-id ClusterCompleteCondition ", 
              "--query StackResources[].ResourceStatus --output text )\n",
              "while [ \"$resourceStatus\" != \"CREATE_COMPLETE\" ]\n",
              "do\n",
              "  sleep 10\n",
              "  resourceStatus=$(aws cloudformation describe-stack-resources ",
              "--region ", {"Ref": "AWS::Region"}, " ",
              "--stack-name ", {"Ref":"AWS::StackName"}, " --logical-resource-id ClusterCompleteCondition ", 
              "--query StackResources[].ResourceStatus --output text )\n",
              "done\n",
              "\n"
            ]]}
          }
        }
      }
    },
}