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

Implement odo set namespace/project #5744

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
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title: odo set namespace
sidebar_position: 3
---

`odo set namespace` lets you set a namespace/project as the current active one in your local `kubeconfig` configuration.

Executing this command inside a component directory will not update the namespace or project of the existing component.

To set the current active namespace you can run `odo set namespace <name>`:
```shell
odo set namespace mynamespace
```

Example:
```shell
odo set namespace mynamespace
✓ Current active namespace set to "mynamespace"
```

Optionally, you can also use `project` as an alias to `namespace`.

To set the current active project you can run `odo set project <name>`:
```shell
odo set project myproject
```

Example:
```shell
odo set project myproject
✓ Current active project set to "myproject"
```

:::note
This command updates your current `kubeconfig` configuration, using either of the aliases.
So running either `odo set project` or `odo set namespace` performs the exact same operation in your configuration.
:::
2 changes: 2 additions & 0 deletions pkg/odo/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ 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/set"
"github.com/redhat-developer/odo/pkg/odo/cli/telemetry"
"github.com/redhat-developer/odo/pkg/odo/cli/utils"
"github.com/redhat-developer/odo/pkg/odo/cli/version"
Expand Down Expand Up @@ -181,6 +182,7 @@ func odoRootCmd(name, fullName string) *cobra.Command {
describe.NewCmdDescribe(describe.RecommendedCommandName, util.GetFullName(fullName, describe.RecommendedCommandName)),
registry.NewCmdRegistry(registry.RecommendedCommandName, util.GetFullName(fullName, registry.RecommendedCommandName)),
create.NewCmdCreate(create.RecommendedCommandName, util.GetFullName(fullName, create.RecommendedCommandName)),
set.NewCmdSet(set.RecommendedCommandName, util.GetFullName(fullName, set.RecommendedCommandName)),
)

// Add all subcommands to base commands
Expand Down
135 changes: 135 additions & 0 deletions pkg/odo/cli/set/namespace/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package namespace

import (
"context"
"fmt"
"os"

dfutil "github.com/devfile/library/pkg/util"

"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"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
scontext "github.com/redhat-developer/odo/pkg/segment/context"

"k8s.io/klog"
ktemplates "k8s.io/kubectl/pkg/util/templates"

"github.com/spf13/cobra"
)

const RecommendedCommandName = "namespace"

var (
setExample = ktemplates.Examples(`
# Set the specified namespace as the current active namespace in the config
%[1]s my-namespace
`)

setLongDesc = ktemplates.LongDesc(`Set the current active namespace.

If executed inside a component directory, this command will not update the namespace of the existing component.
`)

setShortDesc = `Set the current active namespace`
)

// SetOptions encapsulates the options for the odo namespace create command
type SetOptions struct {
// Context
*genericclioptions.Context

// Clients
clientset *clientset.Clientset

// Destination directory
contextDir string

// Parameters
namespaceName string

// value can be either 'project' or 'namespace', depending on what command is called
commandName string
}

// NewSetOptions creates a SetOptions instance
func NewSetOptions() *SetOptions {
return &SetOptions{}
}

func (so *SetOptions) SetClientset(clientset *clientset.Clientset) {
so.clientset = clientset
}

// Complete completes SetOptions after they've been created
func (so *SetOptions) Complete(cmdline cmdline.Cmdline, args []string) (err error) {
so.namespaceName = args[0]
so.Context, err = genericclioptions.New(genericclioptions.NewCreateParameters(cmdline))
if err != nil {
return err
}
so.contextDir, err = so.clientset.FS.Getwd()
if err != nil {
return err
}
if scontext.GetTelemetryStatus(cmdline.Context()) {
scontext.SetClusterType(cmdline.Context(), so.KClient)
}
return nil
}

// Validate validates the parameters of the SetOptions
func (so *SetOptions) Validate() error {
return dfutil.ValidateK8sResourceName("namespace name", so.namespaceName)
}

// Run runs the 'set namespace' command
func (so *SetOptions) Run(ctx context.Context) error {
devfilePresent, err := location.DirectoryContainsDevfile(so.clientset.FS, so.contextDir)
if err != nil {
// Purposely ignoring the error, as it is not mandatory for this command
klog.V(2).Infof("Unexpected error while checking if running inside a component directory: %v", err)
}
if devfilePresent {
log.Warningf("This is being executed inside a component directory. This will not update the %s of the existing component",
so.commandName)
}

err = so.clientset.ProjectClient.SetCurrent(so.namespaceName)
if err != nil {
return err
}

log.Successf("Current active %[1]s set to %q", so.commandName, so.namespaceName)

return nil
}

// NewCmdNamespaceSet creates the 'set namespace' command
func NewCmdNamespaceSet(name, fullName string) *cobra.Command {
o := NewSetOptions()
// To help the UI messages deal better with namespace vs project
o.commandName = name
if len(os.Args) > 2 {
o.commandName = os.Args[2]
}

namespaceSetCmd := &cobra.Command{
Use: name,
Short: setShortDesc,
Long: setLongDesc,
Example: fmt.Sprintf(setExample, fullName),
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
genericclioptions.GenericRun(o, cmd, args)
},
Annotations: map[string]string{"command": "main"},
Aliases: []string{"project"},
}

clientset.Add(namespaceSetCmd, clientset.FILESYSTEM, clientset.PROJECT)

return namespaceSetCmd
}
36 changes: 36 additions & 0 deletions pkg/odo/cli/set/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package set

import (
"fmt"

"github.com/redhat-developer/odo/pkg/odo/cli/set/namespace"
"github.com/redhat-developer/odo/pkg/odo/util"

"github.com/spf13/cobra"
)

// RecommendedCommandName is the recommended namespace command name
const RecommendedCommandName = "set"

// NewCmdSet implements the namespace odo command
func NewCmdSet(name, fullName string) *cobra.Command {

namespaceSetCmd := namespace.NewCmdNamespaceSet(namespace.RecommendedCommandName,
util.GetFullName(fullName, namespace.RecommendedCommandName))
setCmd := &cobra.Command{
Use: name + " [options]",
Short: "Perform set operation",
Long: "Perform set operation",
Example: fmt.Sprintf("%s\n",
namespaceSetCmd.Example,
),
Annotations: map[string]string{"command": "main"},
}

setCmd.AddCommand(namespaceSetCmd)

// Add a defined annotation in order to appear in the help menu
setCmd.SetUsageTemplate(util.CmdUsageTemplate)

return setCmd
}
5 changes: 4 additions & 1 deletion tests/helper/helper_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ type CliRunner interface {
DeletePod(podName string, projectName string)
GetAllNamespaceProjects() []string
GetNamespaceProject() string
CheckNamespaceProjectExists(name string) bool

// HasNamespaceProject returns whether the specified namespace or project exists in the cluster
HasNamespaceProject(name string) bool

GetActiveNamespace() string
GetEnvsDevFileDeployment(componentName, appName, projectName string) map[string]string
GetEnvRefNames(componentName, appName, projectName string) []string
Expand Down
6 changes: 4 additions & 2 deletions tests/helper/helper_kubectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,10 @@ func (kubectl KubectlRunner) GetNamespaceProject() string {
return Cmd(kubectl.path, "get", "namespace").ShouldPass().Out()
}

func (kubectl KubectlRunner) CheckNamespaceProjectExists(name string) bool {
return Cmd(kubectl.path, "get", "namespace", name).ShouldPass().pass
func (kubectl KubectlRunner) HasNamespaceProject(name string) bool {
out := Cmd(kubectl.path, "get", "namespace", name, "-o", "jsonpath={.metadata.name}").
ShouldRun().Out()
return strings.Contains(out, name)
}

func (kubectl KubectlRunner) GetActiveNamespace() string {
Expand Down
6 changes: 4 additions & 2 deletions tests/helper/helper_oc.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,10 @@ func (oc OcRunner) GetNamespaceProject() string {
return Cmd(oc.path, "get", "project").ShouldPass().Out()
}

func (oc OcRunner) CheckNamespaceProjectExists(name string) bool {
return Cmd(oc.path, "get", "project", name).ShouldPass().pass
func (oc OcRunner) HasNamespaceProject(name string) bool {
out := Cmd(oc.path, "get", "project", name, "-o", "jsonpath={.metadata.name}").
ShouldRun().Out()
return strings.Contains(out, name)
}

func (oc OcRunner) GetActiveNamespace() string {
Expand Down
Loading