Skip to content

Commit

Permalink
deployment: New traffic filter update command (#480)
Browse files Browse the repository at this point in the history
New command to perform update actions on extensions:

 - ecctl deployment traffic-filter update <traffic-filter id> {--file <file-path> | --generate-payload}
  • Loading branch information
karencfv committed Mar 25, 2021
1 parent 605ca99 commit 056f4d6
Show file tree
Hide file tree
Showing 12 changed files with 435 additions and 4 deletions.
2 changes: 1 addition & 1 deletion cmd/deployment/trafficfilter/create.go
Expand Up @@ -41,7 +41,7 @@ var createCmd = &cobra.Command{
var rules []*models.TrafficFilterRule
for _, rule := range source {
rules = append(rules, &models.TrafficFilterRule{
Source: ec.String(rule),
Source: rule,
})
}

Expand Down
12 changes: 12 additions & 0 deletions cmd/deployment/trafficfilter/testdata/update-payload.json
@@ -0,0 +1,12 @@
{
"include_by_default": false,
"name": "1235",
"region": "azure-eastus2",
"rules": [
{
"id": "fad8132b0470479f95c3a41c5d67bd57",
"source": "0.0.0.0/0"
}
],
"type": "ip"
}
3 changes: 3 additions & 0 deletions cmd/deployment/trafficfilter/testdata/update.json
@@ -0,0 +1,3 @@
{
"id": "4e974d9476534d35b12fbdcfd0acee0a"
}
106 changes: 106 additions & 0 deletions cmd/deployment/trafficfilter/update.go
@@ -0,0 +1,106 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package cmddeploymenttrafficfilter

import (
"encoding/json"
"errors"

"github.com/elastic/cloud-sdk-go/pkg/api/deploymentapi/trafficfilterapi"
"github.com/elastic/cloud-sdk-go/pkg/models"
"github.com/elastic/cloud-sdk-go/pkg/util/cmdutil"
"github.com/spf13/cobra"

"github.com/elastic/ecctl/pkg/ecctl"
)

const updateExample = `
* Return the current traffic filter state as a valid update payload.
ecctl deployment traffic-filter update <traffic-filter id> --generate-payload > update.json
* After editing the file with your new values pass it as an argument to the --file flag.
ecctl deployment traffic-filter update <traffic-filter id> --file update.json`

var updateCmd = &cobra.Command{
Use: "update <traffic-filter id> {--file <file-path> | --generate-payload}",
Short: "Updates a traffic-filter",
Example: updateExample,
PreRunE: cmdutil.MinimumNArgsAndUUID(1),
RunE: func(cmd *cobra.Command, args []string) error {
genPayload, _ := cmd.Flags().GetBool("generate-payload")
file, _ := cmd.Flags().GetString("file")

if err := flagRequirements(genPayload, file); err != nil {
return err
}

if genPayload {
res, err := trafficfilterapi.Get(trafficfilterapi.GetParams{
API: ecctl.Get().API,
ID: args[0],
})
if err != nil {
return err
}

enc := json.NewEncoder(ecctl.Get().Config.OutputDevice)
enc.SetIndent("", " ")
return enc.Encode(
trafficfilterapi.NewUpdateRequestFromGet(res),
)
}

var req models.TrafficFilterRulesetRequest
if err := cmdutil.DecodeFile(file, &req); err != nil {
return err
}
res, err := trafficfilterapi.Update(trafficfilterapi.UpdateParams{
API: ecctl.Get().API,
ID: args[0],
Req: &req,
})
if err != nil {
return err
}

return ecctl.Get().Formatter.Format("", res)
},
}

func init() {
initUpdateFlags()
}

func initUpdateFlags() {
Command.AddCommand(updateCmd)
updateCmd.Flags().Bool("generate-payload", false, "Outputs JSON which can be used as an argument for the --file flag.")
updateCmd.Flags().String("file", "", "Path to the file containing the update JSON definition.")
updateCmd.MarkFlagFilename("file", "json")
}

func flagRequirements(genPayload bool, file string) error {
if genPayload && file != "" {
return errors.New("both --file and --generate-payload are set. Only one may be used")
}

if !genPayload && file == "" {
return errors.New("one of --file or --generate-payload must be set")
}

return nil
}
195 changes: 195 additions & 0 deletions cmd/deployment/trafficfilter/update_test.go
@@ -0,0 +1,195 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package cmddeploymenttrafficfilter

import (
"encoding/json"
"io/ioutil"
"net/url"
"testing"

"github.com/elastic/cloud-sdk-go/pkg/api"
"github.com/elastic/cloud-sdk-go/pkg/api/mock"
"github.com/elastic/cloud-sdk-go/pkg/models"

"github.com/elastic/ecctl/cmd/util/testutils"
)

func Test_updateCmd(t *testing.T) {
updatePayloadRawResp, err := ioutil.ReadFile("./testdata/update-payload.json")
if err != nil {
t.Fatal(err)
}

var succeedPayloadResp = new(models.TrafficFilterRulesetRequest)
if err := succeedPayloadResp.UnmarshalBinary(updatePayloadRawResp); err != nil {
t.Fatal(err)
}

updatePayloadJSONOutput, err := json.MarshalIndent(succeedPayloadResp, "", " ")
if err != nil {
t.Fatal(err)
}

updateRawResp, err := ioutil.ReadFile("./testdata/update.json")
if err != nil {
t.Fatal(err)
}

var succeedResp = new(models.TrafficFilterRulesetResponse)
if err := succeedResp.UnmarshalBinary(updateRawResp); err != nil {
t.Fatal(err)
}

updateJSONOutput, err := json.MarshalIndent(succeedResp, "", " ")
if err != nil {
t.Fatal(err)
}

tests := []struct {
name string
args testutils.Args
want testutils.Assertion
}{
{
name: "fails due to empty argument",
args: testutils.Args{
Cmd: updateCmd,
Args: []string{
"update",
},
Cfg: testutils.MockCfg{Responses: []mock.Response{
mock.SampleInternalError(),
}},
},
want: testutils.Assertion{
Err: `requires at least 1 arg(s), only received 0`,
},
},
{
name: "fails due to missing flags",
args: testutils.Args{
Cmd: updateCmd,
Args: []string{
"update", "4e974d9476534d35b12fbdcfd0acee0a",
},
Cfg: testutils.MockCfg{Responses: []mock.Response{
mock.SampleInternalError(),
}},
},
want: testutils.Assertion{
Err: `one of --file or --generate-payload must be set`,
},
},
{
name: "fails due to mismatching flags",
args: testutils.Args{
Cmd: updateCmd,
Args: []string{
"update", "4e974d9476534d35b12fbdcfd0acee0a", "--generate-payload", "--file", "testdata/update.json",
},
Cfg: testutils.MockCfg{Responses: []mock.Response{
mock.SampleInternalError(),
}},
},
want: testutils.Assertion{
Err: "both --file and --generate-payload are set. Only one may be used",
},
},
{
name: "fails due to API error",
args: testutils.Args{
Cmd: updateCmd,
Args: []string{
"update", "4e974d9476534d35b12fbdcfd0acee0a", "--generate-payload",
},
Cfg: testutils.MockCfg{Responses: []mock.Response{
mock.SampleInternalError(),
}},
},
want: testutils.Assertion{
Err: mock.MultierrorInternalError.Error(),
},
},
{
name: "succeeds to generate payload",
args: testutils.Args{
Cmd: updateCmd,
Args: []string{
"update", "4e974d9476534d35b12fbdcfd0acee0a", "--generate-payload",
},
Cfg: testutils.MockCfg{
OutputFormat: "json",
Responses: []mock.Response{
mock.New200ResponseAssertion(
&mock.RequestAssertion{
Header: api.DefaultReadMockHeaders,
Method: "GET",
Path: "/api/v1/deployments/traffic-filter/rulesets/4e974d9476534d35b12fbdcfd0acee0a",
Host: api.DefaultMockHost,
Query: url.Values{
"include_associations": []string{"false"},
},
},
mock.NewByteBody(updatePayloadRawResp),
),
},
},
},
want: testutils.Assertion{
Stdout: string(updatePayloadJSONOutput) + "\n",
},
},
{
name: "succeeds to update",
args: testutils.Args{
Cmd: updateCmd,
Args: []string{
"update", "4e974d9476534d35b12fbdcfd0acee0a", "--file", "./testdata/update-payload.json",
},
Cfg: testutils.MockCfg{
OutputFormat: "json",
Responses: []mock.Response{
mock.New200ResponseAssertion(
&mock.RequestAssertion{
Header: api.DefaultWriteMockHeaders,
Method: "PUT",
Path: "/api/v1/deployments/traffic-filter/rulesets/4e974d9476534d35b12fbdcfd0acee0a",
Body: mock.NewStringBody(
`{"include_by_default":false,"name":"1235","region":"azure-eastus2","rules":[{"id":"fad8132b0470479f95c3a41c5d67bd57","source":"0.0.0.0/0"}],"type":"ip"}` +
"\n"),
Host: api.DefaultMockHost,
},
mock.NewByteBody(updateRawResp),
),
},
},
},
want: testutils.Assertion{
Stdout: string(updateJSONOutput) + "\n",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testutils.RunCmdAssertion(t, tt.args, tt.want)
tt.args.Cmd.ResetFlags()
defer initUpdateFlags()
})
}
}
1 change: 1 addition & 0 deletions docs/ecctl-command-reference-index.adoc
Expand Up @@ -60,6 +60,7 @@ include::ecctl_deployment_traffic-filter_create.adoc[]
include::ecctl_deployment_traffic-filter_delete.adoc[]
include::ecctl_deployment_traffic-filter_list.adoc[]
include::ecctl_deployment_traffic-filter_show.adoc[]
include::ecctl_deployment_traffic-filter_update.adoc[]
include::ecctl_deployment_update.adoc[]
include::ecctl_generate.adoc[]
include::ecctl_generate_completions.adoc[]
Expand Down
1 change: 1 addition & 0 deletions docs/ecctl_deployment_traffic-filter.adoc
Expand Up @@ -47,3 +47,4 @@ ecctl deployment traffic-filter [flags]
* xref:ecctl_deployment_traffic-filter_delete[ecctl deployment traffic-filter delete] - Deletes a traffic filter ruleset
* xref:ecctl_deployment_traffic-filter_list[ecctl deployment traffic-filter list] - Lists the traffic filter rulesets
* xref:ecctl_deployment_traffic-filter_show[ecctl deployment traffic-filter show] - Shows information about a traffic filter ruleset
* xref:ecctl_deployment_traffic-filter_update[ecctl deployment traffic-filter update] - Updates a traffic-filter
1 change: 1 addition & 0 deletions docs/ecctl_deployment_traffic-filter.md
Expand Up @@ -43,4 +43,5 @@ ecctl deployment traffic-filter [flags]
* [ecctl deployment traffic-filter delete](ecctl_deployment_traffic-filter_delete.md) - Deletes a traffic filter ruleset
* [ecctl deployment traffic-filter list](ecctl_deployment_traffic-filter_list.md) - Lists the traffic filter rulesets
* [ecctl deployment traffic-filter show](ecctl_deployment_traffic-filter_show.md) - Shows information about a traffic filter ruleset
* [ecctl deployment traffic-filter update](ecctl_deployment_traffic-filter_update.md) - Updates a traffic-filter

0 comments on commit 056f4d6

Please sign in to comment.