Merge pull request #12292 from brendandburns/stdin3

Add support for `--restart`
pull/6/head
Marek Grabowski 2015-08-10 14:54:54 +02:00
commit e27787c9d3
15 changed files with 461 additions and 42 deletions

View File

@ -639,6 +639,7 @@ _kubectl_run()
flags+=("--port=") flags+=("--port=")
flags+=("--replicas=") flags+=("--replicas=")
two_word_flags+=("-r") two_word_flags+=("-r")
flags+=("--restart=")
flags+=("--stdin") flags+=("--stdin")
flags+=("-i") flags+=("-i")
flags+=("--template=") flags+=("--template=")

View File

@ -27,8 +27,8 @@ Creates a replication controller to manage the created container(s).
If true, only print the object that would be sent, without sending it. If true, only print the object that would be sent, without sending it.
.PP .PP
\fB\-\-generator\fP="run/v1" \fB\-\-generator\fP=""
The name of the API generator to use. Default is 'run\-controller/v1'. The name of the API generator to use. Default is 'run/v1' if \-\-restart=Always, otherwise the default is 'run\-pod/v1'.
.PP .PP
\fB\-h\fP, \fB\-\-help\fP=false \fB\-h\fP, \fB\-\-help\fP=false
@ -70,6 +70,10 @@ Creates a replication controller to manage the created container(s).
\fB\-r\fP, \fB\-\-replicas\fP=1 \fB\-r\fP, \fB\-\-replicas\fP=1
Number of replicas to create for this container. Default is 1. Number of replicas to create for this container. Default is 1.
.PP
\fB\-\-restart\fP="Always"
The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a replication controller is created for this pod, if set to OnFailure or Never, only the Pod is created and \-\-replicas must be 1. Default 'Always'
.PP .PP
\fB\-i\fP, \fB\-\-stdin\fP=false \fB\-i\fP, \fB\-\-stdin\fP=false
Keep stdin open on the container(s) in the pod, even if nothing is attached. Keep stdin open on the container(s) in the pod, even if nothing is attached.

View File

@ -121,7 +121,7 @@ $ kubectl annotate pods foo description-
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.183633333 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:02.005112262 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_annotate.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_annotate.md?pixel)]()

View File

@ -103,7 +103,7 @@ $ kubectl config view -o template --template='{{range .users}}{{ if eq .name "e2
* [kubectl config](kubectl_config.md) - config modifies kubeconfig files * [kubectl config](kubectl_config.md) - config modifies kubeconfig files
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.184001914 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:02.005424182 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_config_view.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_config_view.md?pixel)]()

View File

@ -118,7 +118,7 @@ $ kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.182748201 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:02.004335817 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_expose.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_expose.md?pixel)]()

View File

@ -125,7 +125,7 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.175798628 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:01.995301464 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_get.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_get.md?pixel)]()

View File

@ -115,7 +115,7 @@ $ kubectl label pods foo bar-
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.183216488 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:02.004743482 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_label.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_label.md?pixel)]()

View File

@ -117,7 +117,7 @@ $ kubectl rolling-update frontend --image=image:v2
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.179537741 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:01.999165947 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_rolling-update.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_rolling-update.md?pixel)]()

View File

@ -66,7 +66,7 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
``` ```
--attach[=false]: If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true. --attach[=false]: If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.
--dry-run[=false]: If true, only print the object that would be sent, without sending it. --dry-run[=false]: If true, only print the object that would be sent, without sending it.
--generator="run/v1": The name of the API generator to use. Default is 'run-controller/v1'. --generator="": The name of the API generator to use. Default is 'run/v1' if --restart=Always, otherwise the default is 'run-pod/v1'.
-h, --help[=false]: help for run -h, --help[=false]: help for run
--hostport=-1: The host port mapping for the container port. To demonstrate a single-machine container. --hostport=-1: The host port mapping for the container port. To demonstrate a single-machine container.
--image="": The image for the container to run. --image="": The image for the container to run.
@ -77,6 +77,7 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
--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. --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.
--port=-1: The port that this container exposes. --port=-1: The port that this container exposes.
-r, --replicas=1: Number of replicas to create for this container. Default is 1. -r, --replicas=1: Number of replicas to create for this container. Default is 1.
--restart="Always": The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a replication controller is created for this pod, if set to OnFailure or Never, only the Pod is created and --replicas must be 1. Default 'Always'
-i, --stdin[=false]: Keep stdin open on the container(s) in the pod, even if nothing is attached. -i, --stdin[=false]: Keep stdin open on the container(s) in the pod, even if nothing is attached.
-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] -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]
--tty[=false]: Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon. --tty[=false]: Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon.
@ -115,7 +116,7 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
* [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager
###### Auto generated by spf13/cobra at 2015-08-07 03:15:49.181215106 +0000 UTC ###### Auto generated by spf13/cobra at 2015-08-07 19:25:02.003600767 +0000 UTC
<!-- BEGIN MUNGE: GENERATED_ANALYTICS --> <!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_run.md?pixel)]() [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_run.md?pixel)]()

View File

@ -61,7 +61,7 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
}, },
} }
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
cmd.Flags().String("generator", "run/v1", "The name of the API generator to use. Default is 'run-controller/v1'.") cmd.Flags().String("generator", "", "The name of the API generator to use. Default is 'run/v1' if --restart=Always, otherwise the default is 'run-pod/v1'.")
cmd.Flags().String("image", "", "The image for the container to run.") cmd.Flags().String("image", "", "The image for the container to run.")
cmd.MarkFlagRequired("image") cmd.MarkFlagRequired("image")
cmd.Flags().IntP("replicas", "r", 1, "Number of replicas to create for this container. Default is 1.") cmd.Flags().IntP("replicas", "r", 1, "Number of replicas to create for this container. Default is 1.")
@ -73,6 +73,7 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
cmd.Flags().BoolP("stdin", "i", false, "Keep stdin open on the container(s) in the pod, even if nothing is attached.") cmd.Flags().BoolP("stdin", "i", false, "Keep stdin open on the container(s) in the pod, even if nothing is attached.")
cmd.Flags().Bool("tty", false, "Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon.") cmd.Flags().Bool("tty", false, "Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon.")
cmd.Flags().Bool("attach", false, "If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.") cmd.Flags().Bool("attach", false, "If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.")
cmd.Flags().String("restart", "Always", "The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a replication controller is created for this pod, if set to OnFailure or Never, only the Pod is created and --replicas must be 1. Default 'Always'")
return cmd return cmd
} }
@ -105,10 +106,24 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
return err return err
} }
restartPolicy, err := getRestartPolicy(cmd, interactive)
if err != nil {
return err
}
if restartPolicy != api.RestartPolicyAlways && replicas != 1 {
return cmdutil.UsageError(cmd, fmt.Sprintf("--restart=%s requires that --repliacs=1, found %d", restartPolicy, replicas))
}
generatorName := cmdutil.GetFlagString(cmd, "generator") generatorName := cmdutil.GetFlagString(cmd, "generator")
if len(generatorName) == 0 {
if restartPolicy == api.RestartPolicyAlways {
generatorName = "run/v1"
} else {
generatorName = "run-pod/v1"
}
}
generator, found := f.Generator(generatorName) generator, found := f.Generator(generatorName)
if !found { if !found {
return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not found.", generator)) return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not found.", generatorName))
} }
names := generator.ParamNames() names := generator.ParamNames()
params := kubectl.MakeParams(cmd, names) params := kubectl.MakeParams(cmd, names)
@ -119,14 +134,20 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
return err return err
} }
controller, err := generator.Generate(params) obj, err := generator.Generate(params)
if err != nil { if err != nil {
return err return err
} }
inline := cmdutil.GetFlagString(cmd, "overrides") inline := cmdutil.GetFlagString(cmd, "overrides")
if len(inline) > 0 { if len(inline) > 0 {
controller, err = cmdutil.Merge(controller, inline, "ReplicationController") var objType string
if restartPolicy == api.RestartPolicyAlways {
objType = "ReplicationController"
} else {
objType = "Pod"
}
obj, err = cmdutil.Merge(obj, inline, objType)
if err != nil { if err != nil {
return err return err
} }
@ -134,7 +155,11 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
// TODO: extract this flag to a central location, when such a location exists. // TODO: extract this flag to a central location, when such a location exists.
if !cmdutil.GetFlagBool(cmd, "dry-run") { if !cmdutil.GetFlagBool(cmd, "dry-run") {
controller, err = client.ReplicationControllers(namespace).Create(controller.(*api.ReplicationController)) if restartPolicy == api.RestartPolicyAlways {
obj, err = client.ReplicationControllers(namespace).Create(obj.(*api.ReplicationController))
} else {
obj, err = client.Pods(namespace).Create(obj.(*api.Pod))
}
if err != nil { if err != nil {
return err return err
} }
@ -168,9 +193,13 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
return err return err
} }
opts.Client = client opts.Client = client
return handleAttach(client, controller.(*api.ReplicationController), opts) if restartPolicy == api.RestartPolicyAlways {
return handleAttachReplicationController(client, obj.(*api.ReplicationController), opts)
} else {
return handleAttachPod(client, obj.(*api.Pod), opts)
}
} }
return f.PrintObject(cmd, controller, cmdOut) return f.PrintObject(cmd, obj, cmdOut)
} }
func waitForPodRunning(c *client.Client, pod *api.Pod, out io.Writer) error { func waitForPodRunning(c *client.Client, pod *api.Pod, out io.Writer) error {
@ -197,7 +226,7 @@ func waitForPodRunning(c *client.Client, pod *api.Pod, out io.Writer) error {
} }
} }
func handleAttach(c *client.Client, controller *api.ReplicationController, opts *AttachOptions) error { func handleAttachReplicationController(c *client.Client, controller *api.ReplicationController, opts *AttachOptions) error {
var pods *api.PodList var pods *api.PodList
for pods == nil || len(pods.Items) == 0 { for pods == nil || len(pods.Items) == 0 {
var err error var err error
@ -210,7 +239,10 @@ func handleAttach(c *client.Client, controller *api.ReplicationController, opts
} }
} }
pod := &pods.Items[0] pod := &pods.Items[0]
return handleAttachPod(c, pod, opts)
}
func handleAttachPod(c *client.Client, pod *api.Pod, opts *AttachOptions) error {
if err := waitForPodRunning(c, pod, opts.Out); err != nil { if err := waitForPodRunning(c, pod, opts.Out); err != nil {
return err return err
} }
@ -219,3 +251,24 @@ func handleAttach(c *client.Client, controller *api.ReplicationController, opts
opts.Namespace = pod.Namespace opts.Namespace = pod.Namespace
return opts.Run() return opts.Run()
} }
func getRestartPolicy(cmd *cobra.Command, interactive bool) (api.RestartPolicy, error) {
restart := cmdutil.GetFlagString(cmd, "restart")
if len(restart) == 0 {
if interactive {
return api.RestartPolicyOnFailure, nil
} else {
return api.RestartPolicyAlways, nil
}
}
switch api.RestartPolicy(restart) {
case api.RestartPolicyAlways:
return api.RestartPolicyAlways, nil
case api.RestartPolicyOnFailure:
return api.RestartPolicyOnFailure, nil
case api.RestartPolicyNever:
return api.RestartPolicyNever, nil
default:
return "", cmdutil.UsageError(cmd, fmt.Sprintf("invalid restart policy: %s", restart))
}
}

View File

@ -0,0 +1,80 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"testing"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api"
)
func TestGetRestartPolicy(t *testing.T) {
tests := []struct {
input string
interactive bool
expected api.RestartPolicy
expectErr bool
}{
{
input: "",
expected: api.RestartPolicyAlways,
},
{
input: "",
interactive: true,
expected: api.RestartPolicyOnFailure,
},
{
input: string(api.RestartPolicyAlways),
interactive: true,
expected: api.RestartPolicyAlways,
},
{
input: string(api.RestartPolicyNever),
interactive: true,
expected: api.RestartPolicyNever,
},
{
input: string(api.RestartPolicyAlways),
expected: api.RestartPolicyAlways,
},
{
input: string(api.RestartPolicyNever),
expected: api.RestartPolicyNever,
},
{
input: "foo",
expectErr: true,
},
}
for _, test := range tests {
cmd := &cobra.Command{}
cmd.Flags().String("restart", "", "dummy restart flag")
cmd.Flags().Lookup("restart").Value.Set(test.input)
policy, err := getRestartPolicy(cmd, test.interactive)
if test.expectErr && err == nil {
t.Error("unexpected non-error")
}
if !test.expectErr && err != nil {
t.Errorf("unexpected error: %v", err)
}
if !test.expectErr && policy != test.expected {
t.Errorf("expected: %s, saw: %s (%s:%v)", test.expected, policy, test.input, test.interactive)
}
}
}

View File

@ -97,6 +97,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
generators := map[string]kubectl.Generator{ generators := map[string]kubectl.Generator{
"run/v1": kubectl.BasicReplicationController{}, "run/v1": kubectl.BasicReplicationController{},
"run-pod/v1": kubectl.BasicPod{},
"service/v1": kubectl.ServiceGeneratorV1{}, "service/v1": kubectl.ServiceGeneratorV1{},
"service/v2": kubectl.ServiceGeneratorV2{}, "service/v2": kubectl.ServiceGeneratorV2{},
} }

View File

@ -40,6 +40,30 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
} }
} }
func makePodSpec(params map[string]string, name string) (*api.PodSpec, error) {
stdin, err := GetBool(params, "stdin", false)
if err != nil {
return nil, err
}
tty, err := GetBool(params, "tty", false)
if err != nil {
return nil, err
}
spec := api.PodSpec{
Containers: []api.Container{
{
Name: name,
Image: params["image"],
Stdin: stdin,
TTY: tty,
},
},
}
return &spec, nil
}
func (BasicReplicationController) Generate(params map[string]string) (runtime.Object, error) { func (BasicReplicationController) Generate(params map[string]string) (runtime.Object, error) {
name, found := params["name"] name, found := params["name"]
if !found || len(name) == 0 { if !found || len(name) == 0 {
@ -66,16 +90,11 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob
if err != nil { if err != nil {
return nil, err return nil, err
} }
stdin, err := GetBool(params, "stdin", false)
podSpec, err := makePodSpec(params, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tty, err := GetBool(params, "tty", false)
if err != nil {
return nil, err
}
controller := api.ReplicationController{ controller := api.ReplicationController{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: name, Name: name,
@ -88,49 +107,119 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Labels: labels, Labels: labels,
}, },
Spec: api.PodSpec{ Spec: *podSpec,
Containers: []api.Container{
{
Name: name,
Image: params["image"],
Stdin: stdin,
TTY: tty,
},
},
},
}, },
}, },
} }
if err := updatePodPorts(params, &controller.Spec.Template.Spec); err != nil {
return nil, err
}
return &controller, nil
}
func updatePodPorts(params map[string]string, podSpec *api.PodSpec) (err error) {
port := -1 port := -1
hostPort := -1 hostPort := -1
if len(params["port"]) > 0 { if len(params["port"]) > 0 {
port, err = strconv.Atoi(params["port"]) port, err = strconv.Atoi(params["port"])
if err != nil { if err != nil {
return nil, err return err
} }
} }
if len(params["hostport"]) > 0 { if len(params["hostport"]) > 0 {
hostPort, err = strconv.Atoi(params["hostport"]) hostPort, err = strconv.Atoi(params["hostport"])
if err != nil { if err != nil {
return nil, err return err
} }
if hostPort > 0 && port < 0 { if hostPort > 0 && port < 0 {
return nil, fmt.Errorf("--hostport requires --port to be specified") return fmt.Errorf("--hostport requires --port to be specified")
} }
} }
// Don't include the port if it was not specified. // Don't include the port if it was not specified.
if port > 0 { if port > 0 {
controller.Spec.Template.Spec.Containers[0].Ports = []api.ContainerPort{ podSpec.Containers[0].Ports = []api.ContainerPort{
{ {
ContainerPort: port, ContainerPort: port,
}, },
} }
if hostPort > 0 { if hostPort > 0 {
controller.Spec.Template.Spec.Containers[0].Ports[0].HostPort = hostPort podSpec.Containers[0].Ports[0].HostPort = hostPort
} }
} }
return &controller, nil return nil
}
type BasicPod struct{}
func (BasicPod) ParamNames() []GeneratorParam {
return []GeneratorParam{
{"labels", false},
{"default-name", false},
{"name", true},
{"image", true},
{"port", false},
{"hostport", false},
{"stdin", false},
{"tty", false},
{"restart", false},
}
}
func (BasicPod) 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
var err error
if found && len(labelString) > 0 {
labels, err = ParseLabels(labelString)
if err != nil {
return nil, err
}
}
stdin, err := GetBool(params, "stdin", false)
if err != nil {
return nil, err
}
tty, err := GetBool(params, "tty", false)
if err != nil {
return nil, err
}
restartPolicy := api.RestartPolicy(params["restart"])
if len(restartPolicy) == 0 {
restartPolicy = api.RestartPolicyAlways
}
pod := api.Pod{
ObjectMeta: api.ObjectMeta{
Name: name,
Labels: labels,
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: name,
Image: params["image"],
ImagePullPolicy: api.PullIfNotPresent,
Stdin: stdin,
TTY: tty,
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: restartPolicy,
},
}
if err := updatePodPorts(params, &pod.Spec); err != nil {
return nil, err
}
return &pod, nil
} }

View File

@ -190,3 +190,140 @@ func TestGenerate(t *testing.T) {
} }
} }
} }
func TestGeneratePod(t *testing.T) {
tests := []struct {
params map[string]string
expected *api.Pod
expectErr bool
}{
{
params: map[string]string{
"name": "foo",
"image": "someimage",
"port": "-1",
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
},
},
{
params: map[string]string{
"name": "foo",
"image": "someimage",
"port": "80",
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
Ports: []api.ContainerPort{
{
ContainerPort: 80,
},
},
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
},
},
{
params: map[string]string{
"name": "foo",
"image": "someimage",
"port": "80",
"hostport": "80",
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
Ports: []api.ContainerPort{
{
ContainerPort: 80,
HostPort: 80,
},
},
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
},
},
{
params: map[string]string{
"name": "foo",
"image": "someimage",
"hostport": "80",
},
expected: nil,
expectErr: true,
},
{
params: map[string]string{
"name": "foo",
"image": "someimage",
"replicas": "1",
"labels": "foo=bar,baz=blah",
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"},
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
},
},
}
generator := BasicPod{}
for _, test := range tests {
obj, err := generator.Generate(test.params)
if !test.expectErr && err != nil {
t.Errorf("unexpected error: %v", err)
}
if test.expectErr && err != nil {
continue
}
if !reflect.DeepEqual(obj.(*api.Pod), test.expected) {
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*api.Pod))
}
}
}

View File

@ -485,7 +485,7 @@ var _ = Describe("Kubectl client", func() {
}) })
}) })
Describe("Kubectl run", func() { Describe("Kubectl run rc", func() {
var nsFlag string var nsFlag string
var rcName string var rcName string
@ -528,6 +528,59 @@ var _ = Describe("Kubectl client", func() {
}) })
Describe("Kubectl run pod", func() {
var nsFlag string
var podName string
BeforeEach(func() {
nsFlag = fmt.Sprintf("--namespace=%v", ns)
podName = "e2e-test-nginx-pod"
})
AfterEach(func() {
runKubectl("stop", "pods", podName, nsFlag)
})
It("should create a pod from an image when restart is OnFailure", func() {
image := "nginx"
By("running the image " + image)
runKubectl("run", podName, "--restart=OnFailure", "--image="+image, nsFlag)
By("verifying the pod " + podName + " was created")
pod, err := c.Pods(ns).Get(podName)
if err != nil {
Failf("Failed getting pod %s: %v", podName, err)
}
containers := pod.Spec.Containers
if containers == nil || len(containers) != 1 || containers[0].Image != image {
Failf("Failed creating pod %s for 1 pod with expected image %s", podName, image)
}
if pod.Spec.RestartPolicy != api.RestartPolicyOnFailure {
Failf("Failed creating a pod with correct restart policy for --restart=OnFailure")
}
})
It("should create a pod from an image when restart is Never", func() {
image := "nginx"
By("running the image " + image)
runKubectl("run", podName, "--restart=Never", "--image="+image, nsFlag)
By("verifying the pod " + podName + " was created")
pod, err := c.Pods(ns).Get(podName)
if err != nil {
Failf("Failed getting pod %s: %v", podName, err)
}
containers := pod.Spec.Containers
if containers == nil || len(containers) != 1 || containers[0].Image != image {
Failf("Failed creating pod %s for 1 pod with expected image %s", podName, image)
}
if pod.Spec.RestartPolicy != api.RestartPolicyNever {
Failf("Failed creating a pod with correct restart policy for --restart=OnFailure")
}
})
})
Describe("Proxy server", func() { Describe("Proxy server", func() {
// TODO: test proxy options (static, prefix, etc) // TODO: test proxy options (static, prefix, etc)
It("should support proxy with --port 0", func() { It("should support proxy with --port 0", func() {