Skip to content

Instantly share code, notes, and snippets.

@nfisher
Last active August 29, 2015 14:20
Show Gist options
  • Save nfisher/522c303ef325bd5cf43e to your computer and use it in GitHub Desktop.
Save nfisher/522c303ef325bd5cf43e to your computer and use it in GitHub Desktop.
Go(ing) to the clouds complete example.
package main
// This command will allow you to provision, delete, describe, or estimate the cost of the specified CloudFormation template.
//
// Once compiled use the -help flag for details.
import (
"bufio"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"github.com/awslabs/aws-sdk-go/aws"
"github.com/awslabs/aws-sdk-go/aws/awsutil"
awscf "github.com/awslabs/aws-sdk-go/service/cloudformation"
)
func provisionStack(svc *awscf.CloudFormation, b []byte, params []*awscf.Parameter, stackName string) {
input := &awscf.CreateStackInput{
StackName: aws.String(stackName),
Capabilities: []*string{
aws.String("CAPABILITY_IAM"),
},
OnFailure: aws.String("DELETE"),
Parameters: params,
TemplateBody: aws.String(string(b)),
TimeoutInMinutes: aws.Long(20),
}
resp, err := svc.CreateStack(input)
if err != nil {
log.Fatal(err)
}
log.Println(awsutil.StringValue(resp))
}
func delStack(svc *awscf.CloudFormation, stackName string) {
input := &awscf.DeleteStackInput{
StackName: aws.String(stackName),
}
resp, err := svc.DeleteStack(input)
if err != nil {
log.Fatal(err)
}
log.Println(awsutil.StringValue(resp))
}
func descStack(svc *awscf.CloudFormation, stackName string) {
input := &awscf.DescribeStackEventsInput{
StackName: aws.String(stackName),
}
resp, err := svc.DescribeStackEvents(input)
if err != nil {
log.Fatal(err)
}
if len(resp.StackEvents) > 0 {
log.Println(awsutil.StringValue(resp.StackEvents[0]))
}
}
func cost(svc *awscf.CloudFormation, b []byte, params []*awscf.Parameter) {
estInput := &awscf.EstimateTemplateCostInput{
Parameters: params,
TemplateBody: aws.String(string(b)),
}
cost, err := svc.EstimateTemplateCost(estInput)
if err != nil {
log.Fatal(err)
}
fmt.Println(awsutil.StringValue(cost.URL))
}
func main() {
var templateFile string
var outputCost bool
var provision bool
var desc bool
var del bool
var b []byte
var params []*awscf.Parameter
var stackName string
var region string
flag.StringVar(&region, "region", "eu-west-1", "AWS region to provision script to.")
flag.StringVar(&templateFile, "template", "", "Template to validate.")
flag.StringVar(&stackName, "name", "", "Stack name (required).")
flag.BoolVar(&outputCost, "cost", false, "Output cost URL.")
flag.BoolVar(&provision, "provision", false, "Provision template.")
flag.BoolVar(&desc, "desc", false, "Describe stack.")
flag.BoolVar(&del, "del", false, "Delete stack.")
flag.Parse()
if stackName == "" {
fmt.Println("Stack name cannot be empty!\n")
flag.Usage()
return
}
config := &aws.Config{Region: region}
svc := awscf.New(config)
if outputCost || provision {
f, err := os.Open(templateFile)
if err != nil {
log.Fatal(err)
}
b, err = ioutil.ReadAll(f)
if err != nil {
log.Fatal(err)
}
input := &awscf.ValidateTemplateInput{
TemplateBody: aws.String(string(b)),
}
resp, err := svc.ValidateTemplate(input)
if err != nil {
log.Fatal(err)
}
// output the template description
fmt.Println(awsutil.StringValue(resp.Description))
params = make([]*awscf.Parameter, len(resp.Parameters))
// fill out the parameters from the template
stdin := bufio.NewReader(os.Stdin)
for i, p := range resp.Parameters {
fmt.Printf("%v (%v): ", awsutil.StringValue(p.Description), awsutil.StringValue(p.DefaultValue))
// don't care about isMore if someone's typing so much oh well
b, _, err := stdin.ReadLine()
if err != nil {
log.Fatal(err)
}
line := string(b)
params[i] = &awscf.Parameter{
ParameterKey: p.ParameterKey,
UsePreviousValue: aws.Boolean(true),
}
if line != "" {
params[i].ParameterValue = aws.String(line)
} else {
params[i].ParameterValue = p.DefaultValue
}
}
}
if outputCost {
cost(svc, b, params)
return
} else if provision {
provisionStack(svc, b, params, stackName)
} else if desc {
descStack(svc, stackName)
} else if del {
delStack(svc, stackName)
}
}
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "AWS CloudFormation Sample Template VPC_with_PublicIPs_And_DNS: Sample template showing how to create a VPC with DNS and Public IPs enabled. You will be billed for the AWS resources used if you create a stack from this template.",
"Parameters" : {
"KeyName" : {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the bastion host",
"Type" : "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription" : "must be the name of an existing EC2 KeyPair.",
"Default" : "nfisher.macair"
},
"SSHLocation" : {
"Description" : "Lockdown SSH access to the bastion host (default can be accessed from anywhere)",
"Type" : "String",
"MinLength": "9",
"MaxLength": "18",
"Default" : "0.0.0.0/0",
"AllowedPattern" : "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
"ConstraintDescription" : "must be a valid CIDR range of the form x.x.x.x/x."
},
"EC2InstanceType" : {
"Description" : "EC2 instance type",
"Type" : "String",
"Default" : "t2.micro",
"AllowedValues" : [ "t1.micro", "t2.micro", "t2.small", "t2.medium", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "c1.medium", "c1.xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "g2.2xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "d2.xlarge", "d2.2xlarge", "d2.4xlarge", "d2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge", "cg1.4xlarge"]
,
"ConstraintDescription" : "must be a valid EC2 instance type."
}
},
"Mappings" : {
"SubnetConfig" : {
"VPC" : { "CIDR" : "10.0.0.0/16" },
"Public" : { "CIDR" : "10.0.0.0/24" }
},
"AWSInstanceType2Arch" : {
"t1.micro" : { "Arch" : "PV64" },
"t2.micro" : { "Arch" : "HVM64" },
"t2.small" : { "Arch" : "HVM64" },
"t2.medium" : { "Arch" : "HVM64" },
"m1.small" : { "Arch" : "PV64" },
"m1.medium" : { "Arch" : "PV64" },
"m1.large" : { "Arch" : "PV64" },
"m1.xlarge" : { "Arch" : "PV64" },
"m2.xlarge" : { "Arch" : "PV64" },
"m2.2xlarge" : { "Arch" : "PV64" },
"m2.4xlarge" : { "Arch" : "PV64" },
"m3.medium" : { "Arch" : "HVM64" },
"m3.large" : { "Arch" : "HVM64" },
"m3.xlarge" : { "Arch" : "HVM64" },
"m3.2xlarge" : { "Arch" : "HVM64" },
"c1.medium" : { "Arch" : "PV64" },
"c1.xlarge" : { "Arch" : "PV64" },
"c3.large" : { "Arch" : "HVM64" },
"c3.xlarge" : { "Arch" : "HVM64" },
"c3.2xlarge" : { "Arch" : "HVM64" },
"c3.4xlarge" : { "Arch" : "HVM64" },
"c3.8xlarge" : { "Arch" : "HVM64" },
"c4.large" : { "Arch" : "HVM64" },
"c4.xlarge" : { "Arch" : "HVM64" },
"c4.2xlarge" : { "Arch" : "HVM64" },
"c4.4xlarge" : { "Arch" : "HVM64" },
"c4.8xlarge" : { "Arch" : "HVM64" },
"g2.2xlarge" : { "Arch" : "HVMG2" },
"r3.large" : { "Arch" : "HVM64" },
"r3.xlarge" : { "Arch" : "HVM64" },
"r3.2xlarge" : { "Arch" : "HVM64" },
"r3.4xlarge" : { "Arch" : "HVM64" },
"r3.8xlarge" : { "Arch" : "HVM64" },
"i2.xlarge" : { "Arch" : "HVM64" },
"i2.2xlarge" : { "Arch" : "HVM64" },
"i2.4xlarge" : { "Arch" : "HVM64" },
"i2.8xlarge" : { "Arch" : "HVM64" },
"d2.xlarge" : { "Arch" : "HVM64" },
"d2.2xlarge" : { "Arch" : "HVM64" },
"d2.4xlarge" : { "Arch" : "HVM64" },
"d2.8xlarge" : { "Arch" : "HVM64" },
"hi1.4xlarge" : { "Arch" : "HVM64" },
"hs1.8xlarge" : { "Arch" : "HVM64" },
"cr1.8xlarge" : { "Arch" : "HVM64" },
"cc2.8xlarge" : { "Arch" : "HVM64" }
}
,
"AWSRegionArch2AMI" : {
"us-east-1" : {"PV64" : "ami-1ccae774", "HVM64" : "ami-10cae778", "HVMG2" : "ami-8c6b40e4"},
"us-west-2" : {"PV64" : "ami-ff527ecf", "HVM64" : "ami-e9527ed9", "HVMG2" : "ami-abbe919b"},
"us-west-1" : {"PV64" : "ami-d514f291", "HVM64" : "ami-cb14f28f", "HVMG2" : "ami-f31ffeb7"},
"eu-west-1" : {"PV64" : "ami-bf0897c8", "HVM64" : "ami-a30897d4", "HVMG2" : "ami-d5bc24a2"},
"eu-central-1" : {"PV64" : "ami-ac221fb1", "HVM64" : "ami-ae221fb3", "HVMG2" : "ami-7cd2ef61"},
"ap-northeast-1" : {"PV64" : "ami-27f90e27", "HVM64" : "ami-c7f90ec7", "HVMG2" : "ami-6318e863"},
"ap-southeast-1" : {"PV64" : "ami-acd9e8fe", "HVM64" : "ami-64d8e936", "HVMG2" : "ami-3807376a"},
"ap-southeast-2" : {"PV64" : "ami-ff9cecc5", "HVM64" : "ami-f39cecc9", "HVMG2" : "ami-89790ab3"},
"sa-east-1" : {"PV64" : "ami-bb2890a6", "HVM64" : "ami-b72890aa", "HVMG2" : "NOT_SUPPORTED"},
"cn-north-1" : {"PV64" : "ami-fa39abc3", "HVM64" : "ami-e839abd1", "HVMG2" : "NOT_SUPPORTED"}
}
},
"Resources" : {
"VPC" : {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"EnableDnsSupport" : "true",
"EnableDnsHostnames" : "true",
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "VPC", "CIDR" ]},
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"PublicSubnet" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "Public", "CIDR" ]},
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"InternetGateway" : {
"Type" : "AWS::EC2::InternetGateway",
"Properties" : {
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"GatewayToInternet" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"InternetGatewayId" : { "Ref" : "InternetGateway" }
}
},
"PublicRouteTable" : {
"Type" : "AWS::EC2::RouteTable",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"PublicRoute" : {
"Type" : "AWS::EC2::Route",
"DependsOn" : "GatewayToInternet",
"Properties" : {
"RouteTableId" : { "Ref" : "PublicRouteTable" },
"DestinationCidrBlock" : "0.0.0.0/0",
"GatewayId" : { "Ref" : "InternetGateway" }
}
},
"PublicSubnetRouteTableAssociation" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PublicSubnet" },
"RouteTableId" : { "Ref" : "PublicRouteTable" }
}
},
"PublicNetworkAcl" : {
"Type" : "AWS::EC2::NetworkAcl",
"Properties" : {
"VpcId" : { "Ref" : "VPC" },
"Tags" : [
{ "Key" : "Application", "Value" : { "Ref" : "AWS::StackName" } },
{ "Key" : "Network", "Value" : "Public" }
]
}
},
"InboundHTTPPublicNetworkAclEntry" : {
"Type" : "AWS::EC2::NetworkAclEntry",
"Properties" : {
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
"RuleNumber" : "100",
"Protocol" : "6",
"RuleAction" : "allow",
"Egress" : "false",
"CidrBlock" : "0.0.0.0/0",
"PortRange" : { "From" : "80", "To" : "80" }
}
},
"InboundHTTPSPublicNetworkAclEntry" : {
"Type" : "AWS::EC2::NetworkAclEntry",
"Properties" : {
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
"RuleNumber" : "101",
"Protocol" : "6",
"RuleAction" : "allow",
"Egress" : "false",
"CidrBlock" : "0.0.0.0/0",
"PortRange" : { "From" : "443", "To" : "443" }
}
},
"InboundSSHPublicNetworkAclEntry" : {
"Type" : "AWS::EC2::NetworkAclEntry",
"Properties" : {
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
"RuleNumber" : "102",
"Protocol" : "6",
"RuleAction" : "allow",
"Egress" : "false",
"CidrBlock" : { "Ref" : "SSHLocation" },
"PortRange" : { "From" : "22", "To" : "22" }
}
},
"InboundEphemeralPublicNetworkAclEntry" : {
"Type" : "AWS::EC2::NetworkAclEntry",
"Properties" : {
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
"RuleNumber" : "103",
"Protocol" : "6",
"RuleAction" : "allow",
"Egress" : "false",
"CidrBlock" : "0.0.0.0/0",
"PortRange" : { "From" : "1024", "To" : "65535" }
}
},
"OutboundPublicNetworkAclEntry" : {
"Type" : "AWS::EC2::NetworkAclEntry",
"Properties" : {
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
"RuleNumber" : "100",
"Protocol" : "6",
"RuleAction" : "allow",
"Egress" : "true",
"CidrBlock" : "0.0.0.0/0",
"PortRange" : { "From" : "0", "To" : "65535" }
}
},
"PublicSubnetNetworkAclAssociation" : {
"Type" : "AWS::EC2::SubnetNetworkAclAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "PublicSubnet" },
"NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
}
},
"EC2Host" : {
"Type" : "AWS::EC2::Instance",
"DependsOn" : "GatewayToInternet",
"Properties" : {
"InstanceType" : { "Ref" : "EC2InstanceType" },
"KeyName" : { "Ref" : "KeyName" },
"ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
{ "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "EC2InstanceType" }, "Arch" ] } ] },
"NetworkInterfaces" : [{
"GroupSet" : [{ "Ref" : "EC2SecurityGroup" }],
"AssociatePublicIpAddress" : "true",
"DeviceIndex" : "0",
"DeleteOnTermination" : "true",
"SubnetId" : { "Ref" : "PublicSubnet" }
}]
}
},
"EC2SecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable access to the EC2 host",
"VpcId" : { "Ref" : "VPC" },
"SecurityGroupIngress" : [ {
"IpProtocol" : "tcp",
"FromPort" : "22",
"ToPort" : "22",
"CidrIp" : { "Ref" : "SSHLocation" }
} ]
}
}
},
"Outputs" : {
"VPCId" : {
"Description" : "VPCId of the newly created VPC",
"Value" : { "Ref" : "VPC" }
},
"PublicSubnet" : {
"Description" : "SubnetId of the public subnet",
"Value" : { "Ref" : "PublicSubnet" }
},
"DNSName" : {
"Description" : "DNS Name of the EC2 host",
"Value" : { "Fn::GetAtt" : ["EC2Host", "PublicDnsName"] }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment