diff --git a/pkg/odo/cli/deploy/deploy.go b/pkg/odo/cli/deploy/deploy.go index da0168f074a..c62868b56bc 100644 --- a/pkg/odo/cli/deploy/deploy.go +++ b/pkg/odo/cli/deploy/deploy.go @@ -4,6 +4,7 @@ import ( "context" "fmt" dfutil "github.com/devfile/library/v2/pkg/util" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/component" "github.com/redhat-developer/odo/pkg/log" @@ -63,6 +64,9 @@ func (o *DeployOptions) Validate(ctx context.Context) error { if devfileObj == nil { return genericclioptions.NewNoDevfileError(odocontext.GetWorkingDirectory(ctx)) } + if o.clientset.KubernetesClient == nil { + return kclient.NewNoConnectionError() + } componentName := odocontext.GetComponentName(ctx) err := dfutil.ValidateK8sResourceName("component name", componentName) return err @@ -85,6 +89,8 @@ func (o *DeployOptions) Run(ctx context.Context) error { "Namespace: "+namespace, "odo version: "+version.VERSION) + genericclioptions.WarnIfDefaultNamespace(namespace, o.clientset.KubernetesClient) + // Run actual deploy command to be used err := o.clientset.DeployClient.Deploy(ctx) diff --git a/pkg/odo/cli/dev/dev.go b/pkg/odo/cli/dev/dev.go index 43382929073..ea086ee9c79 100644 --- a/pkg/odo/cli/dev/dev.go +++ b/pkg/odo/cli/dev/dev.go @@ -157,7 +157,9 @@ func (o *DevOptions) Run(ctx context.Context) (err error) { log.Title("Developing using the \""+componentName+"\" Devfile", dest, "odo version: "+version.VERSION) - + if platform == commonflags.PlatformCluster { + genericclioptions.WarnIfDefaultNamespace(odocontext.GetNamespace(ctx), o.clientset.KubernetesClient) + } // check for .gitignore file and add odo-file-index.json to .gitignore. // In case the .gitignore was created by odo, it is purposely not reported as candidate for deletion (via a call to files.ReportLocalFileGeneratedByOdo) // because a .gitignore file is more likely to be modified by the user afterward (for another usage). diff --git a/pkg/odo/genericclioptions/util.go b/pkg/odo/genericclioptions/util.go index 839477f5a81..a068c7077e4 100644 --- a/pkg/odo/genericclioptions/util.go +++ b/pkg/odo/genericclioptions/util.go @@ -1,7 +1,11 @@ package genericclioptions import ( + "fmt" + "github.com/redhat-developer/odo/pkg/kclient" + "github.com/redhat-developer/odo/pkg/log" pkgUtil "github.com/redhat-developer/odo/pkg/util" + v1 "k8s.io/api/core/v1" dfutil "github.com/devfile/library/v2/pkg/util" ) @@ -34,3 +38,16 @@ func ApplyIgnore(ignores *[]string, sourcePath string) (err error) { return nil } + +// WarnIfDefaultNamespace warns when user tries to run `odo dev` or `odo deploy` in the default namespace +func WarnIfDefaultNamespace(namespace string, kubeClient kclient.ClientInterface) { + if namespace == v1.NamespaceDefault { + noun := "namespace" + if isOC, _ := kubeClient.IsProjectSupported(); isOC { + noun = "project" + } + fmt.Println() + log.Warningf("You are using \"default\" %[1]s, odo may not work as expected in the default %[1]s.", noun) + log.Warningf("You may set a new %[1]s by running `odo create %[1]s `, or set an existing one by running `odo set %[1]s `", noun) + } +} diff --git a/tests/helper/helper_dev.go b/tests/helper/helper_dev.go index d91711a9c2e..51d99f9ba28 100644 --- a/tests/helper/helper_dev.go +++ b/tests/helper/helper_dev.go @@ -255,18 +255,22 @@ func RunDevMode(options DevSessionOpts, inside func(session *gexec.Session, outC return nil } -// DevModeShouldFail runs `odo dev` with an intention to fail, and checks for a given substring +// WaitForDevModeToContain runs `odo dev` until it contains a given substring in output or errOut(depending on checkErrOut arg). // `odo dev` runs in an infinite reconciliation loop, and hence running it with Cmd will not work for a lot of failing cases, // this function is helpful in such cases. // TODO(pvala): Modify StartDevMode to take substring arg into account, and replace this method with it. -func DevModeShouldFail(options DevSessionOpts, substring string) (DevSession, []byte, []byte, error) { +func WaitForDevModeToContain(options DevSessionOpts, substring string, checkErrOut bool) (DevSession, []byte, []byte, error) { args := []string{"dev", "--random-ports"} args = append(args, options.CmdlineArgs...) if options.RunOnPodman { args = append(args, "--platform", "podman") } session := Cmd("odo", args...).AddEnv(options.EnvVars...).Runner().session - WaitForOutputToContain(substring, 360, 10, session) + if checkErrOut { + WaitForErroutToContain(substring, 360, 10, session) + } else { + WaitForOutputToContain(substring, 360, 10, session) + } result := DevSession{ session: session, } diff --git a/tests/helper/helper_generic.go b/tests/helper/helper_generic.go index ed9800ee834..ba6f9ada3d9 100644 --- a/tests/helper/helper_generic.go +++ b/tests/helper/helper_generic.go @@ -347,7 +347,11 @@ func RunTestSpecs(t *testing.T, description string) { } func IsKubernetesCluster() bool { - return os.Getenv("KUBERNETES") == "true" + k8s, err := strconv.ParseBool(os.Getenv("KUBERNETES")) + if err != nil { + return false + } + return k8s } type ResourceInfo struct { diff --git a/tests/integration/cmd_dev_test.go b/tests/integration/cmd_dev_test.go index 580f11594ef..37ed758cde0 100644 --- a/tests/integration/cmd_dev_test.go +++ b/tests/integration/cmd_dev_test.go @@ -61,13 +61,40 @@ var _ = Describe("odo dev command tests", func() { }) }) - When("a component is bootstrapped and pushed", func() { + When("a component is bootstrapped", func() { BeforeEach(func() { helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() Expect(helper.VerifyFileExists(".odo/env/env.yaml")).To(BeFalse()) }) + It("should fail to run odo dev when not connected to any cluster", Label(helper.LabelNoCluster), func() { + errOut := helper.Cmd("odo", "dev").ShouldFail().Err() + Expect(errOut).To(ContainSubstring("unable to access the cluster")) + }) + It("should fail to run odo dev when podman is nil", Label(helper.LabelPodman), func() { + errOut := helper.Cmd("odo", "dev", "--platform", "podman").WithEnv("PODMAN_CMD=echo").ShouldFail().Err() + Expect(errOut).To(ContainSubstring("unable to access podman")) + }) + When("using a default namespace", func() { + BeforeEach(func() { + commonVar.CliRunner.SetProject("default") + }) + AfterEach(func() { + commonVar.CliRunner.SetProject(commonVar.Project) + }) + It("should print warning about default namespace when running odo dev", func() { + namespace := "project" + if helper.IsKubernetesCluster() { + namespace = "namespace" + } + err := helper.RunDevMode(helper.DevSessionOpts{}, func(session *gexec.Session, outContents []byte, errContents []byte, ports map[string]string) { + Expect(string(errContents)).To(ContainSubstring(fmt.Sprintf("You are using \"default\" %[1]s, odo may not work as expected in the default %[1]s.", namespace))) + }) + Expect(err).ToNot(HaveOccurred()) + }) + }) + It("should add annotation to use ImageStreams", func() { // #6376 err := helper.RunDevMode(helper.DevSessionOpts{}, func(session *gexec.Session, outContents, errContents []byte, ports map[string]string) { @@ -1807,11 +1834,12 @@ CMD ["npm", "start"] }) It("should not build images when odo dev is run", func() { - _, sessionOut, _, err := helper.DevModeShouldFail( + _, sessionOut, _, err := helper.WaitForDevModeToContain( helper.DevSessionOpts{ EnvVars: env, }, - "failed to retrieve "+url) + "failed to retrieve "+url, + false) Expect(err).To(BeNil()) Expect(sessionOut).NotTo(ContainSubstring("build -t quay.io/unknown-account/myimage -f ")) Expect(sessionOut).NotTo(ContainSubstring("push quay.io/unknown-account/myimage")) @@ -2658,48 +2686,6 @@ CMD ["npm", "start"] })) } - Context("using Kubernetes cluster", func() { - BeforeEach(func() { - if os.Getenv("KUBERNETES") != "true" { - Skip("This is a Kubernetes specific scenario, skipping") - } - }) - - It("should run odo dev successfully on default namespace", func() { - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - - session, _, errContents, _, err := helper.StartDevMode(helper.DevSessionOpts{}) - Expect(err).ToNot(HaveOccurred()) - defer func() { - session.Stop() - session.WaitEnd() - }() - helper.DontMatchAllInOutput(string(errContents), []string{"odo may not work as expected in the default project"}) - }) - }) - - /* TODO(feloy) Issue #5591 - Context("using OpenShift cluster", func() { - BeforeEach(func() { - if os.Getenv("KUBERNETES") == "true" { - Skip("This is a OpenShift specific scenario, skipping") - } - }) - It("should run odo dev successfully on default namespace", func() { - helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) - helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile.yaml")).ShouldPass() - helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), commonVar.Context) - - session, _, errContents, err := helper.StartDevMode(helper.DevSessionOpts{}) - Expect(err).ToNot(HaveOccurred()) - defer session.Stop() - helper.MatchAllInOutput(string(errContents), []string{"odo may not work as expected in the default project"}) - }) - }) - */ - // Test reused and adapted from the now-removed `cmd_devfile_delete_test.go`. // cf. https://github.com/redhat-developer/odo/blob/24fd02673d25eb4c7bb166ec3369554a8e64b59c/tests/integration/devfile/cmd_devfile_delete_test.go#L172-L238 When("a component with endpoints is bootstrapped and pushed", func() { diff --git a/tests/integration/cmd_devfile_deploy_test.go b/tests/integration/cmd_devfile_deploy_test.go index 5edbf27650e..6776dbe6636 100644 --- a/tests/integration/cmd_devfile_deploy_test.go +++ b/tests/integration/cmd_devfile_deploy_test.go @@ -43,7 +43,34 @@ var _ = Describe("odo devfile deploy command tests", func() { }) }) + When("a component is bootstrapped", func() { + BeforeEach(func() { + helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context) + helper.Cmd("odo", "init", "--name", cmpName, "--devfile-path", helper.GetExamplePath("source", "devfiles", "nodejs", "devfile-deploy.yaml")).ShouldPass() + }) + When("using a default namespace", func() { + BeforeEach(func() { + commonVar.CliRunner.SetProject("default") + }) + AfterEach(func() { + helper.Cmd("odo", "delete", "component", "-f").ShouldPass() + commonVar.CliRunner.SetProject(commonVar.Project) + }) + It("should display warning when running the deploy command", func() { + errOut := helper.Cmd("odo", "deploy").AddEnv("PODMAN_CMD=echo").ShouldRun().Err() + namespace := "project" + if helper.IsKubernetesCluster() { + namespace = "namespace" + } + Expect(errOut).To(ContainSubstring(fmt.Sprintf("You are using \"default\" %[1]s, odo may not work as expected in the default %[1]s.", namespace))) + }) + }) + It("should fail to run odo deploy when not connected to any cluster", Label(helper.LabelNoCluster), func() { + errOut := helper.Cmd("odo", "deploy").ShouldFail().Err() + Expect(errOut).To(ContainSubstring("unable to access the cluster")) + }) + }) for _, ctx := range []struct { title string devfileName string