mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Make kubectl apply create resources if not found
This commit is contained in:
		@@ -14,6 +14,7 @@ kubectl apply \- Apply a configuration to a resource by filename or stdin
 | 
				
			|||||||
.SH DESCRIPTION
 | 
					.SH DESCRIPTION
 | 
				
			||||||
.PP
 | 
					.PP
 | 
				
			||||||
Apply a configuration to a resource by filename or stdin.
 | 
					Apply a configuration to a resource by filename or stdin.
 | 
				
			||||||
 | 
					The resource will be created if it doesn't exist yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PP
 | 
					.PP
 | 
				
			||||||
JSON and YAML formats are accepted.
 | 
					JSON and YAML formats are accepted.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,7 @@ Apply a configuration to a resource by filename or stdin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Apply a configuration to a resource by filename or stdin.
 | 
					Apply a configuration to a resource by filename or stdin.
 | 
				
			||||||
 | 
					The resource will be created if it doesn't exist yet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
JSON and YAML formats are accepted.
 | 
					JSON and YAML formats are accepted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -97,7 +98,7 @@ $ cat pod.json | kubectl apply -f -
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
					* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###### Auto generated by spf13/cobra at 2015-10-01 05:36:57.66914652 +0000 UTC
 | 
					###### Auto generated by spf13/cobra on 4-Nov-2015
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
 | 
					<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
 | 
				
			||||||
[]()
 | 
					[]()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -635,6 +635,18 @@ runTests() {
 | 
				
			|||||||
  # Clean up
 | 
					  # Clean up
 | 
				
			||||||
  kubectl delete rc,hpa frontend
 | 
					  kubectl delete rc,hpa frontend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ## kubectl apply should create the resource that doesn't exist yet
 | 
				
			||||||
 | 
					  # Pre-Condition: no POD is running 
 | 
				
			||||||
 | 
					  kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''
 | 
				
			||||||
 | 
					  # Command: apply a pod "test-pod" (doesn't exist) should create this pod 
 | 
				
			||||||
 | 
					  kubectl apply -f hack/testdata/pod.yaml "${kube_flags[@]}"
 | 
				
			||||||
 | 
					  # Post-Condition: pod "test-pod" is running
 | 
				
			||||||
 | 
					  kube::test::get_object_assert 'pods test-pod' "{{${labels_field}.name}}" 'test-pod-label'
 | 
				
			||||||
 | 
					  # Post-Condition: pod "test-pod" has configuration annotation
 | 
				
			||||||
 | 
					  [[ "$(kubectl get pods test-pod -o yaml "${kube_flags[@]}" | grep kubectl.kubernetes.io/last-applied-configuration)" ]]
 | 
				
			||||||
 | 
					  # Clean up 
 | 
				
			||||||
 | 
					  kubectl delete pods test-pod "${kube_flags[@]}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ##############
 | 
					  ##############
 | 
				
			||||||
  # Namespaces #
 | 
					  # Namespaces #
 | 
				
			||||||
  ##############
 | 
					  ##############
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubectl"
 | 
						"k8s.io/kubernetes/pkg/kubectl"
 | 
				
			||||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
						cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
						"k8s.io/kubernetes/pkg/kubectl/resource"
 | 
				
			||||||
@@ -37,6 +38,7 @@ type ApplyOptions struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	apply_long = `Apply a configuration to a resource by filename or stdin.
 | 
						apply_long = `Apply a configuration to a resource by filename or stdin.
 | 
				
			||||||
 | 
					The resource will be created if it doesn't exist yet. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
JSON and YAML formats are accepted.`
 | 
					JSON and YAML formats are accepted.`
 | 
				
			||||||
	apply_example = `# Apply the configuration in pod.json to a pod.
 | 
						apply_example = `# Apply the configuration in pod.json to a pod.
 | 
				
			||||||
@@ -119,7 +121,21 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := info.Get(); err != nil {
 | 
							if err := info.Get(); err != nil {
 | 
				
			||||||
			return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
 | 
								if !errors.IsNotFound(err) {
 | 
				
			||||||
 | 
									return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Create the resource if it doesn't exist
 | 
				
			||||||
 | 
								// First, update the annotation used by kubectl apply
 | 
				
			||||||
 | 
								if err := kubectl.CreateApplyAnnotation(info); err != nil {
 | 
				
			||||||
 | 
									return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Then create the resource and skip the three-way merge
 | 
				
			||||||
 | 
								if err := createAndRefresh(info); err != nil {
 | 
				
			||||||
 | 
									return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								count++
 | 
				
			||||||
 | 
								cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "created")
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Serialize the current configuration of the object from the server.
 | 
							// Serialize the current configuration of the object from the server.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ import (
 | 
				
			|||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/api/errors"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/client/unversioned/fake"
 | 
						"k8s.io/kubernetes/pkg/client/unversioned/fake"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubectl"
 | 
						"k8s.io/kubernetes/pkg/kubectl"
 | 
				
			||||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
						cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
				
			||||||
@@ -207,6 +208,43 @@ func TestApplyObject(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestApplyNonExistObject(t *testing.T) {
 | 
				
			||||||
 | 
						nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
				
			||||||
 | 
						pathRC := "/namespaces/test/replicationcontrollers"
 | 
				
			||||||
 | 
						pathNameRC := pathRC + "/" + nameRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f, tf, codec := NewAPIFactory()
 | 
				
			||||||
 | 
						tf.Printer = &testPrinter{}
 | 
				
			||||||
 | 
						tf.Client = &fake.RESTClient{
 | 
				
			||||||
 | 
							Codec: codec,
 | 
				
			||||||
 | 
							Client: fake.HTTPClientFunc(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
 | 
								case p == pathNameRC && m == "GET":
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 404}, errors.NewNotFound("ReplicationController", "")
 | 
				
			||||||
 | 
								case p == pathRC && m == "POST":
 | 
				
			||||||
 | 
									bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 201, Body: bodyRC}, nil
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
 | 
				
			||||||
 | 
									return nil, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tf.Namespace = "test"
 | 
				
			||||||
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd := NewCmdApply(f, buf)
 | 
				
			||||||
 | 
						cmd.Flags().Set("filename", filenameRC)
 | 
				
			||||||
 | 
						cmd.Flags().Set("output", "name")
 | 
				
			||||||
 | 
						cmd.Run(cmd, []string{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// uses the name from the file, not the response
 | 
				
			||||||
 | 
						expectRC := "replicationcontroller/" + nameRC + "\n"
 | 
				
			||||||
 | 
						if buf.String() != expectRC {
 | 
				
			||||||
 | 
							t.Errorf("unexpected output: %s\nexpected: %s", buf.String(), expectRC)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestApplyMultipleObject(t *testing.T) {
 | 
					func TestApplyMultipleObject(t *testing.T) {
 | 
				
			||||||
	nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
						nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
				
			||||||
	pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
 | 
						pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,13 +111,11 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C
 | 
				
			|||||||
			return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
								return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
 | 
							if err := createAndRefresh(info); err != nil {
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
								return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		count++
 | 
							count++
 | 
				
			||||||
		info.Refresh(obj, true)
 | 
					 | 
				
			||||||
		shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
 | 
							shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
 | 
				
			||||||
		if !shortOutput {
 | 
							if !shortOutput {
 | 
				
			||||||
			printObjectSpecificMessage(info.Object, out)
 | 
								printObjectSpecificMessage(info.Object, out)
 | 
				
			||||||
@@ -164,3 +162,13 @@ func makePortsString(ports []api.ServicePort, useNodePort bool) string {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return strings.Join(pieces, ",")
 | 
						return strings.Join(pieces, ",")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// createAndRefresh creates an object from input info and refreshes info with that object
 | 
				
			||||||
 | 
					func createAndRefresh(info *resource.Info) error {
 | 
				
			||||||
 | 
						obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						info.Refresh(obj, true)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user