Skip to content

Commit c8080d0

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

File tree

8 files changed

+294
-4
lines changed

8 files changed

+294
-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

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

test/cmd/basicresources.sh

+8
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,14 @@ 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+
echo 'projects command ok'
313+
306314
os::test::junit::declare_suite_start "cmd/basicresources/patch"
307315
# Validate patching works correctly
308316
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)