Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

odo dev/deploy should display a warning about default namespace on cluster #6688

Merged
merged 5 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pkg/odo/cli/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand Down
4 changes: 3 additions & 1 deletion pkg/odo/cli/dev/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
17 changes: 17 additions & 0 deletions pkg/odo/genericclioptions/util.go
Original file line number Diff line number Diff line change
@@ -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"
)
Expand Down Expand Up @@ -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 <name>`, or set an existing one by running `odo set %[1]s <name>`", noun)
}
}
10 changes: 7 additions & 3 deletions tests/helper/helper_dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
6 changes: 5 additions & 1 deletion tests/helper/helper_generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
76 changes: 31 additions & 45 deletions tests/integration/cmd_dev_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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"))
Expand Down Expand Up @@ -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() {
Expand Down
27 changes: 27 additions & 0 deletions tests/integration/cmd_devfile_deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down