Skip to content

Commit

Permalink
Cluster creation/deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
ipmb committed Dec 14, 2020
1 parent 8ce0000 commit dac85e2
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 8 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/functional_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
-
name: Create cluster
run: ./apppack create cluster --domain testclusters.apppack.io --hosted-zone-id Z05906472T84V7X7Q6UDY
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
-
name: Destroy cluster
run: yes yes | ./apppack destroy cluster apppack
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
-
name: Destroy account
run: yes yes | ./apppack destroy account
Expand Down
89 changes: 89 additions & 0 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,91 @@ var accountCmd = &cobra.Command{
},
}

// createClusterCmd represents the create command
var createClusterCmd = &cobra.Command{
Use: "cluster",
Short: "Setup resources for an AppPack cluster",
Long: `Setup resources for an AppPack cluster`,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
answers, err := askForMissingArgs(cmd, nil)
var clusterName string
if len(args) == 0 {
clusterName = "apppack"
} else {
clusterName = args[0]
}
checkErr(err)
sess := session.Must(session.NewSession())
_, err = stackOutputFromDDBItem(sess, fmt.Sprintf("CLUSTER#%s", clusterName))
if err == nil {
checkErr(fmt.Errorf("cluster %s already exists", clusterName))
}
if createChangeSet {
fmt.Println("Creating Cloudformation Change Set for cluster resources...")
} else {
fmt.Println("Creating cluster resources...")
}
startSpinner()
cfnTags := []*cloudformation.Tag{
{Key: aws.String("paaws:cluster"), Value: &clusterName},
{Key: aws.String("paaws"), Value: aws.String("true")},
}

input := cloudformation.CreateStackInput{
StackName: aws.String(fmt.Sprintf("apppack-cluster-%s", clusterName)),
TemplateURL: aws.String(clusterFormationURL),
Parameters: []*cloudformation.Parameter{
{
ParameterKey: aws.String("Name"),
ParameterValue: &clusterName,
},
{
ParameterKey: aws.String("AvailabilityZones"),
ParameterValue: aws.String(strings.Join(
[]string{fmt.Sprintf("%sa", *sess.Config.Region), fmt.Sprintf("%sb", *sess.Config.Region), fmt.Sprintf("%sc", *sess.Config.Region)},
",",
)),
},
{
ParameterKey: aws.String("Domain"),
ParameterValue: getArgValue(cmd, answers, "domain"),
},
{
ParameterKey: aws.String("HostedZone"),
ParameterValue: getArgValue(cmd, answers, "hosted-zone-id"),
},
},
Capabilities: []*string{aws.String("CAPABILITY_IAM")},
Tags: cfnTags,
}
var statusURL string
if createChangeSet {
changeSet, err := createChangeSetAndWait(sess, &input)
Spinner.Stop()
checkErr(err)
statusURL = fmt.Sprintf("https://console.aws.amazon.com/cloudformation/home#/stacks/events?stackId=%s", url.QueryEscape(*changeSet.ChangeSetId))
if *changeSet.Status != "CREATE_COMPLETE" {
checkErr(fmt.Errorf("Stack ChangeSet creation Failed.\nView status at %s", statusURL))
} else {
fmt.Println("View ChangeSet at:")
fmt.Println(aurora.White(statusURL))
}
} else {
stack, err := createStackAndWait(sess, &input)
Spinner.Stop()
checkErr(err)
statusURL := fmt.Sprintf("https://console.aws.amazon.com/cloudformation/home#/stacks/events?stackId=%s", url.QueryEscape(*stack.Stacks[0].StackId))
if *stack.Stacks[0].StackStatus != "CREATE_COMPLETE" {
checkErr(fmt.Errorf("Stack creation Failed.\nView status at %s", statusURL))
} else {
printSuccess(fmt.Sprintf("AppPack cluster %s created", clusterName))
}
}

},
}

// appCmd represents the create command
var appCmd = &cobra.Command{
Use: "app",
Expand Down Expand Up @@ -702,4 +787,8 @@ func init() {
appCmd.Flags().Bool("addon-ses", false, "Setup SES (Email) add-on (requires manual approval of domain at SES)")
appCmd.Flags().String("addon-ses-domain", "*", "Domain approved for sending via SES add-on. Use '*' for all domains.")
appCmd.Flags().StringSliceP("users", "u", []string{}, "Email addresses for users who can manage the app (comma separated)")

createCmd.AddCommand(createClusterCmd)
createClusterCmd.Flags().StringP("domain", "d", "", "parent domain for apps in the cluster")
createClusterCmd.Flags().StringP("hosted-zone-id", "z", "", "AWS Route53 Hosted Zone ID for domain")
}
27 changes: 19 additions & 8 deletions cmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,28 +94,39 @@ var destroyClusterCmd = &cobra.Command{
clusterName := args[0]
startSpinner()
sess := session.Must(session.NewSession())
stackOutput, err := stackOutputFromDDBItem(sess, fmt.Sprintf("CLUSTER#%s", clusterName))
checkErr(err)
stackID := (*stackOutput)["stack_id"]
stackName := fmt.Sprintf("apppack-cluster-%s", clusterName)
cfnSvc := cloudformation.New(sess)
_, err = cfnSvc.DescribeStacks(&cloudformation.DescribeStacksInput{
StackName: stackID,
stackOutput, err := cfnSvc.DescribeStacks(&cloudformation.DescribeStacksInput{
StackName: &stackName,
})
stackID := *stackOutput.Stacks[0].StackId
checkErr(err)
Spinner.Stop()
var confirm string
fmt.Printf("Are you sure you want to delete your AppPack Cluster %s\n%s? yes/[%s]\n", clusterName, aurora.Faint(*stackID), aurora.Bold("no"))
fmt.Printf("Are you sure you want to delete your AppPack Cluster %s\n%s? yes/[%s]\n", clusterName, aurora.Faint(stackID), aurora.Bold("no"))
fmt.Scanln(&confirm)
if confirm != "yes" {
checkErr(fmt.Errorf("aborting due to user input"))
}
startSpinner()
_, err = cfnSvc.DeleteStack(&cloudformation.DeleteStackInput{
StackName: stackID,
StackName: &stackID,
})
checkErr(err)
err = cfnSvc.WaitUntilStackDeleteComplete(&cloudformation.DescribeStacksInput{
StackName: &stackID,
})
// EC2 instances don't get removed in time to delete the ECS cluster
if err != nil {
printWarning("cluster deletion did not complete successfully, retrying...")
}
startSpinner()
_, err = cfnSvc.DeleteStack(&cloudformation.DeleteStackInput{
StackName: &stackID,
})
checkErr(err)
err = cfnSvc.WaitUntilStackDeleteComplete(&cloudformation.DescribeStacksInput{
StackName: stackID,
StackName: &stackID,
})
checkErr(err)
Spinner.Stop()
Expand Down
5 changes: 5 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func checkErr(err error) {
if err == nil {
return
}
Spinner.Stop()
printError(fmt.Sprintf("%v", err))
os.Exit(1)
}
Expand All @@ -78,3 +79,7 @@ func printError(text string) {
func printSuccess(text string) {
fmt.Println(aurora.Green(fmt.Sprintf("✔ %s", text)))
}

func printWarning(text string) {
fmt.Println(aurora.Yellow(fmt.Sprintf("⚠ %s", text)))
}

0 comments on commit dac85e2

Please sign in to comment.