Browse code

Unify all client Factories into one location

Cleanup policy, login, token, project commands to follow common
patterns.

Extract image template logic so other commands can use it.

Create a new Bulk{} operator for creating multiple items at the same
time.

Move the 'kubectl' alias to 'openshift kube'

Clayton Coleman authored on 2015/02/17 14:45:41
Showing 33 changed files
... ...
@@ -104,24 +104,24 @@ export OPENSHIFT_PROFILE="${CLI_PROFILE-}"
104 104
 [ "$(openshift ex config 2>&1)" ]
105 105
 [ "$(openshift ex tokens)" ]
106 106
 [ "$(openshift ex policy  2>&1)" ]
107
-[ "$(openshift kubectl)" ]
107
+[ "$(openshift kubectl 2>&1)" ]
108 108
 [ "$(openshift kube 2>&1)" ]
109 109
 
110 110
 # help for root commands must be consistent
111 111
 [ "$(openshift | grep 'OpenShift for Admins')" ]
112 112
 [ "$(osc | grep 'OpenShift Client')" ]
113 113
 [ "$(openshift cli | grep 'OpenShift Client')" ]
114
-[ "$(openshift kubectl | grep 'OpenShift Client')" ]
114
+[ "$(openshift kubectl 2>&1 | grep 'Kubernetes cluster')" ]
115 115
 
116 116
 # help for root commands with --help flag must be consistent
117 117
 [ "$(openshift --help 2>&1 | grep 'OpenShift for Admins')" ]
118 118
 [ "$(osc --help 2>&1 | grep 'OpenShift Client')" ]
119 119
 [ "$(openshift cli --help 2>&1 | grep 'OpenShift Client')" ]
120
-[ "$(openshift kubectl --help 2>&1 | grep 'OpenShift Client')" ]
120
+[ "$(openshift kubectl --help 2>&1 | grep 'Kubernetes cluster')" ]
121 121
 
122 122
 # help for root commands through help command must be consistent
123 123
 [ "$(openshift help cli 2>&1 | grep 'OpenShift Client')" ]
124
-[ "$(openshift help kubectl 2>&1 | grep 'OpenShift Client')" ]
124
+[ "$(openshift help kubectl 2>&1 | grep 'Kubernetes cluster')" ]
125 125
 
126 126
 # help for given command with --help flag must be consistent
127 127
 [ "$(osc get --help 2>&1 | grep 'Display one or many resources')" ]
... ...
@@ -185,6 +185,10 @@ osc get imageRepositories
185 185
 osc delete imageRepositories test
186 186
 echo "imageRepositoryMappings: ok"
187 187
 
188
+[ "$(osc new-app php mysql -o yaml | grep 3306)" ]
189
+osc new-app php mysql
190
+echo "new-app: ok"
191
+
188 192
 osc get routes
189 193
 osc create -f test/integration/fixtures/test-route.json create routes
190 194
 osc delete routes testroute
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"fmt"
5 5
 	"os"
6 6
 
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
8 7
 	kubecmd "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
9 8
 	"github.com/golang/glog"
10 9
 	"github.com/spf13/cobra"
... ...
@@ -12,6 +11,7 @@ import (
12 12
 
13 13
 	"github.com/openshift/origin/pkg/cmd/cli/cmd"
14 14
 	"github.com/openshift/origin/pkg/cmd/templates"
15
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
15 16
 )
16 17
 
17 18
 const longDesc = `
... ...
@@ -41,28 +41,20 @@ created for you.
41 41
 Note: This is an alpha release of OpenShift and will change significantly.  See
42 42
     https://github.com/openshift/origin for the latest information on OpenShift.
43 43
 `
44
-const defaultClusterURL = "https://localhost:8443"
45 44
 
46 45
 func NewCommandCLI(name, fullName string) *cobra.Command {
47 46
 	// Main command
48 47
 	cmds := &cobra.Command{
49
-		Use:     name,
50
-		Aliases: []string{"kubectl"},
51
-		Short:   "Client tools for OpenShift",
52
-		Long:    fmt.Sprintf(longDesc, fullName),
48
+		Use:   name,
49
+		Short: "Client tools for OpenShift",
50
+		Long:  fmt.Sprintf(longDesc, fullName),
53 51
 		Run: func(c *cobra.Command, args []string) {
54 52
 			c.SetOutput(os.Stdout)
55 53
 			c.Help()
56 54
 		},
57 55
 	}
58 56
 
59
-	// Override global default to https and port 8443
60
-	clientcmd.DefaultCluster.Server = defaultClusterURL
61
-
62
-	// TODO: there should be two client configs, one for OpenShift, and one for Kubernetes
63
-	clientConfig := DefaultClientConfig(cmds.PersistentFlags())
64
-	f := cmd.NewFactory(clientConfig)
65
-	f.BindFlags(cmds.PersistentFlags())
57
+	f := clientcmd.New(cmds.PersistentFlags())
66 58
 	out := os.Stdout
67 59
 
68 60
 	cmds.SetUsageTemplate(templates.CliUsageTemplate())
... ...
@@ -98,15 +90,18 @@ func NewCommandCLI(name, fullName string) *cobra.Command {
98 98
 // but with support for OpenShift resources
99 99
 func NewCmdKubectl(name string) *cobra.Command {
100 100
 	flags := pflag.NewFlagSet("", pflag.ContinueOnError)
101
-	clientcmd.DefaultCluster.Server = defaultClusterURL
102
-	clientConfig := DefaultClientConfig(flags)
103
-	f := cmd.NewFactory(clientConfig)
104
-	cmd := f.NewKubectlCommand(os.Stdout)
101
+	f := clientcmd.New(flags)
102
+	cmd := f.Factory.NewKubectlCommand(os.Stdout)
103
+	cmd.Aliases = []string{"kubectl"}
105 104
 	cmd.Use = name
106 105
 	cmd.Short = "Kubernetes cluster management via kubectl"
107 106
 	cmd.Long = cmd.Long + "\n\nThis command is provided for direct management of the Kubernetes cluster OpenShift runs on."
108 107
 	flags.VisitAll(func(flag *pflag.Flag) {
109
-		cmd.PersistentFlags().AddFlag(flag)
108
+		if f := cmd.PersistentFlags().Lookup(flag.Name); f == nil {
109
+			cmd.PersistentFlags().AddFlag(flag)
110
+		} else {
111
+			glog.V(6).Infof("already registered flag %s", flag.Name)
112
+		}
110 113
 	})
111 114
 	return cmd
112 115
 }
... ...
@@ -128,19 +123,3 @@ func applyToCreate(dst *cobra.Command) *cobra.Command {
128 128
 	}
129 129
 	return dst
130 130
 }
131
-
132
-// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig
133
-func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
134
-	// TODO find and merge duplicates, this is also in other places
135
-	loadingRules := clientcmd.NewClientConfigLoadingRules()
136
-	loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
137
-	flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
138
-
139
-	overrides := &clientcmd.ConfigOverrides{}
140
-	overrideFlags := clientcmd.RecommendedConfigOverrideFlags("")
141
-	overrideFlags.ContextOverrideFlags.NamespaceShort = "n"
142
-	clientcmd.BindOverrideFlags(overrides, flags, overrideFlags)
143
-	clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
144
-
145
-	return clientConfig
146
-}
... ...
@@ -5,9 +5,11 @@ import (
5 5
 
6 6
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
7 7
 	"github.com/spf13/cobra"
8
+
9
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
8 10
 )
9 11
 
10
-func NewCmdBuildLogs(f *Factory, out io.Writer) *cobra.Command {
12
+func NewCmdBuildLogs(f *clientcmd.Factory, out io.Writer) *cobra.Command {
11 13
 	cmd := &cobra.Command{
12 14
 		Use:   "build-logs <build>",
13 15
 		Short: "Show container logs from the build container",
... ...
@@ -11,12 +11,13 @@ import (
11 11
 
12 12
 	buildapi "github.com/openshift/origin/pkg/build/api"
13 13
 	"github.com/openshift/origin/pkg/build/util"
14
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
14 15
 )
15 16
 
16 17
 // NewCmdCancelBuild manages a build cancelling event.
17 18
 // To cancel a build its name has to be specified, and two options
18 19
 // are available: displaying logs and restarting.
19
-func NewCmdCancelBuild(f *Factory, out io.Writer) *cobra.Command {
20
+func NewCmdCancelBuild(f *clientcmd.Factory, out io.Writer) *cobra.Command {
20 21
 
21 22
 	cmd := &cobra.Command{
22 23
 		Use:   "cancel-build <build>",
23 24
deleted file mode 100644
... ...
@@ -1,127 +0,0 @@
1
-package cmd
2
-
3
-import (
4
-	"fmt"
5
-
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
8
-	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
9
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
10
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
11
-	kubecmd "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
12
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
13
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
14
-	"github.com/spf13/cobra"
15
-
16
-	"github.com/openshift/origin/pkg/api/latest"
17
-	"github.com/openshift/origin/pkg/client"
18
-	"github.com/openshift/origin/pkg/cmd/cli/describe"
19
-)
20
-
21
-// Factory provides common options for OpenShift commands
22
-type Factory struct {
23
-	*kubecmd.Factory
24
-	OpenShiftClientConfig clientcmd.ClientConfig
25
-}
26
-
27
-// NewFactory creates an object that holds common methods across all OpenShift commands
28
-func NewFactory(clientConfig clientcmd.ClientConfig) *Factory {
29
-	mapper := ShortcutExpander{kubectl.ShortcutExpander{latest.RESTMapper}}
30
-
31
-	w := &Factory{kubecmd.NewFactory(clientConfig), clientConfig}
32
-
33
-	w.Object = func(cmd *cobra.Command) (meta.RESTMapper, runtime.ObjectTyper) {
34
-		return mapper, api.Scheme
35
-	}
36
-
37
-	// Save original RESTClient function
38
-	kRESTClientFunc := w.Factory.RESTClient
39
-	w.RESTClient = func(cmd *cobra.Command, mapping *meta.RESTMapping) (resource.RESTClient, error) {
40
-		if latest.OriginKind(mapping.Kind, mapping.APIVersion) {
41
-			cfg, err := w.OpenShiftClientConfig.ClientConfig()
42
-			if err != nil {
43
-				return nil, fmt.Errorf("unable to find client config %s: %v", mapping.Kind, err)
44
-			}
45
-			cli, err := client.New(cfg)
46
-			if err != nil {
47
-				return nil, fmt.Errorf("unable to create client %s: %v", mapping.Kind, err)
48
-			}
49
-			return cli.RESTClient, nil
50
-		}
51
-		return kRESTClientFunc(cmd, mapping)
52
-	}
53
-
54
-	// Save original Describer function
55
-	kDescriberFunc := w.Factory.Describer
56
-	w.Describer = func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.Describer, error) {
57
-		if latest.OriginKind(mapping.Kind, mapping.APIVersion) {
58
-			cfg, err := w.OpenShiftClientConfig.ClientConfig()
59
-			if err != nil {
60
-				return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
61
-			}
62
-			cli, err := client.New(cfg)
63
-			if err != nil {
64
-				return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
65
-			}
66
-			kubeClient, err := kclient.New(cfg)
67
-			if err != nil {
68
-				return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
69
-			}
70
-			describer, ok := describe.DescriberFor(mapping.Kind, cli, kubeClient, "")
71
-			if !ok {
72
-				return nil, fmt.Errorf("no description has been implemented for %q", mapping.Kind)
73
-			}
74
-			return describer, nil
75
-		}
76
-		return kDescriberFunc(cmd, mapping)
77
-	}
78
-
79
-	w.Printer = func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error) {
80
-		return describe.NewHumanReadablePrinter(noHeaders), nil
81
-	}
82
-
83
-	return w
84
-}
85
-
86
-// Clients returns an OpenShift and Kubernetes client.
87
-func (f *Factory) Clients(cmd *cobra.Command) (*client.Client, *kclient.Client, error) {
88
-	os, err := f.OpenShiftClientConfig.ClientConfig()
89
-	if err != nil {
90
-		return nil, nil, err
91
-	}
92
-	oc, err := client.New(os)
93
-	if err != nil {
94
-		return nil, nil, err
95
-	}
96
-	kc, err := f.Client(cmd)
97
-	if err != nil {
98
-		return nil, nil, err
99
-	}
100
-	return oc, kc, nil
101
-}
102
-
103
-// ShortcutExpander is a RESTMapper that can be used for OpenShift resources.
104
-type ShortcutExpander struct {
105
-	meta.RESTMapper
106
-}
107
-
108
-// VersionAndKindForResource implements meta.RESTMapper. It expands the resource first, then invokes the wrapped
109
-// mapper.
110
-func (e ShortcutExpander) VersionAndKindForResource(resource string) (defaultVersion, kind string, err error) {
111
-	resource = expandResourceShortcut(resource)
112
-	return e.RESTMapper.VersionAndKindForResource(resource)
113
-}
114
-
115
-// expandResourceShortcut will return the expanded version of resource
116
-// (something that a pkg/api/meta.RESTMapper can understand), if it is
117
-// indeed a shortcut. Otherwise, will return resource unmodified.
118
-func expandResourceShortcut(resource string) string {
119
-	shortForms := map[string]string{
120
-		"dc": "deploymentConfigs",
121
-		"bc": "buildConfigs",
122
-	}
123
-	if expanded, ok := shortForms[resource]; ok {
124
-		return expanded
125
-	}
126
-	return resource
127
-}
... ...
@@ -7,13 +7,14 @@ import (
7 7
 
8 8
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
9 9
 	cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
10
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
11 10
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
12 11
 	"github.com/golang/glog"
13 12
 	"github.com/spf13/cobra"
14 13
 
15 14
 	buildapi "github.com/openshift/origin/pkg/build/api"
15
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
16 16
 	dockerutil "github.com/openshift/origin/pkg/cmd/util/docker"
17
+	configcmd "github.com/openshift/origin/pkg/config/cmd"
17 18
 	newcmd "github.com/openshift/origin/pkg/generate/app/cmd"
18 19
 	imageapi "github.com/openshift/origin/pkg/image/api"
19 20
 )
... ...
@@ -51,7 +52,7 @@ application is created.
51 51
 ALPHA: This command is under active development - feedback is appreciated.
52 52
 `
53 53
 
54
-func NewCmdNewApplication(f *Factory, out io.Writer) *cobra.Command {
54
+func NewCmdNewApplication(f *clientcmd.Factory, out io.Writer) *cobra.Command {
55 55
 	config := newcmd.NewAppConfig()
56 56
 
57 57
 	helper := dockerutil.NewHelper()
... ...
@@ -107,32 +108,12 @@ func NewCmdNewApplication(f *Factory, out io.Writer) *cobra.Command {
107 107
 				return
108 108
 			}
109 109
 
110
-			mapper, typer := f.Object(c)
111
-			resourceMapper := &resource.Mapper{typer, mapper, f.Factory.ClientMapperForCommand(c)}
112
-			errs := []error{}
113
-			for i, item := range result.List.Items {
114
-				info, err := resourceMapper.InfoForObject(item)
115
-				if err != nil {
116
-					errs = append(errs, err)
117
-					continue
118
-				}
119
-				data, err := info.Mapping.Codec.Encode(item)
120
-				if err != nil {
121
-					errs = append(errs, err)
122
-					glog.Error(err)
123
-					continue
124
-				}
125
-				obj, err := resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, data)
126
-				if err != nil {
127
-					errs = append(errs, err)
128
-					glog.Error(err)
129
-					continue
130
-				}
131
-				info.Refresh(obj, true)
132
-				result.List.Items[i] = obj
133
-				fmt.Fprintf(out, "%s\n", info.Name)
110
+			bulk := configcmd.Bulk{
111
+				Factory: f.Factory,
112
+				Command: c,
113
+				After:   configcmd.NewPrintNameOrErrorAfter(out, os.Stderr),
134 114
 			}
135
-			if len(errs) != 0 {
115
+			if errs := bulk.Create(result.List, namespace); len(errs) != 0 {
136 116
 				os.Exit(1)
137 117
 			}
138 118
 
... ...
@@ -6,9 +6,10 @@ import (
6 6
 	"github.com/spf13/cobra"
7 7
 
8 8
 	"github.com/openshift/origin/pkg/cmd/templates"
9
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
9 10
 )
10 11
 
11
-func NewCmdOptions(f *Factory, out io.Writer) *cobra.Command {
12
+func NewCmdOptions(f *clientcmd.Factory, out io.Writer) *cobra.Command {
12 13
 	cmd := &cobra.Command{
13 14
 		Use: "options",
14 15
 		Run: func(cmd *cobra.Command, args []string) {
... ...
@@ -10,6 +10,7 @@ import (
10 10
 	"github.com/golang/glog"
11 11
 	"github.com/spf13/cobra"
12 12
 
13
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
13 14
 	"github.com/openshift/origin/pkg/template"
14 15
 	"github.com/openshift/origin/pkg/template/api"
15 16
 )
... ...
@@ -35,7 +36,7 @@ func injectUserVars(cmd *cobra.Command, t *api.Template) {
35 35
 }
36 36
 
37 37
 // NewCmdProcess returns a 'process' command
38
-func NewCmdProcess(f *Factory, out io.Writer) *cobra.Command {
38
+func NewCmdProcess(f *clientcmd.Factory, out io.Writer) *cobra.Command {
39 39
 	cmd := &cobra.Command{
40 40
 		Use:   "process -f filename",
41 41
 		Short: "Process template into list of resources",
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"github.com/spf13/cobra"
10 10
 
11 11
 	describe "github.com/openshift/origin/pkg/cmd/cli/describe"
12
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12 13
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
13 14
 )
14 15
 
... ...
@@ -41,7 +42,7 @@ Examples:
41 41
   $ %[1]s %[2]s deployment-1 --output=json | %[1]s update deploymentConfigs deployment -f -
42 42
 `
43 43
 
44
-func NewCmdRollback(parentName string, name string, f *Factory, out io.Writer) *cobra.Command {
44
+func NewCmdRollback(parentName string, name string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
45 45
 	rollback := &deployapi.DeploymentConfigRollback{
46 46
 		Spec: deployapi.DeploymentConfigRollbackSpec{
47 47
 			IncludeTemplate: true,
... ...
@@ -11,9 +11,10 @@ import (
11 11
 	buildapi "github.com/openshift/origin/pkg/build/api"
12 12
 	buildutil "github.com/openshift/origin/pkg/build/util"
13 13
 	osclient "github.com/openshift/origin/pkg/client"
14
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
14 15
 )
15 16
 
16
-func NewCmdStartBuild(f *Factory, out io.Writer) *cobra.Command {
17
+func NewCmdStartBuild(f *clientcmd.Factory, out io.Writer) *cobra.Command {
17 18
 	cmd := &cobra.Command{
18 19
 		Use:   "start-build (<buildConfig>|--from-build=<build>)",
19 20
 		Short: "Starts a new build from existing build or buildConfig",
... ...
@@ -15,8 +15,6 @@ import (
15 15
 
16 16
 	"github.com/openshift/origin/pkg/api/latest"
17 17
 	osclient "github.com/openshift/origin/pkg/client"
18
-	"github.com/openshift/origin/pkg/cmd/cli"
19
-	"github.com/openshift/origin/pkg/cmd/cli/cmd"
20 18
 	cmdutil "github.com/openshift/origin/pkg/cmd/util"
21 19
 	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
22 20
 	dh "github.com/openshift/origin/pkg/cmd/util/docker"
... ...
@@ -77,18 +75,16 @@ type params struct {
77 77
 	env cmdutil.Environment
78 78
 }
79 79
 
80
-func NewCmdGenerate(name string) *cobra.Command {
81
-	cfg := clientcmd.NewConfig()
80
+func NewCmdGenerate(f *clientcmd.Factory, parentName, name string) *cobra.Command {
82 81
 	dockerHelper := dh.NewHelper()
83 82
 	input := params{}
84
-	var factory *cmd.Factory
85 83
 
86 84
 	c := &cobra.Command{
87 85
 		Use:   fmt.Sprintf("%s%s", name, clientcmd.ConfigSyntax),
88 86
 		Short: "Generates an application configuration from a source repository",
89 87
 		Long:  longDescription,
90 88
 		Run: func(c *cobra.Command, args []string) {
91
-			_, osClient, err := cfg.Clients()
89
+			osClient, _, err := f.Clients(c)
92 90
 			if err != nil {
93 91
 				osClient = nil
94 92
 			}
... ...
@@ -116,7 +112,7 @@ func NewCmdGenerate(name string) *cobra.Command {
116 116
 				}
117 117
 				input.env = env
118 118
 			}
119
-			namespace, err := factory.DefaultNamespace(c)
119
+			namespace, err := f.DefaultNamespace(c)
120 120
 			if err != nil {
121 121
 				namespace = ""
122 122
 			}
... ...
@@ -127,9 +123,6 @@ func NewCmdGenerate(name string) *cobra.Command {
127 127
 			}
128 128
 		},
129 129
 	}
130
-	clientConfig := cli.DefaultClientConfig(c.PersistentFlags())
131
-	factory = cmd.NewFactory(clientConfig)
132
-	factory.BindFlags(c.PersistentFlags())
133 130
 
134 131
 	flag := c.Flags()
135 132
 	flag.StringVar(&input.name, "name", "", "Set name to use for generated application artifacts")
... ...
@@ -14,23 +14,18 @@ import (
14 14
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
15 15
 
16 16
 	"github.com/openshift/origin/pkg/client"
17
-	"github.com/openshift/origin/pkg/cmd/cli/cmd"
18 17
 	"github.com/openshift/origin/pkg/cmd/flagtypes"
19
-	cmdutil "github.com/openshift/origin/pkg/cmd/util"
18
+	osclientcmd "github.com/openshift/origin/pkg/cmd/util/clientcmd"
20 19
 	"github.com/openshift/origin/pkg/cmd/util/tokencmd"
21 20
 )
22 21
 
23
-func NewCmdLogin(name string, parent *cobra.Command) *cobra.Command {
24
-	clientConfig := cmdutil.DefaultClientConfig(parent.PersistentFlags())
25
-	f := cmd.NewFactory(clientConfig)
26
-	f.BindFlags(parent.PersistentFlags())
27
-
22
+func NewCmdLogin(f *osclientcmd.Factory, parentName, name string) *cobra.Command {
28 23
 	cmds := &cobra.Command{
29 24
 		Use:   name,
30 25
 		Short: "Logs in and returns a session token",
31 26
 		Long: `Logs in to the OpenShift server and prints out a session token.
32 27
 
33
-Username and password can be provided through flags, the command will 
28
+Username and password can be provided through flags, the command will
34 29
 prompt for user input if not provided.
35 30
 `,
36 31
 		Run: func(cmd *cobra.Command, args []string) {
... ...
@@ -1,26 +1,26 @@
1 1
 package policy
2 2
 
3 3
 import (
4
-	"fmt"
5
-
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7 4
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
5
+	"github.com/golang/glog"
8 6
 	"github.com/spf13/cobra"
9 7
 
10 8
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
11 9
 	"github.com/openshift/origin/pkg/client"
10
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12 11
 )
13 12
 
14 13
 type addGroupOptions struct {
15
-	roleNamespace string
16
-	roleName      string
17
-	clientConfig  clientcmd.ClientConfig
14
+	roleNamespace    string
15
+	roleName         string
16
+	bindingNamespace string
17
+	client           client.Interface
18 18
 
19 19
 	groupNames []string
20 20
 }
21 21
 
22
-func NewCmdAddGroup(clientConfig clientcmd.ClientConfig) *cobra.Command {
23
-	options := &addGroupOptions{clientConfig: clientConfig}
22
+func NewCmdAddGroup(f *clientcmd.Factory) *cobra.Command {
23
+	options := &addGroupOptions{}
24 24
 
25 25
 	cmd := &cobra.Command{
26 26
 		Use:   "add-group <role> <group> [group]...",
... ...
@@ -31,9 +31,15 @@ func NewCmdAddGroup(clientConfig clientcmd.ClientConfig) *cobra.Command {
31 31
 				return
32 32
 			}
33 33
 
34
-			err := options.run()
35
-			if err != nil {
36
-				fmt.Printf("%v\n", err)
34
+			var err error
35
+			if options.client, _, err = f.Clients(cmd); err != nil {
36
+				glog.Fatalf("Error getting client: %v", err)
37
+			}
38
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
39
+				glog.Fatalf("Error getting client: %v", err)
40
+			}
41
+			if err := options.run(); err != nil {
42
+				glog.Fatal(err)
37 43
 			}
38 44
 		},
39 45
 	}
... ...
@@ -56,20 +62,7 @@ func (o *addGroupOptions) complete(cmd *cobra.Command) bool {
56 56
 }
57 57
 
58 58
 func (o *addGroupOptions) run() error {
59
-	clientConfig, err := o.clientConfig.ClientConfig()
60
-	if err != nil {
61
-		return err
62
-	}
63
-	client, err := client.New(clientConfig)
64
-	if err != nil {
65
-		return err
66
-	}
67
-	namespace, err := o.clientConfig.Namespace()
68
-	if err != nil {
69
-		return err
70
-	}
71
-
72
-	roleBindings, roleBindingNames, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, namespace, client)
59
+	roleBindings, roleBindingNames, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, o.bindingNamespace, o.client)
73 60
 	if err != nil {
74 61
 		return err
75 62
 	}
... ...
@@ -92,10 +85,10 @@ func (o *addGroupOptions) run() error {
92 92
 	roleBinding.GroupNames = groups.List()
93 93
 
94 94
 	if isUpdate {
95
-		_, err = client.RoleBindings(namespace).Update(roleBinding)
95
+		_, err = o.client.RoleBindings(o.bindingNamespace).Update(roleBinding)
96 96
 	} else {
97 97
 		roleBinding.Name = getUniqueName(o.roleName, roleBindingNames)
98
-		_, err = client.RoleBindings(namespace).Create(roleBinding)
98
+		_, err = o.client.RoleBindings(o.bindingNamespace).Create(roleBinding)
99 99
 	}
100 100
 	if err != nil {
101 101
 		return err
... ...
@@ -1,26 +1,26 @@
1 1
 package policy
2 2
 
3 3
 import (
4
-	"fmt"
5
-
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7 4
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
5
+	"github.com/golang/glog"
8 6
 	"github.com/spf13/cobra"
9 7
 
10 8
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
11 9
 	"github.com/openshift/origin/pkg/client"
10
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12 11
 )
13 12
 
14 13
 type addUserOptions struct {
15
-	roleNamespace string
16
-	roleName      string
17
-	clientConfig  clientcmd.ClientConfig
14
+	roleNamespace    string
15
+	roleName         string
16
+	bindingNamespace string
17
+	client           client.Interface
18 18
 
19 19
 	userNames []string
20 20
 }
21 21
 
22
-func NewCmdAddUser(clientConfig clientcmd.ClientConfig) *cobra.Command {
23
-	options := &addUserOptions{clientConfig: clientConfig}
22
+func NewCmdAddUser(f *clientcmd.Factory) *cobra.Command {
23
+	options := &addUserOptions{}
24 24
 
25 25
 	cmd := &cobra.Command{
26 26
 		Use:   "add-user <role> <user> [user]...",
... ...
@@ -31,9 +31,15 @@ func NewCmdAddUser(clientConfig clientcmd.ClientConfig) *cobra.Command {
31 31
 				return
32 32
 			}
33 33
 
34
-			err := options.run()
35
-			if err != nil {
36
-				fmt.Printf("%v\n", err)
34
+			var err error
35
+			if options.client, _, err = f.Clients(cmd); err != nil {
36
+				glog.Fatalf("Error getting client: %v", err)
37
+			}
38
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
39
+				glog.Fatalf("Error getting client: %v", err)
40
+			}
41
+			if err := options.run(); err != nil {
42
+				glog.Fatal(err)
37 43
 			}
38 44
 		},
39 45
 	}
... ...
@@ -56,20 +62,7 @@ func (o *addUserOptions) complete(cmd *cobra.Command) bool {
56 56
 }
57 57
 
58 58
 func (o *addUserOptions) run() error {
59
-	clientConfig, err := o.clientConfig.ClientConfig()
60
-	if err != nil {
61
-		return err
62
-	}
63
-	client, err := client.New(clientConfig)
64
-	if err != nil {
65
-		return err
66
-	}
67
-	namespace, err := o.clientConfig.Namespace()
68
-	if err != nil {
69
-		return err
70
-	}
71
-
72
-	roleBindings, roleBindingNames, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, namespace, client)
59
+	roleBindings, roleBindingNames, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, o.bindingNamespace, o.client)
73 60
 	if err != nil {
74 61
 		return err
75 62
 	}
... ...
@@ -92,10 +85,10 @@ func (o *addUserOptions) run() error {
92 92
 	roleBinding.UserNames = users.List()
93 93
 
94 94
 	if isUpdate {
95
-		_, err = client.RoleBindings(namespace).Update(roleBinding)
95
+		_, err = o.client.RoleBindings(o.bindingNamespace).Update(roleBinding)
96 96
 	} else {
97 97
 		roleBinding.Name = getUniqueName(o.roleName, roleBindingNames)
98
-		_, err = client.RoleBindings(namespace).Create(roleBinding)
98
+		_, err = o.client.RoleBindings(o.bindingNamespace).Create(roleBinding)
99 99
 	}
100 100
 	if err != nil {
101 101
 		return err
... ...
@@ -4,17 +4,16 @@ import (
4 4
 	"fmt"
5 5
 	"strings"
6 6
 
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
8 7
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
9 8
 	"github.com/golang/glog"
10 9
 	"github.com/spf13/cobra"
11 10
 
12 11
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
13 12
 	"github.com/openshift/origin/pkg/client"
14
-	cmdutil "github.com/openshift/origin/pkg/cmd/util"
13
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
15 14
 )
16 15
 
17
-func NewCommandPolicy(name string) *cobra.Command {
16
+func NewCommandPolicy(f *clientcmd.Factory, parentName, name string) *cobra.Command {
18 17
 	// Parent command to which all subcommands are added.
19 18
 	cmds := &cobra.Command{
20 19
 		Use:   name,
... ...
@@ -23,17 +22,13 @@ func NewCommandPolicy(name string) *cobra.Command {
23 23
 		Run:   runHelp,
24 24
 	}
25 25
 
26
-	// Override global default to https and port 8443
27
-	clientcmd.DefaultCluster.Server = "https://localhost:8443"
28
-	clientConfig := cmdutil.DefaultClientConfig(cmds.PersistentFlags())
29
-
30
-	cmds.AddCommand(NewCmdAddUser(clientConfig))
31
-	cmds.AddCommand(NewCmdRemoveUser(clientConfig))
32
-	cmds.AddCommand(NewCmdRemoveUserFromProject(clientConfig))
33
-	cmds.AddCommand(NewCmdAddGroup(clientConfig))
34
-	cmds.AddCommand(NewCmdRemoveGroup(clientConfig))
35
-	cmds.AddCommand(NewCmdRemoveGroupFromProject(clientConfig))
36
-	cmds.AddCommand(NewCmdWhoCan(clientConfig))
26
+	cmds.AddCommand(NewCmdAddUser(f))
27
+	cmds.AddCommand(NewCmdRemoveUser(f))
28
+	cmds.AddCommand(NewCmdRemoveUserFromProject(f))
29
+	cmds.AddCommand(NewCmdAddGroup(f))
30
+	cmds.AddCommand(NewCmdRemoveGroup(f))
31
+	cmds.AddCommand(NewCmdRemoveGroupFromProject(f))
32
+	cmds.AddCommand(NewCmdWhoCan(f))
37 33
 
38 34
 	return cmds
39 35
 }
... ...
@@ -65,7 +60,7 @@ func getUniqueName(basename string, existingNames *util.StringSet) string {
65 65
 	return string(util.NewUUID())
66 66
 }
67 67
 
68
-func getExistingRoleBindingsForRole(roleNamespace, role, bindingNamespace string, client *client.Client) ([]*authorizationapi.RoleBinding, *util.StringSet, error) {
68
+func getExistingRoleBindingsForRole(roleNamespace, role, bindingNamespace string, client client.Interface) ([]*authorizationapi.RoleBinding, *util.StringSet, error) {
69 69
 	existingBindings, err := client.PolicyBindings(bindingNamespace).Get(roleNamespace)
70 70
 	if err != nil && !strings.Contains(err.Error(), " not found") {
71 71
 		return nil, &util.StringSet{}, err
... ...
@@ -3,23 +3,25 @@ package policy
3 3
 import (
4 4
 	"fmt"
5 5
 
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7 6
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
7
+	"github.com/golang/glog"
8 8
 	"github.com/spf13/cobra"
9 9
 
10 10
 	"github.com/openshift/origin/pkg/client"
11
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
11 12
 )
12 13
 
13 14
 type removeGroupOptions struct {
14
-	roleNamespace string
15
-	roleName      string
16
-	clientConfig  clientcmd.ClientConfig
15
+	roleNamespace    string
16
+	roleName         string
17
+	bindingNamespace string
18
+	client           client.Interface
17 19
 
18 20
 	groupNames []string
19 21
 }
20 22
 
21
-func NewCmdRemoveGroup(clientConfig clientcmd.ClientConfig) *cobra.Command {
22
-	options := &removeGroupOptions{clientConfig: clientConfig}
23
+func NewCmdRemoveGroup(f *clientcmd.Factory) *cobra.Command {
24
+	options := &removeGroupOptions{}
23 25
 
24 26
 	cmd := &cobra.Command{
25 27
 		Use:   "remove-group <role> <group> [group]...",
... ...
@@ -30,9 +32,15 @@ func NewCmdRemoveGroup(clientConfig clientcmd.ClientConfig) *cobra.Command {
30 30
 				return
31 31
 			}
32 32
 
33
-			err := options.run()
34
-			if err != nil {
35
-				fmt.Printf("%v\n", err)
33
+			var err error
34
+			if options.client, _, err = f.Clients(cmd); err != nil {
35
+				glog.Fatalf("Error getting client: %v", err)
36
+			}
37
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
38
+				glog.Fatalf("Error getting client: %v", err)
39
+			}
40
+			if err := options.run(); err != nil {
41
+				glog.Fatal(err)
36 42
 			}
37 43
 		},
38 44
 	}
... ...
@@ -55,25 +63,12 @@ func (o *removeGroupOptions) complete(cmd *cobra.Command) bool {
55 55
 }
56 56
 
57 57
 func (o *removeGroupOptions) run() error {
58
-	clientConfig, err := o.clientConfig.ClientConfig()
59
-	if err != nil {
60
-		return err
61
-	}
62
-	client, err := client.New(clientConfig)
63
-	if err != nil {
64
-		return err
65
-	}
66
-	namespace, err := o.clientConfig.Namespace()
67
-	if err != nil {
68
-		return err
69
-	}
70
-
71
-	roleBindings, _, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, namespace, client)
58
+	roleBindings, _, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, o.bindingNamespace, o.client)
72 59
 	if err != nil {
73 60
 		return err
74 61
 	}
75 62
 	if len(roleBindings) == 0 {
76
-		return fmt.Errorf("unable to locate RoleBinding for %v::%v in %v", o.roleNamespace, o.roleName, namespace)
63
+		return fmt.Errorf("unable to locate RoleBinding for %v::%v in %v", o.roleNamespace, o.roleName, o.bindingNamespace)
77 64
 	}
78 65
 
79 66
 	for _, roleBinding := range roleBindings {
... ...
@@ -82,7 +77,7 @@ func (o *removeGroupOptions) run() error {
82 82
 		groups.Delete(o.groupNames...)
83 83
 		roleBinding.GroupNames = groups.List()
84 84
 
85
-		_, err = client.RoleBindings(namespace).Update(roleBinding)
85
+		_, err = o.client.RoleBindings(o.bindingNamespace).Update(roleBinding)
86 86
 		if err != nil {
87 87
 			return err
88 88
 		}
... ...
@@ -1,24 +1,24 @@
1 1
 package policy
2 2
 
3 3
 import (
4
-	"fmt"
5
-
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7
-	klabels "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
4
+	labels "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
8 5
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
6
+	"github.com/golang/glog"
9 7
 	"github.com/spf13/cobra"
10 8
 
11 9
 	"github.com/openshift/origin/pkg/client"
10
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12 11
 )
13 12
 
14 13
 type removeGroupFromProjectOptions struct {
15
-	clientConfig clientcmd.ClientConfig
14
+	bindingNamespace string
15
+	client           client.Interface
16 16
 
17 17
 	groupNames []string
18 18
 }
19 19
 
20
-func NewCmdRemoveGroupFromProject(clientConfig clientcmd.ClientConfig) *cobra.Command {
21
-	options := &removeGroupFromProjectOptions{clientConfig: clientConfig}
20
+func NewCmdRemoveGroupFromProject(f *clientcmd.Factory) *cobra.Command {
21
+	options := &removeGroupFromProjectOptions{}
22 22
 
23 23
 	cmd := &cobra.Command{
24 24
 		Use:   "remove-group-from-project  <group> [group]...",
... ...
@@ -29,9 +29,16 @@ func NewCmdRemoveGroupFromProject(clientConfig clientcmd.ClientConfig) *cobra.Co
29 29
 				return
30 30
 			}
31 31
 
32
-			err := options.run()
33
-			if err != nil {
34
-				fmt.Printf("%v\n", err)
32
+			var err error
33
+			if options.client, _, err = f.Clients(cmd); err != nil {
34
+				glog.Fatalf("Error getting client: %v", err)
35
+			}
36
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
37
+				glog.Fatalf("Error getting client: %v", err)
38
+			}
39
+
40
+			if err := options.run(); err != nil {
41
+				glog.Fatal(err)
35 42
 			}
36 43
 		},
37 44
 	}
... ...
@@ -51,20 +58,7 @@ func (o *removeGroupFromProjectOptions) complete(cmd *cobra.Command) bool {
51 51
 }
52 52
 
53 53
 func (o *removeGroupFromProjectOptions) run() error {
54
-	clientConfig, err := o.clientConfig.ClientConfig()
55
-	if err != nil {
56
-		return err
57
-	}
58
-	client, err := client.New(clientConfig)
59
-	if err != nil {
60
-		return err
61
-	}
62
-	namespace, err := o.clientConfig.Namespace()
63
-	if err != nil {
64
-		return err
65
-	}
66
-
67
-	bindingList, err := client.PolicyBindings(namespace).List(klabels.Everything(), klabels.Everything())
54
+	bindingList, err := o.client.PolicyBindings(o.bindingNamespace).List(labels.Everything(), labels.Everything())
68 55
 	if err != nil {
69 56
 		return err
70 57
 	}
... ...
@@ -77,7 +71,7 @@ func (o *removeGroupFromProjectOptions) run() error {
77 77
 
78 78
 			currBinding.GroupNames = groupsForBinding.List()
79 79
 
80
-			_, err = client.RoleBindings(namespace).Update(&currBinding)
80
+			_, err = o.client.RoleBindings(o.bindingNamespace).Update(&currBinding)
81 81
 			if err != nil {
82 82
 				return err
83 83
 			}
... ...
@@ -3,23 +3,25 @@ package policy
3 3
 import (
4 4
 	"fmt"
5 5
 
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7 6
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
7
+	"github.com/golang/glog"
8 8
 	"github.com/spf13/cobra"
9 9
 
10 10
 	"github.com/openshift/origin/pkg/client"
11
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
11 12
 )
12 13
 
13 14
 type removeUserOptions struct {
14
-	roleNamespace string
15
-	roleName      string
16
-	clientConfig  clientcmd.ClientConfig
15
+	roleNamespace    string
16
+	roleName         string
17
+	bindingNamespace string
18
+	client           client.Interface
17 19
 
18 20
 	userNames []string
19 21
 }
20 22
 
21
-func NewCmdRemoveUser(clientConfig clientcmd.ClientConfig) *cobra.Command {
22
-	options := &removeUserOptions{clientConfig: clientConfig}
23
+func NewCmdRemoveUser(f *clientcmd.Factory) *cobra.Command {
24
+	options := &removeUserOptions{}
23 25
 
24 26
 	cmd := &cobra.Command{
25 27
 		Use:   "remove-user <role> <user> [user]...",
... ...
@@ -30,9 +32,15 @@ func NewCmdRemoveUser(clientConfig clientcmd.ClientConfig) *cobra.Command {
30 30
 				return
31 31
 			}
32 32
 
33
-			err := options.run()
34
-			if err != nil {
35
-				fmt.Printf("%v\n", err)
33
+			var err error
34
+			if options.client, _, err = f.Clients(cmd); err != nil {
35
+				glog.Fatalf("Error getting client: %v", err)
36
+			}
37
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
38
+				glog.Fatalf("Error getting client: %v", err)
39
+			}
40
+			if err := options.run(); err != nil {
41
+				glog.Fatal(err)
36 42
 			}
37 43
 		},
38 44
 	}
... ...
@@ -55,25 +63,12 @@ func (o *removeUserOptions) complete(cmd *cobra.Command) bool {
55 55
 }
56 56
 
57 57
 func (o *removeUserOptions) run() error {
58
-	clientConfig, err := o.clientConfig.ClientConfig()
59
-	if err != nil {
60
-		return err
61
-	}
62
-	client, err := client.New(clientConfig)
63
-	if err != nil {
64
-		return err
65
-	}
66
-	namespace, err := o.clientConfig.Namespace()
67
-	if err != nil {
68
-		return err
69
-	}
70
-
71
-	roleBindings, _, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, namespace, client)
58
+	roleBindings, _, err := getExistingRoleBindingsForRole(o.roleNamespace, o.roleName, o.bindingNamespace, o.client)
72 59
 	if err != nil {
73 60
 		return err
74 61
 	}
75 62
 	if len(roleBindings) == 0 {
76
-		return fmt.Errorf("unable to locate RoleBinding for %v::%v in %v", o.roleNamespace, o.roleName, namespace)
63
+		return fmt.Errorf("unable to locate RoleBinding for %v::%v in %v", o.roleNamespace, o.roleName, o.bindingNamespace)
77 64
 	}
78 65
 
79 66
 	for _, roleBinding := range roleBindings {
... ...
@@ -82,7 +77,7 @@ func (o *removeUserOptions) run() error {
82 82
 		users.Delete(o.userNames...)
83 83
 		roleBinding.UserNames = users.List()
84 84
 
85
-		_, err = client.RoleBindings(namespace).Update(roleBinding)
85
+		_, err = o.client.RoleBindings(o.bindingNamespace).Update(roleBinding)
86 86
 		if err != nil {
87 87
 			return err
88 88
 		}
... ...
@@ -1,24 +1,24 @@
1 1
 package policy
2 2
 
3 3
 import (
4
-	"fmt"
5
-
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7
-	klabels "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
4
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
8 5
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
6
+	"github.com/golang/glog"
9 7
 	"github.com/spf13/cobra"
10 8
 
11 9
 	"github.com/openshift/origin/pkg/client"
10
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12 11
 )
13 12
 
14 13
 type removeUserFromProjectOptions struct {
15
-	clientConfig clientcmd.ClientConfig
14
+	bindingNamespace string
15
+	client           client.Interface
16 16
 
17 17
 	userNames []string
18 18
 }
19 19
 
20
-func NewCmdRemoveUserFromProject(clientConfig clientcmd.ClientConfig) *cobra.Command {
21
-	options := &removeUserFromProjectOptions{clientConfig: clientConfig}
20
+func NewCmdRemoveUserFromProject(f *clientcmd.Factory) *cobra.Command {
21
+	options := &removeUserFromProjectOptions{}
22 22
 
23 23
 	cmd := &cobra.Command{
24 24
 		Use:   "remove-user-from-project  <user> [user]...",
... ...
@@ -29,9 +29,15 @@ func NewCmdRemoveUserFromProject(clientConfig clientcmd.ClientConfig) *cobra.Com
29 29
 				return
30 30
 			}
31 31
 
32
-			err := options.run()
33
-			if err != nil {
34
-				fmt.Printf("%v\n", err)
32
+			var err error
33
+			if options.client, _, err = f.Clients(cmd); err != nil {
34
+				glog.Fatalf("Error getting client: %v", err)
35
+			}
36
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
37
+				glog.Fatalf("Error getting client: %v", err)
38
+			}
39
+			if err := options.run(); err != nil {
40
+				glog.Fatal(err)
35 41
 			}
36 42
 		},
37 43
 	}
... ...
@@ -51,20 +57,7 @@ func (o *removeUserFromProjectOptions) complete(cmd *cobra.Command) bool {
51 51
 }
52 52
 
53 53
 func (o *removeUserFromProjectOptions) run() error {
54
-	clientConfig, err := o.clientConfig.ClientConfig()
55
-	if err != nil {
56
-		return err
57
-	}
58
-	client, err := client.New(clientConfig)
59
-	if err != nil {
60
-		return err
61
-	}
62
-	namespace, err := o.clientConfig.Namespace()
63
-	if err != nil {
64
-		return err
65
-	}
66
-
67
-	bindingList, err := client.PolicyBindings(namespace).List(klabels.Everything(), klabels.Everything())
54
+	bindingList, err := o.client.PolicyBindings(o.bindingNamespace).List(labels.Everything(), labels.Everything())
68 55
 	if err != nil {
69 56
 		return err
70 57
 	}
... ...
@@ -77,7 +70,7 @@ func (o *removeUserFromProjectOptions) run() error {
77 77
 
78 78
 			currBinding.UserNames = usersForBinding.List()
79 79
 
80
-			_, err = client.RoleBindings(namespace).Update(&currBinding)
80
+			_, err = o.client.RoleBindings(o.bindingNamespace).Update(&currBinding)
81 81
 			if err != nil {
82 82
 				return err
83 83
 			}
... ...
@@ -3,23 +3,24 @@ package policy
3 3
 import (
4 4
 	"fmt"
5 5
 
6
+	"github.com/golang/glog"
6 7
 	"github.com/spf13/cobra"
7 8
 
8
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
9
-
10 9
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
11 10
 	"github.com/openshift/origin/pkg/client"
11
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
12 12
 )
13 13
 
14 14
 type whoCanOptions struct {
15
-	clientConfig clientcmd.ClientConfig
15
+	bindingNamespace string
16
+	client           client.Interface
16 17
 
17 18
 	verb     string
18 19
 	resource string
19 20
 }
20 21
 
21
-func NewCmdWhoCan(clientConfig clientcmd.ClientConfig) *cobra.Command {
22
-	options := &whoCanOptions{clientConfig: clientConfig}
22
+func NewCmdWhoCan(f *clientcmd.Factory) *cobra.Command {
23
+	options := &whoCanOptions{}
23 24
 
24 25
 	cmd := &cobra.Command{
25 26
 		Use:   "who-can",
... ...
@@ -30,9 +31,15 @@ func NewCmdWhoCan(clientConfig clientcmd.ClientConfig) *cobra.Command {
30 30
 				return
31 31
 			}
32 32
 
33
-			err := options.run()
34
-			if err != nil {
35
-				fmt.Printf("%v\n", err)
33
+			var err error
34
+			if options.client, _, err = f.Clients(cmd); err != nil {
35
+				glog.Fatalf("Error getting client: %v", err)
36
+			}
37
+			if options.bindingNamespace, err = f.DefaultNamespace(cmd); err != nil {
38
+				glog.Fatalf("Error getting client: %v", err)
39
+			}
40
+			if err := options.run(); err != nil {
41
+				glog.Fatal(err)
36 42
 			}
37 43
 		},
38 44
 	}
... ...
@@ -53,24 +60,11 @@ func (o *whoCanOptions) complete(cmd *cobra.Command) bool {
53 53
 }
54 54
 
55 55
 func (o *whoCanOptions) run() error {
56
-	clientConfig, err := o.clientConfig.ClientConfig()
57
-	if err != nil {
58
-		return err
59
-	}
60
-	client, err := client.New(clientConfig)
61
-	if err != nil {
62
-		return err
63
-	}
64
-	namespace, err := o.clientConfig.Namespace()
65
-	if err != nil {
66
-		return err
67
-	}
68
-
69 56
 	resourceAccessReview := &authorizationapi.ResourceAccessReview{}
70 57
 	resourceAccessReview.Resource = o.resource
71 58
 	resourceAccessReview.Verb = o.verb
72 59
 
73
-	resourceAccessReviewResponse, err := client.ResourceAccessReviews(namespace).Create(resourceAccessReview)
60
+	resourceAccessReviewResponse, err := o.client.ResourceAccessReviews(o.bindingNamespace).Create(resourceAccessReview)
74 61
 	if err != nil {
75 62
 		return err
76 63
 	}
... ...
@@ -4,27 +4,28 @@ import (
4 4
 	"fmt"
5 5
 
6 6
 	kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
7
+	"github.com/golang/glog"
8 8
 	"github.com/spf13/cobra"
9 9
 
10 10
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
11 11
 	"github.com/openshift/origin/pkg/client"
12
-	cmdutil "github.com/openshift/origin/pkg/cmd/util"
12
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
13 13
 	projectapi "github.com/openshift/origin/pkg/project/api"
14 14
 )
15 15
 
16 16
 type newProjectOptions struct {
17
-	projectName  string
18
-	displayName  string
19
-	description  string
20
-	clientConfig clientcmd.ClientConfig
17
+	projectName string
18
+	displayName string
19
+	description string
20
+
21
+	client client.Interface
21 22
 
22 23
 	adminRole             string
23 24
 	masterPolicyNamespace string
24 25
 	adminUser             string
25 26
 }
26 27
 
27
-func NewCmdNewProject(name string) *cobra.Command {
28
+func NewCmdNewProject(f *clientcmd.Factory, parentName, name string) *cobra.Command {
28 29
 	options := &newProjectOptions{}
29 30
 
30 31
 	cmd := &cobra.Command{
... ...
@@ -36,18 +37,16 @@ func NewCmdNewProject(name string) *cobra.Command {
36 36
 				return
37 37
 			}
38 38
 
39
-			err := options.run()
40
-			if err != nil {
41
-				fmt.Printf("%v\n", err)
39
+			var err error
40
+			if options.client, _, err = f.Clients(cmd); err != nil {
41
+				glog.Fatalf("Error getting client: %v", err)
42
+			}
43
+			if err := options.run(); err != nil {
44
+				glog.Fatal(err)
42 45
 			}
43 46
 		},
44 47
 	}
45 48
 
46
-	// Override global default to https and port 8443
47
-	clientcmd.DefaultCluster.Server = "https://localhost:8443"
48
-	clientConfig := cmdutil.DefaultClientConfig(cmd.Flags())
49
-	options.clientConfig = clientConfig
50
-
51 49
 	// TODO remove once we have global policy objects
52 50
 	cmd.Flags().StringVar(&options.masterPolicyNamespace, "master-policy-namespace", "master", "master policy namespace")
53 51
 	cmd.Flags().StringVar(&options.adminRole, "admin-role", "admin", "project admin role name in the master policy namespace")
... ...
@@ -71,21 +70,11 @@ func (o *newProjectOptions) complete(cmd *cobra.Command) bool {
71 71
 }
72 72
 
73 73
 func (o *newProjectOptions) run() error {
74
-	clientConfig, err := o.clientConfig.ClientConfig()
75
-	if err != nil {
76
-		return err
77
-	}
78
-	client, err := client.New(clientConfig)
79
-	if err != nil {
80
-		return err
81
-	}
82
-
83
-	_, err = client.Projects().Get(o.projectName)
84
-	projectFound := !kerrors.IsNotFound(err)
85
-	if (err != nil) && (projectFound) {
86
-		return err
87
-	}
88
-	if projectFound {
74
+	if _, err := o.client.Projects().Get(o.projectName); err != nil {
75
+		if !kerrors.IsNotFound(err) {
76
+			return err
77
+		}
78
+	} else {
89 79
 		return fmt.Errorf("project %v already exists", o.projectName)
90 80
 	}
91 81
 
... ...
@@ -94,7 +83,7 @@ func (o *newProjectOptions) run() error {
94 94
 	project.DisplayName = o.displayName
95 95
 	project.Annotations = make(map[string]string)
96 96
 	project.Annotations["description"] = o.description
97
-	project, err = client.Projects().Create(project)
97
+	project, err := o.client.Projects().Create(project)
98 98
 	if err != nil {
99 99
 		return err
100 100
 	}
... ...
@@ -107,7 +96,7 @@ func (o *newProjectOptions) run() error {
107 107
 		adminRoleBinding.RoleRef.Name = o.adminRole
108 108
 		adminRoleBinding.UserNames = []string{o.adminUser}
109 109
 
110
-		_, err := client.RoleBindings(project.Name).Create(adminRoleBinding)
110
+		_, err := o.client.RoleBindings(project.Name).Create(adminRoleBinding)
111 111
 		if err != nil {
112 112
 			fmt.Printf("The project %v was created, but %v could not be added to the %v role.\n", o.projectName, o.adminUser, o.adminRole)
113 113
 			fmt.Printf("To add the user to the existing project, run\n\n\topenshift ex policy add-user --namespace=%v --role-namespace=%v %v %v\n", o.projectName, o.masterPolicyNamespace, o.adminRole, o.adminUser)
... ...
@@ -6,11 +6,11 @@ import (
6 6
 
7 7
 	"github.com/spf13/cobra"
8 8
 
9
-	"github.com/openshift/origin/pkg/cmd/cli/cmd"
9
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
10 10
 	"github.com/openshift/origin/pkg/cmd/util/tokencmd"
11 11
 )
12 12
 
13
-func NewCmdRequestToken(f *cmd.Factory) *cobra.Command {
13
+func NewCmdRequestToken(f *clientcmd.Factory) *cobra.Command {
14 14
 	cmd := &cobra.Command{
15 15
 		Use:   "request-token",
16 16
 		Short: "request an access token",
... ...
@@ -4,21 +4,19 @@ import (
4 4
 	"os"
5 5
 
6 6
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
8 7
 	"github.com/golang/glog"
9 8
 	"github.com/spf13/cobra"
10 9
 
11 10
 	"github.com/openshift/origin/pkg/auth/server/tokenrequest"
12
-	"github.com/openshift/origin/pkg/cmd/cli/cmd"
13 11
 	"github.com/openshift/origin/pkg/cmd/server/origin"
14
-	cmdutil "github.com/openshift/origin/pkg/cmd/util"
12
+	osclientcmd "github.com/openshift/origin/pkg/cmd/util/clientcmd"
15 13
 )
16 14
 
17 15
 const (
18 16
 	TOKEN_FILE_PARAM = "token-file"
19 17
 )
20 18
 
21
-func NewCmdTokens(name string) *cobra.Command {
19
+func NewCmdTokens(f *osclientcmd.Factory, parentName, name string) *cobra.Command {
22 20
 	// Parent command to which all subcommands are added.
23 21
 	cmds := &cobra.Command{
24 22
 		Use:   name,
... ...
@@ -30,13 +28,6 @@ func NewCmdTokens(name string) *cobra.Command {
30 30
 		},
31 31
 	}
32 32
 
33
-	// Override global default to https and port 8443
34
-	clientcmd.DefaultCluster.Server = "https://localhost:8443"
35
-
36
-	// TODO: there should be two client configs, one for OpenShift, and one for Kubernetes
37
-	f := cmd.NewFactory(cmdutil.DefaultClientConfig(cmds.PersistentFlags()))
38
-	f.BindFlags(cmds.PersistentFlags())
39
-
40 33
 	cmds.AddCommand(NewCmdValidateToken(f))
41 34
 	cmds.AddCommand(NewCmdRequestToken(f))
42 35
 	cmds.AddCommand(NewCmdWhoAmI(f))
... ...
@@ -9,11 +9,11 @@ import (
9 9
 	"github.com/spf13/cobra"
10 10
 
11 11
 	osclient "github.com/openshift/origin/pkg/client"
12
-	"github.com/openshift/origin/pkg/cmd/cli/cmd"
12
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
13 13
 	"github.com/openshift/origin/pkg/oauth/osintypes"
14 14
 )
15 15
 
16
-func NewCmdValidateToken(f *cmd.Factory) *cobra.Command {
16
+func NewCmdValidateToken(f *clientcmd.Factory) *cobra.Command {
17 17
 	cmd := &cobra.Command{
18 18
 		Use:   "validate-token",
19 19
 		Short: "validate an access token",
... ...
@@ -9,11 +9,11 @@ import (
9 9
 	"github.com/spf13/cobra"
10 10
 
11 11
 	osclient "github.com/openshift/origin/pkg/client"
12
-	"github.com/openshift/origin/pkg/cmd/cli/cmd"
12
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
13 13
 	"github.com/openshift/origin/pkg/cmd/util/tokencmd"
14 14
 )
15 15
 
16
-func NewCmdWhoAmI(f *cmd.Factory) *cobra.Command {
16
+func NewCmdWhoAmI(f *clientcmd.Factory) *cobra.Command {
17 17
 	cmd := &cobra.Command{
18 18
 		Use:   "whoami",
19 19
 		Short: "checks the identity associated with an access token",
... ...
@@ -20,6 +20,7 @@ import (
20 20
 	"github.com/openshift/origin/pkg/cmd/infra/router"
21 21
 	"github.com/openshift/origin/pkg/cmd/server"
22 22
 	"github.com/openshift/origin/pkg/cmd/templates"
23
+	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
23 24
 	"github.com/openshift/origin/pkg/version"
24 25
 )
25 26
 
... ...
@@ -110,12 +111,17 @@ func newExperimentalCommand(parentName, name string) *cobra.Command {
110 110
 			c.Help()
111 111
 		},
112 112
 	}
113
-	experimental.AddCommand(config.NewCmdConfig(fmt.Sprintf("%s %s", parentName, name), "config"))
114
-	experimental.AddCommand(tokens.NewCmdTokens("tokens"))
115
-	experimental.AddCommand(policy.NewCommandPolicy("policy"))
116
-	experimental.AddCommand(generate.NewCmdGenerate("generate"))
117
-	experimental.AddCommand(login.NewCmdLogin("login", experimental))
118
-	experimental.AddCommand(project.NewCmdNewProject("new-project"))
113
+
114
+	f := clientcmd.New(experimental.PersistentFlags())
115
+
116
+	subName := fmt.Sprintf("%s %s", parentName, name)
117
+	experimental.AddCommand(project.NewCmdNewProject(f, subName, "new-project"))
118
+	experimental.AddCommand(config.NewCmdConfig(subName, "config"))
119
+	experimental.AddCommand(tokens.NewCmdTokens(f, subName, "tokens"))
120
+	experimental.AddCommand(policy.NewCommandPolicy(f, subName, "policy"))
121
+	experimental.AddCommand(generate.NewCmdGenerate(f, subName, "generate"))
122
+	experimental.AddCommand(login.NewCmdLogin(f, subName, "login"))
123
+	//experimental.AddCommand(exrouter.NewCmdRouter(f, subName, "router", os.Stdout))
119 124
 	return experimental
120 125
 }
121 126
 
... ...
@@ -109,6 +109,8 @@ type config struct {
109 109
 	ImageFormat         string
110 110
 	LatestReleaseImages bool
111 111
 
112
+	ImageTemplate variable.ImageTemplate
113
+
112 114
 	Hostname  string
113 115
 	VolumeDir string
114 116
 
... ...
@@ -147,6 +149,8 @@ func NewCommandStartServer(name string) *cobra.Command {
147 147
 		MasterPublicAddr:     flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(),
148 148
 		KubernetesPublicAddr: flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default(),
149 149
 
150
+		ImageTemplate: variable.NewDefaultImageTemplate(),
151
+
150 152
 		Hostname: hostname,
151 153
 		NodeList: flagtypes.StringList{"127.0.0.1"},
152 154
 	}
... ...
@@ -172,8 +176,8 @@ func NewCommandStartServer(name string) *cobra.Command {
172 172
 	flag.Var(&cfg.KubernetesPublicAddr, "public-kubernetes", "The Kubernetes server address for use by public clients, if different. (host, host:port, or URL). Defaults to same as --kubernetes.")
173 173
 	flag.Var(&cfg.PortalNet, "portal-net", "A CIDR notation IP range from which to assign portal IPs. This must not overlap with any IP ranges assigned to nodes for pods.")
174 174
 
175
-	flag.StringVar(&cfg.ImageFormat, "images", "openshift/origin-${component}:${version}", "When fetching images used by the cluster for important components, use this format on both master and nodes. The latest release will be used by default.")
176
-	flag.BoolVar(&cfg.LatestReleaseImages, "latest-images", false, "If true, attempt to use the latest images for the cluster instead of the latest release.")
175
+	flag.StringVar(&cfg.ImageTemplate.Format, "images", cfg.ImageTemplate.Format, "When fetching images used by the cluster for important components, use this format on both master and nodes. The latest release will be used by default.")
176
+	flag.BoolVar(&cfg.ImageTemplate.Latest, "latest-images", cfg.ImageTemplate.Latest, "If true, attempt to use the latest images for the cluster instead of the latest release.")
177 177
 
178 178
 	flag.StringVar(&cfg.VolumeDir, "volume-dir", "openshift.local.volumes", "The volume storage directory.")
179 179
 	flag.StringVar(&cfg.EtcdDir, "etcd-dir", "openshift.local.etcd", "The etcd data directory.")
... ...
@@ -263,9 +267,7 @@ func start(cfg *config, args []string) error {
263 263
 	}
264 264
 
265 265
 	// define a function for resolving components to names
266
-	imageResolverFn := func(component string) string {
267
-		return expandImage(component, cfg.ImageFormat, cfg.LatestReleaseImages)
268
-	}
266
+	imageResolverFn := cfg.ImageTemplate.ExpandOrDie
269 267
 	useLocalImages := env("USE_LOCAL_IMAGES", "false") == "true"
270 268
 
271 269
 	// the node can reuse an existing client
272 270
new file mode 100644
... ...
@@ -0,0 +1,159 @@
0
+package clientcmd
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+
6
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
7
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
8
+	kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
9
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
10
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
11
+	kubecmd "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
12
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
13
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
14
+	"github.com/spf13/cobra"
15
+	"github.com/spf13/pflag"
16
+
17
+	"github.com/openshift/origin/pkg/api/latest"
18
+	"github.com/openshift/origin/pkg/client"
19
+	"github.com/openshift/origin/pkg/cmd/cli/describe"
20
+)
21
+
22
+const defaultClusterURL = "https://localhost:8443"
23
+
24
+// NewFactory creates a default Factory for commands that should share identical server
25
+// connection behavior. Most commands should use this method to get a factory.
26
+func New(flags *pflag.FlagSet) *Factory {
27
+	// Override global default to https and port 8443
28
+	clientcmd.DefaultCluster.Server = defaultClusterURL
29
+
30
+	// TODO: there should be two client configs, one for OpenShift, and one for Kubernetes
31
+	clientConfig := DefaultClientConfig(flags)
32
+	f := NewFactory(clientConfig)
33
+	f.BindFlags(flags)
34
+	return f
35
+}
36
+
37
+// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig
38
+func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
39
+	loadingRules := clientcmd.NewClientConfigLoadingRules()
40
+	loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
41
+	flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
42
+
43
+	overrides := &clientcmd.ConfigOverrides{}
44
+	overrideFlags := clientcmd.RecommendedConfigOverrideFlags("")
45
+	overrideFlags.ContextOverrideFlags.NamespaceShort = "n"
46
+	clientcmd.BindOverrideFlags(overrides, flags, overrideFlags)
47
+	clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
48
+
49
+	return clientConfig
50
+}
51
+
52
+// Factory provides common options for OpenShift commands
53
+type Factory struct {
54
+	*kubecmd.Factory
55
+	OpenShiftClientConfig clientcmd.ClientConfig
56
+}
57
+
58
+// NewFactory creates an object that holds common methods across all OpenShift commands
59
+func NewFactory(clientConfig clientcmd.ClientConfig) *Factory {
60
+	mapper := ShortcutExpander{kubectl.ShortcutExpander{latest.RESTMapper}}
61
+
62
+	w := &Factory{kubecmd.NewFactory(clientConfig), clientConfig}
63
+
64
+	w.Object = func(cmd *cobra.Command) (meta.RESTMapper, runtime.ObjectTyper) {
65
+		return mapper, api.Scheme
66
+	}
67
+
68
+	// Save original RESTClient function
69
+	kRESTClientFunc := w.Factory.RESTClient
70
+	w.RESTClient = func(cmd *cobra.Command, mapping *meta.RESTMapping) (resource.RESTClient, error) {
71
+		if latest.OriginKind(mapping.Kind, mapping.APIVersion) {
72
+			cfg, err := w.OpenShiftClientConfig.ClientConfig()
73
+			if err != nil {
74
+				return nil, fmt.Errorf("unable to find client config %s: %v", mapping.Kind, err)
75
+			}
76
+			cli, err := client.New(cfg)
77
+			if err != nil {
78
+				return nil, fmt.Errorf("unable to create client %s: %v", mapping.Kind, err)
79
+			}
80
+			return cli.RESTClient, nil
81
+		}
82
+		return kRESTClientFunc(cmd, mapping)
83
+	}
84
+
85
+	// Save original Describer function
86
+	kDescriberFunc := w.Factory.Describer
87
+	w.Describer = func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.Describer, error) {
88
+		if latest.OriginKind(mapping.Kind, mapping.APIVersion) {
89
+			cfg, err := w.OpenShiftClientConfig.ClientConfig()
90
+			if err != nil {
91
+				return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
92
+			}
93
+			cli, err := client.New(cfg)
94
+			if err != nil {
95
+				return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
96
+			}
97
+			kubeClient, err := kclient.New(cfg)
98
+			if err != nil {
99
+				return nil, fmt.Errorf("unable to describe %s: %v", mapping.Kind, err)
100
+			}
101
+			describer, ok := describe.DescriberFor(mapping.Kind, cli, kubeClient, "")
102
+			if !ok {
103
+				return nil, fmt.Errorf("no description has been implemented for %q", mapping.Kind)
104
+			}
105
+			return describer, nil
106
+		}
107
+		return kDescriberFunc(cmd, mapping)
108
+	}
109
+
110
+	w.Printer = func(cmd *cobra.Command, mapping *meta.RESTMapping, noHeaders bool) (kubectl.ResourcePrinter, error) {
111
+		return describe.NewHumanReadablePrinter(noHeaders), nil
112
+	}
113
+
114
+	return w
115
+}
116
+
117
+// Clients returns an OpenShift and Kubernetes client.
118
+func (f *Factory) Clients(cmd *cobra.Command) (*client.Client, *kclient.Client, error) {
119
+	os, err := f.OpenShiftClientConfig.ClientConfig()
120
+	if err != nil {
121
+		return nil, nil, err
122
+	}
123
+	oc, err := client.New(os)
124
+	if err != nil {
125
+		return nil, nil, err
126
+	}
127
+	kc, err := f.Client(cmd)
128
+	if err != nil {
129
+		return nil, nil, err
130
+	}
131
+	return oc, kc, nil
132
+}
133
+
134
+// ShortcutExpander is a RESTMapper that can be used for OpenShift resources.
135
+type ShortcutExpander struct {
136
+	meta.RESTMapper
137
+}
138
+
139
+// VersionAndKindForResource implements meta.RESTMapper. It expands the resource first, then invokes the wrapped
140
+// mapper.
141
+func (e ShortcutExpander) VersionAndKindForResource(resource string) (defaultVersion, kind string, err error) {
142
+	resource = expandResourceShortcut(resource)
143
+	return e.RESTMapper.VersionAndKindForResource(resource)
144
+}
145
+
146
+// expandResourceShortcut will return the expanded version of resource
147
+// (something that a pkg/api/meta.RESTMapper can understand), if it is
148
+// indeed a shortcut. Otherwise, will return resource unmodified.
149
+func expandResourceShortcut(resource string) string {
150
+	shortForms := map[string]string{
151
+		"dc": "deploymentConfigs",
152
+		"bc": "buildConfigs",
153
+	}
154
+	if expanded, ok := shortForms[resource]; ok {
155
+		return expanded
156
+	}
157
+	return resource
158
+}
0 159
new file mode 100644
... ...
@@ -0,0 +1,70 @@
0
+package variable
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"strings"
6
+
7
+	"github.com/golang/glog"
8
+)
9
+
10
+// ImageTemplate is a class to assist in expanding parameterized Docker image references
11
+// from configuration or a file
12
+type ImageTemplate struct {
13
+	// Required, set to the image template to pull
14
+	Format string
15
+	Latest bool
16
+	// Optional, if set will substitute the value of ${component} with any env
17
+	// var that matches this format. Is a printf format string accepting a single
18
+	// string parameter.
19
+	EnvFormat string
20
+}
21
+
22
+const defaultImageFormat = "openshift/origin-${component}:${version}"
23
+const defaultImageEnvFormat = "OPENSHIFT_%s_IMAGE"
24
+
25
+func NewDefaultImageTemplate() ImageTemplate {
26
+	return ImageTemplate{
27
+		Format:    defaultImageFormat,
28
+		Latest:    false,
29
+		EnvFormat: defaultImageEnvFormat,
30
+	}
31
+}
32
+
33
+func (t *ImageTemplate) ExpandOrDie(component string) string {
34
+	value, err := t.Expand(component)
35
+	if err != nil {
36
+		glog.Fatalf("Unable to find an image for %q due to an error processing the format: %v", err)
37
+	}
38
+	return value
39
+}
40
+
41
+func (t *ImageTemplate) Expand(component string) (string, error) {
42
+	template := t.Format
43
+	if len(t.EnvFormat) > 0 {
44
+		if s, ok := t.imageComponentEnvExpander(component); ok {
45
+			template = s
46
+		}
47
+	}
48
+	value, err := ExpandStrict(template, func(key string) (string, bool) {
49
+		switch key {
50
+		case "component":
51
+			return component, true
52
+		case "version":
53
+			if t.Latest {
54
+				return "latest", true
55
+			}
56
+		}
57
+		return "", false
58
+	}, Versions)
59
+	return value, err
60
+}
61
+
62
+func (t *ImageTemplate) imageComponentEnvExpander(key string) (string, bool) {
63
+	s := strings.Replace(strings.ToUpper(key), "-", "_", -1)
64
+	val := os.Getenv(fmt.Sprintf(t.EnvFormat, s))
65
+	if len(val) == 0 {
66
+		return "", false
67
+	}
68
+	return val, true
69
+}
0 70
new file mode 100644
... ...
@@ -0,0 +1,66 @@
0
+package cmd
1
+
2
+import (
3
+	"fmt"
4
+	"io"
5
+
6
+	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
7
+	kubecmd "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
8
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
9
+	"github.com/spf13/cobra"
10
+)
11
+
12
+// Bulk provides helpers for iterating over a list of items
13
+type Bulk struct {
14
+	Factory *kubecmd.Factory
15
+	Command *cobra.Command
16
+	After   func(*resource.Info, error)
17
+}
18
+
19
+func NewPrintNameOrErrorAfter(out, errs io.Writer) func(*resource.Info, error) {
20
+	return func(info *resource.Info, err error) {
21
+		if err == nil {
22
+			fmt.Fprintf(out, "%s\n", info.Name)
23
+		} else {
24
+			fmt.Fprintf(errs, "%v\n", err)
25
+		}
26
+	}
27
+}
28
+
29
+// Create attempts to create each item generically, gathering all errors in the
30
+// event a failure occurs. The contents of list will be updated to include the
31
+// version from the server.
32
+func (b *Bulk) Create(list *kapi.List, namespace string) []error {
33
+	mapper, typer := b.Factory.Object(b.Command)
34
+	resourceMapper := &resource.Mapper{typer, mapper, b.Factory.ClientMapperForCommand(b.Command)}
35
+	after := b.After
36
+	if after == nil {
37
+		after = func(*resource.Info, error) {}
38
+	}
39
+
40
+	errs := []error{}
41
+	for i, item := range list.Items {
42
+		info, err := resourceMapper.InfoForObject(item)
43
+		if err != nil {
44
+			errs = append(errs, err)
45
+			after(info, err)
46
+			continue
47
+		}
48
+		data, err := info.Mapping.Codec.Encode(item)
49
+		if err != nil {
50
+			errs = append(errs, err)
51
+			after(info, err)
52
+			continue
53
+		}
54
+		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, data)
55
+		if err != nil {
56
+			errs = append(errs, err)
57
+			after(info, err)
58
+			continue
59
+		}
60
+		info.Refresh(obj, true)
61
+		list.Items[i] = obj
62
+		after(info, nil)
63
+	}
64
+	return errs
65
+}
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
12 12
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
13 13
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
14
-	"github.com/golang/glog"
15 14
 
16 15
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
17 16
 	validation "github.com/openshift/origin/pkg/deploy/api/validation"
... ...
@@ -83,8 +82,6 @@ func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
83 83
 		return nil, kerrors.NewConflict("deploymentConfig", deploymentConfig.Namespace, fmt.Errorf("DeploymentConfig.Namespace does not match the provided context"))
84 84
 	}
85 85
 
86
-	glog.Infof("Creating deploymentConfig with namespace::Name: %v::%v", deploymentConfig.Namespace, deploymentConfig.Name)
87
-
88 86
 	if errs := validation.ValidateDeploymentConfig(deploymentConfig); len(errs) > 0 {
89 87
 		return nil, kerrors.NewInvalid("deploymentConfig", deploymentConfig.Name, errs)
90 88
 	}
... ...
@@ -414,3 +414,67 @@ func generateSecret(n int) string {
414 414
 	}
415 415
 	return base64.URLEncoding.EncodeToString(b)
416 416
 }
417
+
418
+// ContainerPortsFromString extracts sets of port specifications from a comma-delimited string. Each segment
419
+// must be a single port number (container port) or a colon delimited pair of ports (container port and host port).
420
+func ContainerPortsFromString(portString string) ([]kapi.Port, error) {
421
+	ports := []kapi.Port{}
422
+	for _, s := range strings.Split(portString, ",") {
423
+		port, ok := checkPortSpecSegment(s)
424
+		if !ok {
425
+			return nil, fmt.Errorf("%q is not valid: you must specify one (container) or two (container:host) port numbers", s)
426
+		}
427
+		ports = append(ports, port)
428
+	}
429
+	return ports, nil
430
+}
431
+
432
+func checkPortSpecSegment(s string) (port kapi.Port, ok bool) {
433
+	if strings.Contains(s, ":") {
434
+		pair := strings.Split(s, ":")
435
+		if len(pair) != 2 {
436
+			return
437
+		}
438
+		container, err := strconv.Atoi(pair[0])
439
+		if err != nil {
440
+			return
441
+		}
442
+		host, err := strconv.Atoi(pair[1])
443
+		if err != nil {
444
+			return
445
+		}
446
+		return kapi.Port{ContainerPort: container, HostPort: host}, true
447
+	}
448
+
449
+	container, err := strconv.Atoi(s)
450
+	if err != nil {
451
+		return
452
+	}
453
+	return kapi.Port{ContainerPort: container}, true
454
+}
455
+
456
+// LabelsFromSpec turns a set of specs NAME=VALUE or NAME- into a map of labels,
457
+// a remove label list, or an error.
458
+func LabelsFromSpec(spec []string) (map[string]string, []string, error) {
459
+	labels := map[string]string{}
460
+	var remove []string
461
+	for _, labelSpec := range spec {
462
+		if strings.Index(labelSpec, "=") != -1 {
463
+			parts := strings.Split(labelSpec, "=")
464
+			if len(parts) != 2 {
465
+				return nil, nil, fmt.Errorf("invalid label spec: %v", labelSpec)
466
+			}
467
+			labels[parts[0]] = parts[1]
468
+		} else if strings.HasSuffix(labelSpec, "-") {
469
+			remove = append(remove, labelSpec[:len(labelSpec)-1])
470
+		} else {
471
+			return nil, nil, fmt.Errorf("unknown label spec: %v")
472
+		}
473
+	}
474
+	for _, removeLabel := range remove {
475
+		if _, found := labels[removeLabel]; found {
476
+			return nil, nil, fmt.Errorf("can not both modify and remove a label in the same command")
477
+		}
478
+	}
479
+	return labels, remove, nil
480
+}
... ...
@@ -184,6 +184,7 @@ func AddServices(objects Objects) Objects {
184 184
 						ObjectMeta: kapi.ObjectMeta{
185 185
 							Name:         name,
186 186
 							GenerateName: generateName,
187
+							Labels:       t.Labels,
187 188
 						},
188 189
 						Spec: kapi.ServiceSpec{
189 190
 							ContainerPort: kutil.NewIntOrStringFromInt(p),