Skip to content

Commit

Permalink
Bump 0.0.2 - update now uses Cloudformation instead of EB directly, a…
Browse files Browse the repository at this point in the history
…nd CF templates now allow most variable options for EB
  • Loading branch information
Kotowick committed Mar 24, 2017
1 parent eb7b981 commit 0afb2d9
Show file tree
Hide file tree
Showing 9 changed files with 812 additions and 125 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ clean:
@rm -f ./bin/$(BINARY_NAME)

build:
@echo Compiling resources/.. for version $(VERSION)
@go-bindata resources/...
@echo Building $(BINARY_NAME) version $(VERSION)
@go build -a -tags netgo -ldflags '-w' -o ./bin/$(BINARY_NAME)-$(VERSION)
@cp ./bin/$(BINARY_NAME)-$(VERSION) ./bin/$(BINARY_NAME)
Expand Down
Binary file modified bin/go-deploy
Binary file not shown.
Binary file added bin/go-deploy-0.0.2
Binary file not shown.
8 changes: 4 additions & 4 deletions bindata.go

Large diffs are not rendered by default.

153 changes: 147 additions & 6 deletions lib/aws/cloudformation/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,158 @@ import (
"github.com/segmentio/go-camelcase"
)

// DescribeStack describes the specified Cloudformation Stack.
//
// Example:
// // Describe a Cloudformation stack.
// svc := cloudformation.DescribeStack(stackName)
//
func (c *CloudFormation) DescribeStack(stackName string) bool {
if stackName == "" {
return false
}

params := &cloudformation.DescribeStacksInput{
NextToken: aws.String("NextToken"),
StackName: aws.String(stackName),
}

resp, err := c.Service.DescribeStacks(params)

if err != nil {
fmt.Println(err.Error())
return false
}

fmt.Println(resp)

if len(resp.Stacks) > 0 {
return true
}
return false
}

// UpdateStack updates an existing Cloudformation Stack
//
// Example:
// // Update a Cloudformation Stack.
// svc := cloudformation.UpdateStack(paramaters, template)
//
func (c *CloudFormation) UpdateStack(paramaters map[string]string, template []byte, usePreviousTemplate bool) {
var cfParameters []*cloudformation.Parameter

if usePreviousTemplate {
delete(paramaters, "VPC_PRIVATE_SUBNETS")
delete(paramaters, "SOLUTION_STACK")
delete(paramaters, "VPC_ELB_SUBNETS")
delete(paramaters, "VPC_ID")

cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("vpcPrivateSubnets"),
UsePreviousValue: aws.Bool(true),
})

cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("solutionStack"),
UsePreviousValue: aws.Bool(true),
})

cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("vpcElbSubnets"),
UsePreviousValue: aws.Bool(true),
})

cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("vpcId"),
UsePreviousValue: aws.Bool(true),
})
}

if paramaters["VersionLabel"] == "" {
delete(paramaters, "VersionLabel")
delete(paramaters, "AppBucket")
delete(paramaters, "AppKey")
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("versionLabel"),
UsePreviousValue: aws.Bool(true),
})
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("appBucket"),
UsePreviousValue: aws.Bool(true),
})
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("appKey"),
UsePreviousValue: aws.Bool(true),
})
}
if paramaters["AppBucket"] == "" {
delete(paramaters, "AppBucket")
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("appBucket"),
UsePreviousValue: aws.Bool(true),
})
}
if paramaters["AppKey"] == "" {
delete(paramaters, "AppKey")
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String("appKey"),
UsePreviousValue: aws.Bool(true),
})
}

for k, v := range paramaters {
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String(camelcase.Camelcase(k)),
ParameterValue: aws.String(fmt.Sprintf("%s", v)),
})
}

fmt.Printf("%s", cfParameters)

params := &cloudformation.UpdateStackInput{
StackName: aws.String(fmt.Sprintf("%s-%s-%s", paramaters["AppName"], paramaters["EnvName"], paramaters["Tier"])), // Required
Parameters: cfParameters,
}

if usePreviousTemplate {
params.UsePreviousTemplate = aws.Bool(usePreviousTemplate)
} else {
params.TemplateBody = aws.String(fmt.Sprintf("%s", template))
}

resp, err := c.Service.UpdateStack(params)

if err != nil {
fmt.Println(err.Error())
return
}

fmt.Println(resp)
}

// CreateStack creates a new Cloudformation Stack
//
// Example:
// // Create a Cloudformation Stack.
// svc := cloudformation.CreateStack(paramaters, template)
//
func (c *CloudFormation) CreateStack(paramaters map[string]string, template []byte) {
var cf_parameters []*cloudformation.Parameter
var cfParameters []*cloudformation.Parameter

for k, v := range paramaters {
cf_parameters = append(cf_parameters, &cloudformation.Parameter{
cfParameters = append(cfParameters, &cloudformation.Parameter{
ParameterKey: aws.String(camelcase.Camelcase(k)),
ParameterValue: aws.String(fmt.Sprintf("%s", v)),
})
}

fmt.Printf("%s", cf_parameters)
fmt.Printf("%s", cfParameters)

params := &cloudformation.CreateStackInput{
StackName: aws.String(fmt.Sprintf("%s-%s-%s", paramaters["AppName"], paramaters["EnvName"], paramaters["Tier"])), // Required
DisableRollback: aws.Bool(false),
//OnFailure: aws.String("OnFailure"),
Parameters: cf_parameters,
Parameters: cfParameters,
TemplateBody: aws.String(fmt.Sprintf("%s", template)),
TimeoutInMinutes: aws.Int64(25),
}
Expand All @@ -41,9 +176,15 @@ func (c *CloudFormation) CreateStack(paramaters map[string]string, template []by
fmt.Println(resp)
}

func (c *CloudFormation) DeleteStack(stack_name string) {
// DeleteStack deletes a specified Stack
//
// Example:
// // Delete a Cloudformation stack.
// svc := cloudformation.DeleteStack(stackName)
//
func (c *CloudFormation) DeleteStack(stackName string) {
params := &cloudformation.DeleteStackInput{
StackName: aws.String(stack_name),
StackName: aws.String(stackName),
}
resp, err := c.Service.DeleteStack(params)

Expand Down
23 changes: 23 additions & 0 deletions lib/aws/cloudformation/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ import (
"github.com/aws/aws-sdk-go/service/cloudformation"
)

// CloudFormation allows you to create and manage AWS infrastructure deployments
// predictably and repeatedly. You can use AWS CloudFormation to leverage AWS
// products, such as Amazon Elastic Compute Cloud, Amazon Elastic Block Store,
// Amazon Simple Notification Service, Elastic Load Balancing, and Auto Scaling
// to build highly-reliable, highly scalable, cost-effective applications without
// creating or configuring the underlying AWS infrastructure.
//
// With AWS CloudFormation, you declare all of your resources and dependencies
// in a template file. The template defines a collection of resources as a single
// unit called a stack. AWS CloudFormation creates and deletes all member resources
// of the stack together and manages all dependencies between the resources
// for you.
//
// For more information about AWS CloudFormation, see the AWS CloudFormation
// Product Page (http://aws.amazon.com/cloudformation/).
//
// Amazon CloudFormation makes use of other AWS products. For additional technical
// information about a specific AWS product, see its technical documentation
// (http://docs.aws.amazon.com/).
// The service client's operations are safe to be used concurrently.
// It is not safe to mutate any of the client's properties though.
// Please also see https://docs.aws.amazon.com/goto/WebAPI/cloudformation-2010-05-15
//
type CloudFormation struct {
AwsConfig *config.Config
Service *cloudformation.CloudFormation
Expand Down
93 changes: 58 additions & 35 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ var (
create = kingpin.Command("create", "Create EB")
// Application
createApplication = create.Command("application", "Create Application")
createApplicationNameArg = createApplication.Flag("app-name", "Application Name to create").Required().Short('a').String()
createApplicationNameArg = createApplication.Flag("app-name", "Application Name to create").Required().Short('a').Envar("APP_NAME").String()
// Environment
createEnvironment = create.Command("environment", "Create Environment")
createEnvironmentApplicationNameArg = createEnvironment.Flag("app-name", "Application Name").Required().Short('a').String()
createEnvironmentNameArg = createEnvironment.Flag("env-name", "Environment Name to create").Short('e').String()
createEnvironmentTierArg = createEnvironment.Flag("tier", "Environment Tier").Required().Short('t').String()
createEnvironmentS3Arg = createEnvironment.Flag("bucket", "S3 bucket name").Short('b').String()
createEnvironmentConfigArg = createEnvironment.Flag("config", "Config yml file").Short('c').String()
createEnvironmentVersionArg = createEnvironment.Flag("version-label", "Version").Short('l').String()
createEnvironmentLocalFilePathArg = createEnvironment.Flag("local-file-prefix", "The directory (prefix) of the file to upload.").Short('d').String()
createEnvironmentDescriptionArg = createEnvironment.Flag("desc", "Description of Version").String()
createEnvironmentApplicationNameArg = createEnvironment.Flag("app-name", "Application Name").Envar("APP_NAME").Required().Short('a').String()
createEnvironmentNameArg = createEnvironment.Flag("env-name", "Environment Name to create").Short('e').Envar("ENV_NAME").String()
createEnvironmentTierArg = createEnvironment.Flag("tier", "Environment Tier").Required().Short('t').Envar("ENV_TIER").String()
createEnvironmentS3Arg = createEnvironment.Flag("bucket", "S3 bucket name").Short('b').Envar("ENV_S3_BUCKET_LOCATION").String()
createEnvironmentConfigArg = createEnvironment.Flag("config", "Config yml file").Short('c').Envar("ENV_CONFIG_PATH").String()
createEnvironmentVersionArg = createEnvironment.Flag("version-label", "Version").Short('l').Envar("ENV_VERSION_LABEL").String()
createEnvironmentLocalFilePathArg = createEnvironment.Flag("local-file-prefix", "The directory (prefix) of the file to upload.").Short('d').Envar("ENV_LOCAL_FILE_PREFIX").String()
createEnvironmentDescriptionArg = createEnvironment.Flag("desc", "Description of Version").Envar("ENV_DESCRIPTION").String()

delete = kingpin.Command("delete", "Destroy EB")
// Application
Expand All @@ -44,30 +44,31 @@ var (

// Environment
deleteEnvironment = delete.Command("environment", "Destroy environment")
deleteEnvironmentApplicationNameArg = deleteEnvironment.Flag("app-name", "Environment's application name").Required().Short('a').String()
deleteEnvironmentNameArg = deleteEnvironment.Flag("env-name", "Environment to delete").Required().Short('e').String()
deleteEnvironmentTierArg = deleteEnvironment.Flag("tier", "Tier Name (worker | webserver)").Required().Short('t').String()
deleteEnvironmentApplicationNameArg = deleteEnvironment.Flag("app-name", "Environment's application name").Required().Short('a').Envar("APP_NAME").String()
deleteEnvironmentNameArg = deleteEnvironment.Flag("env-name", "Environment to delete").Required().Short('e').Envar("ENV_NAME").String()
deleteEnvironmentTierArg = deleteEnvironment.Flag("tier", "Tier Name (worker | webserver)").Required().Short('t').Envar("ENV_TIER").String()

update = kingpin.Command("update", "Deploy EB")
updateEnvironment = update.Command("environment", "Envrionment")
updateEnvironmentApplicationNameArg = updateEnvironment.Flag("app-name", "The Application in which the environment lives under").Required().Short('a').String()
updateEnvironmentNameArg = updateEnvironment.Flag("env-name", "Envionment name").Required().Short('e').String()
updateEnvironmentVersionArg = updateEnvironment.Flag("version-label", "Version").Required().Short('l').String()
updateEnvironmentTierArg = updateEnvironment.Flag("tier", "Environment Tier").Required().Short('t').String()
updateEnvironmentS3Arg = updateEnvironment.Flag("bucket", "S3 Bucket Name + path").Short('b').String()
updateEnvironmentLocalFilePathArg = updateEnvironment.Flag("local-file-prefix", "The directory (prefix) of the file to upload.").Short('d').String()
updateEnvironmentDescriptionArg = updateEnvironment.Flag("desc", "Description of Version").String()
updateEnvironmentApplicationNameArg = updateEnvironment.Flag("app-name", "The Application in which the environment lives under").Required().Short('a').Envar("APP_NAME").String()
updateEnvironmentNameArg = updateEnvironment.Flag("env-name", "Envionment name").Required().Short('e').Envar("ENV_NAME").String()
updateEnvironmentVersionArg = updateEnvironment.Flag("version-label", "Version").Short('l').Envar("ENV_VERSION_LABEL").String()
updateEnvironmentTierArg = updateEnvironment.Flag("tier", "Environment Tier").Required().Short('t').Envar("ENV_TIER").String()
updateEnvironmentS3Arg = updateEnvironment.Flag("bucket", "S3 Bucket Name + path").Short('b').Envar("ENV_S3_BUCKET_LOCATION").String()
updateEnvironmentLocalFilePathArg = updateEnvironment.Flag("local-file-prefix", "The directory (prefix) of the file to upload.").Short('d').Envar("ENV_LOCAL_FILE_PREFIX").String()
updateEnvironmentDescriptionArg = updateEnvironment.Flag("desc", "Description of Version").Envar("ENV_DESCRIPTION").String()
updateEnvironmentConfigArg = updateEnvironment.Flag("config", "Config yml file").Short('c').Envar("ENV_CONFIG_PATH").String()

rollback = kingpin.Command("rollback", "Rollback EB")

// General Flags
awsRegion = kingpin.Flag("region", "AWS Region").Short('r').String()
awsAccessKeyID = kingpin.Flag("access-key-id", "AWS Access Key ID").Short('k').String()
awsSecretAccessKey = kingpin.Flag("secret-access-key", "AWS Secret Access Key").Short('s').String()
awsProfile = kingpin.Flag("profile", "Aws Profile").Short('p').String()
awsCredPath = kingpin.Flag("cred-path", "Aws Cred Path").String()
awsRegion = kingpin.Flag("region", "AWS Region").Short('r').Envar("AWS_REGION").String()
awsAccessKeyID = kingpin.Flag("access-key-id", "AWS Access Key ID").Short('k').Envar("AWS_ACCESS_KEY_ID").String()
awsSecretAccessKey = kingpin.Flag("secret-access-key", "AWS Secret Access Key").Short('s').Envar("AWS_SECRET_ACCESS_KEY").String()
awsProfile = kingpin.Flag("profile", "Aws Profile").Short('p').Envar("AWS_PROFILE").String()
awsCredPath = kingpin.Flag("cred-path", "Aws Cred Path").Envar("AWS_CRED_PATH").String()

verbose = kingpin.Flag("verbose", "Verbose mode").Short('v').Bool()
verbose = kingpin.Flag("verbose", "Verbose mode").Short('v').Envar("VERBOSE_MODE").Bool()

//Command Regex Section
createRegex = regexp.MustCompile(`^create`)
Expand All @@ -77,7 +78,7 @@ var (
rollbackRegex = regexp.MustCompile(`^rollback`)

//Global Vars
cliVersion = "0.0.1"
cliVersion = "0.0.2"
)

// listFunction operation for Elastic Beanstalk Environment
Expand Down Expand Up @@ -140,6 +141,7 @@ func createFunction(createMethod string, awsConfig config.Config) {
additionalConfigOptions["AppName"] = *createEnvironmentApplicationNameArg
additionalConfigOptions["AppBucket"] = bucketInfo[0]
additionalConfigOptions["AppKey"] = bucketInfo[1] + "/" + *createEnvironmentVersionArg + ".zip"
additionalConfigOptions["VersionLabel"] = *createEnvironmentVersionArg
additionalConfigOptions["Tier"] = *createEnvironmentTierArg

configOptions := utils.GetConfig(*createEnvironmentConfigArg)
Expand Down Expand Up @@ -186,19 +188,40 @@ func updateFunction(updateMethod string, awsConfig config.Config) {

bucketInfo := s3Service.ParseS3Bucket(*updateEnvironmentS3Arg)

svc := elasticbeanstalk.New(
*updateEnvironmentApplicationNameArg, *updateEnvironmentNameArg,
*updateEnvironmentVersionArg, *updateEnvironmentDescriptionArg,
bucketInfo, "versions/"+*updateEnvironmentVersionArg+".zip",
*updateEnvironmentTierArg, awsConfig,
)

switch updateMethod {
case "update environment":
if *updateEnvironmentS3Arg != "" {
environment := utils.GetDefault(*updateEnvironmentNameArg, *updateEnvironmentApplicationNameArg)
asset, err := Asset(fmt.Sprintf("resources/cloudformation/templates/%s_v1.json", *updateEnvironmentTierArg))

if err != nil {
log.Fatalf("Asset not found: %s", err)
return
}

if *updateEnvironmentVersionArg != "" {
s3Service.UploadSingleFile(*updateEnvironmentS3Arg, *updateEnvironmentLocalFilePathArg+"/"+*updateEnvironmentVersionArg+".zip", *updateEnvironmentVersionArg)
}
svc.UpdateEnvironment()

configOptions := make(map[string]string)
configOptions["EnvName"] = environment
configOptions["AppName"] = *updateEnvironmentApplicationNameArg
if len(bucketInfo) > 0 {
configOptions["AppBucket"] = bucketInfo[0]
configOptions["AppKey"] = bucketInfo[1] + "/" + *updateEnvironmentVersionArg + ".zip"
}
configOptions["VersionLabel"] = *updateEnvironmentVersionArg
configOptions["Tier"] = *updateEnvironmentTierArg

usePreviousTemplate := true

if *updateEnvironmentConfigArg != "" {
configOptions = utils.CombineConfigOptions(utils.GetConfig(*updateEnvironmentConfigArg), configOptions)
usePreviousTemplate = false
}

cfServcie := cloudformation.New(awsConfig)

cfServcie.UpdateStack(configOptions, asset, usePreviousTemplate)
}
}

Expand Down
Loading

0 comments on commit 0afb2d9

Please sign in to comment.