github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/internal/cli/env/env.go (about) 1 package env 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/pkg/errors" 8 "github.com/tj/kingpin" 9 10 "github.com/apex/up" 11 "github.com/apex/up/internal/cli/root" 12 "github.com/apex/up/internal/colors" 13 "github.com/apex/up/internal/secret" 14 "github.com/apex/up/internal/stats" 15 "github.com/apex/up/internal/table" 16 "github.com/apex/up/internal/util" 17 "github.com/apex/up/internal/validate" 18 ) 19 20 func init() { 21 cmd := root.Command("env", "Manage encrypted env variables.") 22 cmd.Example(`up env`, "List variables available to all stages.") 23 cmd.Example(`up env -d`, "List decrypted values.") 24 cmd.Example(`up env add FOO=bar BAR=baz`, "Add multiple variables.") 25 cmd.Example(`up env add MONGO_URL="mongodb://db1.example.net:2500/" -s production`, "Add a production env variable.") 26 cmd.Example(`up env add MONGO_URL="mongodb://db2.example.net:2500/" -s staging`, "Add a staging env variable.") 27 cmd.Example(`up env add S3_KEY=xxxxxxx`, "Add add a global env variable for all stages.") 28 cmd.Example(`up env add S3_KEY=xxxxxxx -s production`, "Add a stage specific env var to override the previous.") 29 cmd.Example(`up env add -c DB_USER=tobi`, "Add a cleartext env var.") 30 cmd.Example(`up env add -d 'Mongo password' DB_PASS=xxxxxxx`, "Add a description.") 31 cmd.Example(`up env get DB_URL`, "Get a variable value.") 32 cmd.Example(`up env rm S3_KEY`, "Remove a variable.") 33 cmd.Example(`up env rm S3_KEY -s production`, "Remove a production variable.") 34 cmd.Example(`up env rm FOO BAR BAZ`, "Remove many variables.") 35 add(cmd) 36 get(cmd) 37 list(cmd) 38 remove(cmd) 39 } 40 41 // get variables. 42 func get(cmd *kingpin.Cmd) { 43 c := cmd.Command("get", "Get a variable value.") 44 key := c.Arg("name", "Variable name.").Required().String() 45 stage := c.Flag("stage", "Target stage name.").Short('s').Default("all").String() 46 47 c.Action(func(_ *kingpin.ParseContext) error { 48 c, p, err := root.Init() 49 if err != nil { 50 return errors.Wrap(err, "initializing") 51 } 52 53 stages := append(c.Stages.Names(), "all") 54 if err := validate.List(*stage, stages); err != nil { 55 return err 56 } 57 normalizeStage(stage) 58 59 stats.Track("Get Secret", nil) 60 61 v, err := p.Secrets(*stage).Get(*key) 62 if err != nil { 63 return errors.Wrap(err, "listing secrets") 64 } 65 66 fmt.Printf("%s", v) 67 68 return nil 69 }) 70 } 71 72 // list variables. 73 func list(cmd *kingpin.Cmd) { 74 c := cmd.Command("ls", "List variables.").Alias("list").Default() 75 decrypt := c.Flag("decrypt", "Output decrypted values.").Short('d').Bool() 76 77 c.Action(func(_ *kingpin.ParseContext) error { 78 c, p, err := root.Init() 79 if err != nil { 80 return errors.Wrap(err, "initializing") 81 } 82 83 stats.Track("List Secrets", map[string]interface{}{ 84 "decrypt": *decrypt, 85 }) 86 87 secrets, err := p.Secrets("").List(*decrypt) 88 if err != nil { 89 return errors.Wrap(err, "listing secrets") 90 } 91 92 if len(secrets) == 0 { 93 util.LogPad("No environment variables defined. See `up help env` for examples.") 94 return nil 95 } 96 97 grouped := secret.GroupByStage(secrets) 98 t := table.New() 99 100 stages := append([]string{"all"}, c.Stages.Names()...) 101 for _, name := range stages { 102 secrets, ok := grouped[name] 103 if !ok { 104 continue 105 } 106 107 t.AddRow(table.Row{ 108 { 109 Text: colors.Bold(fmt.Sprintf("\n%s\n", strings.Title(name))), 110 Span: 4, 111 }, 112 }) 113 114 rows(t, secrets) 115 } 116 117 t.Println() 118 println() 119 120 return nil 121 }) 122 } 123 124 // add variables. 125 func add(cmd *kingpin.Cmd) { 126 c := cmd.Command("add", "Add variables.").Alias("set") 127 vars := c.Arg("env", "Environment variables list.").Required().Strings() 128 stage := c.Flag("stage", "Target stage name.").Short('s').Default("all").String() 129 desc := c.Flag("desc", "Variable description message.").Short('d').String() 130 clear := c.Flag("clear", "Store as cleartext (unencrypted).").Short('c').Bool() 131 132 c.Action(func(_ *kingpin.ParseContext) error { 133 c, p, err := root.Init() 134 if err != nil { 135 return errors.Wrap(err, "initializing") 136 } 137 138 // normalize stage 139 stages := append(c.Stages.Names(), "all") 140 if err := validate.List(*stage, stages); err != nil { 141 return err 142 } 143 normalizeStage(stage) 144 145 // parse vars 146 m, err := util.ParseEnviron(*vars) 147 if err != nil { 148 return errors.Wrap(err, "parsing environment variables") 149 } 150 151 defer util.Pad()() 152 153 // define vars 154 for k, v := range m { 155 stats.Track("Add Secret", map[string]interface{}{ 156 "cleartext": *clear, 157 "stage": *stage, 158 "has_desc": *desc != "", 159 }) 160 161 if err := p.Secrets(*stage).Add(k, v, *desc, *clear); err != nil { 162 return errors.Wrap(err, "adding secret") 163 } 164 165 util.Log("Added " + k) 166 } 167 168 return nil 169 }) 170 } 171 172 // remove variables. 173 func remove(cmd *kingpin.Cmd) { 174 c := cmd.Command("rm", "Remove variables.").Alias("remove") 175 stage := c.Flag("stage", "Target stage name.").Short('s').Default("all").String() 176 vars := c.Arg("env", "Environment variables list.").Required().Strings() 177 178 c.Action(func(_ *kingpin.ParseContext) error { 179 defer util.Pad()() 180 181 c, p, err := root.Init() 182 if err != nil { 183 return errors.Wrap(err, "initializing") 184 } 185 186 stages := append(c.Stages.Names(), "all") 187 if err := validate.List(*stage, stages); err != nil { 188 return err 189 } 190 normalizeStage(stage) 191 192 defer util.Pad()() 193 194 for _, name := range *vars { 195 stats.Track("Remove Secret", nil) 196 197 if err := p.Secrets(*stage).Remove(name); err != nil { 198 return errors.Wrap(err, "removing secret") 199 } 200 201 util.Log("Removed " + name) 202 } 203 204 return nil 205 }) 206 } 207 208 // rows helper. 209 func rows(t *table.Table, secrets []*up.Secret) { 210 for _, s := range secrets { 211 mod := fmt.Sprintf("Modified %s", util.RelativeDate(s.LastModified)) 212 if u := s.LastModifiedUser; u != "" { 213 mod += fmt.Sprintf(" by %s", u) 214 } 215 desc := colors.Gray(util.DefaultString(&s.Description, "-")) 216 val := colors.Gray(util.DefaultString(&s.Value, "-")) 217 218 t.AddRow(table.Row{ 219 { 220 Text: colors.Purple(s.Name), 221 }, 222 { 223 Text: val, 224 }, 225 { 226 Text: desc, 227 }, 228 { 229 Text: mod, 230 }, 231 }) 232 } 233 } 234 235 // normalizeStage normalizes "all" which is internally represented as "". 236 func normalizeStage(s *string) { 237 if *s == "all" { 238 *s = "" 239 } 240 }