Skip to content

Commit

Permalink
cmd: Add deployment plan cancel (#72)
Browse files Browse the repository at this point in the history
Adds the deployment plan cancel command which allows users to cancel
pending plans for specific resources.
The syntax is as follows:
ecctl deployment plan cancel <deployment id> --type <type> --ref-id <id>

Signed-off-by: Marc Lopez <marc5.12@outlook.com>
  • Loading branch information
marclop committed Dec 5, 2019
1 parent 520dbf8 commit 88c7938
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cmd/deployment/command.go
Expand Up @@ -24,6 +24,7 @@ import (
cmdelasticsearch "github.com/elastic/ecctl/cmd/deployment/elasticsearch"
cmdkibana "github.com/elastic/ecctl/cmd/deployment/kibana"
cmddeploymentnote "github.com/elastic/ecctl/cmd/deployment/note"
cmddeploymentplan "github.com/elastic/ecctl/cmd/deployment/plan"
)

// Command is the deployment subcommand
Expand All @@ -42,5 +43,6 @@ func init() {
cmdelasticsearch.Command,
cmdkibana.Command,
cmdapm.Command,
cmddeploymentplan.Command,
)
}
56 changes: 56 additions & 0 deletions cmd/deployment/plan/cancel.go
@@ -0,0 +1,56 @@
// 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 cmddeploymentplan

import (
"github.com/spf13/cobra"

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

// cancelPlan is the deployment subcommand
var cancelPlan = &cobra.Command{
Use: "cancel <deployment id> --type <type> --ref-id <ref-id>",
Short: "Cancels a resource's pending plan",
PreRunE: cmdutil.MinimumNArgsAndUUID(1),
RunE: func(cmd *cobra.Command, args []string) error {
force, _ := cmd.Flags().GetBool("force")
resType, _ := cmd.Flags().GetString("type")
refID, _ := cmd.Flags().GetString("ref-id")

_, err := depresource.CancelPlan(depresource.CancelPlanParams{
API: ecctl.Get().API,
DeploymentID: args[0],
Type: resType,
RefID: refID,
ForceDelete: force,
})

return err
},
}

func init() {
Command.AddCommand(cancelPlan)
cancelPlan.Flags().String("type", "", "Optional deployment type to show resource information (elasticsearch, kibana, apm, or appsearch)")
cancelPlan.MarkFlagRequired("type")
cancelPlan.Flags().String("ref-id", "", "Optional deployment type RefId, if not set, the RefId will be auto-discovered")
cancelPlan.MarkFlagRequired("ref-id")
}
32 changes: 32 additions & 0 deletions cmd/deployment/plan/command.go
@@ -0,0 +1,32 @@
// 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 cmddeploymentplan

import (
"github.com/spf13/cobra"
)

// Command is the deployment subcommand
var Command = &cobra.Command{
Use: "plan",
Short: "Manages deployment plans",
PreRunE: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
1 change: 1 addition & 0 deletions docs/ecctl_deployment.md
Expand Up @@ -46,6 +46,7 @@ ecctl deployment [flags]
* [ecctl deployment kibana](ecctl_deployment_kibana.md) - Manages Kibana instances
* [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 plan](ecctl_deployment_plan.md) - Manages deployment plans
* [ecctl deployment restore](ecctl_deployment_restore.md) - Restores a previously shut down deployment and all of its associated sub-resources
* [ecctl deployment search](ecctl_deployment_search.md) - Performs advanced deployment search using the Elasticsearch Query DSL
* [ecctl deployment show](ecctl_deployment_show.md) - Shows the specified deployment resources
Expand Down
43 changes: 43 additions & 0 deletions docs/ecctl_deployment_plan.md
@@ -0,0 +1,43 @@
## ecctl deployment plan

Manages deployment plans

### Synopsis

Manages deployment plans

```
ecctl deployment plan [flags]
```

### Options

```
-h, --help help for plan
```

### 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
--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
--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
* [ecctl deployment plan cancel](ecctl_deployment_plan_cancel.md) - Cancels a resource's pending plan

44 changes: 44 additions & 0 deletions docs/ecctl_deployment_plan_cancel.md
@@ -0,0 +1,44 @@
## ecctl deployment plan cancel

Cancels a resource's pending plan

### Synopsis

Cancels a resource's pending plan

```
ecctl deployment plan cancel <deployment id> --type <type> --ref-id <ref-id> [flags]
```

### Options

```
-h, --help help for cancel
--ref-id string Optional deployment type RefId, if not set, the RefId will be auto-discovered
--type string Optional deployment type to show resource information (elasticsearch, kibana, apm, or appsearch)
```

### 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
--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
--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 plan](ecctl_deployment_plan.md) - Manages deployment plans

80 changes: 80 additions & 0 deletions pkg/deployment/depresource/cancel_plan.go
@@ -0,0 +1,80 @@
// 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 depresource

import (
"errors"

"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/hashicorp/go-multierror"

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

// CancelPlanParams is consumed by CancelPlan
type CancelPlanParams struct {
*api.API

DeploymentID string
Type string
RefID string
ForceDelete bool
}

// Validate ensures the parameters are usable by the consuming function.
func (params CancelPlanParams) 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, deputil.NewInvalidDeploymentIDError(params.DeploymentID))
}

if params.Type == "" {
merr = multierror.Append(merr, errors.New("deployment resource type cannot be empty"))
}

return merr.ErrorOrNil()
}

// CancelPlan cancels a deployment resource plan.
func CancelPlan(params CancelPlanParams) (*models.DeploymentResourceCrudResponse, error) {
if err := params.Validate(); err != nil {
return nil, err
}

res, err := params.V1API.Deployments.CancelDeploymentResourcePendingPlan(
deployments.NewCancelDeploymentResourcePendingPlanParams().
WithDeploymentID(params.DeploymentID).
WithForceDelete(&params.ForceDelete).
WithResourceKind(params.Type).
WithRefID(params.RefID),
params.AuthWriter,
)
if err != nil {
return nil, api.UnwrapError(err)
}

return res.Payload, nil
}
90 changes: 90 additions & 0 deletions pkg/deployment/depresource/cancel_plan_test.go
@@ -0,0 +1,90 @@
// 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 depresource

import (
"encoding/json"
"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/hashicorp/go-multierror"

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

func TestCancelPlan(t *testing.T) {
var internalError = models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{},
},
}
internalErrorBytes, _ := json.MarshalIndent(internalError, "", " ")
type args struct {
params CancelPlanParams
}
tests := []struct {
name string
args args
want *models.DeploymentResourceCrudResponse
err error
}{
{
name: "fails due to parameter validation",
args: args{},
err: &multierror.Error{Errors: []error{
util.ErrAPIReq,
errors.New("id \"\" is invalid"),
errors.New("deployment resource type cannot be empty"),
}},
},
{
name: "fails due to API error",
args: args{params: CancelPlanParams{
API: api.NewMock(mock.New404Response(mock.NewStructBody(internalError))),
DeploymentID: util.ValidClusterID,
Type: "elasticsearch",
}},
err: errors.New(string(internalErrorBytes)),
},
{
name: "succeeds",
args: args{params: CancelPlanParams{
API: api.NewMock(mock.New200Response(mock.NewStringBody(""))),
DeploymentID: util.ValidClusterID,
Type: "elasticsearch",
}},
want: new(models.DeploymentResourceCrudResponse),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CancelPlan(tt.args.params)
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("CancelPlan() error = %v, wantErr %v", err, tt.err)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("CancelPlan() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 88c7938

Please sign in to comment.