Skip to content

Commit 1e9d805

Browse files
authored
deployment: Add elasticsearch keystore commands (#344)
Adds a new `elasticsearch` subcommand to the `deployment` command and a `keystore` subcommand to the `deployment elasticsearch` command. Results in: * `deployment elasticsearch keystore show` * `deployment elasticsearch keystore update|set` Signed-off-by: Marc Lopez <marc5.12@outlook.com>
1 parent f5d478e commit 1e9d805

22 files changed

+1055
-3
lines changed

cmd/deployment/command.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package cmddeployment
2020
import (
2121
"github.com/spf13/cobra"
2222

23+
cmdelasticsearch "github.com/elastic/ecctl/cmd/deployment/elasticsearch"
2324
cmddeploymentnote "github.com/elastic/ecctl/cmd/deployment/note"
2425
cmddeploymentplan "github.com/elastic/ecctl/cmd/deployment/plan"
2526
cmddeploymentresource "github.com/elastic/ecctl/cmd/deployment/resource"
@@ -42,5 +43,6 @@ func init() {
4243
cmddeploymentplan.Command,
4344
cmddeploymentresource.Command,
4445
cmddeploymenttemplate.Command,
46+
cmdelasticsearch.Command,
4547
)
4648
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package cmdelasticsearch
19+
20+
import (
21+
"github.com/spf13/cobra"
22+
23+
cmdeskeystore "github.com/elastic/ecctl/cmd/deployment/elasticsearch/keystore"
24+
)
25+
26+
// Command is the deployment subcommand
27+
var Command = &cobra.Command{
28+
Use: "elasticsearch",
29+
Short: "Manages Elasticsearch resources",
30+
PreRunE: cobra.MaximumNArgs(0),
31+
Run: func(cmd *cobra.Command, args []string) {
32+
cmd.Help()
33+
},
34+
}
35+
36+
func init() {
37+
Command.AddCommand(cmdeskeystore.Command)
38+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package cmdeskeystore
19+
20+
import "github.com/spf13/cobra"
21+
22+
// Command is the deployment subcommand
23+
var Command = &cobra.Command{
24+
Use: "keystore",
25+
Short: "Manages Elasticsearch resource keystores",
26+
PreRunE: cobra.NoArgs,
27+
Run: func(cmd *cobra.Command, args []string) {
28+
cmd.Help()
29+
},
30+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package cmdeskeystore
19+
20+
import (
21+
"github.com/spf13/cobra"
22+
23+
"github.com/elastic/cloud-sdk-go/pkg/api/deploymentapi/eskeystoreapi"
24+
sdkcmdutil "github.com/elastic/cloud-sdk-go/pkg/util/cmdutil"
25+
26+
"github.com/elastic/ecctl/pkg/ecctl"
27+
)
28+
29+
var showCmd = &cobra.Command{
30+
Use: "show <deployment id> [--ref-id <ref-id>]",
31+
Short: "Shows the settings from the Elasticsearch resource keystore",
32+
PreRunE: sdkcmdutil.MinimumNArgsAndUUID(1),
33+
RunE: func(cmd *cobra.Command, args []string) error {
34+
refID, _ := cmd.Flags().GetString("ref-id")
35+
res, err := eskeystoreapi.Get(eskeystoreapi.GetParams{
36+
API: ecctl.Get().API,
37+
DeploymentID: args[0],
38+
RefID: refID,
39+
})
40+
if err != nil {
41+
return err
42+
}
43+
44+
return ecctl.Get().Formatter.Format("deployment/eskeystore_show", res)
45+
},
46+
}
47+
48+
func init() {
49+
Command.AddCommand(showCmd)
50+
showCmd.Flags().String("ref-id", "", "Optional ref_id to use for the Elasticsearch resource, auto-discovered if not specified.")
51+
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package cmdeskeystore
19+
20+
import (
21+
"encoding/json"
22+
"errors"
23+
"io/ioutil"
24+
"net/url"
25+
"testing"
26+
27+
"github.com/elastic/cloud-sdk-go/pkg/api"
28+
"github.com/elastic/cloud-sdk-go/pkg/api/mock"
29+
"github.com/elastic/cloud-sdk-go/pkg/models"
30+
"github.com/elastic/cloud-sdk-go/pkg/util/ec"
31+
32+
"github.com/elastic/ecctl/cmd/util/testutils"
33+
"github.com/elastic/ecctl/pkg/util"
34+
)
35+
36+
func Test_showCmd(t *testing.T) {
37+
var reqAssertion = &mock.RequestAssertion{
38+
Header: api.DefaultReadMockHeaders,
39+
Method: "GET",
40+
Path: "/api/v1/deployments/320b7b540dfc967a7a649c18e2fce4ed/elasticsearch/main-elasticsearch/keystore",
41+
Host: api.DefaultMockHost,
42+
}
43+
44+
showRawResp, err := ioutil.ReadFile("./testdata/show.json")
45+
if err != nil {
46+
t.Fatal(err)
47+
}
48+
49+
var succeedResp = new(models.KeystoreContents)
50+
if err := succeedResp.UnmarshalBinary(showRawResp); err != nil {
51+
t.Fatal(err)
52+
}
53+
54+
showJSONOutput, err := json.MarshalIndent(succeedResp, "", " ")
55+
if err != nil {
56+
t.Fatal(err)
57+
}
58+
59+
tests := []struct {
60+
name string
61+
args testutils.Args
62+
want testutils.Assertion
63+
}{
64+
{
65+
name: "fails due empty argument",
66+
args: testutils.Args{
67+
Cmd: showCmd,
68+
Args: []string{
69+
"show",
70+
},
71+
Cfg: testutils.MockCfg{Responses: []mock.Response{
72+
mock.SampleInternalError(),
73+
}},
74+
},
75+
want: testutils.Assertion{
76+
Err: errors.New("requires at least 1 arg(s), only received 0"),
77+
},
78+
},
79+
{
80+
name: "fails due to API error",
81+
args: testutils.Args{
82+
Cmd: showCmd,
83+
Args: []string{
84+
"show", util.ValidClusterID, "--ref-id=main-elasticsearch",
85+
},
86+
Cfg: testutils.MockCfg{Responses: []mock.Response{
87+
mock.SampleInternalError(),
88+
}},
89+
},
90+
want: testutils.Assertion{
91+
Err: mock.MultierrorInternalError,
92+
},
93+
},
94+
{
95+
name: "succeeds with JSON format",
96+
args: testutils.Args{
97+
Cmd: showCmd,
98+
Args: []string{
99+
"show", util.ValidClusterID, "--ref-id=main-elasticsearch",
100+
},
101+
Cfg: testutils.MockCfg{
102+
OutputFormat: "json",
103+
Responses: []mock.Response{
104+
mock.New200ResponseAssertion(
105+
reqAssertion, mock.NewByteBody(showRawResp),
106+
),
107+
},
108+
},
109+
},
110+
want: testutils.Assertion{
111+
Stdout: string(showJSONOutput) + "\n",
112+
},
113+
},
114+
{
115+
name: "succeeds with text format",
116+
args: testutils.Args{
117+
Cmd: showCmd,
118+
Args: []string{
119+
"show", util.ValidClusterID, "--ref-id=main-elasticsearch",
120+
},
121+
Cfg: testutils.MockCfg{
122+
OutputFormat: "text",
123+
Responses: []mock.Response{
124+
mock.New200ResponseAssertion(
125+
reqAssertion, mock.NewByteBody(showRawResp),
126+
),
127+
},
128+
},
129+
},
130+
want: testutils.Assertion{
131+
Stdout: "SECRET VALUE AS FILE\n" +
132+
"secret-name <no value> false\n",
133+
},
134+
},
135+
{
136+
name: "succeeds with text format and ref-id auto-discovery",
137+
args: testutils.Args{
138+
Cmd: showCmd,
139+
Args: []string{
140+
"show", util.ValidClusterID, "--ref-id=",
141+
},
142+
Cfg: testutils.MockCfg{
143+
OutputFormat: "text",
144+
Responses: []mock.Response{
145+
mock.New200ResponseAssertion(
146+
&mock.RequestAssertion{
147+
Header: api.DefaultReadMockHeaders,
148+
Method: "GET",
149+
Host: api.DefaultMockHost,
150+
Path: "/api/v1/deployments/320b7b540dfc967a7a649c18e2fce4ed",
151+
Query: url.Values{
152+
"convert_legacy_plans": {"false"},
153+
"enrich_with_template": {"true"},
154+
"show_metadata": {"false"},
155+
"show_plan_defaults": {"false"},
156+
"show_plan_history": {"false"},
157+
"show_plan_logs": {"false"},
158+
"show_plans": {"false"},
159+
"show_security": {"false"},
160+
"show_settings": {"false"},
161+
"show_system_alerts": {"5"},
162+
},
163+
},
164+
mock.NewStructBody(models.DeploymentGetResponse{
165+
Healthy: ec.Bool(true),
166+
ID: ec.String(mock.ValidClusterID),
167+
Resources: &models.DeploymentResources{
168+
Elasticsearch: []*models.ElasticsearchResourceInfo{{
169+
ID: ec.String(mock.ValidClusterID),
170+
RefID: ec.String("main-elasticsearch"),
171+
}},
172+
},
173+
}),
174+
),
175+
mock.New200ResponseAssertion(
176+
reqAssertion, mock.NewByteBody(showRawResp),
177+
),
178+
},
179+
},
180+
},
181+
want: testutils.Assertion{
182+
Stdout: "SECRET VALUE AS FILE\n" +
183+
"secret-name <no value> false\n",
184+
},
185+
},
186+
}
187+
for _, tt := range tests {
188+
t.Run(tt.name, func(t *testing.T) {
189+
testutils.RunCmdAssertion(t, tt.args, tt.want)
190+
})
191+
}
192+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"secrets": {
3+
"secret-name": {
4+
"value": null,
5+
"as_file": false
6+
}
7+
}
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"secrets": {
3+
"secret-name": {
4+
"value": "the secret value"
5+
}
6+
}
7+
}

0 commit comments

Comments
 (0)