Skip to content

Commit

Permalink
feat(cmd/influx): add secret cli
Browse files Browse the repository at this point in the history
  • Loading branch information
kelwang committed Feb 7, 2020
1 parent e3acd7f commit d7b3228
Show file tree
Hide file tree
Showing 9 changed files with 452 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

1. [16765](https://github.com/influxdata/influxdb/pull/16765): Extend influx cli pkg command with ability to take multiple files and directories
1. [16767](https://github.com/influxdata/influxdb/pull/16767): Extend influx cli pkg command with ability to take multiple urls, files, directories, and stdin at the same time
1. [16786](https://github.com/influxdata/influxdb/pull/16786): influx cli can manage secrets.

### Bug Fixes

Expand Down
9 changes: 4 additions & 5 deletions cmd/influx/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"time"

"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/cmd/influx/internal"
"github.com/influxdata/influxdb/http"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -108,7 +107,7 @@ func (b *cmdBucketBuilder) cmdCreateRunEFn(*cobra.Command, []string) error {
return fmt.Errorf("failed to create bucket: %v", err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name", "Retention", "OrganizationID")
w.Write(map[string]interface{}{
"ID": bkt.ID.String(),
Expand Down Expand Up @@ -152,7 +151,7 @@ func (b *cmdBucketBuilder) cmdDeleteRunEFn(cmd *cobra.Command, args []string) er
return fmt.Errorf("failed to delete bucket with id %q: %v", id, err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name", "Retention", "OrganizationID", "Deleted")
w.Write(map[string]interface{}{
"ID": bkt.ID.String(),
Expand Down Expand Up @@ -225,7 +224,7 @@ func (b *cmdBucketBuilder) cmdFindRunEFn(cmd *cobra.Command, args []string) erro
return fmt.Errorf("failed to retrieve buckets: %s", err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.HideHeaders(!b.headers)
w.WriteHeaders("ID", "Name", "Retention", "OrganizationID")
for _, b := range buckets {
Expand Down Expand Up @@ -291,7 +290,7 @@ func (b *cmdBucketBuilder) cmdUpdateRunEFn(cmd *cobra.Command, args []string) er
return fmt.Errorf("failed to update bucket: %v", err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name", "Retention", "OrganizationID")
w.Write(map[string]interface{}{
"ID": bkt.ID.String(),
Expand Down
23 changes: 16 additions & 7 deletions cmd/influx/internal/tabwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,35 @@ import (
platform "github.com/influxdata/influxdb"
)

type tabWriter struct {
// TabWriter wraps tab writer headers logic.
type TabWriter struct {
writer *tabwriter.Writer
headers []string
hideHeaders bool
}

func NewTabWriter(w io.Writer) *tabWriter {
return &tabWriter{
// NewTabWriter creates a new tab writer.
func NewTabWriter(w io.Writer) *TabWriter {
return &TabWriter{
writer: tabwriter.NewWriter(w, 0, 8, 1, '\t', 0),
}
}

func (w *tabWriter) HideHeaders(b bool) {
// HideHeaders will set the hideHeaders flag.
func (w *TabWriter) HideHeaders(b bool) {
w.hideHeaders = b
}

func (w *tabWriter) WriteHeaders(h ...string) {
// WriteHeaders will write headers.
func (w *TabWriter) WriteHeaders(h ...string) {
w.headers = h
if !w.hideHeaders {
fmt.Fprintln(w.writer, strings.Join(h, "\t"))
}
}

func (w *tabWriter) Write(m map[string]interface{}) {
// Write will write the map into embed tab writer.
func (w *TabWriter) Write(m map[string]interface{}) {
body := make([]interface{}, len(w.headers))
types := make([]string, len(w.headers))
for i, h := range w.headers {
Expand All @@ -45,7 +50,11 @@ func (w *tabWriter) Write(m map[string]interface{}) {
fmt.Fprintf(w.writer, formatString+"\n", body...)
}

func (w *tabWriter) Flush() {
// Flush should be called after the last call to Write to ensure
// that any data buffered in the Writer is written to output. Any
// incomplete escape sequence at the end is considered
// complete for formatting purposes.
func (w *TabWriter) Flush() {
w.writer.Flush()
}

Expand Down
5 changes: 5 additions & 0 deletions cmd/influx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ func (o genericCLIOpts) newCmd(use string, runE func(*cobra.Command, []string) e
return cmd
}

func (o genericCLIOpts) newTabWriter() *internal.TabWriter {
return internal.NewTabWriter(o.w)
}

func in(r io.Reader) genericCLIOptFn {
return func(o *genericCLIOpts) {
o.in = r
Expand Down Expand Up @@ -128,6 +132,7 @@ func influxCmd(opts ...genericCLIOptFn) *cobra.Command {
cmdQuery(),
cmdTranspile(),
cmdREPL(),
cmdSecret(runEWrapper),
cmdSetup(),
cmdTask(),
cmdUser(runEWrapper),
Expand Down
15 changes: 7 additions & 8 deletions cmd/influx/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/influxdata/influxdb/http"

"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/cmd/influx/internal"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -88,7 +87,7 @@ func (b *cmdOrgBuilder) createRunEFn(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to create organization: %v", err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name")
w.Write(map[string]interface{}{
"ID": org.ID.String(),
Expand Down Expand Up @@ -138,7 +137,7 @@ func (b *cmdOrgBuilder) deleteRunEFn(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to delete org with id %q: %v", id, err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name", "Deleted")
w.Write(map[string]interface{}{
"ID": o.ID.String(),
Expand Down Expand Up @@ -199,7 +198,7 @@ func (b *cmdOrgBuilder) findRunEFn(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed find orgs: %v", err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name")
for _, o := range orgs {
w.Write(map[string]interface{}{
Expand Down Expand Up @@ -269,7 +268,7 @@ func (b *cmdOrgBuilder) updateRunEFn(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to update org: %v", err)
}

w := internal.NewTabWriter(b.w)
w := b.newTabWriter()
w.WriteHeaders("ID", "Name")
w.Write(map[string]interface{}{
"ID": o.ID.String(),
Expand Down Expand Up @@ -348,7 +347,7 @@ func (b *cmdOrgBuilder) memberListRunEFn(cmd *cobra.Command, args []string) erro
}

ctx := context.Background()
return memberList(ctx, b.w, urmSVC, userSVC, influxdb.UserResourceMappingFilter{
return memberList(ctx, b, urmSVC, userSVC, influxdb.UserResourceMappingFilter{
ResourceType: influxdb.OrgsResourceType,
ResourceID: organization.ID,
UserType: influxdb.Member,
Expand Down Expand Up @@ -538,7 +537,7 @@ func newOrganizationService() (influxdb.OrganizationService, error) {
}, nil
}

func memberList(ctx context.Context, w io.Writer, urmSVC influxdb.UserResourceMappingService, userSVC influxdb.UserService, f influxdb.UserResourceMappingFilter) error {
func memberList(ctx context.Context, b *cmdOrgBuilder, urmSVC influxdb.UserResourceMappingService, userSVC influxdb.UserService, f influxdb.UserResourceMappingFilter) error {
mps, _, err := urmSVC.FindUserResourceMappings(ctx, f)
if err != nil {
return fmt.Errorf("failed to find members: %v", err)
Expand Down Expand Up @@ -582,7 +581,7 @@ func memberList(ctx context.Context, w io.Writer, urmSVC influxdb.UserResourceMa
}
}

tw := internal.NewTabWriter(w)
tw := b.newTabWriter()
tw.WriteHeaders("ID", "Name", "Status")
for _, m := range urs {
tw.Write(map[string]interface{}{
Expand Down
186 changes: 186 additions & 0 deletions cmd/influx/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package main

import (
"context"
"fmt"
"os"

"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/http"
"github.com/spf13/cobra"
input "github.com/tcnksm/go-input"
)

type secretSVCsFn func() (influxdb.SecretService, influxdb.OrganizationService, func(*input.UI) string, error)

func cmdSecret(opts ...genericCLIOptFn) *cobra.Command {
return newCmdSecretBuilder(newSecretSVCs, opts...).cmd()
}

type cmdSecretBuilder struct {
genericCLIOpts

svcFn secretSVCsFn

key string
org organization
}

func newCmdSecretBuilder(svcsFn secretSVCsFn, opts ...genericCLIOptFn) *cmdSecretBuilder {
opt := genericCLIOpts{
in: os.Stdin,
w: os.Stdout,
}
for _, o := range opts {
o(&opt)
}

return &cmdSecretBuilder{
genericCLIOpts: opt,
svcFn: svcsFn,
}
}

func (b *cmdSecretBuilder) cmd() *cobra.Command {
cmd := b.newCmd("secret", nil)
cmd.Short = "Secret management commands"
cmd.Run = seeHelp
cmd.AddCommand(
b.cmdDelete(),
b.cmdFind(),
b.cmdUpdate(),
)
return cmd
}

func (b *cmdSecretBuilder) cmdUpdate() *cobra.Command {
cmd := b.newCmd("update", b.cmdUpdateRunEFn)
cmd.Short = "Update secret"
cmd.Flags().StringVarP(&b.key, "key", "k", "", "The secret key (required)")
cmd.MarkFlagRequired("key")
b.org.register(cmd, false)

return cmd
}

func (b *cmdSecretBuilder) cmdDelete() *cobra.Command {
cmd := b.newCmd("delete", b.cmdDeleteRunEFn)
cmd.Short = "Delete secret"

cmd.Flags().StringVarP(&b.key, "key", "k", "", "The secret key (required)")
cmd.MarkFlagRequired("key")
b.org.register(cmd, false)

return cmd
}

func (b *cmdSecretBuilder) cmdUpdateRunEFn(cmd *cobra.Command, args []string) error {
scrSVC, orgSVC, getSecretFn, err := b.svcFn()
if err != nil {
return err
}
orgID, err := b.org.getID(orgSVC)
if err != nil {
return err
}

ctx := context.Background()

ui := &input.UI{
Writer: b.genericCLIOpts.w,
Reader: b.genericCLIOpts.in,
}
secret := getSecretFn(ui)

if err := scrSVC.PatchSecrets(ctx, orgID, map[string]string{
b.key: secret,
}); err != nil {
return fmt.Errorf("failed to update secret with key %q: %v", b.key, err)
}

w := b.newTabWriter()
w.WriteHeaders("Key", "OrgID", "Updated")
w.Write(map[string]interface{}{
"Key": b.key,
"OrgID": orgID,
"Updated": true,
})
w.Flush()

return nil
}

func (b *cmdSecretBuilder) cmdDeleteRunEFn(cmd *cobra.Command, args []string) error {
scrSVC, orgSVC, _, err := b.svcFn()
if err != nil {
return err
}
orgID, err := b.org.getID(orgSVC)
if err != nil {
return err
}

ctx := context.Background()
if err := scrSVC.DeleteSecret(ctx, orgID, b.key); err != nil {
return fmt.Errorf("failed to delete secret with key %q: %v", b.key, err)
}

w := b.newTabWriter()
w.WriteHeaders("Key", "OrgID", "Deleted")
w.Write(map[string]interface{}{
"Key": b.key,
"OrgID": orgID,
"Deleted": true,
})
w.Flush()

return nil
}

func (b *cmdSecretBuilder) cmdFind() *cobra.Command {
cmd := b.newCmd("find", b.cmdFindRunEFn)
cmd.Short = "Find secrets"
b.org.register(cmd, false)

return cmd
}

func (b *cmdSecretBuilder) cmdFindRunEFn(cmd *cobra.Command, args []string) error {

scrSVC, orgSVC, _, err := b.svcFn()
if err != nil {
return err
}

orgID, err := b.org.getID(orgSVC)
if err != nil {
return err
}

secrets, err := scrSVC.GetSecretKeys(context.Background(), orgID)
if err != nil {
return fmt.Errorf("failed to retrieve secret keys: %s", err)
}

w := b.newTabWriter()
w.WriteHeaders("Key", "OrganizationID")
for _, s := range secrets {
w.Write(map[string]interface{}{
"Key": s,
"OrganizationID": orgID,
})
}
w.Flush()

return nil
}

func newSecretSVCs() (influxdb.SecretService, influxdb.OrganizationService, func(*input.UI) string, error) {
httpClient, err := newHTTPClient()
if err != nil {
return nil, nil, nil, err
}
orgSvc := &http.OrganizationService{Client: httpClient}

return &http.SecretService{Client: httpClient}, orgSvc, getSecret, nil
}
Loading

0 comments on commit d7b3228

Please sign in to comment.