Skip to content
This repository has been archived by the owner on May 6, 2022. It is now read-only.

Commit

Permalink
Add --abandon and --yes flags to svcat deprovision command
Browse files Browse the repository at this point in the history
  • Loading branch information
Tara Gu committed May 2, 2019
1 parent f3c7d26 commit 113b3a5
Show file tree
Hide file tree
Showing 9 changed files with 2,466 additions and 1,731 deletions.
48 changes: 47 additions & 1 deletion cmd/svcat/instance/deprovision_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ limitations under the License.
package instance

import (
"bufio"
"fmt"
"os"
"strings"

"github.com/kubernetes-incubator/service-catalog/cmd/svcat/output"
"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/kubernetes-incubator/service-catalog/cmd/svcat/command"
"github.com/spf13/cobra"
Expand All @@ -31,6 +35,8 @@ type deprovisonCmd struct {
*command.Waitable

instanceName string
abandon bool
skipPrompt bool
}

// NewDeprovisionCmd builds a "svcat deprovision" command
Expand All @@ -44,12 +50,26 @@ func NewDeprovisionCmd(cxt *command.Context) *cobra.Command {
Short: "Deletes an instance of a service",
Example: command.NormalizeExamples(`
svcat deprovision wordpress-mysql-instance
svcat deprovision --abandon wordpress-mysql-instance
`),
PreRunE: command.PreRunE(deprovisonCmd),
RunE: command.RunE(deprovisonCmd),
}
deprovisonCmd.AddNamespaceFlags(cmd.Flags(), false)
deprovisonCmd.AddWaitFlags(cmd)
cmd.Flags().BoolVar(
&deprovisonCmd.abandon,
"abandon",
false,
"Forcefully and immediately delete the resource from Service Catalog ONLY, potentially abandoning any broker resources that you may continue to be charged for.",
)
cmd.Flags().BoolVarP(
&deprovisonCmd.skipPrompt,
"yes",
"y",
false,
`Automatic yes to prompts. Assume "yes" as answer to all prompts and run non-interactively.`,
)

return cmd
}
Expand All @@ -68,7 +88,33 @@ func (c *deprovisonCmd) Run() error {
}

func (c *deprovisonCmd) deprovision() error {
err := c.App.Deprovision(c.Namespace, c.instanceName)
var err error
if c.abandon {
fmt.Fprintln(c.Output, "This action is not reversible and may cause you to be charged for the broker resources that are abandoned.")
if !c.skipPrompt {
fmt.Fprintln(c.Output, "Are you sure? [y|n]: ")
s := bufio.NewScanner(os.Stdin)
s.Scan()

err = s.Err()
fmt.Fprintln(c.Output, err)

if strings.ToLower(s.Text()) != "y" {
err = fmt.Errorf("aborted abandon operation")
return err
}
}

si := &v1beta1.ServiceInstance{ObjectMeta: metav1.ObjectMeta{Name: c.instanceName, Namespace: c.Namespace}}
if _, err = c.App.RemoveBindingFinalizerByInstance(si); err != nil {
return err
}
if err = c.App.RemoveFinalizerForInstance(si); err != nil {
return err
}
}

err = c.App.Deprovision(c.Namespace, c.instanceName)
if err != nil {
return err
}
Expand Down
5 changes: 5 additions & 0 deletions cmd/svcat/testdata/output/completion-bash.txt
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ _svcat_deprovision()
flags_with_completion=()
flags_completion=()

flags+=("--abandon")
local_nonpersistent_flags+=("--abandon")
flags+=("--interval=")
local_nonpersistent_flags+=("--interval=")
flags+=("--namespace=")
Expand All @@ -382,6 +384,9 @@ _svcat_deprovision()
local_nonpersistent_flags+=("--timeout=")
flags+=("--wait")
local_nonpersistent_flags+=("--wait")
flags+=("--yes")
flags+=("-y")
local_nonpersistent_flags+=("--yes")
flags+=("--context=")
flags+=("--kubeconfig=")
flags+=("--logtostderr")
Expand Down
5 changes: 5 additions & 0 deletions cmd/svcat/testdata/output/completion-zsh.txt
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ _svcat_deprovision()
flags_with_completion=()
flags_completion=()
flags+=("--abandon")
local_nonpersistent_flags+=("--abandon")
flags+=("--interval=")
local_nonpersistent_flags+=("--interval=")
flags+=("--namespace=")
Expand All @@ -516,6 +518,9 @@ _svcat_deprovision()
local_nonpersistent_flags+=("--timeout=")
flags+=("--wait")
local_nonpersistent_flags+=("--wait")
flags+=("--yes")
flags+=("-y")
local_nonpersistent_flags+=("--yes")
flags+=("--context=")
flags+=("--kubeconfig=")
flags+=("--logtostderr")
Expand Down
12 changes: 11 additions & 1 deletion cmd/svcat/testdata/plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,14 @@ tree:
use: class [NAME] --from [EXISTING_NAME]
use: create
- command: ./svcat deprovision
example: ' svcat deprovision wordpress-mysql-instance'
example: |2-
svcat deprovision wordpress-mysql-instance
svcat deprovision --abandon wordpress-mysql-instance
flags:
- desc: Forcefully and immediately delete the resource from Service Catalog ONLY,
potentially abandoning any broker resources that you may continue to be charged
for.
name: abandon
- desc: 'Poll interval for --wait, specified in human readable format: 30s, 1m,
1h'
name: interval
Expand All @@ -89,6 +95,10 @@ tree:
name: timeout
- desc: Wait until the operation completes.
name: wait
- desc: Automatic yes to prompts. Assume "yes" as answer to all prompts and run
non-interactively.
name: "yes"
shorthand: "y"
name: deprovision
shortDesc: Deletes an instance of a service
use: deprovision NAME
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ func (c *controller) getAuthCredentialsFromClusterServiceBroker(broker *v1beta1.
BearerConfig: bearerConfig,
}, nil
}
return nil, fmt.Errorf("empty auth info or unsupported auth mode: %s", authInfo)
return nil, fmt.Errorf("empty auth info or unsupported auth mode: %v", authInfo)
}

// getAuthCredentialsFromServiceBroker returns the auth credentials, if any, or
Expand Down Expand Up @@ -752,7 +752,7 @@ func (c *controller) getAuthCredentialsFromServiceBroker(broker *v1beta1.Service
BearerConfig: bearerConfig,
}, nil
}
return nil, fmt.Errorf("empty auth info or unsupported auth mode: %s", authInfo)
return nil, fmt.Errorf("empty auth info or unsupported auth mode: %v", authInfo)
}

func getBasicAuthConfig(secret *corev1.Secret) (*osb.BasicAuthConfig, error) {
Expand Down
10 changes: 10 additions & 0 deletions pkg/svcat/service-catalog/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/util/sets"
)

const (
Expand Down Expand Up @@ -291,3 +292,12 @@ func (sdk *SDK) InstanceHasStatus(instance *v1beta1.ServiceInstance, status v1be

return false
}

// RemoveFinalizerForInstance removes v1beta1.FinalizerServiceCatalog from the specified instance.
func (sdk *SDK) RemoveFinalizerForInstance(instance *v1beta1.ServiceInstance) error {
finalizers := sets.NewString(instance.Finalizers...)
finalizers.Delete(v1beta1.FinalizerServiceCatalog)
instance.Finalizers = finalizers.List()
_, err := sdk.ServiceCatalog().ServiceInstances(instance.Namespace).UpdateStatus(instance)
return err
}
32 changes: 32 additions & 0 deletions pkg/svcat/service-catalog/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,4 +743,36 @@ var _ = Describe("Instances", func() {
Expect(actions[0].(testing.GetActionImpl).Namespace).To(Equal(si.Namespace))
})
})

Describe("RemoveFinalizerForInstance", func() {
It("Calls the generated v1beta1 put method with the passed in instance", func() {
err := sdk.RemoveFinalizerForInstance(si)
Expect(err).NotTo(HaveOccurred())

actions := svcCatClient.Actions()
// The one and only action should be an update call
Expect(len(actions)).To(Equal(1))
Expect(actions[0].Matches("update", "serviceinstances")).To(BeTrue())
Expect(actions[0].(testing.UpdateActionImpl).Object.(*v1beta1.ServiceInstance).ObjectMeta.Name).To(Equal(si.Name))
Expect(actions[0].(testing.UpdateActionImpl).Object.(*v1beta1.ServiceInstance).ObjectMeta.Namespace).To(Equal(si.Namespace))
})
It("Bubbles up errors", func() {
errorMessage := "instance not found"
badClient := &fake.Clientset{}
badClient.AddReactor("update", "serviceinstances", func(action testing.Action) (bool, runtime.Object, error) {
return true, nil, fmt.Errorf(errorMessage)
})
sdk.ServiceCatalogClient = badClient

err := sdk.RemoveFinalizerForInstance(si)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(errorMessage))
actions := badClient.Actions()
// The one and only action should be an update call
Expect(len(actions)).To(Equal(1))
Expect(actions[0].Matches("update", "serviceinstances")).To(BeTrue())
Expect(actions[0].(testing.UpdateActionImpl).Object.(*v1beta1.ServiceInstance).ObjectMeta.Name).To(Equal(si.Name))
Expect(actions[0].(testing.UpdateActionImpl).Object.(*v1beta1.ServiceInstance).ObjectMeta.Namespace).To(Equal(si.Namespace))
})
})
})
1 change: 1 addition & 0 deletions pkg/svcat/service-catalog/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type SvcatClient interface {
RemoveBindingFinalizerByInstance(*apiv1beta1.ServiceInstance) ([]types.NamespacedName, error)
RemoveFinalizerForBindings([]types.NamespacedName) ([]types.NamespacedName, error)
RemoveFinalizerForBinding(types.NamespacedName) error
RemoveFinalizerForInstance(*apiv1beta1.ServiceInstance) error

Deregister(string, *ScopeOptions) error
RetrieveBrokers(opts ScopeOptions) ([]Broker, error)
Expand Down
Loading

0 comments on commit 113b3a5

Please sign in to comment.