diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 6799502026c..39150c7fca8 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -697,6 +697,7 @@ _kubectl_expose() flags+=("--protocol=") flags+=("--public-ip=") flags+=("--selector=") + flags+=("--session-affinity=") flags+=("--target-port=") flags+=("--template=") two_word_flags+=("-t") diff --git a/docs/man/man1/kubectl-expose.1 b/docs/man/man1/kubectl-expose.1 index 6b288d38fa7..8e51c69976e 100644 --- a/docs/man/man1/kubectl-expose.1 +++ b/docs/man/man1/kubectl-expose.1 @@ -82,6 +82,10 @@ re\-use the labels from the resource it exposes. \fB\-\-selector\fP="" A label selector to use for this service. If empty (the default) infer the selector from the replication controller. +.PP +\fB\-\-session\-affinity\fP="" + If non\-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP' + .PP \fB\-\-target\-port\fP="" Name or number for the port on the container that the service should direct traffic to. Optional. diff --git a/docs/user-guide/kubectl/kubectl_expose.md b/docs/user-guide/kubectl/kubectl_expose.md index 12377b80fd6..db98f2ea0b0 100644 --- a/docs/user-guide/kubectl/kubectl_expose.md +++ b/docs/user-guide/kubectl/kubectl_expose.md @@ -79,6 +79,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream --protocol="TCP": The network protocol for the service to be created. Default is 'tcp'. --public-ip="": Name of a public IP address to set for the service. The service will be assigned this IP in addition to its generated service IP. --selector="": A label selector to use for this service. If empty (the default) infer the selector from the replication controller. + --session-affinity="": If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP' --target-port="": Name or number for the port on the container that the service should direct traffic to. Optional. -t, --template="": Template string or path to template file to use when -o=template or -o=templatefile. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview] --type="": Type for this service: ClusterIP, NodePort, or LoadBalancer. Default is 'ClusterIP' unless --create-external-load-balancer is specified. @@ -117,7 +118,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra at 2015-07-17 01:17:57.020108348 +0000 UTC +###### Auto generated by spf13/cobra at 2015-07-31 17:33:19.568673976 +0000 UTC diff --git a/pkg/kubectl/cmd/expose.go b/pkg/kubectl/cmd/expose.go index 4ae3ba35bdb..f0189d7ef07 100644 --- a/pkg/kubectl/cmd/expose.go +++ b/pkg/kubectl/cmd/expose.go @@ -70,6 +70,7 @@ func NewCmdExposeService(f *cmdutil.Factory, out io.Writer) *cobra.Command { cmd.Flags().String("public-ip", "", "Name of a public IP address to set for the service. The service will be assigned this IP in addition to its generated service IP.") cmd.Flags().String("overrides", "", "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.") cmd.Flags().String("name", "", "The name for the newly created object.") + cmd.Flags().String("session-affinity", "", "If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP'") return cmd } diff --git a/pkg/kubectl/cmd/expose_test.go b/pkg/kubectl/cmd/expose_test.go index c276a9dfb6a..903c8de0b11 100644 --- a/pkg/kubectl/cmd/expose_test.go +++ b/pkg/kubectl/cmd/expose_test.go @@ -139,6 +139,41 @@ func TestRunExposeService(t *testing.T) { }, status: 200, }, + { + name: "expose-external-affinity-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: "v1"}, + Spec: api.ServiceSpec{ + Selector: map[string]string{"app": "go"}, + }, + }, + flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "create-external-load-balancer": "true", "session-affinity": "ClientIP"}, + output: &api.Service{ + ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "12", Labels: map[string]string{"svc": "test"}}, + TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, + Spec: api.ServiceSpec{ + Ports: []api.ServicePort{ + { + Name: "default", + Protocol: api.Protocol("UDP"), + Port: 14, + TargetPort: util.NewIntOrStringFromInt(14), + }, + }, + Selector: map[string]string{"func": "stream"}, + Type: api.ServiceTypeLoadBalancer, + SessionAffinity: api.ServiceAffinityClientIP, + }, + }, + status: 200, + }, } for _, test := range tests { diff --git a/pkg/kubectl/service.go b/pkg/kubectl/service.go index ab8e1893aef..cd08d7379b7 100644 --- a/pkg/kubectl/service.go +++ b/pkg/kubectl/service.go @@ -61,6 +61,7 @@ func paramNames() []GeneratorParam { {"container-port", false}, // alias of target-port {"target-port", false}, {"port-name", false}, + {"session-affinity", false}, } } @@ -141,5 +142,15 @@ func generate(params map[string]string) (runtime.Object, error) { if len(params["type"]) != 0 { service.Spec.Type = api.ServiceType(params["type"]) } + if len(params["session-affinity"]) != 0 { + switch api.ServiceAffinity(params["session-affinity"]) { + case api.ServiceAffinityNone: + service.Spec.SessionAffinity = api.ServiceAffinityNone + case api.ServiceAffinityClientIP: + service.Spec.SessionAffinity = api.ServiceAffinityClientIP + default: + return nil, fmt.Errorf("unknown session affinity: %s", params["session-affinity"]) + } + } return &service, nil } diff --git a/pkg/kubectl/service_test.go b/pkg/kubectl/service_test.go index 6987843b73f..a00d7b23c9e 100644 --- a/pkg/kubectl/service_test.go +++ b/pkg/kubectl/service_test.go @@ -272,6 +272,37 @@ func TestGenerateService(t *testing.T) { }, }, }, + { + generator: ServiceGeneratorV1{}, + params: map[string]string{ + "selector": "foo=bar,baz=blah", + "name": "test", + "port": "80", + "protocol": "TCP", + "container-port": "1234", + "session-affinity": "ClientIP", + }, + expected: api.Service{ + ObjectMeta: api.ObjectMeta{ + Name: "test", + }, + Spec: api.ServiceSpec{ + Selector: map[string]string{ + "foo": "bar", + "baz": "blah", + }, + Ports: []api.ServicePort{ + { + Name: "default", + Port: 80, + Protocol: "TCP", + TargetPort: util.NewIntOrStringFromInt(1234), + }, + }, + SessionAffinity: api.ServiceAffinityClientIP, + }, + }, + }, } for _, test := range tests { obj, err := test.generator.Generate(test.params)