Skip to content

Commit

Permalink
deployment: Add shutdown command (#32)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
marclop committed Nov 11, 2019
1 parent a01959c commit ee092c6
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 0 deletions.
62 changes: 62 additions & 0 deletions cmd/deployment/shutdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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 cmddeployment

import (
"os"

"github.com/spf13/cobra"

cmdutil "github.com/elastic/ecctl/cmd/util"
"github.com/elastic/ecctl/pkg/deployment"
"github.com/elastic/ecctl/pkg/ecctl"
)

var shutdownCmd = &cobra.Command{
Use: "shutdown <deployment-id>",
Short: "Shuts down a deployment and all of its associated sub-resources",
PreRunE: cmdutil.MinimumNArgsAndUUID(1),
RunE: func(cmd *cobra.Command, args []string) error {
force, _ := cmd.Flags().GetBool("force")
var msg = "This action will delete the specified deployment ID and its associated sub-resources, do you want to continue? [y/n]: "
if !force && !cmdutil.ConfirmAction(msg, os.Stderr, os.Stdout) {
return nil
}

skipSnapshot, _ := cmd.Flags().GetBool("skip-snapshot")
hide, _ := cmd.Flags().GetBool("hide")

res, err := deployment.Shutdown(deployment.ShutdownParams{
API: ecctl.Get().API,
DeploymentID: args[0],
SkipSnapshot: skipSnapshot,
Hide: hide,
})
if err != nil {
return err
}

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

func init() {
Command.AddCommand(shutdownCmd)
shutdownCmd.Flags().Bool("skip-snapshot", false, "Skips taking an Elasticsearch snapshot prior to shutting down the deployment")
shutdownCmd.Flags().Bool("hide", false, "Hides the deployment and its resources after it has been shut down")
}
1 change: 1 addition & 0 deletions docs/ecctl_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ ecctl deployment [flags]
* [ecctl deployment list](ecctl_deployment_list.md) - Lists the platform's deployments
* [ecctl deployment note](ecctl_deployment_note.md) - Manages a deployment's notes
* [ecctl deployment show](ecctl_deployment_show.md) - Shows the specified deployment resources
* [ecctl deployment shutdown](ecctl_deployment_shutdown.md) - Shuts down a deployment and all of its associated sub-resources

45 changes: 45 additions & 0 deletions docs/ecctl_deployment_shutdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## ecctl deployment shutdown

Shuts down a deployment and all of its associated sub-resources

### Synopsis

Shuts down a deployment and all of its associated sub-resources

```
ecctl deployment shutdown <deployment-id> [flags]
```

### Options

```
-h, --help help for shutdown
--hide Hides the deployment and its resources after it has been shut down
--skip-snapshot Skips taking an Elasticsearch snapshot prior to shutting down the deployment
```

### Options inherited from parent commands

```
--apikey string API key to use to authenticate (If empty will look for EC_APIKEY environment variable)
--config string Config name, used to have multiple configs in $HOME/.ecctl/<env> (default "config")
--force Do not ask for confirmation
--format string Formats the output using a Go template
--host string Base URL to use (default "https://api.elastic-cloud.com")
--insecure Skips all TLS validation
--message string A message to set on cluster operation
--output string Output format [text|json] (default "text")
--pass string Password to use to authenticate (If empty will look for EC_PASS environment variable)
--pprof Enables pprofing and saves the profile to pprof-20060102150405
-q, --quiet Suppresses the configuration file used for the run, if any
--region string Elastic Cloud region
--timeout duration Timeout to use on all HTTP calls (default 30s)
--trace Enables tracing saves the trace to trace-20060102150405
--user string Username to use to authenticate (If empty will look for EC_USER environment variable)
--verbose Enable verbose mode
```

### SEE ALSO

* [ecctl deployment](ecctl_deployment.md) - Manages deployments

73 changes: 73 additions & 0 deletions pkg/deployment/shutdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 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 deployment

import (
"github.com/elastic/cloud-sdk-go/pkg/api"
"github.com/elastic/cloud-sdk-go/pkg/client/deployments"
"github.com/elastic/cloud-sdk-go/pkg/models"
"github.com/elastic/cloud-sdk-go/pkg/util/ec"
"github.com/hashicorp/go-multierror"

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

// ShutdownParams is consumed by Shutdown.
type ShutdownParams struct {
*api.API
DeploymentID string

SkipSnapshot bool
Hide bool
}

// Validate ensures the parameters are usable by Shutdown.
func (params ShutdownParams) Validate() error {
var merr = new(multierror.Error)

if params.API == nil {
merr = multierror.Append(merr, util.ErrAPIReq)
}

if len(params.DeploymentID) != 32 {
merr = multierror.Append(merr, util.ErrDeploymentID)
}

return merr.ErrorOrNil()
}

// Shutdown shuts down a deployment and all of its associated resources. To
// shutdown individual deployment resources use the type especific APIs.
func Shutdown(params ShutdownParams) (*models.DeploymentShutdownResponse, error) {
if err := params.Validate(); err != nil {
return nil, err
}

res, err := params.V1API.Deployments.ShutdownDeployment(
deployments.NewShutdownDeploymentParams().
WithDeploymentID(params.DeploymentID).
WithSkipSnapshot(ec.Bool(params.SkipSnapshot)).
WithHide(ec.Bool(params.Hide)),
params.AuthWriter,
)
if err != nil {
return nil, api.UnwrapError(err)
}

return res.Payload, nil
}
84 changes: 84 additions & 0 deletions pkg/deployment/shutdown_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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 deployment

import (
"errors"
"reflect"
"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/cloud-sdk-go/pkg/util/ec"
"github.com/hashicorp/go-multierror"

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

func TestShutdown(t *testing.T) {
type args struct {
params ShutdownParams
}
tests := []struct {
name string
args args
want *models.DeploymentShutdownResponse
err error
}{
{
name: "fails on parameter validation",
err: &multierror.Error{Errors: []error{
util.ErrAPIReq,
util.ErrDeploymentID,
}},
},
{
name: "fails on API error",
args: args{params: ShutdownParams{
API: api.NewMock(mock.New500Response(mock.NewStringBody("error"))),
DeploymentID: util.ValidClusterID,
}},
err: errors.New("unknown error (status 500)"),
},
{
name: "Succeeds",
args: args{params: ShutdownParams{
API: api.NewMock(mock.New200Response(mock.NewStructBody(models.DeploymentShutdownResponse{
ID: ec.String(util.ValidClusterID),
}))),
DeploymentID: util.ValidClusterID,
}},
want: &models.DeploymentShutdownResponse{
ID: ec.String(util.ValidClusterID),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Shutdown(tt.args.params)
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("Shutdown() error = %v, wantErr %v", err, tt.err)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Shutdown() = %v, want %v", got, tt.want)
}
})
}
}
2 changes: 2 additions & 0 deletions pkg/util/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ var (
ErrAPIReq = errors.New("api reference is required for command")
// ErrClusterLength is the message returned when a provided cluster id is not of the expected length (32 chars)
ErrClusterLength = errors.New("cluster id should have a length of 32 characters")
// ErrDeploymentID is the message returned when a provided cluster id is not of the expected length (32 chars)
ErrDeploymentID = errors.New("deployment id should have a length of 32 characters")

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

0 comments on commit ee092c6

Please sign in to comment.