diff --git a/pkg/component/component.go b/pkg/component/component.go index af041bcff1d..a0d0fca1cc3 100644 --- a/pkg/component/component.go +++ b/pkg/component/component.go @@ -22,7 +22,9 @@ import ( "github.com/redhat-developer/odo/pkg/devfile/location" "github.com/redhat-developer/odo/pkg/envinfo" "github.com/redhat-developer/odo/pkg/kclient" + "github.com/redhat-developer/odo/pkg/libdevfile" "github.com/redhat-developer/odo/pkg/localConfigProvider" + "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/preference" "github.com/redhat-developer/odo/pkg/service" urlpkg "github.com/redhat-developer/odo/pkg/url" @@ -32,6 +34,7 @@ import ( v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/klog" ) @@ -538,3 +541,55 @@ func Log(client kclient.ClientInterface, componentName string, appName string, f return client.GetPodLogs(pod.Name, containerName, follow) } + +// Delete deletes the component +func Delete(kubeClient kclient.ClientInterface, devfileObj parser.DevfileObj, componentName string, appName string, labels map[string]string, show bool, wait bool) error { + if labels == nil { + return fmt.Errorf("cannot delete with labels being nil") + } + log.Printf("Gathering information for component: %q", componentName) + podSpinner := log.Spinner("Checking status for component") + defer podSpinner.End(false) + + pod, err := GetOnePod(kubeClient, componentName, appName) + if kerrors.IsForbidden(err) { + klog.V(2).Infof("Resource for %s forbidden", componentName) + // log the error if it failed to determine if the component exists due to insufficient RBACs + podSpinner.End(false) + log.Warningf("%v", err) + return nil + } else if e, ok := err.(*kclient.PodNotFoundError); ok { + podSpinner.End(false) + log.Warningf("%v", e) + return nil + } else if err != nil { + return errors.Wrapf(err, "unable to determine if component %s exists", componentName) + } + + podSpinner.End(true) + + // if there are preStop events, execute them before deleting the deployment + if libdevfile.HasPreStopEvents(devfileObj) { + if pod.Status.Phase != corev1.PodRunning { + return fmt.Errorf("unable to execute preStop events, pod for component %s is not running", componentName) + } + log.Infof("\nExecuting %s event commands for component %s", libdevfile.PreStop, componentName) + err = libdevfile.ExecPreStopEvents(devfileObj, componentName, NewExecHandler(kubeClient, pod.Name, show)) + if err != nil { + return err + } + } + + log.Infof("\nDeleting component %s", componentName) + spinner := log.Spinner("Deleting Kubernetes resources for component") + defer spinner.End(false) + + err = kubeClient.Delete(labels, wait) + if err != nil { + return err + } + + spinner.End(true) + log.Successf("Successfully deleted component") + return nil +} diff --git a/pkg/devfile/adapters/kubernetes/component/exec_handler.go b/pkg/component/exec_handler.go similarity index 98% rename from pkg/devfile/adapters/kubernetes/component/exec_handler.go rename to pkg/component/exec_handler.go index c28062996bf..ee91004c2fa 100644 --- a/pkg/devfile/adapters/kubernetes/component/exec_handler.go +++ b/pkg/component/exec_handler.go @@ -23,7 +23,7 @@ type execHandler struct { const ShellExecutable string = "/bin/sh" -func newExecHandler(kubeClient kclient.ClientInterface, podName string, show bool) *execHandler { +func NewExecHandler(kubeClient kclient.ClientInterface, podName string, show bool) *execHandler { return &execHandler{ kubeClient: kubeClient, podName: podName, diff --git a/pkg/devfile/adapters/common/interface.go b/pkg/devfile/adapters/common/interface.go index 07591f2d149..26d8f375ad0 100644 --- a/pkg/devfile/adapters/common/interface.go +++ b/pkg/devfile/adapters/common/interface.go @@ -8,6 +8,5 @@ import ( type ComponentAdapter interface { commandExecutor Push(parameters PushParameters) error - Delete(labels map[string]string, show bool, wait bool) error CheckSupervisordCommandStatus(command devfilev1.Command) error } diff --git a/pkg/devfile/adapters/common/utils.go b/pkg/devfile/adapters/common/utils.go index 4f61be57582..853ef2dcd4b 100644 --- a/pkg/devfile/adapters/common/utils.go +++ b/pkg/devfile/adapters/common/utils.go @@ -17,9 +17,6 @@ import ( // PredefinedDevfileCommands encapsulates constants for predefined devfile commands type PredefinedDevfileCommands string -// DevfileEventType encapsulates constants for devfile events -type DevfileEventType string - const ( // DefaultDevfileRunCommand is a predefined devfile command for run diff --git a/pkg/devfile/adapters/kubernetes/adapter.go b/pkg/devfile/adapters/kubernetes/adapter.go index 83b0e9b311f..5022d7dfeb6 100644 --- a/pkg/devfile/adapters/kubernetes/adapter.go +++ b/pkg/devfile/adapters/kubernetes/adapter.go @@ -53,17 +53,6 @@ func (k Adapter) CheckSupervisordCommandStatus(command devfilev1.Command) error return nil } -// Delete deletes the Kubernetes resources that correspond to the devfile -func (k Adapter) Delete(labels map[string]string, show bool, wait bool) error { - - err := k.componentAdapter.Delete(labels, show, wait) - if err != nil { - return err - } - - return nil -} - func (k Adapter) ExecCMDInContainer(info common.ComponentInfo, cmd []string, stdOut io.Writer, stdErr io.Writer, stdIn io.Reader, show bool) error { return k.componentAdapter.ExecCMDInContainer(info, cmd, stdOut, stdErr, stdIn, show) } diff --git a/pkg/devfile/adapters/kubernetes/component/adapter.go b/pkg/devfile/adapters/kubernetes/component/adapter.go index 5610a1b3b3f..9dfd24e68f0 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter.go @@ -35,7 +35,6 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog" ) @@ -315,7 +314,7 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) { // didn't previously exist if !componentExists && libdevfile.HasPostStartEvents(a.Devfile) { log.Infof("\nExecuting %s event commands for component %s", string(libdevfile.PostStart), a.ComponentName) - err = libdevfile.ExecPostStartEvents(a.Devfile, a.ComponentName, newExecHandler(a.Client, a.pod.Name, parameters.Show)) + err = libdevfile.ExecPostStartEvents(a.Devfile, a.ComponentName, component.NewExecHandler(a.Client, a.pod.Name, parameters.Show)) if err != nil { return err } @@ -646,6 +645,7 @@ func getFirstContainerWithSourceVolume(containers []corev1.Container) (string, s return "", "", fmt.Errorf("in order to sync files, odo requires at least one component in a devfile to set 'mountSources: true'") } +/* // Delete deletes the component func (a Adapter) Delete(labels map[string]string, show bool, wait bool) error { if labels == nil { @@ -696,7 +696,7 @@ func (a Adapter) Delete(labels map[string]string, show bool, wait bool) error { spinner.End(true) log.Successf("Successfully deleted component") return nil -} +}*/ func (a Adapter) ExecCMDInContainer(componentInfo common.ComponentInfo, cmd []string, stdout io.Writer, stderr io.Writer, stdin io.Reader, tty bool) error { return a.Client.ExecCMDInContainer(componentInfo.ContainerName, componentInfo.PodName, cmd, stdout, stderr, stdin, tty) diff --git a/pkg/devfile/adapters/kubernetes/component/adapter_test.go b/pkg/devfile/adapters/kubernetes/component/adapter_test.go index dc9ef6c7902..b377071459d 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter_test.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter_test.go @@ -461,6 +461,7 @@ func TestWaitAndGetComponentPod(t *testing.T) { } +// TODO move to pkg/component func TestAdapterDelete(t *testing.T) { type args struct { labels map[string]string @@ -570,8 +571,6 @@ func TestAdapterDelete(t *testing.T) { fkclient, fkclientset := kclient.FakeNew() - a := New(adapterCtx, fkclient, nil) - fkclientset.Kubernetes.PrependReactor("delete-collection", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) { if util.ConvertLabelsToSelector(tt.args.labels) != action.(ktesting.DeleteCollectionAction).GetListRestrictions().Labels.String() { return true, nil, errors.Errorf("collection labels are not matching, wanted: %v, got: %v", util.ConvertLabelsToSelector(tt.args.labels), action.(ktesting.DeleteCollectionAction).GetListRestrictions().Labels.String()) @@ -590,7 +589,7 @@ func TestAdapterDelete(t *testing.T) { return true, tt.existingPod, nil }) - if err := a.Delete(tt.args.labels, false, false); (err != nil) != tt.wantErr { + if err := component.Delete(fkclient, devObj, tt.componentName, "app", tt.args.labels, false, false); (err != nil) != tt.wantErr { t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/pkg/devfile/validate/errors.go b/pkg/devfile/validate/errors.go index b4bb6c8855e..f84a1d4f517 100644 --- a/pkg/devfile/validate/errors.go +++ b/pkg/devfile/validate/errors.go @@ -38,11 +38,3 @@ type CompositeRunKindError struct { func (e *CompositeRunKindError) Error() string { return "composite commands of run kind are not supported currently" } - -type UnsupportedFieldError struct { - fieldName string -} - -func (e *UnsupportedFieldError) Error() string { - return fmt.Sprintf("%q is not supported in odo", e.fieldName) -} diff --git a/pkg/odo/cli/component/devfile.go b/pkg/odo/cli/component/devfile.go index 25ae09a91a2..bca253dddae 100644 --- a/pkg/odo/cli/component/devfile.go +++ b/pkg/odo/cli/component/devfile.go @@ -11,6 +11,7 @@ import ( devfilefs "github.com/devfile/library/pkg/testingutil/filesystem" dfutil "github.com/devfile/library/pkg/util" + "github.com/redhat-developer/odo/pkg/component" componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/devfile" "github.com/redhat-developer/odo/pkg/devfile/adapters" @@ -131,20 +132,9 @@ func (do *DeleteOptions) DevfileComponentDelete() error { if err != nil { return err } - componentName := do.EnvSpecificInfo.GetName() - - kc := kubernetes.KubernetesContext{ - Namespace: do.KClient.GetCurrentNamespace(), - } - labels := componentlabels.GetLabels(componentName, do.EnvSpecificInfo.GetApplication(), false) - devfileHandler, err := adapters.NewComponentAdapter(componentName, do.contextFlag, do.GetApplication(), devObj, kc) - if err != nil { - return err - } - - return devfileHandler.Delete(labels, do.showLogFlag, do.waitFlag) + return component.Delete(do.KClient, devObj, componentName, do.GetApplication(), labels, do.showLogFlag, do.waitFlag) } type undeployHandler struct {