Skip to content

Commit fb7681b

Browse files
authored
deployment: Add search command (#34)
Adds deployment search command with a text output template and examples in the docs. Signed-off-by: Marc Lopez <marc5.12@outlook.com>
1 parent ee092c6 commit fb7681b

File tree

7 files changed

+324
-0
lines changed

7 files changed

+324
-0
lines changed

cmd/deployment/search.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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 cmddeployment
19+
20+
import (
21+
"github.com/spf13/cobra"
22+
23+
cmdutil "github.com/elastic/ecctl/cmd/util"
24+
"github.com/elastic/ecctl/pkg/deployment"
25+
"github.com/elastic/ecctl/pkg/ecctl"
26+
)
27+
28+
const searchQueryLong = `Read more about Query DSL in https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html`
29+
30+
var searchExamples = `
31+
$ cat query_string_query.json
32+
{
33+
"query": {
34+
"query_string": {
35+
"query": "name: admin"
36+
}
37+
}
38+
}
39+
$ ecctl deployment search -f query_string_query.json
40+
[...]`[1:]
41+
42+
var searchCmd = &cobra.Command{
43+
Use: `search -f <query file.json>`,
44+
Short: "Performs advanced deployment search using the Elasticsearch Query DSL",
45+
Long: searchQueryLong,
46+
Example: searchExamples,
47+
PreRunE: cobra.NoArgs,
48+
RunE: func(cmd *cobra.Command, args []string) error {
49+
sr, err := cmdutil.ParseQueryDSLFile(cmd.Flag("file").Value.String())
50+
if err != nil {
51+
return err
52+
}
53+
54+
res, err := deployment.Search(deployment.SearchParams{
55+
API: ecctl.Get().API,
56+
Request: &sr,
57+
})
58+
59+
if err != nil {
60+
return err
61+
}
62+
63+
return ecctl.Get().Formatter.Format("deployment/search", res)
64+
},
65+
}
66+
67+
func init() {
68+
Command.AddCommand(searchCmd)
69+
searchCmd.Flags().StringP("file", "f", "", "JSON file that contains JSON-style domain-specific language query")
70+
searchCmd.MarkFlagRequired("file")
71+
}

docs/ecctl_deployment.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ ecctl deployment [flags]
4545
* [ecctl deployment kibana](ecctl_deployment_kibana.md) - Manages Kibana clusters
4646
* [ecctl deployment list](ecctl_deployment_list.md) - Lists the platform's deployments
4747
* [ecctl deployment note](ecctl_deployment_note.md) - Manages a deployment's notes
48+
* [ecctl deployment search](ecctl_deployment_search.md) - Performs advanced deployment search using the Elasticsearch Query DSL
4849
* [ecctl deployment show](ecctl_deployment_show.md) - Shows the specified deployment resources
4950
* [ecctl deployment shutdown](ecctl_deployment_shutdown.md) - Shuts down a deployment and all of its associated sub-resources
5051

docs/ecctl_deployment_search.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
## ecctl deployment search
2+
3+
Performs advanced deployment search using the Elasticsearch Query DSL
4+
5+
### Synopsis
6+
7+
Read more about Query DSL in https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
8+
9+
```
10+
ecctl deployment search -f <query file.json> [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
$ cat query_string_query.json
17+
{
18+
"query": {
19+
"query_string": {
20+
"query": "name: admin"
21+
}
22+
}
23+
}
24+
$ ecctl deployment search -f query_string_query.json
25+
[...]
26+
```
27+
28+
### Options
29+
30+
```
31+
-f, --file string JSON file that contains JSON-style domain-specific language query
32+
-h, --help help for search
33+
```
34+
35+
### Options inherited from parent commands
36+
37+
```
38+
--apikey string API key to use to authenticate (If empty will look for EC_APIKEY environment variable)
39+
--config string Config name, used to have multiple configs in $HOME/.ecctl/<env> (default "config")
40+
--force Do not ask for confirmation
41+
--format string Formats the output using a Go template
42+
--host string Base URL to use (default "https://api.elastic-cloud.com")
43+
--insecure Skips all TLS validation
44+
--message string A message to set on cluster operation
45+
--output string Output format [text|json] (default "text")
46+
--pass string Password to use to authenticate (If empty will look for EC_PASS environment variable)
47+
--pprof Enables pprofing and saves the profile to pprof-20060102150405
48+
-q, --quiet Suppresses the configuration file used for the run, if any
49+
--region string Elastic Cloud region
50+
--timeout duration Timeout to use on all HTTP calls (default 30s)
51+
--trace Enables tracing saves the trace to trace-20060102150405
52+
--user string Username to use to authenticate (If empty will look for EC_USER environment variable)
53+
--verbose Enable verbose mode
54+
```
55+
56+
### SEE ALSO
57+
58+
* [ecctl deployment](ecctl_deployment.md) - Manages deployments
59+

pkg/deployment/search.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 deployment
19+
20+
import (
21+
"errors"
22+
23+
"github.com/elastic/cloud-sdk-go/pkg/api"
24+
"github.com/elastic/cloud-sdk-go/pkg/client/deployments"
25+
"github.com/elastic/cloud-sdk-go/pkg/models"
26+
"github.com/hashicorp/go-multierror"
27+
28+
"github.com/elastic/ecctl/pkg/util"
29+
)
30+
31+
// SearchParams is consumed by Search.
32+
type SearchParams struct {
33+
*api.API
34+
35+
Request *models.SearchRequest
36+
}
37+
38+
// Validate ensures the parameters are usable by Shutdown.
39+
func (params SearchParams) Validate() error {
40+
var merr = new(multierror.Error)
41+
42+
if params.API == nil {
43+
merr = multierror.Append(merr, util.ErrAPIReq)
44+
}
45+
46+
if params.Request == nil {
47+
merr = multierror.Append(merr, errors.New("deployment search: request cannot be empty"))
48+
}
49+
50+
return merr.ErrorOrNil()
51+
}
52+
53+
// Search performs a search using the specified Request against the API.
54+
func Search(params SearchParams) (*models.DeploymentsSearchResponse, error) {
55+
if err := params.Validate(); err != nil {
56+
return nil, err
57+
}
58+
59+
res, err := params.V1API.Deployments.SearchDeployments(
60+
deployments.NewSearchDeploymentsParams().
61+
WithBody(params.Request),
62+
params.AuthWriter,
63+
)
64+
if err != nil {
65+
return nil, api.UnwrapError(err)
66+
}
67+
68+
return res.Payload, nil
69+
}

pkg/deployment/search_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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 deployment
19+
20+
import (
21+
"errors"
22+
"reflect"
23+
"testing"
24+
25+
"github.com/elastic/cloud-sdk-go/pkg/api"
26+
"github.com/elastic/cloud-sdk-go/pkg/api/mock"
27+
"github.com/elastic/cloud-sdk-go/pkg/models"
28+
"github.com/elastic/cloud-sdk-go/pkg/util/ec"
29+
"github.com/hashicorp/go-multierror"
30+
31+
"github.com/elastic/ecctl/pkg/util"
32+
)
33+
34+
func TestSearch(t *testing.T) {
35+
type args struct {
36+
params SearchParams
37+
}
38+
tests := []struct {
39+
name string
40+
args args
41+
want *models.DeploymentsSearchResponse
42+
err error
43+
}{
44+
{
45+
name: "fails on parameter validation",
46+
err: &multierror.Error{Errors: []error{
47+
util.ErrAPIReq,
48+
errors.New("deployment search: request cannot be empty"),
49+
}},
50+
},
51+
{
52+
name: "fails on API error",
53+
args: args{params: SearchParams{
54+
API: api.NewMock(mock.New500Response(mock.NewStringBody("error"))),
55+
Request: &models.SearchRequest{},
56+
}},
57+
err: errors.New("unknown error (status 500)"),
58+
},
59+
{
60+
name: "Succeeds",
61+
args: args{params: SearchParams{
62+
API: api.NewMock(mock.New200Response(mock.NewStructBody(models.DeploymentsSearchResponse{
63+
Deployments: []*models.DeploymentSearchResponse{
64+
{ID: ec.String("123")},
65+
},
66+
}))),
67+
Request: &models.SearchRequest{},
68+
}},
69+
want: &models.DeploymentsSearchResponse{Deployments: []*models.DeploymentSearchResponse{
70+
{ID: ec.String("123")},
71+
}},
72+
},
73+
}
74+
for _, tt := range tests {
75+
t.Run(tt.name, func(t *testing.T) {
76+
got, err := Search(tt.args.params)
77+
if !reflect.DeepEqual(err, tt.err) {
78+
t.Errorf("Search() error = %v, wantErr %v", err, tt.err)
79+
return
80+
}
81+
if !reflect.DeepEqual(got, tt.want) {
82+
t.Errorf("Search() = %v, want %v", got, tt.want)
83+
}
84+
})
85+
}
86+
}

pkg/formatter/templates/bindata.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
// text/apm/planhistory.gotmpl
2727
// text/deployment/list.gotmpl
2828
// text/deployment/notelist.gotmpl
29+
// text/deployment/search.gotmpl
2930
// text/deployment-template/list.gotmpl
3031
// text/elasticsearch/list.gotmpl
3132
// text/elasticsearch/overridecapacity.gotmpl
@@ -302,6 +303,26 @@ func textDeploymentNotelistGotmpl() (*asset, error) {
302303
return a, nil
303304
}
304305

306+
var _textDeploymentSearchGotmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x52\xdd\x6a\x83\x30\x14\xbe\xef\x53\x84\xd0\xdb\xfa\x00\x83\x5e\x64\x55\x98\x74\x95\xd2\xf6\x05\x8e\x7a\xba\xc9\x4c\x0c\x49\x1c\x1b\xe2\xbb\x0f\xf3\x53\x4c\xed\xa0\x57\xc6\xef\x9c\xef\x27\x9f\x0e\xc3\x86\xd4\x78\x6d\x04\x12\xda\x7d\xa3\x52\x4d\x8d\x94\x8c\xe3\x30\x10\x05\xe2\x03\x49\x92\xa2\x6c\xbb\x5f\x8e\xc2\x68\x87\xe3\x0f\x56\xbd\xc1\x0b\x72\xd9\x82\x41\x92\x8c\xe3\x6a\x82\x45\xed\xe7\xe1\x10\x74\x6b\xbc\x42\xdf\x9a\x49\x76\x35\xf9\xd1\x3c\x75\x16\x06\x4a\xbb\x48\x0b\x76\xc8\xe8\x0c\xa1\xd9\x3b\x3b\x5f\xf2\xdd\x39\x63\xa7\xdd\x5b\x34\xd9\xe7\xaf\xac\x60\x11\xc4\x8e\x87\xbb\xf7\xe3\x8d\x68\x0d\x1f\xde\xc4\x4e\xd6\x5f\x4d\x09\x02\xc8\xcb\x96\xd0\x4d\x58\x5f\x83\xe4\x0b\x44\x6a\x04\x55\x7d\xde\xe1\xd8\x82\x36\x4d\xf5\x68\xe6\x4d\x4f\xa8\xbb\x5e\x55\xa8\x13\x26\xb9\xbd\xad\x95\xdf\x92\x24\x4f\x6d\x09\x28\xea\xff\x19\xde\x35\xf0\x42\x88\xa7\xd8\xd9\x3c\x9b\x53\x88\xe3\x3e\xa5\xb2\xb7\x05\x39\xba\x2f\x6b\xc9\xbb\x01\xe1\x8b\x26\x05\x70\x74\x7f\x81\x81\xd2\x1e\x62\xf3\xf9\x72\xd0\x8d\xd6\x5d\x4d\x0b\x28\x34\xe0\xe3\x86\x00\xee\xf9\x17\x00\x00\xff\xff\x34\xd0\x98\x15\xcd\x02\x00\x00")
307+
308+
func textDeploymentSearchGotmplBytes() ([]byte, error) {
309+
return bindataRead(
310+
_textDeploymentSearchGotmpl,
311+
"text/deployment/search.gotmpl",
312+
)
313+
}
314+
315+
func textDeploymentSearchGotmpl() (*asset, error) {
316+
bytes, err := textDeploymentSearchGotmplBytes()
317+
if err != nil {
318+
return nil, err
319+
}
320+
321+
info := bindataFileInfo{name: "text/deployment/search.gotmpl", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
322+
a := &asset{bytes: bytes, info: info}
323+
return a, nil
324+
}
325+
305326
var _textDeploymentTemplateListGotmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x8e\xcd\x4e\x87\x30\x10\xc4\xef\xff\xa7\xd8\xf4\x6e\xdf\xc1\x58\x0e\x3d\xf0\x11\xcb\xc5\x63\xa5\x83\x69\x02\x85\x94\xa2\x92\xa6\xef\x6e\x00\xd1\xa4\x9c\x76\x32\xbb\xfb\x9b\x89\xf1\x89\x0c\x7a\xeb\x40\x6c\xfa\x84\xf7\xd6\x80\x51\x4a\x31\x92\xd7\xee\x03\xc4\x1b\xbd\x0d\x93\x36\x87\x87\x6f\x74\x6b\x40\x8b\x71\x1e\x74\x00\xf1\x94\x1e\x31\x12\xdc\xb9\xfe\x17\x17\xd2\xa0\xd7\xeb\x10\x76\xe2\x63\x8f\x22\x26\xc5\x2f\x3e\xe8\xf7\x53\x10\xab\x9e\xcb\x22\x77\x99\x7a\x53\x6d\x51\xde\x6c\x51\xa8\x97\x57\xd9\xb4\xb2\xae\xfe\xa8\xb7\xa6\x7b\x29\x2e\x45\xf6\xcb\x2b\x3d\x22\x0f\xe7\x6a\x5b\x02\xc6\xfa\xcb\xc1\xe4\xf7\x02\x4b\xe7\xed\x1c\xec\xe4\xae\x28\x38\x73\xa8\x73\xfe\x04\x00\x00\xff\xff\x7d\x8a\x96\xef\x3e\x01\x00\x00")
306327

307328
func textDeploymentTemplateListGotmplBytes() ([]byte, error) {
@@ -763,6 +784,7 @@ var _bindata = map[string]func() (*asset, error){
763784
"text/apm/planhistory.gotmpl": textApmPlanhistoryGotmpl,
764785
"text/deployment/list.gotmpl": textDeploymentListGotmpl,
765786
"text/deployment/notelist.gotmpl": textDeploymentNotelistGotmpl,
787+
"text/deployment/search.gotmpl": textDeploymentSearchGotmpl,
766788
"text/deployment-template/list.gotmpl": textDeploymentTemplateListGotmpl,
767789
"text/elasticsearch/list.gotmpl": textElasticsearchListGotmpl,
768790
"text/elasticsearch/overridecapacity.gotmpl": textElasticsearchOverridecapacityGotmpl,
@@ -841,6 +863,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
841863
"deployment": &bintree{nil, map[string]*bintree{
842864
"list.gotmpl": &bintree{textDeploymentListGotmpl, map[string]*bintree{}},
843865
"notelist.gotmpl": &bintree{textDeploymentNotelistGotmpl, map[string]*bintree{}},
866+
"search.gotmpl": &bintree{textDeploymentSearchGotmpl, map[string]*bintree{}},
844867
}},
845868
"deployment-template": &bintree{nil, map[string]*bintree{
846869
"list.gotmpl": &bintree{textDeploymentTemplateListGotmpl, map[string]*bintree{}},
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{{- define "override" }}{{ range .Deployments }}{{ executeTemplate .}}
2+
{{ end }}{{ end }}{{ define "default" }}
3+
{{- "ID" }}{{tab}}{{ "NAME"}}{{tab}}{{"ELASTICSEARCH"}}{{tab}}{{"KIBANA"}}{{tab}}{{"APM"}}{{tab}}{{"APPSEARCH"}}
4+
{{- range .Deployments }}
5+
{{- $kibana := "-"}}
6+
{{- $apm := "-"}}
7+
{{- $appsearch := "-"}}
8+
{{- $elasticsearch := "-"}}
9+
{{- range .Resources.Apm}}{{ $apm = .ID }}{{end}}
10+
{{- range .Resources.Appsearch}}{{ $appsearch = .ID }}{{end}}
11+
{{- range .Resources.Elasticsearch}}{{ $elasticsearch = .ID }}{{end}}
12+
{{- range .Resources.Kibana}}{{ $kibana = .ID }}{{end}}
13+
{{ .ID }}{{tab}}{{ .Name }}{{ tab }}{{$elasticsearch}}{{tab}}{{ $kibana }}{{ tab }}{{ $apm }}{{ tab }}{{ $appsearch }}
14+
{{- end}}
15+
{{end}}

0 commit comments

Comments
 (0)