Skip to content

Commit 8f9bfd9

Browse files
committed
update "oc projects" to display all projects
1 parent c78c428 commit 8f9bfd9

File tree

8 files changed

+289
-4
lines changed

8 files changed

+289
-4
lines changed

contrib/completions/bash/oc

+43
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,48 @@ _oc_project()
588588
must_have_one_noun=()
589589
}
590590

591+
_oc_projects()
592+
{
593+
last_command="oc_projects"
594+
commands=()
595+
596+
flags=()
597+
two_word_flags=()
598+
flags_with_completion=()
599+
flags_completion=()
600+
601+
flags+=("--short")
602+
flags+=("-q")
603+
flags+=("--api-version=")
604+
flags+=("--as=")
605+
flags+=("--certificate-authority=")
606+
flags_with_completion+=("--certificate-authority")
607+
flags_completion+=("_filedir")
608+
flags+=("--client-certificate=")
609+
flags_with_completion+=("--client-certificate")
610+
flags_completion+=("_filedir")
611+
flags+=("--client-key=")
612+
flags_with_completion+=("--client-key")
613+
flags_completion+=("_filedir")
614+
flags+=("--cluster=")
615+
flags+=("--config=")
616+
flags_with_completion+=("--config")
617+
flags_completion+=("_filedir")
618+
flags+=("--context=")
619+
flags+=("--google-json-key=")
620+
flags+=("--insecure-skip-tls-verify")
621+
flags+=("--log-flush-frequency=")
622+
flags+=("--match-server-version")
623+
flags+=("--namespace=")
624+
two_word_flags+=("-n")
625+
flags+=("--server=")
626+
flags+=("--token=")
627+
flags+=("--user=")
628+
629+
must_have_one_flag=()
630+
must_have_one_noun=()
631+
}
632+
591633
_oc_explain()
592634
{
593635
last_command="oc_explain"
@@ -8851,6 +8893,7 @@ _oc()
88518893
commands+=("new-app")
88528894
commands+=("status")
88538895
commands+=("project")
8896+
commands+=("projects")
88548897
commands+=("explain")
88558898
commands+=("cluster")
88568899
commands+=("deploy")

contrib/completions/bash/openshift

+43
Original file line numberDiff line numberDiff line change
@@ -4176,6 +4176,48 @@ _openshift_cli_project()
41764176
must_have_one_noun=()
41774177
}
41784178

4179+
_openshift_cli_projects()
4180+
{
4181+
last_command="openshift_cli_projects"
4182+
commands=()
4183+
4184+
flags=()
4185+
two_word_flags=()
4186+
flags_with_completion=()
4187+
flags_completion=()
4188+
4189+
flags+=("--short")
4190+
flags+=("-q")
4191+
flags+=("--api-version=")
4192+
flags+=("--as=")
4193+
flags+=("--certificate-authority=")
4194+
flags_with_completion+=("--certificate-authority")
4195+
flags_completion+=("_filedir")
4196+
flags+=("--client-certificate=")
4197+
flags_with_completion+=("--client-certificate")
4198+
flags_completion+=("_filedir")
4199+
flags+=("--client-key=")
4200+
flags_with_completion+=("--client-key")
4201+
flags_completion+=("_filedir")
4202+
flags+=("--cluster=")
4203+
flags+=("--config=")
4204+
flags_with_completion+=("--config")
4205+
flags_completion+=("_filedir")
4206+
flags+=("--context=")
4207+
flags+=("--google-json-key=")
4208+
flags+=("--insecure-skip-tls-verify")
4209+
flags+=("--log-flush-frequency=")
4210+
flags+=("--match-server-version")
4211+
flags+=("--namespace=")
4212+
two_word_flags+=("-n")
4213+
flags+=("--server=")
4214+
flags+=("--token=")
4215+
flags+=("--user=")
4216+
4217+
must_have_one_flag=()
4218+
must_have_one_noun=()
4219+
}
4220+
41794221
_openshift_cli_explain()
41804222
{
41814223
last_command="openshift_cli_explain"
@@ -12439,6 +12481,7 @@ _openshift_cli()
1243912481
commands+=("new-app")
1244012482
commands+=("status")
1244112483
commands+=("project")
12484+
commands+=("projects")
1244212485
commands+=("explain")
1244312486
commands+=("cluster")
1244412487
commands+=("deploy")

docs/generated/oc_by_example_content.adoc

+13
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,19 @@ Switch to another project
16211621
====
16221622

16231623

1624+
== oc projects
1625+
Display existing projects
1626+
1627+
====
1628+
1629+
[options="nowrap"]
1630+
----
1631+
# Display the projects that currently exist
1632+
oc
1633+
----
1634+
====
1635+
1636+
16241637
== oc proxy
16251638
Run a proxy to the Kubernetes API server
16261639

pkg/cmd/cli/cli.go

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ func NewCommandCLI(name, fullName string, in io.Reader, out, errout io.Writer) *
9797
cmd.NewCmdNewApplication(fullName, f, out),
9898
cmd.NewCmdStatus(cmd.StatusRecommendedName, fullName+" "+cmd.StatusRecommendedName, f, out),
9999
cmd.NewCmdProject(fullName+" project", f, out),
100+
cmd.NewCmdProjects(fullName, f, out),
100101
cmd.NewCmdExplain(fullName, f, out),
101102
cluster.NewCmdCluster(cluster.ClusterRecommendedName, fullName+" "+cluster.ClusterRecommendedName, f, out),
102103
},

pkg/cmd/cli/cmd/project.go

-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ func NewCmdProject(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.
6666
Short: "Switch to another project",
6767
Long: projectLong,
6868
Example: fmt.Sprintf(projectExample, fullName),
69-
Aliases: []string{"projects"},
7069
Run: func(cmd *cobra.Command, args []string) {
7170
options.PathOptions = cliconfig.NewPathOptions(cmd)
7271

pkg/cmd/cli/cmd/projects.go

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"io"
6+
7+
"k8s.io/kubernetes/pkg/client/restclient"
8+
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
9+
kubecmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
10+
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
11+
12+
"github.com/openshift/origin/pkg/client"
13+
cliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
14+
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
15+
"github.com/openshift/origin/pkg/project/api"
16+
17+
"github.com/spf13/cobra"
18+
)
19+
20+
type ProjectsOptions struct {
21+
Config clientcmdapi.Config
22+
ClientConfig *restclient.Config
23+
Client *client.Client
24+
Out io.Writer
25+
PathOptions *kubecmdconfig.PathOptions
26+
27+
DisplayShort bool
28+
}
29+
30+
const (
31+
projectsLong = `
32+
Display information about the current active project and existing projects on the server.
33+
34+
For advanced configuration, or to manage the contents of your config file, use the 'config'
35+
command.`
36+
37+
projectsExample = ` # Display the projects that currently exist
38+
%[1]s`
39+
)
40+
41+
// NewCmdProjects implements the OpenShift cli rollback command
42+
func NewCmdProjects(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
43+
options := &ProjectsOptions{}
44+
45+
cmd := &cobra.Command{
46+
Use: "projects",
47+
Short: "Display existing projects",
48+
Long: projectsLong,
49+
Example: fmt.Sprintf(projectsExample, fullName),
50+
Run: func(cmd *cobra.Command, args []string) {
51+
options.PathOptions = cliconfig.NewPathOptions(cmd)
52+
53+
if err := options.Complete(f, args, out); err != nil {
54+
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
55+
}
56+
57+
if err := options.RunProjects(); err != nil {
58+
kcmdutil.CheckErr(err)
59+
}
60+
},
61+
}
62+
63+
cmd.Flags().BoolVarP(&options.DisplayShort, "short", "q", false, "If true, display only the project names")
64+
return cmd
65+
}
66+
67+
func (o *ProjectsOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error {
68+
if len(args) > 0 {
69+
return fmt.Errorf("no arguments should be passed")
70+
}
71+
72+
var err error
73+
o.Config, err = f.OpenShiftClientConfig.RawConfig()
74+
if err != nil {
75+
return err
76+
}
77+
78+
o.ClientConfig, err = f.OpenShiftClientConfig.ClientConfig()
79+
if err != nil {
80+
return err
81+
}
82+
83+
o.Client, _, err = f.Clients()
84+
if err != nil {
85+
return err
86+
}
87+
88+
o.Out = out
89+
90+
return nil
91+
}
92+
93+
// RunProjects lists all projects a user belongs to
94+
func (o ProjectsOptions) RunProjects() error {
95+
config := o.Config
96+
clientCfg := o.ClientConfig
97+
out := o.Out
98+
99+
currentContext := config.Contexts[config.CurrentContext]
100+
currentProject := currentContext.Namespace
101+
102+
var currentProjectExists bool = false
103+
var currentProjectErr error = nil
104+
105+
client := o.Client
106+
107+
if len(currentProject) > 0 {
108+
if _, currentProjectErr := client.Projects().Get(currentProject); currentProjectErr == nil {
109+
currentProjectExists = true
110+
}
111+
}
112+
113+
defaultContextName := cliconfig.GetContextNickname(currentContext.Namespace, currentContext.Cluster, currentContext.AuthInfo)
114+
115+
var msg string
116+
var current string
117+
projects, err := getProjects(client)
118+
if err == nil {
119+
switch len(projects) {
120+
case 0:
121+
msg += "You are not a member of any projects. You can request a project to be created with the 'new-project' command."
122+
case 1:
123+
msg += fmt.Sprintf("\nYou have one project on this server: %s", api.DisplayNameAndNameForProject(&projects[0]))
124+
default:
125+
asterisk := ""
126+
count := 0
127+
if !o.DisplayShort {
128+
msg += "You have access to the following projects and can switch between them with 'oc project <projectname>':\n"
129+
asterisk = " * "
130+
}
131+
for _, project := range projects {
132+
count = count + 1
133+
displayName := project.Annotations["openshift.io/display-name"]
134+
linebreak := "\n"
135+
if len(displayName) == 0 {
136+
displayName = project.Annotations["displayName"]
137+
}
138+
139+
current = ""
140+
if currentProjectExists && currentProject == project.Name && !o.DisplayShort {
141+
current = " (current)"
142+
}
143+
if len(displayName) > 0 && displayName != project.Name && !o.DisplayShort {
144+
msg += fmt.Sprintf("\n * %s (%s)%s", displayName, project.Name, current)
145+
} else {
146+
if o.DisplayShort && count == 1 {
147+
linebreak = ""
148+
}
149+
msg += fmt.Sprintf(linebreak+asterisk+"%s%s", project.Name, current)
150+
}
151+
}
152+
}
153+
fmt.Println(msg)
154+
155+
if len(projects) > 0 && !o.DisplayShort {
156+
if !currentProjectExists {
157+
if clientcmd.IsForbidden(currentProjectErr) {
158+
fmt.Printf("you do not have rights to view project %q. Please switch to an existing one.", currentProject)
159+
}
160+
return currentProjectErr
161+
}
162+
163+
// if they specified a project name and got a generated context, then only show the information they care about. They won't recognize
164+
// a context name they didn't choose
165+
if config.CurrentContext == defaultContextName {
166+
fmt.Fprintf(out, "\nUsing project %q on server %q.\n", currentProject, clientCfg.Host)
167+
} else {
168+
fmt.Fprintf(out, "\nUsing project %q from context named %q on server %q.\n", currentProject, config.CurrentContext, clientCfg.Host)
169+
}
170+
}
171+
return nil
172+
}
173+
174+
return err
175+
}

test/cmd/basicresources.sh

+11
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,17 @@ os::test::junit::declare_suite_end
303303
# service accounts should not be allowed to request new projects
304304
os::cmd::expect_failure_and_text "oc new-project --token="$( oc sa get-token builder )" will-fail" 'Error from server: You may not request a new project via this API'
305305

306+
# test oc projects
307+
os::cmd::expect_failure_and_text 'oc projects test_arg' 'no arguments'
308+
os::cmd::expect_success_and_text 'oc projects' 'You have access'
309+
# log in as a test user and expect no projects
310+
os::cmd::expect_success 'oc login -u test -p test'
311+
os::cmd::expect_success_and_text 'oc projects' 'You are not a member of any projects'
312+
# add a project and expect text for a single project
313+
os::cmd::expect_success_and_text 'oc new-project test4; sleep 2; oc projects' 'You have one project on this server: test4'
314+
os::cmd::expect_success_and_text 'oc new-project test5; sleep 2; oc projects' 'You have access'
315+
echo 'projects command ok'
316+
306317
os::test::junit::declare_suite_start "cmd/basicresources/patch"
307318
# Validate patching works correctly
308319
oc login -u system:admin

test/cmd/help.sh

+3-3
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ os::cmd::expect_success_and_text 'openshift start --help' 'Start an all-in-one s
9595
os::cmd::expect_success_and_text 'openshift start master --help' 'Start a master'
9696
os::cmd::expect_success_and_text 'openshift start node --help' 'Start a node'
9797
os::cmd::expect_success_and_text 'oc project --help' 'Switch to another project'
98-
os::cmd::expect_success_and_text 'oc projects --help' 'Switch to another project'
98+
os::cmd::expect_success_and_text 'oc projects --help' 'existing projects'
9999
os::cmd::expect_success_and_text 'openshift cli project --help' 'Switch to another project'
100-
os::cmd::expect_success_and_text 'openshift cli projects --help' 'Switch to another project'
100+
os::cmd::expect_success_and_text 'openshift cli projects --help' 'current active project and existing projects on the server'
101101
os::cmd::expect_success_and_text 'oc get --help' 'oc'
102102

103103
# help for given command through help command must be consistent
@@ -108,7 +108,7 @@ os::cmd::expect_success_and_text 'openshift help start' 'Start an all-in-one ser
108108
os::cmd::expect_success_and_text 'openshift help start master' 'Start a master'
109109
os::cmd::expect_success_and_text 'openshift help start node' 'Start a node'
110110
os::cmd::expect_success_and_text 'oc help project' 'Switch to another project'
111-
os::cmd::expect_success_and_text 'oc help projects' 'Switch to another project'
111+
os::cmd::expect_success_and_text 'oc help projects' 'current active project and existing projects on the server'
112112

113113
# runnable commands with required flags must error consistently
114114
os::cmd::expect_failure_and_text 'oc get' 'Required resource not specified'

0 commit comments

Comments
 (0)