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  }