diff --git a/clients/config/config.go b/clients/config/config.go index 2644aa4..47b697b 100644 --- a/clients/config/config.go +++ b/clients/config/config.go @@ -94,6 +94,18 @@ func (c Client) Update(cfg config.Config) error { return c.printConfigs(configPrintOpts{config: &cfg}) } +func (c Client) UpdateWithUserPass(cfg config.Config, userPass string) error { + if userPass != "" && cfg.Token != "" { + return fmt.Errorf("token and username-password cannot be specified together, please choose just one") + } + + if cfg.Token == "" && userPass != "" { + cfg.Cookie = base64.StdEncoding.EncodeToString([]byte(userPass)) + } + + return c.Update(cfg) +} + func (c Client) List() error { cfgs, err := c.ConfigService.ListConfigs() if err != nil { diff --git a/clients/config/config_test.go b/clients/config/config_test.go index 789364a..df06b22 100644 --- a/clients/config/config_test.go +++ b/clients/config/config_test.go @@ -2,6 +2,7 @@ package config_test import ( "bytes" + "encoding/base64" "fmt" "strings" "testing" @@ -72,27 +73,58 @@ func TestClient_PrintActive(t *testing.T) { func TestClient_Create(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - stdio := mock.NewMockStdIO(ctrl) - writtenBytes := bytes.Buffer{} - stdio.EXPECT().Write(gomock.Any()).DoAndReturn(writtenBytes.Write).AnyTimes() - - cfg := config.Config{ - Name: "foo", - Active: true, - Host: "http://localhost:8086", - Token: "supersecret", - Org: "me", + testCases := []struct { + name string + cfg config.Config + err error + }{ + { + name: "token", + cfg: config.Config{ + Name: "foo", + Active: true, + Host: "http://localhost:8086", + Token: "supersecret", + Org: "me", + }, + err: nil, + }, + { + name: "userpass", + cfg: config.Config{ + Name: "foo", + Active: true, + Host: "http://localhost:8086", + Cookie: base64.StdEncoding.EncodeToString([]byte("user:pass")), + Org: "me", + }, + err: nil, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + ctrl := gomock.NewController(t) + stdio := mock.NewMockStdIO(ctrl) + writtenBytes := bytes.Buffer{} + stdio.EXPECT().Write(gomock.Any()).DoAndReturn(writtenBytes.Write).AnyTimes() + + cfg := tc.cfg + svc := mock.NewMockConfigService(ctrl) + svc.EXPECT().CreateConfig(cfg).Return(cfg, nil) + + cli := cmd.Client{CLI: clients.CLI{ConfigService: svc, StdIO: stdio}} + err := cli.Create(cfg) + require.NoError(t, err) + testutils.MatchLines(t, []string{ + `Active\s+Name\s+URL\s+Org`, + fmt.Sprintf(`\*\s+%s\s+%s\s+%s`, cfg.Name, cfg.Host, cfg.Org), + }, strings.Split(writtenBytes.String(), "\n")) + }) } - svc := mock.NewMockConfigService(ctrl) - svc.EXPECT().CreateConfig(cfg).Return(cfg, nil) - cli := cmd.Client{CLI: clients.CLI{ConfigService: svc, StdIO: stdio}} - require.NoError(t, cli.Create(cfg)) - testutils.MatchLines(t, []string{ - `Active\s+Name\s+URL\s+Org`, - fmt.Sprintf(`\*\s+%s\s+%s\s+%s`, cfg.Name, cfg.Host, cfg.Org), - }, strings.Split(writtenBytes.String(), "\n")) } func TestClient_Delete(t *testing.T) { @@ -165,32 +197,67 @@ func TestClient_Delete(t *testing.T) { func TestClient_Update(t *testing.T) { t.Parallel() - ctrl := gomock.NewController(t) - stdio := mock.NewMockStdIO(ctrl) - writtenBytes := bytes.Buffer{} - stdio.EXPECT().Write(gomock.Any()).DoAndReturn(writtenBytes.Write).AnyTimes() - - updates := config.Config{ - Name: "foo", - Active: true, - Token: "doublesecret", + testCases := []struct { + name string + updates config.Config + cfg config.Config + err error + }{ + { + name: "token", + updates: config.Config{ + Name: "foo", + Active: true, + Token: "doublesecret", + }, + cfg: config.Config{ + Name: "foo", + Active: true, + Host: "http://localhost:8086", + Token: "doublesecret", + Org: "me", + }, + err: nil, + }, + { + name: "userpass", + updates: config.Config{ + Name: "foo", + Active: true, + Cookie: base64.StdEncoding.EncodeToString([]byte("user:pass")), + }, + cfg: config.Config{ + Name: "foo", + Active: true, + Host: "http://localhost:8086", + Cookie: base64.StdEncoding.EncodeToString([]byte("user:pass")), + Org: "me", + }, + err: nil, + }, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + ctrl := gomock.NewController(t) + stdio := mock.NewMockStdIO(ctrl) + writtenBytes := bytes.Buffer{} + stdio.EXPECT().Write(gomock.Any()).DoAndReturn(writtenBytes.Write).AnyTimes() + + svc := mock.NewMockConfigService(ctrl) + svc.EXPECT().UpdateConfig(tc.updates).Return(tc.cfg, nil) + + cli := cmd.Client{CLI: clients.CLI{ConfigService: svc, StdIO: stdio}} + require.NoError(t, cli.Update(tc.updates)) + testutils.MatchLines(t, []string{ + `Active\s+Name\s+URL\s+Org`, + fmt.Sprintf(`\*\s+%s\s+%s\s+%s`, tc.cfg.Name, tc.cfg.Host, tc.cfg.Org), + }, strings.Split(writtenBytes.String(), "\n")) + }) } - cfg := config.Config{ - Name: updates.Name, - Active: updates.Active, - Host: "http://localhost:8086", - Token: updates.Token, - Org: "me", - } - svc := mock.NewMockConfigService(ctrl) - svc.EXPECT().UpdateConfig(updates).Return(cfg, nil) - cli := cmd.Client{CLI: clients.CLI{ConfigService: svc, StdIO: stdio}} - require.NoError(t, cli.Update(updates)) - testutils.MatchLines(t, []string{ - `Active\s+Name\s+URL\s+Org`, - fmt.Sprintf(`\*\s+%s\s+%s\s+%s`, cfg.Name, cfg.Host, cfg.Org), - }, strings.Split(writtenBytes.String(), "\n")) } func TestClient_List(t *testing.T) { diff --git a/cmd/influx/config.go b/cmd/influx/config.go index 27a4505..2813158 100644 --- a/cmd/influx/config.go +++ b/cmd/influx/config.go @@ -174,6 +174,7 @@ https://docs.influxdata.com/influxdb/latest/reference/cli/influx/config/rm/ func newConfigUpdateCmd() cli.Command { var cfg config.Config + var userpass string return cli.Command{ Name: "set", Aliases: []string{"update"}, @@ -213,6 +214,11 @@ https://docs.influxdata.com/influxdb/latest/reference/cli/influx/config/set/ Usage: "New auth token to set on the config", Destination: &cfg.Token, }, + &cli.StringFlag{ + Name: "username-password, p", + Usage: "Username (and optionally password) to use for authentication. Only supported in OSS", + Destination: &userpass, + }, &cli.StringFlag{ Name: "org, o", Usage: "New default organization to set on the config", @@ -225,7 +231,13 @@ https://docs.influxdata.com/influxdb/latest/reference/cli/influx/config/set/ }, ), Action: func(ctx *cli.Context) error { + if cfg.Token != "" && userpass != "" { + return fmt.Errorf("cannot specify `--token` and `--username-password` together, please choose one") + } client := cmd.Client{CLI: getCLI(ctx)} + if userpass != "" { + return client.UpdateWithUserPass(cfg, userpass) + } return client.Update(cfg) }, } diff --git a/config/local.go b/config/local.go index a40faea..bb4e594 100644 --- a/config/local.go +++ b/config/local.go @@ -124,6 +124,11 @@ func (svc localConfigsSVC) UpdateConfig(up Config) (Config, error) { } if up.Token != "" { p0.Token = up.Token + p0.Cookie = "" + } + if up.Cookie != "" { + p0.Token = "" + p0.Cookie = up.Cookie } if up.Host != "" { p0.Host = up.Host