Skip to content

Commit

Permalink
Colorize.
Browse files Browse the repository at this point in the history
  • Loading branch information
nirdosh17 committed Aug 16, 2021
1 parent 44ae893 commit 1852ad5
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 29 deletions.
3 changes: 2 additions & 1 deletion cmd/deleteStacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cmd
import (
"fmt"

"github.com/gookit/color"
"github.com/nirdosh17/cfn-teardown/utils"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand All @@ -39,7 +40,7 @@ Supply stack pattern as: 'qa-'
return validateConfigs(config)
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Executing command: deleteStacks")
color.Red.Println("Executing command: deleteStacks")
fmt.Println()
if config.DryRun != "false" {
fmt.Println("Running in dry run mode. Set dry run to 'false' to actually delete stacks.")
Expand Down
3 changes: 2 additions & 1 deletion cmd/listDependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cmd
import (
"fmt"

"github.com/gookit/color"
"github.com/nirdosh17/cfn-teardown/utils"
"github.com/spf13/cobra"
)
Expand All @@ -40,7 +41,7 @@ Supply stack pattern as: 'qa-'
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println()
fmt.Println("Executing command: listDependencies")
color.Green.Println("Executing command: listDependencies")
fmt.Println()
// for safety
config.DryRun = "true"
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
github.com/aws/aws-sdk-go v1.40.22
github.com/gookit/color v1.4.2
github.com/mitchellh/go-homedir v1.1.0
github.com/spf13/cobra v0.0.5
github.com/spf13/viper v1.8.1
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
Expand Down Expand Up @@ -350,6 +352,8 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
63 changes: 36 additions & 27 deletions utils/deleter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"time"

"github.com/gookit/color"
. "github.com/nirdosh17/cfn-teardown/models"
)

Expand Down Expand Up @@ -59,7 +60,8 @@ func InitiateTearDown(config Config) {
UpdateNukeStats(dependencyTree)
msg := fmt.Sprintf("Unable to prepare dependencies. Error: %v", err.Error())
notifier.ErrorAlert(AlertMessage{Message: msg})
log.Fatal(msg)
color.Error.Println(msg)
os.Exit(1)
}
dependencyTree = dt // need to do this for global scope
writeToJSON(config.StackPattern, dependencyTree)
Expand All @@ -69,30 +71,29 @@ func InitiateTearDown(config Config) {

if ACTIVE_STACK_COUNT == 0 {
UpdateNukeStats(dependencyTree)
fmt.Printf("\nNo matching stacks to delete! Stack count: %v\n", TOTAL_STACK_COUNT)
color.Yellow.Printf("\nNo matching stacks to delete! Stack count: %v\n", TOTAL_STACK_COUNT)
notifier.SuccessAlert(AlertMessage{})
return
}

fmt.Println()
fmt.Println()
fmt.Printf("Following %v stacks are eligible for deletion:\n", ACTIVE_STACK_COUNT)
fmt.Printf("Following stacks are eligible for deletion | Stack count: %v\n", ACTIVE_STACK_COUNT)
for stackName, _ := range dependencyTree {
fmt.Println(" -", stackName)
color.Gray.Println(" -", stackName)
}
fmt.Println("\nCheck 'stack_teardown_details.json' file for more details.")
color.Style{color.Yellow, color.OpItalic}.Println("\nCheck 'stack_teardown_details.json' file for more details.")
fmt.Println()

// safety check for accidental run
if config.DryRun != "false" {
return
}

msg := fmt.Sprintf("Waiting for `%v minutes` before initiating deletion...", config.AbortWaitTimeMinutes)
msg := fmt.Sprintf("Waiting for `%v minutes` before starting deletion. Abort if necessary.", config.AbortWaitTimeMinutes)
notifier.StartAlert(AlertMessage{Message: msg})
fmt.Println()
fmt.Println(msg)
color.Red.Println(msg)
time.Sleep(time.Duration(config.AbortWaitTimeMinutes) * time.Minute)
fmt.Println("\n\n------------------------- Deletion Started ----------------------------------")
color.Green.Println("\n\n---------------------------- Deletion Started -------------------------------")
for {
// Algorithm:
// 1. Scan stacks who has zero importing stacks i.e. last leaf in the dependency tree
Expand All @@ -112,7 +113,8 @@ func InitiateTearDown(config Config) {
UpdateNukeStats(dependencyTree)
msg := fmt.Sprintf("Unable to empty bucket from stack '%v'", sName)
notifier.ErrorAlert(AlertMessage{Message: msg, FailedStack: stack})
log.Fatalln(msg) // abort!
color.Error.Println(msg)
os.Exit(1)
}

err := cfn.DeleteStack(sName)
Expand All @@ -121,7 +123,8 @@ func InitiateTearDown(config Config) {
msg = fmt.Sprintf("Unable to send delete request for stack '%v' Error: %v", sName, err)
stack.StackStatusReason = msg
notifier.ErrorAlert(AlertMessage{Message: msg, FailedStack: stack})
log.Fatalln(msg)
color.Error.Println(msg)
os.Exit(1)
}
stack.Status = DELETE_IN_PROGRESS
stack.DeleteStartedAt = CurrentUTCDateTime()
Expand Down Expand Up @@ -158,7 +161,8 @@ func InitiateTearDown(config Config) {
msg := fmt.Sprintf("Unable to describe stack '%v'", sName)
stack.StackStatusReason = msg
notifier.ErrorAlert(AlertMessage{Message: msg, FailedStack: stack})
log.Fatal(msg)
color.Error.Println(msg)
os.Exit(1)
}
}

Expand Down Expand Up @@ -198,7 +202,8 @@ func InitiateTearDown(config Config) {
UpdateNukeStats(dependencyTree)
msg := fmt.Sprintf("Failed to delete stack `%v`. Reason: %v", sName, statusReason)
notifier.ErrorAlert(AlertMessage{Message: msg, FailedStack: stack})
log.Fatal(msg)
color.Error.Println(msg)
os.Exit(1)
} else {
// In some cases cloud9 stacks can't be deleted due to security group being manually attached to other resources like elastic search or redis
// In such case it is better to wait for dependent resource's(mostly datastore or cache) stack and security group to get deleted and retry again
Expand All @@ -210,7 +215,8 @@ func InitiateTearDown(config Config) {
msg = fmt.Sprintf("Unable to send delete retry request for stack '%v' Error: %v", sName, err)
stack.StackStatusReason = msg
notifier.ErrorAlert(AlertMessage{Message: msg, FailedStack: stack})
log.Fatalln(msg)
color.Error.Println(msg)
os.Exit(1)
}
stack.Status = DELETE_IN_PROGRESS
stack.DeleteStartedAt = CurrentUTCDateTime()
Expand All @@ -224,17 +230,19 @@ func InitiateTearDown(config Config) {
// 5. If all stacks have already been deleted, stop execution. Else Go to step 1
if isEnvNuked(dependencyTree) {
UpdateNukeStats(dependencyTree)
fmt.Printf("\nStack Teardown Successful! Deleted Stacks: %v\n", DELETED_STACK_COUNT)
color.Green.Printf("\n---------- STACK TEARDOWN SUCCESSFUL! STACKS DELETED: (%v) ----------\n\n", DELETED_STACK_COUNT)
notifier.SuccessAlert(AlertMessage{})
break
}

// 6. Check if nuke is stuck
if isNukeStuck(dependencyTree) {
UpdateNukeStats(dependencyTree)
// TODO: better messaging
msg := "No stacks are eligible for deletion. Please find and delete stacks which do not have follow given pattern: " + config.StackPattern
notifier.StuckAlert(AlertMessage{Message: msg})
log.Fatal(msg)
color.Error.Println(msg)
os.Exit(1)
break
}
}
Expand Down Expand Up @@ -321,24 +329,25 @@ func isEnvNuked(dt map[string]StackDetails) bool {
func prepareDependencyTree(envLabel string, cfn CFNManager) (map[string]StackDetails, error) {
CFNConsoleBaseURL := "https://console.aws.amazon.com/cloudformation/home?region=" + cfn.AWSRegion + "#/stacks/stackinfo?stackId="

fmt.Printf("Listing stacks matching with '%v'...\n", envLabel)
fmt.Printf("-------------- Listing Stacks | Match Pattern: [%v] --------------\n", color.Gray.Render(envLabel))

dependencyTree, err := cfn.ListEnvironmentStacks()
totalStackCount := len(dependencyTree)

if err != nil {
UpdateNukeStats(dependencyTree)
fmt.Printf("Failed listing stacks! Error: %v\n", err)
color.Error.Printf(" Failed listing stacks! Error: %v\n", err)
return dependencyTree, err
}

fmt.Println("Listing all exports...")
color.Gray.Println(" Listing all exports...")
stackExports, err := cfn.ListEnvironmentExports()
if err != nil {
fmt.Printf("Failed listing exports! Error: %v", err)
color.Error.Printf(" Failed listing exports! Error: %v", err)
return dependencyTree, err
}

fmt.Println("Listing all imports...")
color.Gray.Println(" Listing all imports...")
stackCount := 0
var listImportErr error
for stackName, stack := range dependencyTree {
Expand All @@ -352,14 +361,14 @@ func prepareDependencyTree(envLabel string, cfn CFNManager) (map[string]StackDet
// listing all importers. making single api call at a time to avoid rate limiting
importingStacks, listImportErr := cfn.ListImports(stack.Exports)
if listImportErr != nil {
fmt.Printf("Failed listing imports! Error: %v", listImportErr)
color.Error.Printf(" Failed listing imports! Error: %v", listImportErr)
break
}

stack.ActiveImporterStacks = importingStacks
dependencyTree[stackName] = stack
stackCount++
fmt.Println("Listing imports | ", stackCount, "/", totalStackCount, " stacks complete")
color.Gray.Println(" Listing imports | ", stackCount, "/", totalStackCount, " stacks complete")
}

if listImportErr != nil {
Expand All @@ -379,7 +388,7 @@ func prepareDependencyTree(envLabel string, cfn CFNManager) (map[string]StackDet
if err != nil {
dne := strings.Contains(err.Error(), "does not exist")
if !dne {
fmt.Printf("Error describing stack %v", mStk)
color.Error.Printf(" Error describing stack %v", mStk)
break // real error.
}
dependencyTree[mStk] = StackDetails{
Expand All @@ -397,7 +406,7 @@ func prepareDependencyTree(envLabel string, cfn CFNManager) (map[string]StackDet
// list imports
importingStacks, listImportErr := cfn.ListImports(exports)
if listImportErr != nil {
fmt.Println("Failed listing imports!")
color.Error.Println(" Failed listing imports!")
break
}

Expand Down

0 comments on commit 1852ad5

Please sign in to comment.