diff --git a/pkg/kubectl/cmd/expose.go b/pkg/kubectl/cmd/expose.go index fe9ead8550f..50e9e544112 100644 --- a/pkg/kubectl/cmd/expose.go +++ b/pkg/kubectl/cmd/expose.go @@ -98,6 +98,9 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str if err != nil { return err } + if len(infos) > 1 { + return fmt.Errorf("multiple resources provided: %v", args) + } info := infos[0] // Get the input object @@ -118,10 +121,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str } names := generator.ParamNames() params := kubectl.MakeParams(cmd, names) - params["name"] = cmdutil.GetFlagString(cmd, "name") - if len(params["name"]) == 0 { - params["name"] = info.Name - } + params["default-name"] = info.Name if s, found := params["selector"]; !found || len(s) == 0 || cmdutil.GetFlagInt(cmd, "port") < 1 { if len(s) == 0 { s, err := f.PodSelectorForObject(inputObject) diff --git a/pkg/kubectl/cmd/expose_test.go b/pkg/kubectl/cmd/expose_test.go index 94669880769..f1189fc6127 100644 --- a/pkg/kubectl/cmd/expose_test.go +++ b/pkg/kubectl/cmd/expose_test.go @@ -29,16 +29,24 @@ import ( func TestRunExposeService(t *testing.T) { tests := []struct { - name string - args []string - input runtime.Object - flags map[string]string - output runtime.Object - status int + name string + args []string + ns string + calls map[string]string + input runtime.Object + flags map[string]string + output runtime.Object + expected string + status int }{ { name: "expose-service-from-service", args: []string{"service", "baz"}, + ns: "test", + calls: map[string]string{ + "GET": "/namespaces/test/services/baz", + "POST": "/namespaces/test/services", + }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1beta3"}, @@ -61,7 +69,42 @@ func TestRunExposeService(t *testing.T) { Selector: map[string]string{"func": "stream"}, }, }, - status: 200, + expected: "services/foo", + status: 200, + }, + { + name: "no-name-passed-from-the-cli", + args: []string{"service", "mayor"}, + ns: "default", + calls: map[string]string{ + "GET": "/namespaces/default/services/mayor", + "POST": "/namespaces/default/services", + }, + input: &api.Service{ + ObjectMeta: api.ObjectMeta{Name: "mayor", Namespace: "default", ResourceVersion: "12"}, + TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1beta3"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"run": "this"}, + }, + }, + // No --name flag specified below. Service will use the rc's name passed via the 'default-name' parameter + flags: map[string]string{"selector": "run=this", "port": "80", "labels": "runas=amayor"}, + output: &api.Service{ + ObjectMeta: api.ObjectMeta{Name: "mayor", Namespace: "default", ResourceVersion: "12", Labels: map[string]string{"runas": "amayor"}}, + TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1beta3"}, + Spec: api.ServiceSpec{ + Ports: []api.ServicePort{ + { + Name: "default", + Protocol: api.Protocol("TCP"), + Port: 80, + }, + }, + Selector: map[string]string{"run": "this"}, + }, + }, + expected: "services/mayor", + status: 200, }, } @@ -72,9 +115,9 @@ func TestRunExposeService(t *testing.T) { Codec: codec, Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { - case p == "/namespaces/test/services/baz" && m == "GET": + case p == test.calls[m] && m == "GET": return &http.Response{StatusCode: test.status, Body: objBody(codec, test.input)}, nil - case p == "/namespaces/test/services" && m == "POST": + case p == test.calls[m] && m == "POST": return &http.Response{StatusCode: test.status, Body: objBody(codec, test.output)}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) @@ -82,7 +125,7 @@ func TestRunExposeService(t *testing.T) { } }), } - tf.Namespace = "test" + tf.Namespace = test.ns buf := bytes.NewBuffer([]byte{}) cmd := NewCmdExposeService(f, buf) @@ -93,7 +136,7 @@ func TestRunExposeService(t *testing.T) { cmd.Run(cmd, test.args) out := buf.String() - if strings.Contains(out, "services/foo") { + if strings.Contains(out, test.expected) { t.Errorf("%s: unexpected output: %s", test.name, out) } } diff --git a/pkg/kubectl/run.go b/pkg/kubectl/run.go index 3d4906e82fd..e02058221bf 100644 --- a/pkg/kubectl/run.go +++ b/pkg/kubectl/run.go @@ -29,7 +29,8 @@ type BasicReplicationController struct{} func (BasicReplicationController) ParamNames() []GeneratorParam { return []GeneratorParam{ {"labels", false}, - {"name", true}, + {"default-name", true}, + {"name", false}, {"replicas", true}, {"image", true}, {"port", false}, @@ -38,6 +39,13 @@ func (BasicReplicationController) ParamNames() []GeneratorParam { } func (BasicReplicationController) Generate(params map[string]string) (runtime.Object, error) { + name, found := params["name"] + if !found || len(name) == 0 { + name, found = params["default-name"] + if !found || len(name) == 0 { + return nil, fmt.Errorf("'name' is a required parameter.") + } + } // TODO: extract this flag to a central location. labelString, found := params["labels"] var labels map[string]string @@ -49,7 +57,7 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob } } else { labels = map[string]string{ - "run": params["name"], + "run": name, } } count, err := strconv.Atoi(params["replicas"]) @@ -58,7 +66,7 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob } controller := api.ReplicationController{ ObjectMeta: api.ObjectMeta{ - Name: params["name"], + Name: name, Labels: labels, }, Spec: api.ReplicationControllerSpec{ @@ -71,7 +79,7 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob Spec: api.PodSpec{ Containers: []api.Container{ { - Name: params["name"], + Name: name, Image: params["image"], }, }, diff --git a/pkg/kubectl/service.go b/pkg/kubectl/service.go index 8c631b2751a..5f41a0da013 100644 --- a/pkg/kubectl/service.go +++ b/pkg/kubectl/service.go @@ -29,7 +29,8 @@ type ServiceGenerator struct{} func (ServiceGenerator) ParamNames() []GeneratorParam { return []GeneratorParam{ - {"name", true}, + {"default-name", true}, + {"name", false}, {"selector", true}, {"port", true}, {"labels", false}, @@ -62,8 +63,11 @@ func (ServiceGenerator) Generate(params map[string]string) (runtime.Object, erro } name, found := params["name"] - if !found { - return nil, fmt.Errorf("'name' is a required parameter.") + if !found || len(name) == 0 { + name, found = params["default-name"] + if !found || len(name) == 0 { + return nil, fmt.Errorf("'name' is a required parameter.") + } } portString, found := params["port"] if !found {