mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-21 09:34:40 +00:00
kubectl run to produce deployment and job
This commit is contained in:
parent
f3753c02ed
commit
c0c02c95c4
@ -14,7 +14,7 @@ kubectl run \- Run a particular image on the cluster.
|
|||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.PP
|
.PP
|
||||||
Create and run a particular image, possibly replicated.
|
Create and run a particular image, possibly replicated.
|
||||||
Creates a replication controller to manage the created container(s).
|
Creates a replication controller or job to manage the created container(s).
|
||||||
|
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
@ -40,7 +40,7 @@ Creates a replication controller to manage the created container(s).
|
|||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-generator\fP=""
|
\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'.
|
The name of the API generator to use. Default is 'run/v1' if \-\-restart=Always, otherwise the default is 'job/v1beta1'.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-hostport\fP=\-1
|
\fB\-\-hostport\fP=\-1
|
||||||
@ -94,7 +94,7 @@ Creates a replication controller to manage the created container(s).
|
|||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-restart\fP="Always"
|
\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'
|
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, a job is created for this pod and \-\-replicas must be 1. Default 'Always'
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
\fB\-\-save\-config\fP=false
|
\fB\-\-save\-config\fP=false
|
||||||
@ -247,15 +247,18 @@ $ kubectl run nginx \-\-image=nginx \-\-dry\-run
|
|||||||
# Start a single instance of nginx, but overload the spec of the replication controller with a partial set of values parsed from JSON.
|
# Start a single instance of nginx, but overload the spec of the replication controller with a partial set of values parsed from JSON.
|
||||||
$ kubectl run nginx \-\-image=nginx \-\-overrides='{ "apiVersion": "v1", "spec": { ... } }'
|
$ kubectl run nginx \-\-image=nginx \-\-overrides='{ "apiVersion": "v1", "spec": { ... } }'
|
||||||
|
|
||||||
# Start a single instance of nginx and keep it in the foreground, don't restart it if it exits.
|
# Start a single instance of busybox and keep it in the foreground, don't restart it if it exits.
|
||||||
$ kubectl run \-i \-\-tty nginx \-\-image=nginx \-\-restart=Never
|
$ kubectl run \-i \-\-tty busybox \-\-image=busybox \-\-restart=Never
|
||||||
|
|
||||||
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
|
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
|
||||||
$ kubectl run nginx \-\-image=nginx \-\- <arg1> <arg2> ... <argN>
|
$ kubectl run nginx \-\-image=nginx \-\- <arg1> <arg2> ... <argN>
|
||||||
|
|
||||||
# Start the nginx container using a different command and custom arguments
|
# Start the nginx container using a different command and custom arguments.
|
||||||
$ kubectl run nginx \-\-image=nginx \-\-command \-\- <cmd> <arg1> ... <argN>
|
$ kubectl run nginx \-\-image=nginx \-\-command \-\- <cmd> <arg1> ... <argN>
|
||||||
|
|
||||||
|
# Start the perl container to compute π to 2000 places and print it out.
|
||||||
|
$ kubectl run pi \-\-image=perl \-\-restart=OnFailure \-\- perl \-Mbignum=bpi \-wle 'print bpi(2000)'
|
||||||
|
|
||||||
.fi
|
.fi
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ Run a particular image on the cluster.
|
|||||||
|
|
||||||
|
|
||||||
Create and run a particular image, possibly replicated.
|
Create and run a particular image, possibly replicated.
|
||||||
Creates a replication controller to manage the created container(s).
|
Creates a replication controller or job to manage the created container(s).
|
||||||
|
|
||||||
```
|
```
|
||||||
kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]
|
kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]
|
||||||
@ -66,14 +66,17 @@ $ kubectl run nginx --image=nginx --dry-run
|
|||||||
# Start a single instance of nginx, but overload the spec of the replication controller with a partial set of values parsed from JSON.
|
# Start a single instance of nginx, but overload the spec of the replication controller with a partial set of values parsed from JSON.
|
||||||
$ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
|
$ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
|
||||||
|
|
||||||
# Start a single instance of nginx and keep it in the foreground, don't restart it if it exits.
|
# Start a single instance of busybox and keep it in the foreground, don't restart it if it exits.
|
||||||
$ kubectl run -i --tty nginx --image=nginx --restart=Never
|
$ kubectl run -i --tty busybox --image=busybox --restart=Never
|
||||||
|
|
||||||
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
|
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
|
||||||
$ kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
|
$ kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
|
||||||
|
|
||||||
# Start the nginx container using a different command and custom arguments
|
# Start the nginx container using a different command and custom arguments.
|
||||||
$ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
|
$ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
|
||||||
|
|
||||||
|
# Start the perl container to compute π to 2000 places and print it out.
|
||||||
|
$ kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(2000)'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
@ -84,7 +87,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
|
|||||||
--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.
|
||||||
--env=[]: Environment variables to set in the container
|
--env=[]: Environment variables to set in the container
|
||||||
--expose[=false]: If true, a public, external service is created for the container(s) which are run
|
--expose[=false]: If true, a public, external service is created for the container(s) which are run
|
||||||
--generator="": The name of the API generator to use. Default is 'run/v1' if --restart=Always, otherwise the default is 'run-pod/v1'.
|
--generator="": The name of the API generator to use. Default is 'run/v1' if --restart=Always, otherwise the default is 'job/v1beta1'.
|
||||||
--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.
|
||||||
-l, --labels="": Labels to apply to the pod(s).
|
-l, --labels="": Labels to apply to the pod(s).
|
||||||
@ -97,7 +100,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
|
|||||||
--port=-1: The port that this container exposes. If --expose is true, this is also the port used by the service that is created.
|
--port=-1: The port that this container exposes. If --expose is true, this is also the port used by the service that is created.
|
||||||
-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.
|
||||||
--requests="": The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'
|
--requests="": The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'
|
||||||
--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'
|
--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, a job is created for this pod and --replicas must be 1. Default 'Always'
|
||||||
--save-config[=false]: If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
|
--save-config[=false]: If true, the configuration of current object will be saved in its annotation. This is useful when you want to perform kubectl apply on this object in the future.
|
||||||
--service-generator="service/v2": The name of the generator to use for creating a service. Only used if --expose is true
|
--service-generator="service/v2": The name of the generator to use for creating a service. Only used if --expose is true
|
||||||
--service-overrides="": An inline JSON override for the generated service object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field. Only used if --expose is true.
|
--service-overrides="": An inline JSON override for the generated service object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field. Only used if --expose is true.
|
||||||
|
@ -611,7 +611,7 @@ runTests() {
|
|||||||
# Pre-Condition: no RC is running
|
# Pre-Condition: no RC is running
|
||||||
kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
|
kube::test::get_object_assert rc "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
# Command: create the rc "nginx" with image nginx
|
# Command: create the rc "nginx" with image nginx
|
||||||
kubectl run nginx --image=nginx --save-config "${kube_flags[@]}"
|
kubectl run nginx --image=nginx --save-config --generator=run/v1 "${kube_flags[@]}"
|
||||||
# Post-Condition: rc "nginx" has configuration annotation
|
# Post-Condition: rc "nginx" has configuration annotation
|
||||||
[[ "$(kubectl get rc nginx -o yaml "${kube_flags[@]}" | grep kubectl.kubernetes.io/last-applied-configuration)" ]]
|
[[ "$(kubectl get rc nginx -o yaml "${kube_flags[@]}" | grep kubectl.kubernetes.io/last-applied-configuration)" ]]
|
||||||
## 5. kubectl expose --save-config should generate configuration annotation
|
## 5. kubectl expose --save-config should generate configuration annotation
|
||||||
@ -647,6 +647,24 @@ runTests() {
|
|||||||
# Clean up
|
# Clean up
|
||||||
kubectl delete pods test-pod "${kube_flags[@]}"
|
kubectl delete pods test-pod "${kube_flags[@]}"
|
||||||
|
|
||||||
|
## kubectl run should create deployments or jobs
|
||||||
|
# Pre-Condition: no Job is running
|
||||||
|
kube::test::get_object_assert jobs "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
|
# Command
|
||||||
|
kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(20)'
|
||||||
|
# Post-Condition: Job "pi" is created
|
||||||
|
kube::test::get_object_assert jobs "{{range.items}}{{$id_field}}:{{end}}" 'pi:'
|
||||||
|
# Clean up
|
||||||
|
kubectl delete jobs pi
|
||||||
|
# Pre-Condition: no Deployment is running
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" ''
|
||||||
|
# Command
|
||||||
|
kubectl run nginx --image=nginx --generator=deployment/v1beta1
|
||||||
|
# Post-Condition: Deployment "nginx" is created
|
||||||
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx:'
|
||||||
|
# Clean up
|
||||||
|
kubectl delete deployment nginx
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# Namespaces #
|
# Namespaces #
|
||||||
##############
|
##############
|
||||||
|
@ -297,7 +297,10 @@ func ValidateDeploymentSpec(spec *extensions.DeploymentSpec) validation.ErrorLis
|
|||||||
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(spec.Replicas), "replicas")...)
|
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(spec.Replicas), "replicas")...)
|
||||||
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpecForRC(&spec.Template, spec.Selector, spec.Replicas, "template")...)
|
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpecForRC(&spec.Template, spec.Selector, spec.Replicas, "template")...)
|
||||||
allErrs = append(allErrs, ValidateDeploymentStrategy(&spec.Strategy, "strategy")...)
|
allErrs = append(allErrs, ValidateDeploymentStrategy(&spec.Strategy, "strategy")...)
|
||||||
|
// empty string is a valid UniqueLabelKey
|
||||||
|
if len(spec.UniqueLabelKey) > 0 {
|
||||||
allErrs = append(allErrs, apivalidation.ValidateLabelName(spec.UniqueLabelKey, "uniqueLabel")...)
|
allErrs = append(allErrs, apivalidation.ValidateLabelName(spec.UniqueLabelKey, "uniqueLabel")...)
|
||||||
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
run_long = `Create and run a particular image, possibly replicated.
|
run_long = `Create and run a particular image, possibly replicated.
|
||||||
Creates a replication controller to manage the created container(s).`
|
Creates a replication controller or job to manage the created container(s).`
|
||||||
run_example = `# Start a single instance of nginx.
|
run_example = `# Start a single instance of nginx.
|
||||||
$ kubectl run nginx --image=nginx
|
$ kubectl run nginx --image=nginx
|
||||||
|
|
||||||
@ -53,14 +53,17 @@ $ kubectl run nginx --image=nginx --dry-run
|
|||||||
# Start a single instance of nginx, but overload the spec of the replication controller with a partial set of values parsed from JSON.
|
# Start a single instance of nginx, but overload the spec of the replication controller with a partial set of values parsed from JSON.
|
||||||
$ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
|
$ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
|
||||||
|
|
||||||
# Start a single instance of nginx and keep it in the foreground, don't restart it if it exits.
|
# Start a single instance of busybox and keep it in the foreground, don't restart it if it exits.
|
||||||
$ kubectl run -i --tty nginx --image=nginx --restart=Never
|
$ kubectl run -i --tty busybox --image=busybox --restart=Never
|
||||||
|
|
||||||
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
|
# Start the nginx container using the default command, but use custom arguments (arg1 .. argN) for that command.
|
||||||
$ kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
|
$ kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>
|
||||||
|
|
||||||
# Start the nginx container using a different command and custom arguments
|
# Start the nginx container using a different command and custom arguments.
|
||||||
$ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>`
|
$ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
|
||||||
|
|
||||||
|
# Start the perl container to compute π to 2000 places and print it out.
|
||||||
|
$ kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(2000)'`
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||||
@ -84,7 +87,8 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addRunFlags(cmd *cobra.Command) {
|
func addRunFlags(cmd *cobra.Command) {
|
||||||
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'.")
|
// TODO: Change the default to "deployment/v1beta1" (which is a valid generator) when deployment reaches beta (#15313)
|
||||||
|
cmd.Flags().String("generator", "", "The name of the API generator to use. Default is 'run/v1' if --restart=Always, otherwise the default is 'job/v1beta1'.")
|
||||||
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.")
|
||||||
@ -98,7 +102,7 @@ func addRunFlags(cmd *cobra.Command) {
|
|||||||
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().Bool("leave-stdin-open", false, "If the pod is started in interactive mode or with stdin, leave stdin open after the first attach completes. By default, stdin will be closed after the first attach completes.")
|
cmd.Flags().Bool("leave-stdin-open", false, "If the pod is started in interactive mode or with stdin, leave stdin open after the first attach completes. By default, stdin will be closed after the first attach completes.")
|
||||||
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'")
|
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, a job is created for this pod and --replicas must be 1. Default 'Always'")
|
||||||
cmd.Flags().Bool("command", false, "If true and extra arguments are present, use them as the 'command' field in the container, rather than the 'args' field which is the default.")
|
cmd.Flags().Bool("command", false, "If true and extra arguments are present, use them as the 'command' field in the container, rather than the 'args' field which is the default.")
|
||||||
cmd.Flags().String("requests", "", "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'")
|
cmd.Flags().String("requests", "", "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'")
|
||||||
cmd.Flags().String("limits", "", "The resource requirement limits for this container. For example, 'cpu=200m,memory=512Mi'")
|
cmd.Flags().String("limits", "", "The resource requirement limits for this container. For example, 'cpu=200m,memory=512Mi'")
|
||||||
@ -142,10 +146,11 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
|
|||||||
|
|
||||||
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
generatorName := cmdutil.GetFlagString(cmd, "generator")
|
||||||
if len(generatorName) == 0 {
|
if len(generatorName) == 0 {
|
||||||
|
// TODO: Change the default to "deployment/v1beta1" when deployment reaches beta (#15313)
|
||||||
if restartPolicy == api.RestartPolicyAlways {
|
if restartPolicy == api.RestartPolicyAlways {
|
||||||
generatorName = "run/v1"
|
generatorName = "run/v1"
|
||||||
} else {
|
} else {
|
||||||
generatorName = "run-pod/v1"
|
generatorName = "job/v1beta1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generator, found := f.Generator(generatorName)
|
generator, found := f.Generator(generatorName)
|
||||||
|
@ -36,6 +36,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/meta"
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/registered"
|
"k8s.io/kubernetes/pkg/api/registered"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@ -116,6 +117,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
"service/v1": kubectl.ServiceGeneratorV1{},
|
"service/v1": kubectl.ServiceGeneratorV1{},
|
||||||
"service/v2": kubectl.ServiceGeneratorV2{},
|
"service/v2": kubectl.ServiceGeneratorV2{},
|
||||||
"horizontalpodautoscaler/v1beta1": kubectl.HorizontalPodAutoscalerV1Beta1{},
|
"horizontalpodautoscaler/v1beta1": kubectl.HorizontalPodAutoscalerV1Beta1{},
|
||||||
|
"deployment/v1beta1": kubectl.DeploymentV1Beta1{},
|
||||||
|
"job/v1beta1": kubectl.JobV1Beta1{},
|
||||||
}
|
}
|
||||||
|
|
||||||
clientConfig := optionalClientConfig
|
clientConfig := optionalClientConfig
|
||||||
@ -312,18 +315,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
}
|
}
|
||||||
switch t := object.(type) {
|
switch t := object.(type) {
|
||||||
case *api.ReplicationController:
|
case *api.ReplicationController:
|
||||||
var pods *api.PodList
|
return GetFirstPod(client, t.Namespace, t.Spec.Selector)
|
||||||
for pods == nil || len(pods.Items) == 0 {
|
case *extensions.Deployment:
|
||||||
var err error
|
return GetFirstPod(client, t.Namespace, t.Spec.Selector)
|
||||||
if pods, err = client.Pods(t.Namespace).List(labels.SelectorFromSet(t.Spec.Selector), fields.Everything()); err != nil {
|
case *extensions.Job:
|
||||||
return nil, err
|
return GetFirstPod(client, t.Namespace, t.Spec.Selector.MatchLabels)
|
||||||
}
|
|
||||||
if len(pods.Items) == 0 {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pod := &pods.Items[0]
|
|
||||||
return pod, nil
|
|
||||||
case *api.Pod:
|
case *api.Pod:
|
||||||
return t, nil
|
return t, nil
|
||||||
default:
|
default:
|
||||||
@ -337,6 +333,22 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFirstPod returns the first pod of an object from its namespace and selector
|
||||||
|
func GetFirstPod(client *client.Client, namespace string, selector map[string]string) (*api.Pod, error) {
|
||||||
|
var pods *api.PodList
|
||||||
|
for pods == nil || len(pods.Items) == 0 {
|
||||||
|
var err error
|
||||||
|
if pods, err = client.Pods(namespace).List(labels.SelectorFromSet(selector), fields.Everything()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(pods.Items) == 0 {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pod := &pods.Items[0]
|
||||||
|
return pod, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BindFlags adds any flags that are common to all kubectl sub commands.
|
// BindFlags adds any flags that are common to all kubectl sub commands.
|
||||||
func (f *Factory) BindFlags(flags *pflag.FlagSet) {
|
func (f *Factory) BindFlags(flags *pflag.FlagSet) {
|
||||||
// any flags defined by external projects (not part of pflags)
|
// any flags defined by external projects (not part of pflags)
|
||||||
|
@ -23,10 +23,264 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/validation"
|
"k8s.io/kubernetes/pkg/util/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DeploymentV1Beta1 struct{}
|
||||||
|
|
||||||
|
func (DeploymentV1Beta1) ParamNames() []GeneratorParam {
|
||||||
|
return []GeneratorParam{
|
||||||
|
{"labels", false},
|
||||||
|
{"default-name", false},
|
||||||
|
{"name", true},
|
||||||
|
{"replicas", true},
|
||||||
|
{"image", true},
|
||||||
|
{"port", false},
|
||||||
|
{"hostport", false},
|
||||||
|
{"stdin", false},
|
||||||
|
{"tty", false},
|
||||||
|
{"command", false},
|
||||||
|
{"args", false},
|
||||||
|
{"env", false},
|
||||||
|
{"requests", false},
|
||||||
|
{"limits", false},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
||||||
|
args, err := getArgs(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
envs, err := getEnvs(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
params, err := getParams(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err := getName(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels, err := getLabels(params, true, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := strconv.Atoi(params["replicas"])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
podSpec, err := makePodSpec(params, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := updatePodPorts(params, podSpec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use versioned types for generators so that we don't need to
|
||||||
|
// set default values manually (see issue #17384)
|
||||||
|
deployment := extensions.Deployment{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Spec: extensions.DeploymentSpec{
|
||||||
|
Replicas: count,
|
||||||
|
Selector: labels,
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Spec: *podSpec,
|
||||||
|
},
|
||||||
|
UniqueLabelKey: "deployment.kubernetes.io/podTemplateHash",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &deployment, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLabels(params map[string]string, defaultRunLabel bool, name string) (map[string]string, error) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
} else if defaultRunLabel {
|
||||||
|
labels = map[string]string{
|
||||||
|
"run": name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getName(params map[string]string) (string, error) {
|
||||||
|
name, found := params["name"]
|
||||||
|
if !found || len(name) == 0 {
|
||||||
|
name, found = params["default-name"]
|
||||||
|
if !found || len(name) == 0 {
|
||||||
|
return "", fmt.Errorf("'name' is a required parameter.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getParams(genericParams map[string]interface{}) (map[string]string, error) {
|
||||||
|
params := map[string]string{}
|
||||||
|
for key, value := range genericParams {
|
||||||
|
strVal, isString := value.(string)
|
||||||
|
if !isString {
|
||||||
|
return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
|
||||||
|
}
|
||||||
|
params[key] = strVal
|
||||||
|
}
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getArgs(genericParams map[string]interface{}) ([]string, error) {
|
||||||
|
args := []string{}
|
||||||
|
val, found := genericParams["args"]
|
||||||
|
if found {
|
||||||
|
var isArray bool
|
||||||
|
args, isArray = val.([]string)
|
||||||
|
if !isArray {
|
||||||
|
return nil, fmt.Errorf("expected []string, found: %v", val)
|
||||||
|
}
|
||||||
|
delete(genericParams, "args")
|
||||||
|
}
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnvs(genericParams map[string]interface{}) ([]api.EnvVar, error) {
|
||||||
|
var envs []api.EnvVar
|
||||||
|
envStrings, found := genericParams["env"]
|
||||||
|
if found {
|
||||||
|
if envStringArray, isArray := envStrings.([]string); isArray {
|
||||||
|
var err error
|
||||||
|
envs, err = parseEnvs(envStringArray)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
delete(genericParams, "env")
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("expected []string, found: %v", envStrings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return envs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobV1Beta1 struct{}
|
||||||
|
|
||||||
|
func (JobV1Beta1) ParamNames() []GeneratorParam {
|
||||||
|
return []GeneratorParam{
|
||||||
|
{"labels", false},
|
||||||
|
{"default-name", false},
|
||||||
|
{"name", true},
|
||||||
|
{"image", true},
|
||||||
|
{"port", false},
|
||||||
|
{"hostport", false},
|
||||||
|
{"stdin", false},
|
||||||
|
{"leave-stdin-open", false},
|
||||||
|
{"tty", false},
|
||||||
|
{"command", false},
|
||||||
|
{"args", false},
|
||||||
|
{"env", false},
|
||||||
|
{"requests", false},
|
||||||
|
{"limits", false},
|
||||||
|
{"restart", false},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (JobV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
||||||
|
args, err := getArgs(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
envs, err := getEnvs(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
params, err := getParams(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name, err := getName(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels, err := getLabels(params, true, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
podSpec, err := makePodSpec(params, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveStdinOpen, err := GetBool(params, "leave-stdin-open", false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
podSpec.Containers[0].StdinOnce = !leaveStdinOpen && podSpec.Containers[0].Stdin
|
||||||
|
|
||||||
|
if err := updatePodPorts(params, podSpec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
restartPolicy := api.RestartPolicy(params["restart"])
|
||||||
|
if len(restartPolicy) == 0 {
|
||||||
|
restartPolicy = api.RestartPolicyAlways
|
||||||
|
}
|
||||||
|
podSpec.RestartPolicy = restartPolicy
|
||||||
|
|
||||||
|
job := extensions.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Spec: extensions.JobSpec{
|
||||||
|
Selector: &extensions.PodSelector{
|
||||||
|
MatchLabels: labels,
|
||||||
|
},
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Spec: *podSpec,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &job, nil
|
||||||
|
}
|
||||||
|
|
||||||
type BasicReplicationController struct{}
|
type BasicReplicationController struct{}
|
||||||
|
|
||||||
func (BasicReplicationController) ParamNames() []GeneratorParam {
|
func (BasicReplicationController) ParamNames() []GeneratorParam {
|
||||||
@ -119,62 +373,31 @@ func makePodSpec(params map[string]string, name string) (*api.PodSpec, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (BasicReplicationController) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
func (BasicReplicationController) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
||||||
args := []string{}
|
args, err := getArgs(genericParams)
|
||||||
val, found := genericParams["args"]
|
|
||||||
if found {
|
|
||||||
var isArray bool
|
|
||||||
args, isArray = val.([]string)
|
|
||||||
if !isArray {
|
|
||||||
return nil, fmt.Errorf("expected []string, found: %v", val)
|
|
||||||
}
|
|
||||||
delete(genericParams, "args")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: abstract this logic so that multiple generators can handle env in the same way. Same for parse envs.
|
|
||||||
var envs []api.EnvVar
|
|
||||||
envStrings, found := genericParams["env"]
|
|
||||||
if found {
|
|
||||||
if envStringArray, isArray := envStrings.([]string); isArray {
|
|
||||||
var err error
|
|
||||||
envs, err = parseEnvs(envStringArray)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
delete(genericParams, "env")
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("expected []string, found: %v", envStrings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := map[string]string{}
|
envs, err := getEnvs(genericParams)
|
||||||
for key, value := range genericParams {
|
|
||||||
strVal, isString := value.(string)
|
|
||||||
if !isString {
|
|
||||||
return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
|
|
||||||
}
|
|
||||||
params[key] = strVal
|
|
||||||
}
|
|
||||||
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
labels = map[string]string{
|
params, err := getParams(genericParams)
|
||||||
"run": name,
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name, err := getName(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
labels, err := getLabels(params, true, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
count, err := strconv.Atoi(params["replicas"])
|
count, err := strconv.Atoi(params["replicas"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -184,20 +407,13 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(args) > 0 {
|
|
||||||
command, err := GetBool(params, "command", false)
|
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if command {
|
|
||||||
podSpec.Containers[0].Command = args
|
|
||||||
} else {
|
|
||||||
podSpec.Containers[0].Args = args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(envs) > 0 {
|
if err := updatePodPorts(params, podSpec); err != nil {
|
||||||
podSpec.Containers[0].Env = envs
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
controller := api.ReplicationController{
|
controller := api.ReplicationController{
|
||||||
@ -216,12 +432,28 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := updatePodPorts(params, &controller.Spec.Template.Spec); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &controller, nil
|
return &controller, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updatePodContainers(params map[string]string, args []string, envs []api.EnvVar, podSpec *api.PodSpec) error {
|
||||||
|
if len(args) > 0 {
|
||||||
|
command, err := GetBool(params, "command", false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if command {
|
||||||
|
podSpec.Containers[0].Command = args
|
||||||
|
} else {
|
||||||
|
podSpec.Containers[0].Args = args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(envs) > 0 {
|
||||||
|
podSpec.Containers[0].Env = envs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func updatePodPorts(params map[string]string, podSpec *api.PodSpec) (err error) {
|
func updatePodPorts(params map[string]string, podSpec *api.PodSpec) (err error) {
|
||||||
port := -1
|
port := -1
|
||||||
hostPort := -1
|
hostPort := -1
|
||||||
@ -279,57 +511,31 @@ func (BasicPod) ParamNames() []GeneratorParam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object, error) {
|
||||||
args := []string{}
|
args, err := getArgs(genericParams)
|
||||||
val, found := genericParams["args"]
|
|
||||||
if found {
|
|
||||||
var isArray bool
|
|
||||||
args, isArray = val.([]string)
|
|
||||||
if !isArray {
|
|
||||||
return nil, fmt.Errorf("expected []string, found: %v", val)
|
|
||||||
}
|
|
||||||
delete(genericParams, "args")
|
|
||||||
}
|
|
||||||
// TODO: abstract this logic so that multiple generators can handle env in the same way. Same for parse envs.
|
|
||||||
var envs []api.EnvVar
|
|
||||||
envStrings, found := genericParams["env"]
|
|
||||||
if found {
|
|
||||||
if envStringArray, isArray := envStrings.([]string); isArray {
|
|
||||||
var err error
|
|
||||||
envs, err = parseEnvs(envStringArray)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
delete(genericParams, "env")
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("expected []string, found: %v", envStrings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params := map[string]string{}
|
envs, err := getEnvs(genericParams)
|
||||||
for key, value := range genericParams {
|
|
||||||
strVal, isString := value.(string)
|
|
||||||
if !isString {
|
|
||||||
return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
|
|
||||||
}
|
|
||||||
params[key] = strVal
|
|
||||||
}
|
|
||||||
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params, err := getParams(genericParams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name, err := getName(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels, err := getLabels(params, false, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
stdin, err := GetBool(params, "stdin", false)
|
stdin, err := GetBool(params, "stdin", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -374,21 +580,9 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
|
|||||||
RestartPolicy: restartPolicy,
|
RestartPolicy: restartPolicy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(args) > 0 {
|
if err = updatePodContainers(params, args, envs, &pod.Spec); err != nil {
|
||||||
command, err := GetBool(params, "command", false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if command {
|
|
||||||
pod.Spec.Containers[0].Command = args
|
|
||||||
} else {
|
|
||||||
pod.Spec.Containers[0].Args = args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(envs) > 0 {
|
|
||||||
pod.Spec.Containers[0].Env = envs
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := updatePodPorts(params, &pod.Spec); err != nil {
|
if err := updatePodPorts(params, &pod.Spec); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerate(t *testing.T) {
|
func TestGenerate(t *testing.T) {
|
||||||
@ -625,3 +626,188 @@ func TestGeneratePod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateDeployment(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
params map[string]interface{}
|
||||||
|
expected *extensions.Deployment
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"labels": "foo=bar,baz=blah",
|
||||||
|
"name": "foo",
|
||||||
|
"replicas": "3",
|
||||||
|
"image": "someimage",
|
||||||
|
"port": "80",
|
||||||
|
"hostport": "80",
|
||||||
|
"stdin": "true",
|
||||||
|
"command": "true",
|
||||||
|
"args": []string{"bar", "baz", "blah"},
|
||||||
|
"env": []string{"a=b", "c=d"},
|
||||||
|
"requests": "cpu=100m,memory=100Mi",
|
||||||
|
"limits": "cpu=400m,memory=200Mi",
|
||||||
|
},
|
||||||
|
expected: &extensions.Deployment{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||||
|
},
|
||||||
|
Spec: extensions.DeploymentSpec{
|
||||||
|
Replicas: 3,
|
||||||
|
Selector: map[string]string{"foo": "bar", "baz": "blah"},
|
||||||
|
UniqueLabelKey: "deployment.kubernetes.io/podTemplateHash",
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
Image: "someimage",
|
||||||
|
Stdin: true,
|
||||||
|
Ports: []api.ContainerPort{
|
||||||
|
{
|
||||||
|
ContainerPort: 80,
|
||||||
|
HostPort: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Command: []string{"bar", "baz", "blah"},
|
||||||
|
Env: []api.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
Value: "b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "c",
|
||||||
|
Value: "d",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resources: api.ResourceRequirements{
|
||||||
|
Requests: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100m"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100Mi"),
|
||||||
|
},
|
||||||
|
Limits: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("400m"),
|
||||||
|
api.ResourceMemory: resource.MustParse("200Mi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
generator := DeploymentV1Beta1{}
|
||||||
|
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.(*extensions.Deployment), test.expected) {
|
||||||
|
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensions.Deployment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateJob(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
params map[string]interface{}
|
||||||
|
expected *extensions.Job
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
params: map[string]interface{}{
|
||||||
|
"labels": "foo=bar,baz=blah",
|
||||||
|
"name": "foo",
|
||||||
|
"image": "someimage",
|
||||||
|
"port": "80",
|
||||||
|
"hostport": "80",
|
||||||
|
"stdin": "true",
|
||||||
|
"leave-stdin-open": "true",
|
||||||
|
"command": "true",
|
||||||
|
"args": []string{"bar", "baz", "blah"},
|
||||||
|
"env": []string{"a=b", "c=d"},
|
||||||
|
"requests": "cpu=100m,memory=100Mi",
|
||||||
|
"limits": "cpu=400m,memory=200Mi",
|
||||||
|
"restart": "OnFailure",
|
||||||
|
},
|
||||||
|
expected: &extensions.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||||
|
},
|
||||||
|
Spec: extensions.JobSpec{
|
||||||
|
Selector: &extensions.PodSelector{
|
||||||
|
MatchLabels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||||
|
},
|
||||||
|
Template: api.PodTemplateSpec{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: map[string]string{"foo": "bar", "baz": "blah"},
|
||||||
|
},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
RestartPolicy: api.RestartPolicyOnFailure,
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
Image: "someimage",
|
||||||
|
Stdin: true,
|
||||||
|
StdinOnce: false,
|
||||||
|
Ports: []api.ContainerPort{
|
||||||
|
{
|
||||||
|
ContainerPort: 80,
|
||||||
|
HostPort: 80,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Command: []string{"bar", "baz", "blah"},
|
||||||
|
Env: []api.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "a",
|
||||||
|
Value: "b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "c",
|
||||||
|
Value: "d",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resources: api.ResourceRequirements{
|
||||||
|
Requests: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("100m"),
|
||||||
|
api.ResourceMemory: resource.MustParse("100Mi"),
|
||||||
|
},
|
||||||
|
Limits: api.ResourceList{
|
||||||
|
api.ResourceCPU: resource.MustParse("400m"),
|
||||||
|
api.ResourceMemory: resource.MustParse("200Mi"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
generator := JobV1Beta1{}
|
||||||
|
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.(*extensions.Job), test.expected) {
|
||||||
|
t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensions.Job))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -44,6 +44,7 @@ import (
|
|||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/util/wait"
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
|
|
||||||
@ -367,7 +368,7 @@ var _ = Describe("Kubectl client", func() {
|
|||||||
execOrDie()
|
execOrDie()
|
||||||
Expect(runOutput).To(ContainSubstring("abcd1234"))
|
Expect(runOutput).To(ContainSubstring("abcd1234"))
|
||||||
Expect(runOutput).To(ContainSubstring("stdin closed"))
|
Expect(runOutput).To(ContainSubstring("stdin closed"))
|
||||||
Expect(c.Pods(ns).Delete("run-test", api.NewDeleteOptions(0))).To(BeNil())
|
Expect(c.Extensions().Jobs(ns).Delete("run-test", api.NewDeleteOptions(0))).To(BeNil())
|
||||||
|
|
||||||
By("executing a command with run and attach without stdin")
|
By("executing a command with run and attach without stdin")
|
||||||
runOutput = newKubectlCommand(fmt.Sprintf("--namespace=%v", ns), "run", "run-test-2", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--", "sh", "-c", "cat && echo 'stdin closed'").
|
runOutput = newKubectlCommand(fmt.Sprintf("--namespace=%v", ns), "run", "run-test-2", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--", "sh", "-c", "cat && echo 'stdin closed'").
|
||||||
@ -375,24 +376,28 @@ var _ = Describe("Kubectl client", func() {
|
|||||||
execOrDie()
|
execOrDie()
|
||||||
Expect(runOutput).ToNot(ContainSubstring("abcd1234"))
|
Expect(runOutput).ToNot(ContainSubstring("abcd1234"))
|
||||||
Expect(runOutput).To(ContainSubstring("stdin closed"))
|
Expect(runOutput).To(ContainSubstring("stdin closed"))
|
||||||
Expect(c.Pods(ns).Delete("run-test-2", api.NewDeleteOptions(0))).To(BeNil())
|
Expect(c.Extensions().Jobs(ns).Delete("run-test-2", api.NewDeleteOptions(0))).To(BeNil())
|
||||||
|
|
||||||
By("executing a command with run and attach with stdin with open stdin should remain running")
|
By("executing a command with run and attach with stdin with open stdin should remain running")
|
||||||
runOutput = newKubectlCommand(nsFlag, "run", "run-test-3", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--stdin", "--", "sh", "-c", "cat && echo 'stdin closed'").
|
runOutput = newKubectlCommand(nsFlag, "run", "run-test-3", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--stdin", "--", "sh", "-c", "cat && echo 'stdin closed'").
|
||||||
withStdinData("abcd1234\n").
|
withStdinData("abcd1234\n").
|
||||||
execOrDie()
|
execOrDie()
|
||||||
Expect(runOutput).ToNot(ContainSubstring("stdin closed"))
|
Expect(runOutput).ToNot(ContainSubstring("stdin closed"))
|
||||||
if !checkPodsRunningReady(c, ns, []string{"run-test-3"}, time.Minute) {
|
runTestPod, err := util.GetFirstPod(c, ns, map[string]string{"run": "run-test-3"})
|
||||||
Failf("Pod %q should still be running", "run-test-3")
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if !checkPodsRunningReady(c, ns, []string{runTestPod.Name}, time.Minute) {
|
||||||
|
Failf("Pod %q of Job %q should still be running", runTestPod.Name, "run-test-3")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we cannot guarantee our output showed up in the container logs before stdin was closed, so we have
|
// NOTE: we cannot guarantee our output showed up in the container logs before stdin was closed, so we have
|
||||||
// to loop test.
|
// to loop test.
|
||||||
err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
|
err = wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
|
||||||
if !checkPodsRunningReady(c, ns, []string{"run-test-3"}, 1*time.Second) {
|
if !checkPodsRunningReady(c, ns, []string{runTestPod.Name}, 1*time.Second) {
|
||||||
Failf("Pod %q should still be running", "run-test-3")
|
Failf("Pod %q of Job %q should still be running", runTestPod.Name, "run-test-3")
|
||||||
}
|
}
|
||||||
logOutput := runKubectlOrDie(nsFlag, "logs", "run-test-3")
|
logOutput := runKubectlOrDie(nsFlag, "logs", runTestPod.Name)
|
||||||
Expect(logOutput).ToNot(ContainSubstring("stdin closed"))
|
Expect(logOutput).ToNot(ContainSubstring("stdin closed"))
|
||||||
return strings.Contains(logOutput, "abcd1234"), nil
|
return strings.Contains(logOutput, "abcd1234"), nil
|
||||||
})
|
})
|
||||||
@ -401,7 +406,7 @@ var _ = Describe("Kubectl client", func() {
|
|||||||
}
|
}
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
Expect(c.Pods(ns).Delete("run-test-3", api.NewDeleteOptions(0))).To(BeNil())
|
Expect(c.Extensions().Jobs(ns).Delete("run-test-3", api.NewDeleteOptions(0))).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should support port-forward", func() {
|
It("should support port-forward", func() {
|
||||||
@ -804,54 +809,54 @@ var _ = Describe("Kubectl client", func() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Kubectl run pod", func() {
|
Describe("Kubectl run job", func() {
|
||||||
var nsFlag string
|
var nsFlag string
|
||||||
var podName string
|
var jobName string
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
nsFlag = fmt.Sprintf("--namespace=%v", ns)
|
nsFlag = fmt.Sprintf("--namespace=%v", ns)
|
||||||
podName = "e2e-test-nginx-pod"
|
jobName = "e2e-test-nginx-job"
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
runKubectlOrDie("stop", "pods", podName, nsFlag)
|
runKubectlOrDie("stop", "jobs", jobName, nsFlag)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should create a pod from an image when restart is OnFailure [Conformance]", func() {
|
It("should create a job from an image when restart is OnFailure [Conformance]", func() {
|
||||||
image := "nginx"
|
image := "nginx"
|
||||||
|
|
||||||
By("running the image " + image)
|
By("running the image " + image)
|
||||||
runKubectlOrDie("run", podName, "--restart=OnFailure", "--image="+image, nsFlag)
|
runKubectlOrDie("run", jobName, "--restart=OnFailure", "--image="+image, nsFlag)
|
||||||
By("verifying the pod " + podName + " was created")
|
By("verifying the job " + jobName + " was created")
|
||||||
pod, err := c.Pods(ns).Get(podName)
|
job, err := c.Extensions().Jobs(ns).Get(jobName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Failf("Failed getting pod %s: %v", podName, err)
|
Failf("Failed getting job %s: %v", jobName, err)
|
||||||
}
|
}
|
||||||
containers := pod.Spec.Containers
|
containers := job.Spec.Template.Spec.Containers
|
||||||
if containers == nil || len(containers) != 1 || containers[0].Image != image {
|
if containers == nil || len(containers) != 1 || containers[0].Image != image {
|
||||||
Failf("Failed creating pod %s for 1 pod with expected image %s", podName, image)
|
Failf("Failed creating job %s for 1 pod with expected image %s", jobName, image)
|
||||||
}
|
}
|
||||||
if pod.Spec.RestartPolicy != api.RestartPolicyOnFailure {
|
if job.Spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure {
|
||||||
Failf("Failed creating a pod with correct restart policy for --restart=OnFailure")
|
Failf("Failed creating a job with correct restart policy for --restart=OnFailure")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should create a pod from an image when restart is Never [Conformance]", func() {
|
It("should create a job from an image when restart is Never [Conformance]", func() {
|
||||||
image := "nginx"
|
image := "nginx"
|
||||||
|
|
||||||
By("running the image " + image)
|
By("running the image " + image)
|
||||||
runKubectlOrDie("run", podName, "--restart=Never", "--image="+image, nsFlag)
|
runKubectlOrDie("run", jobName, "--restart=Never", "--image="+image, nsFlag)
|
||||||
By("verifying the pod " + podName + " was created")
|
By("verifying the job " + jobName + " was created")
|
||||||
pod, err := c.Pods(ns).Get(podName)
|
job, err := c.Extensions().Jobs(ns).Get(jobName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Failf("Failed getting pod %s: %v", podName, err)
|
Failf("Failed getting job %s: %v", jobName, err)
|
||||||
}
|
}
|
||||||
containers := pod.Spec.Containers
|
containers := job.Spec.Template.Spec.Containers
|
||||||
if containers == nil || len(containers) != 1 || containers[0].Image != image {
|
if containers == nil || len(containers) != 1 || containers[0].Image != image {
|
||||||
Failf("Failed creating pod %s for 1 pod with expected image %s", podName, image)
|
Failf("Failed creating job %s for 1 pod with expected image %s", jobName, image)
|
||||||
}
|
}
|
||||||
if pod.Spec.RestartPolicy != api.RestartPolicyNever {
|
if job.Spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
|
||||||
Failf("Failed creating a pod with correct restart policy for --restart=OnFailure")
|
Failf("Failed creating a job with correct restart policy for --restart=OnFailure")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user