| ... | ... |
@@ -588,6 +588,48 @@ _oc_project() |
| 588 | 588 |
must_have_one_noun=() |
| 589 | 589 |
} |
| 590 | 590 |
|
| 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 |
+ |
|
| 591 | 633 |
_oc_explain() |
| 592 | 634 |
{
|
| 593 | 635 |
last_command="oc_explain" |
| ... | ... |
@@ -8851,6 +8893,7 @@ _oc() |
| 8851 | 8851 |
commands+=("new-app")
|
| 8852 | 8852 |
commands+=("status")
|
| 8853 | 8853 |
commands+=("project")
|
| 8854 |
+ commands+=("projects")
|
|
| 8854 | 8855 |
commands+=("explain")
|
| 8855 | 8856 |
commands+=("cluster")
|
| 8856 | 8857 |
commands+=("deploy")
|
| ... | ... |
@@ -4176,6 +4176,48 @@ _openshift_cli_project() |
| 4176 | 4176 |
must_have_one_noun=() |
| 4177 | 4177 |
} |
| 4178 | 4178 |
|
| 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 |
+ |
|
| 4179 | 4221 |
_openshift_cli_explain() |
| 4180 | 4222 |
{
|
| 4181 | 4223 |
last_command="openshift_cli_explain" |
| ... | ... |
@@ -12439,6 +12481,7 @@ _openshift_cli() |
| 12439 | 12439 |
commands+=("new-app")
|
| 12440 | 12440 |
commands+=("status")
|
| 12441 | 12441 |
commands+=("project")
|
| 12442 |
+ commands+=("projects")
|
|
| 12442 | 12443 |
commands+=("explain")
|
| 12443 | 12444 |
commands+=("cluster")
|
| 12444 | 12445 |
commands+=("deploy")
|
| ... | ... |
@@ -1621,6 +1621,19 @@ Switch to another project |
| 1621 | 1621 |
==== |
| 1622 | 1622 |
|
| 1623 | 1623 |
|
| 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 |
+ |
|
| 1624 | 1637 |
== oc proxy |
| 1625 | 1638 |
Run a proxy to the Kubernetes API server |
| 1626 | 1639 |
|
| ... | ... |
@@ -97,6 +97,7 @@ func NewCommandCLI(name, fullName string, in io.Reader, out, errout io.Writer) * |
| 97 | 97 |
cmd.NewCmdNewApplication(fullName, f, out), |
| 98 | 98 |
cmd.NewCmdStatus(cmd.StatusRecommendedName, fullName+" "+cmd.StatusRecommendedName, f, out), |
| 99 | 99 |
cmd.NewCmdProject(fullName+" project", f, out), |
| 100 |
+ cmd.NewCmdProjects(fullName, f, out), |
|
| 100 | 101 |
cmd.NewCmdExplain(fullName, f, out), |
| 101 | 102 |
cluster.NewCmdCluster(cluster.ClusterRecommendedName, fullName+" "+cluster.ClusterRecommendedName, f, out), |
| 102 | 103 |
}, |
| ... | ... |
@@ -66,7 +66,6 @@ func NewCmdProject(fullName string, f *clientcmd.Factory, out io.Writer) *cobra. |
| 66 | 66 |
Short: "Switch to another project", |
| 67 | 67 |
Long: projectLong, |
| 68 | 68 |
Example: fmt.Sprintf(projectExample, fullName), |
| 69 |
- Aliases: []string{"projects"},
|
|
| 70 | 69 |
Run: func(cmd *cobra.Command, args []string) {
|
| 71 | 70 |
options.PathOptions = cliconfig.NewPathOptions(cmd) |
| 72 | 71 |
|
| 73 | 72 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,175 @@ |
| 0 |
+package cmd |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "io" |
|
| 5 |
+ |
|
| 6 |
+ "k8s.io/kubernetes/pkg/client/restclient" |
|
| 7 |
+ clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" |
|
| 8 |
+ kubecmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config" |
|
| 9 |
+ kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
|
| 10 |
+ |
|
| 11 |
+ "github.com/openshift/origin/pkg/client" |
|
| 12 |
+ cliconfig "github.com/openshift/origin/pkg/cmd/cli/config" |
|
| 13 |
+ "github.com/openshift/origin/pkg/cmd/util/clientcmd" |
|
| 14 |
+ "github.com/openshift/origin/pkg/project/api" |
|
| 15 |
+ |
|
| 16 |
+ "github.com/spf13/cobra" |
|
| 17 |
+) |
|
| 18 |
+ |
|
| 19 |
+type ProjectsOptions struct {
|
|
| 20 |
+ Config clientcmdapi.Config |
|
| 21 |
+ ClientConfig *restclient.Config |
|
| 22 |
+ Client *client.Client |
|
| 23 |
+ Out io.Writer |
|
| 24 |
+ PathOptions *kubecmdconfig.PathOptions |
|
| 25 |
+ |
|
| 26 |
+ DisplayShort bool |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 29 |
+const ( |
|
| 30 |
+ projectsLong = ` |
|
| 31 |
+Display information about the current active project and existing projects on the server. |
|
| 32 |
+ |
|
| 33 |
+For advanced configuration, or to manage the contents of your config file, use the 'config' |
|
| 34 |
+command.` |
|
| 35 |
+ |
|
| 36 |
+ projectsExample = ` # Display the projects that currently exist |
|
| 37 |
+ %[1]s` |
|
| 38 |
+) |
|
| 39 |
+ |
|
| 40 |
+// NewCmdProjects implements the OpenShift cli rollback command |
|
| 41 |
+func NewCmdProjects(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
|
|
| 42 |
+ options := &ProjectsOptions{}
|
|
| 43 |
+ |
|
| 44 |
+ cmd := &cobra.Command{
|
|
| 45 |
+ Use: "projects", |
|
| 46 |
+ Short: "Display existing projects", |
|
| 47 |
+ Long: projectsLong, |
|
| 48 |
+ Example: fmt.Sprintf(projectsExample, fullName), |
|
| 49 |
+ Run: func(cmd *cobra.Command, args []string) {
|
|
| 50 |
+ options.PathOptions = cliconfig.NewPathOptions(cmd) |
|
| 51 |
+ |
|
| 52 |
+ if err := options.Complete(f, args, out); err != nil {
|
|
| 53 |
+ kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error())) |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ if err := options.RunProjects(); err != nil {
|
|
| 57 |
+ kcmdutil.CheckErr(err) |
|
| 58 |
+ } |
|
| 59 |
+ }, |
|
| 60 |
+ } |
|
| 61 |
+ |
|
| 62 |
+ cmd.Flags().BoolVarP(&options.DisplayShort, "short", "q", false, "If true, display only the project names") |
|
| 63 |
+ return cmd |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+func (o *ProjectsOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error {
|
|
| 67 |
+ if len(args) > 0 {
|
|
| 68 |
+ return fmt.Errorf("no arguments should be passed")
|
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ var err error |
|
| 72 |
+ o.Config, err = f.OpenShiftClientConfig.RawConfig() |
|
| 73 |
+ if err != nil {
|
|
| 74 |
+ return err |
|
| 75 |
+ } |
|
| 76 |
+ |
|
| 77 |
+ o.ClientConfig, err = f.OpenShiftClientConfig.ClientConfig() |
|
| 78 |
+ if err != nil {
|
|
| 79 |
+ return err |
|
| 80 |
+ } |
|
| 81 |
+ |
|
| 82 |
+ o.Client, _, err = f.Clients() |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ return err |
|
| 85 |
+ } |
|
| 86 |
+ |
|
| 87 |
+ o.Out = out |
|
| 88 |
+ |
|
| 89 |
+ return nil |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 92 |
+// RunProjects lists all projects a user belongs to |
|
| 93 |
+func (o ProjectsOptions) RunProjects() error {
|
|
| 94 |
+ config := o.Config |
|
| 95 |
+ clientCfg := o.ClientConfig |
|
| 96 |
+ out := o.Out |
|
| 97 |
+ |
|
| 98 |
+ currentContext := config.Contexts[config.CurrentContext] |
|
| 99 |
+ currentProject := currentContext.Namespace |
|
| 100 |
+ |
|
| 101 |
+ var currentProjectExists bool = false |
|
| 102 |
+ var currentProjectErr error = nil |
|
| 103 |
+ |
|
| 104 |
+ client := o.Client |
|
| 105 |
+ |
|
| 106 |
+ if len(currentProject) > 0 {
|
|
| 107 |
+ if _, currentProjectErr := client.Projects().Get(currentProject); currentProjectErr == nil {
|
|
| 108 |
+ currentProjectExists = true |
|
| 109 |
+ } |
|
| 110 |
+ } |
|
| 111 |
+ |
|
| 112 |
+ defaultContextName := cliconfig.GetContextNickname(currentContext.Namespace, currentContext.Cluster, currentContext.AuthInfo) |
|
| 113 |
+ |
|
| 114 |
+ var msg string |
|
| 115 |
+ var current string |
|
| 116 |
+ projects, err := getProjects(client) |
|
| 117 |
+ if err == nil {
|
|
| 118 |
+ switch len(projects) {
|
|
| 119 |
+ case 0: |
|
| 120 |
+ msg += "You are not a member of any projects. You can request a project to be created with the 'new-project' command." |
|
| 121 |
+ case 1: |
|
| 122 |
+ msg += fmt.Sprintf("You have one project on this server: %q.", api.DisplayNameAndNameForProject(&projects[0]))
|
|
| 123 |
+ default: |
|
| 124 |
+ asterisk := "" |
|
| 125 |
+ count := 0 |
|
| 126 |
+ if !o.DisplayShort {
|
|
| 127 |
+ msg += "You have access to the following projects and can switch between them with 'oc project <projectname>':\n" |
|
| 128 |
+ asterisk = " * " |
|
| 129 |
+ } |
|
| 130 |
+ for _, project := range projects {
|
|
| 131 |
+ count = count + 1 |
|
| 132 |
+ displayName := project.Annotations["openshift.io/display-name"] |
|
| 133 |
+ linebreak := "\n" |
|
| 134 |
+ if len(displayName) == 0 {
|
|
| 135 |
+ displayName = project.Annotations["displayName"] |
|
| 136 |
+ } |
|
| 137 |
+ |
|
| 138 |
+ current = "" |
|
| 139 |
+ if currentProjectExists && currentProject == project.Name && !o.DisplayShort {
|
|
| 140 |
+ current = " (current)" |
|
| 141 |
+ } |
|
| 142 |
+ if len(displayName) > 0 && displayName != project.Name && !o.DisplayShort {
|
|
| 143 |
+ msg += fmt.Sprintf("\n * %s (%s)%s", displayName, project.Name, current)
|
|
| 144 |
+ } else {
|
|
| 145 |
+ if o.DisplayShort && count == 1 {
|
|
| 146 |
+ linebreak = "" |
|
| 147 |
+ } |
|
| 148 |
+ msg += fmt.Sprintf(linebreak+asterisk+"%s%s", project.Name, current) |
|
| 149 |
+ } |
|
| 150 |
+ } |
|
| 151 |
+ } |
|
| 152 |
+ fmt.Println(msg) |
|
| 153 |
+ |
|
| 154 |
+ if len(projects) > 0 && !o.DisplayShort {
|
|
| 155 |
+ if !currentProjectExists {
|
|
| 156 |
+ if clientcmd.IsForbidden(currentProjectErr) {
|
|
| 157 |
+ fmt.Printf("you do not have rights to view project %q. Please switch to an existing one.", currentProject)
|
|
| 158 |
+ } |
|
| 159 |
+ return currentProjectErr |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ // if they specified a project name and got a generated context, then only show the information they care about. They won't recognize |
|
| 163 |
+ // a context name they didn't choose |
|
| 164 |
+ if config.CurrentContext == defaultContextName {
|
|
| 165 |
+ fmt.Fprintf(out, "\nUsing project %q on server %q.\n", currentProject, clientCfg.Host) |
|
| 166 |
+ } else {
|
|
| 167 |
+ fmt.Fprintf(out, "\nUsing project %q from context named %q on server %q.\n", currentProject, config.CurrentContext, clientCfg.Host) |
|
| 168 |
+ } |
|
| 169 |
+ } |
|
| 170 |
+ return nil |
|
| 171 |
+ } |
|
| 172 |
+ |
|
| 173 |
+ return err |
|
| 174 |
+} |
| ... | ... |
@@ -303,6 +303,17 @@ os::test::junit::declare_suite_end |
| 303 | 303 |
# service accounts should not be allowed to request new projects |
| 304 | 304 |
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' |
| 305 | 305 |
|
| 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 |
+ |
|
| 306 | 317 |
os::test::junit::declare_suite_start "cmd/basicresources/patch" |
| 307 | 318 |
# Validate patching works correctly |
| 308 | 319 |
oc login -u system:admin |
| ... | ... |
@@ -95,9 +95,9 @@ os::cmd::expect_success_and_text 'openshift start --help' 'Start an all-in-one s |
| 95 | 95 |
os::cmd::expect_success_and_text 'openshift start master --help' 'Start a master' |
| 96 | 96 |
os::cmd::expect_success_and_text 'openshift start node --help' 'Start a node' |
| 97 | 97 |
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' |
|
| 99 | 99 |
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' |
|
| 101 | 101 |
os::cmd::expect_success_and_text 'oc get --help' 'oc' |
| 102 | 102 |
|
| 103 | 103 |
# 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 |
| 108 | 108 |
os::cmd::expect_success_and_text 'openshift help start master' 'Start a master' |
| 109 | 109 |
os::cmd::expect_success_and_text 'openshift help start node' 'Start a node' |
| 110 | 110 |
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' |
|
| 112 | 112 |
|
| 113 | 113 |
# runnable commands with required flags must error consistently |
| 114 | 114 |
os::cmd::expect_failure_and_text 'oc get' 'Required resource not specified' |