Skip to content

Commit ee092c6

Browse files
authored
deployment: Add shutdown command (#32)
Adds the deployment shutdown command with an interactive prompt confirming the action which can be skipped by using the `--force` flag. Signed-off-by: Marc Lopez <marc5.12@outlook.com>
1 parent a01959c commit ee092c6

File tree

6 files changed

+267
-0
lines changed

6 files changed

+267
-0
lines changed

cmd/deployment/shutdown.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
"os"
22+
23+
"github.com/spf13/cobra"
24+
25+
cmdutil "github.com/elastic/ecctl/cmd/util"
26+
"github.com/elastic/ecctl/pkg/deployment"
27+
"github.com/elastic/ecctl/pkg/ecctl"
28+
)
29+
30+
var shutdownCmd = &cobra.Command{
31+
Use: "shutdown <deployment-id>",
32+
Short: "Shuts down a deployment and all of its associated sub-resources",
33+
PreRunE: cmdutil.MinimumNArgsAndUUID(1),
34+
RunE: func(cmd *cobra.Command, args []string) error {
35+
force, _ := cmd.Flags().GetBool("force")
36+
var msg = "This action will delete the specified deployment ID and its associated sub-resources, do you want to continue? [y/n]: "
37+
if !force && !cmdutil.ConfirmAction(msg, os.Stderr, os.Stdout) {
38+
return nil
39+
}
40+
41+
skipSnapshot, _ := cmd.Flags().GetBool("skip-snapshot")
42+
hide, _ := cmd.Flags().GetBool("hide")
43+
44+
res, err := deployment.Shutdown(deployment.ShutdownParams{
45+
API: ecctl.Get().API,
46+
DeploymentID: args[0],
47+
SkipSnapshot: skipSnapshot,
48+
Hide: hide,
49+
})
50+
if err != nil {
51+
return err
52+
}
53+
54+
return ecctl.Get().Formatter.Format("deployment/shutdown", res)
55+
},
56+
}
57+
58+
func init() {
59+
Command.AddCommand(shutdownCmd)
60+
shutdownCmd.Flags().Bool("skip-snapshot", false, "Skips taking an Elasticsearch snapshot prior to shutting down the deployment")
61+
shutdownCmd.Flags().Bool("hide", false, "Hides the deployment and its resources after it has been shut down")
62+
}

docs/ecctl_deployment.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ ecctl deployment [flags]
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
4848
* [ecctl deployment show](ecctl_deployment_show.md) - Shows the specified deployment resources
49+
* [ecctl deployment shutdown](ecctl_deployment_shutdown.md) - Shuts down a deployment and all of its associated sub-resources
4950

docs/ecctl_deployment_shutdown.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
## ecctl deployment shutdown
2+
3+
Shuts down a deployment and all of its associated sub-resources
4+
5+
### Synopsis
6+
7+
Shuts down a deployment and all of its associated sub-resources
8+
9+
```
10+
ecctl deployment shutdown <deployment-id> [flags]
11+
```
12+
13+
### Options
14+
15+
```
16+
-h, --help help for shutdown
17+
--hide Hides the deployment and its resources after it has been shut down
18+
--skip-snapshot Skips taking an Elasticsearch snapshot prior to shutting down the deployment
19+
```
20+
21+
### Options inherited from parent commands
22+
23+
```
24+
--apikey string API key to use to authenticate (If empty will look for EC_APIKEY environment variable)
25+
--config string Config name, used to have multiple configs in $HOME/.ecctl/<env> (default "config")
26+
--force Do not ask for confirmation
27+
--format string Formats the output using a Go template
28+
--host string Base URL to use (default "https://api.elastic-cloud.com")
29+
--insecure Skips all TLS validation
30+
--message string A message to set on cluster operation
31+
--output string Output format [text|json] (default "text")
32+
--pass string Password to use to authenticate (If empty will look for EC_PASS environment variable)
33+
--pprof Enables pprofing and saves the profile to pprof-20060102150405
34+
-q, --quiet Suppresses the configuration file used for the run, if any
35+
--region string Elastic Cloud region
36+
--timeout duration Timeout to use on all HTTP calls (default 30s)
37+
--trace Enables tracing saves the trace to trace-20060102150405
38+
--user string Username to use to authenticate (If empty will look for EC_USER environment variable)
39+
--verbose Enable verbose mode
40+
```
41+
42+
### SEE ALSO
43+
44+
* [ecctl deployment](ecctl_deployment.md) - Manages deployments
45+

pkg/deployment/shutdown.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
"github.com/elastic/cloud-sdk-go/pkg/api"
22+
"github.com/elastic/cloud-sdk-go/pkg/client/deployments"
23+
"github.com/elastic/cloud-sdk-go/pkg/models"
24+
"github.com/elastic/cloud-sdk-go/pkg/util/ec"
25+
"github.com/hashicorp/go-multierror"
26+
27+
"github.com/elastic/ecctl/pkg/util"
28+
)
29+
30+
// ShutdownParams is consumed by Shutdown.
31+
type ShutdownParams struct {
32+
*api.API
33+
DeploymentID string
34+
35+
SkipSnapshot bool
36+
Hide bool
37+
}
38+
39+
// Validate ensures the parameters are usable by Shutdown.
40+
func (params ShutdownParams) Validate() error {
41+
var merr = new(multierror.Error)
42+
43+
if params.API == nil {
44+
merr = multierror.Append(merr, util.ErrAPIReq)
45+
}
46+
47+
if len(params.DeploymentID) != 32 {
48+
merr = multierror.Append(merr, util.ErrDeploymentID)
49+
}
50+
51+
return merr.ErrorOrNil()
52+
}
53+
54+
// Shutdown shuts down a deployment and all of its associated resources. To
55+
// shutdown individual deployment resources use the type especific APIs.
56+
func Shutdown(params ShutdownParams) (*models.DeploymentShutdownResponse, error) {
57+
if err := params.Validate(); err != nil {
58+
return nil, err
59+
}
60+
61+
res, err := params.V1API.Deployments.ShutdownDeployment(
62+
deployments.NewShutdownDeploymentParams().
63+
WithDeploymentID(params.DeploymentID).
64+
WithSkipSnapshot(ec.Bool(params.SkipSnapshot)).
65+
WithHide(ec.Bool(params.Hide)),
66+
params.AuthWriter,
67+
)
68+
if err != nil {
69+
return nil, api.UnwrapError(err)
70+
}
71+
72+
return res.Payload, nil
73+
}

pkg/deployment/shutdown_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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 TestShutdown(t *testing.T) {
35+
type args struct {
36+
params ShutdownParams
37+
}
38+
tests := []struct {
39+
name string
40+
args args
41+
want *models.DeploymentShutdownResponse
42+
err error
43+
}{
44+
{
45+
name: "fails on parameter validation",
46+
err: &multierror.Error{Errors: []error{
47+
util.ErrAPIReq,
48+
util.ErrDeploymentID,
49+
}},
50+
},
51+
{
52+
name: "fails on API error",
53+
args: args{params: ShutdownParams{
54+
API: api.NewMock(mock.New500Response(mock.NewStringBody("error"))),
55+
DeploymentID: util.ValidClusterID,
56+
}},
57+
err: errors.New("unknown error (status 500)"),
58+
},
59+
{
60+
name: "Succeeds",
61+
args: args{params: ShutdownParams{
62+
API: api.NewMock(mock.New200Response(mock.NewStructBody(models.DeploymentShutdownResponse{
63+
ID: ec.String(util.ValidClusterID),
64+
}))),
65+
DeploymentID: util.ValidClusterID,
66+
}},
67+
want: &models.DeploymentShutdownResponse{
68+
ID: ec.String(util.ValidClusterID),
69+
},
70+
},
71+
}
72+
for _, tt := range tests {
73+
t.Run(tt.name, func(t *testing.T) {
74+
got, err := Shutdown(tt.args.params)
75+
if !reflect.DeepEqual(err, tt.err) {
76+
t.Errorf("Shutdown() error = %v, wantErr %v", err, tt.err)
77+
return
78+
}
79+
if !reflect.DeepEqual(got, tt.want) {
80+
t.Errorf("Shutdown() = %v, want %v", got, tt.want)
81+
}
82+
})
83+
}
84+
}

pkg/util/helper.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ var (
3737
ErrAPIReq = errors.New("api reference is required for command")
3838
// ErrClusterLength is the message returned when a provided cluster id is not of the expected length (32 chars)
3939
ErrClusterLength = errors.New("cluster id should have a length of 32 characters")
40+
// ErrDeploymentID is the message returned when a provided cluster id is not of the expected length (32 chars)
41+
ErrDeploymentID = errors.New("deployment id should have a length of 32 characters")
4042

4143
// SkipMaintenanceHeaders tells the EC proxy layer to still send requests to the
4244
// underlying cluster instances even if they are in maintenance mode

0 commit comments

Comments
 (0)