From ec8c252dbbddc649c6bddc8feb1817c54cc47b2d Mon Sep 17 00:00:00 2001 From: Johnny Steenbergen Date: Thu, 18 Jun 2020 06:47:07 -0700 Subject: [PATCH] feat(pkger): extend public apply API with new action to skip resources by kind closes: #18490 --- CHANGELOG.md | 1 + cmd/influxd/launcher/pkger_test.go | 183 +++++++++++++++++++---------- http/swagger.yml | 63 +++++----- pkger/http_remote_service.go | 10 ++ pkger/http_server.go | 38 +++++- 5 files changed, 196 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec16b486913..3aa11056014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ 1. [18560](https://github.com/influxdata/influxdb/pull/18560): Extend stacks API with update capability 1. [18568](https://github.com/influxdata/influxdb/pull/18568): Add support for config files to influxd and any cli.NewCommand use case 1. [18573](https://github.com/influxdata/influxdb/pull/18573): Extend influx stacks cmd with new influx stacks update cmd +1. [18595](https://github.com/influxdata/influxdb/pull/18595): Add ability to skip resources in a template by kind or by metadata.name ## v2.0.0-beta.12 [2020-06-12] diff --git a/cmd/influxd/launcher/pkger_test.go b/cmd/influxd/launcher/pkger_test.go index fb30f8353bf..92a460b2dd4 100644 --- a/cmd/influxd/launcher/pkger_test.go +++ b/cmd/influxd/launcher/pkger_test.go @@ -1539,9 +1539,6 @@ func TestLauncher_Pkger(t *testing.T) { }) t.Run("apply with actions", func(t *testing.T) { - stack, cleanup := newStackFn(t, pkger.Stack{}) - defer cleanup() - var ( bucketPkgName = "rucketeer-1" checkPkgName = "checkers" @@ -1553,70 +1550,126 @@ func TestLauncher_Pkger(t *testing.T) { telegrafPkgName = "teletype" variablePkgName = "laces-out-dan" ) - pkg := newPkg( - newBucketObject(bucketPkgName, "", ""), - newCheckDeadmanObject(t, checkPkgName, "", time.Hour), - newDashObject(dashPkgName, "", ""), - newEndpointHTTP(endpointPkgName, "", ""), - newLabelObject(labelPkgName, "", "", ""), - newRuleObject(t, rulePkgName, "", endpointPkgName, ""), - newTaskObject(taskPkgName, "", ""), - newTelegrafObject(telegrafPkgName, "", ""), - newVariableObject(variablePkgName, "", ""), - ) - impact, err := svc.Apply(ctx, l.Org.ID, l.User.ID, - pkger.ApplyWithPkg(pkg), - pkger.ApplyWithStackID(stack.ID), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindBucket, - MetaName: bucketPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindCheckDeadman, - MetaName: checkPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindDashboard, - MetaName: dashPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindNotificationEndpointHTTP, - MetaName: endpointPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindLabel, - MetaName: labelPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindNotificationRule, - MetaName: rulePkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindTask, - MetaName: taskPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindTelegraf, - MetaName: telegrafPkgName, - }), - pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ - Kind: pkger.KindVariable, - MetaName: variablePkgName, - }), - ) - require.NoError(t, err) + tests := []struct { + name string + applyOpts []pkger.ApplyOptFn + }{ + { + name: "skip resource", + applyOpts: []pkger.ApplyOptFn{ + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindBucket, + MetaName: bucketPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindCheckDeadman, + MetaName: checkPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindDashboard, + MetaName: dashPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindNotificationEndpointHTTP, + MetaName: endpointPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindLabel, + MetaName: labelPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindNotificationRule, + MetaName: rulePkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindTask, + MetaName: taskPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindTelegraf, + MetaName: telegrafPkgName, + }), + pkger.ApplyWithResourceSkip(pkger.ActionSkipResource{ + Kind: pkger.KindVariable, + MetaName: variablePkgName, + }), + }, + }, + { + name: "skip kind", + applyOpts: []pkger.ApplyOptFn{ + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindBucket, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindCheckDeadman, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindDashboard, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindNotificationEndpointHTTP, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindLabel, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindNotificationRule, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindTask, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindTelegraf, + }), + pkger.ApplyWithKindSkip(pkger.ActionSkipKind{ + Kind: pkger.KindVariable, + }), + }, + }, + } + + for _, tt := range tests { + fn := func(t *testing.T) { + stack, cleanup := newStackFn(t, pkger.Stack{}) + defer cleanup() + + pkg := newPkg( + newBucketObject(bucketPkgName, "", ""), + newCheckDeadmanObject(t, checkPkgName, "", time.Hour), + newDashObject(dashPkgName, "", ""), + newEndpointHTTP(endpointPkgName, "", ""), + newLabelObject(labelPkgName, "", "", ""), + newRuleObject(t, rulePkgName, "", endpointPkgName, ""), + newTaskObject(taskPkgName, "", ""), + newTelegrafObject(telegrafPkgName, "", ""), + newVariableObject(variablePkgName, "", ""), + ) + + impact, err := svc.Apply(ctx, l.Org.ID, l.User.ID, + append( + tt.applyOpts, + pkger.ApplyWithPkg(pkg), + pkger.ApplyWithStackID(stack.ID), + )..., + ) + require.NoError(t, err) - summary := impact.Summary - assert.Empty(t, summary.Buckets) - assert.Empty(t, summary.Checks) - assert.Empty(t, summary.Dashboards) - assert.Empty(t, summary.NotificationEndpoints) - assert.Empty(t, summary.Labels) - assert.Empty(t, summary.NotificationRules, 0) - assert.Empty(t, summary.Tasks) - assert.Empty(t, summary.TelegrafConfigs) - assert.Empty(t, summary.Variables) + summary := impact.Summary + assert.Empty(t, summary.Buckets) + assert.Empty(t, summary.Checks) + assert.Empty(t, summary.Dashboards) + assert.Empty(t, summary.NotificationEndpoints) + assert.Empty(t, summary.Labels) + assert.Empty(t, summary.NotificationRules, 0) + assert.Empty(t, summary.Tasks) + assert.Empty(t, summary.TelegrafConfigs) + assert.Empty(t, summary.Variables) + } + + t.Run(tt.name, fn) + } }) t.Run("exporting the existing state of stack resources to a pkg", func(t *testing.T) { diff --git a/http/swagger.yml b/http/swagger.yml index 5fd3b95b6c7..4ce8420606a 100644 --- a/http/swagger.yml +++ b/http/swagger.yml @@ -7695,6 +7695,17 @@ components: type: array items: oneOf: + - type: object + properties: + action: + type: string + enum: ["skipKind"] + properties: + type: object + properties: + kind: + $ref: "#/components/schemas/TemplateKind" + required: ["kind"] - type: object properties: action: @@ -7704,22 +7715,27 @@ components: type: object properties: kind: - type: string + $ref: "#/components/schemas/TemplateKind" resourceTemplateName: type: string required: ["kind", "resourceTemplateName"] - PkgCreateKind: + TemplateKind: type: string enum: - - bucket - - check - - dashboard - - label - - notification_endpoint - - notification_rule - - task - - telegraf - - variable + - Bucket + - Check + - CheckDeadman + - CheckThreshold + - Dashboard + - Label + - NotificationEndpoint + - NotificationEndpointHTTP + - NotificationEndpointPagerDuty + - NotificationEndpointSlack + - NotificationRule + - Task + - Telegraf + - Variable PkgCreate: type: object properties: @@ -7740,14 +7756,14 @@ components: byResourceKind: type: array items: - $ref: "#/components/schemas/PkgCreateKind" + $ref: "#/components/schemas/TemplateKind" resources: type: object properties: id: type: string kind: - $ref: "#/components/schemas/PkgCreateKind" + $ref: "#/components/schemas/TemplateKind" name: type: string required: [id, kind] @@ -7759,20 +7775,7 @@ components: apiVersion: type: string kind: - type: string - enum: - - Bucket - - CheckDeadman - - CheckThreshold - - Dashboard - - Label - - NotificationEndpointHTTP - - NotificationEndpointPagerDuty - - NotificationEndpointSlack - - NotificationRule - - Task - - Telegraf - - Variable + $ref: "#/components/schemas/TemplateKind" meta: type: object properties: @@ -8368,7 +8371,7 @@ components: type: object properties: kind: - type: string + $ref: "#/components/schemas/TemplateKind" reason: type: string fields: @@ -8437,7 +8440,7 @@ components: resourceID: type: string kind: - type: string + $ref: "#/components/schemas/TemplateKind" pkgName: type: string associations: @@ -8446,7 +8449,7 @@ components: type: object properties: kind: - type: string + $ref: "#/components/schemas/TemplateKind" pkgName: type: string urls: diff --git a/pkger/http_remote_service.go b/pkger/http_remote_service.go index 9b8e5c44014..815c6ff2e94 100644 --- a/pkger/http_remote_service.go +++ b/pkger/http_remote_service.go @@ -225,6 +225,16 @@ func (s *HTTPRemoteService) apply(ctx context.Context, orgID influxdb.ID, dryRun Properties: b, }) } + for kind := range opt.KindsToSkip { + b, err := json.Marshal(ActionSkipKind{Kind: kind}) + if err != nil { + return PkgImpactSummary{}, influxErr(influxdb.EInvalid, err) + } + reqBody.RawActions = append(reqBody.RawActions, ReqRawAction{ + Action: string(ActionTypeSkipKind), + Properties: b, + }) + } var resp RespApplyPkg err := s.Client. diff --git a/pkger/http_server.go b/pkger/http_server.go index e32cee45779..acadfb4de8f 100644 --- a/pkger/http_server.go +++ b/pkger/http_server.go @@ -14,6 +14,7 @@ import ( "github.com/go-chi/chi/middleware" "github.com/influxdata/influxdb/v2" pctx "github.com/influxdata/influxdb/v2/context" + ierrors "github.com/influxdata/influxdb/v2/kit/errors" kithttp "github.com/influxdata/influxdb/v2/kit/transport/http" "github.com/influxdata/influxdb/v2/pkg/jsonnet" "go.uber.org/zap" @@ -556,31 +557,57 @@ func (r ReqApplyPkg) Pkgs(encoding Encoding) (*Pkg, error) { type actionType string +// various ActionTypes the transport API speaks const ( + ActionTypeSkipKind actionType = "skipKind" ActionTypeSkipResource actionType = "skipResource" ) func (r ReqApplyPkg) validActions() (struct { + SkipKinds []ActionSkipKind SkipResources []ActionSkipResource }, error) { type actions struct { + SkipKinds []ActionSkipKind SkipResources []ActionSkipResource } + unmarshalErrFn := func(err error, idx int, actionType string) error { + msg := fmt.Sprintf("failed to unmarshal properties for actions[%d] %q", idx, actionType) + return ierrors.Wrap(err, msg) + } + + kindErrFn := func(err error, idx int, actionType string) error { + msg := fmt.Sprintf("invalid kind for actions[%d] %q", idx, actionType) + return ierrors.Wrap(err, msg) + } + var out actions - for _, rawAct := range r.RawActions { + for i, rawAct := range r.RawActions { switch a := rawAct.Action; actionType(a) { case ActionTypeSkipResource: var asr ActionSkipResource if err := json.Unmarshal(rawAct.Properties, &asr); err != nil { - return actions{}, influxErr(influxdb.EInvalid, err) + return actions{}, influxErr(influxdb.EInvalid, unmarshalErrFn(err, i, a)) } if err := asr.Kind.OK(); err != nil { - return actions{}, influxErr(influxdb.EInvalid, err) + return actions{}, influxErr(influxdb.EInvalid, kindErrFn(err, i, a)) } out.SkipResources = append(out.SkipResources, asr) + case ActionTypeSkipKind: + var ask ActionSkipKind + if err := json.Unmarshal(rawAct.Properties, &ask); err != nil { + return actions{}, influxErr(influxdb.EInvalid, unmarshalErrFn(err, i, a)) + } + if err := ask.Kind.OK(); err != nil { + return actions{}, influxErr(influxdb.EInvalid, kindErrFn(err, i, a)) + } + out.SkipKinds = append(out.SkipKinds, ask) default: - msg := fmt.Sprintf("invalid action type provided %q; Must be one of [%s]", a, ActionTypeSkipResource) + msg := fmt.Sprintf( + "invalid action type %q provided for actions[%d] ; Must be one of [%s]", + a, i, ActionTypeSkipResource, + ) return actions{}, influxErr(influxdb.EInvalid, msg) } } @@ -649,6 +676,9 @@ func (s *HTTPServer) applyPkg(w http.ResponseWriter, r *http.Request) { for _, a := range actions.SkipResources { applyOpts = append(applyOpts, ApplyWithResourceSkip(a)) } + for _, a := range actions.SkipKinds { + applyOpts = append(applyOpts, ApplyWithKindSkip(a)) + } auth, err := pctx.GetAuthorizer(r.Context()) if err != nil {