Merge pull request #30614 from AdoHe/run_pull_policy

Automatic merge from submit-queue

kubectl run add pull-policy flag to control image pull policy

```release-note
Add support for --image-pull-policy to 'kubectl run'
```

Fix #30493 
@pwittrock @thockin ptal
This commit is contained in:
Kubernetes Submit Queue 2016-08-21 14:04:15 -07:00 committed by GitHub
commit d1ed6f598f
3 changed files with 98 additions and 48 deletions

View File

@ -107,6 +107,7 @@ func addRunFlags(cmd *cobra.Command) {
cmd.Flags().String("generator", "", "The name of the API generator to use. Default is 'deployment/v1beta1' if --restart=Always, 'job/v1' for OnFailure and 'run-pod/v1' for Never. This will happen only for cluster version at least 1.3, for 1.2 we will fallback to 'deployment/v1beta1' for --restart=Always, 'job/v1' for others, for olders we will fallback to 'run/v1' for --restart=Always, 'run-pod/v1' for others.")
cmd.Flags().String("image", "", "The image for the container to run.")
cmd.MarkFlagRequired("image")
cmd.Flags().String("image-pull-policy", "", "The image pull policy for the container. If left empty, this value will not be specified by the client and defaulted by the server")
cmd.Flags().IntP("replicas", "r", 1, "Number of replicas to create for this container. Default is 1.")
cmd.Flags().Bool("rm", false, "If true, delete resources created in this command for attached containers.")
cmd.Flags().String("overrides", "", "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.")
@ -168,6 +169,10 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
return cmdutil.UsageError(cmd, fmt.Sprintf("--restart=%s requires that --replicas=1, found %d", restartPolicy, replicas))
}
if err := verifyImagePullPolicy(cmd); err != nil {
return err
}
generatorName := cmdutil.GetFlagString(cmd, "generator")
schedule := cmdutil.GetFlagString(cmd, "schedule")
if len(schedule) != 0 && len(generatorName) == 0 {
@ -511,6 +516,18 @@ func getRestartPolicy(cmd *cobra.Command, interactive bool) (api.RestartPolicy,
}
}
func verifyImagePullPolicy(cmd *cobra.Command) error {
pullPolicy := cmdutil.GetFlagString(cmd, "image-pull-policy")
switch api.PullPolicy(pullPolicy) {
case api.PullAlways, api.PullIfNotPresent, api.PullNever:
return nil
case "":
return nil
default:
return cmdutil.UsageError(cmd, fmt.Sprintf("invalid image pull policy: %s", pullPolicy))
}
}
func generateService(f *cmdutil.Factory, cmd *cobra.Command, args []string, serviceGenerator string, paramsIn map[string]interface{}, namespace string, out io.Writer) error {
generators := f.Generators("expose")
generator, found := generators[serviceGenerator]

View File

@ -42,6 +42,7 @@ func (DeploymentV1Beta1) ParamNames() []GeneratorParam {
{"name", true},
{"replicas", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
@ -90,7 +91,8 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime
return nil, err
}
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err
}
@ -217,6 +219,7 @@ func (JobV1Beta1) ParamNames() []GeneratorParam {
{"default-name", false},
{"name", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
@ -262,7 +265,8 @@ func (JobV1Beta1) Generate(genericParams map[string]interface{}) (runtime.Object
return nil, err
}
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err
}
@ -312,6 +316,7 @@ func (JobV1) ParamNames() []GeneratorParam {
{"default-name", false},
{"name", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
@ -357,7 +362,8 @@ func (JobV1) Generate(genericParams map[string]interface{}) (runtime.Object, err
return nil, err
}
if err = updateV1PodContainers(params, args, envs, podSpec); err != nil {
imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updateV1PodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err
}
@ -403,6 +409,7 @@ func (ScheduledJobV2Alpha1) ParamNames() []GeneratorParam {
{"default-name", false},
{"name", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
@ -449,7 +456,8 @@ func (ScheduledJobV2Alpha1) Generate(genericParams map[string]interface{}) (runt
return nil, err
}
if err = updateV1PodContainers(params, args, envs, podSpec); err != nil {
imagePullPolicy := v1.PullPolicy(params["image-pull-policy"])
if err = updateV1PodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err
}
@ -502,6 +510,7 @@ func (BasicReplicationController) ParamNames() []GeneratorParam {
{"name", true},
{"replicas", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
@ -690,7 +699,8 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
return nil, err
}
if err = updatePodContainers(params, args, envs, podSpec); err != nil {
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, podSpec); err != nil {
return nil, err
}
@ -717,7 +727,7 @@ func (BasicReplicationController) Generate(genericParams map[string]interface{})
return &controller, nil
}
func updatePodContainers(params map[string]string, args []string, envs []api.EnvVar, podSpec *api.PodSpec) error {
func updatePodContainers(params map[string]string, args []string, envs []api.EnvVar, imagePullPolicy api.PullPolicy, podSpec *api.PodSpec) error {
if len(args) > 0 {
command, err := GetBool(params, "command", false)
if err != nil {
@ -733,10 +743,15 @@ func updatePodContainers(params map[string]string, args []string, envs []api.Env
if len(envs) > 0 {
podSpec.Containers[0].Env = envs
}
if len(imagePullPolicy) > 0 {
// imagePullPolicy should be valid here since we have verified it before.
podSpec.Containers[0].ImagePullPolicy = imagePullPolicy
}
return nil
}
func updateV1PodContainers(params map[string]string, args []string, envs []v1.EnvVar, podSpec *v1.PodSpec) error {
func updateV1PodContainers(params map[string]string, args []string, envs []v1.EnvVar, imagePullPolicy v1.PullPolicy, podSpec *v1.PodSpec) error {
if len(args) > 0 {
command, err := GetBool(params, "command", false)
if err != nil {
@ -752,6 +767,11 @@ func updateV1PodContainers(params map[string]string, args []string, envs []v1.En
if len(envs) > 0 {
podSpec.Containers[0].Env = envs
}
if len(imagePullPolicy) > 0 {
// imagePullPolicy should be valid here since we have verified it before.
podSpec.Containers[0].ImagePullPolicy = imagePullPolicy
}
return nil
}
@ -831,6 +851,7 @@ func (BasicPod) ParamNames() []GeneratorParam {
{"default-name", false},
{"name", true},
{"image", true},
{"image-pull-policy", false},
{"port", false},
{"hostport", false},
{"stdin", false},
@ -894,6 +915,8 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
if len(restartPolicy) == 0 {
restartPolicy = api.RestartPolicyAlways
}
// TODO: Figure out why we set ImagePullPolicy here, whether we can make it
// consistent with the other places imagePullPolicy is set using flag.
pod := api.Pod{
ObjectMeta: api.ObjectMeta{
Name: name,
@ -915,7 +938,8 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
RestartPolicy: restartPolicy,
},
}
if err = updatePodContainers(params, args, envs, &pod.Spec); err != nil {
imagePullPolicy := api.PullPolicy(params["image-pull-policy"])
if err = updatePodContainers(params, args, envs, imagePullPolicy, &pod.Spec); err != nil {
return nil, err
}

View File

@ -35,10 +35,11 @@ func TestGenerate(t *testing.T) {
}{
{
params: map[string]interface{}{
"name": "foo",
"image": "someimage",
"replicas": "1",
"port": "-1",
"name": "foo",
"image": "someimage",
"image-pull-policy": "Always",
"replicas": "1",
"port": "-1",
},
expected: &api.ReplicationController{
ObjectMeta: api.ObjectMeta{
@ -55,8 +56,9 @@ func TestGenerate(t *testing.T) {
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullAlways,
},
},
},
@ -110,11 +112,12 @@ func TestGenerate(t *testing.T) {
{
params: map[string]interface{}{
"name": "foo",
"image": "someimage",
"replicas": "1",
"port": "-1",
"args": []string{"bar", "baz", "blah"},
"name": "foo",
"image": "someimage",
"image-pull-policy": "Never",
"replicas": "1",
"port": "-1",
"args": []string{"bar", "baz", "blah"},
},
expected: &api.ReplicationController{
ObjectMeta: api.ObjectMeta{
@ -131,9 +134,10 @@ func TestGenerate(t *testing.T) {
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
Args: []string{"bar", "baz", "blah"},
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullNever,
Args: []string{"bar", "baz", "blah"},
},
},
},
@ -213,11 +217,12 @@ func TestGenerate(t *testing.T) {
},
{
params: map[string]interface{}{
"name": "foo",
"image": "someimage",
"replicas": "1",
"port": "80",
"hostport": "80",
"name": "foo",
"image": "someimage",
"image-pull-policy": "IfNotPresent",
"replicas": "1",
"port": "80",
"hostport": "80",
},
expected: &api.ReplicationController{
ObjectMeta: api.ObjectMeta{
@ -234,8 +239,9 @@ func TestGenerate(t *testing.T) {
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
Ports: []api.ContainerPort{
{
ContainerPort: 80,
@ -435,9 +441,10 @@ func TestGeneratePod(t *testing.T) {
},
{
params: map[string]interface{}{
"name": "foo",
"image": "someimage",
"env": []string{"a=b", "c=d"},
"name": "foo",
"image": "someimage",
"image-pull-policy": "Always",
"env": []string{"a=b", "c=d"},
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
@ -448,7 +455,7 @@ func TestGeneratePod(t *testing.T) {
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
ImagePullPolicy: api.PullAlways,
Env: []api.EnvVar{
{
Name: "a",
@ -639,18 +646,19 @@ func TestGenerateDeployment(t *testing.T) {
}{
{
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",
"labels": "foo=bar,baz=blah",
"name": "foo",
"replicas": "3",
"image": "someimage",
"image-pull-policy": "Always",
"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{
@ -667,9 +675,10 @@ func TestGenerateDeployment(t *testing.T) {
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
Stdin: true,
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullAlways,
Stdin: true,
Ports: []api.ContainerPort{
{
ContainerPort: 80,