github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/internal/cli/stack/stack.go (about) 1 package stack 2 3 import ( 4 "fmt" 5 6 "github.com/pkg/errors" 7 "github.com/tj/kingpin" 8 "github.com/tj/survey" 9 10 "github.com/apex/up/internal/cli/root" 11 "github.com/apex/up/internal/stats" 12 "github.com/apex/up/internal/util" 13 ) 14 15 func init() { 16 cmd := root.Command("stack", "Stack resource management.") 17 18 cmd.Example(`up stack`, "Show status of the stack resources.") 19 cmd.Example(`up stack plan`, "Show resource changes.") 20 cmd.Example(`up stack apply`, "Apply resource changes.") 21 cmd.Example(`up stack delete`, "Delete the stack resources.") 22 23 plan(cmd) 24 apply(cmd) 25 delete(cmd) 26 status(cmd) 27 } 28 29 // plan changes. 30 func plan(cmd *kingpin.Cmd) { 31 c := cmd.Command("plan", "Plan configuration changes.") 32 c.Example(`up stack plan`, "Show changes planned.") 33 34 c.Action(func(_ *kingpin.ParseContext) error { 35 c, p, err := root.Init() 36 if err != nil { 37 return errors.Wrap(err, "initializing") 38 } 39 40 stats.Track("Plan Stack", nil) 41 region := c.Regions[0] 42 43 ok, err := p.Exists(region) 44 if err != nil { 45 return errors.Wrap(err, "checking if app exists") 46 } 47 48 if !ok { 49 return errors.New("Application does not exist, please run `$ up` initially to create it.") 50 } 51 52 // TODO: multi-region 53 return p.PlanStack(region) 54 }) 55 } 56 57 // apply changes. 58 func apply(cmd *kingpin.Cmd) { 59 c := cmd.Command("apply", "Apply configuration changes.") 60 c.Example(`up stack apply`, "Apply the changes of the previous plan.") 61 62 c.Action(func(_ *kingpin.ParseContext) error { 63 c, p, err := root.Init() 64 if err != nil { 65 return errors.Wrap(err, "initializing") 66 } 67 68 stats.Track("Apply Stack", map[string]interface{}{ 69 "dns_zone_count": len(c.DNS.Zones), 70 "stage_count": len(c.Stages.List()), 71 "stage_domain_count": len(c.Stages.Domains()), 72 "alerts_count": len(c.Alerts), 73 "actions_count": len(c.Actions), 74 }) 75 76 // TODO: multi-region 77 return p.ApplyStack(c.Regions[0]) 78 }) 79 } 80 81 // delete resources. 82 func delete(cmd *kingpin.Cmd) { 83 c := cmd.Command("delete", "Delete configured resources.") 84 c.Example(`up stack delete`, "Delete stack with confirmation prompt.") 85 c.Example(`up stack delete --force`, "Delete stack without confirmation prompt.") 86 c.Example(`up stack delete --async`, "Don't wait for deletion to complete.") 87 c.Example(`up stack delete -fa`, "Force asynchronous deletion.") 88 89 force := c.Flag("force", "Skip the confirmation prompt.").Short('f').Bool() 90 async := c.Flag("async", "Perform deletion asynchronously.").Short('a').Bool() 91 92 c.Action(func(_ *kingpin.ParseContext) error { 93 c, p, err := root.Init() 94 if err != nil { 95 return errors.Wrap(err, "initializing") 96 } 97 98 wait := !*async 99 defer util.Pad()() 100 101 stats.Track("Delete Stack", map[string]interface{}{ 102 "force": *force, 103 "wait": wait, 104 }) 105 106 if *force { 107 // TODO: multi-region 108 return p.DeleteStack(c.Regions[0], wait) 109 } 110 111 prompt := &survey.Confirm{ 112 Message: fmt.Sprintf("Really destroy stack %q?", c.Name), 113 } 114 115 var ok bool 116 if err := survey.AskOne(prompt, &ok, nil); err != nil { 117 return err 118 } 119 120 if !ok { 121 util.LogPad("Aborted") 122 return nil 123 } 124 125 return p.DeleteStack(c.Regions[0], wait) 126 }) 127 } 128 129 // status of the stack. 130 func status(cmd *kingpin.Cmd) { 131 c := cmd.Command("status", "Show status of resources.").Default() 132 133 c.Action(func(_ *kingpin.ParseContext) error { 134 c, p, err := root.Init() 135 if err != nil { 136 return errors.Wrap(err, "initializing") 137 } 138 139 stats.Track("Show Stack", nil) 140 141 // TODO: multi-region 142 return p.ShowStack(c.Regions[0]) 143 }) 144 }