mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Add --restart support to kubectl run
This commit is contained in:
		@@ -633,6 +633,7 @@ _kubectl_run()
 | 
			
		||||
    flags+=("--port=")
 | 
			
		||||
    flags+=("--replicas=")
 | 
			
		||||
    two_word_flags+=("-r")
 | 
			
		||||
    flags+=("--restart=")
 | 
			
		||||
    flags+=("--stdin")
 | 
			
		||||
    flags+=("-i")
 | 
			
		||||
    flags+=("--template=")
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 | 
			
		||||
.PP
 | 
			
		||||
\fB\-\-generator\fP="run/v1"
 | 
			
		||||
    The name of the API generator to use.  Default is 'run\-controller/v1'.
 | 
			
		||||
\fB\-\-generator\fP=""
 | 
			
		||||
    The name of the API generator to use.  Default is 'run/v1' if \-\-restart=Always, otherwise the default is 'run\-pod/v1'.
 | 
			
		||||
 | 
			
		||||
.PP
 | 
			
		||||
\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
 | 
			
		||||
    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
 | 
			
		||||
\fB\-i\fP, \fB\-\-stdin\fP=false
 | 
			
		||||
    Keep stdin open on the container(s) in the pod, even if nothing is attached.
 | 
			
		||||
 
 | 
			
		||||
@@ -121,7 +121,7 @@ $ kubectl annotate pods foo description-
 | 
			
		||||
 | 
			
		||||
* [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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
###### 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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -118,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-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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -125,7 +125,7 @@ $ kubectl get rc/web service/frontend pods/web-pod-13je7
 | 
			
		||||
 | 
			
		||||
* [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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ $ kubectl label pods foo bar-
 | 
			
		||||
 | 
			
		||||
* [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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -117,7 +117,7 @@ $ kubectl rolling-update frontend --image=image:v2
 | 
			
		||||
 | 
			
		||||
* [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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
      --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
 | 
			
		||||
      --hostport=-1: The host port mapping for the container port. To demonstrate a single-machine container.
 | 
			
		||||
      --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.
 | 
			
		||||
      --port=-1: The port that this container exposes.
 | 
			
		||||
  -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.
 | 
			
		||||
  -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.
 | 
			
		||||
@@ -115,7 +116,7 @@ $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { .
 | 
			
		||||
 | 
			
		||||
* [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 -->
 | 
			
		||||
[]()
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	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.MarkFlagRequired("image")
 | 
			
		||||
	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().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().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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -105,10 +106,24 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
 | 
			
		||||
		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")
 | 
			
		||||
	if len(generatorName) == 0 {
 | 
			
		||||
		if restartPolicy == api.RestartPolicyAlways {
 | 
			
		||||
			generatorName = "run/v1"
 | 
			
		||||
		} else {
 | 
			
		||||
			generatorName = "run-pod/v1"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	generator, found := f.Generator(generatorName)
 | 
			
		||||
	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()
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	controller, err := generator.Generate(params)
 | 
			
		||||
	obj, err := generator.Generate(params)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline := cmdutil.GetFlagString(cmd, "overrides")
 | 
			
		||||
	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 {
 | 
			
		||||
			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.
 | 
			
		||||
	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 {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -168,9 +193,13 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		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 {
 | 
			
		||||
@@ -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
 | 
			
		||||
	for pods == nil || len(pods.Items) == 0 {
 | 
			
		||||
		var err error
 | 
			
		||||
@@ -210,7 +239,10 @@ func handleAttach(c *client.Client, controller *api.ReplicationController, opts
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	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 {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -219,3 +251,24 @@ func handleAttach(c *client.Client, controller *api.ReplicationController, opts
 | 
			
		||||
	opts.Namespace = pod.Namespace
 | 
			
		||||
	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))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										80
									
								
								pkg/kubectl/cmd/run_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								pkg/kubectl/cmd/run_test.go
									
									
									
									
									
										Normal 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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -97,6 +97,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
 | 
			
		||||
 | 
			
		||||
	generators := map[string]kubectl.Generator{
 | 
			
		||||
		"run/v1":     kubectl.BasicReplicationController{},
 | 
			
		||||
		"run-pod/v1": kubectl.BasicPod{},
 | 
			
		||||
		"service/v1": kubectl.ServiceGeneratorV1{},
 | 
			
		||||
		"service/v2": kubectl.ServiceGeneratorV2{},
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
	name, found := params["name"]
 | 
			
		||||
	if !found || len(name) == 0 {
 | 
			
		||||
@@ -66,16 +90,11 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	stdin, err := GetBool(params, "stdin", false)
 | 
			
		||||
 | 
			
		||||
	podSpec, err := makePodSpec(params, name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tty, err := GetBool(params, "tty", false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	controller := api.ReplicationController{
 | 
			
		||||
		ObjectMeta: api.ObjectMeta{
 | 
			
		||||
			Name:   name,
 | 
			
		||||
@@ -88,49 +107,119 @@ func (BasicReplicationController) Generate(params map[string]string) (runtime.Ob
 | 
			
		||||
				ObjectMeta: api.ObjectMeta{
 | 
			
		||||
					Labels: labels,
 | 
			
		||||
				},
 | 
			
		||||
				Spec: api.PodSpec{
 | 
			
		||||
					Containers: []api.Container{
 | 
			
		||||
						{
 | 
			
		||||
							Name:  name,
 | 
			
		||||
							Image: params["image"],
 | 
			
		||||
							Stdin: stdin,
 | 
			
		||||
							TTY:   tty,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				Spec: *podSpec,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
	hostPort := -1
 | 
			
		||||
	if len(params["port"]) > 0 {
 | 
			
		||||
		port, err = strconv.Atoi(params["port"])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(params["hostport"]) > 0 {
 | 
			
		||||
		hostPort, err = strconv.Atoi(params["hostport"])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		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.
 | 
			
		||||
	if port > 0 {
 | 
			
		||||
		controller.Spec.Template.Spec.Containers[0].Ports = []api.ContainerPort{
 | 
			
		||||
		podSpec.Containers[0].Ports = []api.ContainerPort{
 | 
			
		||||
			{
 | 
			
		||||
				ContainerPort: port,
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
		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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -485,7 +485,7 @@ var _ = Describe("Kubectl client", func() {
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	Describe("Kubectl run", func() {
 | 
			
		||||
	Describe("Kubectl run rc", func() {
 | 
			
		||||
		var nsFlag 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() {
 | 
			
		||||
		// TODO: test proxy options (static, prefix, etc)
 | 
			
		||||
		It("should support proxy with --port 0", func() {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user