Skip to content

Commit

Permalink
feat(influx): extend stacks update cmd with ability to add resources
Browse files Browse the repository at this point in the history
  • Loading branch information
jsteenb2 committed Jun 29, 2020
1 parent c93408d commit 2f2140e
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 126 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## v2.0.0-beta.14 [unreleased]

### Features

1. [18758](https://github.com/influxdata/influxdb/pull/18758): Extend influx stacks update cmd with ability to add resources without apply template

### Bug Fixes

## v2.0.0-beta.13 [2020-06-25]
Expand Down
143 changes: 106 additions & 37 deletions cmd/influx/pkg.go → cmd/influx/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ type cmdPkgBuilder struct {
telegrafs string
variables string
}

updateStackOpts struct {
addResources []string
}
}

func newCmdPkgBuilder(svcFn pkgSVCsFn, f *globalFlags, opts genericCLIOpts) *cmdPkgBuilder {
Expand Down Expand Up @@ -410,17 +414,10 @@ func (b *cmdPkgBuilder) exportRunEFn(cmd *cobra.Command, args []string) error {
}

if b.exportOpts.resourceType == "" {
return b.exportPkg(cmd.OutOrStdout(), pkgSVC, b.file, opts...)
return b.exportTemplate(cmd.OutOrStdout(), pkgSVC, b.file, opts...)
}

resType := strings.ToLower(b.exportOpts.resourceType)
resKind := pkger.KindUnknown
for _, k := range pkger.Kinds() {
if strings.ToLower(string(k)) == resType {
resKind = k
break
}
}
resKind := templateKindFold(b.exportOpts.resourceType)

if err := resKind.OK(); err != nil {
return errors.New("resource type is invalid; got: " + b.exportOpts.resourceType)
Expand All @@ -439,7 +436,7 @@ func (b *cmdPkgBuilder) exportRunEFn(cmd *cobra.Command, args []string) error {
}
opts = append(opts, resTypeOpt)

return b.exportPkg(cmd.OutOrStdout(), pkgSVC, b.file, opts...)
return b.exportTemplate(cmd.OutOrStdout(), pkgSVC, b.file, opts...)
}

func (b *cmdPkgBuilder) cmdExportAll() *cobra.Command {
Expand Down Expand Up @@ -526,7 +523,7 @@ func (b *cmdPkgBuilder) exportAllRunEFn(cmd *cobra.Command, args []string) error
LabelNames: labelNames,
ResourceKinds: resourceKinds,
})
return b.exportPkg(cmd.OutOrStdout(), pkgSVC, b.file, orgOpt)
return b.exportTemplate(cmd.OutOrStdout(), pkgSVC, b.file, orgOpt)
}

func (b *cmdPkgBuilder) cmdExportStack() *cobra.Command {
Expand Down Expand Up @@ -680,10 +677,10 @@ func (b *cmdPkgBuilder) cmdStackInit() *cobra.Command {
Examples:
# Initialize a stack with a name and description
influx stack init -n $STACK_NAME -d $STACK_DESCRIPTION
influx stacks init -n $STACK_NAME -d $STACK_DESCRIPTION
# Initialize a stack with a name and urls to associate with stack.
influx stack init -n $STACK_NAME -u $PATH_TO_TEMPLATE
influx stacks init -n $STACK_NAME -u $PATH_TO_TEMPLATE
For information about how stacks work with InfluxDB templates, see
https://v2.docs.influxdata.com/v2.0/reference/cli/influx/stacks/
Expand Down Expand Up @@ -714,10 +711,10 @@ func (b *cmdPkgBuilder) stackInitRunEFn(cmd *cobra.Command, args []string) error

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,
OrgID: orgID,
Name: b.name,
Description: b.description,
TemplateURLs: b.urls,
})
if err != nil {
return err
Expand Down Expand Up @@ -791,7 +788,7 @@ func (b *cmdPkgBuilder) stackListRunEFn(cmd *cobra.Command, args []string) error
"Description": stack.Description,
"Num Resources": len(stack.Resources),
"Sources": stack.Sources,
"URLs": stack.URLs,
"URLs": stack.TemplateURLs,
"Created At": stack.CreatedAt,
})
}
Expand Down Expand Up @@ -862,7 +859,7 @@ func (b *cmdPkgBuilder) stackRemoveRunEFn(cmd *cobra.Command, args []string) err
"Description": stack.Description,
"Num Resources": len(stack.Resources),
"Sources": stack.Sources,
"URLs": stack.URLs,
"URLs": stack.TemplateURLs,
"Created At": stack.CreatedAt,
})

Expand Down Expand Up @@ -901,10 +898,23 @@ func (b *cmdPkgBuilder) cmdStackUpdate() *cobra.Command {
Examples:
# Update a stack with a name and description
influx stack update -i $STACK_ID -n $STACK_NAME -d $STACK_DESCRIPTION
influx stacks update -i $STACK_ID -n $STACK_NAME -d $STACK_DESCRIPTION
# Update a stack with a name and urls to associate with stack.
influx stack update --stack-id $STACK_ID --stack-name $STACK_NAME --template-url $PATH_TO_TEMPLATE
influx stacks update --stack-id $STACK_ID --stack-name $STACK_NAME --template-url $PATH_TO_TEMPLATE
# Update stack with new resources to manage
influx stacks update \
--stack-id $STACK_ID \
--addResource=Bucket=$BUCKET_ID \
--addResource=Dashboard=$DASH_ID
# Update stack with new resources to manage and export stack
# as a template
influx stacks update \
--stack-id $STACK_ID \
--addResource=Bucket=$BUCKET_ID \
--export-file /path/to/file.yml
For information about how stacks work with InfluxDB templates, see
https://v2.docs.influxdata.com/v2.0/reference/cli/influx/stacks
Expand All @@ -917,6 +927,8 @@ func (b *cmdPkgBuilder) cmdStackUpdate() *cobra.Command {
cmd.Flags().StringVarP(&b.name, "stack-name", "n", "", "Name for stack")
cmd.Flags().StringVarP(&b.description, "stack-description", "d", "", "Description for stack")
cmd.Flags().StringArrayVarP(&b.urls, "template-url", "u", nil, "Template urls to associate with stack")
cmd.Flags().StringArrayVar(&b.updateStackOpts.addResources, "addResource", nil, "Additional resources to associate with stack")
cmd.Flags().StringVarP(&b.file, "export-file", "f", "", "Destination for exported template")
registerPrintOptions(cmd, &b.hideHeaders, &b.json)

return cmd
Expand All @@ -933,17 +945,62 @@ func (b *cmdPkgBuilder) stackUpdateRunEFn(cmd *cobra.Command, args []string) err
return ierror.Wrap(err, "required stack id is invalid")
}

stack, err := pkgSVC.UpdateStack(context.Background(), pkger.StackUpdate{
ID: *stackID,
Name: &b.name,
Description: &b.description,
URLs: b.urls,
})
update := pkger.StackUpdate{
ID: *stackID,
Name: &b.name,
Description: &b.description,
TemplateURLs: b.urls,
}

for _, res := range b.updateStackOpts.addResources {
parts := strings.SplitN(res, "=", 2)
if len(parts) < 2 {
continue
}

kind, idRaw := templateKindFold(parts[0]), parts[1]
if err := kind.OK(); err != nil {
return errors.New("resource type is invalid; got: " + b.exportOpts.resourceType)
}

id, err := influxdb.IDFromString(idRaw)
if err != nil {
return ierror.Wrap(err, fmt.Sprintf("%s resource id %q is invalid", kind, idRaw))
}
update.AdditionalResources = append(update.AdditionalResources, pkger.StackAdditionalResource{
APIVersion: pkger.APIVersion,
ID: *id,
Kind: kind,
})
}

stack, err := pkgSVC.UpdateStack(context.Background(), update)
if err != nil {
return err
}

return b.writeStack(b.w, stack)
if err := b.writeStack(b.w, stack); err != nil {
return err
}

if len(update.AdditionalResources) == 0 {
return nil
}

if b.file == "" {
const msg = `
Your stack now differs from your template. Applying an outdated template will revert
these updates. Export a new template with these updates to prevent accidental changes? (y/n)`
for range make([]struct{}, 3) {
if in := b.getInput(msg, "n"); in == "y" {
break
} else if in == "n" {
return nil
}
}
}

return b.exportTemplate(cmd.OutOrStdout(), pkgSVC, b.file, pkger.ExportWithStackID(*stackID))
}

func (b *cmdPkgBuilder) writeStack(w io.Writer, stack pkger.Stack) error {
Expand All @@ -956,15 +1013,16 @@ func (b *cmdPkgBuilder) writeStack(w io.Writer, stack pkger.Stack) error {

tabW.HideHeaders(b.hideHeaders)

tabW.WriteHeaders("ID", "OrgID", "Name", "Description", "Sources", "URLs", "Created At")
tabW.WriteHeaders("ID", "OrgID", "Name", "Description", "Num Resources", "Sources", "URLs", "Created At")
tabW.Write(map[string]interface{}{
"ID": stack.ID,
"OrgID": stack.OrgID,
"Name": stack.Name,
"Description": stack.Description,
"Sources": stack.Sources,
"URLs": stack.URLs,
"Created At": stack.CreatedAt,
"ID": stack.ID,
"OrgID": stack.OrgID,
"Name": stack.Name,
"Description": stack.Description,
"Num Resources": len(stack.Resources),
"Sources": stack.Sources,
"URLs": stack.TemplateURLs,
"Created At": stack.CreatedAt,
})

return nil
Expand Down Expand Up @@ -994,7 +1052,7 @@ func (b *cmdPkgBuilder) registerPkgFileFlags(cmd *cobra.Command) {
cmd.MarkFlagFilename("encoding", "yaml", "yml", "json", "jsonnet")
}

func (b *cmdPkgBuilder) exportPkg(w io.Writer, pkgSVC pkger.SVC, outPath string, opts ...pkger.ExportOptFn) error {
func (b *cmdPkgBuilder) exportTemplate(w io.Writer, pkgSVC pkger.SVC, outPath string, opts ...pkger.ExportOptFn) error {
pkg, err := pkgSVC.Export(context.Background(), opts...)
if err != nil {
return err
Expand Down Expand Up @@ -2089,6 +2147,17 @@ func missingValKeys(m map[string]string) []string {
return out
}

func templateKindFold(resType string) pkger.Kind {
resKind := pkger.KindUnknown
for _, k := range pkger.Kinds() {
if strings.EqualFold(string(k), resType) {
resKind = k
break
}
}
return resKind
}

func find(needle string, haystack []string) int {
for i, h := range haystack {
if strings.ToLower(h) == needle {
Expand Down
4 changes: 2 additions & 2 deletions cmd/influx/pkg_test.go → cmd/influx/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ func Test_Template_Commands(t *testing.T) {
OrgID: 1,
Name: "foo",
Description: "desc",
URLs: []string{
TemplateURLs: []string{
"http://example.com/1",
"http://example.com/2",
},
Expand All @@ -557,7 +557,7 @@ func Test_Template_Commands(t *testing.T) {
OrgID: 1,
Name: "foo",
Description: "desc",
URLs: []string{
TemplateURLs: []string{
"http://example.com/1",
"http://example.com/2",
},
Expand Down
32 changes: 16 additions & 16 deletions cmd/influxd/launcher/pkger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ func TestLauncher_Pkger(t *testing.T) {
assert.Equal(t, stack.Name, newStack.Name)
assert.Equal(t, stack.Description, newStack.Description)
assert.NotNil(t, newStack.Resources, "failed to match stack resources")
expectedURLs := stack.URLs
expectedURLs := stack.TemplateURLs
if expectedURLs == nil {
expectedURLs = []string{}
}
assert.Equal(t, expectedURLs, newStack.URLs, "failed to match stack URLs")
assert.Equal(t, expectedURLs, newStack.TemplateURLs, "failed to match stack URLs")
assert.NotZero(t, newStack.CRUDLog)

return newStack, func() {
Expand Down Expand Up @@ -252,10 +252,10 @@ func TestLauncher_Pkger(t *testing.T) {

t.Run("creating a stack", func(t *testing.T) {
_, cleanup := newStackFn(t, pkger.Stack{
OrgID: l.Org.ID,
Name: "first stack",
Description: "desc",
URLs: []string{"http://example.com"},
OrgID: l.Org.ID,
Name: "first stack",
Description: "desc",
TemplateURLs: []string{"http://example.com"},
})
cleanup()
})
Expand Down Expand Up @@ -406,10 +406,10 @@ func TestLauncher_Pkger(t *testing.T) {

t.Run("updating a stack", func(t *testing.T) {
stack, cleanup := newStackFn(t, pkger.Stack{
OrgID: l.Org.ID,
Name: "first name",
Description: "first desc",
URLs: []string{},
OrgID: l.Org.ID,
Name: "first name",
Description: "first desc",
TemplateURLs: []string{},
})
defer cleanup()

Expand All @@ -418,7 +418,7 @@ func TestLauncher_Pkger(t *testing.T) {
assert.Equal(t, stack.ID, st.ID)
assert.Equal(t, "2nd name", st.Name)
assert.Equal(t, "2nd desc", st.Description)
assert.Equal(t, []string{"http://example.com"}, st.URLs)
assert.Equal(t, []string{"http://example.com"}, st.TemplateURLs)
resources := []pkger.StackResource{
{
APIVersion: pkger.APIVersion,
Expand All @@ -432,10 +432,10 @@ func TestLauncher_Pkger(t *testing.T) {
}

updStack, err := svc.UpdateStack(ctx, pkger.StackUpdate{
ID: stack.ID,
Name: strPtr("2nd name"),
Description: strPtr("2nd desc"),
URLs: []string{"http://example.com"},
ID: stack.ID,
Name: strPtr("2nd name"),
Description: strPtr("2nd desc"),
TemplateURLs: []string{"http://example.com"},
AdditionalResources: []pkger.StackAdditionalResource{
{
APIVersion: pkger.APIVersion,
Expand Down Expand Up @@ -483,7 +483,7 @@ func TestLauncher_Pkger(t *testing.T) {
}

newStack, cleanup := newStackFn(t, pkger.Stack{
URLs: expectedURLs,
TemplateURLs: expectedURLs,
})
defer cleanup()

Expand Down
16 changes: 8 additions & 8 deletions pkger/http_remote_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (s *HTTPRemoteService) InitStack(ctx context.Context, userID influxdb.ID, s
OrgID: stack.OrgID.String(),
Name: stack.Name,
Description: stack.Description,
URLs: stack.URLs,
URLs: stack.TemplateURLs,
}

var respBody RespStack
Expand Down Expand Up @@ -89,7 +89,7 @@ func (s *HTTPRemoteService) UpdateStack(ctx context.Context, upd StackUpdate) (S
reqBody := ReqUpdateStack{
Name: upd.Name,
Description: upd.Description,
TemplateURLs: upd.URLs,
TemplateURLs: upd.TemplateURLs,
}
for _, r := range upd.AdditionalResources {
reqBody.AdditionalResources = append(reqBody.AdditionalResources, ReqUpdateStackResource{
Expand Down Expand Up @@ -242,12 +242,12 @@ func (s *HTTPRemoteService) apply(ctx context.Context, orgID influxdb.ID, dryRun

func convertRespStackToStack(respStack RespStack) (Stack, error) {
newStack := Stack{
Name: respStack.Name,
Description: respStack.Description,
Sources: respStack.Sources,
URLs: respStack.URLs,
Resources: make([]StackResource, 0, len(respStack.Resources)),
CRUDLog: respStack.CRUDLog,
Name: respStack.Name,
Description: respStack.Description,
Sources: respStack.Sources,
TemplateURLs: respStack.URLs,
Resources: make([]StackResource, 0, len(respStack.Resources)),
CRUDLog: respStack.CRUDLog,
}
for _, r := range respStack.Resources {
sr := StackResource{
Expand Down
Loading

0 comments on commit 2f2140e

Please sign in to comment.