Skip to content

Commit

Permalink
odo remove binding (redhat-developer#5787)
Browse files Browse the repository at this point in the history
* odo remove binding

Signed-off-by: Parthvi Vala <[email protected]>

* Documentation

Signed-off-by: Parthvi Vala <[email protected]>

* Refactor pkg/binding and separate add and remove code

* Add unit test

* Rebase alterations

* Refactor

* Philippe's review

Signed-off-by: Parthvi Vala <[email protected]>

* Rebase
  • Loading branch information
valaparthvi authored and cdrage committed Aug 31, 2022
1 parent 8783273 commit dc4dba4
Show file tree
Hide file tree
Showing 13 changed files with 522 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: odo remove binding
---

## Description
The `odo remove binding` command removes the link created between the component and a service via Service Binding.

## Running the Command
Running this command removes the reference from the devfile, but does not necessarily remove it from the cluster. To remove the ServiceBinding from the cluster, you must run `odo dev`, or `odo deploy`.

The command takes a required `--name` flag that points to the name of the Service Binding to be removed.
```shell
odo remove binding --name <ServiceBinding_name>
```

## Examples
```shell
$ odo remove binding --name redis-service-my-nodejs-app
```

There is no interactive mode for this command at the moment.
83 changes: 83 additions & 0 deletions pkg/binding/add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package binding

import (
"fmt"

"github.com/devfile/library/pkg/devfile/parser"
sboApi "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

backendpkg "github.com/redhat-developer/odo/pkg/binding/backend"
"github.com/redhat-developer/odo/pkg/kclient"
"github.com/redhat-developer/odo/pkg/libdevfile"
)

// ValidateAddBinding calls Validate method of the adequate backend
func (o *BindingClient) ValidateAddBinding(flags map[string]string) error {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
return backend.Validate(flags)
}

func (o *BindingClient) SelectServiceInstance(flags map[string]string, serviceMap map[string]unstructured.Unstructured) (string, error) {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
return backend.SelectServiceInstance(flags[backendpkg.FLAG_SERVICE], serviceMap)
}

func (o *BindingClient) AskBindingName(serviceName, componentName string, flags map[string]string) (string, error) {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
defaultBindingName := fmt.Sprintf("%v-%v", componentName, serviceName)
return backend.AskBindingName(defaultBindingName, flags)
}

func (o *BindingClient) AskBindAsFiles(flags map[string]string) (bool, error) {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
return backend.AskBindAsFiles(flags)
}

func (o *BindingClient) AddBinding(bindingName string, bindAsFiles bool, unstructuredService unstructured.Unstructured, obj parser.DevfileObj) (parser.DevfileObj, error) {
service, err := o.kubernetesClient.NewServiceBindingServiceObject(unstructuredService, bindingName)
if err != nil {
return obj, err
}

deploymentName := fmt.Sprintf("%s-app", obj.GetMetadataName())
deploymentGVR, err := o.kubernetesClient.GetDeploymentAPIVersion()
if err != nil {
return obj, err
}

serviceBinding := kclient.NewServiceBindingObject(bindingName, bindAsFiles, deploymentName, deploymentGVR, []sboApi.Mapping{}, []sboApi.Service{service})

// Note: we cannot directly marshal the serviceBinding object to yaml because it doesn't do that in the correct k8s manifest format
serviceBindingUnstructured, err := kclient.ConvertK8sResourceToUnstructured(serviceBinding)
if err != nil {
return obj, err
}
yamlDesc, err := yaml.Marshal(serviceBindingUnstructured.UnstructuredContent())
if err != nil {
return obj, err
}

return libdevfile.AddKubernetesComponentToDevfile(string(yamlDesc), serviceBinding.Name, obj)
}
73 changes: 2 additions & 71 deletions pkg/binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import (
bindingApi "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
specApi "github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha3"

"github.com/devfile/library/pkg/devfile/parser"
devfilefs "github.com/devfile/library/pkg/testingutil/filesystem"
"gopkg.in/yaml.v2"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

devfilev1alpha2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/pkg/devfile/parser"
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
devfilefs "github.com/devfile/library/pkg/testingutil/filesystem"

"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/binding/asker"
Expand Down Expand Up @@ -56,75 +56,6 @@ func (o *BindingClient) GetFlags(flags map[string]string) map[string]string {
return bindingFlags
}

// Validate calls Validate method of the adequate backend
func (o *BindingClient) Validate(flags map[string]string) error {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
return backend.Validate(flags)
}

func (o *BindingClient) SelectServiceInstance(flags map[string]string, serviceMap map[string]unstructured.Unstructured) (string, error) {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
return backend.SelectServiceInstance(flags[backendpkg.FLAG_SERVICE], serviceMap)
}

func (o *BindingClient) AskBindingName(serviceName, componentName string, flags map[string]string) (string, error) {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
defaultBindingName := fmt.Sprintf("%v-%v", componentName, serviceName)
return backend.AskBindingName(defaultBindingName, flags)
}

func (o *BindingClient) AskBindAsFiles(flags map[string]string) (bool, error) {
var backend backendpkg.AddBindingBackend
if len(flags) == 0 {
backend = o.interactiveBackend
} else {
backend = o.flagsBackend
}
return backend.AskBindAsFiles(flags)
}

func (o *BindingClient) AddBinding(bindingName string, bindAsFiles bool, unstructuredService unstructured.Unstructured, obj parser.DevfileObj) (parser.DevfileObj, error) {
service, err := o.kubernetesClient.NewServiceBindingServiceObject(unstructuredService, bindingName)
if err != nil {
return obj, err
}

deploymentName := fmt.Sprintf("%s-app", obj.GetMetadataName())
deploymentGVR, err := o.kubernetesClient.GetDeploymentAPIVersion()
if err != nil {
return obj, err
}

serviceBinding := kclient.NewServiceBindingObject(bindingName, bindAsFiles, deploymentName, deploymentGVR, []bindingApi.Mapping{}, []bindingApi.Service{service})

// Note: we cannot directly marshal the serviceBinding object to yaml because it doesn't do that in the correct k8s manifest format
serviceBindingUnstructured, err := kclient.ConvertK8sResourceToUnstructured(serviceBinding)
if err != nil {
return obj, err
}
yamlDesc, err := yaml.Marshal(serviceBindingUnstructured.UnstructuredContent())
if err != nil {
return obj, err
}

return libdevfile.AddKubernetesComponentToDevfile(string(yamlDesc), serviceBinding.Name, obj)
}

func (o *BindingClient) GetServiceInstances() (map[string]unstructured.Unstructured, error) {
// Get the BindableKinds/bindable-kinds object
bindableKind, err := o.kubernetesClient.GetBindableKinds()
Expand Down
25 changes: 16 additions & 9 deletions pkg/binding/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,30 @@ import (
type Client interface {
// GetFlags gets the necessary flags for binding
GetFlags(flags map[string]string) map[string]string
// Validate returns error if the backend failed to validate; mainly useful for flags backend
Validate(flags map[string]string) error
// GetServiceInstances returns a map of bindable instance name with its unstructured.Unstructured object, and an error
GetServiceInstances() (map[string]unstructured.Unstructured, error)
// GetBindingsFromDevfile returns the bindings defined in the devfile with the status extracted from cluster
GetBindingsFromDevfile(devfileObj parser.DevfileObj, context string) ([]api.ServiceBinding, error)
// GetBindingFromCluster returns information about a binding in the cluster (either from group binding.operators.coreos.com or servicebinding.io)
GetBindingFromCluster(name string) (api.ServiceBinding, error)

// add_binding.go

// ValidateAddBinding returns error if the backend failed to validate; mainly useful for flags backend
ValidateAddBinding(flags map[string]string) error
// SelectServiceInstance returns the service to bind to the component
SelectServiceInstance(flags map[string]string, serviceMap map[string]unstructured.Unstructured) (string, error)
// AskBindingName returns the name to be set for the binding
AskBindingName(serviceName, componentName string, flags map[string]string) (string, error)
// AskBindAsFiles asks if the service should be bound as files
AskBindAsFiles(flags map[string]string) (bool, error)

// AddBinding adds the ServiceBinding manifest to the devfile
AddBinding(bindingName string, bindAsFiles bool, unstructuredService unstructured.Unstructured, obj parser.DevfileObj) (parser.DevfileObj, error)
// GetServiceInstances returns a map of bindable instance name with its unstructured.Unstructured object, and an error
GetServiceInstances() (map[string]unstructured.Unstructured, error)

// GetBindingsFromDevfile returns the bindings defined in the devfile with the status extracted from cluster
GetBindingsFromDevfile(devfileObj parser.DevfileObj, context string) ([]api.ServiceBinding, error)
// remove_binding.go

// GetBindingFromCluster returns information about a binding in the cluster (either from group binding.operators.coreos.com or servicebinding.io)
GetBindingFromCluster(name string) (api.ServiceBinding, error)
// ValidateRemoveBinding validates if the command has adequate arguments/flags
ValidateRemoveBinding(flags map[string]string) error
// RemoveBinding removes the binding from devfile
RemoveBinding(bindingName string, obj parser.DevfileObj) (parser.DevfileObj, error)
}
103 changes: 66 additions & 37 deletions pkg/binding/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit dc4dba4

Please sign in to comment.