From 850c7cd7237d531edbb01703a389ad22b5adbe66 Mon Sep 17 00:00:00 2001 From: Philippe Martin Date: Mon, 7 Feb 2022 05:42:15 +0100 Subject: [PATCH] Remove commands that wont be implemented for v3-alpha1 (#5433) * Remove odo staorage commands * Remove "odo service" + "odo catalog * service" commands * Remove odo link/unlink commands * Remove related integration tests * Remove application concept * fix rebase * fix test * Remove config command * Remove env command * Remove application package * Remove config package * Move odogenerator and unions packages into kclient * Move notify package to cli/version * Fix script mockgen * Remove odo debug command oand debug package * Remove odo component describe/exec/log/status/test * Remove operator-hub tests from IBM tests * Remove operator hub tests from CI * Fix e2e tests --- .ibm/pipelines/kubernetes-tests.sh | 1 - .ibm/pipelines/openshift-tests.sh | 1 - .ibm/pipelines/windows-test-script.ps1 | 2 - Makefile | 4 - pkg/application/application.go | 12 - pkg/application/doc.go | 5 - pkg/application/kubernetes.go | 112 --- pkg/application/kubernetes_test.go | 348 -------- pkg/application/mock.go | 122 --- pkg/application/types.go | 29 - pkg/config/config.go | 106 --- pkg/config/config_test.go | 209 ----- pkg/debug/OWNERS | 5 - pkg/debug/info.go | 160 ---- pkg/debug/info_test.go | 369 --------- pkg/debug/portforward.go | 78 -- pkg/envinfo/envinfo.go | 1 + pkg/kclient/fake/ingress.go | 2 +- pkg/kclient/ingress.go | 2 +- pkg/kclient/ingress_test.go | 2 +- pkg/kclient/interface.go | 2 +- pkg/kclient/mock_Client.go | 2 +- .../unions}/ingressgenerator.go | 4 +- .../unions/kubernetes_ingress.go | 3 +- pkg/odo/cli/application/application.go | 48 -- pkg/odo/cli/application/delete.go | 152 ---- pkg/odo/cli/application/delete_test.go | 203 ----- pkg/odo/cli/application/describe.go | 124 --- pkg/odo/cli/application/describe_test.go | 197 ----- pkg/odo/cli/application/list.go | 128 --- pkg/odo/cli/application/list_test.go | 149 ---- pkg/odo/cli/catalog/describe/describe.go | 4 +- pkg/odo/cli/catalog/describe/interface.go | 11 - .../cli/catalog/describe/operator_backend.go | 345 -------- .../catalog/describe/operator_backend_test.go | 50 -- pkg/odo/cli/catalog/describe/service.go | 84 -- pkg/odo/cli/catalog/list/list.go | 8 +- pkg/odo/cli/catalog/list/services.go | 105 --- pkg/odo/cli/catalog/search/search.go | 5 +- pkg/odo/cli/catalog/search/service.go | 86 -- pkg/odo/cli/cli.go | 20 +- pkg/odo/cli/component/common_link.go | 390 --------- pkg/odo/cli/component/component.go | 10 +- pkg/odo/cli/component/create.go | 3 - pkg/odo/cli/component/delete.go | 8 +- pkg/odo/cli/component/describe.go | 117 --- pkg/odo/cli/component/devfile.go | 92 --- pkg/odo/cli/component/exec.go | 97 --- pkg/odo/cli/component/get.go | 3 - pkg/odo/cli/component/link.go | 131 ---- pkg/odo/cli/component/list.go | 3 - pkg/odo/cli/component/log.go | 90 --- pkg/odo/cli/component/status.go | 134 ---- pkg/odo/cli/component/test.go | 104 --- pkg/odo/cli/component/unlink.go | 101 --- pkg/odo/cli/component/watch.go | 4 - pkg/odo/cli/config/config.go | 44 -- pkg/odo/cli/config/set.go | 214 ----- pkg/odo/cli/config/unset.go | 171 ---- pkg/odo/cli/config/view.go | 90 --- pkg/odo/cli/debug/debug.go | 39 - pkg/odo/cli/debug/info.go | 98 --- pkg/odo/cli/debug/portforward.go | 170 ---- pkg/odo/cli/env/env.go | 68 -- pkg/odo/cli/env/env_test.go | 61 -- pkg/odo/cli/env/set.go | 138 ---- pkg/odo/cli/env/unset.go | 129 --- pkg/odo/cli/env/view.go | 93 --- pkg/odo/cli/service/OWNERS | 9 - pkg/odo/cli/service/create.go | 144 ---- pkg/odo/cli/service/delete.go | 117 --- pkg/odo/cli/service/describe.go | 108 --- pkg/odo/cli/service/interface.go | 17 - pkg/odo/cli/service/list.go | 86 -- pkg/odo/cli/service/list_operator.go | 218 ----- pkg/odo/cli/service/list_operator_test.go | 277 ------- pkg/odo/cli/service/operator_backend.go | 385 --------- pkg/odo/cli/service/service.go | 54 -- pkg/odo/cli/service/types.go | 21 - pkg/odo/cli/service/utils.go | 22 - pkg/odo/cli/storage/create.go | 133 ---- pkg/odo/cli/storage/delete.go | 122 --- pkg/odo/cli/storage/list.go | 216 ----- pkg/odo/cli/storage/list_test.go | 130 --- pkg/odo/cli/storage/storage.go | 44 -- pkg/{notify => odo/cli/version}/notify.go | 6 +- .../cli/version}/notify_test.go | 2 +- pkg/odo/cli/version/version.go | 3 +- pkg/odo/util/completion/completionhandlers.go | 20 - pkg/url/kubernetes.go | 2 +- pkg/url/kubernetes_test.go | 2 +- pkg/url/status_test.go | 2 +- pkg/url/types.go | 2 +- scripts/minikube-minishift-all-tests.sh | 1 - scripts/mockgen.sh | 4 - scripts/openshiftci-periodic-tests.sh | 1 - .../openshiftci-presubmit-all-tests-old.sh | 1 - scripts/openshiftci-presubmit-all-tests.sh | 3 - scripts/release-bit-verification.sh | 1 - scripts/run_script_e2e.sh | 1 - tests/e2escenarios/e2e_devfile_test.go | 34 +- tests/integration/cmd_link_unlink_test.go | 216 ----- tests/integration/cmd_pref_config_test.go | 56 -- .../devfile/cmd_devfile_app_test.go | 216 ----- .../devfile/cmd_devfile_catalog_test.go | 4 - .../devfile/cmd_devfile_config_test.go | 92 --- .../devfile/cmd_devfile_create_test.go | 7 - .../devfile/cmd_devfile_debug_test.go | 162 ---- .../devfile/cmd_devfile_delete_test.go | 17 +- .../devfile/cmd_devfile_describe_test.go | 170 ---- .../devfile/cmd_devfile_env_test.go | 118 --- .../devfile/cmd_devfile_exec_test.go | 77 -- .../devfile/cmd_devfile_list_test.go | 63 -- .../devfile/cmd_devfile_log_test.go | 79 -- .../devfile/cmd_devfile_push_test.go | 15 - .../devfile/cmd_devfile_status_test.go | 325 -------- .../devfile/cmd_devfile_storage_test.go | 439 ----------- .../devfile/cmd_devfile_test_test.go | 134 ---- .../devfile/cmd_devfile_watch_test.go | 7 +- .../devfile/cmd_dot_devfile_test.go | 109 --- .../devfile/debug/cmd_devfile_debug_test.go | 91 --- .../integration/operatorhub/cmd_link_test.go | 463 ----------- .../operatorhub/cmd_service_test.go | 742 ------------------ .../operatorhub/operatorhub_suite_test.go | 11 - 124 files changed, 51 insertions(+), 11652 deletions(-) delete mode 100644 pkg/application/application.go delete mode 100644 pkg/application/doc.go delete mode 100644 pkg/application/kubernetes.go delete mode 100644 pkg/application/kubernetes_test.go delete mode 100644 pkg/application/mock.go delete mode 100644 pkg/application/types.go delete mode 100644 pkg/config/config.go delete mode 100644 pkg/config/config_test.go delete mode 100644 pkg/debug/OWNERS delete mode 100644 pkg/debug/info.go delete mode 100644 pkg/debug/info_test.go delete mode 100644 pkg/debug/portforward.go rename pkg/{odogenerator => kclient/unions}/ingressgenerator.go (95%) rename pkg/{ => kclient}/unions/kubernetes_ingress.go (96%) delete mode 100644 pkg/odo/cli/application/application.go delete mode 100644 pkg/odo/cli/application/delete.go delete mode 100644 pkg/odo/cli/application/delete_test.go delete mode 100644 pkg/odo/cli/application/describe.go delete mode 100644 pkg/odo/cli/application/describe_test.go delete mode 100644 pkg/odo/cli/application/list.go delete mode 100644 pkg/odo/cli/application/list_test.go delete mode 100644 pkg/odo/cli/catalog/describe/interface.go delete mode 100644 pkg/odo/cli/catalog/describe/operator_backend.go delete mode 100644 pkg/odo/cli/catalog/describe/operator_backend_test.go delete mode 100644 pkg/odo/cli/catalog/describe/service.go delete mode 100644 pkg/odo/cli/catalog/list/services.go delete mode 100644 pkg/odo/cli/catalog/search/service.go delete mode 100644 pkg/odo/cli/component/common_link.go delete mode 100644 pkg/odo/cli/component/describe.go delete mode 100644 pkg/odo/cli/component/exec.go delete mode 100644 pkg/odo/cli/component/link.go delete mode 100644 pkg/odo/cli/component/log.go delete mode 100644 pkg/odo/cli/component/status.go delete mode 100644 pkg/odo/cli/component/test.go delete mode 100644 pkg/odo/cli/component/unlink.go delete mode 100644 pkg/odo/cli/config/config.go delete mode 100644 pkg/odo/cli/config/set.go delete mode 100644 pkg/odo/cli/config/unset.go delete mode 100644 pkg/odo/cli/config/view.go delete mode 100644 pkg/odo/cli/debug/debug.go delete mode 100644 pkg/odo/cli/debug/info.go delete mode 100644 pkg/odo/cli/debug/portforward.go delete mode 100644 pkg/odo/cli/env/env.go delete mode 100644 pkg/odo/cli/env/env_test.go delete mode 100644 pkg/odo/cli/env/set.go delete mode 100644 pkg/odo/cli/env/unset.go delete mode 100644 pkg/odo/cli/env/view.go delete mode 100644 pkg/odo/cli/service/OWNERS delete mode 100644 pkg/odo/cli/service/create.go delete mode 100644 pkg/odo/cli/service/delete.go delete mode 100644 pkg/odo/cli/service/describe.go delete mode 100644 pkg/odo/cli/service/interface.go delete mode 100644 pkg/odo/cli/service/list.go delete mode 100644 pkg/odo/cli/service/list_operator.go delete mode 100644 pkg/odo/cli/service/list_operator_test.go delete mode 100644 pkg/odo/cli/service/operator_backend.go delete mode 100644 pkg/odo/cli/service/service.go delete mode 100644 pkg/odo/cli/service/types.go delete mode 100644 pkg/odo/cli/service/utils.go delete mode 100644 pkg/odo/cli/storage/create.go delete mode 100644 pkg/odo/cli/storage/delete.go delete mode 100644 pkg/odo/cli/storage/list.go delete mode 100644 pkg/odo/cli/storage/list_test.go delete mode 100644 pkg/odo/cli/storage/storage.go rename pkg/{notify => odo/cli/version}/notify.go (90%) rename pkg/{notify => odo/cli/version}/notify_test.go (97%) delete mode 100644 tests/integration/cmd_link_unlink_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_app_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_config_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_debug_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_describe_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_env_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_exec_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_log_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_status_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_storage_test.go delete mode 100644 tests/integration/devfile/cmd_devfile_test_test.go delete mode 100644 tests/integration/devfile/debug/cmd_devfile_debug_test.go delete mode 100644 tests/integration/operatorhub/cmd_link_test.go delete mode 100644 tests/integration/operatorhub/cmd_service_test.go delete mode 100644 tests/integration/operatorhub/operatorhub_suite_test.go diff --git a/.ibm/pipelines/kubernetes-tests.sh b/.ibm/pipelines/kubernetes-tests.sh index a7fe25c61..8dca26533 100644 --- a/.ibm/pipelines/kubernetes-tests.sh +++ b/.ibm/pipelines/kubernetes-tests.sh @@ -13,7 +13,6 @@ cleanup_namespaces set -e make install make test-integration-devfile - make test-operator-hub make test-e2e-devfile make test-cmd-project ) |& tee "/tmp/${LOGFILE}" diff --git a/.ibm/pipelines/openshift-tests.sh b/.ibm/pipelines/openshift-tests.sh index 21815f790..1a027f5c1 100644 --- a/.ibm/pipelines/openshift-tests.sh +++ b/.ibm/pipelines/openshift-tests.sh @@ -13,7 +13,6 @@ cleanup_namespaces make install make test-integration make test-integration-devfile - make test-operator-hub make test-cmd-login-logout make test-cmd-project make test-e2e-devfile diff --git a/.ibm/pipelines/windows-test-script.ps1 b/.ibm/pipelines/windows-test-script.ps1 index 2110916eb..f271d8830 100644 --- a/.ibm/pipelines/windows-test-script.ps1 +++ b/.ibm/pipelines/windows-test-script.ps1 @@ -66,8 +66,6 @@ function Run-Test { Check-ExitCode $LASTEXITCODE make test-integration | tee -a C:\Users\Administrator.ANSIBLE-TEST-VS\AppData\Local\Temp\$LOGFILE Check-ExitCode $LASTEXITCODE - make test-operator-hub | tee -a C:\Users\Administrator.ANSIBLE-TEST-VS\AppData\Local\Temp\$LOGFILE - Check-ExitCode $LASTEXITCODE make test-cmd-login-logout | tee -a C:\Users\Administrator.ANSIBLE-TEST-VS\AppData\Local\Temp\$LOGFILE Check-ExitCode $LASTEXITCODE make test-cmd-project | tee -a C:\Users\Administrator.ANSIBLE-TEST-VS\AppData\Local\Temp\$LOGFILE diff --git a/Makefile b/Makefile index 142b14957..d300fa918 100644 --- a/Makefile +++ b/Makefile @@ -297,10 +297,6 @@ vendor-update: ## Update vendoring openshiftci-presubmit-unittests: ./scripts/openshiftci-presubmit-unittests.sh -.PHONY: test-operator-hub -test-operator-hub: ## Run OperatorHub tests - $(RUN_GINKGO) $(GINKGO_FLAGS) tests/integration/operatorhub/ - .PHONY: test-cmd-devfile-describe test-cmd-devfile-describe: $(RUN_GINKGO) $(GINKGO_FLAGS) -focus="odo devfile describe command tests" tests/integration/devfile/ diff --git a/pkg/application/application.go b/pkg/application/application.go deleted file mode 100644 index 7169f78f6..000000000 --- a/pkg/application/application.go +++ /dev/null @@ -1,12 +0,0 @@ -package application - -import "github.com/redhat-developer/odo/pkg/component" - -type Client interface { - List() ([]string, error) - Exists(app string) (bool, error) - Delete(name string) error - ComponentList(name string) ([]component.Component, error) - GetMachineReadableFormat(appName string, projectName string) App - GetMachineReadableFormatForList(apps []App) AppList -} diff --git a/pkg/application/doc.go b/pkg/application/doc.go deleted file mode 100644 index 6012c0ca4..000000000 --- a/pkg/application/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package application provides functions to list, check existence of, delete and get machine readable description of applications. -// An application is a set of components and services. -// An application is materialized by the `app:` label in `deployments`, `deploymentconfigs`, -// or service instances (service instances from Operator Backed Services). -package application diff --git a/pkg/application/kubernetes.go b/pkg/application/kubernetes.go deleted file mode 100644 index 8e073ce28..000000000 --- a/pkg/application/kubernetes.go +++ /dev/null @@ -1,112 +0,0 @@ -package application - -import ( - "github.com/pkg/errors" - - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/component" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/util" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog" -) - -type kubernetesClient struct { - client kclient.ClientInterface -} - -func NewClient(client kclient.ClientInterface) Client { - return kubernetesClient{ - client: client, - } -} - -// List all applications names in current project by looking at `app` labels in deployments -func (o kubernetesClient) List() ([]string, error) { - if o.client == nil { - return nil, nil - } - - // Get all Deployments with the "app" label - deploymentAppNames, err := o.client.GetDeploymentLabelValues(applabels.ApplicationLabel, applabels.ApplicationLabel) - if err != nil { - return nil, errors.Wrap(err, "unable to list applications from deployments") - } - - // Filter out any names, as there could be multiple components but within the same application - return util.RemoveDuplicates(deploymentAppNames), nil -} - -// Exists checks whether the given app exist or not in the list of applications -func (o kubernetesClient) Exists(app string) (bool, error) { - - appList, err := o.List() - - if err != nil { - return false, err - } - for _, appName := range appList { - if appName == app { - return true, nil - } - } - return false, nil -} - -// Delete the given application by deleting deployments and services instances belonging to this application -func (o kubernetesClient) Delete(name string) error { - klog.V(4).Infof("Deleting application %q", name) - - labels := applabels.GetLabels(name, false) - - // delete application from cluster - err := o.client.Delete(labels, false) - if err != nil { - return errors.Wrapf(err, "unable to delete application %s", name) - } - - return nil -} - -// ComponentList returns the list of components for an application -func (o kubernetesClient) ComponentList(name string) ([]component.Component, error) { - selector := applabels.GetSelector(name) - componentList, err := component.List(o.client, selector) - if err != nil { - return nil, errors.Wrap(err, "failed to get Component list") - } - return componentList.Items, nil -} - -// GetMachineReadableFormat returns resource information in machine readable format -func (o kubernetesClient) GetMachineReadableFormat(appName string, projectName string) App { - componentList, _ := component.GetComponentNames(o.client, appName) - appDef := App{ - TypeMeta: metav1.TypeMeta{ - Kind: appKind, - APIVersion: machineoutput.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: appName, - Namespace: projectName, - }, - Spec: AppSpec{ - Components: componentList, - }, - } - return appDef -} - -// GetMachineReadableFormatForList returns application list in machine readable format -func (o kubernetesClient) GetMachineReadableFormatForList(apps []App) AppList { - return AppList{ - TypeMeta: metav1.TypeMeta{ - Kind: appList, - APIVersion: machineoutput.APIVersion, - }, - ListMeta: metav1.ListMeta{}, - Items: apps, - } -} diff --git a/pkg/application/kubernetes_test.go b/pkg/application/kubernetes_test.go deleted file mode 100644 index 67a46b496..000000000 --- a/pkg/application/kubernetes_test.go +++ /dev/null @@ -1,348 +0,0 @@ -package application - -import ( - "errors" - "reflect" - "strings" - "testing" - - gomock "github.com/golang/mock/gomock" - - applabels "github.com/redhat-developer/odo/pkg/application/labels" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/testingutil" - "github.com/redhat-developer/odo/pkg/unions" - "github.com/redhat-developer/odo/pkg/version" - - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - ktesting "k8s.io/client-go/testing" -) - -func TestList(t *testing.T) { - ctrl := gomock.NewController(t) - kubclient := kclient.NewMockClientInterface(ctrl) - kubclient.EXPECT().GetDeploymentLabelValues("app.kubernetes.io/part-of", "app.kubernetes.io/part-of").Return([]string{"app1", "app3", "app1", "app2"}, nil).AnyTimes() - appClient := NewClient(kubclient) - result, err := appClient.List() - expected := []string{"app1", "app2", "app3"} - if err != nil { - t.Errorf("Expected nil error, got %s", err) - } - if !reflect.DeepEqual(result, expected) { - t.Errorf("Got %v, expected %v", result, expected) - } -} - -func TestExists(t *testing.T) { - - tests := []struct { - name string - search string - result bool - err bool - }{ - { - name: "not exists", - search: "an-app", - result: false, - err: false, - }, - { - name: "exists", - search: "app1", - result: true, - err: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctrl := gomock.NewController(t) - kubclient := kclient.NewMockClientInterface(ctrl) - kubclient.EXPECT().GetDeploymentLabelValues("app.kubernetes.io/part-of", "app.kubernetes.io/part-of").Return([]string{"app1", "app3", "app1", "app2"}, nil).AnyTimes() - appClient := NewClient(kubclient) - result, err := appClient.Exists(tt.search) - if err != nil != tt.err { - t.Errorf("Expected %v error, got %v", tt.err, err) - } - if result != tt.result { - t.Errorf("Expected %v, got %v", tt.result, result) - } - }) - } - -} - -func TestDelete(t *testing.T) { - - tests := []struct { - name string - deleteReturn error - expectedErr string - }{ - { - name: "kubernetes delete works", - deleteReturn: nil, - expectedErr: "", - }, - { - name: "kubernetes delete fails", - deleteReturn: errors.New("an error"), - expectedErr: "unable to delete application", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctrl := gomock.NewController(t) - kubclient := kclient.NewMockClientInterface(ctrl) - appClient := NewClient(kubclient) - labels := map[string]string{ - "app.kubernetes.io/part-of": "an-app", - } - kubclient.EXPECT().Delete(labels, false).Return(tt.deleteReturn).Times(1) - - // kube Delete works - err := appClient.Delete("an-app") - - if err == nil && tt.expectedErr != "" { - t.Errorf("Expected %v, got no error", tt.expectedErr) - return - } - if err != nil && tt.expectedErr == "" { - t.Errorf("Expected no error, got %v", err.Error()) - return - } - if err != nil && tt.expectedErr != "" && !strings.Contains(err.Error(), tt.expectedErr) { - t.Errorf("Expected error %v, got %v", tt.expectedErr, err.Error()) - return - } - if err != nil { - return - } - }) - } -} - -func TestComponentList(t *testing.T) { - ctrl := gomock.NewController(t) - kubclient := kclient.NewMockClientInterface(ctrl) - depList := []appsv1.Deployment{ - { - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/instance": "a-component", - "app.kubernetes.io/part-of": "an-app-name", - }, - Annotations: map[string]string{ - "odo.dev/project-type": "nodejs", - }, - }, - }, - } - kubclient.EXPECT().GetDeploymentFromSelector("app=an-app-name,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=an-app-name").Return(depList, nil).AnyTimes() - kubclient.EXPECT().GetCurrentNamespace().Return("my-namespace").AnyTimes() - kubclient.EXPECT().GetOneDeployment("a-component", "an-app-name").Return(&depList[0], nil).AnyTimes() - ingresses := &unions.KubernetesIngressList{ - Items: nil, - } - kubclient.EXPECT().ListIngresses("app.kubernetes.io/instance=a-component,app.kubernetes.io/part-of=an-app-name").Return(ingresses, nil).AnyTimes() - kubclient.EXPECT().IsServiceBindingSupported().Return(false, nil).AnyTimes() - kubclient.EXPECT().ListSecrets("app.kubernetes.io/instance=a-component,app.kubernetes.io/part-of=an-app-name").Return(nil, nil).AnyTimes() - kubclient.EXPECT().ListServices("").Return(nil, nil).AnyTimes() - appClient := NewClient(kubclient) - - result, err := appClient.ComponentList("an-app-name") - if len(result) != 1 { - t.Errorf("expected 1 component in list, got %d", len(result)) - } - component := result[0] - if component.Name != "a-component" { - t.Errorf("Expected component name %q, got %q", "a-component", component.Name) - } - if err != nil { - t.Errorf("Expected no error, got %s", err) - } -} - -func TestGetMachineReadableFormat(t *testing.T) { - type args struct { - appName string - projectName string - active bool - } - tests := []struct { - name string - args args - want App - }{ - { - - name: "Test Case: machine readable output for application", - args: args{ - appName: "myapp", - projectName: "myproject", - active: true, - }, - want: App{ - TypeMeta: metav1.TypeMeta{ - Kind: appKind, - APIVersion: machineoutput.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "myapp", - Namespace: "myproject", - }, - Spec: AppSpec{ - Components: []string{"frontend"}, - }, - }, - }, - } - deploymentList := appsv1.DeploymentList{ - Items: []appsv1.Deployment{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "frontend-myapp", - Namespace: "myproject", - Labels: map[string]string{ - applabels.ApplicationLabel: "myapp", - componentlabels.ComponentLabel: "frontend", - componentlabels.ComponentTypeLabel: "nodejs", - applabels.ManagedBy: "odo", - applabels.ManagerVersion: version.VERSION, - }, - }, - Spec: appsv1.DeploymentSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "dummyContainer", - }, - }, - }, - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "backend-app", - Namespace: "myproject", - Labels: map[string]string{ - applabels.ApplicationLabel: "app", - componentlabels.ComponentLabel: "backend", - componentlabels.ComponentTypeLabel: "java", - applabels.ManagedBy: "odo", - applabels.ManagerVersion: version.VERSION, - }, - }, - Spec: appsv1.DeploymentSpec{ - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "dummyContainer", - }, - }, - }, - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Fake the client with the appropriate arguments - client, fakeClientSet := kclient.FakeNew() - - // fake the project - fakeClientSet.Kubernetes.PrependReactor("get", "projects", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) { - return true, &testingutil.FakeOnlyOneExistingProjects().Items[0], nil - }) - - //fake the deployments - fakeClientSet.Kubernetes.PrependReactor("list", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) { - return true, &deploymentList, nil - }) - - for i := range deploymentList.Items { - fakeClientSet.Kubernetes.PrependReactor("get", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) { - return true, &deploymentList.Items[i], nil - }) - } - kclient := NewClient(client) - if got := kclient.GetMachineReadableFormat(tt.args.appName, tt.args.projectName); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetMachineReadableFormat() = %v,\n want %v", got, tt.want) - } - }) - } -} - -func TestGetMachineReadableFormatForList(t *testing.T) { - type args struct { - apps []App - } - tests := []struct { - name string - args args - want AppList - }{ - { - name: "Test Case: Machine Readable for Application List", - args: args{ - apps: []App{ - { - TypeMeta: metav1.TypeMeta{ - Kind: appKind, - APIVersion: machineoutput.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "myapp", - }, - Spec: AppSpec{ - Components: []string{"frontend"}, - }, - }, - }, - }, - want: AppList{ - TypeMeta: metav1.TypeMeta{ - Kind: appList, - APIVersion: machineoutput.APIVersion, - }, - ListMeta: metav1.ListMeta{}, - Items: []App{ - { - TypeMeta: metav1.TypeMeta{ - Kind: appKind, - APIVersion: machineoutput.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "myapp", - }, - Spec: AppSpec{ - Components: []string{"frontend"}, - }, - }, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - client, _ := kclient.FakeNew() - kclient := NewClient(client) - if got := kclient.GetMachineReadableFormatForList(tt.args.apps); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetMachineReadableFormatForList() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/application/mock.go b/pkg/application/mock.go deleted file mode 100644 index a01f724d0..000000000 --- a/pkg/application/mock.go +++ /dev/null @@ -1,122 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: pkg/application/application.go - -// Package application is a generated GoMock package. -package application - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - component "github.com/redhat-developer/odo/pkg/component" -) - -// MockClient is a mock of Client interface. -type MockClient struct { - ctrl *gomock.Controller - recorder *MockClientMockRecorder -} - -// MockClientMockRecorder is the mock recorder for MockClient. -type MockClientMockRecorder struct { - mock *MockClient -} - -// NewMockClient creates a new mock instance. -func NewMockClient(ctrl *gomock.Controller) *MockClient { - mock := &MockClient{ctrl: ctrl} - mock.recorder = &MockClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockClient) EXPECT() *MockClientMockRecorder { - return m.recorder -} - -// ComponentList mocks base method. -func (m *MockClient) ComponentList(name string) ([]component.Component, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ComponentList", name) - ret0, _ := ret[0].([]component.Component) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ComponentList indicates an expected call of ComponentList. -func (mr *MockClientMockRecorder) ComponentList(name interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ComponentList", reflect.TypeOf((*MockClient)(nil).ComponentList), name) -} - -// Delete mocks base method. -func (m *MockClient) Delete(name string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", name) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockClientMockRecorder) Delete(name interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClient)(nil).Delete), name) -} - -// Exists mocks base method. -func (m *MockClient) Exists(app string) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Exists", app) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Exists indicates an expected call of Exists. -func (mr *MockClientMockRecorder) Exists(app interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockClient)(nil).Exists), app) -} - -// GetMachineReadableFormat mocks base method. -func (m *MockClient) GetMachineReadableFormat(appName, projectName string) App { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMachineReadableFormat", appName, projectName) - ret0, _ := ret[0].(App) - return ret0 -} - -// GetMachineReadableFormat indicates an expected call of GetMachineReadableFormat. -func (mr *MockClientMockRecorder) GetMachineReadableFormat(appName, projectName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMachineReadableFormat", reflect.TypeOf((*MockClient)(nil).GetMachineReadableFormat), appName, projectName) -} - -// GetMachineReadableFormatForList mocks base method. -func (m *MockClient) GetMachineReadableFormatForList(apps []App) AppList { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMachineReadableFormatForList", apps) - ret0, _ := ret[0].(AppList) - return ret0 -} - -// GetMachineReadableFormatForList indicates an expected call of GetMachineReadableFormatForList. -func (mr *MockClientMockRecorder) GetMachineReadableFormatForList(apps interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMachineReadableFormatForList", reflect.TypeOf((*MockClient)(nil).GetMachineReadableFormatForList), apps) -} - -// List mocks base method. -func (m *MockClient) List() ([]string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "List") - ret0, _ := ret[0].([]string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// List indicates an expected call of List. -func (mr *MockClientMockRecorder) List() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List)) -} diff --git a/pkg/application/types.go b/pkg/application/types.go deleted file mode 100644 index ccabecfe9..000000000 --- a/pkg/application/types.go +++ /dev/null @@ -1,29 +0,0 @@ -package application - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const ( - appKind = "Application" - appList = "List" -) - -// Application -type App struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Spec AppSpec `json:"spec,omitempty"` -} - -// AppSpec is list of components present in given application -type AppSpec struct { - Components []string `json:"components,omitempty"` -} - -// AppList is a list of applications -type AppList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []App `json:"items"` -} diff --git a/pkg/config/config.go b/pkg/config/config.go deleted file mode 100644 index 2b5a09c3f..000000000 --- a/pkg/config/config.go +++ /dev/null @@ -1,106 +0,0 @@ -package config - -import ( - "strings" - - "github.com/devfile/library/pkg/devfile/parser" - - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/util" -) - -const ( - // Name is the name of the setting controlling the component name - Name = "Name" - // NameDescription is human-readable description of the Name setting - NameDescription = "The name of the component" - // Memory is the name of the setting controlling the memory a component consumes - Memory = "Memory" - // MemoryDescription is the description of the setting controlling the min and max memory to same value - MemoryDescription = "The minimum and maximum memory a component can consume" - // Ports is the space separated list of user specified ports to be opened in the component - Ports = "Ports" - // PortsDescription is the description of the ports component setting - PortsDescription = "Ports to be opened in the component" -) - -var ( - supportedDevfileParameterDescriptions = map[string]string{ - Name: NameDescription, - Ports: PortsDescription, - Memory: MemoryDescription, - } - lowerCaseDevfileParameters = util.GetLowerCaseParameters(GetDevfileSupportedParameters()) -) - -// FormatDevfileSupportedParameters outputs supported parameters and their description -func FormatDevfileSupportedParameters() (result string) { - for _, v := range GetDevfileSupportedParameters() { - result = result + " " + v + " - " + supportedDevfileParameterDescriptions[v] + "\n" - } - return "\nAvailable Parameters for Devfile Components:\n" + result -} - -func GetDevfileSupportedParameters() []string { - return util.GetSortedKeys(supportedDevfileParameterDescriptions) -} - -// AsDevfileSupportedParameter returns the parameter in lower case and a boolean indicating if it is a supported parameter -func AsDevfileSupportedParameter(param string) (string, bool) { - lower := strings.ToLower(param) - return lower, lowerCaseDevfileParameters[lower] -} - -// SetDevfileConfiguration allows setting all the parameters that are configurable in a devfile -func SetDevfileConfiguration(d parser.DevfileObj, parameter string, value interface{}) error { - - // we are ignoring this error becase a developer is usually aware of the type of value that is - // being passed. So consider this a shortcut, if you know its a string value use this strValue - // else parse it inside the switch case. - strValue, _ := value.(string) - if param, ok := AsDevfileSupportedParameter(parameter); ok { - switch param { - case "name": - return d.SetMetadataName(strValue) - case "ports": - arrValue := strings.Split(strValue, ",") - return d.SetPorts(arrValue...) - case "memory": - return d.SetMemory(strValue) - } - - } - return errors.Errorf("unknown parameter :'%s' is not a configurable parameter in the devfile", parameter) - -} - -// DeleteConfiguration allows deleting the parameters that are configurable in a devfile -func DeleteDevfileConfiguration(d parser.DevfileObj, parameter string) error { - if param, ok := AsDevfileSupportedParameter(parameter); ok { - switch param { - case "name": - return d.SetMetadataName("") - case "ports": - return d.RemovePorts() - case "memory": - return d.SetMemory("") - } - } - return errors.Errorf("unknown parameter :'%s' is not a configurable parameter in the devfile", parameter) -} - -// IsSet checks if a parameter is set in the devfile -func IsSetInDevfile(d parser.DevfileObj, parameter string) bool { - if p, ok := AsDevfileSupportedParameter(parameter); ok { - switch p { - case "name": - return d.GetMetadataName() != "" - case "ports": - return d.HasPorts() - case "memory": - return d.GetMemory() != "" - } - } - return false - -} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go deleted file mode 100644 index ca9409d1b..000000000 --- a/pkg/config/config_test.go +++ /dev/null @@ -1,209 +0,0 @@ -package config - -import ( - "reflect" - "testing" - - "github.com/devfile/library/pkg/devfile/parser/data" - - devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" - "github.com/devfile/library/pkg/devfile/parser" - devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" - devfilefs "github.com/devfile/library/pkg/testingutil/filesystem" - "github.com/kylelemons/godebug/pretty" - odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil" -) - -func TestSetDevfileConfiguration(t *testing.T) { - - // Use fakeFs - fs := devfilefs.NewFakeFs() - - tests := []struct { - name string - args map[string]string - currentDevfile parser.DevfileObj - wantDevFile parser.DevfileObj - wantErr bool - }{ - { - name: "case 1: set memory to 500Mi", - args: map[string]string{ - "memory": "500Mi", - }, - currentDevfile: odoTestingUtil.GetTestDevfileObj(fs), - wantDevFile: parser.DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), - Data: func() data.DevfileData { - devfileData, err := data.NewDevfileData(string(data.APISchemaVersion200)) - if err != nil { - t.Error(err) - } - err = devfileData.AddComponents([]devfilev1.Component{ - { - Name: "runtime", - ComponentUnion: devfilev1.ComponentUnion{ - Container: &devfilev1.ContainerComponent{ - Container: devfilev1.Container{ - Image: "quay.io/nodejs-12", - MemoryLimit: "500Mi", - }, - Endpoints: []devfilev1.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, - }, - }, - }, - }, - }, - { - Name: "loadbalancer", - ComponentUnion: devfilev1.ComponentUnion{ - Container: &devfilev1.ContainerComponent{ - Container: devfilev1.Container{ - Image: "quay.io/nginx", - MemoryLimit: "500Mi", - }, - }, - }, - }, - }) - if err != nil { - t.Error(err) - } - err = devfileData.AddCommands([]devfilev1.Command{ - { - Id: "devbuild", - CommandUnion: devfilev1.CommandUnion{ - Exec: &devfilev1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }) - if err != nil { - t.Error(err) - } - return devfileData - }(), - }, - }, - { - name: "case 2: set ports array", - args: map[string]string{ - "ports": "8080,8081/UDP,8080/TCP", - }, - currentDevfile: odoTestingUtil.GetTestDevfileObj(fs), - wantDevFile: parser.DevfileObj{ - Ctx: devfileCtx.FakeContext(fs, parser.OutputDevfileYamlPath), - Data: func() data.DevfileData { - devfileData, err := data.NewDevfileData(string(data.APISchemaVersion200)) - if err != nil { - t.Error(err) - } - err = devfileData.AddCommands([]devfilev1.Command{ - { - Id: "devbuild", - CommandUnion: devfilev1.CommandUnion{ - Exec: &devfilev1.ExecCommand{ - WorkingDir: "/projects/nodejs-starter", - }, - }, - }, - }) - if err != nil { - t.Error(err) - } - err = devfileData.AddComponents([]devfilev1.Component{ - { - Name: "runtime", - ComponentUnion: devfilev1.ComponentUnion{ - Container: &devfilev1.ContainerComponent{ - Container: devfilev1.Container{ - Image: "quay.io/nodejs-12", - }, - Endpoints: []devfilev1.Endpoint{ - { - Name: "port-3030", - TargetPort: 3000, - }, - { - Name: "port-8080-tcp", - TargetPort: 8080, - Protocol: "tcp", - }, { - Name: "port-8081-udp", - TargetPort: 8081, - Protocol: "udp", - }, - }, - }, - }, - }, - { - Name: "loadbalancer", - ComponentUnion: devfilev1.ComponentUnion{ - Container: &devfilev1.ContainerComponent{ - Container: devfilev1.Container{ - Image: "quay.io/nginx", - }, - Endpoints: []devfilev1.Endpoint{ - { - Name: "port-8080-tcp", - TargetPort: 8080, - Protocol: "tcp", - }, { - Name: "port-8081-udp", - TargetPort: 8081, - Protocol: "udp", - }, - }, - }, - }, - }, - }) - if err != nil { - t.Error(err) - } - return devfileData - }(), - }, - }, - { - name: "case 3: set ports array fails due to validation", - args: map[string]string{ - "ports": "8080,8081/UDP,8083/", - }, - currentDevfile: odoTestingUtil.GetTestDevfileObj(fs), - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - for key, value := range tt.args { - err := SetDevfileConfiguration(tt.currentDevfile, key, value) - if tt.wantErr { - if err == nil { - t.Errorf("expected error but got nil") - } - // we dont expect an error here - } else { - if err != nil { - t.Errorf("error while setting configuration %+v", err.Error()) - } - } - } - - if !tt.wantErr { - if !reflect.DeepEqual(tt.currentDevfile.Data, tt.wantDevFile.Data) { - t.Errorf("wanted: %v, got: %v, difference at %v", tt.wantDevFile, tt.currentDevfile, pretty.Compare(tt.currentDevfile.Data, tt.wantDevFile.Data)) - } - } - - }) - } - -} diff --git a/pkg/debug/OWNERS b/pkg/debug/OWNERS deleted file mode 100644 index f16ee1949..000000000 --- a/pkg/debug/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md - -approvers: -- mik-dass - diff --git a/pkg/debug/info.go b/pkg/debug/info.go deleted file mode 100644 index 05941b5e1..000000000 --- a/pkg/debug/info.go +++ /dev/null @@ -1,160 +0,0 @@ -package debug - -import ( - "encoding/json" - "errors" - "net" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "syscall" - - "github.com/redhat-developer/odo/pkg/testingutil/filesystem" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/klog" -) - -// Info contains the information about the current Debug session -type Info struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - Spec InfoSpec `json:"spec"` -} - -type InfoSpec struct { - App string `json:"app,omitempty"` - DebugProcessID int `json:"debugProcessID"` - RemotePort int `json:"remotePort"` - LocalPort int `json:"localPort"` -} - -// GetDebugInfoFilePath gets the file path of the debug info file -func GetDebugInfoFilePath(componentName, appName string, projectName string) string { - tempDir := os.TempDir() - debugFileSuffix := "odo-debug.json" - var arr []string - if appName == "" { - arr = []string{projectName, componentName, debugFileSuffix} - } else { - arr = []string{projectName, appName, componentName, debugFileSuffix} - } - debugFileName := strings.Join(arr, "-") - return filepath.Join(tempDir, debugFileName) -} - -func CreateDebugInfoFile(f *DefaultPortForwarder, portPair string) error { - return createDebugInfoFile(f, portPair, filesystem.DefaultFs{}) -} - -// createDebugInfoFile creates a file in the temp directory with information regarding the debugging session of a component -func createDebugInfoFile(f *DefaultPortForwarder, portPair string, fs filesystem.Filesystem) error { - portPairs := strings.Split(portPair, ":") - if len(portPairs) != 2 { - return errors.New("port pair should be of the format localPort:RemotePort") - } - - localPort, err := strconv.Atoi(portPairs[0]) - if err != nil { - return errors.New("local port should be a int") - } - remotePort, err := strconv.Atoi(portPairs[1]) - if err != nil { - return errors.New("remote port should be a int") - } - - debugFile := Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: f.componentName, - Namespace: f.projectName, - }, - Spec: InfoSpec{ - App: f.appName, - DebugProcessID: os.Getpid(), - RemotePort: remotePort, - LocalPort: localPort, - }, - } - odoDebugPathData, err := json.Marshal(debugFile) - if err != nil { - return errors.New("error marshalling json data") - } - - // writes the data to the debug info file - file, err := fs.OpenFile(GetDebugInfoFilePath(f.componentName, f.appName, f.projectName), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) - if err != nil { - return err - } - defer file.Close() // #nosec G307 - - _, err = file.Write(odoDebugPathData) - if err != nil { - return err - } - return nil -} - -// GetInfo gathers the information with regards to debugging information -func GetInfo(f *DefaultPortForwarder) (Info, bool) { - return getInfo(f, filesystem.DefaultFs{}) -} - -// getInfo gets information regarding the debugging session of the component -// returns the OdoDebugFile from the debug info file -// returns true if debugging is running else false -func getInfo(f *DefaultPortForwarder, fs filesystem.Filesystem) (Info, bool) { - // gets the debug info file path and reads/unmarshalls it - debugInfoFilePath := GetDebugInfoFilePath(f.componentName, f.appName, f.projectName) - readFile, err := fs.ReadFile(debugInfoFilePath) - if err != nil { - klog.V(4).Infof("the debug %v is not present", debugInfoFilePath) - return Info{}, false - } - - var info Info - err = json.Unmarshal(readFile, &info) - if err != nil { - klog.V(4).Infof("couldn't unmarshal the debug file %v", debugInfoFilePath) - return Info{}, false - } - - // get the debug process id and send a signal 0 to check if it's alive or not - // according to https://golang.org/pkg/os/#FindProcess - // On Unix systems, FindProcess always succeeds and returns a Process for the given pid, regardless of whether the process exists. - // thus this step will pass on Unix systems and so for those systems and some others supporting signals - // we check if the process is alive or not by sending a signal 0 to the process - processInfo, err := os.FindProcess(info.Spec.DebugProcessID) - if err != nil || processInfo == nil { - klog.V(4).Infof("error getting the process info for pid %v", info.Spec.DebugProcessID) - return Info{}, false - } - - // signal is not available on windows so we skip this step for windows - if runtime.GOOS != "windows" { - err = processInfo.Signal(syscall.Signal(0)) - if err != nil { - klog.V(4).Infof("error sending signal 0 to pid %v, cause: %v", info.Spec.DebugProcessID, err) - return Info{}, false - } - } - - // gets the debug local port and tries to listen on it - // if error doesn't occur the debug port was free and thus no debug process was using the port - addressLook := "localhost:" + strconv.Itoa(info.Spec.LocalPort) - listener, err := net.Listen("tcp", addressLook) - if err == nil { - klog.V(4).Infof("the debug port %v is free, thus debug is not running", info.Spec.LocalPort) - err = listener.Close() - if err != nil { - klog.V(4).Infof("error occurred while closing the listener, cause :%v", err) - } - return Info{}, false - } - - return info, true -} diff --git a/pkg/debug/info_test.go b/pkg/debug/info_test.go deleted file mode 100644 index 94fd1cf92..000000000 --- a/pkg/debug/info_test.go +++ /dev/null @@ -1,369 +0,0 @@ -package debug - -import ( - "encoding/json" - "os" - "reflect" - "testing" - - "github.com/redhat-developer/odo/pkg/util" - - "github.com/redhat-developer/odo/pkg/testingutil" - "github.com/redhat-developer/odo/pkg/testingutil/filesystem" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// fakeOdoDebugFileString creates a json string of a fake OdoDebugFile -func fakeOdoDebugFileString(typeMeta metav1.TypeMeta, processID int, projectName, appName, componentName string, remotePort, localPort int) (string, error) { - file := Info{ - TypeMeta: typeMeta, - ObjectMeta: metav1.ObjectMeta{ - Namespace: projectName, - Name: componentName, - }, - Spec: InfoSpec{ - App: appName, - DebugProcessID: processID, - RemotePort: remotePort, - LocalPort: localPort, - }, - } - - data, err := json.Marshal(file) - if err != nil { - return "", err - } - return string(data), nil -} - -func Test_createDebugInfoFile(t *testing.T) { - - // create a fake fs in memory - fs := filesystem.NewFakeFs() - - type args struct { - defaultPortForwarder *DefaultPortForwarder - portPair string - fs filesystem.Filesystem - } - tests := []struct { - name string - args args - alreadyExistFile bool - wantDebugInfo Info - wantErr bool - }{ - { - name: "case 1: normal json write to the debug file", - args: args{ - defaultPortForwarder: &DefaultPortForwarder{ - componentName: "nodejs-ex", - appName: "app", - projectName: "testing-1", - }, - portPair: "5858:9001", - fs: fs, - }, - wantDebugInfo: Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nodejs-ex", - Namespace: "testing-1", - }, - Spec: InfoSpec{ - DebugProcessID: os.Getpid(), - App: "app", - RemotePort: 9001, - LocalPort: 5858, - }, - }, - alreadyExistFile: false, - wantErr: false, - }, - { - name: "case 2: overwrite the debug file", - args: args{ - defaultPortForwarder: &DefaultPortForwarder{ - componentName: "nodejs-ex", - appName: "app", - projectName: "testing-1", - }, - portPair: "5758:9004", - fs: fs, - }, - wantDebugInfo: Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nodejs-ex", - Namespace: "testing-1", - }, - Spec: InfoSpec{ - DebugProcessID: os.Getpid(), - App: "app", - RemotePort: 9004, - LocalPort: 5758, - }, - }, - alreadyExistFile: true, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - debugFilePath := GetDebugInfoFilePath(tt.args.defaultPortForwarder.componentName, tt.args.defaultPortForwarder.appName, tt.args.defaultPortForwarder.projectName) - // create a already existing file - if tt.alreadyExistFile { - _, err := testingutil.MkFileWithContent(debugFilePath, "blah", fs) - if err != nil { - t.Errorf("error happened while writing, cause: %v", err) - } - } - - if err := createDebugInfoFile(tt.args.defaultPortForwarder, tt.args.portPair, tt.args.fs); (err != nil) != tt.wantErr { - t.Errorf("createDebugInfoFile() error = %v, wantErr %v", err, tt.wantErr) - } - - readBytes, err := fs.ReadFile(debugFilePath) - if err != nil { - t.Errorf("error while reading file, cause: %v", err) - } - var odoDebugFileData Info - err = json.Unmarshal(readBytes, &odoDebugFileData) - if err != nil { - t.Errorf("error occured while unmarshalling json, cause: %v", err) - } - - if !reflect.DeepEqual(tt.wantDebugInfo, odoDebugFileData) { - t.Errorf("odo debug info on file doesn't match, got: %v, want: %v", odoDebugFileData, tt.wantDebugInfo) - } - - // clear the odo debug info file - _ = fs.RemoveAll(debugFilePath) - }) - } -} - -func Test_getDebugInfo(t *testing.T) { - - // create a fake fs in memory - fs := filesystem.NewFakeFs() - - type args struct { - defaultPortForwarder *DefaultPortForwarder - fs filesystem.Filesystem - } - tests := []struct { - name string - args args - fileExists bool - debugPortListening bool - readDebugFile Info - wantDebugFile Info - debugRunning bool - }{ - { - name: "case 1: the debug file exists", - args: args{ - defaultPortForwarder: &DefaultPortForwarder{ - appName: "app", - componentName: "nodejs-ex", - projectName: "testing-1", - }, - fs: fs, - }, - wantDebugFile: Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nodejs-ex", - Namespace: "testing-1", - }, - Spec: InfoSpec{ - DebugProcessID: os.Getpid(), - App: "app", - RemotePort: 5858, - LocalPort: 9001, - }, - }, - readDebugFile: Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nodejs-ex", - Namespace: "testing-1", - }, - Spec: InfoSpec{ - DebugProcessID: os.Getpid(), - App: "app", - RemotePort: 5858, - LocalPort: 9001, - }, - }, - debugPortListening: true, - fileExists: true, - debugRunning: true, - }, - { - name: "case 2: the debug file doesn't exists", - args: args{ - defaultPortForwarder: &DefaultPortForwarder{ - appName: "app", - componentName: "nodejs-ex", - projectName: "testing-1", - }, - fs: fs, - }, - debugPortListening: true, - wantDebugFile: Info{}, - readDebugFile: Info{}, - fileExists: false, - debugRunning: false, - }, - { - name: "case 3: debug port not listening", - args: args{ - defaultPortForwarder: &DefaultPortForwarder{ - appName: "app", - componentName: "nodejs-ex", - projectName: "testing-1", - }, - fs: fs, - }, - debugPortListening: false, - wantDebugFile: Info{}, - readDebugFile: Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nodejs-ex", - Namespace: "testing-1", - }, - Spec: InfoSpec{ - DebugProcessID: os.Getpid(), - App: "app", - RemotePort: 5858, - LocalPort: 9001, - }, - }, - fileExists: true, - debugRunning: false, - }, - { - name: "case 4: the process is not running", - args: args{ - defaultPortForwarder: &DefaultPortForwarder{ - appName: "app", - componentName: "nodejs-ex", - projectName: "testing-1", - }, - fs: fs, - }, - debugPortListening: true, - wantDebugFile: Info{}, - readDebugFile: Info{ - TypeMeta: metav1.TypeMeta{ - Kind: "OdoDebugInfo", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nodejs-ex", - Namespace: "testing-1", - }, - Spec: InfoSpec{ - DebugProcessID: os.Getpid() + 818177979, - App: "app", - RemotePort: 5858, - LocalPort: 9001, - }, - }, - fileExists: true, - debugRunning: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - freePort, err := util.HTTPGetFreePort() - if err != nil { - t.Errorf("error occured while getting a free port, cause: %v", err) - } - - if tt.readDebugFile.Spec.LocalPort != 0 { - tt.readDebugFile.Spec.LocalPort = freePort - } - - if tt.wantDebugFile.Spec.LocalPort != 0 { - tt.wantDebugFile.Spec.LocalPort = freePort - } - - odoDebugFilePath := GetDebugInfoFilePath(tt.args.defaultPortForwarder.componentName, tt.args.defaultPortForwarder.appName, tt.args.defaultPortForwarder.projectName) - if tt.fileExists { - fakeString, err := fakeOdoDebugFileString(tt.readDebugFile.TypeMeta, - tt.readDebugFile.Spec.DebugProcessID, - tt.readDebugFile.ObjectMeta.Namespace, - tt.readDebugFile.Spec.App, - tt.readDebugFile.ObjectMeta.Name, - tt.readDebugFile.Spec.RemotePort, - tt.readDebugFile.Spec.LocalPort) - - if err != nil { - t.Errorf("error occured while getting odo debug file string, cause: %v", err) - } - - _, err = testingutil.MkFileWithContent(odoDebugFilePath, fakeString, fs) - if err != nil { - t.Errorf("error occured while writing to file, cause: %v", err) - } - } - - stopListenerChan := make(chan bool) - listenerStarted := false - if tt.debugPortListening { - startListenerChan := make(chan bool) - go func() { - err := testingutil.FakePortListener(startListenerChan, stopListenerChan, tt.readDebugFile.Spec.LocalPort) - if err != nil { - // the fake listener failed, show error and close the channel - t.Errorf("error while starting fake port listerner, cause: %v", err) - close(startListenerChan) - } - }() - // wait for the test server to start listening - if <-startListenerChan { - listenerStarted = true - } - } - - got, resultRunning := getInfo(tt.args.defaultPortForwarder, tt.args.fs) - - if !reflect.DeepEqual(got, tt.wantDebugFile) { - t.Errorf("getDebugInfo() got = %v, want %v", got, tt.wantDebugFile) - } - if resultRunning != tt.debugRunning { - t.Errorf("getDebugInfo() got1 = %v, want %v", resultRunning, tt.debugRunning) - } - - // clear the odo debug info file - _ = fs.RemoveAll(odoDebugFilePath) - - // close the listener - if listenerStarted == true { - stopListenerChan <- true - } - close(stopListenerChan) - }) - } -} diff --git a/pkg/debug/portforward.go b/pkg/debug/portforward.go deleted file mode 100644 index 1d8135c33..000000000 --- a/pkg/debug/portforward.go +++ /dev/null @@ -1,78 +0,0 @@ -package debug - -import ( - "github.com/redhat-developer/odo/pkg/kclient" - "k8s.io/client-go/rest" - - "fmt" - "net/http" - - "github.com/redhat-developer/odo/pkg/log" - corev1 "k8s.io/api/core/v1" - - k8sgenclioptions "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/tools/portforward" - "k8s.io/client-go/transport/spdy" -) - -// DefaultPortForwarder implements the SPDY based port forwarder -type DefaultPortForwarder struct { - kClient kclient.ClientInterface - k8sgenclioptions.IOStreams - componentName string - appName string - projectName string -} - -func NewDefaultPortForwarder(componentName, appName string, projectName string, kClient kclient.ClientInterface, streams k8sgenclioptions.IOStreams) *DefaultPortForwarder { - return &DefaultPortForwarder{ - kClient: kClient, - IOStreams: streams, - componentName: componentName, - appName: appName, - projectName: projectName, - } -} - -// ForwardPorts forwards the port using the url for the remote pod. -// portPair is a pair of port in format "localPort:RemotePort" that is to be forwarded -// stop Chan is used to stop port forwarding -// ready Chan is used to signal failure to the channel receiver -func (f *DefaultPortForwarder) ForwardPorts(portPair string, stopChan, readyChan chan struct{}, isDevfile bool) error { - var pod *corev1.Pod - var conf *rest.Config - var err error - - if f.kClient != nil && isDevfile { - conf, err = f.kClient.GetConfig().ClientConfig() - if err != nil { - return err - } - - pod, err = f.kClient.GetOnePod(f.componentName, f.appName) - if err != nil { - return err - } - } else { - conf = f.kClient.GetClientConfig() - } - - if pod.Status.Phase != corev1.PodRunning { - return fmt.Errorf("unable to forward port because pod is not running. Current status=%v", pod.Status.Phase) - } - - transport, upgrader, err := spdy.RoundTripperFor(conf) - if err != nil { - return err - } - - req := f.kClient.GeneratePortForwardReq(pod.Name) - - dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", req.URL()) - fw, err := portforward.New(dialer, []string{portPair}, stopChan, readyChan, f.Out, f.ErrOut) - if err != nil { - return err - } - log.Info("Started port forwarding at ports -", portPair) - return fw.ForwardPorts() -} diff --git a/pkg/envinfo/envinfo.go b/pkg/envinfo/envinfo.go index 79a815136..271767a90 100644 --- a/pkg/envinfo/envinfo.go +++ b/pkg/envinfo/envinfo.go @@ -1,3 +1,4 @@ +// envinfo package is DEPRECATED and will be removed during v3 implementation package envinfo import ( diff --git a/pkg/kclient/fake/ingress.go b/pkg/kclient/fake/ingress.go index c4c1158c9..f71cfe6f8 100644 --- a/pkg/kclient/fake/ingress.go +++ b/pkg/kclient/fake/ingress.go @@ -6,7 +6,7 @@ import ( "github.com/devfile/library/pkg/devfile/generator" applabels "github.com/redhat-developer/odo/pkg/application/labels" componentlabels "github.com/redhat-developer/odo/pkg/component/labels" - "github.com/redhat-developer/odo/pkg/unions" + "github.com/redhat-developer/odo/pkg/kclient/unions" "github.com/redhat-developer/odo/pkg/url/labels" "github.com/redhat-developer/odo/pkg/util" "github.com/redhat-developer/odo/pkg/version" diff --git a/pkg/kclient/ingress.go b/pkg/kclient/ingress.go index bd0c0551b..7b84c32c2 100644 --- a/pkg/kclient/ingress.go +++ b/pkg/kclient/ingress.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/redhat-developer/odo/pkg/unions" + "github.com/redhat-developer/odo/pkg/kclient/unions" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/pkg/kclient/ingress_test.go b/pkg/kclient/ingress_test.go index 9c3882f18..f6922868e 100644 --- a/pkg/kclient/ingress_test.go +++ b/pkg/kclient/ingress_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/redhat-developer/odo/pkg/unions" + "github.com/redhat-developer/odo/pkg/kclient/unions" "github.com/devfile/library/pkg/devfile/generator" "github.com/pkg/errors" diff --git a/pkg/kclient/interface.go b/pkg/kclient/interface.go index 0c6124085..15c73e752 100644 --- a/pkg/kclient/interface.go +++ b/pkg/kclient/interface.go @@ -11,8 +11,8 @@ import ( projectv1 "github.com/openshift/api/project/v1" routev1 "github.com/openshift/api/route/v1" olm "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/redhat-developer/odo/pkg/kclient/unions" "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/unions" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/kclient/mock_Client.go b/pkg/kclient/mock_Client.go index 0490acdfb..7ffe948a6 100644 --- a/pkg/kclient/mock_Client.go +++ b/pkg/kclient/mock_Client.go @@ -14,8 +14,8 @@ import ( v1 "github.com/openshift/api/project/v1" v10 "github.com/openshift/api/route/v1" v1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + unions "github.com/redhat-developer/odo/pkg/kclient/unions" log "github.com/redhat-developer/odo/pkg/log" - unions "github.com/redhat-developer/odo/pkg/unions" v11 "k8s.io/api/apps/v1" v12 "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/api/meta" diff --git a/pkg/odogenerator/ingressgenerator.go b/pkg/kclient/unions/ingressgenerator.go similarity index 95% rename from pkg/odogenerator/ingressgenerator.go rename to pkg/kclient/unions/ingressgenerator.go index 13ff26c14..7e7d628a0 100644 --- a/pkg/odogenerator/ingressgenerator.go +++ b/pkg/kclient/unions/ingressgenerator.go @@ -1,4 +1,4 @@ -package odogenerator +package unions import ( "github.com/devfile/library/pkg/devfile/generator" @@ -54,7 +54,7 @@ func getNetworkingV1IngressSpec(ingressSpecParams generator.IngressSpecParams) * return ingressSpec } -func GetNetworkingV1Ingress(ingressParams generator.IngressParams) *v1.Ingress { +func getNetworkingV1Ingress(ingressParams generator.IngressParams) *v1.Ingress { var ip *v1.Ingress ingressSpec := getNetworkingV1IngressSpec(ingressParams.IngressSpecParams) ip = &v1.Ingress{ diff --git a/pkg/unions/kubernetes_ingress.go b/pkg/kclient/unions/kubernetes_ingress.go similarity index 96% rename from pkg/unions/kubernetes_ingress.go rename to pkg/kclient/unions/kubernetes_ingress.go index 10339be50..a2eee45f3 100644 --- a/pkg/unions/kubernetes_ingress.go +++ b/pkg/kclient/unions/kubernetes_ingress.go @@ -5,7 +5,6 @@ import ( v1alpha2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/devfile/library/pkg/devfile/generator" - "github.com/redhat-developer/odo/pkg/odogenerator" "k8s.io/api/extensions/v1beta1" v1 "k8s.io/api/networking/v1" ) @@ -37,7 +36,7 @@ func NewGeneratedKubernetesIngress() *KubernetesIngress { //NewKubernetesIngressFromParams generates a new KubernetesIngress from the ingress params func NewKubernetesIngressFromParams(ingressParams generator.IngressParams) *KubernetesIngress { ki := NewGeneratedKubernetesIngress() - ki.NetworkingV1Ingress = odogenerator.GetNetworkingV1Ingress(ingressParams) + ki.NetworkingV1Ingress = getNetworkingV1Ingress(ingressParams) ki.ExtensionV1Beta1Ingress = generator.GetIngress(v1alpha2.Endpoint{}, ingressParams) return ki } diff --git a/pkg/odo/cli/application/application.go b/pkg/odo/cli/application/application.go deleted file mode 100644 index 3ae0cd436..000000000 --- a/pkg/odo/cli/application/application.go +++ /dev/null @@ -1,48 +0,0 @@ -package application - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/redhat-developer/odo/pkg/odo/util" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" -) - -// RecommendedCommandName is the recommended app command name -const RecommendedCommandName = "app" - -// NewCmdApplication implements the odo application command -func NewCmdApplication(name, fullName string) *cobra.Command { - delete := NewCmdDelete(deleteRecommendedCommandName, odoutil.GetFullName(fullName, deleteRecommendedCommandName)) - describe := NewCmdDescribe(describeRecommendedCommandName, odoutil.GetFullName(fullName, describeRecommendedCommandName)) - list := NewCmdList(listRecommendedCommandName, odoutil.GetFullName(fullName, listRecommendedCommandName)) - applicationCmd := &cobra.Command{ - Use: name, - Short: "Perform application operations", - Long: `Performs application operations related to your project.`, - Example: fmt.Sprintf("%s\n\n%s\n\n%s", - delete.Example, - describe.Example, - list.Example), - Aliases: []string{"application"}, - Run: func(cmd *cobra.Command, args []string) { - }, - } - - applicationCmd.AddCommand(delete, describe, list) - - // Add a defined annotation in order to appear in the help menu - applicationCmd.Annotations = map[string]string{"command": "main"} - applicationCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - - return applicationCmd -} - -// AddApplicationFlag adds a `app` flag to the given cobra command -// Also adds a completion handler to the flag -func AddApplicationFlag(cmd *cobra.Command) { - cmd.Flags().String(util.ApplicationFlagName, "", "Application, defaults to active application") - completion.RegisterCommandFlagHandler(cmd, "app", completion.AppCompletionHandler) -} diff --git a/pkg/odo/cli/application/delete.go b/pkg/odo/cli/application/delete.go deleted file mode 100644 index bc42424a7..000000000 --- a/pkg/odo/cli/application/delete.go +++ /dev/null @@ -1,152 +0,0 @@ -package application - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/redhat-developer/odo/pkg/application" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/cli/ui" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoUtil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const deleteRecommendedCommandName = "delete" - -var ( - deleteExample = ktemplates.Examples(` # Delete the application - %[1]s myapp`) -) - -// DeleteOptions encapsulates the options for the odo command -type DeleteOptions struct { - // Context - *genericclioptions.Context - - // Clients - appClient application.Client - - // Parameters - appName string - - // Flags - forceFlag bool -} - -// NewDeleteOptions creates a new DeleteOptions instance -func NewDeleteOptions(appClient application.Client) *DeleteOptions { - return &DeleteOptions{ - appClient: appClient, - } -} - -// Complete completes DeleteOptions after they've been created -func (o *DeleteOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - o.appName = o.GetApplication() - if len(args) == 1 { - // If app name passed, consider it for deletion - o.appName = args[0] - } - return -} - -// Validate validates the DeleteOptions based on completed values -func (o *DeleteOptions) Validate() (err error) { - if o.Context.GetProject() == "" || o.appName == "" { - return odoUtil.ThrowContextError() - } - - exist, err := o.appClient.Exists(o.appName) - if !exist { - return fmt.Errorf("%s app does not exists", o.appName) - } - return err -} - -// Run contains the logic for the odo command -func (o *DeleteOptions) Run() (err error) { - if o.IsJSON() { - return o.appClient.Delete(o.appName) - } - - // Print App Information which will be deleted - err = printAppInfo(o.appClient, o.appName, o.GetProject()) - if err != nil { - return err - } - - if o.forceFlag || ui.Proceed(fmt.Sprintf("Are you sure you want to delete the application: %v from project: %v", o.appName, o.GetProject())) { - err = o.appClient.Delete(o.appName) - if err != nil { - return err - } - log.Infof("Deleted application: %s from project: %v", o.appName, o.GetProject()) - } else { - log.Infof("Aborting deletion of application: %v", o.appName) - } - return nil -} - -// printAppInfo will print information about the app requested for deletion -func printAppInfo(appClient application.Client, appName string, projectName string) error { - components, err := appClient.ComponentList(appName) - if err != nil { - return err - } - if len(components) != 0 { - log.Info("This application has following components that will be deleted") - for _, currentComponent := range components { - log.Info("component named", currentComponent.Name) - - if len(currentComponent.Spec.URL) != 0 { - log.Info("This component has following urls that will be deleted with component") - for _, u := range currentComponent.Spec.URLSpec { - log.Info("URL named", u.GetName(), "with host", u.Spec.Host, "having protocol", u.Spec.Protocol, "at port", u.Spec.Port) - } - } - - if len(currentComponent.Spec.Storage) != 0 { - log.Info("The component has following storages which will be deleted with the component") - for _, storage := range currentComponent.Spec.StorageSpec { - store := storage - log.Info("Storage named", store.GetName(), "of size", store.Spec.Size) - } - } - } - } - return nil -} - -// NewCmdDelete implements the odo command. -func NewCmdDelete(name, fullName string) *cobra.Command { - // The error is not handled at this point, it will be handled during Context creation - kubclient, _ := kclient.New() - o := NewDeleteOptions(application.NewClient(kubclient)) - command := &cobra.Command{ - Use: name, - Short: "Delete the given application", - Long: "Delete the given application", - Example: fmt.Sprintf(deleteExample, fullName), - Args: cobra.MaximumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - command.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Delete application without prompting") - - project.AddProjectFlag(command) - completion.RegisterCommandHandler(command, completion.AppCompletionHandler) - return command -} diff --git a/pkg/odo/cli/application/delete_test.go b/pkg/odo/cli/application/delete_test.go deleted file mode 100644 index ee39ed42d..000000000 --- a/pkg/odo/cli/application/delete_test.go +++ /dev/null @@ -1,203 +0,0 @@ -package application - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/golang/mock/gomock" - - "github.com/redhat-developer/odo/pkg/application" - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/testingutil/filesystem" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestDelete(t *testing.T) { - - prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-") - if err != nil { - t.Errorf("Error creating temp directory for tests") - return - } - workingDir := filepath.Join(prefixDir, "myapp") - - tests := []struct { - name string - populateWorkingDir func(fs filesystem.Filesystem) - args []string - existingApps []string - wantAppName string - wantErrValidate string - }{ - { - name: "default app", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "an-app-name", - }, - { - name: "app from args", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - args: []string{"another-app-name"}, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "another-app-name", - }, - { - name: "empty app name", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "", - }) - }, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "", - wantErrValidate: "Please specify the application name and project name", - }, - { - name: "non existing app name", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - args: []string{"an-unknown-app-name"}, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "an-unknown-app-name", - wantErrValidate: " app does not exists", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution) - os.RemoveAll(prefixDir) - // the second one to cleanup after execution - defer os.RemoveAll(prefixDir) - - // Fake Cobra - ctrl := gomock.NewController(t) - defer ctrl.Finish() - cmdline := cmdline.NewMockCmdline(ctrl) - - // Fake odo Kube client - kclient := kclient.NewMockClientInterface(ctrl) - - /* Mocks for Complete */ - cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes() - cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes() - cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes() - cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes() - - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "a-project", - }, - } - kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes() - kclient.EXPECT().SetNamespace("a-project").AnyTimes() - - tt.populateWorkingDir(filesystem.DefaultFs{}) - - /* Mocks for Complete */ - appClient := application.NewMockClient(ctrl) - appClient.EXPECT().Exists(tt.wantAppName).Return(func() bool { - for _, app := range tt.existingApps { - if tt.wantAppName == app { - return true - } - } - return false - }(), nil).AnyTimes() - appClient.EXPECT().ComponentList(tt.wantAppName).AnyTimes() - opts := NewDeleteOptions(appClient) - // Force to disable interactive confirmation - opts.forceFlag = true - - /* COMPLETE */ - err := opts.Complete(cmdline, tt.args) - - if err != nil { - t.Errorf("Expected nil error, got %s", err) - return - } - if opts.appName != tt.wantAppName { - t.Errorf("Got appName %q, expected %q", opts.appName, tt.wantAppName) - } - - /* VALIDATE */ - err = opts.Validate() - - if err == nil && tt.wantErrValidate != "" { - t.Errorf("Expected %v, got no error", tt.wantErrValidate) - return - } - if err != nil && tt.wantErrValidate == "" { - t.Errorf("Expected no error, got %v", err.Error()) - return - } - if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) { - t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error()) - return - } - if err != nil { - return - } - - /* Mocks for Run */ - kclient.EXPECT().GetDeploymentFromSelector(fmt.Sprintf("app=%s,app.kubernetes.io/managed-by=odo,app.kubernetes.io/part-of=%s", tt.wantAppName, tt.wantAppName)).AnyTimes() - appClient.EXPECT().Delete(tt.wantAppName).Times(1) - - /* RUN */ - err = opts.Run() - if err != nil { - t.Errorf("Expected nil err, got %s", err) - } - }) - } -} diff --git a/pkg/odo/cli/application/describe.go b/pkg/odo/cli/application/describe.go deleted file mode 100644 index f3af947a7..000000000 --- a/pkg/odo/cli/application/describe.go +++ /dev/null @@ -1,124 +0,0 @@ -package application - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/redhat-developer/odo/pkg/application" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const describeRecommendedCommandName = "describe" - -var ( - describeExample = ktemplates.Examples(` # Describe 'webapp' application - %[1]s webapp`) -) - -// DescribeOptions encapsulates the options for the odo command -type DescribeOptions struct { - // Context - *genericclioptions.Context - - // Clients - appClient application.Client - - // Parameters - appName string -} - -// NewDescribeOptions creates a new DescribeOptions instance -func NewDescribeOptions(appClient application.Client) *DescribeOptions { - return &DescribeOptions{ - appClient: appClient, - } -} - -// Complete completes DescribeOptions after they've been created -func (o *DescribeOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - o.appName = o.GetApplication() - if len(args) == 1 { - o.appName = args[0] - } - return -} - -// Validate validates the DescribeOptions based on completed values -func (o *DescribeOptions) Validate() (err error) { - if o.Context.GetProject() == "" || o.appName == "" { - return util.ThrowContextError() - } - - exist, err := o.appClient.Exists(o.appName) - if !exist { - return fmt.Errorf("%s app does not exists", o.appName) - } - return err -} - -// Run contains the logic for the odo command -func (o *DescribeOptions) Run() (err error) { - if o.IsJSON() { - appDef := o.appClient.GetMachineReadableFormat(o.appName, o.GetProject()) - machineoutput.OutputSuccess(appDef) - return nil - } - - componentList, err := o.appClient.ComponentList(o.appName) - if err != nil { - return err - } - - if len(componentList) == 0 { - fmt.Printf("Application %s has no components or services deployed.", o.appName) - return - } - - fmt.Printf("Application Name: %s has %v component(s):\n--------------------------------------\n", - o.appName, len(componentList)) - for _, currentComponent := range componentList { - err := util.PrintComponentInfo(o.KClient, currentComponent.Name, currentComponent, o.appName, o.GetProject()) - if err != nil { - return err - } - fmt.Println("--------------------------------------") - } - - return nil -} - -// NewCmdDescribe implements the odo command. -func NewCmdDescribe(name, fullName string) *cobra.Command { - // The error is not handled at this point, it will be handled during Context creation - kubclient, _ := kclient.New() - o := NewDescribeOptions(application.NewClient(kubclient)) - command := &cobra.Command{ - Use: fmt.Sprintf("%s [application_name]", name), - Short: "Describe the given application", - Long: "Describe the given application", - Example: fmt.Sprintf(describeExample, fullName), - Args: cobra.MaximumNArgs(1), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - completion.RegisterCommandHandler(command, completion.AppCompletionHandler) - - project.AddProjectFlag(command) - return command -} diff --git a/pkg/odo/cli/application/describe_test.go b/pkg/odo/cli/application/describe_test.go deleted file mode 100644 index 88902cdf0..000000000 --- a/pkg/odo/cli/application/describe_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package application - -import ( - "os" - "path/filepath" - "strings" - "testing" - - "github.com/golang/mock/gomock" - - "github.com/redhat-developer/odo/pkg/application" - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/testingutil/filesystem" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestDescribe(t *testing.T) { - - prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-") - if err != nil { - t.Errorf("Error creating temp directory for tests") - return - } - workingDir := filepath.Join(prefixDir, "myapp") - - tests := []struct { - name string - populateWorkingDir func(fs filesystem.Filesystem) - args []string - existingApps []string - wantAppName string - wantErrValidate string - }{ - { - name: "default app", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "an-app-name", - }, - { - name: "app from args", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - args: []string{"another-app-name"}, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "another-app-name", - }, - { - name: "empty app name", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "", - }) - }, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "", - wantErrValidate: "Please specify the application name and project name", - }, - { - name: "non existing app name", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - args: []string{"an-unknown-app-name"}, - existingApps: []string{"an-app-name", "another-app-name"}, - wantAppName: "an-unknown-app-name", - wantErrValidate: " app does not exists", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution) - os.RemoveAll(prefixDir) - // the second one to cleanup after execution - defer os.RemoveAll(prefixDir) - - // Fake Cobra - ctrl := gomock.NewController(t) - defer ctrl.Finish() - cmdline := cmdline.NewMockCmdline(ctrl) - - // Fake odo Kube client - kclient := kclient.NewMockClientInterface(ctrl) - - /* Mocks for Complete */ - cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes() - cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes() - cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes() - cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes() - - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "a-project", - }, - } - kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes() - kclient.EXPECT().SetNamespace("a-project").AnyTimes() - - tt.populateWorkingDir(filesystem.DefaultFs{}) - - /* Mocks for Complete */ - appClient := application.NewMockClient(ctrl) - appClient.EXPECT().Exists(tt.wantAppName).Return(func() bool { - for _, app := range tt.existingApps { - if tt.wantAppName == app { - return true - } - } - return false - }(), nil).AnyTimes() - opts := NewDescribeOptions(appClient) - - /* COMPLETE */ - err := opts.Complete(cmdline, tt.args) - - if err != nil { - return - } - if opts.appName != tt.wantAppName { - t.Errorf("Got appName %q, expected %q", opts.appName, tt.wantAppName) - } - - /* VALIDATE */ - err = opts.Validate() - - if err == nil && tt.wantErrValidate != "" { - t.Errorf("Expected %v, got no error", tt.wantErrValidate) - return - } - if err != nil && tt.wantErrValidate == "" { - t.Errorf("Expected no error, got %v", err.Error()) - return - } - if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) { - t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error()) - return - } - if err != nil { - return - } - - /* Mocks for Run */ - appClient.EXPECT().ComponentList(tt.wantAppName) - - /* RUN */ - err = opts.Run() - if err != nil { - t.Errorf("Expected nil err, got %s", err) - } - }) - } -} diff --git a/pkg/odo/cli/application/list.go b/pkg/odo/cli/application/list.go deleted file mode 100644 index 068954847..000000000 --- a/pkg/odo/cli/application/list.go +++ /dev/null @@ -1,128 +0,0 @@ -package application - -import ( - "fmt" - "os" - "text/tabwriter" - - "github.com/spf13/cobra" - - "github.com/redhat-developer/odo/pkg/application" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/odo/util" - - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const listRecommendedCommandName = "list" - -var ( - listExample = ktemplates.Examples(` # List all applications in the current project - %[1]s - - # List all applications in the specified project - %[1]s --project myproject`) -) - -// ListOptions encapsulates the options for the odo command -type ListOptions struct { - // Context - *genericclioptions.Context - - // Clients - appClient application.Client -} - -// NewListOptions creates a new ListOptions instance -func NewListOptions(appClient application.Client) *ListOptions { - return &ListOptions{ - appClient: appClient, - } -} - -// Complete completes ListOptions after they've been created -func (o *ListOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - return err -} - -// Validate validates the ListOptions based on completed values -func (o *ListOptions) Validate() (err error) { - // list doesn't need the app name - if o.Context.GetProject() == "" { - return util.ThrowContextError() - } - return nil -} - -// Run contains the logic for the odo command -func (o *ListOptions) Run() (err error) { - apps, err := o.appClient.List() - if err != nil { - return fmt.Errorf("unable to get list of applications: %v", err) - } - - if len(apps) == 0 { - if o.IsJSON() { - apps := o.appClient.GetMachineReadableFormatForList([]application.App{}) - machineoutput.OutputSuccess(apps) - return nil - } - - log.Infof("There are no applications deployed in the project '%v'", o.GetProject()) - return nil - } - - if o.IsJSON() { - var appList []application.App - for _, app := range apps { - appDef := o.appClient.GetMachineReadableFormat(app, o.GetProject()) - appList = append(appList, appDef) - } - - appListDef := o.appClient.GetMachineReadableFormatForList(appList) - machineoutput.OutputSuccess(appListDef) - return nil - } - - log.Infof("The project '%v' has the following applications:", o.GetProject()) - tabWriter := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent) - _, err = fmt.Fprintln(tabWriter, "NAME") - if err != nil { - return err - } - for _, app := range apps { - _, err := fmt.Fprintln(tabWriter, app) - if err != nil { - return err - } - } - return tabWriter.Flush() - -} - -// NewCmdList implements the odo command. -func NewCmdList(name, fullName string) *cobra.Command { - // The error is not handled at this point, it will be handled during Context creation - kubclient, _ := kclient.New() - o := NewListOptions(application.NewClient(kubclient)) - command := &cobra.Command{ - Use: name, - Short: "List all applications in the current project", - Long: "List all applications in the current project", - Example: fmt.Sprintf(listExample, fullName), - Args: cobra.NoArgs, - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - project.AddProjectFlag(command) - return command -} diff --git a/pkg/odo/cli/application/list_test.go b/pkg/odo/cli/application/list_test.go deleted file mode 100644 index 1c3bf519b..000000000 --- a/pkg/odo/cli/application/list_test.go +++ /dev/null @@ -1,149 +0,0 @@ -package application - -import ( - "os" - "path/filepath" - "strings" - "testing" - - "github.com/golang/mock/gomock" - - "github.com/redhat-developer/odo/pkg/application" - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/testingutil/filesystem" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestList(t *testing.T) { - - prefixDir, err := os.MkdirTemp(os.TempDir(), "unittests-") - if err != nil { - t.Errorf("Error creating temp directory for tests") - return - } - workingDir := filepath.Join(prefixDir, "myapp") - - tests := []struct { - name string - populateWorkingDir func(fs filesystem.Filesystem) - currentNamespace string - wantErrValidate string - }{ - { - name: "default app", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "a-project", - AppName: "an-app-name", - }) - }, - }, - { - name: "empty project name", - populateWorkingDir: func(fs filesystem.Filesystem) { - _ = fs.MkdirAll(filepath.Join(prefixDir, "myapp", ".odo", "env"), 0755) - env, err := envinfo.NewEnvSpecificInfo(filepath.Join(prefixDir, "myapp")) - if err != nil { - return - } - _ = env.SetComponentSettings(envinfo.ComponentSettings{ - Name: "a-name", - Project: "", - AppName: "an-app-name", - }) - }, - currentNamespace: "", - wantErrValidate: "Please specify the application name and project name", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // the first one is to cleanup the directory before execution (in case there are remaining files from a previous execution) - os.RemoveAll(prefixDir) - // the second one to cleanup after execution - defer os.RemoveAll(prefixDir) - - // Fake Cobra - ctrl := gomock.NewController(t) - defer ctrl.Finish() - cmdline := cmdline.NewMockCmdline(ctrl) - - // Fake odo Kube client - kclient := kclient.NewMockClientInterface(ctrl) - - /* Mocks for Complete */ - cmdline.EXPECT().GetWorkingDirectory().Return(workingDir, nil).AnyTimes() - cmdline.EXPECT().CheckIfConfigurationNeeded().Return(false, nil).AnyTimes() - cmdline.EXPECT().FlagValueIfSet("project").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("app").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("component").Return("").AnyTimes() - cmdline.EXPECT().FlagValueIfSet("o").Return("").AnyTimes() - cmdline.EXPECT().GetName().Return("list").AnyTimes() - cmdline.EXPECT().GetParentName().Return("application").AnyTimes() - cmdline.EXPECT().GetKubeClient().Return(kclient, nil).AnyTimes() - - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "a-project", - }, - } - kclient.EXPECT().GetNamespaceNormal("a-project").Return(ns, nil).AnyTimes() - kclient.EXPECT().GetNamespaceNormal("").Return(nil, nil).AnyTimes() - kclient.EXPECT().SetNamespace("a-project").AnyTimes() - kclient.EXPECT().SetNamespace("").AnyTimes() - kclient.EXPECT().GetCurrentNamespace().Return(tt.currentNamespace).AnyTimes() - - tt.populateWorkingDir(filesystem.DefaultFs{}) - - /* Mocks for Complete */ - appClient := application.NewMockClient(ctrl) - opts := NewListOptions(appClient) - - /* COMPLETE */ - err := opts.Complete(cmdline, []string{}) - - if err != nil { - return - } - - /* VALIDATE */ - err = opts.Validate() - - if err == nil && tt.wantErrValidate != "" { - t.Errorf("Expected %v, got no error", tt.wantErrValidate) - return - } - if err != nil && tt.wantErrValidate == "" { - t.Errorf("Expected no error, got %v", err.Error()) - return - } - if err != nil && tt.wantErrValidate != "" && !strings.Contains(err.Error(), tt.wantErrValidate) { - t.Errorf("Expected error %v, got %v", tt.wantErrValidate, err.Error()) - return - } - if err != nil { - return - } - - /* Mocks for Run */ - appClient.EXPECT().List().Times(1) - - /* RUN */ - err = opts.Run() - if err != nil { - t.Errorf("Expected nil err, got %s", err) - } - }) - } -} diff --git a/pkg/odo/cli/catalog/describe/describe.go b/pkg/odo/cli/catalog/describe/describe.go index 82e829945..c0457bf46 100644 --- a/pkg/odo/cli/catalog/describe/describe.go +++ b/pkg/odo/cli/catalog/describe/describe.go @@ -13,17 +13,15 @@ const RecommendedCommandName = "describe" // NewCmdCatalogDescribe implements the odo catalog describe command func NewCmdCatalogDescribe(name, fullName string) *cobra.Command { component := NewCmdCatalogDescribeComponent(componentRecommendedCommandName, util.GetFullName(fullName, componentRecommendedCommandName)) - service := NewCmdCatalogDescribeService(serviceRecommendedCommandName, util.GetFullName(fullName, serviceRecommendedCommandName)) catalogDescribeCmd := &cobra.Command{ Use: name, Short: "Describe catalog item", Long: "Describe the given catalog item from OpenShift", Args: cobra.ExactArgs(1), - Example: fmt.Sprintf("%s\n\n%s\n", component.Example, service.Example), + Example: fmt.Sprintf("%s\n", component.Example), } catalogDescribeCmd.AddCommand( component, - service, ) return catalogDescribeCmd diff --git a/pkg/odo/cli/catalog/describe/interface.go b/pkg/odo/cli/catalog/describe/interface.go deleted file mode 100644 index 62380beca..000000000 --- a/pkg/odo/cli/catalog/describe/interface.go +++ /dev/null @@ -1,11 +0,0 @@ -package describe - -// CatalogProviderBackend is implemented by the catalog backends supported by odo -// It is used in "odo catalog describe service". -type CatalogProviderBackend interface { - // the second argument can be a list of anything that needs to be sent to populate internal - // structs - CompleteDescribeService(*DescribeServiceOptions, []string) error - ValidateDescribeService(*DescribeServiceOptions) error - RunDescribeService(*DescribeServiceOptions) error -} diff --git a/pkg/odo/cli/catalog/describe/operator_backend.go b/pkg/odo/cli/catalog/describe/operator_backend.go deleted file mode 100644 index 8cb8caf57..000000000 --- a/pkg/odo/cli/catalog/describe/operator_backend.go +++ /dev/null @@ -1,345 +0,0 @@ -package describe - -import ( - "encoding/json" - "fmt" - "io" - "os" - "regexp" - "sort" - "strings" - "text/tabwriter" - - "github.com/go-openapi/spec" - olm "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/service" - "gopkg.in/yaml.v2" - "k8s.io/klog" -) - -type operatorBackend struct { - Name string - OperatorType string - CustomResource string - CSV olm.ClusterServiceVersion - CR *olm.CRDDescription - CRDSpec *spec.Schema - CRDList *service.OperatorBackedServiceCRList -} - -func NewOperatorBackend() *operatorBackend { - return &operatorBackend{} -} - -func (ohb *operatorBackend) CompleteDescribeService(dso *DescribeServiceOptions, args []string) error { - ohb.Name = args[0] - oprType, CR, err := service.SplitServiceKindName(ohb.Name) - if err != nil { - klog.V(2).Infof("could not determine csv, falling back to describing all of them") - oprType = args[0] - CR = "" - } - // we check if the cluster supports ClusterServiceVersion or not. - isCSVSupported, err := dso.KClient.IsCSVSupported() - if err != nil { - // if there is an error checking it, we return the error. - return err - } - // if its not supported then we return an error - if !isCSVSupported { - return errors.New("it seems the cluster doesn't support Operators. Please install OLM and try again") - } - ohb.OperatorType = oprType - ohb.CustomResource = CR - return nil -} - -func (ohb *operatorBackend) ValidateDescribeService(dso *DescribeServiceOptions) error { - var err error - if ohb.OperatorType == "" { - return errors.New("invalid service name provided. should either be or /") - } - // make sure that CSV of the specified OperatorType exists - ohb.CSV, err = dso.KClient.GetClusterServiceVersion(ohb.OperatorType) - if err != nil { - // error only occurs when OperatorHub is not installed. - // k8s does't have it installed by default but OCP does - return err - } - - //if both operator type and cr are known, validate that it exists - if ohb.OperatorType != "" && ohb.CustomResource != "" { - var hasCR bool - hasCR, ohb.CR = dso.KClient.CheckCustomResourceInCSV(ohb.CustomResource, &ohb.CSV) - if !hasCR { - return fmt.Errorf("the %q resource doesn't exist in specified %q operator", ohb.CustomResource, ohb.OperatorType) - } - - ohb.CRDSpec, err = dso.KClient.GetCRDSpec(ohb.CR, ohb.OperatorType, ohb.CustomResource) - if err != nil { - return err - } - } - return nil - -} - -func (ohb *operatorBackend) RunDescribeService(dso *DescribeServiceOptions) error { - if ohb.OperatorType != "" && ohb.CustomResource == "" { - //we don't have cr so list all possible crds - ohb.CRDList = service.NewOperatorBackedCRList(ohb.OperatorType, ohb.CSV.Spec.DisplayName, ohb.CSV.Spec.Description) - crds := *dso.KClient.GetCustomResourcesFromCSV(&ohb.CSV) - for _, custRes := range crds { - ohb.CRDList.Spec.CRDS = append(ohb.CRDList.Spec.CRDS, service.OperatorServiceCRItem{ - Kind: custRes.Kind, - Description: custRes.Description, - }) - } - if log.IsJSON() { - machineoutput.OutputSuccess(ohb.CRDList) - } else { - HumanReadableCRListOutput(os.Stdout, ohb.CRDList) - } - return nil - } - if dso.exampleFlag { - almExample, err := service.GetAlmExample(ohb.CSV, ohb.CustomResource, ohb.OperatorType) - if err != nil { - return err - } - if log.IsJSON() { - jsonExample := service.NewOperatorExample(almExample) - jsonCR, err := json.MarshalIndent(jsonExample, "", " ") - if err != nil { - return err - } - - fmt.Println(string(jsonCR)) - - } else { - yamlCR, err := yaml.Marshal(almExample) - if err != nil { - return err - } - - log.Info(string(yamlCR)) - } - } - svc := service.NewOperatorBackedService(ohb.Name, ohb.CR.Kind, ohb.CR.Version, ohb.CR.Description, ohb.CR.DisplayName, ohb.CRDSpec) - if log.IsJSON() { - machineoutput.OutputSuccess(svc) - } else { - - HumanReadableOutput(os.Stdout, svc) - } - return nil -} - -func HumanReadableOutput(w io.Writer, service service.OperatorBackedService) { - fmt.Fprintf(w, "KIND: %s\n", service.Spec.Kind) - fmt.Fprintf(w, "VERSION: %s\n", service.Spec.Version) - fmt.Fprintf(w, "\nDESCRIPTION:\n%s", indentText(service.Spec.Description, 5)) - - if service.Spec.Schema == nil { - log.Warningf("Unable to get parameters from CRD or CSV; Operator %q doesn't have the required information", service.Name) - return - } - fmt.Fprintln(w, "\nFIELDS:") - displayProperties(w, service.Spec.Schema, "") -} - -func HumanReadableCRListOutput(w io.Writer, crsList *service.OperatorBackedServiceCRList) { - fmt.Fprintf(w, "NAME:\t%s\n", crsList.Name) - descriptionLines := strings.ReplaceAll(crsList.Spec.Description, "\n", "\n\t") - fmt.Fprintf(w, "DESCRIPTION:\n\n\t%s\n\n", descriptionLines) - fmt.Fprintf(w, "CRDs:\n") - tw := tabwriter.NewWriter(w, 4, 4, 3, ' ', tabwriter.TabIndent) - defer tw.Flush() - fmt.Fprintf(tw, "\tNAME\tDESCRIPTION\n") - for _, it := range crsList.Spec.CRDS { - fmt.Fprintf(tw, "\t%s\t%s\n", it.Kind, it.Description) - } -} - -// displayProperties displays the properties of an OpenAPI schema in a human readable form -// required fields are displayed first -func displayProperties(w io.Writer, schema *spec.Schema, prefix string) { - required := schema.Required - requiredMap := map[string]bool{} - for _, req := range required { - requiredMap[req] = true - } - - reqKeys := []string{} - for key := range schema.Properties { - if requiredMap[key] { - reqKeys = append(reqKeys, key) - } - } - sort.Strings(reqKeys) - - nonReqKeys := []string{} - for key := range schema.Properties { - if !requiredMap[key] { - nonReqKeys = append(nonReqKeys, key) - } - } - sort.Strings(nonReqKeys) - keys := append(reqKeys, nonReqKeys...) - - for _, key := range keys { - property := schema.Properties[key] - requiredInfo := "" - if requiredMap[key] { - requiredInfo = "-required-" - } - fmt.Fprintf(w, "%s%s (%s) %s\n", strings.Repeat(" ", 3+2*strings.Count(prefix, ".")), prefix+key, getTypeString(property), requiredInfo) - nl := false - if len(property.Title) > 0 { - fmt.Fprintf(w, "%s\n", indentText(property.Title, 5+2*strings.Count(prefix, "."))) - nl = true - } - if len(property.Description) > 0 { - fmt.Fprintf(w, "%s\n", indentText(property.Description, 5+2*strings.Count(prefix, "."))) - nl = true - } - if !nl { - fmt.Fprintln(w) - } - if property.Type.Contains("object") { - displayProperties(w, &property, prefix+key+".") - } else if property.Type.Contains("array") && property.Items.Schema.Type.Contains("object") { - displayProperties(w, property.Items.Schema, prefix+key+".*.") - } - } -} - -func getTypeString(property spec.Schema) string { - if len(property.Type) != 1 { - // should not happen - return strings.Join(property.Type, ", ") - } - tpe := property.Type[0] - if tpe == "array" { - tpe = "[]" + getTypeString(*property.Items.Schema) - } - return tpe -} - -func indentText(t string, indent int) string { - lines := wrapString(t, 80-indent) - res := "" - for _, line := range lines { - res += strings.Repeat(" ", indent) + line + "\n" - } - return res -} - -// Following code from https://github.com/kubernetes/kubectl/blob/159a770147fb28337c6807abb1b2b9db843d0aff/pkg/explain/formatter.go - -type line struct { - wrap int - words []string -} - -func (l *line) String() string { - return strings.Join(l.words, " ") -} - -func (l *line) Empty() bool { - return len(l.words) == 0 -} - -func (l *line) Len() int { - return len(l.String()) -} - -// Add adds the word to the line, returns true if we could, false if we -// didn't have enough room. It's always possible to add to an empty line. -func (l *line) Add(word string) bool { - newLine := line{ - wrap: l.wrap, - words: append(l.words, word), - } - if newLine.Len() <= l.wrap || len(l.words) == 0 { - l.words = newLine.words - return true - } - return false -} - -func wrapString(str string, wrap int) []string { - wrapped := []string{} - l := line{wrap: wrap} - // track the last word added to the current line - lastWord := "" - flush := func() { - if !l.Empty() { - lastWord = "" - wrapped = append(wrapped, l.String()) - l = line{wrap: wrap} - } - } - - // iterate over the lines in the original description - for _, str := range strings.Split(str, "\n") { - // preserve code blocks and blockquotes as-is - if strings.HasPrefix(str, " ") { - flush() - wrapped = append(wrapped, str) - continue - } - - // preserve empty lines after the first line, since they can separate logical sections - if len(wrapped) > 0 && len(strings.TrimSpace(str)) == 0 { - flush() - wrapped = append(wrapped, "") - continue - } - - // flush if we should start a new line - if shouldStartNewLine(lastWord, str) { - flush() - } - words := strings.Fields(str) - for _, word := range words { - lastWord = word - if !l.Add(word) { - flush() - if !l.Add(word) { - panic("Couldn't add to empty line.") - } - } - } - } - flush() - return wrapped -} - -var bullet = regexp.MustCompile(`^(\d+\.?|-|\*)\s`) - -func shouldStartNewLine(lastWord, str string) bool { - // preserve line breaks ending in : - if strings.HasSuffix(lastWord, ":") { - return true - } - - // preserve code blocks - if strings.HasPrefix(str, " ") { - return true - } - str = strings.TrimSpace(str) - // preserve empty lines - if len(str) == 0 { - return true - } - // preserve lines that look like they're starting lists - if bullet.MatchString(str) { - return true - } - // otherwise combine - return false -} diff --git a/pkg/odo/cli/catalog/describe/operator_backend_test.go b/pkg/odo/cli/catalog/describe/operator_backend_test.go deleted file mode 100644 index 21a21389c..000000000 --- a/pkg/odo/cli/catalog/describe/operator_backend_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package describe - -import ( - "testing" - - "github.com/go-openapi/spec" -) - -func TestGetTypeString(t *testing.T) { - tests := []struct { - name string - property spec.Schema - want string - }{ - { - name: "string type", - property: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - }, - }, - want: "string", - }, - { - name: "array of strings type", - property: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - }, - }, - }, - }, - }, - want: "[]string", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := getTypeString(tt.property) - if result != tt.want { - t.Errorf("Failed %s: got: %q, want: %q", t.Name(), result, tt.want) - } - }) - } -} diff --git a/pkg/odo/cli/catalog/describe/service.go b/pkg/odo/cli/catalog/describe/service.go deleted file mode 100644 index 4a8059440..000000000 --- a/pkg/odo/cli/catalog/describe/service.go +++ /dev/null @@ -1,84 +0,0 @@ -package describe - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const serviceRecommendedCommandName = "service" - -var ( - serviceExample = ktemplates.Examples(`# Describe a Operator backed service - %[1]s - `) - - serviceLongDesc = ktemplates.LongDesc(`Describes a service type. - This command supports Operator backed services. - A user can describe an Operator backed service by providing the full identifier for an Operand i.e. / which they can find by running "odo catalog list services". -`) -) - -// DescribeServiceOptions encapsulates the options for the odo catalog describe service command -type DescribeServiceOptions struct { - // Context - *genericclioptions.Context - - // Flags - exampleFlag bool - - // Service backend - backend CatalogProviderBackend -} - -// NewDescribeServiceOptions creates a new DescribeServiceOptions instance -func NewDescribeServiceOptions() *DescribeServiceOptions { - return &DescribeServiceOptions{} -} - -// Complete completes DescribeServiceOptions after they've been created -func (o *DescribeServiceOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - - //we initialize operator backend regardless of if we can split name or not. Decision - //to describe crs or not will be taken later - o.backend = NewOperatorBackend() - return o.backend.CompleteDescribeService(o, args) -} - -// Validate validates the DescribeServiceOptions based on completed values -func (o *DescribeServiceOptions) Validate() (err error) { - return o.backend.ValidateDescribeService(o) - -} - -// Run contains the logic for the command associated with DescribeServiceOptions -func (o *DescribeServiceOptions) Run() (err error) { - return o.backend.RunDescribeService(o) -} - -// NewCmdCatalogDescribeService implements the odo catalog describe service command -func NewCmdCatalogDescribeService(name, fullName string) *cobra.Command { - o := NewDescribeServiceOptions() - command := &cobra.Command{ - Use: name, - Short: "Describe a service", - Long: serviceLongDesc, - Example: fmt.Sprintf(serviceExample, fullName), - Annotations: map[string]string{"machineoutput": "json"}, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - command.Flags().BoolVarP(&o.exampleFlag, "example", "e", false, "Show an example of the service") - - return command -} diff --git a/pkg/odo/cli/catalog/list/list.go b/pkg/odo/cli/catalog/list/list.go index 9a34f7f0e..56a9b729b 100644 --- a/pkg/odo/cli/catalog/list/list.go +++ b/pkg/odo/cli/catalog/list/list.go @@ -13,18 +13,16 @@ const RecommendedCommandName = "list" // NewCmdCatalogList implements the odo catalog list command func NewCmdCatalogList(name, fullName string) *cobra.Command { components := NewCmdCatalogListComponents(componentsRecommendedCommandName, util.GetFullName(fullName, componentsRecommendedCommandName)) - services := NewCmdCatalogListServices(servicesRecommendedCommandName, util.GetFullName(fullName, servicesRecommendedCommandName)) catalogListCmd := &cobra.Command{ Use: name, - Short: "List all available component & service types.", - Long: "List all available component and service types from OpenShift", - Example: fmt.Sprintf("%s\n\n%s\n", components.Example, services.Example), + Short: "List all available component types.", + Long: "List all available component types from OpenShift", + Example: fmt.Sprintf("%s\n", components.Example), } catalogListCmd.AddCommand( components, - services, ) return catalogListCmd diff --git a/pkg/odo/cli/catalog/list/services.go b/pkg/odo/cli/catalog/list/services.go deleted file mode 100644 index 709913959..000000000 --- a/pkg/odo/cli/catalog/list/services.go +++ /dev/null @@ -1,105 +0,0 @@ -package list - -import ( - "fmt" - "strings" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - olm "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cli/catalog/util" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/service" - "github.com/spf13/cobra" -) - -const servicesRecommendedCommandName = "services" - -var servicesExample = ` # Get the supported services - %[1]s` - -// ServiceOptions encapsulates the options for the odo catalog list services command -type ServiceOptions struct { - // Context - *genericclioptions.Context - - // list of clusterserviceversions (installed by Operators) - csvs *olm.ClusterServiceVersionList -} - -// NewServiceOptions creates a new ListServicesOptions instance -func NewServiceOptions() *ServiceOptions { - return &ServiceOptions{} -} - -// Complete completes ListServicesOptions after they've been created -func (o *ServiceOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - - o.csvs, err = service.ListSucceededClusterServiceVersions(o.KClient) - if err != nil && !strings.Contains(err.Error(), "could not find specified operator") { - return err - } - return nil -} - -// Validate validates the ListServicesOptions based on completed values -func (o *ServiceOptions) Validate() error { - return nil -} - -// Run contains the logic for the command associated with ListServicesOptions -func (o *ServiceOptions) Run() error { - if log.IsJSON() { - machineoutput.OutputSuccess(newCatalogListOutput(o.csvs)) - } else { - if len(o.csvs.Items) == 0 { - log.Info("no deployable operators found") - return nil - } - - if len(o.csvs.Items) > 0 { - util.DisplayClusterServiceVersions(o.csvs) - } - } - return nil -} - -// NewCmdCatalogListServices implements the odo catalog list services command -func NewCmdCatalogListServices(name, fullName string) *cobra.Command { - o := NewServiceOptions() - return &cobra.Command{ - Use: name, - Short: "Lists all available services", - Long: "Lists all available services", - Example: fmt.Sprintf(servicesExample, fullName), - Args: cobra.ExactArgs(0), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } -} - -type catalogListOutput struct { - v1.TypeMeta `json:",inline"` - v1.ObjectMeta `json:"metadata,omitempty"` - // list of clusterserviceversions (installed by Operators) - Operators *olm.ClusterServiceVersionList `json:"operators,omitempty"` -} - -func newCatalogListOutput(operators *olm.ClusterServiceVersionList) catalogListOutput { - return catalogListOutput{ - TypeMeta: v1.TypeMeta{ - Kind: "List", - APIVersion: machineoutput.APIVersion, - }, - Operators: operators, - } -} diff --git a/pkg/odo/cli/catalog/search/search.go b/pkg/odo/cli/catalog/search/search.go index 9537b0b65..0e2464697 100644 --- a/pkg/odo/cli/catalog/search/search.go +++ b/pkg/odo/cli/catalog/search/search.go @@ -13,7 +13,6 @@ const RecommendedCommandName = "search" // NewCmdCatalogSearch implements the odo catalog search command func NewCmdCatalogSearch(name, fullName string) *cobra.Command { component := NewCmdCatalogSearchComponent(componentRecommendedCommandName, util.GetFullName(fullName, componentRecommendedCommandName)) - service := NewCmdCatalogSearchService(serviceRecommendedCommandName, util.GetFullName(fullName, serviceRecommendedCommandName)) catalogSearchCmd := &cobra.Command{ Use: name, Short: "Search available component & service types.", @@ -22,9 +21,9 @@ func NewCmdCatalogSearch(name, fullName string) *cobra.Command { This searches for a partial match for the given search term in all the available components & services. `, - Example: fmt.Sprintf("%s\n\n%s\n", component.Example, service.Example), + Example: fmt.Sprintf("%s\n", component.Example), } - catalogSearchCmd.AddCommand(component, service) + catalogSearchCmd.AddCommand(component) return catalogSearchCmd } diff --git a/pkg/odo/cli/catalog/search/service.go b/pkg/odo/cli/catalog/search/service.go deleted file mode 100644 index 16ce1225d..000000000 --- a/pkg/odo/cli/catalog/search/service.go +++ /dev/null @@ -1,86 +0,0 @@ -package search - -import ( - "fmt" - - olm "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/redhat-developer/odo/pkg/odo/cli/catalog/util" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/spf13/cobra" -) - -const serviceRecommendedCommandName = "service" - -var serviceExample = ` # Search for a service - %[1]s mysql` - -// SearchServiceOptions encapsulates the options for the odo catalog describe service command -type SearchServiceOptions struct { - // Context - *genericclioptions.Context - - // Parameters - searchTerm string - - // list of clusterserviceversions (installed by Operators) - csvs *olm.ClusterServiceVersionList -} - -// NewSearchServiceOptions creates a new SearchServiceOptions instance -func NewSearchServiceOptions() *SearchServiceOptions { - return &SearchServiceOptions{} -} - -// Complete completes SearchServiceOptions after they've been created -func (o *SearchServiceOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - - o.searchTerm = args[0] - - o.csvs, err = o.KClient.SearchClusterServiceVersionList(o.searchTerm) - if err != nil { - return fmt.Errorf("unable to list services because Operator Hub is not enabled in your cluster: %v", err) - } - - return nil -} - -// Validate validates the SearchServiceOptions based on completed values -func (o *SearchServiceOptions) Validate() error { - if len(o.csvs.Items) == 0 { - return fmt.Errorf("no service matched the query: %s", o.searchTerm) - } - return nil -} - -// Run contains the logic for the command associated with SearchServiceOptions -func (o *SearchServiceOptions) Run() error { - if len(o.csvs.Items) > 0 { - util.DisplayClusterServiceVersions(o.csvs) - } - return nil -} - -// NewCmdCatalogSearchService implements the odo catalog search service command -func NewCmdCatalogSearchService(name, fullName string) *cobra.Command { - o := NewSearchServiceOptions() - return &cobra.Command{ - Use: name, - Short: "Search service type in catalog", - Long: `Search service type in catalog. - -This searches for a partial match for the given search term in all the available -services from operator hub services. -`, - Example: fmt.Sprintf(serviceExample, fullName), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - -} diff --git a/pkg/odo/cli/cli.go b/pkg/odo/cli/cli.go index 5f0773f59..2181a48fc 100644 --- a/pkg/odo/cli/cli.go +++ b/pkg/odo/cli/cli.go @@ -6,14 +6,10 @@ import ( "os" "strings" - "github.com/redhat-developer/odo/pkg/odo/cli/application" "github.com/redhat-developer/odo/pkg/odo/cli/build_images" "github.com/redhat-developer/odo/pkg/odo/cli/catalog" "github.com/redhat-developer/odo/pkg/odo/cli/component" - "github.com/redhat-developer/odo/pkg/odo/cli/config" - "github.com/redhat-developer/odo/pkg/odo/cli/debug" "github.com/redhat-developer/odo/pkg/odo/cli/deploy" - "github.com/redhat-developer/odo/pkg/odo/cli/env" _init "github.com/redhat-developer/odo/pkg/odo/cli/init" "github.com/redhat-developer/odo/pkg/odo/cli/login" "github.com/redhat-developer/odo/pkg/odo/cli/logout" @@ -21,8 +17,6 @@ import ( "github.com/redhat-developer/odo/pkg/odo/cli/preference" "github.com/redhat-developer/odo/pkg/odo/cli/project" "github.com/redhat-developer/odo/pkg/odo/cli/registry" - "github.com/redhat-developer/odo/pkg/odo/cli/service" - "github.com/redhat-developer/odo/pkg/odo/cli/storage" "github.com/redhat-developer/odo/pkg/odo/cli/telemetry" "github.com/redhat-developer/odo/pkg/odo/cli/url" "github.com/redhat-developer/odo/pkg/odo/cli/utils" @@ -181,34 +175,22 @@ func odoRootCmd(name, fullName string) *cobra.Command { cobra.AddTemplateFunc("CapitalizeFlagDescriptions", util.CapitalizeFlagDescriptions) cobra.AddTemplateFunc("ModifyAdditionalFlags", util.ModifyAdditionalFlags) - rootCmdList := append([]*cobra.Command{}, application.NewCmdApplication(application.RecommendedCommandName, util.GetFullName(fullName, application.RecommendedCommandName)), + rootCmdList := append([]*cobra.Command{}, catalog.NewCmdCatalog(catalog.RecommendedCommandName, util.GetFullName(fullName, catalog.RecommendedCommandName)), component.NewCmdComponent(component.RecommendedCommandName, util.GetFullName(fullName, component.RecommendedCommandName)), component.NewCmdCreate(component.CreateRecommendedCommandName, util.GetFullName(fullName, component.CreateRecommendedCommandName)), component.NewCmdDelete(component.DeleteRecommendedCommandName, util.GetFullName(fullName, component.DeleteRecommendedCommandName)), - component.NewCmdDescribe(component.DescribeRecommendedCommandName, util.GetFullName(fullName, component.DescribeRecommendedCommandName)), - component.NewCmdLink(component.LinkRecommendedCommandName, util.GetFullName(fullName, component.LinkRecommendedCommandName)), - component.NewCmdUnlink(component.UnlinkRecommendedCommandName, util.GetFullName(fullName, component.UnlinkRecommendedCommandName)), component.NewCmdList(component.ListRecommendedCommandName, util.GetFullName(fullName, component.ListRecommendedCommandName)), - component.NewCmdLog(component.LogRecommendedCommandName, util.GetFullName(fullName, component.LogRecommendedCommandName)), component.NewCmdPush(component.PushRecommendedCommandName, util.GetFullName(fullName, component.PushRecommendedCommandName)), component.NewCmdWatch(component.WatchRecommendedCommandName, util.GetFullName(fullName, component.WatchRecommendedCommandName)), - component.NewCmdStatus(component.StatusRecommendedCommandName, util.GetFullName(fullName, component.StatusRecommendedCommandName)), - component.NewCmdExec(component.ExecRecommendedCommandName, util.GetFullName(fullName, component.ExecRecommendedCommandName)), login.NewCmdLogin(login.RecommendedCommandName, util.GetFullName(fullName, login.RecommendedCommandName)), logout.NewCmdLogout(logout.RecommendedCommandName, util.GetFullName(fullName, logout.RecommendedCommandName)), project.NewCmdProject(project.RecommendedCommandName, util.GetFullName(fullName, project.RecommendedCommandName)), - service.NewCmdService(service.RecommendedCommandName, util.GetFullName(fullName, service.RecommendedCommandName)), - storage.NewCmdStorage(storage.RecommendedCommandName, util.GetFullName(fullName, storage.RecommendedCommandName)), url.NewCmdURL(url.RecommendedCommandName, util.GetFullName(fullName, url.RecommendedCommandName)), utils.NewCmdUtils(utils.RecommendedCommandName, util.GetFullName(fullName, utils.RecommendedCommandName)), version.NewCmdVersion(version.RecommendedCommandName, util.GetFullName(fullName, version.RecommendedCommandName)), - config.NewCmdConfiguration(config.RecommendedCommandName, util.GetFullName(fullName, config.RecommendedCommandName)), preference.NewCmdPreference(preference.RecommendedCommandName, util.GetFullName(fullName, preference.RecommendedCommandName)), - debug.NewCmdDebug(debug.RecommendedCommandName, util.GetFullName(fullName, debug.RecommendedCommandName)), registry.NewCmdRegistry(registry.RecommendedCommandName, util.GetFullName(fullName, registry.RecommendedCommandName)), - component.NewCmdTest(component.TestRecommendedCommandName, util.GetFullName(fullName, component.TestRecommendedCommandName)), - env.NewCmdEnv(env.RecommendedCommandName, util.GetFullName(fullName, env.RecommendedCommandName)), telemetry.NewCmdTelemetry(telemetry.RecommendedCommandName), build_images.NewCmdBuildImages(build_images.RecommendedCommandName, util.GetFullName(fullName, build_images.RecommendedCommandName)), deploy.NewCmdDeploy(deploy.RecommendedCommandName, util.GetFullName(fullName, deploy.RecommendedCommandName)), diff --git a/pkg/odo/cli/component/common_link.go b/pkg/odo/cli/component/common_link.go deleted file mode 100644 index fface5213..000000000 --- a/pkg/odo/cli/component/common_link.go +++ /dev/null @@ -1,390 +0,0 @@ -package component - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/redhat-developer/odo/pkg/devfile" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/odo/util" - svc "github.com/redhat-developer/odo/pkg/service" - - v1 "k8s.io/api/core/v1" - - kerrors "k8s.io/apimachinery/pkg/api/errors" - - servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1" - "gopkg.in/yaml.v2" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -const unlink = "unlink" - -type commonLinkOptions struct { - secretName string - isTargetAService bool - name string - bindAsFiles bool - - devfilePath string - - suppliedName string - operation func(secretName, componentName, applicationName string) error - operationName string - - // Service Binding Operator options - serviceBinding *servicebinding.ServiceBinding - serviceType string - serviceName string - *genericclioptions.Context - // choose between Operator Hub and Service Catalog. If true, Operator Hub - csvSupport bool - - inlined bool - // mappings is an array of strings representing the custom binding data that user wants to inject into the component - mappings []string -} - -func newCommonLinkOptions() *commonLinkOptions { - return &commonLinkOptions{} -} - -func (o *commonLinkOptions) getLinkType() string { - linkType := "component" - if o.isTargetAService { - linkType = "service" - } - return linkType -} - -// Complete completes LinkOptions after they've been created -func (o *commonLinkOptions) complete(cmdline cmdline.Cmdline, args []string, context string) (err error) { - o.operationName = cmdline.GetName() - o.suppliedName = args[0] - - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(context)) - if err != nil { - return err - } - - o.csvSupport, _ = o.KClient.IsCSVSupported() - - o.serviceType, o.serviceName, err = svc.IsOperatorServiceNameValid(o.suppliedName) - if err != nil { - // error indicates the service name provided by user doesn't adhere to / - // so it's another odo component that they want to link/unlink to/from - o.serviceName = o.suppliedName - o.isTargetAService = false - o.serviceType = "Service" // Kubernetes Service - - // TODO find the service using an app name to link components in other apps - // requires modification of the app flag or finding some other way - var s *v1.Service - s, err = o.Context.KClient.GetOneService(o.suppliedName, o.EnvSpecificInfo.GetApplication()) - if kerrors.IsNotFound(err) { - return fmt.Errorf("couldn't find component named %q. Refer %q to see list of running components", o.suppliedName, "odo list") - } - if err != nil { - return err - } - o.serviceName = s.Name - } else { - o.isTargetAService = true - } - - if o.operationName == unlink { - // rest of the code is specific to link operation - return nil - } - - componentName := o.EnvSpecificInfo.GetName() - - deployment, err := o.KClient.GetOneDeployment(componentName, o.EnvSpecificInfo.GetApplication()) - if err != nil { - return err - } - - deploymentGVR, err := o.KClient.GetDeploymentAPIVersion() - if err != nil { - return err - } - - paramsMap, err := util.MapFromParameters(o.mappings) - if err != nil { - return err - } - - // MappingsMap is a map of mappings to be used in the ServiceBinding we create for an "odo link" - var mappingsMap []servicebinding.Mapping - for kv := range paramsMap { - mapping := servicebinding.Mapping{ - Name: kv, - Value: paramsMap[kv], - } - mappingsMap = append(mappingsMap, mapping) - } - - var service servicebinding.Service - if o.isTargetAService { - // since the service exists, let's get more info to populate service binding request - // first get the CR itself - cr, err := o.KClient.GetCustomResource(o.serviceType) - if err != nil { - return err - } - - // now get the group, version, kind information from CR - group, version, kind, err := svc.GetGVKFromCR(cr) - if err != nil { - return err - } - - service = servicebinding.Service{ - Id: &o.serviceName, // Id field is helpful if user wants to inject mappings (custom binding data) - NamespacedRef: servicebinding.NamespacedRef{ - Ref: servicebinding.Ref{ - Group: group, - Version: version, - Kind: kind, - Name: o.serviceName, - }, - }, - } - } else { - service = servicebinding.Service{ - Id: &o.serviceName, // Id field is helpful if user wants to inject mappings (custom binding data) - NamespacedRef: servicebinding.NamespacedRef{ - Ref: servicebinding.Ref{ - Version: "v1", - Kind: "Service", - Name: o.serviceName, - }, - }, - } - } - - o.serviceBinding = &servicebinding.ServiceBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: strings.Join([]string{kclient.ServiceBindingGroup, kclient.ServiceBindingVersion}, "/"), - Kind: kclient.ServiceBindingKind, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: o.getServiceBindingName(componentName), - }, - Spec: servicebinding.ServiceBindingSpec{ - DetectBindingResources: true, - BindAsFiles: o.bindAsFiles, - Application: servicebinding.Application{ - Ref: servicebinding.Ref{ - Name: deployment.Name, - Group: deploymentGVR.Group, - Version: deploymentGVR.Version, - Resource: deploymentGVR.Resource, - }, - }, - Mappings: mappingsMap, - Services: []servicebinding.Service{service}, - }, - } - - return nil -} - -func (o *commonLinkOptions) validate() (err error) { - if o.EnvSpecificInfo == nil { - return fmt.Errorf("failed to find environment info to validate") - } - - var svcFullName string - - if o.isTargetAService { - // let's validate if the service exists - svcFullName = strings.Join([]string{o.serviceType, o.serviceName}, "/") - svcExists, err := svc.OperatorSvcExists(o.KClient, svcFullName) - if err != nil { - return err - } - if !svcExists { - return fmt.Errorf("couldn't find service named %q. Refer %q to see list of running services", svcFullName, "odo service list") - } - } else { - svcFullName = o.serviceName - if o.suppliedName == o.EnvSpecificInfo.GetName() { - if o.operationName == unlink { - return fmt.Errorf("the component %q cannot be unlinked from itself", o.suppliedName) - } else { - return fmt.Errorf("the component %q cannot be linked with itself", o.suppliedName) - } - } - } - - if o.operationName == unlink { - _, found, err := svc.FindDevfileServiceBinding(o.EnvSpecificInfo.GetDevfileObj(), o.serviceType, o.serviceName, o.GetComponentContext()) - if err != nil { - return err - } - if !found { - if o.getLinkType() == "service" { - return fmt.Errorf("failed to unlink the %s %q since no link was found in the configuration referring this %s", o.getLinkType(), svcFullName, o.getLinkType()) - } - return fmt.Errorf("failed to unlink the %s %q since no link was found in the configuration referring this %s", o.getLinkType(), o.suppliedName, o.getLinkType()) - } - return nil - } - - return nil -} - -func (o *commonLinkOptions) run() (err error) { - if o.Context.EnvSpecificInfo != nil { - if o.operationName == unlink { - return o.unlinkOperator() - } - return o.linkOperator() - } - - var component string - if o.Context.EnvSpecificInfo != nil { - component = o.EnvSpecificInfo.GetName() - err = o.operation(o.secretName, component, o.GetApplication()) - } else { - component, err = o.Component() - if err != nil { - return err - } - err = o.operation(o.secretName, component, o.GetApplication()) - } - - if err != nil { - return err - } - - switch o.operationName { - case "link": - log.Successf("The %s %s has been successfully linked to the component %s\n", o.getLinkType(), o.suppliedName, component) - case "unlink": - log.Successf("The %s %s has been successfully unlinked from the component %s\n", o.getLinkType(), o.suppliedName, component) - default: - return fmt.Errorf("unknown operation %s", o.operationName) - } - - secret, err := o.KClient.GetSecret(o.secretName, o.GetProject()) - if err != nil { - return err - } - - if len(secret.Data) == 0 { - log.Infof("There are no secret environment variables to expose within the %s service", o.suppliedName) - } else { - if o.operationName == "link" { - log.Infof("The below secret environment variables were added to the '%s' component:\n", component) - } else { - log.Infof("The below secret environment variables were removed from the '%s' component:\n", component) - } - - // Output the environment variables - for i := range secret.Data { - fmt.Printf("· %v\n", i) - } - - // Retrieve the first variable to use as an example. - // Have to use a range to access the map - var exampleEnv string - for i := range secret.Data { - exampleEnv = i - break - } - - // Output what to do next if first linking... - if o.operationName == "link" { - log.Italicf(` -You can now access the environment variables from within the component pod, for example: -$%s is now available as a variable within component %s`, exampleEnv, component) - } - } - return -} - -// getServiceBindingName creates a name to be used for creation/deletion of SBR during link/unlink operations -func (o *commonLinkOptions) getServiceBindingName(componentName string) string { - if len(o.name) > 0 { - return o.name - } - if !o.isTargetAService { - return strings.Join([]string{componentName, o.serviceName}, "-") - } - return strings.Join([]string{componentName, strings.ToLower(o.serviceType), o.serviceName}, "-") -} - -// linkOperator creates a service binding resource and links -// the current component with the given odo service or -// the current component with the given component's service -// and stores the link info in the env -func (o *commonLinkOptions) linkOperator() (err error) { - // Convert ServiceBinding -> JSON -> Map -> YAML - // JSON conversion step is necessary to inline TypeMeta - - intermediate, err := json.Marshal(o.serviceBinding) - if err != nil { - return err - } - - serviceBindingMap := make(map[string]interface{}) - err = json.Unmarshal(intermediate, &serviceBindingMap) - if err != nil { - return err - } - - yamlDesc, err := yaml.Marshal(serviceBindingMap) - if err != nil { - return err - } - - // check if the component is already linked to the requested component/service - _, found, err := svc.FindDevfileServiceBinding(o.EnvSpecificInfo.GetDevfileObj(), o.serviceType, o.serviceName, o.GetComponentContext()) - if err != nil { - return err - } - if found { - return fmt.Errorf("component %q is already linked with the %s %q", o.Context.EnvSpecificInfo.GetName(), o.getLinkType(), o.suppliedName) - } - - if o.inlined { - err = devfile.AddKubernetesComponentToDevfile(string(yamlDesc), o.serviceBinding.Name, o.EnvSpecificInfo.GetDevfileObj()) - if err != nil { - return err - } - } else { - err = devfile.AddKubernetesComponent(string(yamlDesc), o.serviceBinding.Name, o.GetComponentContext(), o.EnvSpecificInfo.GetDevfileObj()) - if err != nil { - return err - } - } - - log.Successf("Successfully created link between component %q and %s %q\n", o.Context.EnvSpecificInfo.GetName(), o.getLinkType(), o.suppliedName) - log.Italic("To apply the link, please use `odo push`") - return err -} - -// unlinkOperator deletes the service binding resource from the devfile -func (o *commonLinkOptions) unlinkOperator() (err error) { - - // We already tested `found` in `validateForOperator` - name, _, err := svc.FindDevfileServiceBinding(o.EnvSpecificInfo.GetDevfileObj(), o.serviceType, o.serviceName, o.GetComponentContext()) - if err != nil { - return err - } - - err = devfile.DeleteKubernetesComponentFromDevfile(name, o.EnvSpecificInfo.GetDevfileObj(), o.GetComponentContext()) - if err != nil { - return err - } - - log.Successf("Successfully unlinked component %q from %s %q\n", o.Context.EnvSpecificInfo.GetName(), o.getLinkType(), o.suppliedName) - log.Italic("To apply the changes, please use `odo push`") - return nil -} diff --git a/pkg/odo/cli/component/component.go b/pkg/odo/cli/component/component.go index fa0b311f6..cb072335f 100644 --- a/pkg/odo/cli/component/component.go +++ b/pkg/odo/cli/component/component.go @@ -43,16 +43,9 @@ func NewCmdComponent(name, fullName string) *cobra.Command { componentGetCmd := NewCmdGet(GetRecommendedCommandName, odoutil.GetFullName(fullName, GetRecommendedCommandName)) createCmd := NewCmdCreate(CreateRecommendedCommandName, odoutil.GetFullName(fullName, CreateRecommendedCommandName)) deleteCmd := NewCmdDelete(DeleteRecommendedCommandName, odoutil.GetFullName(fullName, DeleteRecommendedCommandName)) - describeCmd := NewCmdDescribe(DescribeRecommendedCommandName, odoutil.GetFullName(fullName, DescribeRecommendedCommandName)) - linkCmd := NewCmdLink(LinkRecommendedCommandName, odoutil.GetFullName(fullName, LinkRecommendedCommandName)) - unlinkCmd := NewCmdUnlink(UnlinkRecommendedCommandName, odoutil.GetFullName(fullName, UnlinkRecommendedCommandName)) listCmd := NewCmdList(ListRecommendedCommandName, odoutil.GetFullName(fullName, ListRecommendedCommandName)) - logCmd := NewCmdLog(LogRecommendedCommandName, odoutil.GetFullName(fullName, LogRecommendedCommandName)) pushCmd := NewCmdPush(PushRecommendedCommandName, odoutil.GetFullName(fullName, PushRecommendedCommandName)) watchCmd := NewCmdWatch(WatchRecommendedCommandName, odoutil.GetFullName(fullName, WatchRecommendedCommandName)) - testCmd := NewCmdTest(TestRecommendedCommandName, odoutil.GetFullName(fullName, TestRecommendedCommandName)) - execCmd := NewCmdExec(ExecRecommendedCommandName, odoutil.GetFullName(fullName, ExecRecommendedCommandName)) - statusCmd := NewCmdStatus(StatusRecommendedCommandName, odoutil.GetFullName(fullName, StatusRecommendedCommandName)) // componentCmd represents the component command var componentCmd = &cobra.Command{ @@ -68,8 +61,7 @@ func NewCmdComponent(name, fullName string) *cobra.Command { // add flags from 'get' to component command componentCmd.Flags().AddFlagSet(componentGetCmd.Flags()) - componentCmd.AddCommand(componentGetCmd, createCmd, deleteCmd, describeCmd, linkCmd, unlinkCmd, listCmd, logCmd, pushCmd, watchCmd, execCmd) - componentCmd.AddCommand(testCmd, statusCmd) + componentCmd.AddCommand(componentGetCmd, createCmd, deleteCmd, listCmd, pushCmd, watchCmd) // Add a defined annotation in order to appear in the help menu componentCmd.Annotations = map[string]string{"command": "main"} diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index 2fe41abb9..fd4e9a8ea 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -21,7 +21,6 @@ import ( "github.com/redhat-developer/odo/pkg/devfile/location" "github.com/redhat-developer/odo/pkg/envinfo" "github.com/redhat-developer/odo/pkg/log" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" "github.com/redhat-developer/odo/pkg/odo/genericclioptions" odoutil "github.com/redhat-developer/odo/pkg/odo/util" @@ -394,8 +393,6 @@ func NewCmdCreate(name, fullName string) *cobra.Command { odoutil.AddNowFlag(componentCreateCmd, &co.nowFlag) //Adding `--project` flag projectCmd.AddProjectFlag(componentCreateCmd) - //Adding `--application` flag - appCmd.AddApplicationFlag(componentCreateCmd) completion.RegisterCommandHandler(componentCreateCmd, completion.CreateCompletionHandler) completion.RegisterCommandFlagHandler(componentCreateCmd, "context", completion.FileCompletionHandler) diff --git a/pkg/odo/cli/component/delete.go b/pkg/odo/cli/component/delete.go index 191331b85..8c46edb38 100644 --- a/pkg/odo/cli/component/delete.go +++ b/pkg/odo/cli/component/delete.go @@ -3,16 +3,16 @@ package component import ( "errors" "fmt" - "github.com/redhat-developer/odo/pkg/devfile/adapters/kubernetes/component" - "github.com/spf13/cobra" "os" "path/filepath" + "github.com/redhat-developer/odo/pkg/devfile/adapters/kubernetes/component" + "github.com/spf13/cobra" + "github.com/redhat-developer/odo/pkg/devfile" "github.com/redhat-developer/odo/pkg/devfile/adapters/common" "github.com/redhat-developer/odo/pkg/devfile/consts" "github.com/redhat-developer/odo/pkg/log" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" "github.com/redhat-developer/odo/pkg/odo/cli/ui" "github.com/redhat-developer/odo/pkg/odo/cmdline" @@ -267,8 +267,6 @@ func NewCmdDelete(name, fullName string) *cobra.Command { // Adding `--project` flag projectCmd.AddProjectFlag(componentDeleteCmd) - // Adding `--application` flag - appCmd.AddApplicationFlag(componentDeleteCmd) return componentDeleteCmd } diff --git a/pkg/odo/cli/component/describe.go b/pkg/odo/cli/component/describe.go deleted file mode 100644 index 773f59e2a..000000000 --- a/pkg/odo/cli/component/describe.go +++ /dev/null @@ -1,117 +0,0 @@ -package component - -import ( - "fmt" - "os" - - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - - "github.com/redhat-developer/odo/pkg/component" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" - projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - - ktemplates "k8s.io/kubectl/pkg/util/templates" - - "github.com/spf13/cobra" -) - -// DescribeRecommendedCommandName is the recommended describe command name -const DescribeRecommendedCommandName = "describe" - -var describeExample = ktemplates.Examples(` # Describe nodejs component -%[1]s nodejs -`) - -// DescribeOptions is a dummy container to attach complete, validate and run pattern -type DescribeOptions struct { - // Component context - *ComponentOptions - - // Flags - contextFlag string -} - -// NewDescribeOptions returns new instance of ListOptions -func NewDescribeOptions() *DescribeOptions { - return &DescribeOptions{ - ComponentOptions: &ComponentOptions{}, - } -} - -// Complete completes describe args -func (do *DescribeOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - if do.contextFlag == "" { - do.contextFlag, err = os.Getwd() - if err != nil { - return err - } - } - err = do.ComponentOptions.Complete(cmdline, args) - if err != nil { - return err - } - return nil -} - -// Validate validates the describe parameters -func (do *DescribeOptions) Validate() (err error) { - - if !((do.GetApplication() != "" && do.GetProject() != "") || do.EnvSpecificInfo.Exists()) { - return fmt.Errorf("component %v does not exist", do.componentName) - } - - return nil -} - -// Run has the logic to perform the required actions as part of command -func (do *DescribeOptions) Run() (err error) { - - cfd, err := component.NewComponentFullDescriptionFromClientAndLocalConfigProvider(do.Context.KClient, do.EnvSpecificInfo, do.componentName, do.Context.GetApplication(), do.Context.GetProject(), do.contextFlag) - if err != nil { - return err - } - - if log.IsJSON() { - machineoutput.OutputSuccess(cfd) - } else { - err = cfd.Print(do.Context.KClient) - if err != nil { - return err - } - } - return -} - -// NewCmdDescribe implements the describe odo command -func NewCmdDescribe(name, fullName string) *cobra.Command { - do := NewDescribeOptions() - - var describeCmd = &cobra.Command{ - Use: fmt.Sprintf("%s [component_name]", name), - Short: "Describe component", - Long: `Describe component.`, - Example: fmt.Sprintf(describeExample, fullName), - Args: cobra.RangeArgs(0, 1), - Annotations: map[string]string{"machineoutput": "json", "command": "component"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(do, cmd, args) - }, - } - - describeCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - completion.RegisterCommandHandler(describeCmd, completion.ComponentNameCompletionHandler) - // Adding --context flag - odoutil.AddContextFlag(describeCmd, &do.contextFlag) - - //Adding `--project` flag - projectCmd.AddProjectFlag(describeCmd) - //Adding `--application` flag - appCmd.AddApplicationFlag(describeCmd) - - return describeCmd -} diff --git a/pkg/odo/cli/component/devfile.go b/pkg/odo/cli/component/devfile.go index 4a45fdc15..9c9fe70c3 100644 --- a/pkg/odo/cli/component/devfile.go +++ b/pkg/odo/cli/component/devfile.go @@ -2,12 +2,10 @@ package component import ( "os" - "reflect" "strings" "github.com/redhat-developer/odo/pkg/devfile" - devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/pkg/errors" "github.com/redhat-developer/odo/pkg/envinfo" "github.com/redhat-developer/odo/pkg/machineoutput" @@ -114,58 +112,6 @@ func (po *PushOptions) devfilePushInner() (err error) { return } -// DevfileComponentLog fetch and display log from devfile components -func (lo LogOptions) DevfileComponentLog() error { - devObj, err := devfile.ParseAndValidateFromFile(lo.GetDevfilePath()) - if err != nil { - return err - } - - componentName := lo.Context.EnvSpecificInfo.GetName() - - var platformContext interface{} - kc := kubernetes.KubernetesContext{ - Namespace: lo.KClient.GetCurrentNamespace(), - } - platformContext = kc - - devfileHandler, err := adapters.NewComponentAdapter(componentName, lo.contextFlag, lo.GetApplication(), devObj, platformContext) - - if err != nil { - return err - } - - var command devfilev1.Command - if lo.debugFlag { - command, err = common.GetDebugCommand(devObj.Data, "") - if err != nil { - return err - } - if reflect.DeepEqual(devfilev1.Command{}, command) { - return errors.Errorf("no debug command found in devfile, please run \"odo log\" for run command logs") - } - - } else { - command, err = common.GetRunCommand(devObj.Data, "") - if err != nil { - return err - } - } - - // Start or update the component - rd, err := devfileHandler.Log(lo.followFlag, command) - if err != nil { - log.Errorf( - "Failed to log component with name %s.\nError: %v", - componentName, - err, - ) - return err - } - - return util.DisplayLog(lo.followFlag, rd, os.Stdout, componentName, -1) -} - // DevfileUnDeploy undeploys the devfile kubernetes components func (do *DeleteOptions) DevfileUnDeploy() error { devObj, err := devfile.ParseAndValidateFromFile(do.GetDevfilePath()) @@ -208,41 +154,3 @@ func (do *DeleteOptions) DevfileComponentDelete() error { return devfileHandler.Delete(labels, do.showLogFlag, do.waitFlag) } - -// RunTestCommand runs the specific test command in devfile -func (to *TestOptions) RunTestCommand() error { - componentName := to.Context.EnvSpecificInfo.GetName() - - var platformContext interface{} - kc := kubernetes.KubernetesContext{ - Namespace: to.KClient.GetCurrentNamespace(), - } - platformContext = kc - - devfileHandler, err := adapters.NewComponentAdapter(componentName, to.contextFlag, to.GetApplication(), to.devObj, platformContext) - if err != nil { - return err - } - return devfileHandler.Test(to.testCommandFlag, to.showLogFlag) -} - -// DevfileComponentExec executes the given user command inside the component -func (eo *ExecOptions) DevfileComponentExec(command []string) error { - devObj, err := devfile.ParseAndValidateFromFile(eo.componentOptions.GetDevfilePath()) - if err != nil { - return err - } - - componentName := eo.componentOptions.EnvSpecificInfo.GetName() - - kc := kubernetes.KubernetesContext{ - Namespace: eo.componentOptions.KClient.GetCurrentNamespace(), - } - - devfileHandler, err := adapters.NewComponentAdapter(componentName, eo.contextFlag, eo.componentOptions.GetApplication(), devObj, kc) - if err != nil { - return err - } - - return devfileHandler.Exec(command) -} diff --git a/pkg/odo/cli/component/exec.go b/pkg/odo/cli/component/exec.go deleted file mode 100644 index ac82720b0..000000000 --- a/pkg/odo/cli/component/exec.go +++ /dev/null @@ -1,97 +0,0 @@ -package component - -import ( - "fmt" - - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" - projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -// ExecRecommendedCommandName is the recommended exec command name -const ExecRecommendedCommandName = "exec" - -var execExample = ktemplates.Examples(` # Executes a command inside the component -%[1]s -- ls -a -`) - -// ExecOptions contains exec options -type ExecOptions struct { - // Component context - componentOptions *ComponentOptions - - // Parameters - command []string - - // Flags - contextFlag string -} - -// NewExecOptions returns new instance of ExecOptions -func NewExecOptions() *ExecOptions { - return &ExecOptions{ - componentOptions: &ComponentOptions{}, - } -} - -// Complete completes exec args -func (eo *ExecOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - // gets the command args passed after the dash i.e `--` - eo.command, err = cmdline.GetArgsAfterDashes(args) - if err != nil || len(eo.command) <= 0 { - return fmt.Errorf(`no command was given for the exec command -Please provide a command to execute, odo exec -- `) - } - - // checks if something is passed between `odo exec` and the dash `--` - if len(eo.command) != len(args) { - return fmt.Errorf("no parameter is expected for the command") - } - - eo.componentOptions.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(eo.contextFlag)) - return err -} - -// Validate validates the exec parameters -func (eo *ExecOptions) Validate() (err error) { - return -} - -// Run has the logic to perform the required actions as part of command -func (eo *ExecOptions) Run() (err error) { - return eo.DevfileComponentExec(eo.command) -} - -// NewCmdExec implements the exec odo command -func NewCmdExec(name, fullName string) *cobra.Command { - o := NewExecOptions() - - var execCmd = &cobra.Command{ - Use: name, - Short: "Executes a command inside the component", - Long: `Executes a command inside the component`, - Example: fmt.Sprintf(execExample, fullName), - Annotations: map[string]string{"command": "component"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - execCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - completion.RegisterCommandHandler(execCmd, completion.ComponentNameCompletionHandler) - odoutil.AddContextFlag(execCmd, &o.contextFlag) - - //Adding `--project` flag - projectCmd.AddProjectFlag(execCmd) - - // Adding `--app` flag - appCmd.AddApplicationFlag(execCmd) - - return execCmd -} diff --git a/pkg/odo/cli/component/get.go b/pkg/odo/cli/component/get.go index a35d50127..e0ec361c7 100644 --- a/pkg/odo/cli/component/get.go +++ b/pkg/odo/cli/component/get.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/redhat-developer/odo/pkg/log" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" "github.com/redhat-developer/odo/pkg/odo/cli/project" "github.com/redhat-developer/odo/pkg/odo/cmdline" "github.com/redhat-developer/odo/pkg/odo/genericclioptions" @@ -97,8 +96,6 @@ func NewCmdGet(name, fullName string) *cobra.Command { //Adding `--project` flag project.AddProjectFlag(componentGetCmd) - //Adding `--application` flag - appCmd.AddApplicationFlag(componentGetCmd) return componentGetCmd } diff --git a/pkg/odo/cli/component/link.go b/pkg/odo/cli/component/link.go deleted file mode 100644 index 76624b9dd..000000000 --- a/pkg/odo/cli/component/link.go +++ /dev/null @@ -1,131 +0,0 @@ -package component - -import ( - "fmt" - - servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1" - "github.com/spf13/cobra" - - "github.com/redhat-developer/odo/pkg/devfile/location" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -// LinkRecommendedCommandName is the recommended link command name -const LinkRecommendedCommandName = "link" - -var ( - linkExample = ktemplates.Examples(`# Link the current component to the 'EtcdCluster' named 'myetcd' -%[1]s EtcdCluster/myetcd - -# Link current component to the 'backend' component (backend must have a single exposed port) -%[1]s backend - -# Link current component to the 'backend' component and puts the link definition in the devfile instead of a separate file -%[1]s backend --inlined - -# Link component 'nodejs' to the 'backend' component -%[1]s backend --component nodejs - -# Link current component to port 8080 of the 'backend' component (backend must have port 8080 exposed) -%[1]s backend --port 8080 - -# Link the current component to the 'EtcdCluster' named 'myetcd' -# and make the secrets accessible as files in the '/bindings/etcd/' directory -%[1]s EtcdCluster/myetcd --bind-as-files --name etcd`) - - linkLongDesc = `Link current or provided component to a service (backed by an Operator) or another component - -The appropriate secret will be added to the environment of the source component as environment variables by -default. - -For example: - -Let us say we have created a nodejs application called 'frontend' which we link to an another component called -'backend' which exposes port 8080, then linking the 2 using: -odo link backend --component frontend - -The frontend has 2 ENV variables it can use: -SERVICE_BACKEND_IP=10.217.4.194 -SERVICE_BACKEND_PORT_PORT-8080=8080 - -Using the '--bind-as-files' flag, secrets will be accessible as files instead of environment variables. -The value of the '--name' flag indicates the name of the directory under '/bindings/' containing the secrets files. -` -) - -// LinkOptions encapsulates the options for the odo link command -type LinkOptions struct { - // Common link/unlink context - *commonLinkOptions - - // Flags - contextFlag string -} - -// NewLinkOptions creates a new LinkOptions instance -func NewLinkOptions() *LinkOptions { - options := LinkOptions{} - options.commonLinkOptions = newCommonLinkOptions() - options.commonLinkOptions.serviceBinding = &servicebinding.ServiceBinding{} - return &options -} - -// Complete completes LinkOptions after they've been created -func (o *LinkOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.commonLinkOptions.devfilePath = location.DevfileLocation(o.contextFlag) - - err = o.complete(cmdline, args, o.contextFlag) - if err != nil { - return err - } - - if o.csvSupport { - o.operation = o.KClient.LinkSecret - } - return err -} - -// Validate validates the LinkOptions based on completed values -func (o *LinkOptions) Validate() (err error) { - return o.validate() -} - -// Run contains the logic for the odo link command -func (o *LinkOptions) Run() (err error) { - return o.run() -} - -// NewCmdLink implements the link odo command -func NewCmdLink(name, fullName string) *cobra.Command { - o := NewLinkOptions() - - linkCmd := &cobra.Command{ - Use: fmt.Sprintf("%s / OR %s / --component [component] OR %s --component [component]", name, name, name), - Short: "Link component to a service or component", - Long: linkLongDesc, - Example: fmt.Sprintf(linkExample, fullName), - Args: cobra.ExactArgs(1), - Annotations: map[string]string{"command": "component"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - linkCmd.PersistentFlags().BoolVarP(&o.inlined, "inlined", "", false, "Puts the link definition in the devfile instead of a separate file") - linkCmd.PersistentFlags().StringVar(&o.name, "name", "", "Name of the created ServiceBinding resource") - linkCmd.PersistentFlags().BoolVar(&o.bindAsFiles, "bind-as-files", false, "If enabled, configuration values will be mounted as files, instead of declared as environment variables") - linkCmd.PersistentFlags().StringArrayVarP(&o.mappings, "map", "", []string{}, "Mappings (custom binding data) to be added to the component; each map should be specified as =") - linkCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - - //Adding `--component` flag - AddComponentFlag(linkCmd) - - //Adding context flag - odoutil.AddContextFlag(linkCmd, &o.contextFlag) - - return linkCmd -} diff --git a/pkg/odo/cli/component/list.go b/pkg/odo/cli/component/list.go index f47e0c0c0..208494275 100644 --- a/pkg/odo/cli/component/list.go +++ b/pkg/odo/cli/component/list.go @@ -19,7 +19,6 @@ import ( "github.com/redhat-developer/odo/pkg/component" "github.com/redhat-developer/odo/pkg/log" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" "github.com/redhat-developer/odo/pkg/odo/cmdline" "github.com/redhat-developer/odo/pkg/odo/genericclioptions" @@ -237,8 +236,6 @@ func NewCmdList(name, fullName string) *cobra.Command { //Adding `--project` flag projectCmd.AddProjectFlag(componentListCmd) - //Adding `--application` flag - appCmd.AddApplicationFlag(componentListCmd) completion.RegisterCommandFlagHandler(componentListCmd, "path", completion.FileCompletionHandler) diff --git a/pkg/odo/cli/component/log.go b/pkg/odo/cli/component/log.go deleted file mode 100644 index 83bb040e4..000000000 --- a/pkg/odo/cli/component/log.go +++ /dev/null @@ -1,90 +0,0 @@ -package component - -import ( - "fmt" - - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" - projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - ktemplates "k8s.io/kubectl/pkg/util/templates" - - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - - "github.com/spf13/cobra" -) - -// LogRecommendedCommandName is the recommended watch command name -const LogRecommendedCommandName = "log" - -var logExample = ktemplates.Examples(` # Get the logs for the nodejs component -%[1]s nodejs -`) - -// LogOptions contains log options -type LogOptions struct { - // Component context - *ComponentOptions - - // Flags - followFlag bool - debugFlag bool - contextFlag string -} - -// NewLogOptions returns new instance of LogOptions -func NewLogOptions() *LogOptions { - return &LogOptions{ - ComponentOptions: &ComponentOptions{}, - } -} - -// Complete completes log args -func (lo *LogOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - lo.ComponentOptions.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(lo.contextFlag)) - return err -} - -// Validate validates the log parameters -func (lo *LogOptions) Validate() (err error) { - return -} - -// Run has the logic to perform the required actions as part of command -func (lo *LogOptions) Run() (err error) { - err = lo.DevfileComponentLog() - return -} - -// NewCmdLog implements the log odo command -func NewCmdLog(name, fullName string) *cobra.Command { - o := NewLogOptions() - - var logCmd = &cobra.Command{ - Use: fmt.Sprintf("%s [component_name]", name), - Short: "Retrieve the log for the given component", - Long: `Retrieve the log for the given component`, - Example: fmt.Sprintf(logExample, fullName), - Args: cobra.RangeArgs(0, 1), - Annotations: map[string]string{"command": "component"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - logCmd.Flags().BoolVarP(&o.followFlag, "follow", "f", false, "Follow logs") - logCmd.Flags().BoolVar(&o.debugFlag, "debug", false, "Show logs for debug command") - - logCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - completion.RegisterCommandHandler(logCmd, completion.ComponentNameCompletionHandler) - // Adding `--context` flag - odoutil.AddContextFlag(logCmd, &o.contextFlag) - - //Adding `--project` flag - projectCmd.AddProjectFlag(logCmd) - //Adding `--application` flag - appCmd.AddApplicationFlag(logCmd) - - return logCmd -} diff --git a/pkg/odo/cli/component/status.go b/pkg/odo/cli/component/status.go deleted file mode 100644 index dd3a551db..000000000 --- a/pkg/odo/cli/component/status.go +++ /dev/null @@ -1,134 +0,0 @@ -package component - -import ( - "fmt" - "time" - - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/devfile/adapters" - "github.com/redhat-developer/odo/pkg/devfile/adapters/common" - "github.com/redhat-developer/odo/pkg/devfile/adapters/kubernetes" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" - projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/url" - - "github.com/redhat-developer/odo/pkg/odo/util/completion" - ktemplates "k8s.io/kubectl/pkg/util/templates" - - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - - "github.com/spf13/cobra" -) - -// StatusRecommendedCommandName is the recommended watch command name -const StatusRecommendedCommandName = "status" - -var statusExample = ktemplates.Examples(` # Get the status for the nodejs component -%[1]s nodejs -o json --follow -`) - -// StatusOptions contains status options -type StatusOptions struct { - // Context - *genericclioptions.Context - - // Flags - contextFlag string - followFlag bool - - componentName string - - devfileHandler common.ComponentAdapter -} - -// NewStatusOptions returns new instance of StatusOptions -func NewStatusOptions() *StatusOptions { - return &StatusOptions{} -} - -// Complete completes status args -func (so *StatusOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - so.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(so.contextFlag)) - if err != nil { - return err - } - - // Get the component name - so.componentName = so.EnvSpecificInfo.GetName() - - platformContext := kubernetes.KubernetesContext{ - Namespace: so.KClient.GetCurrentNamespace(), - } - - so.devfileHandler, err = adapters.NewComponentAdapter(so.componentName, so.contextFlag, so.GetApplication(), so.EnvSpecificInfo.GetDevfileObj(), platformContext) - return err -} - -// Validate validates the status parameters -func (so *StatusOptions) Validate() (err error) { - - if !so.followFlag { - return fmt.Errorf("this command must be called with --follow") - } - - return -} - -// Run has the logic to perform the required actions as part of command -func (so *StatusOptions) Run() (err error) { - if !log.IsJSON() { - return errors.New("this command only supports the '-o json' output format") - } - so.devfileHandler.StartSupervisordCtlStatusWatch() - so.devfileHandler.StartContainerStatusWatch() - - loggingClient := machineoutput.NewConsoleMachineEventLoggingClient() - - url.StartURLHttpRequestStatusWatchForK8S(so.KClient, &so.LocalConfigProvider, loggingClient) - - // You can call Run() any time you like, but you can never leave. - for { - time.Sleep(60 * time.Second) - } - -} - -// NewCmdStatus implements the status odo command -func NewCmdStatus(name, fullName string) *cobra.Command { - o := NewStatusOptions() - - annotations := map[string]string{"command": "component", "machineoutput": "json"} - - var statusCmd = &cobra.Command{ - Use: fmt.Sprintf("%s [component_name]", name), - Short: "Watches the given component and outputs machine-readable JSON events representing component status changes", - Long: `Watches the given component and outputs machine-readable JSON events representing component status changes`, - Example: fmt.Sprintf(statusExample, fullName), - Args: cobra.MaximumNArgs(1), - Annotations: annotations, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - statusCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - - // Adding context flag - odoutil.AddContextFlag(statusCmd, &o.contextFlag) - - statusCmd.Flags().BoolVarP(&o.followFlag, "follow", "f", false, "Follow the component and report all changes") - - //Adding `--application` flag - appCmd.AddApplicationFlag(statusCmd) - - //Adding `--project` flag - projectCmd.AddProjectFlag(statusCmd) - - completion.RegisterCommandHandler(statusCmd, completion.ComponentNameCompletionHandler) - - return statusCmd -} diff --git a/pkg/odo/cli/component/test.go b/pkg/odo/cli/component/test.go deleted file mode 100644 index 9cf595cd5..000000000 --- a/pkg/odo/cli/component/test.go +++ /dev/null @@ -1,104 +0,0 @@ -package component - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/devfile" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/util" - - devfileParser "github.com/devfile/library/pkg/devfile/parser" - projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - "github.com/spf13/cobra" - "k8s.io/kubectl/pkg/util/templates" -) - -// TestRecommendedCommandName is the recommended test command name -const TestRecommendedCommandName = "test" - -// TestOptions encapsulates the options for the odo command -type TestOptions struct { - // Context - *genericclioptions.Context - - // Flags - testCommandFlag string - contextFlag string - showLogFlag bool - - // devfile content - devObj devfileParser.DevfileObj -} - -var testExample = templates.Examples(` - # Run default test command - %[1]s - - # Run a specific test command - %[1]s --test-command - -`) - -// NewTestOptions creates a new TestOptions instance -func NewTestOptions() *TestOptions { - return &TestOptions{} -} - -// Complete completes TestOptions after they've been created -func (to *TestOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - to.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(to.contextFlag)) - return -} - -// Validate validates the TestOptions based on completed values -func (to *TestOptions) Validate() (err error) { - - if !util.CheckPathExists(to.Context.GetDevfilePath()) { - return fmt.Errorf("unable to find devfile, odo test command is only supported by devfile components") - } - - devObj, err := devfile.ParseAndValidateFromFile(to.Context.GetDevfilePath()) - if err != nil { - return err - } - to.devObj = devObj - return -} - -// Run contains the logic for the odo command -func (to *TestOptions) Run() (err error) { - return to.RunTestCommand() -} - -// NewCmdTest implements the odo test command -func NewCmdTest(name, fullName string) *cobra.Command { - to := NewTestOptions() - testCmd := &cobra.Command{ - Use: name, - Short: "Run the test command defined in the devfile", - Long: "Run the test command defined in the devfile", - Example: fmt.Sprintf(testExample, fullName), - Args: cobra.MaximumNArgs(0), - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(to, cmd, args) - }, - } - - // Add a defined annotation in order to appear in the help menu - testCmd.Annotations = map[string]string{"command": "main"} - testCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - testCmd.Flags().StringVar(&to.testCommandFlag, "test-command", "", "Devfile Test Command to execute") - testCmd.Flags().BoolVar(&to.showLogFlag, "show-log", false, "If enabled, logs will be shown when running the test command") - //Adding `--context` flag - odoutil.AddContextFlag(testCmd, &to.contextFlag) - //Adding `--project` flag - projectCmd.AddProjectFlag(testCmd) - // Adding `--app` flag - appCmd.AddApplicationFlag(testCmd) - completion.RegisterCommandHandler(testCmd, completion.ComponentNameCompletionHandler) - return testCmd -} diff --git a/pkg/odo/cli/component/unlink.go b/pkg/odo/cli/component/unlink.go deleted file mode 100644 index a6539b493..000000000 --- a/pkg/odo/cli/component/unlink.go +++ /dev/null @@ -1,101 +0,0 @@ -package component - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - - "github.com/redhat-developer/odo/pkg/odo/util" - ktemplates "k8s.io/kubectl/pkg/util/templates" - - "github.com/spf13/cobra" -) - -// UnlinkRecommendedCommandName is the recommended unlink command name -const UnlinkRecommendedCommandName = "unlink" - -var ( - unlinkExample = ktemplates.Examples(`# Unlink the 'my-postgresql' service from the current component -%[1]s my-postgresql - -# Unlink the 'my-postgresql' service from the 'nodejs' component -%[1]s my-postgresql --component nodejs - -# Unlink the 'backend' component from the current component (backend must have a single exposed port) -%[1]s backend - -# Unlink the 'backend' service from the 'nodejs' component -%[1]s backend --component nodejs - -# Unlink the backend's 8080 port from the current component -%[1]s backend --port 8080`) - - unlinkLongDesc = `Unlink component or service from a component. -For this command to be successful, the service or component needs to have been linked prior to the invocation using 'odo link'` -) - -// UnlinkOptions encapsulates the options for the odo link command -type UnlinkOptions struct { - // Common link/unlink context - *commonLinkOptions - - // Flags - contextFlag string -} - -// NewUnlinkOptions creates a new UnlinkOptions instance -func NewUnlinkOptions() *UnlinkOptions { - options := UnlinkOptions{} - options.commonLinkOptions = newCommonLinkOptions() - return &options -} - -// Complete completes UnlinkOptions after they've been created -func (o *UnlinkOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - err = o.complete(cmdline, args, o.contextFlag) - if err != nil { - return err - } - - if o.csvSupport { - o.operation = o.KClient.UnlinkSecret - } - return err -} - -// Validate validates the UnlinkOptions based on completed values -func (o *UnlinkOptions) Validate() (err error) { - return o.validate() -} - -// Run contains the logic for the odo link command -func (o *UnlinkOptions) Run() (err error) { - return o.run() -} - -// NewCmdUnlink implements the link odo command -func NewCmdUnlink(name, fullName string) *cobra.Command { - o := NewUnlinkOptions() - - unlinkCmd := &cobra.Command{ - Use: fmt.Sprintf("%s --component [component] OR %s --component [component]", name, name), - Short: "Unlink component to a service or component", - Long: unlinkLongDesc, - Example: fmt.Sprintf(unlinkExample, fullName), - Args: cobra.ExactArgs(1), - Annotations: map[string]string{"command": "component"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - unlinkCmd.SetUsageTemplate(util.CmdUsageTemplate) - //Adding `--component` flag - AddComponentFlag(unlinkCmd) - // Adding context flag - odoutil.AddContextFlag(unlinkCmd, &o.contextFlag) - - return unlinkCmd -} diff --git a/pkg/odo/cli/component/watch.go b/pkg/odo/cli/component/watch.go index 3a57dd2f5..933c28f4f 100644 --- a/pkg/odo/cli/component/watch.go +++ b/pkg/odo/cli/component/watch.go @@ -11,7 +11,6 @@ import ( "github.com/redhat-developer/odo/pkg/devfile/adapters/common" "github.com/redhat-developer/odo/pkg/devfile/adapters/kubernetes" "github.com/redhat-developer/odo/pkg/envinfo" - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" "github.com/redhat-developer/odo/pkg/odo/cmdline" ktemplates "k8s.io/kubectl/pkg/util/templates" @@ -177,9 +176,6 @@ func NewCmdWatch(name, fullName string) *cobra.Command { // Adding context flag odoutil.AddContextFlag(watchCmd, &wo.contextFlag) - //Adding `--application` flag - appCmd.AddApplicationFlag(watchCmd) - //Adding `--project` flag projectCmd.AddProjectFlag(watchCmd) diff --git a/pkg/odo/cli/config/config.go b/pkg/odo/cli/config/config.go deleted file mode 100644 index 5f1aaee90..000000000 --- a/pkg/odo/cli/config/config.go +++ /dev/null @@ -1,44 +0,0 @@ -package config - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/config" - "github.com/redhat-developer/odo/pkg/odo/util" - - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -// RecommendedCommandName is the recommended config command name -const RecommendedCommandName = "config" - -var configLongDesc = ktemplates.LongDesc(`Modifies odo specific configuration settings within the devfile or config file. - -%[1]s -`) - -// NewCmdConfiguration implements the utils config odo command -func NewCmdConfiguration(name, fullName string) *cobra.Command { - configurationViewCmd := NewCmdView(viewCommandName, util.GetFullName(fullName, viewCommandName)) - configurationSetCmd := NewCmdSet(setCommandName, util.GetFullName(fullName, setCommandName)) - configurationUnsetCmd := NewCmdUnset(unsetCommandName, util.GetFullName(fullName, unsetCommandName)) - configurationCmd := &cobra.Command{ - Use: name, - Short: "Change or view configuration", - Long: fmt.Sprintf(configLongDesc, config.FormatDevfileSupportedParameters()), - Example: fmt.Sprintf("%s\n%s\n%s", - configurationViewCmd.Example, - configurationSetCmd.Example, - configurationUnsetCmd.Example, - ), - Aliases: []string{"configuration"}, - } - - configurationCmd.AddCommand(configurationViewCmd, configurationSetCmd) - configurationCmd.AddCommand(configurationUnsetCmd) - configurationCmd.SetUsageTemplate(util.CmdUsageTemplate) - configurationCmd.Annotations = map[string]string{"command": "main"} - - return configurationCmd -} diff --git a/pkg/odo/cli/config/set.go b/pkg/odo/cli/config/set.go deleted file mode 100644 index d58b885a5..000000000 --- a/pkg/odo/cli/config/set.go +++ /dev/null @@ -1,214 +0,0 @@ -package config - -import ( - "fmt" - "strings" - - "github.com/redhat-developer/odo/pkg/envvar" - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/preference" - "github.com/redhat-developer/odo/pkg/project" - "github.com/redhat-developer/odo/pkg/util" - - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/config" - "github.com/redhat-developer/odo/pkg/log" - clicomponent "github.com/redhat-developer/odo/pkg/odo/cli/component" - "github.com/redhat-developer/odo/pkg/odo/cli/ui" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/validation" - - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const setCommandName = "set" - -var ( - setLongDesc = ktemplates.LongDesc(`Set an individual value in the devfile or odo configuration file. -%[1]s -`) - - devfileSetExample = ktemplates.Examples(` - # Set a configuration value in the devfile - %[1]s %[2]s testapp - %[1]s %[3]s 8080/TCP,8443/TCP - %[1]s %[4]s 500M - - # Set a env variable in the devfiles - %[1]s --env KAFKA_HOST=kafka --env KAFKA_PORT=6639 - `) -) - -// SetOptions encapsulates the options for the command -type SetOptions struct { - // Push context - *clicomponent.PushOptions - - // Parameters - paramName string - paramValue string - - // Flags - forceFlag bool - envArrayFlag []string - nowFlag bool -} - -// NewSetOptions creates a new SetOptions instance -func NewSetOptions(prjClient project.Client, prefClient preference.Client) *SetOptions { - return &SetOptions{ - PushOptions: clicomponent.NewPushOptions(prjClient, prefClient), - } -} - -// Complete completes SetOptions after they've been created -func (o *SetOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - params := genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.GetComponentContext()) - if o.nowFlag { - params.CreateAppIfNeeded().RequireRouteAvailability() - } - o.Context, err = genericclioptions.New(params) - if err != nil { - if err1 := util.IsInvalidKubeConfigError(err); err1 != nil { - return err1 - } - return err - } - - o.DevfilePath = o.Context.EnvSpecificInfo.GetDevfilePath() - o.EnvSpecificInfo = o.Context.EnvSpecificInfo - - if o.envArrayFlag == nil { - o.paramName = args[0] - o.paramValue = args[1] - } - - if o.nowFlag { - prjName := o.Context.LocalConfigProvider.GetNamespace() - o.ResolveSrcAndConfigFlags() - err = o.ResolveProject(prjName) - if err != nil { - return err - } - } - - return nil -} - -// Validate validates the SetOptions based on completed values -func (o *SetOptions) Validate() error { - if !o.Context.LocalConfigProvider.Exists() { - return fmt.Errorf("the directory doesn't contain a component. Use 'odo create' to create a component") - } - return nil -} - -// Run contains the logic for the command -func (o *SetOptions) Run() error { - if o.envArrayFlag != nil { - newEnvVarList, err := envvar.NewListFromSlice(o.envArrayFlag) - if err != nil { - return err - } - err = o.EnvSpecificInfo.GetDevfileObj().AddEnvVars(newEnvVarList.ToDevfileEnvVar()) - if err != nil { - return err - } - - log.Success("Environment variables were successfully updated") - if o.nowFlag { - return o.DevfilePush() - } - log.Italic("\nRun `odo push` command to apply changes to the cluster") - return err - } - if !o.forceFlag { - if config.IsSetInDevfile(o.EnvSpecificInfo.GetDevfileObj(), o.paramName) { - if !ui.Proceed(fmt.Sprintf("%v is already set. Do you want to override it in the devfile", o.paramName)) { - fmt.Println("Aborted by the user.") - return nil - } - } - } - - err := config.SetDevfileConfiguration(o.EnvSpecificInfo.GetDevfileObj(), strings.ToLower(o.paramName), o.paramValue) - if err != nil { - return err - } - log.Success("Devfile successfully updated") - if o.nowFlag { - return o.DevfilePush() - } - log.Italic("\nRun `odo push` command to apply changes to the cluster") - return err -} - -func isValidArgumentList(args []string) error { - - if len(args) < 2 { - return fmt.Errorf("please provide a parameter name and value") - } else if len(args) > 2 { - return fmt.Errorf("only one value per parameter is allowed") - } - - var err error - param, ok := config.AsDevfileSupportedParameter(args[0]) - - if !ok { - err = errors.Errorf("the provided parameter is not supported, %v", args[0]) - } - - switch param { - case "memory", "minmemory", "maxmemory", "cpu", "mincpu", "maxcpu": - err = validation.NonNegativeValidator(args[1]) - if err != nil { - err = errors.Errorf("%s is invalid %v", param, err) - } - case "ports", "debugport": - err = validation.PortsValidator(args[1]) - } - - if err != nil { - err = errors.Errorf("validation failed for the provided arguments, %v", err) - } - - return err -} - -// NewCmdSet implements the config set odo command -func NewCmdSet(name, fullName string) *cobra.Command { - // The error is not handled at this point, it will be handled during Context creation - kubclient, _ := kclient.New() - prefClient, err := preference.NewClient() - if err != nil { - odoutil.LogErrorAndExit(err, "unable to set preference, something is wrong with odo, kindly raise an issue at https://github.com/redhat-developer/odo/issues/new?template=Bug.md") - } - o := NewSetOptions(project.NewClient(kubclient), prefClient) - configurationSetCmd := &cobra.Command{ - Use: name, - Short: "Set a value in odo config file", - Long: fmt.Sprintf(setLongDesc, config.FormatDevfileSupportedParameters()), - Example: fmt.Sprintf("\n"+devfileSetExample, fullName, config.Name, config.Ports, config.Memory), - Args: func(cmd *cobra.Command, args []string) error { - if o.envArrayFlag != nil { - // no args are needed - if len(args) > 0 { - return fmt.Errorf("expected 0 args") - } - return nil - } - return isValidArgumentList(args) - }, Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - configurationSetCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Don't ask for confirmation, set the config directly") - configurationSetCmd.Flags().StringArrayVarP(&o.envArrayFlag, "env", "e", nil, "Set the environment variables in config") - o.AddContextFlag(configurationSetCmd) - odoutil.AddNowFlag(configurationSetCmd, &o.nowFlag) - - return configurationSetCmd -} diff --git a/pkg/odo/cli/config/unset.go b/pkg/odo/cli/config/unset.go deleted file mode 100644 index 1c6f5ad1b..000000000 --- a/pkg/odo/cli/config/unset.go +++ /dev/null @@ -1,171 +0,0 @@ -package config - -import ( - "fmt" - "strings" - - "github.com/redhat-developer/odo/pkg/kclient" - "github.com/redhat-developer/odo/pkg/preference" - "github.com/redhat-developer/odo/pkg/project" - "github.com/redhat-developer/odo/pkg/util" - - "github.com/redhat-developer/odo/pkg/config" - "github.com/redhat-developer/odo/pkg/log" - clicomponent "github.com/redhat-developer/odo/pkg/odo/cli/component" - "github.com/redhat-developer/odo/pkg/odo/cli/ui" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const unsetCommandName = "unset" - -var ( - unsetLongDesc = ktemplates.LongDesc(`Unset an individual value in the devfile or odo configuration file. -%[1]s -`) - devfileUnsetExample = ktemplates.Examples(` - # Unset a configuration value in the devfile - %[1]s %[2]s - %[1]s %[3]s - %[1]s %[4]s - - # Unset a env variable in the devfiles - %[1]s --env KAFKA_HOST --env KAFKA_PORT - `) -) - -// UnsetOptions encapsulates the options for the command -type UnsetOptions struct { - // Push context - *clicomponent.PushOptions - - // Parameters - paramName string - - // Flags - forceFlag bool - envArrayFlag []string - nowFlag bool -} - -// NewUnsetOptions creates a new UnsetOptions instance -func NewUnsetOptions(prjClient project.Client, prefClient preference.Client) *UnsetOptions { - return &UnsetOptions{ - PushOptions: clicomponent.NewPushOptions(prjClient, prefClient), - } -} - -// Complete completes UnsetOptions after they've been created -func (o *UnsetOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - params := genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.GetComponentContext()) - if o.nowFlag { - params.CreateAppIfNeeded().RequireRouteAvailability() - } - o.Context, err = genericclioptions.New(params) - if err != nil { - if err1 := util.IsInvalidKubeConfigError(err); err1 != nil { - return err1 - } - return err - } - - o.DevfilePath = o.Context.EnvSpecificInfo.GetDevfilePath() - o.EnvSpecificInfo = o.Context.EnvSpecificInfo - - if o.envArrayFlag == nil { - o.paramName = args[0] - } - - if o.nowFlag { - prjName := o.Context.LocalConfigProvider.GetNamespace() - o.ResolveSrcAndConfigFlags() - err = o.ResolveProject(prjName) - if err != nil { - return err - } - } - - return nil -} - -// Validate validates the UnsetOptions based on completed values -func (o *UnsetOptions) Validate() error { - if !o.Context.LocalConfigProvider.Exists() { - return fmt.Errorf("the directory doesn't contain a component. Use 'odo create' to create a component") - } - return nil -} - -// Run contains the logic for the command -func (o *UnsetOptions) Run() error { - if o.envArrayFlag != nil { - - if err := o.EnvSpecificInfo.GetDevfileObj().RemoveEnvVars(o.envArrayFlag); err != nil { - return err - } - log.Success("Environment variables were successfully updated") - if o.nowFlag { - return o.DevfilePush() - } - log.Italic("\nRun `odo push` command to apply changes to the cluster") - return nil - } - if isSet := config.IsSetInDevfile(o.EnvSpecificInfo.GetDevfileObj(), o.paramName); isSet { - if !o.forceFlag && !ui.Proceed(fmt.Sprintf("Do you want to unset %s in the devfile", o.paramName)) { - fmt.Println("Aborted by the user.") - return nil - } - err := config.DeleteDevfileConfiguration(o.EnvSpecificInfo.GetDevfileObj(), strings.ToLower(o.paramName)) - log.Success("Devfile was successfully updated.") - if o.nowFlag { - return o.DevfilePush() - } - return err - } - return fmt.Errorf("config already unset, cannot unset a configuration which is not set") -} - -// NewCmdUnset implements the config unset odo command -func NewCmdUnset(name, fullName string) *cobra.Command { - // The error is not handled at this point, it will be handled during Context creation - kubclient, _ := kclient.New() - prefClient, err := preference.NewClient() - if err != nil { - odoutil.LogErrorAndExit(err, "unable to set preference, something is wrong with odo, kindly raise an issue at https://github.com/redhat-developer/odo/issues/new?template=Bug.md") - } - o := NewUnsetOptions(project.NewClient(kubclient), prefClient) - configurationUnsetCmd := &cobra.Command{ - Use: name, - Short: "Unset a value in odo config file", - Long: fmt.Sprintf(unsetLongDesc, config.FormatDevfileSupportedParameters()), - Example: fmt.Sprintf("\n"+devfileUnsetExample, fullName, config.Name, config.Ports, config.Memory), - Args: func(cmd *cobra.Command, args []string) error { - if o.envArrayFlag != nil { - // no args are needed - if len(args) > 0 { - return fmt.Errorf("expected 0 args") - } - return nil - } - - if len(args) < 1 { - return fmt.Errorf("please provide a parameter name") - } else if len(args) > 1 { - return fmt.Errorf("only one parameter is allowed") - } else { - return nil - } - - }, Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - configurationUnsetCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Don't ask for confirmation, unsetting the config directly") - configurationUnsetCmd.Flags().StringSliceVarP(&o.envArrayFlag, "env", "e", nil, "Unset the environment variables in config") - o.AddContextFlag(configurationUnsetCmd) - odoutil.AddNowFlag(configurationUnsetCmd, &o.nowFlag) - return configurationUnsetCmd -} diff --git a/pkg/odo/cli/config/view.go b/pkg/odo/cli/config/view.go deleted file mode 100644 index 79000afbc..000000000 --- a/pkg/odo/cli/config/view.go +++ /dev/null @@ -1,90 +0,0 @@ -package config - -import ( - "fmt" - "os" - "text/tabwriter" - - "github.com/redhat-developer/odo/pkg/component" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" - "sigs.k8s.io/yaml" -) - -const viewCommandName = "view" - -var viewExample = ktemplates.Examples(`# For viewing the current configuration from devfile or local config file - %[1]s - - `) - -// ViewOptions encapsulates the options for the command -type ViewOptions struct { - // Context - *genericclioptions.Context - - // Flags - contextFlag string -} - -// NewViewOptions creates a new ViewOptions instance -func NewViewOptions() *ViewOptions { - return &ViewOptions{} -} - -// Complete completes ViewOptions after they've been created -func (o *ViewOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - params := genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag) - o.Context, err = genericclioptions.New(params) - return err -} - -// Validate validates the ViewOptions based on completed values -func (o *ViewOptions) Validate() error { - return nil -} - -// Run contains the logic for the command -func (o *ViewOptions) Run() (err error) { - w := tabwriter.NewWriter(os.Stdout, 5, 2, 2, ' ', tabwriter.TabIndent) - repr, err := component.ToDevfileRepresentation(o.Context.EnvSpecificInfo.GetDevfileObj()) - if err != nil { - return err - } - if log.IsJSON() { - machineoutput.OutputSuccess(component.WrapFromJSONOutput(repr)) - return nil - } - representation, err := yaml.Marshal(repr) - if err != nil { - return err - } - - fmt.Fprintln(w, string(representation)) - return nil -} - -// NewCmdView implements the config view odo command -func NewCmdView(name, fullName string) *cobra.Command { - o := NewViewOptions() - configurationViewCmd := &cobra.Command{ - Use: name, - Short: "View current configuration values", - Long: "View current configuration values", - Annotations: map[string]string{"machineoutput": "json"}, - Example: fmt.Sprintf(fmt.Sprint("\n", viewExample), fullName), - Args: cobra.ExactArgs(0), - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - odoutil.AddContextFlag(configurationViewCmd, &o.contextFlag) - - return configurationViewCmd -} diff --git a/pkg/odo/cli/debug/debug.go b/pkg/odo/cli/debug/debug.go deleted file mode 100644 index f7bfa4cac..000000000 --- a/pkg/odo/cli/debug/debug.go +++ /dev/null @@ -1,39 +0,0 @@ -package debug - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const ( - // RecommendedCommandName is the recommended debug command name - RecommendedCommandName = "debug" -) - -var debugLongDesc = ktemplates.LongDesc(`Debug allows you to remotely debug your application.`) - -func NewCmdDebug(name, fullName string) *cobra.Command { - - portforwardCmd := NewCmdPortForward(portforwardCommandName, util.GetFullName(fullName, portforwardCommandName)) - infoCmd := NewCmdInfo(infoCommandName, util.GetFullName(fullName, infoCommandName)) - - debugCmd := &cobra.Command{ - Use: name, - Short: "Debug commands", - Example: fmt.Sprintf("%s\n\n%s", - portforwardCmd.Example, - infoCmd.Example), - Long: debugLongDesc, - Aliases: []string{"d"}, - } - - debugCmd.SetUsageTemplate(util.CmdUsageTemplate) - debugCmd.AddCommand(portforwardCmd) - debugCmd.AddCommand(infoCmd) - debugCmd.Annotations = map[string]string{"command": "main"} - - return debugCmd -} diff --git a/pkg/odo/cli/debug/info.go b/pkg/odo/cli/debug/info.go deleted file mode 100644 index d50a60b3c..000000000 --- a/pkg/odo/cli/debug/info.go +++ /dev/null @@ -1,98 +0,0 @@ -package debug - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/debug" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - k8sgenclioptions "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/templates" -) - -// InfoOptions contains all the options for running the info cli command. -type InfoOptions struct { - // Context - *genericclioptions.Context - - // Flags - contextFlag string - - // Port forwarder backend - PortForwarder *debug.DefaultPortForwarder -} - -var ( - infoLong = templates.LongDesc(` - Gets information regarding any debug session of the component. - `) - - infoExample = templates.Examples(` - # Get information regarding any debug session of the component - odo debug info - - `) -) - -const ( - infoCommandName = "info" -) - -func NewInfoOptions() *InfoOptions { - return &InfoOptions{} -} - -// Complete completes all the required options for port-forward cmd. -func (o *InfoOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - - // Using Discard streams because nothing important is logged - o.PortForwarder = debug.NewDefaultPortForwarder(o.Context.EnvSpecificInfo.GetName(), o.Context.GetApplication(), o.Context.EnvSpecificInfo.GetNamespace(), o.KClient, k8sgenclioptions.NewTestIOStreamsDiscard()) - - return err -} - -// Validate validates all the required options for port-forward cmd. -func (o InfoOptions) Validate() error { - return nil -} - -// Run implements all the necessary functionality for port-forward cmd. -func (o InfoOptions) Run() error { - if debugInfo, debugging := debug.GetInfo(o.PortForwarder); debugging { - if log.IsJSON() { - machineoutput.OutputSuccess(debugInfo) - } else { - log.Infof("Debug is running for the component on the local port : %v", debugInfo.Spec.LocalPort) - } - } else { - return fmt.Errorf("debug is not running for the component %v", o.Context.EnvSpecificInfo.GetName()) - } - return nil -} - -// NewCmdInfo implements the debug info odo command -func NewCmdInfo(name, fullName string) *cobra.Command { - - opts := NewInfoOptions() - cmd := &cobra.Command{ - Use: name, - Short: "Displays debug info of a component", - Long: infoLong, - Example: infoExample, - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(opts, cmd, args) - }, - } - odoutil.AddContextFlag(cmd, &opts.contextFlag) - - return cmd -} diff --git a/pkg/odo/cli/debug/portforward.go b/pkg/odo/cli/debug/portforward.go deleted file mode 100644 index d1e3f77bc..000000000 --- a/pkg/odo/cli/debug/portforward.go +++ /dev/null @@ -1,170 +0,0 @@ -package debug - -import ( - "fmt" - "net" - "os" - "os/signal" - "strconv" - "syscall" - - "github.com/redhat-developer/odo/pkg/debug" - "github.com/redhat-developer/odo/pkg/devfile/location" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/util" - - "github.com/spf13/cobra" - - k8sgenclioptions "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/templates" -) - -const ( - // DefaultDebugPort is the default port used for debugging on remote pod - DefaultDebugPort = 5858 -) - -// PortForwardOptions contains all the options for running the port-forward cli command. -type PortForwardOptions struct { - // Context - *genericclioptions.Context - - // Flags - contextFlag string - localPortFlag int - - // PortPair is the combination of local and remote port in the format "local:remote" - PortPair string - - // Port forwarder backend - PortForwarder *debug.DefaultPortForwarder - - // StopChannel is used to stop port forwarding - StopChannel chan struct{} - - // ReadChannel is used to receive status of port forwarding ( ready or not ready ) - ReadyChannel chan struct{} -} - -var ( - portforwardLong = templates.LongDesc(`Forward a local port to a remote port on the pod where the application is listening for a debugger. By default the local port and the remote port will be same. To change the local port you can use --local-port argument and to change the remote port use "odo env set DebugPort " - `) - - portforwardExample = templates.Examples(` - # Listen on default port and forwarding to the default port in the pod - odo debug port-forward - - # Listen on the 5000 port locally, forwarding to default port in the pod - odo debug port-forward --local-port 5000 - - `) -) - -const ( - portforwardCommandName = "port-forward" -) - -// NewPortForwardOptions returns the PortForwardOptions struct -func NewPortForwardOptions() *PortForwardOptions { - return &PortForwardOptions{} -} - -// Complete completes all the required options for port-forward cmd. -func (o *PortForwardOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline)) - if err != nil { - return err - } - - remotePort := o.Context.EnvSpecificInfo.GetDebugPort() - - // try to listen on the given local port and check if the port is free or not - addressLook := "localhost:" + strconv.Itoa(o.localPortFlag) - listener, err := net.Listen("tcp", addressLook) - if err != nil { - // if the local-port flag is set by the user, return the error and stop execution - if cmdline.IsFlagSet("local-port") { - return err - } - // else display a error message and auto select a new free port - log.Errorf("the local debug port %v is not free, cause: %v", o.localPortFlag, err) - o.localPortFlag, err = util.HTTPGetFreePort() - if err != nil { - return err - } - log.Infof("The local port %v is auto selected", o.localPortFlag) - } else { - err = listener.Close() - if err != nil { - return err - } - } - - o.PortPair = fmt.Sprintf("%d:%d", o.localPortFlag, remotePort) - - // Using Discard streams because nothing important is logged - o.PortForwarder = debug.NewDefaultPortForwarder(o.Context.EnvSpecificInfo.GetName(), o.Context.GetApplication(), o.Context.EnvSpecificInfo.GetNamespace(), o.KClient, k8sgenclioptions.NewTestIOStreamsDiscard()) - - o.StopChannel = make(chan struct{}, 1) - o.ReadyChannel = make(chan struct{}) - return nil -} - -// Validate validates all the required options for port-forward cmd. -func (o PortForwardOptions) Validate() error { - if len(o.PortPair) < 1 { - return fmt.Errorf("ports cannot be empty") - } - return nil -} - -// Run implements all the necessary functionality for port-forward cmd. -func (o PortForwardOptions) Run() error { - - signals := make(chan os.Signal, 1) - signal.Notify(signals, os.Interrupt, - syscall.SIGHUP, - syscall.SIGINT, - syscall.SIGTERM, - syscall.SIGQUIT) - defer signal.Stop(signals) - defer os.RemoveAll(debug.GetDebugInfoFilePath(o.Context.EnvSpecificInfo.GetName(), o.Context.GetApplication(), o.Context.EnvSpecificInfo.GetNamespace())) - - go func() { - <-signals - if o.StopChannel != nil { - close(o.StopChannel) - } - }() - - err := debug.CreateDebugInfoFile(o.PortForwarder, o.PortPair) - if err != nil { - return err - } - - devfilePath := location.DevfileLocation(o.contextFlag) - return o.PortForwarder.ForwardPorts(o.PortPair, o.StopChannel, o.ReadyChannel, util.CheckPathExists(devfilePath)) -} - -// NewCmdPortForward implements the port-forward odo command -func NewCmdPortForward(name, fullName string) *cobra.Command { - - opts := NewPortForwardOptions() - cmd := &cobra.Command{ - Use: name, - Short: "Forward one or more local ports to a pod", - Long: portforwardLong, - Example: portforwardExample, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(opts, cmd, args) - }, - } - - odoutil.AddContextFlag(cmd, &opts.contextFlag) - cmd.Flags().IntVarP(&opts.localPortFlag, "local-port", "l", DefaultDebugPort, "Set the local port") - - return cmd -} diff --git a/pkg/odo/cli/env/env.go b/pkg/odo/cli/env/env.go deleted file mode 100644 index 3d9a10cd1..000000000 --- a/pkg/odo/cli/env/env.go +++ /dev/null @@ -1,68 +0,0 @@ -package env - -import ( - "fmt" - "strings" - - "github.com/redhat-developer/odo/pkg/odo/util" - genericUtil "github.com/redhat-developer/odo/pkg/util" - - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -// RecommendedCommandName is the recommended env command name -const RecommendedCommandName = "env" - -const ( - nameParameter = "Name" - nameParameterDescription = "Use this value to set component name" - projectParameter = "Project" - projectParameterDescription = "Use this value to set component project" - debugportParameter = "DebugPort" - debugportParameterDescription = "Use this value to set component debug port" -) - -var envLongDesc = ktemplates.LongDesc(`Modifies odo specific configuration settings within environment file`) - -// NewCmdEnv implements the environment configuration command -func NewCmdEnv(name, fullName string) *cobra.Command { - envViewCmd := NewCmdView(viewCommandName, util.GetFullName(fullName, viewCommandName)) - envSetCmd := NewCmdSet(setCommandName, util.GetFullName(fullName, setCommandName)) - envUnsetCmd := NewCmdUnset(unsetCommandName, util.GetFullName(fullName, unsetCommandName)) - envCmd := &cobra.Command{ - Use: name, - Short: "Change or view environment configuration", - Long: envLongDesc, - Example: fmt.Sprintf("%s\n\n%s\n\n%s", - envViewCmd.Example, - envSetCmd.Example, - envUnsetCmd.Example, - ), - } - - envCmd.AddCommand(envViewCmd, envSetCmd, envUnsetCmd) - envCmd.SetUsageTemplate(util.CmdUsageTemplate) - envCmd.Annotations = map[string]string{"command": "main"} - - return envCmd -} - -func printSupportedParameters(supportedParameters map[string]string) string { - output := "\n\nAvailable parameters:\n" - for _, parameter := range genericUtil.GetSortedKeys(supportedParameters) { - output = fmt.Sprintf("%s %s: %s\n", output, parameter, supportedParameters[parameter]) - } - - return output -} - -func isSupportedParameter(parameter string, supportedParameters map[string]string) bool { - for supportedParameter := range supportedParameters { - if strings.EqualFold(supportedParameter, parameter) { - return true - } - } - - return false -} diff --git a/pkg/odo/cli/env/env_test.go b/pkg/odo/cli/env/env_test.go deleted file mode 100644 index d7919bfc4..000000000 --- a/pkg/odo/cli/env/env_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package env - -import ( - "reflect" - "sort" - "strings" - "testing" -) - -func TestPrintSupportedParameters(t *testing.T) { - supportedSetParameters := map[string]string{ - nameParameter: nameParameterDescription, - projectParameter: projectParameterDescription, - debugportParameter: debugportParameterDescription, - } - - wantSetParameters := `Available parameters: - DebugPort: Use this value to set component debug port - Name: Use this value to set component name - Project: Use this value to set component project` - - supportedUnsetParameters := map[string]string{ - debugportParameter: debugportParameterDescription, - } - - wantUnsetParameters := `Available parameters: - DebugPort: Use this value to set component debug port` - - tests := []struct { - name string - supportedParameters map[string]string - want string - }{ - { - name: "Case 1: Test print supported set parameters", - supportedParameters: supportedSetParameters, - want: wantSetParameters, - }, - { - name: "Case 2: Test print supported unset parameters", - supportedParameters: supportedUnsetParameters, - want: wantUnsetParameters, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := strings.TrimSpace(printSupportedParameters(tt.supportedParameters)) - - gotStrings := strings.Split(got, "\n") - wantStrings := strings.Split(tt.want, "\n") - - sort.Strings(gotStrings) - sort.Strings(wantStrings) - - if !reflect.DeepEqual(wantStrings, gotStrings) { - t.Errorf("\nGot: %s\nWant: %s", got, tt.want) - } - }) - } -} diff --git a/pkg/odo/cli/env/set.go b/pkg/odo/cli/env/set.go deleted file mode 100644 index 512ad215b..000000000 --- a/pkg/odo/cli/env/set.go +++ /dev/null @@ -1,138 +0,0 @@ -package env - -import ( - "fmt" - "strings" - - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - - "github.com/redhat-developer/odo/pkg/odo/cli/ui" - - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const setCommandName = "set" - -var ( - setLongDesc = ktemplates.LongDesc(` - Set an individual value in the odo environment file - `) - - setExample = ktemplates.Examples(` - # Set an individual value in the odo environment file - %[1]s %[2]s myNodejs - %[1]s %[3]s myProject - %[1]s %[4]s 8888 - `) -) - -var ( - supportedSetParameters = map[string]string{ - nameParameter: nameParameterDescription, - projectParameter: projectParameterDescription, - debugportParameter: debugportParameterDescription, - } -) - -// SetOptions encapsulates the options for the command -type SetOptions struct { - // Env context - cfg *envinfo.EnvSpecificInfo - - // Parameters - paramName string - paramValue string - - // Flags - contextFlag string - forceFlag bool -} - -// NewSetOptions creates a new SetOptions instance -func NewSetOptions() *SetOptions { - return &SetOptions{} -} - -// Complete completes SetOptions after they've been created -func (o *SetOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.cfg, err = envinfo.NewEnvSpecificInfo(o.contextFlag) - if err != nil { - return errors.Wrap(err, "failed to load environment file") - } - - o.paramName = args[0] - o.paramValue = args[1] - - return nil -} - -// Validate validates the SetOptions based on completed values -func (o *SetOptions) Validate() (err error) { - if !o.cfg.Exists() { - return errors.Errorf("the context directory doesn't contain a component, please refer `odo create --help` to create a component") - } - - if !isSupportedParameter(o.paramName, supportedSetParameters) { - return errors.Errorf("%q is not a valid parameter to set, please refer `odo env set --help` to set a valid parameter", o.paramName) - } - - return nil -} - -// Run contains the logic for the command -func (o *SetOptions) Run() (err error) { - if !o.forceFlag { - if isSet := o.cfg.IsSet(o.paramName); isSet { - if !ui.Proceed(fmt.Sprintf("%v is already set. Do you want to override it in the environment", o.paramName)) { - log.Info("Aborted by the user") - return nil - } - } - } - - err = o.cfg.SetConfiguration(strings.ToLower(o.paramName), o.paramValue) - if err != nil { - return err - } - - log.Info("Environment was successfully updated") - if strings.ToLower(o.paramName) == "name" || strings.ToLower(o.paramName) == "project" { - log.Warningf("Updated %q would create a new component", o.paramName) - } - - return nil -} - -// NewCmdSet implements the env set odo command -func NewCmdSet(name, fullName string) *cobra.Command { - o := NewSetOptions() - envSetCmd := &cobra.Command{ - Use: name, - Short: "Set a value in odo environment file", - Long: setLongDesc + printSupportedParameters(supportedSetParameters), - Example: fmt.Sprintf(fmt.Sprint(setExample), fullName, - envinfo.Name, envinfo.Project, envinfo.DebugPort), - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 2 { - return fmt.Errorf("please provide a parameter name and value") - } else if len(args) > 2 { - return fmt.Errorf("only one value per parameter is allowed") - } else { - return nil - } - - }, Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - envSetCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Don't ask for confirmation, set the environment directly") - envSetCmd.Flags().StringVar(&o.contextFlag, "context", "", "Use given context directory as a source for component settings") - - return envSetCmd -} diff --git a/pkg/odo/cli/env/unset.go b/pkg/odo/cli/env/unset.go deleted file mode 100644 index d4c15a8d2..000000000 --- a/pkg/odo/cli/env/unset.go +++ /dev/null @@ -1,129 +0,0 @@ -package env - -import ( - "fmt" - "strings" - - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/odo/cli/ui" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const unsetCommandName = "unset" - -var ( - unsetLongDesc = ktemplates.LongDesc(` - Unset an individual value in the odo environment file - `) - - unsetExample = ktemplates.Examples(` - # Unset an individual value in the environment file - %[1]s %[2]s - `) -) - -var ( - supportedUnsetParameters = map[string]string{ - debugportParameter: debugportParameterDescription, - } -) - -// UnsetOptions encapsulates the options for the command -type UnsetOptions struct { - // Env context - cfg *envinfo.EnvSpecificInfo - - // Parameters - paramName string - - // Flags - contextFlag string - forceFlag bool -} - -// NewUnsetOptions creates a new UnsetOptions instance -func NewUnsetOptions() *UnsetOptions { - return &UnsetOptions{} -} - -// Complete completes UnsetOptions after they've been created -func (o *UnsetOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.cfg, err = envinfo.NewEnvSpecificInfo(o.contextFlag) - if err != nil { - return errors.Wrap(err, "failed to load environment file") - } - - o.paramName = args[0] - - return nil -} - -// Validate validates the UnsetOptions based on completed values -func (o *UnsetOptions) Validate() (err error) { - if !o.cfg.Exists() { - return errors.Errorf("the context directory doesn't contain a component, please refer `odo create --help` to create a component") - } - - if !isSupportedParameter(o.paramName, supportedUnsetParameters) { - return errors.Errorf("%q is not a valid parameter to unset, please refer `odo env unset --help` to unset a valid parameter", o.paramName) - } - - return nil -} - -// Run contains the logic for the command -func (o *UnsetOptions) Run() (err error) { - if !o.forceFlag { - if isSet := o.cfg.IsSet(o.paramName); isSet { - if !ui.Proceed(fmt.Sprintf("Do you want to unset %s in the environment", o.paramName)) { - log.Infof("Aborted by the user") - return nil - } - } else { - return errors.New("environment already unset, cannot unset a environment which is not set") - } - } - - err = o.cfg.DeleteConfiguration(strings.ToLower(o.paramName)) - if err != nil { - return err - } - - log.Info("Environment was successfully updated") - return nil - -} - -// NewCmdUnset implements the environment unset odo command -func NewCmdUnset(name, fullName string) *cobra.Command { - o := NewUnsetOptions() - envUnsetCmd := &cobra.Command{ - Use: name, - Short: "Unset a value in odo environment file", - Long: unsetLongDesc + printSupportedParameters(supportedUnsetParameters), - Example: fmt.Sprintf(fmt.Sprint(unsetExample), fullName, envinfo.DebugPort), - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("please provide a parameter name") - } else if len(args) > 1 { - return fmt.Errorf("only one parameter is allowed") - } else { - return nil - } - - }, Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - envUnsetCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Don't ask for confirmation, unsetting the environment directly") - envUnsetCmd.Flags().StringVar(&o.contextFlag, "context", "", "Use given context directory as a source for component settings") - - return envUnsetCmd -} diff --git a/pkg/odo/cli/env/view.go b/pkg/odo/cli/env/view.go deleted file mode 100644 index cf4b0db62..000000000 --- a/pkg/odo/cli/env/view.go +++ /dev/null @@ -1,93 +0,0 @@ -package env - -import ( - "fmt" - "os" - - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const viewCommandName = "view" - -var ( - viewLongDesc = ktemplates.LongDesc(` - View current values in odo environment file - `) - - viewExample = ktemplates.Examples(` - # For viewing the current environment configuration settings - %[1]s - `) -) - -// ViewOptions encapsulates the options for the command -type ViewOptions struct { - // Env context - cfg *envinfo.EnvSpecificInfo - - // Flags - contextFlag string -} - -// NewViewOptions creates a new ViewOptions instance -func NewViewOptions() *ViewOptions { - return &ViewOptions{} -} - -// Complete completes ViewOptions after they've been created -func (o *ViewOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.cfg, err = envinfo.NewEnvSpecificInfo(o.contextFlag) - if err != nil { - return errors.Wrap(err, "failed to load environment file") - } - - return nil -} - -// Validate validates the ViewOptions based on completed values -func (o *ViewOptions) Validate() (err error) { - if !o.cfg.Exists() { - return errors.Errorf("the context directory doesn't contain a component, please refer `odo create --help` on how to create a component") - } - - return nil -} - -// Run contains the logic for the command -func (o *ViewOptions) Run() (err error) { - info := envinfo.NewInfo(o.cfg.GetComponentSettings()) - if log.IsJSON() { - machineoutput.OutputSuccess(info) - return - } - info.Output(os.Stdout) - return nil -} - -// NewCmdView implements the env view odo command -func NewCmdView(name, fullName string) *cobra.Command { - o := NewViewOptions() - envViewCmd := &cobra.Command{ - Use: name, - Short: "View current values in odo environment file", - Long: viewLongDesc, - Example: fmt.Sprintf(fmt.Sprint(viewExample), fullName), - Annotations: map[string]string{"machineoutput": "json"}, - - Args: cobra.ExactArgs(0), - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - envViewCmd.Flags().StringVar(&o.contextFlag, "context", "", "Use given context directory as a source for component settings") - - return envViewCmd -} diff --git a/pkg/odo/cli/service/OWNERS b/pkg/odo/cli/service/OWNERS deleted file mode 100644 index 55786f8d9..000000000 --- a/pkg/odo/cli/service/OWNERS +++ /dev/null @@ -1,9 +0,0 @@ -# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md - -approvers: -- dharmit -- mik-dass - -reviewers: -- dharmit -- mik-dass \ No newline at end of file diff --git a/pkg/odo/cli/service/create.go b/pkg/odo/cli/service/create.go deleted file mode 100644 index 0c915ac33..000000000 --- a/pkg/odo/cli/service/create.go +++ /dev/null @@ -1,144 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - "github.com/redhat-developer/odo/pkg/odo/util" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const ( - createRecommendedCommandName = "create" -) - -var ( - createOperatorExample = ktemplates.Examples(` - # Create new EtcdCluster service from etcdoperator.v0.9.4 operator. - %[1]s etcdoperator.v0.9.4/EtcdCluster - - # Create new EtcdCluster service from etcdoperator.v0.9.4 operator and puts the service definition in the devfile instead of a separate file. - %[1]s etcdoperator.v0.9.4/EtcdCluster --inlined`) - - createShortDesc = `Create a new service from Operator Hub and deploy it on Kubernetes or OpenShift.` - - createLongDesc = ktemplates.LongDesc(` -Create a new service from Operator Hub and deploy it on Kubernetes or OpenShift. - -Service creation can be performed from a valid component directory (one containing a devfile.yaml) only. - -To create the service from outside a component directory, specify path to a valid component directory using "--context" flag. - -When creating a service using Operator Hub, provide a service name along with Operator name. - -For a full list of service types, use: 'odo catalog list services'`) -) - -// CreateOptions encapsulates the options for the odo service create command -type CreateOptions struct { - // Context - *genericclioptions.Context - - // Flags - parametersFlag []string - waitFlag bool - contextFlag string - DryRunFlag bool - fromFileFlag string - inlinedFlag bool - - // ServiceType corresponds to the service class name - ServiceType string - // ServiceName is how the service will be named and known by odo - ServiceName string - // ParametersMap is populated from the flag-provided values (parameters) and/or the interactive mode and is the expected format by the business logic - ParametersMap map[string]string - // interactive specifies whether the command operates in interactive mode or not - interactive bool - // CmdFullName records the command's full name - CmdFullName string - // Backend is the service provider backend providing the service requested by the user - Backend ServiceProviderBackend -} - -// NewCreateOptions creates a new CreateOptions instance -func NewCreateOptions() *CreateOptions { - return &CreateOptions{} -} - -// Complete completes CreateOptions after they've been created -func (o *CreateOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag)) - if err != nil { - return err - } - // we convert the param list provided in the format of key=value list - // to a map - o.ParametersMap, err = util.MapFromParameters(o.parametersFlag) - if err != nil { - return err - } - - err = validDevfileDirectory(o.contextFlag) - if err != nil { - return err - } - // if no args are provided and if request is not from file, user wants interactive mode - if o.fromFileFlag == "" && len(args) == 0 { - return fmt.Errorf("odo doesn't support interactive mode for creating Operator backed service") - } - o.Backend = NewOperatorBackend() - o.interactive = false - return o.Backend.CompleteServiceCreate(o, args) -} - -// Validate validates the CreateOptions based on completed values -func (o *CreateOptions) Validate() (err error) { - return o.Backend.ValidateServiceCreate(o) -} - -// Run contains the logic for the odo service create command -func (o *CreateOptions) Run() (err error) { - err = o.Backend.RunServiceCreate(o) - if err != nil { - return fmt.Errorf("service %q already exists in configuration", o.ServiceName) - } - - // Information on what to do next; don't do this if "--dry-run" was requested as it gets appended to the file - if !o.DryRunFlag { - log.Info("Successfully added service to the configuration; do 'odo push' to create service on the cluster") - } - - return nil -} - -// NewCmdServiceCreate implements the odo service create command. -func NewCmdServiceCreate(name, fullName string) *cobra.Command { - o := NewCreateOptions() - o.CmdFullName = fullName - serviceCreateCmd := &cobra.Command{ - Use: name + " / [service_name] [flags]", - Short: createShortDesc, - Long: createLongDesc, - Example: fmt.Sprintf(createOperatorExample, fullName), - Args: cobra.RangeArgs(0, 2), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - serviceCreateCmd.Flags().BoolVar(&o.inlinedFlag, "inlined", false, "Puts the service definition in the devfile instead of a separate file") - serviceCreateCmd.Flags().BoolVar(&o.DryRunFlag, "dry-run", false, "Print the yaml specificiation that will be used to create the operator backed service") - // remove this feature after enabling service create interactive mode for operator backed services - serviceCreateCmd.Flags().StringVar(&o.fromFileFlag, "from-file", "", "Path to the file containing yaml specification to use to start operator backed service") - - serviceCreateCmd.Flags().StringArrayVarP(&o.parametersFlag, "parameters", "p", []string{}, "Parameters to be used to create Operator backed service where a parameter is expressed as =", - Short: "Delete an existing service", - Long: deleteLongDesc, - Example: fmt.Sprintf(deleteExample, fullName), - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - klog.V(4).Infof("service delete called\n args: %#v", strings.Join(args, " ")) - genericclioptions.GenericRun(o, cmd, args) - }, - } - serviceDeleteCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Delete service without prompting") - odoutil.AddContextFlag(serviceDeleteCmd, &o.contextFlag) - return serviceDeleteCmd -} diff --git a/pkg/odo/cli/service/describe.go b/pkg/odo/cli/service/describe.go deleted file mode 100644 index 347925cd8..000000000 --- a/pkg/odo/cli/service/describe.go +++ /dev/null @@ -1,108 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/service" - svc "github.com/redhat-developer/odo/pkg/service" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const describeRecommendedCommandName = "describe" - -var ( - describeExample = ktemplates.Examples(` - # Describe the service named 'mysql-persistent' - %[1]s mysql-persistent`) - - describeLongDesc = ktemplates.LongDesc(` - Describe an existing service, either defined locally or deployed to the cluster`) -) - -// DescribeOptions encapsulates the options for the odo service describe command -type DescribeOptions struct { - // Context - *genericclioptions.Context - - // Parameters - serviceName string - - // Flags - contextFlag string - - // Backend is the service provider backend that was used to create the service - Backend ServiceProviderBackend -} - -// NewDescribeOptions creates a new DescribeOptions instance -func NewDescribeOptions() *DescribeOptions { - return &DescribeOptions{} -} - -func (o *DescribeOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag)) - if err != nil { - return err - } - - err = validDevfileDirectory(o.contextFlag) - if err != nil { - return err - } - - o.serviceName = args[0] - _, _, err = service.SplitServiceKindName(o.serviceName) - if err != nil { - return fmt.Errorf("invalid service name") - } - o.Backend = NewOperatorBackend() - - return nil -} - -// Validate validates the DescribeOptions based on completed values -func (o *DescribeOptions) Validate() error { - svcDefined, err := o.Backend.ServiceDefined(o.Context, o.serviceName) - if err != nil { - return err - } - - svcDeployed, err := svc.OperatorSvcExists(o.KClient, o.serviceName) - if err != nil { - return err - } - - if !svcDefined && !svcDeployed { - return fmt.Errorf("couldn't find service named %q. Refer %q to see list of defined services", o.serviceName, "odo service list") - } - return nil -} - -// Run contains the logic for the odo service describe command -func (o *DescribeOptions) Run() error { - return o.Backend.DescribeService(o, o.serviceName, o.GetApplication()) -} - -// NewCmdDescribe implements the describe odo command -func NewCmdServiceDescribe(name, fullName string) *cobra.Command { - do := NewDescribeOptions() - - var describeCmd = &cobra.Command{ - Use: fmt.Sprintf("%s [service_name]", name), - Short: "Describe an existing service", - Long: describeLongDesc, - Example: fmt.Sprintf(describeExample, fullName), - Args: cobra.ExactArgs(1), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(do, cmd, args) - }, - } - - odoutil.AddContextFlag(describeCmd, &do.contextFlag) - return describeCmd -} diff --git a/pkg/odo/cli/service/interface.go b/pkg/odo/cli/service/interface.go deleted file mode 100644 index 7c932d568..000000000 --- a/pkg/odo/cli/service/interface.go +++ /dev/null @@ -1,17 +0,0 @@ -package service - -import ( - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" -) - -// ServiceProviderBackend is implemented by the backends supported by odo -// It is used in "odo service create" and "odo service delete" -type ServiceProviderBackend interface { - CompleteServiceCreate(options *CreateOptions, args []string) error - ValidateServiceCreate(options *CreateOptions) error - RunServiceCreate(options *CreateOptions) error - - ServiceDefined(context *genericclioptions.Context, name string) (bool, error) - DeleteService(options *DeleteOptions, serviceName, app string) error - DescribeService(options *DescribeOptions, serviceName, app string) error -} diff --git a/pkg/odo/cli/service/list.go b/pkg/odo/cli/service/list.go deleted file mode 100644 index 545618cfe..000000000 --- a/pkg/odo/cli/service/list.go +++ /dev/null @@ -1,86 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const listRecommendedCommandName = "list" - -var ( - listExample = ktemplates.Examples(` - # List all services in the application - %[1]s`) - listLongDesc = ktemplates.LongDesc(` -List all services in the current application -`) -) - -// ServiceListOptions encapsulates the options for the odo service list command -type ServiceListOptions struct { - // Context - *genericclioptions.Context - - // Flags - contextFlag string - - // If true, Operator Hub is installed on the cluster - csvSupport bool -} - -// NewServiceListOptions creates a new ServiceListOptions instance -func NewServiceListOptions() *ServiceListOptions { - return &ServiceListOptions{} -} - -// Complete completes ServiceListOptions after they've been created -func (o *ServiceListOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag)) - if err != nil { - return err - } - - o.csvSupport, err = o.KClient.IsCSVSupported() - if err != nil { - return err - } - - if !o.csvSupport { - return fmt.Errorf("failed to list Operator backed services, make sure you have installed the Operators on the cluster") - } - - return nil -} - -// Validate validates the ServiceListOptions based on completed values -func (o *ServiceListOptions) Validate() (err error) { - return nil -} - -// Run contains the logic for the odo service list command -func (o *ServiceListOptions) Run() (err error) { - return o.listOperatorServices() -} - -// NewCmdServiceList implements the odo service list command. -func NewCmdServiceList(name, fullName string) *cobra.Command { - o := NewServiceListOptions() - serviceListCmd := &cobra.Command{ - Use: name, - Short: "List all services in the current application", - Long: listLongDesc, - Example: fmt.Sprintf(listExample, fullName), - Args: cobra.NoArgs, - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - odoutil.AddContextFlag(serviceListCmd, &o.contextFlag) - return serviceListCmd -} diff --git a/pkg/odo/cli/service/list_operator.go b/pkg/odo/cli/service/list_operator.go deleted file mode 100644 index 99662a4b1..000000000 --- a/pkg/odo/cli/service/list_operator.go +++ /dev/null @@ -1,218 +0,0 @@ -package service - -import ( - "fmt" - "os" - "sort" - "strings" - "text/tabwriter" - "time" - - applabels "github.com/redhat-developer/odo/pkg/application/labels" - cmplabels "github.com/redhat-developer/odo/pkg/component/labels" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - svc "github.com/redhat-developer/odo/pkg/service" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -const ServiceItemKind = "Service" - -type clusterInfo struct { - Labels map[string]string `json:"labels"` - CreationTimestamp time.Time `json:"creationTimestamp"` -} - -type serviceItem struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - ClusterInfo *clusterInfo `json:"clusterInfo,omitempty"` - InDevfile bool `json:"inDevfile"` - Deployed bool `json:"deployed"` - Manifest map[string]interface{} `json:"manifest"` -} - -type serviceItemList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []serviceItem `json:"items"` -} - -func NewServiceItem(name string) *serviceItem { - return &serviceItem{ - TypeMeta: metav1.TypeMeta{ - Kind: ServiceItemKind, - APIVersion: machineoutput.APIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - } -} - -// listOperatorServices lists the operator backed services -// - deployed in the cluster -// - defined in the current devfile -func (o *ServiceListOptions) listOperatorServices() (err error) { - - // get the services deployed - var clusterList []unstructured.Unstructured - clusterList, failedListingCR, err := svc.ListOperatorServices(o.KClient) - if err != nil { - return err - } - - // get the services defined in the devfile - // and the name of the component of the devfile - var devfileList map[string]unstructured.Unstructured - var devfileComponent string - if o.EnvSpecificInfo != nil { - devfileList, err = svc.ListDevfileServices(o.KClient, o.EnvSpecificInfo.GetDevfileObj(), o.contextFlag) - if err != nil { - return fmt.Errorf("error reading devfile") - } - devfileComponent = o.EnvSpecificInfo.GetComponentSettings().Name - } - - servicesItems := mixServices(clusterList, devfileList) - - if len(servicesItems.Items) == 0 { - if len(failedListingCR) > 0 { - fmt.Printf("Failed to fetch services for operator(s): %q\n\n", strings.Join(failedListingCR, ", ")) - } - return fmt.Errorf("no operator backed services found in namespace: %s", o.KClient.GetCurrentNamespace()) - } - - if log.IsJSON() { - machineoutput.OutputSuccess(servicesItems) - return nil - } - - // output result - w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent) - fmt.Fprintln(w, "NAME", "\t", "MANAGED BY ODO", "\t", "STATE", "\t", "AGE") - for i := range servicesItems.Items { - item := servicesItems.Items[i] - managedByOdo, state, duration := getTabularInfo(&item, devfileComponent) - fmt.Fprintln(w, item.Name, "\t", managedByOdo, "\t", state, "\t", duration) - } - w.Flush() - - if len(failedListingCR) > 0 { - fmt.Printf("\nFailed to fetch services for operator(s): %q\n", strings.Join(failedListingCR, ", ")) - } - - return nil -} - -// mixServices returns a structure containing both the services in cluster and defined in devfile -func mixServices(clusterList []unstructured.Unstructured, devfileList map[string]unstructured.Unstructured) serviceItemList { - servicesItems := map[string]*serviceItem{} - for _, item := range clusterList { - if item.GetKind() == "ServiceBinding" { - continue - } - name := strings.Join([]string{item.GetKind(), item.GetName()}, "/") - if _, ok := servicesItems[name]; !ok { - servicesItems[name] = NewServiceItem(name) - } - servicesItems[name].Manifest = item.Object - servicesItems[name].Deployed = true - servicesItems[name].ClusterInfo = &clusterInfo{ - Labels: item.GetLabels(), - CreationTimestamp: item.GetCreationTimestamp().Time, - } - } - - for name, manifest := range devfileList { - if manifest.GetKind() == "ServiceBinding" { - continue - } - if _, ok := servicesItems[name]; !ok { - servicesItems[name] = NewServiceItem(name) - } - servicesItems[name].InDevfile = true - if !servicesItems[name].Deployed { - servicesItems[name].Manifest = manifest.Object - } - } - - return serviceItemList{ - TypeMeta: metav1.TypeMeta{ - Kind: "List", - APIVersion: machineoutput.APIVersion, - }, - Items: getOrderedServices(servicesItems), - } -} - -// getOrderedServices returns the services as a slice, ordered by name -func getOrderedServices(items map[string]*serviceItem) []serviceItem { - orderedNames := getOrderedServicesNames(items) - result := make([]serviceItem, len(items)) - i := 0 - for _, name := range orderedNames { - result[i] = *items[name] - i++ - } - return result -} - -// getOrderedServicesNames returns the names of the services ordered in alphabetic order -func getOrderedServicesNames(items map[string]*serviceItem) []string { - orderedNames := make([]string, len(items)) - i := 0 - for name := range items { - orderedNames[i] = name - i++ - } - sort.Strings(orderedNames) - return orderedNames -} - -// getTabularInfo returns information to be displayed in the output for a specific service and a specific current devfile component -func getTabularInfo(serviceItem *serviceItem, devfileComponent string) (managedByOdo, state, duration string) { - clusterItem := serviceItem.ClusterInfo - inDevfile := serviceItem.InDevfile - if clusterItem != nil { - // service deployed into cluster - var component string - labels := clusterItem.Labels - isManagedByOdo := labels[applabels.ManagedBy] == "odo" - if isManagedByOdo { - component = labels[cmplabels.ComponentLabel] - managedByOdo = fmt.Sprintf("Yes (%s)", component) - } else { - managedByOdo = "No" - } - duration = time.Since(clusterItem.CreationTimestamp).Truncate(time.Second).String() - if inDevfile { - // service deployed into cluster and defined in devfile - state = "Pushed" - } else { - // service deployed into cluster and not defined in devfile - if isManagedByOdo { - if devfileComponent == component { - state = "Deleted locally" - } else { - state = "" - } - } else { - state = "" - } - } - } else { - if inDevfile { - // service not deployed into cluster and defined in devfile - state = "Not pushed" - managedByOdo = fmt.Sprintf("Yes (%s)", devfileComponent) - } else { - // service not deployed into cluster and not defined in devfile - // should not happen - state = "Err!" - managedByOdo = "Err!" - } - } - return -} diff --git a/pkg/odo/cli/service/list_operator_test.go b/pkg/odo/cli/service/list_operator_test.go deleted file mode 100644 index 2ed28417d..000000000 --- a/pkg/odo/cli/service/list_operator_test.go +++ /dev/null @@ -1,277 +0,0 @@ -package service - -import ( - "reflect" - "testing" - "time" - - "github.com/ghodss/yaml" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -func TestGetOrderedServicesNames(t *testing.T) { - tests := []struct { - name string - services map[string]*serviceItem - want []string - }{ - { - name: "Unordered names", - services: map[string]*serviceItem{ - "name3": nil, - "name1": nil, - "name2": nil, - }, - want: []string{"name1", "name2", "name3"}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := getOrderedServicesNames(tt.services) - if !reflect.DeepEqual(result, tt.want) { - t.Errorf("Failed %s: got: %q, want: %q", t.Name(), result, tt.want) - } - }) - } -} - -type getTabularInfoResult struct { - managedByOdo string - state string - durationContent bool -} - -func TestGetTabularInfo(t *testing.T) { - - tests := []struct { - name string - service *serviceItem - devfileComponent string - want getTabularInfoResult - }{ - { - name: "case 1: service in cluster managed by current devfile", - service: &serviceItem{ - ClusterInfo: &clusterInfo{ - Labels: map[string]string{ - "app.kubernetes.io/managed-by": "odo", - "app.kubernetes.io/instance": "component1", - }, - }, - InDevfile: true, - }, - devfileComponent: "component1", - want: getTabularInfoResult{ - managedByOdo: "Yes (component1)", - state: "Pushed", - durationContent: true, - }, - }, - { - name: "case 2: service in cluster not managed by Odo", - service: &serviceItem{ - ClusterInfo: &clusterInfo{ - Labels: map[string]string{}, - }, - InDevfile: false, - }, - devfileComponent: "component1", - want: getTabularInfoResult{ - managedByOdo: "No", - state: "", - durationContent: true, - }, - }, - { - name: "case 3: service in cluster absent from current devfile", - service: &serviceItem{ - ClusterInfo: &clusterInfo{ - Labels: map[string]string{ - "app.kubernetes.io/managed-by": "odo", - "app.kubernetes.io/instance": "component1", - }, - }, - InDevfile: false, - }, - devfileComponent: "component1", - want: getTabularInfoResult{ - managedByOdo: "Yes (component1)", - state: "Deleted locally", - durationContent: true, - }, - }, - { - name: "case 4: service in cluster maaged by another devfile", - service: &serviceItem{ - ClusterInfo: &clusterInfo{ - Labels: map[string]string{ - "app.kubernetes.io/managed-by": "odo", - "app.kubernetes.io/instance": "component2", - }, - }, - InDevfile: false, - }, - devfileComponent: "component1", - want: getTabularInfoResult{ - managedByOdo: "Yes (component2)", - state: "", - durationContent: true, - }, - }, - { - name: "case 5: service defined in devfile, not in cluster", - service: &serviceItem{ - ClusterInfo: nil, - InDevfile: true, - }, - devfileComponent: "component1", - want: getTabularInfoResult{ - managedByOdo: "Yes (component1)", - state: "Not pushed", - durationContent: false, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - managedByOdo, state, duration := getTabularInfo(tt.service, tt.devfileComponent) - if managedByOdo != tt.want.managedByOdo { - t.Errorf("Failed %s: managedByOdo got: %q, want: %q", t.Name(), managedByOdo, tt.want.managedByOdo) - } - if state != tt.want.state { - t.Errorf("Failed %s: state got: %q, want: %q", t.Name(), state, tt.want.state) - } - if len(duration) > 0 != tt.want.durationContent { - t.Errorf("Failed %s: duration content got: %v, want: %v", t.Name(), len(duration) > 0, tt.want.durationContent) - } - }) - } -} - -func TestMixServices(t *testing.T) { - atime, _ := time.Parse(time.RFC3339, "2021-06-02T08:39:20Z00:00") - tests := []struct { - name string - clusterListInlined []string - devfileList []string - want []serviceItem - }{ - { - name: "two in cluster and two in devfile, including one in common", - clusterListInlined: []string{` -kind: kind1 -metadata: - name: name1 - labels: - app.kubernetes.io/managed-by: odo - app.kubernetes.io/instance: component1 - creationTimestamp: 2021-06-02T08:39:20Z00:00 -spec: - field1: value1`, - ` -kind: kind2 -metadata: - name: name2 - labels: - app.kubernetes.io/managed-by: odo - app.kubernetes.io/instance: component2 - creationTimestamp: 2021-06-02T08:39:20Z00:00 -spec: - field2: value2`}, - devfileList: []string{` -kind: kind1 -metadata: - name: name1 -spec: - field1: value1`, ` -kind: kind3 -metadata: - name: name3 -spec: - field3: value3`}, - want: []serviceItem{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - APIVersion: "odo.dev/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "kind1/name1", - }, - ClusterInfo: &clusterInfo{ - Labels: map[string]string{ - "app.kubernetes.io/managed-by": "odo", - "app.kubernetes.io/instance": "component1", - }, - CreationTimestamp: atime, - }, - InDevfile: true, - Deployed: true, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - APIVersion: "odo.dev/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "kind2/name2", - }, - ClusterInfo: &clusterInfo{ - Labels: map[string]string{ - "app.kubernetes.io/managed-by": "odo", - "app.kubernetes.io/instance": "component2", - }, - CreationTimestamp: atime, - }, - InDevfile: false, - Deployed: true, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "Service", - APIVersion: "odo.dev/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "kind3/name3", - }, - ClusterInfo: nil, - InDevfile: true, - Deployed: false, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - usCluster := make([]unstructured.Unstructured, len(tt.clusterListInlined)) - for i, clusterInlined := range tt.clusterListInlined { - err := yaml.Unmarshal([]byte(clusterInlined), &usCluster[i]) - if err != nil { - t.Errorf("Failed to unmarshal spec manifest %q: %u", clusterInlined, err) - } - } - usDevfiles := make(map[string]unstructured.Unstructured) - for _, devfile := range tt.devfileList { - usDevfile := unstructured.Unstructured{} - err := yaml.Unmarshal([]byte(devfile), &usDevfile) - if err != nil { - t.Errorf("Failed to unmarshal spec manifest %q, %u", devfile, err) - } - usDevfiles[usDevfile.GetKind()+"/"+usDevfile.GetName()] = usDevfile - } - result := mixServices(usCluster, usDevfiles) - for i := range result.Items { - if reflect.DeepEqual(result.Items[i].Manifest, unstructured.Unstructured{}) { - t.Errorf("Manifest is empty") - } - // do not check manifest content - result.Items[i].Manifest = unstructured.Unstructured{}.Object - } - if !reflect.DeepEqual(result.Items, tt.want) { - t.Errorf("Failed %s\n\ngot: %+v\n\nwant: %+v\n", t.Name(), result.Items, tt.want) - } - }) - } -} diff --git a/pkg/odo/cli/service/operator_backend.go b/pkg/odo/cli/service/operator_backend.go deleted file mode 100644 index 200e458c1..000000000 --- a/pkg/odo/cli/service/operator_backend.go +++ /dev/null @@ -1,385 +0,0 @@ -/* - This file contains code for various service backends supported by odo. Different backends have different logics for - Complete, Validate and Run functions. These are covered in this file. -*/ -package service - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "strings" - "text/tabwriter" - - "github.com/ghodss/yaml" - "github.com/go-openapi/strfmt" - "github.com/go-openapi/validate" - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/devfile" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - svc "github.com/redhat-developer/odo/pkg/service" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" -) - -var ( - ErrNoMetadataName = errors.New("invalid \"metadata\" in the yaml; provide a valid \"metadata.name\"") -) - -// CompleteServiceCreate contains logic to complete the "odo service create" call for the case of Operator backend -func (b *OperatorBackend) CompleteServiceCreate(o *CreateOptions, args []string) (err error) { - // since interactive mode is not supported for Operators yet, set it to false - o.interactive = false - - // if user has just used "odo service create", simply return - if o.fromFileFlag == "" && len(args) == 0 { - return - } - - // if user wants to create service from file and use a name given on CLI - if o.fromFileFlag != "" { - if len(args) == 1 { - o.ServiceName = args[0] - } - return - } - - // split the name provided on CLI and populate servicetype & customresource - o.ServiceType, b.CustomResource, err = svc.SplitServiceKindName(args[0]) - if err != nil { - return fmt.Errorf("invalid service name, use the format /") - } - - // if two args are given, first is service type and second one is service name - if len(args) == 2 { - o.ServiceName = args[1] - } - - return nil -} - -func (b *OperatorBackend) ValidateServiceCreate(o *CreateOptions) error { - u := unstructured.Unstructured{} - // if the user wants to create service from a file, we check for - // existence of file and validate if the requested operator and CR - // exist on the cluster - if o.fromFileFlag != "" { - if _, err := os.Stat(o.fromFileFlag); err != nil { - return errors.Wrap(err, "unable to find specified file") - } - - // Parse the file to find Operator and CR info - fileContents, err := ioutil.ReadFile(o.fromFileFlag) - if err != nil { - return err - } - - err = yaml.Unmarshal(fileContents, &u.Object) - if err != nil { - return err - } - - gvk := u.GroupVersionKind() - b.group, b.version, b.kind = gvk.Group, gvk.Version, gvk.Kind - - if u.GetName() == "" { - return ErrNoMetadataName - } - - if o.ServiceName != "" && !o.DryRunFlag { - // First check if service with provided name already exists - svcFullName := strings.Join([]string{b.kind, o.ServiceName}, "/") - exists, e := svc.OperatorSvcExists(o.KClient, svcFullName) - if e != nil { - return e - } - if exists { - return fmt.Errorf("service %q already exists; please provide a different name or delete the existing service first", svcFullName) - } - u.SetName(o.ServiceName) - } else { - o.ServiceName = u.GetName() - } - - csvPtr, err := o.KClient.GetCSVWithCR(u.GetKind()) - if err != nil { - // error only occurs when OperatorHub is not installed. - // k8s doesn't have it installed by default but OCP does - return err - } - csv := *csvPtr - - // CRD is valid. We can use it further to create a service from it. - b.CustomResourceDefinition = u.Object - - // Validate spec - hasCR, cr := o.KClient.CheckCustomResourceInCSV(b.kind, &csv) - if !hasCR { - return fmt.Errorf("the %q resource doesn't exist in specified %q operator", b.CustomResource, b.group) - } - - crd, err := o.KClient.GetCRDSpec(cr, b.group, b.kind) - if err != nil { - return err - } - - err = validate.AgainstSchema(crd, u.Object["spec"], strfmt.Default) - if err != nil { - return err - } - - } else if b.CustomResource != "" { - // make sure that CSV of the specified ServiceType exists - csv, err := o.KClient.GetClusterServiceVersion(o.ServiceType) - if err != nil { - // error only occurs when OperatorHub is not installed. - // k8s doesn't have it installed by default but OCP does - return err - } - b.group, b.version, b.resource, err = svc.GetGVRFromOperator(csv, b.CustomResource) - if err != nil { - return err - } - - // if the service name is blank then we set it to custom resource name - if o.ServiceName == "" { - o.ServiceName = strings.ToLower(b.CustomResource) - } - - hasCR, cr := o.KClient.CheckCustomResourceInCSV(b.CustomResource, &csv) - if !hasCR { - return fmt.Errorf("the %q resource doesn't exist in specified %q operator", b.CustomResource, b.group) - } - - crd, err := o.KClient.GetCRDSpec(cr, b.group, b.CustomResource) - if err != nil { - return err - } - - if len(o.parametersFlag) != 0 { - builtCRD, e := svc.BuildCRDFromParams(o.ParametersMap, crd, b.group, b.version, b.CustomResource) - if e != nil { - return e - } - - u.Object = builtCRD - } else { - almExample, e := svc.GetAlmExample(csv, b.CustomResource, o.ServiceType) - if e != nil { - return e - } - - u.Object = almExample - } - - if o.ServiceName != "" && !o.DryRunFlag { - // First check if service with provided name already exists - svcFullName := strings.Join([]string{b.CustomResource, o.ServiceName}, "/") - exists, e := svc.OperatorSvcExists(o.KClient, svcFullName) - if e != nil { - return e - } - if exists { - return fmt.Errorf("service %q already exists; please provide a different name or delete the existing service first", svcFullName) - } - } - - u.SetName(o.ServiceName) - if u.GetName() == "" { - return ErrNoMetadataName - } - - // CRD is valid. We can use it further to create a service from it. - b.CustomResourceDefinition = u.Object - - if o.ServiceName == "" { - o.ServiceName = u.GetName() - } - - // Validate spec - err = validate.AgainstSchema(crd, u.Object["spec"], strfmt.Default) - if err != nil { - return err - } - - } else { - // This block is executed only when user has neither provided a - // file nor a valid `odo service create ` to start - // the service from an Operator. So we raise an error because the - // correct way is to execute: - // `odo service create /` - - return fmt.Errorf("please use a valid command to start an Operator backed service; desired format: %q", "odo service create /") - } - - return nil -} - -func (b *OperatorBackend) RunServiceCreate(o *CreateOptions) (err error) { - s := &log.Status{} - - // if cluster has resources of type CSV and o.CustomResource is not - // empty, we're expected to create an Operator backed service - if o.DryRunFlag { - // if it's dry run, only print the alm-example (o.CustomResourceDefinition) and exit - jsonCR, err := json.MarshalIndent(b.CustomResourceDefinition, "", " ") - if err != nil { - return err - } - - // convert json to yaml - yamlCR, err := yaml.JSONToYAML(jsonCR) - if err != nil { - return err - } - - log.Info(string(yamlCR)) - - return nil - } else { - - if o.inlinedFlag { - crdYaml, err := yaml.Marshal(b.CustomResourceDefinition) - if err != nil { - return err - } - - err = devfile.AddKubernetesComponentToDevfile(string(crdYaml), o.ServiceName, o.EnvSpecificInfo.GetDevfileObj()) - if err != nil { - return err - } - - } else { - crdYaml, err := yaml.Marshal(b.CustomResourceDefinition) - if err != nil { - return err - } - - err = devfile.AddKubernetesComponent(string(crdYaml), o.ServiceName, o.contextFlag, o.EnvSpecificInfo.GetDevfileObj()) - if err != nil { - return err - } - } - - if log.IsJSON() { - svcFullName := strings.Join([]string{b.CustomResource, o.ServiceName}, "/") - svc := NewServiceItem(svcFullName) - svc.Manifest = b.CustomResourceDefinition - svc.InDevfile = true - machineoutput.OutputSuccess(svc) - } - } - s.End(true) - return -} - -// ServiceDefined returns true if the service is defined in the devfile -func (b *OperatorBackend) ServiceDefined(ctx *genericclioptions.Context, name string) (bool, error) { - _, instanceName, err := svc.SplitServiceKindName(name) - if err != nil { - return false, err - } - return devfile.IsComponentDefined(instanceName, ctx.EnvSpecificInfo.GetDevfileObj()) -} - -func (b *OperatorBackend) DeleteService(o *DeleteOptions, name string, application string) error { - // "name" is of the form CR-Name/Instance-Name so we split it - _, instanceName, err := svc.SplitServiceKindName(name) - if err != nil { - return err - } - - err = devfile.DeleteKubernetesComponentFromDevfile(instanceName, o.EnvSpecificInfo.GetDevfileObj(), o.contextFlag) - if err != nil { - return errors.Wrap(err, "failed to delete service from the devfile") - } - - return nil -} - -func (b *OperatorBackend) DescribeService(o *DescribeOptions, serviceName, app string) error { - - clusterList, _, err := svc.ListOperatorServices(o.KClient) - if err != nil { - return err - } - var clusterFound *unstructured.Unstructured - for i, clusterInstance := range clusterList { - fullName := strings.Join([]string{clusterInstance.GetKind(), clusterInstance.GetName()}, "/") - if fullName == serviceName { - clusterFound = &clusterList[i] - break - } - } - - devfileList, err := svc.ListDevfileServices(o.KClient, o.EnvSpecificInfo.GetDevfileObj(), o.contextFlag) - if err != nil { - return err - } - devfileService, inDevfile := devfileList[serviceName] - - item := NewServiceItem(serviceName) - item.InDevfile = inDevfile - item.Deployed = clusterFound != nil - if item.Deployed { - item.Manifest = clusterFound.Object - } else if item.InDevfile { - item.Manifest = devfileService.Object - } - - if log.IsJSON() { - machineoutput.OutputSuccess(item) - return nil - } - - return PrintHumanReadableOutput(item) -} - -// PrintHumanReadableOutput outputs the description of a service in a human readable format -func PrintHumanReadableOutput(item *serviceItem) error { - log.Describef("Version: ", "%s", item.Manifest["apiVersion"]) - log.Describef("Kind: ", "%s", item.Manifest["kind"]) - metadata, ok := item.Manifest["metadata"].(map[string]interface{}) - if !ok { - return errors.New("unable to get name from manifest") - } - log.Describef("Name: ", "%s", metadata["name"]) - spec, ok := item.Manifest["spec"].(map[string]interface{}) - if !ok { - return errors.New("unable to get specifications from manifest") - } - - var tab bytes.Buffer - - wr := tabwriter.NewWriter(&tab, 5, 2, 3, ' ', tabwriter.TabIndent) - fmt.Fprint(wr, "NAME", "\t", "VALUE", "\n") - displayParameters(wr, spec, "") - wr.Flush() - - log.Describef("Parameters:\n", tab.String()) - - return nil -} - -// displayParameters adds lines describing fields of a given map -func displayParameters(wr *tabwriter.Writer, spec map[string]interface{}, prefix string) { - keys := make([]string, len(spec)) - i := 0 - for key := range spec { - keys[i] = key - i++ - } - - for _, k := range keys { - v := spec[k] - switch val := v.(type) { - case map[string]interface{}: - displayParameters(wr, val, prefix+k+".") - default: - fmt.Fprintf(wr, "%s%s\t%v\n", prefix, k, val) - } - } -} diff --git a/pkg/odo/cli/service/service.go b/pkg/odo/cli/service/service.go deleted file mode 100644 index 650fb1b4c..000000000 --- a/pkg/odo/cli/service/service.go +++ /dev/null @@ -1,54 +0,0 @@ -package service - -import ( - "fmt" - - appCmd "github.com/redhat-developer/odo/pkg/odo/cli/application" - projectCmd "github.com/redhat-developer/odo/pkg/odo/cli/project" - - "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -// RecommendedCommandName is the recommended service command name -const RecommendedCommandName = "service" - -var serviceLongDesc = ktemplates.LongDesc(`Perform service related operations`) - -// NewCmdService implements the odo service command -func NewCmdService(name, fullName string) *cobra.Command { - serviceCreateCmd := NewCmdServiceCreate(createRecommendedCommandName, util.GetFullName(fullName, createRecommendedCommandName)) - serviceListCmd := NewCmdServiceList(listRecommendedCommandName, util.GetFullName(fullName, listRecommendedCommandName)) - serviceDeleteCmd := NewCmdServiceDelete(deleteRecommendedCommandName, util.GetFullName(fullName, deleteRecommendedCommandName)) - serviceDescribeCmd := NewCmdServiceDescribe(describeRecommendedCommandName, util.GetFullName(fullName, describeRecommendedCommandName)) - serviceCmd := &cobra.Command{ - Use: name, - Short: "Perform service related operations", - Long: serviceLongDesc, - Example: fmt.Sprintf("%s\n\n%s\n\n%s\n\n%s", - serviceCreateCmd.Example, - serviceDeleteCmd.Example, - serviceDescribeCmd.Example, - serviceListCmd.Example), - Args: cobra.RangeArgs(1, 3), - } - // Add a defined annotation in order to appear in the help menu - serviceCmd.Annotations = map[string]string{"command": "main"} - serviceCmd.SetUsageTemplate(util.CmdUsageTemplate) - serviceCmd.AddCommand(serviceCreateCmd, serviceDeleteCmd, serviceDescribeCmd, serviceListCmd) - - //Adding `--project` flag - projectCmd.AddProjectFlag(serviceCreateCmd) - projectCmd.AddProjectFlag(serviceDeleteCmd) - projectCmd.AddProjectFlag(serviceDescribeCmd) - projectCmd.AddProjectFlag(serviceListCmd) - - //Adding `--application` flag - appCmd.AddApplicationFlag(serviceCreateCmd) - appCmd.AddApplicationFlag(serviceDeleteCmd) - appCmd.AddApplicationFlag(serviceDescribeCmd) - appCmd.AddApplicationFlag(serviceListCmd) - - return serviceCmd -} diff --git a/pkg/odo/cli/service/types.go b/pkg/odo/cli/service/types.go deleted file mode 100644 index fb99439e9..000000000 --- a/pkg/odo/cli/service/types.go +++ /dev/null @@ -1,21 +0,0 @@ -package service - -//OperatorBackend implements the interface ServiceProviderBackend and contains methods that help create a service from Operators -type OperatorBackend struct { - // Custom Resrouce to create service from - CustomResource string - // Custom Resrouce's Definition fetched from alm-examples - CustomResourceDefinition map[string]interface{} - // Group of the GVR - group string - // Version of the GVR - version string - // Resource of the GVR - resource string - // Kind of GVK - kind string -} - -func NewOperatorBackend() *OperatorBackend { - return &OperatorBackend{} -} diff --git a/pkg/odo/cli/service/utils.go b/pkg/odo/cli/service/utils.go deleted file mode 100644 index 0bf4b4ba3..000000000 --- a/pkg/odo/cli/service/utils.go +++ /dev/null @@ -1,22 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/devfile/location" - "github.com/redhat-developer/odo/pkg/odo/cli/component" - "github.com/redhat-developer/odo/pkg/util" -) - -// validDevfileDirectory returns an error if the "odo service" command is executed from a directory not containing devfile.yaml -func validDevfileDirectory(componentContext string) error { - if componentContext == "" { - componentContext = component.LocalDirectoryDefaultLocation - } - devfilePath := location.DevfileLocation(componentContext) - if !util.CheckPathExists(devfilePath) { - return fmt.Errorf("service can be created/deleted from a valid component directory only\n"+ - "refer %q for more information", "odo service create -h") - } - return nil -} diff --git a/pkg/odo/cli/storage/create.go b/pkg/odo/cli/storage/create.go deleted file mode 100644 index f692f561e..000000000 --- a/pkg/odo/cli/storage/create.go +++ /dev/null @@ -1,133 +0,0 @@ -package storage - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/localConfigProvider" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - "github.com/redhat-developer/odo/pkg/storage" - "github.com/redhat-developer/odo/pkg/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const createRecommendedCommandName = "create" - -var ( - storageCreateShortDesc = `Create storage and mount to a component` - storageCreateLongDesc = ktemplates.LongDesc(`Create storage and mount to a component`) - storageCreateExample = ktemplates.Examples(` - # Create storage of size 1Gb to a component - %[1]s mystorage --path=/opt/app-root/src/storage/ --size=1Gi - - # Create storage with ephemeral volume of size 2Gi to a component - %[1]s mystorage --path=/opt/app-root/src/storage/ --size=2Gi --ephemeral - `) -) - -type CreateOptions struct { - // Context - *genericclioptions.Context - - // Parameters - storageName string - - // Flags - sizeFlag string - pathFlag string - contextFlag string - containerFlag string - ephemeralFlag bool - - storage localConfigProvider.LocalStorage -} - -// NewStorageCreateOptions creates a new CreateOptions instance -func NewStorageCreateOptions() *CreateOptions { - return &CreateOptions{} -} - -// Complete completes CreateOptions after they've been created -func (o *CreateOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag)) - if err != nil { - return err - } - - if len(args) != 0 { - o.storageName = args[0] - } else { - o.storageName = fmt.Sprintf("%s-%s", o.Context.LocalConfigProvider.GetName(), util.GenerateRandomString(4)) - } - - var eph *bool - if o.ephemeralFlag { - eph = &o.ephemeralFlag - } - o.storage = localConfigProvider.LocalStorage{ - Name: o.storageName, - Size: o.sizeFlag, - Ephemeral: eph, - Path: o.pathFlag, - Container: o.containerFlag, - } - - o.Context.LocalConfigProvider.CompleteStorage(&o.storage) - - return nil -} - -// Validate validates the CreateOptions based on completed values -func (o *CreateOptions) Validate() (err error) { - // validate the storage - return o.LocalConfigProvider.ValidateStorage(o.storage) -} - -// Run contains the logic for the odo storage create command -func (o *CreateOptions) Run() (err error) { - err = o.Context.LocalConfigProvider.CreateStorage(o.storage) - if err != nil { - return err - } - - if log.IsJSON() { - storageResultMachineReadable := storage.NewStorage(o.storage.Name, o.storage.Size, o.storage.Path, nil) - machineoutput.OutputSuccess(storageResultMachineReadable) - } else { - log.Successf("Added storage %v to %v", o.storageName, o.Context.LocalConfigProvider.GetName()) - - log.Italic("\nPlease use `odo push` command to make the storage accessible to the component") - } - return nil -} - -// NewCmdStorageCreate implements the odo storage create command. -func NewCmdStorageCreate(name, fullName string) *cobra.Command { - o := NewStorageCreateOptions() - storageCreateCmd := &cobra.Command{ - Use: name, - Short: storageCreateShortDesc, - Long: storageCreateLongDesc, - Example: fmt.Sprintf(storageCreateExample, fullName), - Args: cobra.MaximumNArgs(1), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - storageCreateCmd.Flags().StringVar(&o.sizeFlag, "size", "", "Size of storage to add") - storageCreateCmd.Flags().StringVar(&o.pathFlag, "path", "", "Path to mount the storage on") - storageCreateCmd.Flags().StringVar(&o.containerFlag, "container", "", "Name of container to attach the storage to in devfile") - storageCreateCmd.Flags().BoolVar(&o.ephemeralFlag, "ephemeral", false, "Set volume as ephemeral") - - odoutil.AddContextFlag(storageCreateCmd, &o.contextFlag) - completion.RegisterCommandFlagHandler(storageCreateCmd, "context", completion.FileCompletionHandler) - - return storageCreateCmd -} diff --git a/pkg/odo/cli/storage/delete.go b/pkg/odo/cli/storage/delete.go deleted file mode 100644 index eb99a6478..000000000 --- a/pkg/odo/cli/storage/delete.go +++ /dev/null @@ -1,122 +0,0 @@ -package storage - -import ( - "fmt" - - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cli/ui" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - "github.com/redhat-developer/odo/pkg/storage" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -const deleteRecommendedCommandName = "delete" - -var ( - storageDeleteShortDesc = `Delete storage from component` - storageDeleteLongDesc = ktemplates.LongDesc(`Delete storage from component`) - storageDeleteExample = ktemplates.Examples(` - # Delete storage mystorage from the currently active component - %[1]s mystorage -`) -) - -type DeleteOptions struct { - // Context - *genericclioptions.Context - - // Parameters - storageName string - - // Flags - forceFlag bool - contextFlag string -} - -// NewStorageDeleteOptions creates a new DeleteOptions instance -func NewStorageDeleteOptions() *DeleteOptions { - return &DeleteOptions{} -} - -// Complete completes DeleteOptions after they've been created -func (o *DeleteOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag)) - if err != nil { - return err - } - - o.storageName = args[0] - return nil -} - -// Validate validates the DeleteOptions based on completed values -func (o *DeleteOptions) Validate() (err error) { - gotStorage, err := o.LocalConfigProvider.GetStorage(o.storageName) - if err != nil { - return err - } - if gotStorage == nil { - return fmt.Errorf("the storage %v does not exists in the application %v, cause %v", o.storageName, o.GetApplication(), err) - } - - return nil -} - -// Run contains the logic for the odo storage delete command -func (o *DeleteOptions) Run() (err error) { - mPath, err := o.Context.LocalConfigProvider.GetStorageMountPath(o.storageName) - if err != nil { - return err - } - - deleteMsg := fmt.Sprintf("Are you sure you want to delete the storage %v mounted to %v in %v component", o.storageName, mPath, o.Context.LocalConfigProvider.GetName()) - - if log.IsJSON() || o.forceFlag || ui.Proceed(deleteMsg) { - err := o.Context.LocalConfigProvider.DeleteStorage(o.storageName) - if err != nil { - return fmt.Errorf("failed to delete storage, cause %v", err) - } - - successMessage := fmt.Sprintf("Deleted storage %v from %v", o.storageName, o.Context.LocalConfigProvider.GetName()) - - log.Infof(successMessage) - log.Italic("\nPlease use `odo push` command to delete the storage from the cluster") - - if log.IsJSON() { - machineoutput.SuccessStatus(storage.StorageKind, o.storageName, successMessage) - } - } else { - return fmt.Errorf("aborting deletion of storage: %v", o.storageName) - } - - return nil -} - -// NewCmdStorageDelete implements the odo storage delete command. -func NewCmdStorageDelete(name, fullName string) *cobra.Command { - o := NewStorageDeleteOptions() - storageDeleteCmd := &cobra.Command{ - Use: name, - Short: storageDeleteShortDesc, - Long: storageDeleteLongDesc, - Example: fmt.Sprintf(storageDeleteExample, fullName), - Args: cobra.ExactArgs(1), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - storageDeleteCmd.Flags().BoolVarP(&o.forceFlag, "force", "f", false, "Delete storage without prompting") - completion.RegisterCommandHandler(storageDeleteCmd, completion.StorageDeleteCompletionHandler) - - odoutil.AddContextFlag(storageDeleteCmd, &o.contextFlag) - completion.RegisterCommandFlagHandler(storageDeleteCmd, "context", completion.FileCompletionHandler) - - return storageDeleteCmd -} diff --git a/pkg/odo/cli/storage/list.go b/pkg/odo/cli/storage/list.go deleted file mode 100644 index bc55424e5..000000000 --- a/pkg/odo/cli/storage/list.go +++ /dev/null @@ -1,216 +0,0 @@ -package storage - -import ( - "fmt" - "os" - "text/tabwriter" - - "github.com/redhat-developer/odo/pkg/localConfigProvider" - "github.com/redhat-developer/odo/pkg/log" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/odo/cmdline" - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/redhat-developer/odo/pkg/odo/util/completion" - "github.com/redhat-developer/odo/pkg/storage" - - "github.com/redhat-developer/odo/pkg/odo/genericclioptions" - ktemplates "k8s.io/kubectl/pkg/util/templates" - - "github.com/spf13/cobra" -) - -const listRecommendedCommandName = "list" - -var ( - storageListShortDesc = `List storage attached to a component` - storageListLongDesc = ktemplates.LongDesc(`List storage attached to a component`) - storageListExample = ktemplates.Examples(` - # List all storage attached to the current component - %[1]s - `) -) - -type ListOptions struct { - // Context - *genericclioptions.Context - - // Flags - contextFlag string - - // Backend - client storage.Client -} - -// NewStorageListOptions creates a new ListOptions instance -func NewStorageListOptions() *ListOptions { - return &ListOptions{} -} - -// Complete completes ListOptions after they've been created -func (o *ListOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) { - o.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline).NeedDevfile(o.contextFlag)) - if err != nil { - return err - } - - o.client = storage.NewClient(storage.ClientOptions{ - LocalConfigProvider: o.Context.LocalConfigProvider, - Client: o.Context.KClient, - }) - - return nil -} - -// Validate validates the ListOptions based on completed values -func (o *ListOptions) Validate() (err error) { - return nil -} - -func (o *ListOptions) Run() (err error) { - storageList, err := o.client.List() - if err != nil { - return err - } - - if log.IsJSON() { - machineoutput.OutputSuccess(storageList) - } else { - localContainers, err := o.Context.LocalConfigProvider.GetContainers() - if err != nil { - return err - } - if isContainerDisplay(storageList, localContainers) { - printStorageWithContainer(storageList, o.Context.LocalConfigProvider.GetName()) - } else { - printStorage(storageList, o.Context.LocalConfigProvider.GetName()) - } - } - - return nil -} - -// printStorage prints the given storageList -func printStorage(storageList storage.StorageList, compName string) { - - if len(storageList.Items) > 0 { - - tabWriterMounted := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent) - - storageMap := make(map[string]bool) - - // create headers of mounted storage table - fmt.Fprintln(tabWriterMounted, "NAME", "\t", "SIZE", "\t", "PATH", "\t", "STATE") - // iterating over all mounted storage and put in the mount storage table - for _, mStorage := range storageList.Items { - _, ok := storageMap[mStorage.Name] - if !ok { - storageMap[mStorage.Name] = true - fmt.Fprintln(tabWriterMounted, mStorage.Name, "\t", mStorage.Spec.Size, "\t", mStorage.Spec.Path, "\t", mStorage.Status) - } - } - - // print all mounted storage of the given component - log.Infof("The component '%v' has the following storage attached:", compName) - tabWriterMounted.Flush() - } else { - log.Infof("The component '%v' has no storage attached", compName) - } - - fmt.Println("") -} - -// printStorageWithContainer prints the given storageList with the corresponding container name -func printStorageWithContainer(storageList storage.StorageList, compName string) { - - if len(storageList.Items) > 0 { - - tabWriterMounted := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent) - - // create headers of mounted storage table - fmt.Fprintln(tabWriterMounted, "NAME", "\t", "SIZE", "\t", "PATH", "\t", "CONTAINER", "\t", "STATE") - // iterating over all mounted storage and put in the mount storage table - for _, mStorage := range storageList.Items { - fmt.Fprintln(tabWriterMounted, mStorage.Name, "\t", mStorage.Spec.Size, "\t", mStorage.Spec.Path, "\t", mStorage.Spec.ContainerName, "\t", mStorage.Status) - } - - // print all mounted storage of the given component - log.Infof("The component '%v' has the following storage attached:", compName) - tabWriterMounted.Flush() - } else { - log.Infof("The component '%v' has no storage attached", compName) - } - - fmt.Println("") -} - -// isContainerDisplay checks whether the container name should be included in the output -func isContainerDisplay(storageList storage.StorageList, components []localConfigProvider.LocalContainer) bool { - - // get all the container names - componentsMap := make(map[string]bool) - for _, comp := range components { - componentsMap[comp.Name] = true - } - - storageCompMap := make(map[string][]string) - pathMap := make(map[string]string) - storageMap := make(map[string]storage.StorageStatus) - - for _, storageItem := range storageList.Items { - if pathMap[storageItem.Name] == "" { - pathMap[storageItem.Name] = storageItem.Spec.Path - } - if storageMap[storageItem.Name] == "" { - storageMap[storageItem.Name] = storageItem.Status - } - - // check if the storage is mounted on the same path in all the containers - if pathMap[storageItem.Name] != storageItem.Spec.Path { - return true - } - - // check if the storage is in the same state for all the containers - if storageMap[storageItem.Name] != storageItem.Status { - return true - } - - // check if the storage is mounted on a valid devfile container - // this situation can arrive when a container is removed from the devfile - // but the state is not pushed thus it exists on the cluster - _, ok := componentsMap[storageItem.Spec.ContainerName] - if !ok { - return true - } - storageCompMap[storageItem.Name] = append(storageCompMap[storageItem.Name], storageItem.Spec.ContainerName) - } - - for _, containerNames := range storageCompMap { - // check if the storage is mounted on all the devfile containers - if len(containerNames) != len(componentsMap) { - return true - } - } - - return false -} - -// NewCmdStorageList implements the odo storage list command. -func NewCmdStorageList(name, fullName string) *cobra.Command { - o := NewStorageListOptions() - storageListCmd := &cobra.Command{ - Use: name, - Short: storageListShortDesc, - Long: storageListLongDesc, - Example: fmt.Sprintf(storageListExample, fullName), - Args: cobra.MaximumNArgs(1), - Annotations: map[string]string{"machineoutput": "json"}, - Run: func(cmd *cobra.Command, args []string) { - genericclioptions.GenericRun(o, cmd, args) - }, - } - - odoutil.AddContextFlag(storageListCmd, &o.contextFlag) - completion.RegisterCommandFlagHandler(storageListCmd, "context", completion.FileCompletionHandler) - - return storageListCmd -} diff --git a/pkg/odo/cli/storage/list_test.go b/pkg/odo/cli/storage/list_test.go deleted file mode 100644 index ffc9f03de..000000000 --- a/pkg/odo/cli/storage/list_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package storage - -import ( - "testing" - - "github.com/redhat-developer/odo/pkg/localConfigProvider" - "github.com/redhat-developer/odo/pkg/storage" -) - -func Test_isContainerDisplay(t *testing.T) { - generateStorage := func(storage storage.Storage, status storage.StorageStatus, containerName string) storage.Storage { - storage.Status = status - storage.Spec.ContainerName = containerName - return storage - } - - type args struct { - storageList storage.StorageList - obj []localConfigProvider.LocalContainer - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "case 1: storage is mounted on all the containers on the same path", - args: args{ - storageList: storage.StorageList{ - Items: []storage.Storage{ - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-0"), - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-1"), - }, - }, - obj: []localConfigProvider.LocalContainer{ - { - Name: "container-0", - }, - { - Name: "container-1", - }, - }, - }, - want: false, - }, - { - name: "case 2: storage is mounted on different paths", - args: args{ - storageList: storage.StorageList{ - Items: []storage.Storage{ - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-0"), - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/path", nil), storage.StateTypePushed, "container-1"), - }, - }, - obj: []localConfigProvider.LocalContainer{ - { - Name: "container-0", - }, - { - Name: "container-1", - }, - }, - }, - want: true, - }, - { - name: "case 3: storage is mounted to the same path on all the containers but states are different", - args: args{ - storageList: storage.StorageList{ - Items: []storage.Storage{ - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-0"), - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypeNotPushed, "container-1"), - }, - }, - obj: []localConfigProvider.LocalContainer{ - { - Name: "container-0", - }, - { - Name: "container-1", - }, - }, - }, - want: true, - }, - { - name: "case 4: storage is not mounted on all the containers", - args: args{ - storageList: storage.StorageList{ - Items: []storage.Storage{ - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-0"), - }, - }, - obj: []localConfigProvider.LocalContainer{ - { - Name: "container-0", - }, - { - Name: "container-1", - }, - }, - }, - want: true, - }, - { - name: "case 5: storage is mounted on a container deleted locally from the devfile", - args: args{ - storageList: storage.StorageList{ - Items: []storage.Storage{ - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-0"), - generateStorage(storage.NewStorage("pvc-1", "1Gi", "/data", nil), storage.StateTypePushed, "container-1"), - }, - }, - obj: []localConfigProvider.LocalContainer{ - { - Name: "container-0", - }, - }, - }, - want: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := isContainerDisplay(tt.args.storageList, tt.args.obj); got != tt.want { - t.Errorf("isContainerDisplay() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/odo/cli/storage/storage.go b/pkg/odo/cli/storage/storage.go deleted file mode 100644 index 8afcc0d56..000000000 --- a/pkg/odo/cli/storage/storage.go +++ /dev/null @@ -1,44 +0,0 @@ -package storage - -import ( - "fmt" - - odoutil "github.com/redhat-developer/odo/pkg/odo/util" - "github.com/spf13/cobra" - ktemplates "k8s.io/kubectl/pkg/util/templates" -) - -// RecommendedCommandName is the recommended command name -const RecommendedCommandName = "storage" - -var ( - storageShortDesc = `Perform storage operations` - storageLongDesc = ktemplates.LongDesc(`Perform storage operations`) -) - -// NewCmdStorage implements the odo storage command -func NewCmdStorage(name, fullName string) *cobra.Command { - storageCreateCmd := NewCmdStorageCreate(createRecommendedCommandName, odoutil.GetFullName(fullName, createRecommendedCommandName)) - storageDeleteCmd := NewCmdStorageDelete(deleteRecommendedCommandName, odoutil.GetFullName(fullName, deleteRecommendedCommandName)) - storageListCmd := NewCmdStorageList(listRecommendedCommandName, odoutil.GetFullName(fullName, listRecommendedCommandName)) - - var storageCmd = &cobra.Command{ - Use: name, - Short: storageShortDesc, - Long: storageLongDesc, - Example: fmt.Sprintf("%s\n\n%s\n\n%s", - storageCreateCmd.Example, - storageDeleteCmd.Example, - storageListCmd.Example), - } - - storageCmd.AddCommand(storageCreateCmd) - storageCmd.AddCommand(storageDeleteCmd) - storageCmd.AddCommand(storageListCmd) - - // Add a defined annotation in order to appear in the help menu - storageCmd.Annotations = map[string]string{"command": "main"} - storageCmd.SetUsageTemplate(odoutil.CmdUsageTemplate) - - return storageCmd -} diff --git a/pkg/notify/notify.go b/pkg/odo/cli/version/notify.go similarity index 90% rename from pkg/notify/notify.go rename to pkg/odo/cli/version/notify.go index 40a26ba58..b0092a6bb 100644 --- a/pkg/notify/notify.go +++ b/pkg/odo/cli/version/notify.go @@ -1,4 +1,4 @@ -package notify +package version import ( "strings" @@ -30,9 +30,9 @@ func getLatestReleaseTag() (string, error) { return strings.TrimSuffix(string(body), "\n"), nil } -// CheckLatestReleaseTag returns the latest release tag if a newer latest +// checkLatestReleaseTag returns the latest release tag if a newer latest // release is available, else returns an empty string -func CheckLatestReleaseTag(currentVersion string) (string, error) { +func checkLatestReleaseTag(currentVersion string) (string, error) { currentSemver, err := semver.Make(strings.TrimPrefix(currentVersion, "v")) if err != nil { return "", errors.Wrapf(err, "unable to make semver from the current version: %v", currentVersion) diff --git a/pkg/notify/notify_test.go b/pkg/odo/cli/version/notify_test.go similarity index 97% rename from pkg/notify/notify_test.go rename to pkg/odo/cli/version/notify_test.go index a912d49ab..d51512ef7 100644 --- a/pkg/notify/notify_test.go +++ b/pkg/odo/cli/version/notify_test.go @@ -1,4 +1,4 @@ -package notify +package version /* import ( diff --git a/pkg/odo/cli/version/version.go b/pkg/odo/cli/version/version.go index 9a33533e4..a99f3824f 100644 --- a/pkg/odo/cli/version/version.go +++ b/pkg/odo/cli/version/version.go @@ -13,7 +13,6 @@ import ( "github.com/redhat-developer/odo/pkg/preference" odoversion "github.com/redhat-developer/odo/pkg/version" - "github.com/redhat-developer/odo/pkg/notify" "github.com/redhat-developer/odo/pkg/odo/util" "github.com/spf13/cobra" "k8s.io/klog" @@ -136,7 +135,7 @@ func NewCmdVersion(name, fullName string) *cobra.Command { // GetLatestReleaseInfo Gets information about the latest release func GetLatestReleaseInfo(info chan<- string) { - newTag, err := notify.CheckLatestReleaseTag(odoversion.VERSION) + newTag, err := checkLatestReleaseTag(odoversion.VERSION) if err != nil { // The error is intentionally not being handled because we don't want // to stop the execution of the program because of this failure diff --git a/pkg/odo/util/completion/completionhandlers.go b/pkg/odo/util/completion/completionhandlers.go index 043660283..7ba69bdd2 100644 --- a/pkg/odo/util/completion/completionhandlers.go +++ b/pkg/odo/util/completion/completionhandlers.go @@ -8,7 +8,6 @@ import ( "github.com/redhat-developer/odo/pkg/testingutil/filesystem" "github.com/posener/complete" - "github.com/redhat-developer/odo/pkg/application" "github.com/redhat-developer/odo/pkg/catalog" "github.com/redhat-developer/odo/pkg/component" "github.com/redhat-developer/odo/pkg/odo/genericclioptions" @@ -16,25 +15,6 @@ import ( "github.com/spf13/cobra" ) -// AppCompletionHandler provides completion for the app commands -var AppCompletionHandler = func(cmd *cobra.Command, args parsedArgs, context *genericclioptions.Context) (completions []string) { - completions = make([]string, 0) - - appClient := application.NewClient(context.KClient) - applications, err := appClient.List() - if err != nil { - return completions - } - - for _, app := range applications { - if args.commands[app] { - return nil - } - completions = append(completions, app) - } - return -} - // FileCompletionHandler provides suggestions for files and directories var FileCompletionHandler = func(cmd *cobra.Command, args parsedArgs, context *genericclioptions.Context) (completions []string) { completions = append(completions, complete.PredictFiles("*").Predict(args.original)...) diff --git a/pkg/url/kubernetes.go b/pkg/url/kubernetes.go index 5205d02c4..e7eee8ae1 100644 --- a/pkg/url/kubernetes.go +++ b/pkg/url/kubernetes.go @@ -4,7 +4,7 @@ import ( "fmt" "sort" - "github.com/redhat-developer/odo/pkg/unions" + "github.com/redhat-developer/odo/pkg/kclient/unions" "github.com/devfile/library/pkg/devfile/generator" routev1 "github.com/openshift/api/route/v1" diff --git a/pkg/url/kubernetes_test.go b/pkg/url/kubernetes_test.go index 6e61fcc5d..e84d1fc54 100644 --- a/pkg/url/kubernetes_test.go +++ b/pkg/url/kubernetes_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/redhat-developer/odo/pkg/unions" + "github.com/redhat-developer/odo/pkg/kclient/unions" networkingv1 "k8s.io/api/networking/v1" "github.com/devfile/library/pkg/devfile/generator" diff --git a/pkg/url/status_test.go b/pkg/url/status_test.go index fe937716c..87a0080b2 100644 --- a/pkg/url/status_test.go +++ b/pkg/url/status_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/redhat-developer/odo/pkg/unions" + "github.com/redhat-developer/odo/pkg/kclient/unions" "github.com/golang/mock/gomock" routev1 "github.com/openshift/api/route/v1" diff --git a/pkg/url/types.go b/pkg/url/types.go index 03a223bc4..4a476998d 100644 --- a/pkg/url/types.go +++ b/pkg/url/types.go @@ -5,9 +5,9 @@ import ( "reflect" routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/odo/pkg/kclient/unions" "github.com/redhat-developer/odo/pkg/localConfigProvider" "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/pkg/unions" urlLabels "github.com/redhat-developer/odo/pkg/url/labels" iextensionsv1 "k8s.io/api/extensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/scripts/minikube-minishift-all-tests.sh b/scripts/minikube-minishift-all-tests.sh index 904cd3e2c..3bf4a294c 100755 --- a/scripts/minikube-minishift-all-tests.sh +++ b/scripts/minikube-minishift-all-tests.sh @@ -13,7 +13,6 @@ SCRIPT_IDENTITY=${SCRIPT_IDENTITY:-"def-id"} # Integration tests shout "| Running integration Tests on MiniKube" -make test-operator-hub make test-cmd-project make test-integration-devfile diff --git a/scripts/mockgen.sh b/scripts/mockgen.sh index 68721f9a4..55cafc8a5 100755 --- a/scripts/mockgen.sh +++ b/scripts/mockgen.sh @@ -27,10 +27,6 @@ mockgen -source=pkg/odo/cmdline/cmdline.go \ -package cmdline \ -destination pkg/odo/cmdline/mock.go -mockgen -source=pkg/application/application.go \ - -package application \ - -destination pkg/application/mock.go - mockgen -source=pkg/project/project.go \ -package project \ -destination pkg/project/mock.go diff --git a/scripts/openshiftci-periodic-tests.sh b/scripts/openshiftci-periodic-tests.sh index 263a895ff..706c3f894 100755 --- a/scripts/openshiftci-periodic-tests.sh +++ b/scripts/openshiftci-periodic-tests.sh @@ -31,7 +31,6 @@ make test-integration || error=true make test-integration-devfile || error=true make test-cmd-login-logout || error=true make test-cmd-project || error=true -make test-operator-hub || error=true # E2e tests make test-e2e-all || error=true diff --git a/scripts/openshiftci-presubmit-all-tests-old.sh b/scripts/openshiftci-presubmit-all-tests-old.sh index b42fc1743..39f65c97a 100755 --- a/scripts/openshiftci-presubmit-all-tests-old.sh +++ b/scripts/openshiftci-presubmit-all-tests-old.sh @@ -53,7 +53,6 @@ else make test-integration-devfile || error=true make test-cmd-login-logout || error=true make test-cmd-project || error=true - make test-operator-hub || error=true # E2e tests make test-e2e-all || error=true diff --git a/scripts/openshiftci-presubmit-all-tests.sh b/scripts/openshiftci-presubmit-all-tests.sh index bcc00c6e2..7814da4e5 100755 --- a/scripts/openshiftci-presubmit-all-tests.sh +++ b/scripts/openshiftci-presubmit-all-tests.sh @@ -39,7 +39,6 @@ if [ "${ARCH}" == "s390x" ]; then make test-integration-devfile make test-cmd-login-logout make test-cmd-project - make test-operator-hub # E2e tests make test-e2e-all elif [ "${ARCH}" == "ppc64le" ]; then @@ -50,14 +49,12 @@ elif [ "${ARCH}" == "ppc64le" ]; then make test-cmd-project # E2e tests make test-e2e-all - make test-operator-hub else # Integration tests make test-integration || error=true make test-integration-devfile || error=true make test-cmd-login-logout || error=true make test-cmd-project || error=true - make test-operator-hub || error=true # E2e tests make test-e2e-all || error=true diff --git a/scripts/release-bit-verification.sh b/scripts/release-bit-verification.sh index 124617b01..7f6960e6d 100755 --- a/scripts/release-bit-verification.sh +++ b/scripts/release-bit-verification.sh @@ -69,7 +69,6 @@ git clone $REPO_URL odo && cd $WORKING_DIR/odo && git checkout "v$VERSION" #Run tests make test-integration-devfile make test-integration -make test-operator-hub make test-e2e-all make test-cmd-project diff --git a/scripts/run_script_e2e.sh b/scripts/run_script_e2e.sh index b6ae76cf3..95e0a2df4 100644 --- a/scripts/run_script_e2e.sh +++ b/scripts/run_script_e2e.sh @@ -73,7 +73,6 @@ set -x # # Integration tests shout "Running integration Tests" -make test-operator-hub || error=true make test-integration || error=true make test-integration-devfile || error=true make test-cmd-login-logout || error=true diff --git a/tests/e2escenarios/e2e_devfile_test.go b/tests/e2escenarios/e2e_devfile_test.go index 9837fb36f..af899204d 100644 --- a/tests/e2escenarios/e2e_devfile_test.go +++ b/tests/e2escenarios/e2e_devfile_test.go @@ -1,10 +1,6 @@ package e2escenarios import ( - "fmt" - "strings" - "time" - "github.com/redhat-developer/odo/tests/helper" . "github.com/onsi/ginkgo" @@ -45,21 +41,21 @@ var _ = Describe("odo devfile supported tests", func() { helper.Cmd("odo", "push", "--context", projectDirPath).ShouldPass() helper.Cmd("odo", "push", "--debug", "--context", projectDirPath).ShouldPass() - stopChannel := make(chan bool) - go func() { - helper.Cmd("odo", "debug", "port-forward", "--local-port", debugLocalPort, "--context", projectDirPath).WithTerminate(60*time.Second, stopChannel).ShouldRun() - }() - - // Make sure that the debug information output, outputs correctly. - // We do *not* check the json output since the debugProcessID will be different each time. - helper.WaitForCmdOut("odo", []string{"debug", "info", "-o", "json", "--context", projectDirPath}, 1, false, func(output string) bool { - if strings.Contains(output, `"kind": "OdoDebugInfo"`) && - strings.Contains(output, fmt.Sprintf(`"localPort": %s`, debugLocalPort)) { - return true - } - return false - }) - stopChannel <- true + // stopChannel := make(chan bool) + // go func() { + // helper.Cmd("odo", "debug", "port-forward", "--local-port", debugLocalPort, "--context", projectDirPath).WithTerminate(60*time.Second, stopChannel).ShouldRun() + // }() + // + // // Make sure that the debug information output, outputs correctly. + // // We do *not* check the json output since the debugProcessID will be different each time. + // helper.WaitForCmdOut("odo", []string{"debug", "info", "-o", "json", "--context", projectDirPath}, 1, false, func(output string) bool { + // if strings.Contains(output, `"kind": "OdoDebugInfo"`) && + // strings.Contains(output, fmt.Sprintf(`"localPort": %s`, debugLocalPort)) { + // return true + // } + // return false + // }) + // stopChannel <- true } Context("odo debug support for devfile components", func() { diff --git a/tests/integration/cmd_link_unlink_test.go b/tests/integration/cmd_link_unlink_test.go deleted file mode 100644 index a34b853e2..000000000 --- a/tests/integration/cmd_link_unlink_test.go +++ /dev/null @@ -1,216 +0,0 @@ -package integration - -import ( - "fmt" - "path/filepath" - "strings" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/redhat-developer/odo/tests/helper" -) - -var _ = Describe("odo link and unlink command tests", func() { - - var commonVar helper.CommonVar - - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - // wait until timeout(sec) for odo to see all the operators installed by setup script in the namespace - odoArgs := []string{"catalog", "list", "services"} - operator := "redis-operator" - helper.WaitForCmdOut("odo", odoArgs, 5, true, func(output string) bool { - return strings.Contains(output, operator) - }) - }) - - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - Context("Running the help command", func() { - It("should display the help", func() { - By("for the link command", func() { - appHelp := helper.Cmd("odo", "link", "-h").ShouldPass().Out() - helper.MatchAllInOutput(appHelp, []string{"Link current or provided component", "backed by an Operator", "or another component"}) - }) - By("for the unlink command", func() { - appHelp := helper.Cmd("odo", "unlink", "-h").ShouldPass().Out() - Expect(appHelp).To(ContainSubstring("Unlink component or service from a component")) - }) - }) - }) - - When("two components are deployed", func() { - var frontendContext, backendContext, frontendURL, frontendComp, backendComp string - - // checkDescribe: checks that the linked component and related variables are present in the output of odo describe - var checkDescribe = func(contextDir string, compName string, pushed bool, bindAsFiles bool) { - stdOut := helper.Cmd("odo", "describe", "--context", contextDir).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring("Linked Services")) - Expect(stdOut).To(ContainSubstring(compName)) - if pushed { - if bindAsFiles { - Expect(stdOut).To(ContainSubstring("/bindings")) - } else { - Expect(stdOut).To(ContainSubstring("SERVICE_BACKEND_IP")) - Expect(stdOut).To(ContainSubstring("SERVICE_BACKEND_PORT")) - } - } - } - - // createAndPush: creates component, a URL for it and deploys it - var createAndPush = func(compType string, compName string, contextDir string) { - helper.CopyExample(filepath.Join("source", compType), contextDir) - helper.Cmd("odo", "create", compName, "--context", contextDir, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", compType, "devfile-registry.yaml")).ShouldPass() - helper.Cmd("odo", "url", "create", "--port", "8080", "--context", contextDir).ShouldPass() - helper.Cmd("odo", "push", "--context", contextDir).ShouldPass() - } - - BeforeEach(func() { - frontendComp = fmt.Sprintf("frontend-%v", helper.RandString(3)) - frontendContext = helper.CreateNewContext() - createAndPush("nodejs", frontendComp, frontendContext) - frontendURL = helper.DetermineRouteURL(frontendContext) - - backendComp = fmt.Sprintf("backend-%v", helper.RandString(3)) - backendContext = helper.CreateNewContext() - createAndPush("python", backendComp, backendContext) - }) - - AfterEach(func() { - helper.DeleteDir(frontendContext) - helper.DeleteDir(backendContext) - }) - - When("a link is created between the two components", func() { - BeforeEach(func() { - // we link - helper.Cmd("odo", "link", backendComp, "--context", frontendContext).ShouldPass() - }) - - It("should find the link in odo describe", func() { - checkDescribe(frontendContext, backendComp, false, false) - }) - - It("should unlinking a non-pushed link successfully", func() { - helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldPass() - }) - - When("the link is pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", frontendContext).ShouldPass() - }) - It("should ensure that the proper envFrom entry was created", func() { - envFromOutput := commonVar.CliRunner.GetEnvFromEntry(frontendComp, "app", commonVar.Project) - Expect(envFromOutput).To(ContainSubstring(backendComp)) - helper.HttpWaitFor(frontendURL, "Hello world from node.js!", 20, 1) - }) - It("should find the link and environment variables in odo describe", func() { - checkDescribe(frontendContext, backendComp, true, false) - }) - It("should find the linked environment variable", func() { - stdOut := helper.Cmd("odo", "exec", "--context", frontendContext, "--", "sh", "-c", "echo $SERVICE_BACKEND_IP").ShouldPass().Out() - Expect(stdOut).To(Not(BeEmpty())) - }) - It("should not allow re-linking", func() { - outputErr := helper.Cmd("odo", "link", backendComp, "--context", frontendContext).ShouldFail().Err() - Expect(outputErr).To(ContainSubstring("already linked")) - }) - - It("should successfully delete component after linked component is deleted", func() { - // Testing: https://github.com/redhat-developer/odo/issues/2355 - helper.Cmd("odo", "delete", "-f", "--context", backendContext).ShouldPass() - helper.Cmd("odo", "delete", "-f", "--context", frontendContext).ShouldPass() - }) - - When("unlinking the two components", func() { - BeforeEach(func() { - helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldPass() - }) - It("should find the link in odo describe", func() { - checkDescribe(frontendContext, backendComp, true, false) - }) - It("should not allow unlinking again", func() { - stdOut := helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("failed to unlink the component %q since no link was found in the configuration referring this component", backendComp))) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", frontendContext).ShouldPass() - }) - It("should no longer find the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", frontendContext).ShouldPass().Out() - Expect(stdOut).ToNot(ContainSubstring("Linked Services")) - Expect(stdOut).ToNot(ContainSubstring(backendComp)) - }) - It("should not allow unlinking again", func() { - stdOut := helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("failed to unlink the component %q since no link was found in the configuration referring this component", backendComp))) - }) - }) - }) - }) - }) - When("a link is created between the two components with --bind-as-files", func() { - BeforeEach(func() { - helper.Cmd("odo", "link", backendComp, "--bind-as-files", "--context", frontendContext).ShouldPass() - }) - - It("should unlinking a non-pushed link successfully", func() { - helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldPass() - }) - - When("the component is pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", frontendContext).ShouldPass() - }) - - It("should find the link in odo describe", func() { - checkDescribe(frontendContext, backendComp, true, true) - }) - It("should list the binding directory", func() { - stdOut := helper.Cmd("odo", "exec", "--context", frontendContext, "--", "ls", "/bindings").ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(backendComp)) - }) - It("should not allow re-linking", func() { - outputErr := helper.Cmd("odo", "link", backendComp, "--context", frontendContext).ShouldFail().Err() - Expect(outputErr).To(ContainSubstring("already linked")) - }) - - When("unlinking the two components", func() { - BeforeEach(func() { - helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldPass() - }) - - It("should find the link in odo describe", func() { - checkDescribe(frontendContext, backendComp, true, true) - }) - - It("should not allow unlinking again", func() { - stdOut := helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("failed to unlink the component %q since no link was found in the configuration referring this component", backendComp))) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", frontendContext).ShouldPass() - }) - - It("should no longer find the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", frontendContext).ShouldPass().Out() - Expect(stdOut).ToNot(ContainSubstring("Linked Services")) - Expect(stdOut).ToNot(ContainSubstring(backendComp)) - }) - It("should not allow unlinking again", func() { - stdOut := helper.Cmd("odo", "unlink", backendComp, "--context", frontendContext).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("failed to unlink the component %q since no link was found in the configuration referring this component", backendComp))) - }) - }) - }) - }) - }) - }) -}) diff --git a/tests/integration/cmd_pref_config_test.go b/tests/integration/cmd_pref_config_test.go index ba01a7ef1..6ff248805 100644 --- a/tests/integration/cmd_pref_config_test.go +++ b/tests/integration/cmd_pref_config_test.go @@ -44,28 +44,6 @@ var _ = Describe("odo preference and config command tests", func() { }) }) - Context("when running help for config command", func() { - It("should display the help", func() { - appHelp := helper.Cmd("odo", "config", "-h").ShouldPass().Out() - Expect(appHelp).To(ContainSubstring("Modifies odo specific configuration settings within the devfile or config file")) - }) - }) - - When("running odo config view", func() { - It("should pass if devfile is present in current dir", func() { - helper.Chdir(commonVar.Context) - cmpName := helper.RandString(6) - helper.Cmd("odo", "create", cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - out := helper.Cmd("odo", "config", "view").ShouldPass().Out() - helper.MatchAllInOutput(out, []string{"runtime", "Memory: 1024Mi"}) - }) - - It("should fail if devfile not present in current dir", func() { - err := helper.Cmd("odo", "config", "view").ShouldFail().Err() - Expect(err).To(ContainSubstring("the current directory does not represent an odo component.")) - }) - }) - Context("When viewing global config", func() { var newContext string // ConsentTelemetry is set to false in helper.CommonBeforeEach so that it does not prompt to set a value @@ -138,40 +116,6 @@ var _ = Describe("odo preference and config command tests", func() { }) }) - Context("when viewing local config without logging into the OpenShift cluster", func() { - var ocRunner helper.OcRunner - var token string - BeforeEach(func() { - if helper.IsKubernetesCluster() { - Skip("skipping for kubernetes until we can figure out how to simulate logged out state there") - } - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - helper.Cmd("odo", "create", "nodejs", "--project", commonVar.Project, "--context", commonVar.Context, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - ocRunner = helper.NewOcRunner("oc") - token = ocRunner.GetToken() - ocRunner.Logout() - }) - AfterEach(func() { - ocRunner.LoginUsingToken(token) - }) - When("user is working with a devfile component", func() { - It("should set, list and delete config successfully", func() { - helper.Cmd("odo", "config", "set", "--force", "--context", commonVar.Context, "Name", "foobar").ShouldPass() - configValue := helper.Cmd("odo", "config", "view", "--context", commonVar.Context).ShouldPass().Out() - Expect(configValue).To(ContainSubstring("foobar")) - helper.Cmd("odo", "config", "unset", "--force", "--context", commonVar.Context, "Name").ShouldPass() - }) - It("should set, list and delete config envs successfully", func() { - multiLineContent := `line1 -line2 -line3` - helper.Cmd("odo", "config", "set", "--force", "--env", "hello=world", "--env", "certif="+multiLineContent, "--context", commonVar.Context).ShouldPass() - configValue := helper.Cmd("odo", "config", "view", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(configValue, []string{"hello", "world", "line1", "line2", "line3"}) - }) - }) - }) - Context("When no ConsentTelemetry preference value is set", func() { var _ = JustBeforeEach(func() { // unset the preference in case it is already set diff --git a/tests/integration/devfile/cmd_devfile_app_test.go b/tests/integration/devfile/cmd_devfile_app_test.go deleted file mode 100644 index 0f68e64f1..000000000 --- a/tests/integration/devfile/cmd_devfile_app_test.go +++ /dev/null @@ -1,216 +0,0 @@ -package devfile - -import ( - "path/filepath" - - "github.com/tidwall/gjson" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/tests/helper" -) - -var _ = Describe("odo devfile app command tests", func() { - - var namespace string - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - namespace = commonVar.Project - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - It("should display the help for app command", func() { - appHelp := helper.Cmd("odo", "app", "-h").ShouldPass().Out() - // Trimmed the end of the message string to make it compatible across clusters - Expect(appHelp).To(ContainSubstring("Performs application operations related to")) - }) - - Context("on a fresh new project", func() { - - BeforeEach(func() { - appList := helper.Cmd("odo", "app", "list", "--project", commonVar.Project).ShouldPass().Out() - Expect(appList).To(ContainSubstring("There are no applications deployed")) - actual := helper.Cmd("odo", "app", "list", "-o", "json", "--project", commonVar.Project).ShouldPass().Out() - values := gjson.GetMany(actual, "kind", "metadata", "items") - expected := []string{"List", "{}", "[]"} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - }) - - It("should fail deleting non existing app", func() { - appDelete := helper.Cmd("odo", "app", "delete", "test", "--project", commonVar.Project, "-f").ShouldFail().Err() - Expect(appDelete).To(ContainSubstring("test app does not exists")) - }) - - It("should fail describing non existing app", func() { - appDescribe := helper.Cmd("odo", "app", "describe", "test", "--project", commonVar.Project).ShouldFail().Err() - Expect(appDescribe).To(ContainSubstring("test app does not exists")) - }) - - }) - - When("the user creates and pushes two new devfile components in different apps", func() { - var context0 string - var context1 string - var component0 string - var component1 string - - var app0 string - var app1 string - - BeforeEach(func() { - app0 = helper.RandString(4) - app1 = helper.RandString(4) - - // create first component in the first app - context0 = helper.CreateNewContext() - component0 = helper.RandString(4) - createComponent(component0, app0, namespace, context0) - - // create second component in the second app - context1 = helper.CreateNewContext() - component1 = helper.RandString(4) - createComponent(component1, app1, namespace, context1) - }) - - AfterEach(func() { - helper.Cmd("odo", "delete", "-f", "--context", context0).ShouldPass() - helper.Cmd("odo", "delete", "-f", "--context", context1).ShouldPass() - - helper.DeleteDir(context0) - helper.DeleteDir(context1) - }) - - When("the user creates and pushes a third devfile component", func() { - - var context00 string - var info testInfo - - BeforeEach(func() { - context00 = helper.CreateNewContext() - component00 := helper.RandString(4) - storage00 := helper.RandString(4) - url00 := helper.RandString(4) - - helper.Cmd("odo", "create", "--project", namespace, component00, "--context", context00, "--app", app0, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfileNestedCompCommands.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context00) - helper.Cmd("odo", "storage", "create", storage00, "--path", "/data", "--size", "1Gi", "--context", context00).ShouldPass() - helper.Cmd("odo", "url", "create", url00, "--port", "3000", "--context", context00, "--host", "com", "--ingress").ShouldPass() - helper.Cmd("odo", "push", "--context", context00).ShouldPass() - - info = testInfo{ - app0: app0, - app1: app1, - comp0: component0, - comp00: component00, - url00: url00, - storage00: storage00, - namespace: namespace, - } - }) - - AfterEach(func() { - helper.Cmd("odo", "delete", "-f", "--context", context00).ShouldPass() - helper.DeleteDir(context00) - }) - - It("should list, describe and delete the app properly with json output", func() { - runner(info) - }) - }) - }) - - When("the user creates two components with the same name in different apps", func() { - var context0 string - var context1 string - var component string - - var app0 string - var app1 string - - BeforeEach(func() { - app0 = helper.RandString(4) - app1 = helper.RandString(4) - - component = helper.RandString(4) - - // create first component in the first app - context0 = helper.CreateNewContext() - createComponent(component, app0, namespace, context0) - - // create second component in the second app - context1 = helper.CreateNewContext() - createComponent(component, app1, namespace, context1) - }) - - AfterEach(func() { - helper.Cmd("odo", "delete", "-f", "--context", context0).ShouldPass() - helper.Cmd("odo", "delete", "-f", "--context", context1).ShouldPass() - - helper.DeleteDir(context0) - helper.DeleteDir(context1) - }) - - It("should list the components", func() { - output := helper.Cmd("odo", "list", "--app", app0).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{app0, component}) - output = helper.Cmd("odo", "list", "--app", app1).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{app1, component}) - }) - }) -}) - -// createComponent creates with the given parameters and pushes it -func createComponent(componentName, appName, project, context string) { - helper.Cmd("odo", "create", "--project", project, componentName, "--context", context, "--app", appName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context) - helper.Cmd("odo", "push", "--context", context).ShouldPass() -} - -// testInfo holds the information to run the matchers in the runner function -type testInfo struct { - // the name of the two apps - app0 string - app1 string - - // the name of the components belonging to the first app - comp0, comp00 string - - // the url and storage belonging to one of the components in the first app - url00, storage00 string - - namespace string -} - -func runner(info testInfo) { - - stdOut := helper.Cmd("odo", "app", "list", "--project", info.namespace).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{info.app0, info.app1}) - - // test the json output - stdOut = helper.Cmd("odo", "app", "list", "--project", info.namespace, "-o", "json").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{info.app0, info.app1}) - Expect(helper.IsJSON(stdOut)).To(BeTrue()) - - stdOut = helper.Cmd("odo", "app", "describe", info.app0, "--project", info.namespace).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{info.app0, info.comp0, info.comp00, info.storage00, info.url00, "http", "3000"}) - - // test the json output - stdOut = helper.Cmd("odo", "app", "describe", info.app0, "--project", info.namespace, "-o", "json").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{info.app0, info.comp0, info.comp00}) - Expect(helper.IsJSON(stdOut)).To(BeTrue()) - - // delete the app - stdOut = helper.Cmd("odo", "app", "delete", info.app0, "--project", info.namespace, "-f").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{info.app0, info.comp0, info.comp00, info.url00, info.storage00}) - - // test the list output again - stdOut = helper.Cmd("odo", "app", "list", "--project", info.namespace).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{info.app1}) -} diff --git a/tests/integration/devfile/cmd_devfile_catalog_test.go b/tests/integration/devfile/cmd_devfile_catalog_test.go index 6aacb090e..383570c80 100644 --- a/tests/integration/devfile/cmd_devfile_catalog_test.go +++ b/tests/integration/devfile/cmd_devfile_catalog_test.go @@ -44,10 +44,6 @@ var _ = Describe("odo devfile catalog command tests", func() { Expect(err).ToNot(HaveOccurred()) }) - It("should succeed checking catalog for installed services", func() { - helper.Cmd("odo", "catalog", "list", "services").ShouldPass() - }) - When("executing catalog list components", func() { var output string diff --git a/tests/integration/devfile/cmd_devfile_config_test.go b/tests/integration/devfile/cmd_devfile_config_test.go deleted file mode 100644 index bdba863ac..000000000 --- a/tests/integration/devfile/cmd_devfile_config_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package devfile - -import ( - . "github.com/onsi/ginkgo" - "github.com/redhat-developer/odo/tests/helper" -) - -var _ = Describe("odo devfile config command tests", func() { - - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - helper.Chdir(commonVar.Context) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - It("should fail to set and unset an invalid parameter", func() { - const fakeParameter = "fakeParameter" - helper.Cmd("odo", "config", "set", fakeParameter, fakeParameter, "-f").ShouldFail() - helper.Cmd("odo", "config", "unset", fakeParameter, "-f").ShouldFail() - }) - - When("a component is created", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "nodejs", "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - }) - - When("executing config view", func() { - var output string - - BeforeEach(func() { - output = helper.Cmd("odo", "config", "view").ShouldPass().Out() - }) - - It("should view all default parameters", func() { - wantOutput := []string{ - "nodejs", - "Ports", - "Memory", - } - helper.MatchAllInOutput(output, wantOutput) - }) - }) - - When("executing config set", func() { - - const ( - testName = "testname" - testMemory = "500Mi" - testDebugPort = "8888" - ) - - BeforeEach(func() { - helper.Cmd("odo", "config", "set", "Name", testName, "-f").ShouldPass() - helper.Cmd("odo", "config", "set", "Ports", testDebugPort, "-f").ShouldPass() - helper.Cmd("odo", "config", "set", "Memory", testMemory, "-f").ShouldPass() - }) - - It("should successfully set the parameters", func() { - output := helper.Cmd("odo", "config", "view").ShouldPass().Out() - wantOutput := []string{ - testName, - testMemory, - testDebugPort, - } - helper.MatchAllInOutput(output, wantOutput) - }) - - When("unsettting a parameter", func() { - - BeforeEach(func() { - helper.Cmd("odo", "config", "unset", "Ports", "-f").ShouldPass() - }) - - It("should successfully unset the parameter", func() { - output := helper.Cmd("odo", "config", "view").ShouldPass().Out() - dontWantOutput := []string{ - testDebugPort, - } - helper.DontMatchAllInOutput(output, dontWantOutput) - helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass() - }) - }) - }) - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_create_test.go b/tests/integration/devfile/cmd_devfile_create_test.go index 046ba9373..febbb1bc7 100644 --- a/tests/integration/devfile/cmd_devfile_create_test.go +++ b/tests/integration/devfile/cmd_devfile_create_test.go @@ -7,7 +7,6 @@ import ( "path" "path/filepath" "regexp" - "strings" "github.com/tidwall/gjson" "gopkg.in/yaml.v2" @@ -104,12 +103,6 @@ var _ = Describe("odo devfile create command tests", func() { Expect(util.CheckPathExists(devfilePath)).Should(BeTrue()) Expect(util.CheckPathExists(envFilePath)).Should(BeTrue()) }) - - By("checking the auto generated name is displayed", func() { - output := helper.Cmd("odo", "env", "view", "--context", newContext, "-o", "json").ShouldPass().Out() - value := gjson.Get(output, "spec.name") - Expect(strings.TrimSpace(value.String())).To(ContainSubstring(strings.TrimSpace("nodejs-" + filepath.Base(strings.ToLower(newContext))))) - }) }) It("should successfully create the devfile component and download the source in the context when used with --starter flag", func() { diff --git a/tests/integration/devfile/cmd_devfile_debug_test.go b/tests/integration/devfile/cmd_devfile_debug_test.go deleted file mode 100644 index b4e00c42a..000000000 --- a/tests/integration/devfile/cmd_devfile_debug_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package devfile - -import ( - "os" - "path/filepath" - "runtime" - "strconv" - "time" - - "github.com/redhat-developer/odo/pkg/util" - "github.com/tidwall/gjson" - - "github.com/redhat-developer/odo/tests/helper" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("odo devfile debug command tests", func() { - var componentName string - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - componentName = helper.RandString(6) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - When("creating an application using devfile with debugrun", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--context", commonVar.Context, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-debugrun.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - }) - When("the debug command in the devfile is invalid", func() { - BeforeEach(func() { - helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "npm run debug", "npm run debugs") - }) - It("should return an error message along with a log on odo push", func() { - _, output := helper.Cmd("odo", "push", "--debug", "--context", commonVar.Context).ShouldPass().OutAndErr() - helper.MatchAllInOutput(output, []string{ - "exited with error status within 1 sec", - "Did you mean this?", - }) - - _, output = helper.Cmd("odo", "push", "--debug", "--context", commonVar.Context, "--debug-command", "debug", "-f").ShouldPass().OutAndErr() - helper.MatchAllInOutput(output, []string{ - "exited with error status within 1 sec", - "Did you mean this?", - }) - }) - }) - - When("the application is pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--debug", "--context", commonVar.Context).ShouldPass() - }) - It("checks that machine output debug information works", func() { - httpPort, err := util.HTTPGetFreePort() - Expect(err).NotTo(HaveOccurred()) - freePort := strconv.Itoa(httpPort) - - stopChannel := make(chan bool) - go func() { - helper.Cmd("odo", "debug", "port-forward", "--local-port", freePort, "--context", commonVar.Context).WithTerminate(60*time.Second, stopChannel).ShouldRun() - }() - - // Make sure that the debug information output, outputs correctly. - // We do *not* check the json output since the debugProcessID will be different each time. - helper.WaitForCmdOut("odo", []string{"debug", "info", "-o", "json", "--context", commonVar.Context}, 1, false, func(output string) bool { - values := gjson.GetMany(output, "kind", "spec.localPort") - expected := []string{"OdoDebugInfo", freePort} - return helper.GjsonMatcher(values, expected) - }) - stopChannel <- true - }) - - It("should expect a ws connection when tried to connect on default debug port locally", func() { - // check the env for the runMode - envOutput, err := helper.ReadFile(filepath.Join(commonVar.Context, ".odo/env/env.yaml")) - Expect(err).To(BeNil()) - Expect(envOutput).To(ContainSubstring(" RunMode: debug")) - - stopChannel := make(chan bool) - go func() { - helper.Cmd("odo", "debug", "port-forward", "--context", commonVar.Context).WithTerminate(60*time.Second, stopChannel).ShouldRun() - }() - - // 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET - // We are just using this to validate if nodejs agent is listening on the other side - helper.HttpWaitForWithStatus("http://localhost:5858", "WebSockets request was expected", 12, 5, 400) - stopChannel <- true - }) - - It("should error out when using an invalid devfile", func() { - By("listening on default port and forwarding to the default port", func() { - helper.Cmd("odo", "debug", "port-forward", "--context", commonVar.Context, "--devfile", "invalid.yaml").ShouldFail() - }) - By("getting debug session information", func() { - helper.Cmd("odo", "debug", "info", "--context", commonVar.Context, "--devfile", "invalid.yaml").ShouldFail() - }) - }) - - It("should start a debug session and run debug info on a closed debug session", func() { - httpPort, err := util.HTTPGetFreePort() - Expect(err).NotTo(HaveOccurred()) - freePort := strconv.Itoa(httpPort) - - stopChannel := make(chan bool) - go func() { - helper.Cmd("odo", "debug", "port-forward", "--local-port", freePort, "--context", commonVar.Context).WithTerminate(60*time.Second, stopChannel).ShouldRun() - }() - - // 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET - // We are just using this to validate if nodejs agent is listening on the other side - helper.HttpWaitForWithStatus("http://localhost:"+freePort, "WebSockets request was expected", 12, 5, 400) - runningString := helper.Cmd("odo", "debug", "info", "--context", commonVar.Context).ShouldPass().Out() - Expect(runningString).To(ContainSubstring(freePort)) - stopChannel <- true - failString := helper.Cmd("odo", "debug", "info", "--context", commonVar.Context).ShouldFail().Err() - Expect(failString).To(ContainSubstring("not running")) - - // according to https://golang.org/pkg/os/#Signal On Windows, sending os.Interrupt to a process with os.Process.Signal is not implemented - // discussion on the go repo https://github.com/golang/go/issues/6720 - // session.Interrupt() will not work as it internally uses syscall.SIGINT - // thus debug port-forward won't stop running - // the solution is to use syscall.SIGKILL for windows but this will kill the process immediately - // and the cleaning and closing tasks for debug port-forward won't run and the debug info file won't be cleared - // thus we skip this last check - // CTRL_C_EVENTS from the terminal works fine https://github.com/golang/go/issues/6720#issuecomment-66087737 - // here's a hack to generate the event https://golang.org/cl/29290044 - // but the solution is unacceptable https://github.com/golang/go/issues/6720#issuecomment-66087749 - if runtime.GOOS != "windows" { - Expect(helper.ListFilesInDir(os.TempDir())).To(Not(ContainElement(commonVar.Project + "-app" + "-nodejs-cmp-" + commonVar.Project + "-odo-debug.json"))) - } - }) - It("should start a debug session and run debug info on a running debug session", func() { - httpPort, err := util.HTTPGetFreePort() - Expect(err).NotTo(HaveOccurred()) - freePort := strconv.Itoa(httpPort) - - stopChannel := make(chan bool) - go func() { - helper.Cmd("odo", "debug", "port-forward", "--local-port", freePort, "--context", commonVar.Context).WithTerminate(60*time.Second, stopChannel).ShouldRun() - }() - - // 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET - // We are just using this to validate if nodejs agent is listening on the other side - helper.HttpWaitForWithStatus("http://localhost:"+freePort, "WebSockets request was expected", 12, 5, 400) - runningString := helper.Cmd("odo", "debug", "info", "--context", commonVar.Context).ShouldPass().Out() - Expect(runningString).To(ContainSubstring(freePort)) - Expect(helper.ListFilesInDir(os.TempDir())).To(ContainElement(commonVar.Project + "-app-" + componentName + "-odo-debug.json")) - defer helper.DeleteFile(filepath.Join(os.TempDir(), commonVar.Project+"-app-"+componentName+"-odo-debug.json")) - stopChannel <- true - }) - }) - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_delete_test.go b/tests/integration/devfile/cmd_devfile_delete_test.go index 34cb3053b..b5a7e71a3 100644 --- a/tests/integration/devfile/cmd_devfile_delete_test.go +++ b/tests/integration/devfile/cmd_devfile_delete_test.go @@ -16,7 +16,6 @@ import ( var _ = Describe("odo devfile delete command tests", func() { const devfile = "devfile.yaml" - const appName = "app" var devfilePath string var componentName, invalidNamespace string @@ -40,7 +39,7 @@ var _ = Describe("odo devfile delete command tests", func() { }) When("a component is created", func() { BeforeEach(func() { - helper.Cmd("odo", "create", componentName, "--project", commonVar.Project, "--app", appName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() + helper.Cmd("odo", "create", componentName, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) }) It("should delete the component", func() { @@ -145,7 +144,7 @@ var _ = Describe("odo devfile delete command tests", func() { }) // Marked as pending because it does not work at the moment. It takes the component in current directory into account while deleting. XIt("should delete with the component name", func() { - output := helper.Cmd("odo", "delete", firstComp, "--app", "app", "--project", commonVar.Project, "-f").ShouldPass().Out() + output := helper.Cmd("odo", "delete", firstComp, "--project", commonVar.Project, "-f").ShouldPass().Out() Expect(output).ToNot(ContainSubstring(secondComp)) Expect(output).To(ContainSubstring(firstComp)) }) @@ -157,8 +156,8 @@ var _ = Describe("odo devfile delete command tests", func() { By("--project flag") helper.Cmd("odo", "delete", "--project", commonVar.Project, "-f").ShouldFail() - By("component name, --app, --project and --all flag") - helper.Cmd("odo", "delete", componentName, "--app", appName, "--project", commonVar.Project, "--all", "-f").ShouldFail() + By("component name, --project and --all flag") + helper.Cmd("odo", "delete", componentName, "--project", commonVar.Project, "--all", "-f").ShouldFail() By("component name and --all flag") helper.Cmd("odo", "delete", componentName, "--all", "-f").ShouldFail() @@ -180,7 +179,6 @@ var _ = Describe("odo devfile delete command tests", func() { helper.Cmd("odo", "url", "create", "example-1", "--port", "3000").ShouldPass() resourceTypes = append(resourceTypes, helper.ResourceTypeRoute) } - helper.Cmd("odo", "storage", "create", "storage-1", "--size", "1Gi", "--path", "/data1", "--context", commonVar.Context).ShouldPass() }) When("the component is pushed", func() { BeforeEach(func() { @@ -229,11 +227,6 @@ var _ = Describe("odo devfile delete command tests", func() { ResourceName: componentName, Namespace: commonVar.Project, }, - { - ResourceType: helper.ResourceTypePVC, - ResourceName: "storage-1", - Namespace: commonVar.Project, - }, { ResourceType: helper.ResourceTypeRoute, ResourceName: "example-1", @@ -268,7 +261,7 @@ var _ = Describe("odo devfile delete command tests", func() { When("the component is created in a non-existent project", func() { invalidNamespace = "garbage" BeforeEach(func() { - helper.Cmd("odo", "create", componentName, "--project", invalidNamespace, "--app", appName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() + helper.Cmd("odo", "create", componentName, "--project", invalidNamespace, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() }) It("should let the user delete the local config files with -a flag", func() { // DeleteLocalConfig appends -a flag diff --git a/tests/integration/devfile/cmd_devfile_describe_test.go b/tests/integration/devfile/cmd_devfile_describe_test.go deleted file mode 100644 index 4ff72c50c..000000000 --- a/tests/integration/devfile/cmd_devfile_describe_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package devfile - -import ( - "os" - "path/filepath" - - devfilepkg "github.com/devfile/api/v2/pkg/devfile" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/pkg/component" - "github.com/redhat-developer/odo/tests/helper" - "github.com/tidwall/gjson" -) - -var _ = Describe("odo devfile describe command tests", func() { - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - if os.Getenv("KUBERNETES") != "true" { - Skip("Plain Kubernetes scenario only, skipping") - } - - commonVar = helper.CommonBeforeEach() - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - When("a component is created with storage and url", func() { - var ( - compName = "cmp-git" - compType = "django" - appName = "testing" - ) - BeforeEach(func() { - // Using Django example here because it helps to distinguish between language and projectType. - // With nodejs, both projectType and language is nodejs, but with python-django, django is the projectType and python is the language - helper.CopyExample(filepath.Join("source", "python"), commonVar.Context) - helper.Cmd("odo", "create", "python-django", compName, "--project", commonVar.Project, "--context", commonVar.Context, "--app", appName).ShouldPass() - helper.Cmd("odo", "url", "create", "url-1", "--port", "3000", "--host", "example.com", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "url", "create", "url-2", "--port", "4000", "--host", "example.com", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "storage", "create", "storage-1", "--size", "1Gi", "--path", "/data1", "--context", commonVar.Context).ShouldPass() - }) - AfterEach(func() { - // odo delete requires changing directory because it does not work as intended with --context - // TODO: Remove helper.Chdir after these issues are closed - https://github.com/redhat-developer/odo/issues/4451 - // TODO: and https://github.com/redhat-developer/odo/issues/4135 - helper.Chdir(commonVar.Context) - helper.Cmd("odo", "delete", "-f", "--all").ShouldPass() - }) - var checkDescribe = func(status string) { - cmpDescribe := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(cmpDescribe, []string{ - compName, - compType, - "url-1", - "url-2", - "storage-1", - }) - By("checking describe works with json output", func() { - cmpDescribeJSON, err := helper.Unindented(helper.Cmd("odo", "describe", "-o", "json", "--context", commonVar.Context).ShouldPass().Out()) - Expect(err).Should(BeNil()) - valuesDes := gjson.GetMany(cmpDescribeJSON, "kind", "metadata.name", "status.state", "spec.urls.items.0.metadata.name", "spec.urls.items.0.spec.host", "spec.urls.items.1.metadata.name", "spec.urls.items.1.spec.host", "spec.storages.items.0.metadata.name", "spec.storages.items.0.spec.containerName") - expectedDes := []string{"Component", compName, status, "url-1", "url-1.example.com", "url-2", "url-2.example.com", "storage-1", "py-web"} - Expect(helper.GjsonMatcher(valuesDes, expectedDes)).To(Equal(true)) - }) - - By("checking describe with component name works", func() { - // odo should describe not-pushed component if component name is given. - helper.Cmd("odo", "describe", compName, "--context", commonVar.Context).ShouldPass() - Expect(cmpDescribe).To(ContainSubstring(compName)) - }) - } - - It("should describe the component correctly", func() { - checkDescribe("Not Pushed") - }) - - It("should describe the component correctly from a disconnected cluster", func() { - By("getting human readable output", func() { - output := helper.Cmd("odo", "describe", "--context", commonVar.Context).WithEnv("KUBECONFIG=/no/path", "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{compName, compType}) - }) - - By("getting json output", func() { - output := helper.Cmd("odo", "describe", "--context", commonVar.Context, "-o", "json").WithEnv("KUBECONFIG=/no/path", "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out() - values := gjson.GetMany(output, "kind", "metadata.name", "spec.type", "status.state") - Expect(helper.GjsonMatcher(values, []string{"Component", compName, compType, "Unknown"})).To(Equal(true)) - }) - }) - - When("the component is pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should describe the component correctly", func() { - checkDescribe("Pushed") - }) - It("should describe the component correctly when run outside the context directory", func() { - By("getting human readable output", func() { - output := helper.Cmd("odo", "describe", compName, "--app", appName, "--project", commonVar.Project).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{compName, compType}) - }) - By("getting json output", func() { - output := helper.Cmd("odo", "describe", compName, "--app", appName, "--project", commonVar.Project, "-o", "json").ShouldPass().Out() - values := gjson.GetMany(output, "kind", "metadata.name", "spec.type", "status.state") - Expect(helper.GjsonMatcher(values, []string{"Component", compName, compType, "Pushed"})).To(Equal(true)) - }) - }) - }) - }) - - When("devfile has missing metadata", func() { - // Note: We will be using SpringBoot example here because it helps to distinguish between language and projectType. - // In terms of SpringBoot, spring is the projectType and java is the language; see https://github.com/redhat-developer/odo/issues/4815 - - var metadata devfilepkg.DevfileMetadata - - // checkDescribe checks the describe output (both normal and json) to see if it contains the expected componentType - var checkDescribe = func(componentType string) { - By("checking the human readable output", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(componentType)) - }) - By("checking the json output", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context, "-o", "json").ShouldPass().Out() - Expect(gjson.Get(stdOut, "spec.type").String()).To(Equal(componentType)) - }) - } - - When("projectType is missing", func() { - BeforeEach(func() { - helper.CopyAndCreate(filepath.Join("source", "devfiles", "springboot", "project"), filepath.Join("source", "devfiles", "springboot", "devfile-with-missing-projectType-metadata.yaml"), commonVar.Context) - metadata = helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml")) - }) - - It("should show the language for 'Type' in odo describe", func() { - checkDescribe(metadata.Language) - }) - When("the component is pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out() - }) - It("should show the language for 'Type' in odo describe", func() { - checkDescribe(metadata.Language) - }) - }) - - }) - When("projectType and language is missing", func() { - BeforeEach(func() { - helper.CopyAndCreate(filepath.Join("source", "devfiles", "springboot", "project"), filepath.Join("source", "devfiles", "springboot", "devfile-with-missing-projectType-and-language-metadata.yaml"), commonVar.Context) - metadata = helper.GetMetadataFromDevfile(filepath.Join(commonVar.Context, "devfile.yaml")) - }) - It("should show 'Not available' for 'Type' in odo describe", func() { - checkDescribe(component.NotAvailable) - }) - When("the component is pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out() - }) - It("should show 'Not available' for 'Type' in odo describe", func() { - checkDescribe(component.NotAvailable) - }) - }) - }) - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_env_test.go b/tests/integration/devfile/cmd_devfile_env_test.go deleted file mode 100644 index 017831628..000000000 --- a/tests/integration/devfile/cmd_devfile_env_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package devfile - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/tests/helper" - "github.com/tidwall/gjson" -) - -var _ = Describe("odo devfile env command tests", func() { - const ( - testName = "testname" - testProject = "testproject" - testDebugPort = "8888" - fakeParameter = "fakeParameter" - ) - - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - helper.Chdir(commonVar.Context) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - When("creating a component", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "acomponentname", "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - }) - - It("Should fail to set and unset an invalid parameter", func() { - helper.Cmd("odo", "env", "set", fakeParameter, fakeParameter, "-f").ShouldFail() - helper.Cmd("odo", "env", "unset", fakeParameter, "-f").ShouldFail() - }) - - It("should show all default parameters with odo view info", func() { - output := helper.Cmd("odo", "env", "view").ShouldPass().Out() - wantOutput := []string{ - "PARAMETER NAME", - "PARAMETER VALUE", - "NAME", - "acomponentname", - "Project", - commonVar.Project, - "DebugPort", - "Application", - "app", - } - helper.MatchAllInOutput(output, wantOutput) - }) - - It("should show all default parameters with odo view info and JSON output ", func() { - output := helper.Cmd("odo", "env", "view", "-o", "json").ShouldPass().Out() - values := gjson.GetMany(output, "kind", "spec.name", "spec.project", "spec.appName") - expected := []string{"EnvInfo", "acomponentname", commonVar.Project, "app"} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - }) - - When("executing env set", func() { - BeforeEach(func() { - helper.Cmd("odo", "env", "set", "Name", testName, "-f").ShouldPass() - helper.Cmd("odo", "env", "set", "Project", testProject, "-f").ShouldPass() - helper.Cmd("odo", "env", "set", "DebugPort", testDebugPort, "-f").ShouldPass() - }) - - It("should successfully view the parameters", func() { - output := helper.Cmd("odo", "env", "view").ShouldPass().Out() - wantOutput := []string{ - "PARAMETER NAME", - "PARAMETER VALUE", - "NAME", - testName, - "Project", - testProject, - "DebugPort", - testDebugPort, - "Application", - "app", - } - helper.MatchAllInOutput(output, wantOutput) - }) - - It("should successfully view the parameters with JSON output", func() { - output := helper.Cmd("odo", "env", "view", "-o", "json").ShouldPass().Out() - values := gjson.GetMany(output, "kind", "spec.name", "spec.project", "spec.debugPort") - expected := []string{"EnvInfo", testName, testProject, testDebugPort} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - }) - - When("unsetting a parameter", func() { - BeforeEach(func() { - helper.Cmd("odo", "env", "unset", "DebugPort", "-f").ShouldPass() - }) - - It("should not show the parameter", func() { - output := helper.Cmd("odo", "env", "view").ShouldPass().Out() - dontWantOutput := []string{ - testDebugPort, - } - helper.DontMatchAllInOutput(output, dontWantOutput) - helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass() - }) - - It("should not show the parameter in JSON output", func() { - output := helper.Cmd("odo", "env", "view", "-o", "json").ShouldPass().Out() - values := gjson.GetMany(output, "kind", "spec.debugPort") - expected := []string{"EnvInfo", ""} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - }) - }) - }) - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_exec_test.go b/tests/integration/devfile/cmd_devfile_exec_test.go deleted file mode 100644 index 804de5483..000000000 --- a/tests/integration/devfile/cmd_devfile_exec_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package devfile - -import ( - "path/filepath" - - "github.com/redhat-developer/odo/tests/helper" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("odo devfile exec command tests", func() { - var cmpName string - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - cmpName = helper.RandString(6) - helper.Chdir(commonVar.Context) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - When("a component is created", func() { - - BeforeEach(func() { - helper.Cmd("odo", "create", cmpName, "--context", commonVar.Context, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - - }) - - It("should error out", func() { - By("exec on a non deployed component", func() { - err := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "touch", "/projects/blah.js").ShouldFail().Err() - Expect(err).To(ContainSubstring("doesn't exist on the cluster")) - }) - By("exec with invalid devfile flag", func() { - err := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--devfile", "invalid.yaml", "--", "touch", "/projects/blah.js").ShouldFail().Err() - Expect(err).To(ContainSubstring("unknown flag: --devfile")) - }) - - // TODO(feloy): Uncomment when https://github.com/redhat-developer/odo/issues/5012 is fixed - // By("exec from a context with no component", func() { - // err := helper.Cmd("odo", "exec", "--context", "/tmp", "--", "touch", "/projects/blah.js").ShouldFail().Err() - // Expect(err).To(ContainSubstring("the current directory does not contain an odo component")) - // }) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should execute the given command successfully in the container", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "touch", "/projects/blah.js").ShouldPass() - podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - listDir := commonVar.CliRunner.ExecListDir(podName, commonVar.Project, "/projects") - Expect(listDir).To(ContainSubstring("blah.js")) - }) - - It("should error out when no command is given by the user", func() { - output := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--").ShouldFail().Err() - Expect(output).To(ContainSubstring("no command was given")) - }) - - It("should error out when an invalid command is given by the user", func() { - output := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "invalidCommand").ShouldFail().Err() - Expect(output).To(ContainSubstring("executable file not found in $PATH")) - }) - }) - - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_list_test.go b/tests/integration/devfile/cmd_devfile_list_test.go index 77d57dcce..a7b417212 100644 --- a/tests/integration/devfile/cmd_devfile_list_test.go +++ b/tests/integration/devfile/cmd_devfile_list_test.go @@ -48,69 +48,6 @@ var _ = Describe("odo list with devfile", func() { expected := []string{"List", "Component", cmpName, "Not Pushed"} Expect(helper.GjsonExactMatcher(values, expected)).To(Equal(true)) }) - - When("the first component is pushed and a second component is created in different application", func() { - var context2 string - var cmpName2 string - var appName string - - BeforeEach(func() { - output := helper.Cmd("odo", "push").ShouldPass().Out() - Expect(output).To(ContainSubstring("Changes successfully pushed to component")) - - context2 = helper.CreateNewContext() - cmpName2 = helper.RandString(6) - appName = helper.RandString(6) - - helper.Cmd("odo", "create", "--project", commonVar.Project, "--app", appName, "--context", context2, cmpName2, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context2) - }) - - AfterEach(func() { - helper.DeleteDir(context2) - }) - - It("should show the second component as 'NotPushed'", func() { - output := helper.Cmd("odo", "list", "--context", context2).ShouldPass().Out() - Expect(helper.Suffocate(output)).To(ContainSubstring(helper.Suffocate(fmt.Sprintf("%s%s%s%sNotPushed", appName, cmpName2, commonVar.Project, "nodejs")))) - }) - - It("should show the second component as 'Not Pushed' in JSON output", func() { - output := helper.Cmd("odo", "list", "-o", "json", "--context", context2).ShouldPass().Out() - values := gjson.GetMany(output, "kind", "devfileComponents.0.kind", "devfileComponents.0.metadata.name", "devfileComponents.0.status.state") - expected := []string{"List", "Component", cmpName2, "Not Pushed"} - Expect(helper.GjsonExactMatcher(values, expected)).To(Equal(true)) - }) - - When("second component is pushed", func() { - BeforeEach(func() { - output2 := helper.Cmd("odo", "push", "--context", context2).ShouldPass().Out() - Expect(output2).To(ContainSubstring("Changes successfully pushed to component")) - }) - - It("should show components in the current application in 'Pushed' state", func() { - output := helper.Cmd("odo", "list", "--project", commonVar.Project).ShouldPass().Out() - // this test makes sure that a devfile component doesn't show up as an s2i component as well - Expect(helper.Suffocate(output)).To(Equal(helper.Suffocate(fmt.Sprintf(` - APP NAME PROJECT TYPE STATE MANAGED BY ODO - app %[1]s %[2]s nodejs Pushed Yes - `, cmpName, commonVar.Project)))) - }) - - It("should show components in the current application in 'Pushed' state in JSON output", func() { - output := helper.Cmd("odo", "list", "-o", "json", "--project", commonVar.Project).ShouldPass().Out() - values := gjson.GetMany(output, "kind", "devfileComponents.0.kind", "devfileComponents.0.metadata.name", "devfileComponents.0.status.state") - expected := []string{"List", "Component", cmpName, "Pushed"} - Expect(helper.GjsonExactMatcher(values, expected)).To(Equal(true)) - }) - - It("should show components in all applications", func() { - output := helper.Cmd("odo", "list", "--all-apps", "--project", commonVar.Project).ShouldPass().Out() - Expect(output).To(ContainSubstring(cmpName)) - Expect(output).To(ContainSubstring(cmpName2)) - }) - }) - }) }) Context("devfile has missing metadata", func() { // Note: We will be using SpringBoot example here because it helps to distinguish between language and projectType. diff --git a/tests/integration/devfile/cmd_devfile_log_test.go b/tests/integration/devfile/cmd_devfile_log_test.go deleted file mode 100644 index 3614830dc..000000000 --- a/tests/integration/devfile/cmd_devfile_log_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package devfile - -import ( - "path/filepath" - - "github.com/redhat-developer/odo/tests/helper" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("odo devfile log command tests", func() { - var cmpName string - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - cmpName = helper.RandString(6) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - When("When a springboot component is created and pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--context", commonVar.Context, "--devfile", helper.GetExamplePath("source", "devfiles", "springboot", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context) - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should log run command output and fail for debug command", func() { - output := helper.Cmd("odo", "log", "--context", commonVar.Context).ShouldPass().Out() - Expect(output).To(ContainSubstring("ODO_COMMAND_RUN")) - - // It should fail for debug command as no debug command in devfile - helper.Cmd("odo", "log", "--debug").ShouldFail() - - /* - Flaky Test odo log -f, see issue https://github.com/redhat-developer/odo/issues/3809 *** Issue got closed due to inactivity, but is not resolved *** - match, err := helper.RunCmdWithMatchOutputFromBuffer(30*time.Second, "program=devrun", "odo", "log", "-f") - Expect(err).To(BeNil()) - Expect(match).To(BeTrue()) - */ - - }) - }) - - When("a component is created but not pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--context", commonVar.Context, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - }) - It("Should error out", func() { - helper.Cmd("odo", "log").ShouldFail() - }) - When("a command is created and pushed with debugrun", func() { - var projectDir string - BeforeEach(func() { - projectDir = filepath.Join(commonVar.Context, "projectDir") - helper.CopyExample(filepath.Join("source", "web-nodejs-sample"), projectDir) - helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--context", projectDir, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-debugrun.yaml")).ShouldPass() - helper.Cmd("odo", "push", "--debug", "--context", projectDir).ShouldPass() - }) - It("should log debug command output", func() { - output := helper.Cmd("odo", "log", "--debug", "--context", projectDir).ShouldPass().Out() - Expect(output).To(ContainSubstring("ODO_COMMAND_DEBUG")) - - /* - Flaky Test odo log -f, see issue https://github.com/redhat-developer/odo/issues/3809 *** Issue got closed due to inactivity, but is not resolved *** - match, err := helper.RunCmdWithMatchOutputFromBuffer(30*time.Second, "program=debugrun", "odo", "log", "-f") - Expect(err).To(BeNil()) - Expect(match).To(BeTrue()) - */ - }) - }) - - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_push_test.go b/tests/integration/devfile/cmd_devfile_push_test.go index a009724f8..666c4007e 100644 --- a/tests/integration/devfile/cmd_devfile_push_test.go +++ b/tests/integration/devfile/cmd_devfile_push_test.go @@ -465,10 +465,6 @@ var _ = Describe("odo devfile push command tests", func() { Expect(output).To(ContainSubstring("Executing devrun command \"npm start\"")) helper.Cmd("odo", "push", "-f").ShouldPass() - - logs := helper.Cmd("odo", "log").ShouldPass().Out() - Expect(logs).To(ContainSubstring("stop the program")) - }) }) @@ -482,10 +478,6 @@ var _ = Describe("odo devfile push command tests", func() { Expect(output).To(ContainSubstring("Executing devrun command \"npm start\"")) helper.Cmd("odo", "push", "-f").ShouldPass() - - logs := helper.Cmd("odo", "log").ShouldPass().Out() - Expect(logs).To(ContainSubstring("Don't start program again, program is already started")) - }) When("doing odo push --debug ", func() { @@ -496,13 +488,6 @@ var _ = Describe("odo devfile push command tests", func() { It("should restart the application regardless of hotReloadCapable value", func() { Expect(stdOut).To(Not(ContainSubstring("No file changes detected, skipping build"))) - - logs := helper.Cmd("odo", "log").ShouldPass().Out() - - helper.MatchAllInOutput(logs, []string{ - "\"stop the program\" program=debugrun", - "\"stop the program\" program=devrun", - }) }) }) }) diff --git a/tests/integration/devfile/cmd_devfile_status_test.go b/tests/integration/devfile/cmd_devfile_status_test.go deleted file mode 100644 index 7521bafcf..000000000 --- a/tests/integration/devfile/cmd_devfile_status_test.go +++ /dev/null @@ -1,325 +0,0 @@ -package devfile - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "time" - - "github.com/redhat-developer/odo/pkg/devfile/adapters/common" - "github.com/redhat-developer/odo/pkg/machineoutput" - "github.com/redhat-developer/odo/tests/helper" - "github.com/redhat-developer/odo/tests/integration/devfile/utils" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -var _ = Describe("odo devfile status command tests", func() { - var namespace, context, cmpName string - var commonVar helper.CommonVar - // Using program commmand according to cliRunner in devfile - cliRunner := helper.GetCliRunner() - - // This is run after every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - SetDefaultEventuallyTimeout(5 * time.Minute) - cmpName = helper.RandString(6) - namespace = commonVar.Project - context = commonVar.Context - helper.Chdir(commonVar.Context) - }) - - // Clean up after the test - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - //Function used to test context: "Verify URL status is correctly reported" - testCombo := func(ingress bool, secure bool, name string) { - defer GinkgoRecover() - It("Verify that odo component status detects the URL status: "+name, func() { - openshift := os.Getenv("KUBERNETES") != "true" - if !ingress && !openshift { - Skip("Route-based URLs is an OpenShift only scenario") - } - urlHost := helper.RandString(12) + ".com" - - urlParams := []string{"url", "create", "my-url", "--port", "3000"} - if secure { - urlParams = append(urlParams, "--secure") - } - - if ingress { - urlParams = append(urlParams, "--ingress") - urlParams = append(urlParams, "--host", urlHost) - } - - helper.Cmd("odo", urlParams...).ShouldPass() - - helper.Cmd("odo", "push", "-o", "json", "--project", namespace).ShouldPass() - - session := helper.CmdRunner("odo", "component", "status", "-o", "json", "--project", namespace, "--follow") - - helper.WaitForOutputToContain("urlReachable", 180, 10, session) - - stdoutContents := string(session.Out.Contents()) - - entries, err := utils.ParseMachineEventJSONLines(stdoutContents) - Expect(err).NotTo(HaveOccurred()) - - // Verify url status is present and correct - urlReachableEntry := utils.GetMostRecentEventOfType(machineoutput.TypeURLReachable, entries, true).(*machineoutput.URLReachable) - - expectedKind := "ingress" - if !ingress || openshift { - expectedKind = "route" - } - - Expect(urlReachableEntry.Kind).To(Equal(expectedKind)) - Expect(urlReachableEntry.Reachable).To(Equal(!ingress || openshift)) // On non-openshift, the ingress URL is using a random hostname, so should not be resolveable - Expect(urlReachableEntry.Port).To(Equal(3000)) - Expect(urlReachableEntry.Secure).To(Equal(secure)) - - utils.TerminateSession(session) - - }) - } - - When("Creating nodejs component using devfile", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "--project", namespace, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context) - }) - testCombo(false, false, "Route Nonsecure") - testCombo(true, false, "Ingress Nonsecure") - // testCombo(false, true, "Route Secure") # Commented until issue https://github.com/redhat-developer/odo/issues/5217 gets fixed - // testCombo(true, true, "Ingress Secure") # Commented until issue https://github.com/redhat-developer/odo/issues/5217 gets fixed - - When("doing odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "-o", "json", "--project", namespace).ShouldPass() - }) - It("Verify that odo component status correctly reports supervisord status", func() { - - session := helper.CmdRunner("odo", "component", "status", "-o", "json", "--project", namespace, "--follow") - - helper.WaitForOutputToContain("supervisordStatus", 180, 10, session) - - stdoutContents := string(session.Out.Contents()) - - entries, err := utils.ParseMachineEventJSONLines(stdoutContents) - Expect(err).NotTo(HaveOccurred()) - - // Verify supervisord status is present and correct - supervisordEntry := utils.GetMostRecentEventOfType(machineoutput.TypeSupervisordStatus, entries, true).(*machineoutput.SupervisordStatus) - count := 0 - for _, status := range supervisordEntry.ProgramStatus { - if status.Program == string(common.DefaultDevfileRunCommand) { - Expect(status.Status).To(Equal("RUNNING")) - } else if status.Program == string(common.DefaultDevfileDebugCommand) { - Expect(status.Status).To(Equal("STOPPED")) - } else { - Fail(fmt.Sprintf("Unexpected program: %v", status.Program)) - } - count++ - } - Expect(count).To(Equal(2)) - - // Kill the node processes within the container, returns true when complete - Eventually(func() bool { - podName := cliRunner.GetRunningPodNameByComponent(cmpName, namespace) - - contents := helper.GetCliRunner().Exec(podName, namespace, "--", "ps", "-ef") - - pids := []string{} - for _, str := range strings.Split(contents, "\n") { - - if strings.Contains(str, "node") || strings.Contains(str, "npm") { - - fields := strings.Fields(str) - if len(fields) >= 2 { - pids = append(pids, fields[1]) - } - } - } - - for _, pid := range pids { - helper.GetCliRunner().Exec(podName, namespace, "--", "kill", "-9", pid) - } - - // We expect (at least) 2 node processes - return len(pids) >= 2 - - }, 180, 10).Should(Equal(true)) - - // Wait for 'odo component status' to report that the programs are no longer RUNNING (EXITED or STOPPED) - Eventually(func() bool { - stdoutContents := string(session.Out.Contents()) - entries, err := utils.ParseMachineEventJSONLines(stdoutContents) - if err != nil { - return false - } - - supervisordStatus := utils.GetMostRecentEventOfType(machineoutput.TypeSupervisordStatus, entries, false).(*machineoutput.SupervisordStatus) - if supervisordStatus == nil { - return false - } - - // All programs should be stopped, because we killed the node processes - for _, programStatus := range supervisordStatus.ProgramStatus { - if programStatus.Status == "RUNNING" { - return false - } - } - - return true - }, 180, 10).Should(Equal(true)) - - utils.TerminateSession(session) - - }) - - It("Verify that odo component status correctly detects component Kubernetes pods", func() { - - session := helper.CmdRunner("odo", "component", "status", "-o", "json", "--project", namespace, "--follow") - - // Returns true if 'odo component status' correctly reported the status of the expected pod, false otherwise - Eventually(func() bool { - - stdoutContents := string(session.Out.Contents()) - entries, err := utils.ParseMachineEventJSONLines(stdoutContents) - if err != nil { - return false - } - - statusEntry := utils.GetMostRecentEventOfType(machineoutput.TypeKubernetesPodStatus, entries, false) - - if statusEntry == nil { - return false - } - - podStatus := statusEntry.(*machineoutput.KubernetesPodStatus) - - // Check if a pod is running and correct, returns "" if success, otherwise returns the reason why not - checkPod := func(pod machineoutput.KubernetesPodStatusEntry) string { - if len(pod.StartTime) == 0 { - return "StartTime is empty" - } - - if pod.Phase != "Running" { - return "Phase is not running" - } - - match := false - for _, labelValue := range pod.Labels { - if labelValue == cmpName { - match = true - break - } - } - if !match { - return "No matching labels" - } - - match = false - for _, container := range pod.Containers { - if container.Name == "runtime" && container.State.Running != nil { - match = true - break - } - } - if !match { - return "Could not find runtime container" - } - return "" - } // end checkpod - - for _, pod := range podStatus.Pods { - failReason := checkPod(pod) - if failReason == "" { - return true - } - fmt.Println("pod", pod.Name, "did not satisfy condition:", failReason) - } - - return false - }, 180, 10).Should(Equal(true)) - - // Delete the old pod, so that we can confirm that we can find the new one - oldPodName := cliRunner.GetRunningPodNameByComponent(cmpName, namespace) - cliRunner.DeletePod(oldPodName, namespace) - - // Returns true if we correctly found the new pod that was launched by k8s after we deleted the old pod, false otherwise - Eventually(func() bool { - - stdoutContents := string(session.Out.Contents()) - entries, err := utils.ParseMachineEventJSONLines(stdoutContents) - if err != nil { - return false - } - - statusEntry := utils.GetMostRecentEventOfType(machineoutput.TypeKubernetesPodStatus, entries, false) - - if statusEntry == nil { - return false - } - - podStatus := statusEntry.(*machineoutput.KubernetesPodStatus) - - // Check if a pod is running and correct, and different from the old pod; returns "" if success, otherwise returns the reason why not - checkPod := func(pod machineoutput.KubernetesPodStatusEntry) string { - - if pod.Name == oldPodName { - return "Skipping old pod" - } - - if pod.Phase != "Running" { - return "Phase is not running" - } - - match := false - for _, labelValue := range pod.Labels { - if labelValue == cmpName { - match = true - break - } - } - if !match { - return "No matching labels" - } - - match = false - for _, container := range pod.Containers { - if container.Name == "runtime" && container.State.Running != nil { - match = true - break - } - } - if !match { - return "Could not find runtime container" - } - return "" - } // end checkPod - - for _, pod := range podStatus.Pods { - failReason := checkPod(pod) - if failReason == "" { - return true - } - fmt.Println("Pod", pod.Name, "did not satisfy condition:", failReason) - } - - return false - }, 180, 10).Should(Equal(true)) - - utils.TerminateSession(session) - - }) // end It - }) - }) - -}) diff --git a/tests/integration/devfile/cmd_devfile_storage_test.go b/tests/integration/devfile/cmd_devfile_storage_test.go deleted file mode 100644 index 9d6e0ff23..000000000 --- a/tests/integration/devfile/cmd_devfile_storage_test.go +++ /dev/null @@ -1,439 +0,0 @@ -package devfile - -import ( - "path/filepath" - "sort" - "strings" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/pkg/util" - "github.com/redhat-developer/odo/tests/helper" - "github.com/tidwall/gjson" -) - -var _ = Describe("odo devfile storage command tests", func() { - var cmpName string - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - cmpName = helper.RandString(6) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - When("creating a nodejs component", func() { - - BeforeEach(func() { - helper.Cmd("odo", "create", cmpName, "--context", commonVar.Context, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - }) - - It("should throw error if no storage is present", func() { - helper.Cmd("odo", "storage", "delete", helper.RandString(5), "--context", commonVar.Context, "-f").ShouldFail() - }) - - It("should fail if trying to create an ephemeral storage with devfile 2.0.0", func() { - stderr := helper.Cmd("odo", "storage", "create", "--ephemeral", "--context", commonVar.Context).ShouldFail().Err() - Expect(stderr).To(ContainSubstring(`Version of devfile is "2.0.0", should be at least "2.1.0" to use --ephemeral flag`)) - }) - - When("ephemeral is set to true in preference.yaml and doing odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "preference", "set", "ephemeral", "true").ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should not create a pvc to store source code", func() { - // Verify the pvc size - PVCs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project) - - Expect(len(PVCs)).To(Equal(0)) - output := commonVar.CliRunner.GetVolumeNamesFromDeployment(cmpName, "app", commonVar.Project) - value, ok := output["odo-projects"] - Expect(ok).To(BeTrue()) - Expect(value).Should(Equal(("emptyDir"))) - }) - }) - - When("ephemeral is set to false in preference.yaml and doing odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "preference", "set", "ephemeral", "false").ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should create a pvc to store source code", func() { - // Verify the pvc size - PVCs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project) - - Expect(len(PVCs)).To(Not(Equal(0))) - - output := commonVar.CliRunner.GetVolumeNamesFromDeployment(cmpName, "app", commonVar.Project) - found := false - for key, value := range output { - if key == "odo-projects" { - if len(PVCs) > 0 && value == PVCs[0] { - found = true - break - } - } - } - Expect(found).To(BeTrue()) - Expect(len(output)).To(Equal(2)) - - helper.Cmd("odo", "delete", "-f", "--context", commonVar.Context).ShouldPass() - - // check if the owner reference is set on the source code PVC properly or not - commonVar.CliRunner.WaitAndCheckForTerminatingState("pvc", commonVar.Project, 1) - }) - }) - - When("storage create command is executed", func() { - storageNames := []string{helper.RandString(5), helper.RandString(5)} - pathNames := []string{"/data", "/" + storageNames[1]} - sizes := []string{"5Gi", "1Gi"} - BeforeEach(func() { - helper.Cmd("odo", "storage", "create", storageNames[0], "--path", pathNames[0], "--size", sizes[0], "--context", commonVar.Context).ShouldPass() - }) - - It("should error if same path or same storage is provided again", func() { - By("same path is provided again", func() { - helper.Cmd("odo", "storage", "create", storageNames[1], "--path", pathNames[0], "--size", sizes[1], "--context", commonVar.Context).ShouldFail() - }) - By("same storage is provided again", func() { - helper.Cmd("odo", "storage", "create", storageNames[0], "--path", pathNames[1], "--size", sizes[1], "--context", commonVar.Context).ShouldFail() - }) - }) - - It("should list output in json format", func() { - actualStorageList := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context, "-o", "json").ShouldPass().Out() - valuesSL := gjson.GetMany(actualStorageList, "kind", "items.0.kind", "items.0.metadata.name", "items.0.spec.size", "items.0.spec.path", "items.0.spec.containerName", "items.0.status") - expectedSL := []string{"List", "Storage", storageNames[0], sizes[0], pathNames[0], "runtime", "Not Pushed"} - Expect(helper.GjsonMatcher(valuesSL, expectedSL)).To(Equal(true)) - }) - - It("should list storage in not pushed state", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{storageNames[0], pathNames[0], sizes[0], "Not Pushed", cmpName}) - helper.DontMatchAllInOutput(stdOut, []string{"CONTAINER", "runtime"}) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should list storage in pushed state", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{storageNames[0], pathNames[0], sizes[0], "Pushed"}) - helper.DontMatchAllInOutput(stdOut, []string{"CONTAINER", "runtime"}) - }) - - When("creating new storage", func() { - BeforeEach(func() { - helper.Cmd("odo", "storage", "create", storageNames[1], "--path", pathNames[1], "--size", sizes[1], "--context", commonVar.Context).ShouldPass() - }) - - It("should list storage in correct state", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{storageNames[0], pathNames[0], sizes[0], "Pushed"}) - helper.MatchAllInOutput(stdOut, []string{storageNames[1], pathNames[1], sizes[1], "Not Pushed"}) - helper.DontMatchAllInOutput(stdOut, []string{"CONTAINER", "runtime"}) - }) - When("deleting pushed storage", func() { - BeforeEach(func() { - helper.Cmd("odo", "storage", "delete", storageNames[0], "-f", "--context", commonVar.Context).ShouldPass() - }) - - It("should list it as locally deleted", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{storageNames[0], pathNames[0], sizes[0], "Locally Deleted"}) - helper.DontMatchAllInOutput(stdOut, []string{"CONTAINER", "runtime"}) - }) - - When("doing odo push, odo delete -f", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "delete", "-f", "--context", commonVar.Context).ShouldPass() - // since we don't have `wait` for `odo delete` at this moment - // we need to wait for the pod to be in the terminating state or it has been deleted from the cluster - commonVar.CliRunner.WaitAndCheckForTerminatingState("pods", commonVar.Project, 1) - }) - It("should list storage with correct state", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"Not Pushed"}) - // since `Pushed` is a sub string of `Not Pushed`, we count the occurrence of `Pushed` - count := strings.Count(stdOut, "Pushed") - Expect(count).To(Equal(1)) - }) - }) - }) - - When("pushing the new storage", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should mount it on the container with correct path and size", func() { - volumesMatched := 0 - - // check the volume name and mount paths for the containers - deploymentName, err := util.NamespaceKubernetesObject(cmpName, "app") - Expect(err).To(BeNil()) - volNamesAndPaths := commonVar.CliRunner.GetVolumeMountNamesandPathsFromContainer(deploymentName, "runtime", commonVar.Project) - volNamesAndPathsArr := strings.Fields(volNamesAndPaths) - for _, volNamesAndPath := range volNamesAndPathsArr { - volNamesAndPathArr := strings.Split(volNamesAndPath, ":") - - for i, storageName := range storageNames { - if strings.Contains(volNamesAndPathArr[0], storageName) && volNamesAndPathArr[1] == pathNames[i] { - volumesMatched++ - } - } - } - - Expect(volumesMatched).To(Equal(2)) - - for i, storageName := range storageNames { - // Verify the pvc size - storageSize := commonVar.CliRunner.GetPVCSize(cmpName, storageName, commonVar.Project) - Expect(storageSize).To(ContainSubstring(sizes[i])) - } - }) - }) - }) - - When("creating with output as json format", func() { - var values []gjson.Result - BeforeEach(func() { - actualJSONStorage := helper.Cmd("odo", "storage", "create", "mystorage", "--path=/opt/app-root/src/storage/", "--size=1Gi", "--context", commonVar.Context, "-o", "json").ShouldPass().Out() - values = gjson.GetMany(actualJSONStorage, "kind", "metadata.name", "spec.size", "spec.path") - }) - It("should create storage", func() { - expected := []string{"Storage", "mystorage", "1Gi", "/opt/app-root/src/storage/"} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - }) - When("doing storage delete with output as json", func() { - BeforeEach(func() { - deleteJSONStorage := helper.Cmd("odo", "storage", "delete", "mystorage", "--context", commonVar.Context, "-o", "json").ShouldPass().Out() - values = gjson.GetMany(deleteJSONStorage, "kind", "status", "message", "details.name", "details.kind") - - }) - It("should delete storage", func() { - deleteExpected := []string{"Status", "Success", "Deleted storage", "mystorage", "Storage"} - Expect(helper.GjsonMatcher(values, deleteExpected)).To(Equal(true)) - }) - }) - }) - }) - }) - - When("ephemeral is not set in preference.yaml", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - value := helper.GetPreferenceValue("Ephemeral") - Expect(value).To(BeEmpty()) - }) - It("should not create a pvc to store source code (default is ephemeral=true)", func() { - helper.Cmd("odo", "preference", "view").ShouldPass().Out() - - // Verify the pvc size - PVCs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project) - - Expect(len(PVCs)).To(Equal(0)) - - output := commonVar.CliRunner.GetVolumeNamesFromDeployment(cmpName, "app", commonVar.Project) - - value, found := output["odo-projects"] - Expect(found).To(BeTrue()) - Expect(value).Should(Equal("emptyDir")) - }) - }) - - When("creating storage without --size and pushed", func() { - storageName := helper.RandString(5) - BeforeEach(func() { - helper.Cmd("odo", "storage", "create", storageName, "--path", "/data", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should create a storage with default size", func() { - // Verify the pvc size - storageSize := commonVar.CliRunner.GetPVCSize(cmpName, storageName, commonVar.Project) - Expect(storageSize).To(ContainSubstring("1Gi")) - }) - }) - - When("creating storage without storage name and pushed", func() { - BeforeEach(func() { - helper.Cmd("odo", "storage", "create", "--path", "/data", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should create a storage", func() { - // Verify the pvc size - PVCs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project) - Expect(len(PVCs)).To(Equal(1)) - }) - }) - }) - - When("creating the storage with proper states and container names set in the devfile", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", cmpName, "--context", commonVar.Context, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-volume-components.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - - }) - - It("should list the storage with the proper states and container names", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"firstvol", "secondvol", "/secondvol", "/data", "/data2", "Not Pushed", "CONTAINER", "runtime", "runtime2"}) - }) - - When("doing odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should list the storage with the proper states and container names", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"firstvol", "secondvol", "/secondvol", "/data", "/data2", "Pushed", "CONTAINER", "runtime", "runtime2"}) - }) - - When("deleting storage push and doing storage list", func() { - BeforeEach(func() { - helper.Cmd("odo", "storage", "delete", "firstvol", "-f", "--context", commonVar.Context).ShouldPass() - }) - - It("should list the storage with the proper states and container names", func() { - stdOut := helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"firstvol", "secondvol", "/secondvol", "/data", "/data2", "Pushed", "Locally Deleted", "CONTAINER", "runtime", "runtime2"}) - }) - }) - }) - }) - - When("creating a springboot component", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", cmpName, "--context", commonVar.Context, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "springboot", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "springboot", "project"), commonVar.Context) - }) - When("creating storage ", func() { - - var storageList string - storageName := helper.RandString(5) - pathName := "/data1" - size := "1Gi" - - BeforeEach(func() { - helper.Cmd("odo", "storage", "create", storageName, "--path", pathName, "--context", commonVar.Context, "--container", "tools", "--size", size).ShouldPass() - - }) - It("should list the storage attached to the specified container", func() { - storageList = helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(storageList, []string{pathName, "tools", storageName, size}) - }) - When("doing odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should list the storage attached to the specified container", func() { - storageList = helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(storageList, []string{pathName, "tools", storageName}) - // check the volume name and mount paths for the funtime container - deploymentName, err := util.NamespaceKubernetesObject(cmpName, "app") - Expect(err).To(BeNil()) - - volumesMatched := 0 - volNamesAndPaths := commonVar.CliRunner.GetVolumeMountNamesandPathsFromContainer(deploymentName, "tools", commonVar.Project) - volNamesAndPathsArr := strings.Fields(volNamesAndPaths) - for _, volNamesAndPath := range volNamesAndPathsArr { - volNamesAndPathArr := strings.Split(volNamesAndPath, ":") - if strings.Contains(volNamesAndPathArr[0], storageName) && volNamesAndPathArr[1] == pathName { - volumesMatched++ - } - } - Expect(volumesMatched).To(Equal(1)) - - // check the volume name and mount path Not present in runtime container - volumesMatched = 0 - volNamesAndPaths = commonVar.CliRunner.GetVolumeMountNamesandPathsFromContainer(deploymentName, "runtime", commonVar.Project) - volNamesAndPathsArr = strings.Fields(volNamesAndPaths) - for _, volNamesAndPath := range volNamesAndPathsArr { - volNamesAndPathArr := strings.Split(volNamesAndPath, ":") - if strings.Contains(volNamesAndPathArr[0], storageName) && volNamesAndPathArr[1] == pathName { - volumesMatched++ - } - } - Expect(volumesMatched).To(Equal(0)) - }) - - When("deleting storage and doing odo push", func() { - - BeforeEach(func() { - helper.Cmd("odo", "storage", "delete", "-f", "--context", commonVar.Context, storageName).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should list the deleted storage with odo list", func() { - storageList = helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.DontMatchAllInOutput(storageList, []string{pathName, "tools", storageName, size}) - }) - It("should be able to create and push storage at same path", func() { - storageName2 := helper.RandString(5) - helper.Cmd("odo", "storage", "create", storageName2, "--path", pathName, "--context", commonVar.Context, "--container", "runtime", "--size", size).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - }) - }) - }) - }) - - When("creating a nodejs component with devfile v2.1.0 and two storages, one persistent and one ephemeral", func() { - - BeforeEach(func() { - helper.Cmd("odo", "create", cmpName, "--context", commonVar.Context, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-2.1.0.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - - helper.Cmd("odo", "storage", "create", "ephemeral-storage", "--ephemeral", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "storage", "create", "persistent-storage", "--context", commonVar.Context).ShouldPass() - }) - - When("ephemeral is set to true in preference.yaml and run odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "preference", "set", "ephemeral", "true").ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should create only one PVC", func() { - pvcs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project) - Expect(len(pvcs)).To(Equal(1)) - Expect(pvcs[0]).To(ContainSubstring("persistent-storage")) - podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - bufferOutput := commonVar.CliRunner.Run("get", "pods", podName, "-o", `jsonpath='{.spec.volumes[?(@.name=="ephemeral-storage")]}'`).Out.Contents() - Expect(string(bufferOutput)).To(ContainSubstring("emptyDir")) - bufferOutput = commonVar.CliRunner.Run("get", "pods", podName, "-o", `jsonpath='{.spec.volumes[?(@.name=="odo-projects")]}'`).Out.Contents() - Expect(string(bufferOutput)).To(ContainSubstring("emptyDir")) - }) - }) - - When("ephemeral is set to false in preference.yaml and run odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "preference", "set", "ephemeral", "false").ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should create only two PVCs (one for odo-project volume, one for persistent volume)", func() { - pvcs := commonVar.CliRunner.GetAllPVCNames(commonVar.Project) - Expect(len(pvcs)).To(Equal(2)) - sort.Strings(pvcs) - Expect(pvcs[0]).To(ContainSubstring("odo-projects")) - Expect(pvcs[1]).To(ContainSubstring("persistent-storage")) - podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - bufferOutput := commonVar.CliRunner.Run("get", "pods", podName, "-o", `jsonpath='{.spec.volumes[?(@.name=="ephemeral-storage")]}'`).Out.Contents() - Expect(string(bufferOutput)).To(ContainSubstring("emptyDir")) - }) - }) - }) -}) diff --git a/tests/integration/devfile/cmd_devfile_test_test.go b/tests/integration/devfile/cmd_devfile_test_test.go deleted file mode 100644 index 96eeef605..000000000 --- a/tests/integration/devfile/cmd_devfile_test_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package devfile - -import ( - "path/filepath" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/tests/helper" -) - -var _ = Describe("odo devfile test command tests", func() { - var cmpName string - var sourcePath = "/projects" - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - cmpName = helper.RandString(6) - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - It("should error out on devfile flag", func() { - helper.Cmd("odo", "test", "--devfile", "invalid.yaml", "--context", commonVar.Context).ShouldFail() - }) - - When("Create a nodejs component", func() { - BeforeEach(func() { - helper.Cmd("odo", "create", "--context", commonVar.Context, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-testgroup.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - }) - - It("should show error if component is not pushed", func() { - output := helper.Cmd("odo", "test", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("error occurred while getting the pod: pod not found for the selector")) - }) - - When("doing odo push", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should error out if a non-existent command or a command from wrong group is specified", func() { - By("should error out if a non-existent command", func() { - output := helper.Cmd("odo", "test", "--test-command", "invalidcmd", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("not found in the devfile")) - }) - By("a command from wrong group is specified", func() { - output := helper.Cmd("odo", "test", "--test-command", "devrun", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("command devrun is of group run in devfile.yaml")) - }) - }) - - It("Should run test command successfully with only one default specified", func() { - output := helper.Cmd("odo", "test", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{"Executing test1 command", "mkdir test1"}) - - podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath) - Expect(output).To(ContainSubstring("test1")) - }) - - It("Should run test command successfully with test-command specified", func() { - output := helper.Cmd("odo", "test", "--test-command", "test2", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{"Executing test2 command", "mkdir test2"}) - - podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath) - Expect(output).To(ContainSubstring("test2")) - }) - - It("Should run composite test command successfully", func() { - output := helper.Cmd("odo", "test", "--test-command", "compositetest", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{"Executing test1 command", "mkdir test1", "Executing test2 command", "mkdir test2"}) - - podName := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - output = commonVar.CliRunner.ExecListDir(podName, commonVar.Project, sourcePath) - helper.MatchAllInOutput(output, []string{"test1", "test2"}) - }) - }) - - When("removing default command from devfile", func() { - BeforeEach(func() { - helper.ReplaceString(filepath.Join(commonVar.Context, "devfile.yaml"), "isDefault: true", "") - }) - - When("doing odo push", func() { - output := "" - BeforeEach(func() { - output = helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldFail().Err() - }) - It("push should fail", func() { - Expect(output).To(ContainSubstring("command group test warning - there should be exactly one default command, currently there is no default command")) - }) - It("should show error if devfile has no default test command", func() { - output := helper.Cmd("odo", "test", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("command group test warning - there should be exactly one default command, currently there is no default command")) - }) - }) - }) - - When("using devfile that doesn't contains group of kind \"test\" and doing odo push", func() { - BeforeEach(func() { - helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(commonVar.Context, "devfile.yaml")) - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should show error if no test group is defined", func() { - output := helper.Cmd("odo", "test", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("the command group of kind \"test\" is not found in the devfile")) - }) - }) - - When("devfile has multiple default test command", func() { - BeforeEach(func() { - helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-multiple-defaults.yaml"), filepath.Join(commonVar.Context, "devfile.yaml")) - }) - - It("should show error if devfile has multiple default test command", func() { - By("should fail on odo push", func() { - output := helper.Cmd("odo", "push", "--build-command", "firstbuild", "--run-command", "secondrun", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("command group test error - there should be exactly one default command, currently there are multiple default commands")) - }) - By("should fail on odo test", func() { - output := helper.Cmd("odo", "test", "--context", commonVar.Context).ShouldFail().Err() - Expect(output).To(ContainSubstring("command group test error - there should be exactly one default command, currently there are multiple default commands")) - }) - }) - }) - }) - -}) diff --git a/tests/integration/devfile/cmd_devfile_watch_test.go b/tests/integration/devfile/cmd_devfile_watch_test.go index 57685206d..ac1fed087 100644 --- a/tests/integration/devfile/cmd_devfile_watch_test.go +++ b/tests/integration/devfile/cmd_devfile_watch_test.go @@ -242,17 +242,14 @@ var _ = Describe("odo devfile watch command tests", func() { StringsToBeMatched: []string{"Executing devbuild command", "Executing debugrun command"}, } // odo watch and validate if we can port forward successfully - utils.OdoWatchWithDebug(odoV2Watch, commonVar.Context, watchFlag) + // utils.OdoWatchWithDebug(odoV2Watch, commonVar.Context, watchFlag) // check the --debug-command flag - watchFlag = "--debug-command debug" odoV2Watch.StringsToBeMatched = []string{"Executing debug command"} // odo watch and validate if we can port forward successfully - utils.OdoWatchWithDebug(odoV2Watch, commonVar.Context, watchFlag) + // utils.OdoWatchWithDebug(odoV2Watch, commonVar.Context, watchFlag) - // revert to normal odo push - watchFlag = "" output := helper.Cmd("odo", "push", "--project", commonVar.Project).ShouldPass().Out() Expect(output).To(ContainSubstring("Changes successfully pushed to component")) diff --git a/tests/integration/devfile/cmd_dot_devfile_test.go b/tests/integration/devfile/cmd_dot_devfile_test.go index 8ccbefd66..eaf7b2819 100644 --- a/tests/integration/devfile/cmd_dot_devfile_test.go +++ b/tests/integration/devfile/cmd_dot_devfile_test.go @@ -1,13 +1,9 @@ package devfile import ( - "fmt" "path/filepath" - "regexp" - "strings" . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" //We continued iterating on bracket pair guides. Horizontal lines now outline the scope of a bracket pair. Also, vertical lines now depend on the indentation of the code that is surrounded by the bracket pair.. "github.com/onsi/gomega" "github.com/redhat-developer/odo/tests/helper" @@ -60,110 +56,5 @@ var _ = Describe("Test suits to check .devfile.yaml compatibility", func() { }) }) }) - - When("creating a storage", func() { - var storageName, pathName, size, stdOut string - BeforeEach(func() { - storageName = helper.RandString(5) - pathName = "/data" - size = "5Gi" - helper.Cmd("odo", "storage", "create", storageName, "--path", pathName, "--size", size, "--context", commonVar.Context).ShouldPass() - }) - It("should list the storage with the proper states and container names", func() { - stdOut = helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{storageName, pathName, size, "Not Pushed", cmpName}) - }) - When("doing odo push with storage", func() { - - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - It("should list the storage with the proper states and container names", func() { - stdOut = helper.Cmd("odo", "storage", "list", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{storageName, pathName, "Pushed", cmpName}) - }) - }) - }) - }) - - When("creating and pushing with --debug a nodejs component with debhug run", func() { - var projectDir string - BeforeEach(func() { - projectDir = filepath.Join(commonVar.Context, "projectDir") - helper.CopyExample(filepath.Join("source", "web-nodejs-sample"), projectDir) - helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--context", projectDir, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-debugrun.yaml")).ShouldPass() - helper.Cmd("pwd").ShouldPass() - helper.Cmd("mv", fmt.Sprint(projectDir, "/devfile.yaml"), fmt.Sprint(projectDir, "/.devfile.yaml")).ShouldPass() - helper.Cmd("odo", "push", "--debug", "--context", projectDir).ShouldPass() - }) - It("should log debug command output", func() { - output := helper.Cmd("odo", "log", "--debug", "--context", projectDir).ShouldPass().Out() - Expect(output).To(ContainSubstring("ODO_COMMAND_DEBUG")) - }) - }) - - When("Creating a nodejs component and replace devfile.yaml with .devfile.yaml", func() { - var _ = BeforeEach(func() { - helper.Cmd("odo", "create", "--project", commonVar.Project, cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - helper.Cmd("mv", "devfile.yaml", ".devfile.yaml").ShouldPass() - }) - When("creating a service", func() { - var redisOperator string - var operandName string - var odoArgs []string - var operators []string - BeforeEach(func() { - odoArgs = []string{"catalog", "list", "services"} - operators = []string{"redis-operator"} - for _, operator := range operators { - helper.WaitForCmdOut("odo", odoArgs, 5, true, func(output string) bool { - return strings.Contains(output, operator) - }) - } - commonVar.CliRunner.CreateSecret("redis-secret", "password", commonVar.Project) - operators := helper.Cmd("odo", "catalog", "list", "services").ShouldPass().Out() - redisOperator = regexp.MustCompile(`redis-operator\.*[a-z][0-9]\.[0-9]\.[0-9]`).FindString(operators) - operandName = helper.RandString(10) - helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), operandName, "--context", commonVar.Context).ShouldPass() - }) - - AfterEach(func() { - helper.Cmd("odo", "service", "delete", fmt.Sprintf("Redis/%s", operandName), "-f", "--context", commonVar.Context).ShouldPass().Out() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out() - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out() - name := commonVar.CliRunner.GetRunningPodNameByComponent(cmpName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should find files in component container", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass() - }) - - It("should create pods in running state", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, fmt.Sprintf(`%s-0`, operandName)) - }) - - It("should list the service", func() { - stdOut := helper.Cmd("odo", "service", "list", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("Redis/%s", operandName))) - }) - - When("a link between the component and the service is created", func() { - - BeforeEach(func() { - helper.Cmd("odo", "link", fmt.Sprintf("Redis/%s", operandName), "--context", commonVar.Context).ShouldPass() - }) - - It("should run odo push successfully", func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - }) - }) - }) }) }) diff --git a/tests/integration/devfile/debug/cmd_devfile_debug_test.go b/tests/integration/devfile/debug/cmd_devfile_debug_test.go deleted file mode 100644 index c30428c10..000000000 --- a/tests/integration/devfile/debug/cmd_devfile_debug_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package debug - -import ( - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/redhat-developer/odo/pkg/envinfo" - "github.com/redhat-developer/odo/pkg/testingutil" - "github.com/redhat-developer/odo/tests/helper" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -// since during parallel runs of cmd devfile debug, the port might be occupied by the other tests -// we execute these tests serially -var _ = Describe("odo devfile debug command serial tests", func() { - - var componentName, projectDirPath string - var projectDir = "/projectDir" - - var commonVar helper.CommonVar - - // This is run before every Spec (It) - var _ = BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - componentName = helper.RandString(6) - helper.Chdir(commonVar.Context) - projectDirPath = commonVar.Context + projectDir - }) - - // This is run after every Spec (It) - var _ = AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - It("should auto-select a local debug port when the given local port is occupied for a devfile component", func() { - helper.MakeDir(projectDirPath) - helper.Chdir(projectDirPath) - - helper.Cmd("odo", "create", "--project", commonVar.Project, componentName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-with-debugrun.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), projectDirPath) - helper.Cmd("odo", "push", "--debug").ShouldPass() - - stopChannel := make(chan bool) - go func() { - helper.Cmd("odo", "debug", "port-forward").WithTerminate(60*time.Second, stopChannel).ShouldRun() - }() - - stopListenerChan := make(chan bool) - startListenerChan := make(chan bool) - listenerStarted := false - go func() { - defer GinkgoRecover() - err := testingutil.FakePortListener(startListenerChan, stopListenerChan, envinfo.DefaultDebugPort) - if err != nil { - close(startListenerChan) - Expect(err).Should(BeNil()) - } - }() - // wait for the test server to start listening - if <-startListenerChan { - listenerStarted = true - } - - freePort := "" - helper.WaitForCmdOut("odo", []string{"debug", "info"}, 1, false, func(output string) bool { - if strings.Contains(output, "Debug is running") { - splits := strings.SplitN(output, ":", 2) - Expect(len(splits)).To(Equal(2)) - freePort = strings.TrimSpace(splits[1]) - _, err := strconv.Atoi(freePort) - Expect(err).NotTo(HaveOccurred()) - return true - } - return false - }) - - // 400 response expected because the endpoint expects a websocket request and we are doing a HTTP GET - // We are just using this to validate if nodejs agent is listening on the other side - helper.HttpWaitForWithStatus("http://localhost:"+freePort, "WebSockets request was expected", 12, 5, 400) - stopChannel <- true - if listenerStarted == true { - stopListenerChan <- true - } else { - close(stopListenerChan) - } - }) -}) diff --git a/tests/integration/operatorhub/cmd_link_test.go b/tests/integration/operatorhub/cmd_link_test.go deleted file mode 100644 index 5ddb65fdd..000000000 --- a/tests/integration/operatorhub/cmd_link_test.go +++ /dev/null @@ -1,463 +0,0 @@ -package integration - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/tests/helper" -) - -var _ = Describe("odo link command tests for OperatorHub", func() { - - var commonVar helper.CommonVar - var redisServiceName = "redis" - - BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - }) - - AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - Context("Operators are installed in the cluster", func() { - - var redisOperator string - var redisCluster string - - BeforeEach(func() { - // wait till odo can see that all operators installed by setup script in the namespace - odoArgs := []string{"catalog", "list", "services"} - operators := []string{"redis-operator"} - for _, operator := range operators { - helper.WaitForCmdOut("odo", odoArgs, 5, true, func(output string) bool { - return strings.Contains(output, operator) - }) - } - - commonVar.CliRunner.CreateSecret("redis-secret", "password", commonVar.Project) - list := helper.Cmd("odo", "catalog", "list", "services").ShouldPass().Out() - redisOperator = regexp.MustCompile(`redis-operator\.*[a-z][0-9]\.[0-9]\.[0-9]`).FindString(list) - redisCluster = fmt.Sprintf("%s/Redis", redisOperator) - }) - - When("a component and a service are deployed", func() { - - var componentName string - var svcFullName string - var serviceName string - - BeforeEach(func() { - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - componentName = "cmp-" + helper.RandString(6) - helper.Cmd("odo", "create", componentName, "--context", commonVar.Context, "--project", commonVar.Project, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - helper.Cmd("odo", "config", "set", "Memory", "300M", "-f", "--context", commonVar.Context).ShouldPass() - - serviceName = "service" + helper.RandString(6) - svcFullName = strings.Join([]string{"Redis", serviceName}, "/") - helper.Cmd("odo", "service", "create", redisCluster, serviceName, "--context", commonVar.Context).ShouldPass() - - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should find files in component container", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass() - }) - - When("a storage is added and deployed", func() { - BeforeEach(func() { - helper.Cmd("odo", "storage", "create", "--context", commonVar.Context).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - When("a link between the component and the service is created", func() { - - BeforeEach(func() { - helper.Cmd("odo", "link", svcFullName, "--context", commonVar.Context).ShouldPass() - }) - - It("should run odo push successfully", func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - }) - }) - - When("a link between the component and the service is created", func() { - - BeforeEach(func() { - helper.Cmd("odo", "link", svcFullName, "--context", commonVar.Context).ShouldPass() - }) - - It("should find the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - }) - - It("should not insert the link definition in devfile.yaml when the inlined flag is not used", func() { - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"inlined", "ServiceBinding"} - helper.DontMatchAllInOutput(string(content), matchInOutput) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should find files in component container", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass() - }) - - It("should find the link environment variable", func() { - stdOut := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "sh", "-c", "echo $REDIS_CLUSTERIP").ShouldPass().Out() - Expect(stdOut).To(Not(BeEmpty())) - }) - - It("should find the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - Expect(stdOut).To(ContainSubstring("Environment Variables")) - Expect(stdOut).To(ContainSubstring("REDIS_CLUSTERIP")) - }) - - It("should not list the service binding in `odo service list`", func() { - stdOut := helper.Cmd("odo", "service", "list", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).ToNot(ContainSubstring("ServiceBinding/")) - }) - }) - }) - - When("a link with between the component and the service is created with --bind-as-files", func() { - - var bindingName string - BeforeEach(func() { - bindingName = "sbr-" + helper.RandString(6) - helper.Cmd("odo", "link", svcFullName, "--bind-as-files", "--name", bindingName, "--context", commonVar.Context).ShouldPass() - }) - - It("should display the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - }) - - It("should not insert the link definition in devfile.yaml when the inlined flag is not used", func() { - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"inlined", "Redis", "redis", "ServiceBinding"} - helper.DontMatchAllInOutput(string(content), matchInOutput) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should find files in component container", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass() - }) - - It("should find bindings for service", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/bindings/"+bindingName+"/clusterIP").ShouldPass() - }) - - It("should display the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - Expect(stdOut).To(ContainSubstring("Files")) - Expect(stdOut).To(ContainSubstring("/bindings/" + bindingName + "/clusterIP")) - }) - }) - }) - - When("a link between the component and the service is created inline", func() { - - BeforeEach(func() { - helper.Cmd("odo", "link", svcFullName, "--context", commonVar.Context, "--inlined").ShouldPass() - }) - - It("should insert service definition in devfile.yaml when the inlined flag is used", func() { - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"kubernetes", "inlined", "ServiceBinding"} - helper.MatchAllInOutput(string(content), matchInOutput) - }) - - It("should find the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should find the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - Expect(stdOut).To(ContainSubstring("Environment Variables")) - Expect(stdOut).To(ContainSubstring("REDIS_CLUSTERIP")) - }) - }) - }) - - When("a link with between the component and the service is created with --bind-as-files and --inlined", func() { - - var bindingName string - BeforeEach(func() { - bindingName = "sbr-" + helper.RandString(6) - helper.Cmd("odo", "link", svcFullName, "--bind-as-files", "--name", bindingName, "--context", commonVar.Context, "--inlined").ShouldPass() - }) - - It("should insert service definition in devfile.yaml when the inlined flag is used", func() { - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"kubernetes", "inlined", "Redis", "redis", "ServiceBinding"} - helper.MatchAllInOutput(string(content), matchInOutput) - }) - - It("should display the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should display the link in odo describe", func() { - stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(svcFullName)) - Expect(stdOut).To(ContainSubstring("Files")) - Expect(stdOut).To(ContainSubstring("/bindings/" + bindingName + "/clusterIP")) - }) - }) - }) - - When("a link is created and custom binding data is being injected with --map", func() { - var imageMapping string - var imageMappingValue = "image=quay.io/opstree/redis:v6.2.5" - - BeforeEach(func() { - imageMapping = fmt.Sprintf("image={{ .%s.spec.kubernetesConfig.image }}", serviceName) - }) - - When("no additional flag other than --map is passed to odo link", func() { - BeforeEach(func() { - helper.Cmd("odo", "link", svcFullName, "--context", commonVar.Context, "--map", "key=value", "--map", imageMapping).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should have created the mappings correctly", func() { - stdOut := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "env").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"key=value", imageMappingValue}) - }) - }) - - When("--inlined flag is passed to odo link", func() { - BeforeEach(func() { - helper.Cmd("odo", "link", svcFullName, "--inlined", "--context", commonVar.Context, "--map", "key=value", "--map", imageMapping).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - }) - - It("should have created the mappings correctly", func() { - stdOut := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "env").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"key=value", imageMappingValue}) - }) - }) - - When("--bind-as-files flag is used along with --map", func() { - BeforeEach(func() { - helper.Cmd("odo", "link", svcFullName, "--bind-as-files", "--context", commonVar.Context, "--map", "key=value", "--map", imageMapping).ShouldPass() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - // change the imageMappingValue variable here because we're going to "cat" the file (named after our key) content (contains our value as content) - imageMappingValue = "quay.io/opstree/redis:v6.2.5" - }) - - It("should have created the mappings correctly", func() { - stdOut := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "cat", "/bindings/"+componentName+"-redis-"+serviceName+"/image").ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(imageMappingValue)) - stdOut = helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "cat", "/bindings/"+componentName+"-redis-"+serviceName+"/key").ShouldPass().Out() - Expect(stdOut).To(ContainSubstring("value")) - }) - }) - }) - }) - - When("getting sources, a devfile defining a component, a service and a link, and executing odo push", func() { - - BeforeEach(func() { - componentName := "api" // this is the name of the component in the devfile - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-link.yaml"), filepath.Join(commonVar.Context, "devfile.yaml")) - helper.Cmd("odo", "create", componentName, "--project", commonVar.Project, "--context", commonVar.Context).ShouldPass() - - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass() - name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project) - Expect(name).To(Not(BeEmpty())) - }) - - It("should find files in component container", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass() - }) - - It("should find bindings for service", func() { - helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/bindings/redis-link/clusterIP").ShouldPass() - }) - - // Removed from issue https://github.com/redhat-developer/odo/issues/5084 - XIt("should find owner references on link and service", func() { - if os.Getenv("KUBERNETES") == "true" { - Skip("This is a OpenShift specific scenario, skipping") - } - args := []string{"get", "servicebinding", "redis-link", "-o", "jsonpath='{.metadata.ownerReferences.*.name}'", "-n", commonVar.Project} - commonVar.CliRunner.WaitForRunnerCmdOut(args, 1, true, func(output string) bool { - return strings.Contains(output, "api-app") - }) - - args = []string{"get", "redis.redis.redis.opstreelabs.in", "myredis", "-o", "jsonpath='{.metadata.ownerReferences.*.name}'", "-n", commonVar.Project} - commonVar.CliRunner.WaitForRunnerCmdOut(args, 1, true, func(output string) bool { - return strings.Contains(output, "api-app") - }) - }) - }) - }) - - When("one component is deployed", func() { - var context0 string - var cmp0 string - - BeforeEach(func() { - context0 = helper.CreateNewContext() - cmp0 = helper.RandString(5) - - helper.Cmd("odo", "create", cmp0, "--context", context0, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context0) - - helper.Cmd("odo", "push", "--context", context0).ShouldPass() - }) - - AfterEach(func() { - helper.Cmd("odo", "delete", "-f", "--context", context0).ShouldPass() - helper.DeleteDir(context0) - }) - - It("should fail when linking to itself", func() { - stdOut := helper.Cmd("odo", "link", cmp0, "--context", context0).ShouldFail().Err() - helper.MatchAllInOutput(stdOut, []string{cmp0, "cannot be linked with itself"}) - }) - - It("should fail if the component doesn't exist and the service name doesn't adhere to the / format", func() { - helper.Cmd("odo", "link", "Redis").ShouldFail() - helper.Cmd("odo", "link", "Redis/").ShouldFail() - helper.Cmd("odo", "link", fmt.Sprintf("/%s", redisServiceName)).ShouldFail() - }) - - When("another component is deployed", func() { - var context1 string - var cmp1 string - - BeforeEach(func() { - context1 = helper.CreateNewContext() - cmp1 = helper.RandString(5) - - helper.Cmd("odo", "create", cmp1, "--context", context1, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfileNestedCompCommands.yaml")).ShouldPass() - - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context1) - - helper.Cmd("odo", "push", "--context", context1).ShouldPass() - }) - - AfterEach(func() { - helper.Cmd("odo", "delete", "-f", "--context", context1).ShouldPass() - helper.DeleteDir(context1) - }) - - // Removed from issue https://github.com/redhat-developer/odo/issues/5084 - XIt("should link the two components successfully with service binding operator", func() { - - if os.Getenv("KUBERNETES") == "true" { - // service binding operator is not installed on kubernetes - Skip("This is a OpenShift specific scenario, skipping") - } - - helper.Cmd("odo", "link", cmp1, "--context", context0).ShouldPass() - helper.Cmd("odo", "push", "--context", context0).ShouldPass() - - // check the link exists with the specific name - ocArgs := []string{"get", "servicebinding", strings.Join([]string{cmp0, cmp1}, "-"), "-o", "jsonpath='{.status.secret}'", "-n", commonVar.Project} - helper.WaitForCmdOut("oc", ocArgs, 1, true, func(output string) bool { - return strings.Contains(output, strings.Join([]string{cmp0, cmp1}, "-")) - }) - - // delete the link and undeploy it - helper.Cmd("odo", "unlink", cmp1, "--context", context0).ShouldPass() - helper.Cmd("odo", "push", "--context", context0).ShouldPass() - commonVar.CliRunner.WaitAndCheckForTerminatingState("servicebinding", commonVar.Project, 1) - }) - - It("should link the two components successfully without service binding operator", func() { - - if os.Getenv("KUBERNETES") != "true" { - // service binding operator is not installed on kubernetes - Skip("This is a Kubernetes specific scenario, skipping") - } - - helper.Cmd("odo", "link", cmp1, "--context", context0).ShouldPass() - helper.Cmd("odo", "push", "--context", context0).ShouldPass() - - // check the secrets exists with the specific name - secrets := commonVar.CliRunner.GetSecrets(commonVar.Project) - Expect(secrets).To(ContainSubstring(fmt.Sprintf("%v-%v", cmp0, cmp1))) - - envFromValues := commonVar.CliRunner.GetEnvRefNames(cmp0, "app", commonVar.Project) - envFound := false - for i := range envFromValues { - if strings.Contains(envFromValues[i], fmt.Sprintf("%v-%v", cmp0, cmp1)) { - envFound = true - } - } - Expect(envFound).To(BeTrue()) - - // delete the link and undeploy it - helper.Cmd("odo", "unlink", cmp1, "--context", context0).ShouldPass() - helper.Cmd("odo", "push", "--context", context0).ShouldPass() - - // check the secrets exists with the specific name - secrets = commonVar.CliRunner.GetSecrets(commonVar.Project) - Expect(secrets).NotTo(ContainSubstring(fmt.Sprintf("%v-%v", cmp0, cmp1))) - envFromValues = commonVar.CliRunner.GetEnvRefNames(cmp0, "app", commonVar.Project) - envFound = false - for i := range envFromValues { - if strings.Contains(envFromValues[i], fmt.Sprintf("%v-%v", cmp0, cmp1)) { - envFound = true - } - } - Expect(envFound).To(BeFalse()) - }) - }) - }) -}) diff --git a/tests/integration/operatorhub/cmd_service_test.go b/tests/integration/operatorhub/cmd_service_test.go deleted file mode 100644 index 1a7e5052c..000000000 --- a/tests/integration/operatorhub/cmd_service_test.go +++ /dev/null @@ -1,742 +0,0 @@ -package integration - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "regexp" - "strings" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/redhat-developer/odo/pkg/util" - "github.com/redhat-developer/odo/tests/helper" - "github.com/tidwall/gjson" -) - -var _ = Describe("odo service command tests for OperatorHub", func() { - - var commonVar helper.CommonVar - var redisServiceName = "redis" - - BeforeEach(func() { - commonVar = helper.CommonBeforeEach() - helper.Chdir(commonVar.Context) - }) - - AfterEach(func() { - helper.CommonAfterEach(commonVar) - }) - - Context("Operators are installed in the cluster", func() { - - BeforeEach(func() { - // wait till odo can see that all operators installed by setup script in the namespace - odoArgs := []string{"catalog", "list", "services"} - operators := []string{"redis-operator"} - for _, operator := range operators { - helper.WaitForCmdOut("odo", odoArgs, 5, true, func(output string) bool { - return strings.Contains(output, operator) - }) - } - }) - - It("should not allow creating service without valid context", func() { - stdOut := helper.Cmd("odo", "service", "create").ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("service can be created/deleted from a valid component directory only")) - }) - - Context("a specific operator is installed", func() { - var redisOperator string - var redisCluster string - - BeforeEach(func() { - commonVar.CliRunner.CreateSecret("redis-secret", "password", commonVar.Project) - operators := helper.Cmd("odo", "catalog", "list", "services").ShouldPass().Out() - redisOperator = regexp.MustCompile(`redis-operator\.*[a-z][0-9]\.[0-9]\.[0-9]`).FindString(operators) - redisCluster = fmt.Sprintf("%s/Redis", redisOperator) - }) - - It("should describe operator without crd with human readable output", func() { - output := helper.Cmd("odo", "catalog", "describe", "service", redisOperator).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{ - "redis-operator", "NAME", "DESCRIPTION", "CRDs", "RedisCluster", "Redis", - }) - }) - - It("should describe operator without crd in machine readable format", func() { - outputJSON := helper.Cmd("odo", "catalog", "describe", "service", redisOperator, "-o", "json").ShouldPass().Out() - displayName := gjson.Get(outputJSON, "spec.displayName") - Expect(displayName).To(ContainSubstring("Redis Operator")) - }) - - It("should describe the operator with human-readable output", func() { - output := helper.Cmd("odo", "catalog", "describe", "service", redisCluster).ShouldPass().Out() - Expect(output).To(MatchRegexp("KIND: *Redis")) - Expect(output).To(MatchRegexp(`redisExporter\.image *\(string\) *-required-`)) - }) - - It("should describe the example of the operator", func() { - output := helper.Cmd("odo", "catalog", "describe", "service", redisCluster, "--example").ShouldPass().Out() - Expect(output).To(ContainSubstring("kind: Redis")) - helper.MatchAllInOutput(output, []string{"apiVersion", "kind"}) - }) - - It("should describe the example of the operator as json", func() { - outputJSON := helper.Cmd("odo", "catalog", "describe", "service", redisCluster, "--example", "-o", "json").ShouldPass().Out() - value := gjson.Get(outputJSON, "spec.kind") - Expect(value.String()).To(Equal("Redis")) - }) - - It("should describe the operator with json output", func() { - outputJSON := helper.Cmd("odo", "catalog", "describe", "service", redisCluster, "-o", "json").ShouldPass().Out() - values := gjson.GetMany(outputJSON, "spec.kind", "spec.displayName", "spec.schema.type", "spec.schema.properties.redisExporter.properties.image.type") - expected := []string{"Redis", "Redis", "object", "string"} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - }) - - It("should find the services by keyword", func() { - stdOut := helper.Cmd("odo", "catalog", "search", "service", "redis").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"redis-operator", "Redis"}) - - stdOut = helper.Cmd("odo", "catalog", "search", "service", "Redis").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"redis-operator", "Redis"}) - - stdOut = helper.Cmd("odo", "catalog", "search", "service", "dummy").ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("no service matched the query: dummy")) - }) - - It("should list the operator in JSON output", func() { - jsonOut := helper.Cmd("odo", "catalog", "list", "services", "-o", "json").ShouldPass().Out() - helper.MatchAllInOutput(jsonOut, []string{"redis-operator"}) - }) - - When("a nodejs component is created", func() { - - var cmpName string - BeforeEach(func() { - cmpName = helper.RandString(4) - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - helper.Cmd("odo", "create", cmpName, "--devfile", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-registry.yaml")).ShouldPass() - helper.Cmd("odo", "config", "set", "Memory", "300M", "-f").ShouldPass() - }) - - It("should fail for interactive mode", func() { - stdOut := helper.Cmd("odo", "service", "create").ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("odo doesn't support interactive mode for creating Operator backed service")) - }) - - It("should define the CR output of the operator instance in dryRun mode", func() { - stdOut := helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), "--dry-run", "--project", commonVar.Project).ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{"apiVersion", "kind"}) - }) - - It("should fail creating a service with wrong parameters", func() { - helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), "-p", "a=b").ShouldFail() - }) - - It("should create a service with parameters of different types", func() { - helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), - "-p", "kubernetesConfig.image=quay.io/opstree/redis:v6.2.5", - "-p", "kubernetesConfig.imagePullPolicy=IfNotPresent", - "-p", "kubernetesConfig.serviceType=ClusterIP", - "-p", "redisExporter.enabled=false", - "-p", "redisExporter.image=quay.io/opstree/redis-exporter:1.0", - "-p", "securityContext.runAsUser=1000").ShouldPass() - }) - - It("should try to create a service in dry run mode with some provided params", func() { - serviceName := helper.RandString(10) - output := helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), serviceName, - "-p", "kubernetesConfig.image=quay.io/opstree/redis:v6.2.5", - "-p", "redisExporter.image=quay.io/opstree/redis-exporter:1.0", - "-p", "kubernetesConfig.serviceType=ClusterIP", - "-p", "kubernetesConfig.resources.requests.cpu=100m", - "-p", "kubernetesConfig.resources.requests.memory=128Mi", - "--dry-run", "--context", commonVar.Context).ShouldPass().Out() - helper.MatchAllInOutput(output, []string{fmt.Sprintf("name: %s", serviceName), "quay.io/opstree/redis:v6.2.5", "ClusterIP", "100m", "128Mi"}) - }) - - When("creating a Redis operand with params", func() { - var operandName string - - BeforeEach(func() { - operandName = helper.RandString(10) - helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), operandName, - "-p", "kubernetesConfig.image=quay.io/opstree/redis:v6.2.5", - "-p", "redisExporter.image=quay.io/opstree/redis-exporter:1.0", - "-p", "kubernetesConfig.serviceType=ClusterIP", - "-p", "kubernetesConfig.resources.requests.cpu=100m", - "-p", "kubernetesConfig.resources.requests.memory=128Mi", - "--context", commonVar.Context).ShouldPass().Out() - - }) - - AfterEach(func() { - helper.Cmd("odo", "service", "delete", fmt.Sprintf("Redis/%s", operandName), "-f", "--context", commonVar.Context).ShouldPass().Out() - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out() - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out() - }) - - It("should create pods in running state", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, fmt.Sprintf(`%s-0`, operandName)) - }) - - It("should list the service", func() { - stdOut := helper.Cmd("odo", "service", "list", "--context", commonVar.Context).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("Redis/%s", operandName))) - }) - }) - - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should fail if the provided service doesn't exist in the namespace", func() { - stdOut := helper.Cmd("odo", "link", fmt.Sprintf("Redis/%s", redisServiceName)).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("couldn't find service named %q", fmt.Sprintf("Redis/%s", redisServiceName))) - }) - }) - - When("a Redis instance definition copied from example file", func() { - - var fileName string - - BeforeEach(func() { - randomFileName := helper.RandString(6) + ".yaml" - fileName = filepath.Join(os.TempDir(), randomFileName) - helper.CopyExampleFile(filepath.Join("operators", "redis.yaml"), filepath.Join(fileName)) - }) - - AfterEach(func() { - os.Remove(fileName) - }) - - When("a service is created from the output of the dryRun command with no name and odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "service", "create", "--from-file", fileName, "--project", commonVar.Project).ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - AfterEach(func() { - helper.Cmd("odo", "service", "delete", fmt.Sprintf("Redis/%s", redisServiceName), "-f").ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should create pods in running state", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, `redis.[a-z0-9-]*`) - }) - }) - - When("a service is created from the output of the dryRun command with a specific name and odo push is executed", func() { - - var name string - var svcFullName string - BeforeEach(func() { - name = helper.RandString(6) - svcFullName = strings.Join([]string{"Redis", name}, "/") - helper.Cmd("odo", "service", "create", "--from-file", fileName, name, "--project", commonVar.Project).ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - AfterEach(func() { - helper.Cmd("odo", "service", "delete", svcFullName, "-f").ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should fail to create a service again with the same name", func() { - stdOut := helper.Cmd("odo", "service", "create", "--from-file", fileName, name, "--project", commonVar.Project).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("please provide a different name or delete the existing service first")) - }) - - It("should create pods in running state", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, name+`-.[a-z0-9-]*`) - }) - }) - }) - - When("a Redis instance is created with no name and inlined flag is used", func() { - var stdOut string - BeforeEach(func() { - stdOut = helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), "--project", commonVar.Project, "--inlined").ShouldPass().Out() - Expect(stdOut).To(ContainSubstring("Successfully added service to the configuration")) - }) - - It("should insert service definition in devfile.yaml when the inlined flag is used", func() { - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"kubernetes", "inlined", "Redis", "redis"} - helper.MatchAllInOutput(string(content), matchInOutput) - }) - - It("should list the service in JSON format", func() { - jsonOut := helper.Cmd("odo", "service", "list", "-o", "json").ShouldPass().Out() - helper.MatchAllInOutput(jsonOut, []string{"\"apiVersion\": \"redis.redis.opstreelabs.in/v1beta1\"", "\"kind\": \"Redis\"", "\"name\": \"redis\""}) - }) - - When("odo push is executed", func() { - - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should create pods in running state", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, `redis.[a-z0-9-]*`) - }) - - It("should list the service", func() { - // now test listing of the service using odo - stdOut = helper.Cmd("odo", "service", "list").ShouldPass().Out() - Expect(stdOut).To(ContainSubstring("Redis/redis")) - }) - - It("should list the service in JSON format", func() { - jsonOut := helper.Cmd("odo", "service", "list", "-o", "json").ShouldPass().Out() - helper.MatchAllInOutput(jsonOut, []string{"\"apiVersion\": \"redis.redis.opstreelabs.in/v1beta1\"", "\"kind\": \"Redis\"", "\"name\": \"redis\""}) - }) - - When("a link is created with the service", func() { - BeforeEach(func() { - stdOut = helper.Cmd("odo", "link", "Redis/redis").ShouldPass().Out() - }) - - It("should display a successful message", func() { - Expect(stdOut).To(ContainSubstring("Successfully created link between component")) - }) - - It("Should fail to link it again", func() { - stdOut = helper.Cmd("odo", "link", "Redis/redis").ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("already linked with the service")) - }) - - When("the link is deleted", func() { - BeforeEach(func() { - stdOut = helper.Cmd("odo", "unlink", "Redis/redis").ShouldPass().Out() - }) - - It("should display a successful message", func() { - Expect(stdOut).To(ContainSubstring("Successfully unlinked component")) - }) - - It("should fail to delete it again", func() { - stdOut = helper.Cmd("odo", "unlink", "Redis/redis").ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("failed to unlink the service")) - }) - }) - }) - - When("the service is deleted", func() { - BeforeEach(func() { - helper.Cmd("odo", "service", "delete", "Redis/redis", "-f").ShouldPass() - }) - - It("should delete service definition from devfile.yaml", func() { - // read the devfile.yaml to check if service definition was deleted - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"kubernetes", "inlined", "Redis", "redis"} - helper.DontMatchAllInOutput(string(content), matchInOutput) - }) - - It("should fail to delete the service again", func() { - stdOut = helper.Cmd("odo", "service", "delete", "Redis/redis", "-f").ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("couldn't find service named")) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("Should fail listing the services", func() { - out := helper.Cmd("odo", "service", "list").ShouldFail().Err() - msg := fmt.Sprintf("no operator backed services found in namespace: %s", commonVar.Project) - Expect(out).To(ContainSubstring(msg)) - }) - - It("Should fail listing the services in JSON format", func() { - jsonOut := helper.Cmd("odo", "service", "list", "-o", "json").ShouldFail().Err() - msg := fmt.Sprintf("no operator backed services found in namespace: %s", commonVar.Project) - msgWithQuote := fmt.Sprintf("\"message\": \"no operator backed services found in namespace: %s\"", commonVar.Project) - helper.MatchAllInOutput(jsonOut, []string{msg, msgWithQuote}) - }) - }) - }) - - When("a second service is created and odo push is executed", func() { - BeforeEach(func() { - stdOut = helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), "myredis2", "--project", commonVar.Project).ShouldPass().Out() - Expect(stdOut).To(ContainSubstring("Successfully added service to the configuration")) - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should list both services", func() { - stdOut = helper.Cmd("odo", "service", "list").ShouldPass().Out() - // first service still here - Expect(stdOut).To(ContainSubstring("Redis/redis")) - // second service created - Expect(stdOut).To(ContainSubstring("Redis/myredis2")) - }) - }) - }) - }) - - When("a Redis instance is created with a specific name", func() { - - var name string - var svcFullName string - - BeforeEach(func() { - name = helper.RandString(6) - svcFullName = strings.Join([]string{"Redis", name}, "/") - helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), name, "--project", commonVar.Project).ShouldPass() - }) - - AfterEach(func() { - helper.Cmd("odo", "service", "delete", svcFullName, "-f").ShouldRun() - }) - - It("should not insert service definition in devfile.yaml when the inlined flag is not used", func() { - devfilePath := filepath.Join(commonVar.Context, "devfile.yaml") - content, err := ioutil.ReadFile(devfilePath) - Expect(err).To(BeNil()) - matchInOutput := []string{"redis", "Redis", "inlined"} - helper.DontMatchAllInOutput(string(content), matchInOutput) - }) - - It("should be listed as Not pushed", func() { - stdOut := helper.Cmd("odo", "service", "list").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{svcFullName, "Not pushed"}) - }) - - When("odo push is executed", func() { - - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should create pods in running state", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, name+`-.[a-z0-9-]*`) - }) - - It("should fail to create a service again with the same name", func() { - stdOut := helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), name, "--project", commonVar.Project).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring(fmt.Sprintf("service %q already exists", svcFullName))) - }) - - It("should be listed as Pushed", func() { - stdOut := helper.Cmd("odo", "service", "list").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{svcFullName, "Pushed"}) - }) - - When("the redisCluster instance is deleted", func() { - BeforeEach(func() { - helper.Cmd("odo", "service", "delete", svcFullName, "-f").ShouldPass() - }) - - It("should be listed as Deleted locally", func() { - stdOut := helper.Cmd("odo", "service", "list").ShouldPass().Out() - helper.MatchAllInOutput(stdOut, []string{svcFullName, "Deleted locally"}) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should not be listed anymore", func() { - stdOut := helper.Cmd("odo", "service", "list").ShouldRun().Out() - Expect(strings.Contains(stdOut, svcFullName)).To(BeFalse()) - }) - }) - }) - - When("a link is created with a specific name", func() { - - var linkName string - - BeforeEach(func() { - linkName = "link-" + helper.RandString(6) - helper.Cmd("odo", "link", "Redis/"+name, "--name", linkName).ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - AfterEach(func() { - // delete the link - helper.Cmd("odo", "unlink", "Redis/"+name).ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should create the link with the specified name", func() { - envFromValues := commonVar.CliRunner.GetEnvRefNames(cmpName, "app", commonVar.Project) - envFound := false - for i := range envFromValues { - if strings.Contains(envFromValues[i], linkName) { - envFound = true - } - } - Expect(envFound).To(BeTrue()) - }) - }) - - When("a link is created with a specific name and bind-as-files flag", func() { - - var linkName string - - BeforeEach(func() { - linkName = "link-" + helper.RandString(6) - helper.Cmd("odo", "link", "Redis/"+name, "--name", linkName, "--bind-as-files").ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - AfterEach(func() { - // delete the link - helper.Cmd("odo", "unlink", "Redis/"+name).ShouldPass() - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should create a link with bindAsFiles set to true", func() { - // check the volume name and mount paths for the container - deploymentName, err := util.NamespaceKubernetesObject(cmpName, "app") - if err != nil { - Expect(err).To(BeNil()) - } - volNamesAndPaths := commonVar.CliRunner.GetVolumeMountNamesandPathsFromContainer(deploymentName, "runtime", commonVar.Project) - mountFound := false - volNamesAndPathsArr := strings.Fields(volNamesAndPaths) - for _, volNamesAndPath := range volNamesAndPathsArr { - volNamesAndPathArr := strings.Split(volNamesAndPath, ":") - if strings.Contains(volNamesAndPathArr[0], linkName) { - mountFound = true - } - } - Expect(mountFound).To(BeTrue()) - }) - }) - }) - }) - - When("a Redis instance is created with a specific name and json output", func() { - - var name string - var svcFullName string - var output string - - testServiceInfo := func(serviceName string, text string) { - values := gjson.GetMany(text, "kind", "metadata.name", "manifest.kind", "manifest.metadata.name") - expected := []string{"Service", "Redis/" + serviceName, "Redis", serviceName} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - } - - testClusterInfo := func(serviceName string, text string, inDevfile bool, deployed bool) { - - values := gjson.GetMany(text, "inDevfile", "deployed") - expected := []string{fmt.Sprintf("%v", inDevfile), fmt.Sprintf("%v", deployed)} - Expect(helper.GjsonMatcher(values, expected)).To(Equal(true)) - - tsValue := gjson.Get(text, "manifest.metadata.creationTimestamp") - if deployed { - Expect(tsValue.Str).NotTo(BeEmpty()) - } else { - Expect(tsValue.Str).To(BeEmpty()) - } - } - - BeforeEach(func() { - name = helper.RandString(6) - svcFullName = strings.Join([]string{"Redis", name}, "/") - output = helper.Cmd("odo", "service", "create", fmt.Sprintf("%s/Redis", redisOperator), name, "--project", commonVar.Project, "-o", "json").ShouldPass().Out() - }) - - AfterEach(func() { - helper.Cmd("odo", "service", "delete", svcFullName, "-f").ShouldRun() - }) - - It("should display valid information in output of create command", func() { - By("displaying service information", func() { - testServiceInfo(name, output) - }) - - By("not containing cluster specific information", func() { - testClusterInfo(name, output, true, false) - }) - }) - - When("executing odo service describe", func() { - var descOutput string - BeforeEach(func() { - descOutput = helper.Cmd("odo", "service", "describe", "Redis/"+name, "--project", commonVar.Project, "-o", "json").ShouldPass().Out() - }) - - It("should display valid information in output of create command", func() { - By("displaying service information", func() { - testServiceInfo(name, descOutput) - }) - - By("not containing cluster specific information", func() { - testClusterInfo(name, descOutput, true, false) - }) - }) - }) - - When("odo push is executed", func() { - - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - When("executing odo service describe", func() { - var descOutput string - BeforeEach(func() { - descOutput = helper.Cmd("odo", "service", "describe", "Redis/"+name, "--project", commonVar.Project, "-o", "json").ShouldPass().Out() - }) - - It("should display valid information in output of create command", func() { - By("displaying service information", func() { - testServiceInfo(name, descOutput) - }) - - By("containing cluster specific information", func() { - testClusterInfo(name, descOutput, true, true) - }) - }) - }) - - When("service is deleted from devfile", func() { - BeforeEach(func() { - helper.Cmd("odo", "service", "delete", "Redis/"+name, "--project", commonVar.Project, "-f").ShouldPass() - }) - - When("executing odo service describe", func() { - var descOutput string - BeforeEach(func() { - descOutput = helper.Cmd("odo", "service", "describe", "Redis/"+name, "--project", commonVar.Project, "-o", "json").ShouldPass().Out() - }) - - It("should display valid information in output of create command", func() { - By("displaying service information", func() { - testServiceInfo(name, descOutput) - }) - - By("containing cluster specific information", func() { - testClusterInfo(name, descOutput, false, true) - }) - }) - }) - - When("odo push is executed", func() { - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should not describe the service anymore", func() { - helper.Cmd("odo", "service", "describe", "Redis/"+name, "--project", commonVar.Project, "-o", "json").ShouldFail() - }) - }) - }) - }) - }) - - Context("Invalid service templates exist", func() { - - var tmpContext string - var noMetaFileName string - var invalidFileName string - - BeforeEach(func() { - tmpContext = helper.CreateNewContext() - - // TODO write helpers to create such files - noMetadata := ` -apiVersion: redis.redis.opstreelabs.in/v1beta1 -kind: Redis -spec:` - noMetaFile := helper.RandString(6) + ".yaml" - noMetaFileName = filepath.Join(tmpContext, noMetaFile) - if err := ioutil.WriteFile(noMetaFileName, []byte(noMetadata), 0644); err != nil { - fmt.Printf("Could not write yaml spec to file %s because of the error %v", noMetaFileName, err.Error()) - } - - invalidMetadata := ` -apiVersion: redis.redis.opstreelabs.in/v1beta1 -kind: Redis -metadata: - noname: noname -spec:` - invalidMetaFile := helper.RandString(6) + ".yaml" - invalidFileName = filepath.Join(tmpContext, invalidMetaFile) - if err := ioutil.WriteFile(invalidFileName, []byte(invalidMetadata), 0644); err != nil { - fmt.Printf("Could not write yaml spec to file %s because of the error %v", invalidFileName, err.Error()) - } - - }) - - AfterEach(func() { - helper.DeleteDir(tmpContext) - }) - - It("should fail to create a service based on a template without metadata", func() { - stdOut := helper.Cmd("odo", "service", "create", "--from-file", noMetaFileName, "--project", commonVar.Project).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("invalid \"metadata\" in the yaml; provide a valid \"metadata.name\"")) - }) - - It("should fail to create a service based on a template with invalid metadata", func() { - stdOut := helper.Cmd("odo", "service", "create", "--from-file", invalidFileName, "--project", commonVar.Project).ShouldFail().Err() - Expect(stdOut).To(ContainSubstring("invalid \"metadata\" in the yaml; provide a valid \"metadata.name\"")) - }) - }) - Context("Operator present in devfile is not installed on the cluster", func() { - BeforeEach(func() { - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-pod.yaml"), filepath.Join(commonVar.Context, "devfile.yaml")) - }) - - When("listing service and pushing the component", func() { - It("should show the service in devfile in 'odo service list'", func() { - // this test case helps check if odo can list services that are present in devfile but the corresponding - // Operator is not installed on the cluster - out := helper.Cmd("odo", "service", "list").ShouldPass().Out() - Expect(out).To(ContainSubstring("EtcdCluster/etcdcluster")) - }) - It("should fail to push since the Operator doesn't exist on the cluster", func() { - err := helper.Cmd("odo", "push").ShouldFail().Err() - helper.MatchAllInOutput(err, []string{"Failed to start component with name", "please install corresponding Operator(s)", "EtcdCluster"}) - }) - }) - - When("deleting service", func() { - BeforeEach(func() { - helper.Cmd("odo", "service", "delete", "EtcdCluster/etcdcluster", "-f").ShouldPass() - }) - - It("should not show the service in devfile in 'odo service list'", func() { - // below command will fail as the underlying devfile doesn't have any services any more - err := helper.Cmd("odo", "service", "list").ShouldFail().Err() - Expect(err).ToNot(ContainSubstring("EtcdCluster/etcdcluster")) - }) - - When("odo push is executed, nginx pod should be created on the cluster", func() { - BeforeEach(func() { - helper.Cmd("odo", "push").ShouldPass() - }) - - It("should have pod in Running state on the cluster", func() { - commonVar.CliRunner.PodsShouldBeRunning(commonVar.Project, `nginx`) - }) - }) - }) - }) - }) - }) - }) -}) diff --git a/tests/integration/operatorhub/operatorhub_suite_test.go b/tests/integration/operatorhub/operatorhub_suite_test.go deleted file mode 100644 index 295194048..000000000 --- a/tests/integration/operatorhub/operatorhub_suite_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package integration_test - -import ( - "testing" - - "github.com/redhat-developer/odo/tests/helper" -) - -func TestOperatorhub(t *testing.T) { - helper.RunTestSpecs(t, "Operatorhub Suite") -}