Skip to content

Commit

Permalink
feat(pkger): add stack init cmd to influx cli
Browse files Browse the repository at this point in the history
closes: #17235
  • Loading branch information
jsteenb2 committed Mar 26, 2020
1 parent a142d11 commit 195bf41
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 85 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
1. [17363](https://github.com/influxdata/influxdb/pull/17363): Telegraf config tokens can no longer be retrieved after creation, but new tokens can be created after a telegraf has been setup
1. [17400](https://github.com/influxdata/influxdb/pull/17400): Be able to delete bucket by name via cli
1. [17396](https://github.com/influxdata/influxdb/pull/17396): Add module to write line data to specified url, org, and bucket
1. [17448](https://github.com/influxdata/influxdb/pull/17448): Add foundation for pkger stacks, stateful package management

### Bug Fixes

Expand Down
5 changes: 5 additions & 0 deletions cmd/influx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -88,6 +89,10 @@ func (o genericCLIOpts) newCmd(use string, runE func(*cobra.Command, []string) e
return cmd
}

func (o genericCLIOpts) writeJSON(v interface{}) error {
return json.NewEncoder(o.w).Encode(v)
}

func (o genericCLIOpts) newTabWriter() *internal.TabWriter {
return internal.NewTabWriter(o.w)
}
Expand Down
67 changes: 67 additions & 0 deletions cmd/influx/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ type cmdPkgBuilder struct {
file string
files []string
filters []string
description string
disableColor bool
disableTableBorders bool
json bool
name string
org organization
quiet bool
recurse bool
Expand Down Expand Up @@ -82,7 +85,9 @@ func (b *cmdPkgBuilder) cmd() *cobra.Command {
b.cmdPkgExport(),
b.cmdPkgSummary(),
b.cmdPkgValidate(),
b.cmdStack(),
)

return cmd
}

Expand Down Expand Up @@ -345,6 +350,68 @@ func (b *cmdPkgBuilder) cmdPkgValidate() *cobra.Command {
return cmd
}

func (b *cmdPkgBuilder) cmdStack() *cobra.Command {
cmd := b.newCmd("stack", nil, false)
cmd.Short = "Stack command is the container for all stack CRUD"
cmd.AddCommand(b.cmdStackInit())
return cmd
}

func (b *cmdPkgBuilder) cmdStackInit() *cobra.Command {
cmd := b.newCmd("init", b.stackInitRunEFn, true)
cmd.Short = "Initialize a stack"

cmd.Flags().StringVarP(&b.name, "stack-name", "n", "", "Name given to created stack")
cmd.Flags().StringVarP(&b.description, "stack-description", "d", "", "Description given to created stack")
cmd.Flags().StringArrayVarP(&b.urls, "package-url", "u", nil, "Package urls to pull associate with new stack")
cmd.Flags().BoolVar(&b.json, "json", false, "Output data as json")

b.org.register(cmd, false)

return cmd
}

func (b *cmdPkgBuilder) stackInitRunEFn(cmd *cobra.Command, args []string) error {
pkgSVC, orgSVC, err := b.svcFn()
if err != nil {
return err
}

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

const fakeUserID = 0 // is 0 because user is pulled from token...
stack, err := pkgSVC.InitStack(context.Background(), fakeUserID, pkger.Stack{
OrgID: orgID,
Name: b.name,
Description: b.description,
URLs: b.urls,
})
if err != nil {
return err
}

if b.json {
return b.writeJSON(stack)
}

tabW := b.newTabWriter()
tabW.WriteHeaders("ID", "OrgID", "Name", "Description", "URLs", "Created At")
tabW.Write(map[string]interface{}{
"ID": stack.ID,
"OrgID": stack.OrgID,
"Name": stack.Name,
"Description": stack.Description,
"URLs": stack.URLs,
"Created At": stack.CreatedAt,
})
tabW.Flush()

return nil
}

func (b *cmdPkgBuilder) registerPkgFileFlags(cmd *cobra.Command) {
cmd.Flags().StringSliceVarP(&b.files, "file", "f", nil, "Path to package file")
cmd.MarkFlagFilename("file", "yaml", "yml", "json", "jsonnet")
Expand Down
143 changes: 140 additions & 3 deletions cmd/influx/pkg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -447,6 +449,122 @@ func TestCmdPkg(t *testing.T) {
require.Error(t, cmd.Execute())
})
})

t.Run("stack", func(t *testing.T) {
t.Run("init", func(t *testing.T) {
tests := []struct {
name string
args []string
envVars map[string]string
expectedStack pkger.Stack
shouldErr bool
}{
{
name: "when only org and token provided is successful",
args: []string{"--org-id=" + influxdb.ID(1).String()},
expectedStack: pkger.Stack{
OrgID: 1,
},
},
{
name: "when org and name provided provided is successful",
args: []string{
"--org-id=" + influxdb.ID(1).String(),
"--stack-name=foo",
},
expectedStack: pkger.Stack{
OrgID: 1,
Name: "foo",
},
},
{
name: "when all flags provided provided is successful",
args: []string{
"--org-id=" + influxdb.ID(1).String(),
"--stack-name=foo",
"--stack-description=desc",
"--package-url=http://example.com/1",
"--package-url=http://example.com/2",
},
expectedStack: pkger.Stack{
OrgID: 1,
Name: "foo",
Description: "desc",
URLs: []string{
"http://example.com/1",
"http://example.com/2",
},
},
},
{
name: "when all shorthand flags provided provided is successful",
args: []string{
"--org-id=" + influxdb.ID(1).String(),
"-n=foo",
"-d=desc",
"-u=http://example.com/1",
"-u=http://example.com/2",
},
expectedStack: pkger.Stack{
OrgID: 1,
Name: "foo",
Description: "desc",
URLs: []string{
"http://example.com/1",
"http://example.com/2",
},
},
},
}

for _, tt := range tests {
fn := func(t *testing.T) {
defer addEnvVars(t, envVarsZeroMap)()

outBuf := new(bytes.Buffer)
defer func() {
if t.Failed() && outBuf.Len() > 0 {
t.Log(outBuf.String())
}
}()

builder := newInfluxCmdBuilder(
in(new(bytes.Buffer)),
out(outBuf),
)

rootCmd := builder.cmd(func(f *globalFlags, opt genericCLIOpts) *cobra.Command {
echoSVC := &fakePkgSVC{
initStackFn: func(ctx context.Context, userID influxdb.ID, stack pkger.Stack) (pkger.Stack, error) {
stack.ID = 9000
return stack, nil
},
}
return newCmdPkgBuilder(fakeSVCFn(echoSVC), opt).cmd()
})

baseArgs := []string{"pkg", "stack", "init", "--json"}

rootCmd.SetArgs(append(baseArgs, tt.args...))

err := rootCmd.Execute()
if tt.shouldErr {
require.Error(t, err)
} else {
require.NoError(t, err)
var stack pkger.Stack
testDecodeJSONBody(t, outBuf, &stack)
if tt.expectedStack.ID == 0 {
tt.expectedStack.ID = 9000
}
assert.Equal(t, tt.expectedStack, stack)
}
}

t.Run(tt.name, fn)
}
})
})
}

func Test_readFilesFromPath(t *testing.T) {
Expand Down Expand Up @@ -586,12 +704,16 @@ func testPkgWritesToBuffer(newCmdFn func(w io.Writer) *cobra.Command, args pkgFi
}

type fakePkgSVC struct {
createFn func(ctx context.Context, setters ...pkger.CreatePkgSetFn) (*pkger.Pkg, error)
dryRunFn func(ctx context.Context, orgID, userID influxdb.ID, pkg *pkger.Pkg) (pkger.Summary, pkger.Diff, error)
applyFn func(ctx context.Context, orgID, userID influxdb.ID, pkg *pkger.Pkg, opts ...pkger.ApplyOptFn) (pkger.Summary, error)
initStackFn func(ctx context.Context, userID influxdb.ID, stack pkger.Stack) (pkger.Stack, error)
createFn func(ctx context.Context, setters ...pkger.CreatePkgSetFn) (*pkger.Pkg, error)
dryRunFn func(ctx context.Context, orgID, userID influxdb.ID, pkg *pkger.Pkg) (pkger.Summary, pkger.Diff, error)
applyFn func(ctx context.Context, orgID, userID influxdb.ID, pkg *pkger.Pkg, opts ...pkger.ApplyOptFn) (pkger.Summary, error)
}

func (f *fakePkgSVC) InitStack(ctx context.Context, userID influxdb.ID, stack pkger.Stack) (pkger.Stack, error) {
if f.initStackFn != nil {
return f.initStackFn(ctx, userID, stack)
}
panic("not implemented")
}

Expand Down Expand Up @@ -639,3 +761,18 @@ func idsStr(ids ...influxdb.ID) string {
}
return strings.Join(idStrs, ",")
}

func testNewURL(t *testing.T, rawurl string) url.URL {
t.Helper()

u, err := url.Parse(rawurl)
require.NoError(t, err)
return *u
}

func testDecodeJSONBody(t *testing.T, r io.Reader, v interface{}) {
t.Helper()

err := json.NewDecoder(r).Decode(v)
require.NoError(t, err)
}
12 changes: 6 additions & 6 deletions cmd/influxd/launcher/pkger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@ func TestLauncher_Pkger(t *testing.T) {
svc := l.PkgerService(t)

t.Run("creating a stack", func(t *testing.T) {
expectedURLs := []url.URL{newURL(t, "http://example.com")}
expectedURLs := []string{"http://example.com"}

fmt.Println("org init id: ", l.Org.ID)

newStack, err := svc.InitStack(timedCtx(5*time.Second), l.User.ID, pkger.Stack{
OrgID: l.Org.ID,
Name: "first stack",
Desc: "desc",
URLs: expectedURLs,
OrgID: l.Org.ID,
Name: "first stack",
Description: "desc",
URLs: expectedURLs,
})
require.NoError(t, err)

assert.NotZero(t, newStack.ID)
assert.Equal(t, l.Org.ID, newStack.OrgID)
assert.Equal(t, "first stack", newStack.Name)
assert.Equal(t, "desc", newStack.Desc)
assert.Equal(t, "desc", newStack.Description)
assert.Equal(t, expectedURLs, newStack.URLs)
assert.NotNil(t, newStack.Resources)
assert.NotZero(t, newStack.CRUDLog)
Expand Down
24 changes: 7 additions & 17 deletions pkger/http_remote_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net/http"
"net/url"

"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/pkg/httpc"
Expand All @@ -21,10 +20,8 @@ func (s *HTTPRemoteService) InitStack(ctx context.Context, userID influxdb.ID, s
reqBody := ReqCreateStack{
OrgID: stack.OrgID.String(),
Name: stack.Name,
Description: stack.Desc,
}
for _, u := range stack.URLs {
reqBody.URLs = append(reqBody.URLs, u.String())
Description: stack.Description,
URLs: stack.URLs,
}

var respBody RespCreateStack
Expand All @@ -37,10 +34,11 @@ func (s *HTTPRemoteService) InitStack(ctx context.Context, userID influxdb.ID, s
}

newStack := Stack{
Name: respBody.Name,
Desc: respBody.Description,
Resources: make([]StackResource, 0),
CRUDLog: respBody.CRUDLog,
Name: respBody.Name,
Description: respBody.Description,
URLs: respBody.URLs,
Resources: make([]StackResource, 0),
CRUDLog: respBody.CRUDLog,
}

id, err := influxdb.IDFromString(respBody.ID)
Expand All @@ -57,14 +55,6 @@ func (s *HTTPRemoteService) InitStack(ctx context.Context, userID influxdb.ID, s
}
newStack.OrgID = *orgID

for _, rawurl := range respBody.URLs {
u, err := url.Parse(rawurl)
if err != nil {
return Stack{}, err
}
newStack.URLs = append(newStack.URLs, *u)
}

return newStack, nil
}

Expand Down
Loading

0 comments on commit 195bf41

Please sign in to comment.