mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Merge pull request #86408 from julianvmodesto/kubectl-ss-dry-run-helper
Support server-side dry-run in cli-runtime REST Helper
This commit is contained in:
		
							
								
								
									
										110465
									
								
								staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110465
									
								
								staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -11,6 +11,7 @@ require (
 | 
				
			|||||||
	github.com/ghodss/yaml v1.0.0 // indirect
 | 
						github.com/ghodss/yaml v1.0.0 // indirect
 | 
				
			||||||
	github.com/go-openapi/jsonreference v0.19.3 // indirect
 | 
						github.com/go-openapi/jsonreference v0.19.3 // indirect
 | 
				
			||||||
	github.com/go-openapi/spec v0.19.3 // indirect
 | 
						github.com/go-openapi/spec v0.19.3 // indirect
 | 
				
			||||||
 | 
						github.com/googleapis/gnostic v0.1.0
 | 
				
			||||||
	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
 | 
						github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
 | 
				
			||||||
	github.com/mailru/easyjson v0.7.0 // indirect
 | 
						github.com/mailru/easyjson v0.7.0 // indirect
 | 
				
			||||||
	github.com/pkg/errors v0.8.1
 | 
						github.com/pkg/errors v0.8.1
 | 
				
			||||||
@@ -18,9 +19,11 @@ require (
 | 
				
			|||||||
	github.com/spf13/pflag v1.0.5
 | 
						github.com/spf13/pflag v1.0.5
 | 
				
			||||||
	github.com/stretchr/testify v1.4.0
 | 
						github.com/stretchr/testify v1.4.0
 | 
				
			||||||
	golang.org/x/text v0.3.2
 | 
						golang.org/x/text v0.3.2
 | 
				
			||||||
 | 
						gopkg.in/yaml.v2 v2.2.7
 | 
				
			||||||
	k8s.io/api v0.0.0
 | 
						k8s.io/api v0.0.0
 | 
				
			||||||
	k8s.io/apimachinery v0.0.0
 | 
						k8s.io/apimachinery v0.0.0
 | 
				
			||||||
	k8s.io/client-go v0.0.0
 | 
						k8s.io/client-go v0.0.0
 | 
				
			||||||
 | 
						k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
 | 
				
			||||||
	sigs.k8s.io/kustomize v2.0.3+incompatible
 | 
						sigs.k8s.io/kustomize v2.0.3+incompatible
 | 
				
			||||||
	sigs.k8s.io/yaml v1.1.0
 | 
						sigs.k8s.io/yaml v1.1.0
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								staging/src/k8s.io/cli-runtime/go.sum
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								staging/src/k8s.io/cli-runtime/go.sum
									
									
									
										generated
									
									
									
								
							@@ -36,6 +36,7 @@ github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6
 | 
				
			|||||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 | 
					github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 | 
					github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
					github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
				
			||||||
 | 
					github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM=
 | 
				
			||||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 | 
					github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 | 
				
			||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 | 
					github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 | 
				
			||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 | 
					github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,9 @@ go_library(
 | 
				
			|||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        "builder.go",
 | 
					        "builder.go",
 | 
				
			||||||
        "client.go",
 | 
					        "client.go",
 | 
				
			||||||
 | 
					        "crd_finder.go",
 | 
				
			||||||
        "doc.go",
 | 
					        "doc.go",
 | 
				
			||||||
 | 
					        "dry_run_verifier.go",
 | 
				
			||||||
        "fake.go",
 | 
					        "fake.go",
 | 
				
			||||||
        "helper.go",
 | 
					        "helper.go",
 | 
				
			||||||
        "interfaces.go",
 | 
					        "interfaces.go",
 | 
				
			||||||
@@ -39,11 +41,14 @@ go_library(
 | 
				
			|||||||
        "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/cli-runtime/pkg/kustomize:go_default_library",
 | 
					        "//staging/src/k8s.io/cli-runtime/pkg/kustomize:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/client-go/discovery:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/discovery:go_default_library",
 | 
				
			||||||
 | 
					        "//staging/src/k8s.io/client-go/dynamic:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/client-go/rest:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/rest:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/client-go/restmapper:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/restmapper:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
 | 
				
			||||||
        "//vendor/golang.org/x/text/encoding/unicode:go_default_library",
 | 
					        "//vendor/golang.org/x/text/encoding/unicode:go_default_library",
 | 
				
			||||||
        "//vendor/golang.org/x/text/transform:go_default_library",
 | 
					        "//vendor/golang.org/x/text/transform:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/gopkg.in/yaml.v2:go_default_library",
 | 
				
			||||||
        "//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library",
 | 
					        "//vendor/sigs.k8s.io/kustomize/pkg/fs:go_default_library",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -52,6 +57,8 @@ go_test(
 | 
				
			|||||||
    name = "go_default_test",
 | 
					    name = "go_default_test",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        "builder_test.go",
 | 
					        "builder_test.go",
 | 
				
			||||||
 | 
					        "crd_finder_test.go",
 | 
				
			||||||
 | 
					        "dry_run_verifier_test.go",
 | 
				
			||||||
        "helper_test.go",
 | 
					        "helper_test.go",
 | 
				
			||||||
        "scheme_test.go",
 | 
					        "scheme_test.go",
 | 
				
			||||||
        "visitor_test.go",
 | 
					        "visitor_test.go",
 | 
				
			||||||
@@ -81,7 +88,9 @@ go_test(
 | 
				
			|||||||
        "//staging/src/k8s.io/client-go/restmapper:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/restmapper:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/client-go/util/testing:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/util/testing:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/davecgh/go-spew/spew:go_default_library",
 | 
					        "//vendor/github.com/davecgh/go-spew/spew:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/stretchr/testify/assert:go_default_library",
 | 
					        "//vendor/github.com/stretchr/testify/assert:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/k8s.io/kube-openapi/pkg/util/proto/testing:go_default_library",
 | 
				
			||||||
        "//vendor/sigs.k8s.io/yaml:go_default_library",
 | 
					        "//vendor/sigs.k8s.io/yaml:go_default_library",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package util
 | 
					package resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@@ -14,14 +14,13 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package util_test
 | 
					package resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
	"k8s.io/kubectl/pkg/cmd/util"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCacheCRDFinder(t *testing.T) {
 | 
					func TestCacheCRDFinder(t *testing.T) {
 | 
				
			||||||
@@ -30,7 +29,7 @@ func TestCacheCRDFinder(t *testing.T) {
 | 
				
			|||||||
		called += 1
 | 
							called += 1
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	finder := util.NewCRDFinder(getter)
 | 
						finder := NewCRDFinder(getter)
 | 
				
			||||||
	if called != 0 {
 | 
						if called != 0 {
 | 
				
			||||||
		t.Fatalf("Creating the finder shouldn't call the getter, has called = %v", called)
 | 
							t.Fatalf("Creating the finder shouldn't call the getter, has called = %v", called)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -55,7 +54,7 @@ func TestCRDFinderErrors(t *testing.T) {
 | 
				
			|||||||
	getter := func() ([]schema.GroupKind, error) {
 | 
						getter := func() ([]schema.GroupKind, error) {
 | 
				
			||||||
		return nil, errors.New("not working")
 | 
							return nil, errors.New("not working")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	finder := util.NewCRDFinder(getter)
 | 
						finder := NewCRDFinder(getter)
 | 
				
			||||||
	found, err := finder.HasCRD(schema.GroupKind{Group: "", Kind: "Pod"})
 | 
						found, err := finder.HasCRD(schema.GroupKind{Group: "", Kind: "Pod"})
 | 
				
			||||||
	if found == true {
 | 
						if found == true {
 | 
				
			||||||
		t.Fatalf("Found the CRD with non-working getter function")
 | 
							t.Fatalf("Found the CRD with non-working getter function")
 | 
				
			||||||
@@ -78,7 +77,7 @@ func TestCRDFinder(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}, nil
 | 
							}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	finder := util.NewCRDFinder(getter)
 | 
						finder := NewCRDFinder(getter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if found, _ := finder.HasCRD(schema.GroupKind{Group: "crd.com", Kind: "MyCRD"}); !found {
 | 
						if found, _ := finder.HasCRD(schema.GroupKind{Group: "crd.com", Kind: "MyCRD"}); !found {
 | 
				
			||||||
		t.Fatalf("Failed to find CRD MyCRD")
 | 
							t.Fatalf("Failed to find CRD MyCRD")
 | 
				
			||||||
							
								
								
									
										121
									
								
								staging/src/k8s.io/cli-runtime/pkg/resource/dry_run_verifier.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								staging/src/k8s.io/cli-runtime/pkg/resource/dry_run_verifier.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2019 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
 | 
				
			||||||
 | 
						yaml "gopkg.in/yaml.v2"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
						"k8s.io/client-go/discovery"
 | 
				
			||||||
 | 
						"k8s.io/client-go/dynamic"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VerifyDryRun returns nil if a resource group-version-kind supports
 | 
				
			||||||
 | 
					// server-side dry-run. Otherwise, an error is returned.
 | 
				
			||||||
 | 
					func VerifyDryRun(gvk schema.GroupVersionKind, dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface) error {
 | 
				
			||||||
 | 
						verifier := NewDryRunVerifier(dynamicClient, discoveryClient)
 | 
				
			||||||
 | 
						return verifier.HasSupport(gvk)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewDryRunVerifier(dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface) *DryRunVerifier {
 | 
				
			||||||
 | 
						return &DryRunVerifier{
 | 
				
			||||||
 | 
							Finder:        NewCRDFinder(CRDFromDynamic(dynamicClient)),
 | 
				
			||||||
 | 
							OpenAPIGetter: discoveryClient,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func hasGVKExtension(extensions []*openapi_v2.NamedAny, gvk schema.GroupVersionKind) bool {
 | 
				
			||||||
 | 
						for _, extension := range extensions {
 | 
				
			||||||
 | 
							if extension.GetValue().GetYaml() == "" ||
 | 
				
			||||||
 | 
								extension.GetName() != "x-kubernetes-group-version-kind" {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var value map[string]string
 | 
				
			||||||
 | 
							err := yaml.Unmarshal([]byte(extension.GetValue().GetYaml()), &value)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if value["group"] == gvk.Group && value["kind"] == gvk.Kind && value["version"] == gvk.Version {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DryRunVerifier verifies if a given group-version-kind supports DryRun
 | 
				
			||||||
 | 
					// against the current server. Sending dryRun requests to apiserver that
 | 
				
			||||||
 | 
					// don't support it will result in objects being unwillingly persisted.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It reads the OpenAPI to see if the given GVK supports dryRun. If the
 | 
				
			||||||
 | 
					// GVK can not be found, we assume that CRDs will have the same level of
 | 
				
			||||||
 | 
					// support as "namespaces", and non-CRDs will not be supported. We
 | 
				
			||||||
 | 
					// delay the check for CRDs as much as possible though, since it
 | 
				
			||||||
 | 
					// requires an extra round-trip to the server.
 | 
				
			||||||
 | 
					type DryRunVerifier struct {
 | 
				
			||||||
 | 
						Finder        CRDFinder
 | 
				
			||||||
 | 
						OpenAPIGetter discovery.OpenAPISchemaInterface
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HasSupport verifies if the given gvk supports DryRun. An error is
 | 
				
			||||||
 | 
					// returned if it doesn't.
 | 
				
			||||||
 | 
					func (v *DryRunVerifier) HasSupport(gvk schema.GroupVersionKind) error {
 | 
				
			||||||
 | 
						oapi, err := v.OpenAPIGetter.OpenAPISchema()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("failed to download openapi: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						supports, err := SupportsDryRun(oapi, gvk)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// We assume that we couldn't find the type, then check for namespace:
 | 
				
			||||||
 | 
							supports, _ = SupportsDryRun(oapi, schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"})
 | 
				
			||||||
 | 
							// If namespace supports dryRun, then we will support dryRun for CRDs only.
 | 
				
			||||||
 | 
							if supports {
 | 
				
			||||||
 | 
								supports, err = v.Finder.HasCRD(gvk.GroupKind())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return fmt.Errorf("failed to check CRD: %v", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !supports {
 | 
				
			||||||
 | 
							return fmt.Errorf("%v doesn't support dry-run", gvk)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SupportsDryRun is a method that let's us look in the OpenAPI if the
 | 
				
			||||||
 | 
					// specific group-version-kind supports the dryRun query parameter for
 | 
				
			||||||
 | 
					// the PATCH end-point.
 | 
				
			||||||
 | 
					func SupportsDryRun(doc *openapi_v2.Document, gvk schema.GroupVersionKind) (bool, error) {
 | 
				
			||||||
 | 
						for _, path := range doc.GetPaths().GetPath() {
 | 
				
			||||||
 | 
							// Is this describing the gvk we're looking for?
 | 
				
			||||||
 | 
							if !hasGVKExtension(path.GetValue().GetPatch().GetVendorExtension(), gvk) {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, param := range path.GetValue().GetPatch().GetParameters() {
 | 
				
			||||||
 | 
								if param.GetParameter().GetNonBodyParameter().GetQueryParameterSubSchema().GetName() == "dryRun" {
 | 
				
			||||||
 | 
									return true, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false, errors.New("couldn't find GVK in openapi")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2019 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/runtime/schema"
 | 
				
			||||||
 | 
						openapitesting "k8s.io/kube-openapi/pkg/util/proto/testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSupportsDryRun(t *testing.T) {
 | 
				
			||||||
 | 
						doc, err := fakeSchema.OpenAPISchema()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Failed to get OpenAPI Schema: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							gvk      schema.GroupVersionKind
 | 
				
			||||||
 | 
							success  bool
 | 
				
			||||||
 | 
							supports bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								gvk: schema.GroupVersionKind{
 | 
				
			||||||
 | 
									Group:   "",
 | 
				
			||||||
 | 
									Version: "v1",
 | 
				
			||||||
 | 
									Kind:    "Pod",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								success:  true,
 | 
				
			||||||
 | 
								supports: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								gvk: schema.GroupVersionKind{
 | 
				
			||||||
 | 
									Group:   "",
 | 
				
			||||||
 | 
									Version: "v1",
 | 
				
			||||||
 | 
									Kind:    "UnknownKind",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								success:  false,
 | 
				
			||||||
 | 
								supports: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								gvk: schema.GroupVersionKind{
 | 
				
			||||||
 | 
									Group:   "",
 | 
				
			||||||
 | 
									Version: "v1",
 | 
				
			||||||
 | 
									Kind:    "NodeProxyOptions",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								success:  true,
 | 
				
			||||||
 | 
								supports: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							supports, err := SupportsDryRun(doc, test.gvk)
 | 
				
			||||||
 | 
							if supports != test.supports || ((err == nil) != test.success) {
 | 
				
			||||||
 | 
								errStr := "nil"
 | 
				
			||||||
 | 
								if test.success == false {
 | 
				
			||||||
 | 
									errStr = "err"
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								t.Errorf("SupportsDryRun(doc, %v) = (%v, %v), expected (%v, %v)",
 | 
				
			||||||
 | 
									test.gvk,
 | 
				
			||||||
 | 
									supports, err,
 | 
				
			||||||
 | 
									test.supports, errStr,
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var fakeSchema = openapitesting.Fake{Path: filepath.Join("..", "..", "artifacts", "openapi", "swagger.json")}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDryRunVerifier(t *testing.T) {
 | 
				
			||||||
 | 
						dryRunVerifier := DryRunVerifier{
 | 
				
			||||||
 | 
							Finder: NewCRDFinder(func() ([]schema.GroupKind, error) {
 | 
				
			||||||
 | 
								return []schema.GroupKind{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Group: "crd.com",
 | 
				
			||||||
 | 
										Kind:  "MyCRD",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Group: "crd.com",
 | 
				
			||||||
 | 
										Kind:  "MyNewCRD",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								}, nil
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							OpenAPIGetter: &fakeSchema,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "NodeProxyOptions"})
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("NodeProxyOptions doesn't support dry-run, yet no error found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("Pod should support dry-run: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "MyCRD"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("MyCRD should support dry-run: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "Random"})
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Random doesn't support dry-run, yet no error found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type EmptyOpenAPI struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (EmptyOpenAPI) OpenAPISchema() (*openapi_v2.Document, error) {
 | 
				
			||||||
 | 
						return &openapi_v2.Document{}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDryRunVerifierNoOpenAPI(t *testing.T) {
 | 
				
			||||||
 | 
						dryRunVerifier := DryRunVerifier{
 | 
				
			||||||
 | 
							Finder: NewCRDFinder(func() ([]schema.GroupKind, error) {
 | 
				
			||||||
 | 
								return []schema.GroupKind{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Group: "crd.com",
 | 
				
			||||||
 | 
										Kind:  "MyCRD",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Group: "crd.com",
 | 
				
			||||||
 | 
										Kind:  "MyNewCRD",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								}, nil
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
							OpenAPIGetter: EmptyOpenAPI{},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Pod doesn't support dry-run, yet no error found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "MyCRD"})
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("MyCRD doesn't support dry-run, yet no error found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -38,6 +38,13 @@ type Helper struct {
 | 
				
			|||||||
	RESTClient RESTClient
 | 
						RESTClient RESTClient
 | 
				
			||||||
	// True if the resource type is scoped to namespaces
 | 
						// True if the resource type is scoped to namespaces
 | 
				
			||||||
	NamespaceScoped bool
 | 
						NamespaceScoped bool
 | 
				
			||||||
 | 
						// If true, then use server-side dry-run to not persist changes to storage
 | 
				
			||||||
 | 
						// for verbs and resources that support server-side dry-run.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// Note this should only be used against an apiserver with dry-run enabled,
 | 
				
			||||||
 | 
						// and on resources that support dry-run. If the apiserver or the resource
 | 
				
			||||||
 | 
						// does not support dry-run, then the change will be persisted to storage.
 | 
				
			||||||
 | 
						ServerDryRun bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewHelper creates a Helper from a ResourceMapping
 | 
					// NewHelper creates a Helper from a ResourceMapping
 | 
				
			||||||
@@ -49,6 +56,13 @@ func NewHelper(client RESTClient, mapping *meta.RESTMapping) *Helper {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DryRun, if true, will use server-side dry-run to not persist changes to storage.
 | 
				
			||||||
 | 
					// Otherwise, changes will be persisted to storage.
 | 
				
			||||||
 | 
					func (m *Helper) DryRun(dryRun bool) *Helper {
 | 
				
			||||||
 | 
						m.ServerDryRun = dryRun
 | 
				
			||||||
 | 
						return m
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Helper) Get(namespace, name string, export bool) (runtime.Object, error) {
 | 
					func (m *Helper) Get(namespace, name string, export bool) (runtime.Object, error) {
 | 
				
			||||||
	req := m.RESTClient.Get().
 | 
						req := m.RESTClient.Get().
 | 
				
			||||||
		NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
							NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
				
			||||||
@@ -99,6 +113,13 @@ func (m *Helper) Delete(namespace, name string) (runtime.Object, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Helper) DeleteWithOptions(namespace, name string, options *metav1.DeleteOptions) (runtime.Object, error) {
 | 
					func (m *Helper) DeleteWithOptions(namespace, name string, options *metav1.DeleteOptions) (runtime.Object, error) {
 | 
				
			||||||
 | 
						if options == nil {
 | 
				
			||||||
 | 
							options = &metav1.DeleteOptions{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if m.ServerDryRun {
 | 
				
			||||||
 | 
							options.DryRun = []string{metav1.DryRunAll}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return m.RESTClient.Delete().
 | 
						return m.RESTClient.Delete().
 | 
				
			||||||
		NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
							NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
				
			||||||
		Resource(m.Resource).
 | 
							Resource(m.Resource).
 | 
				
			||||||
@@ -108,10 +129,17 @@ func (m *Helper) DeleteWithOptions(namespace, name string, options *metav1.Delet
 | 
				
			|||||||
		Get()
 | 
							Get()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Helper) Create(namespace string, modify bool, obj runtime.Object, options *metav1.CreateOptions) (runtime.Object, error) {
 | 
					func (m *Helper) Create(namespace string, modify bool, obj runtime.Object) (runtime.Object, error) {
 | 
				
			||||||
 | 
						return m.CreateWithOptions(namespace, modify, obj, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Helper) CreateWithOptions(namespace string, modify bool, obj runtime.Object, options *metav1.CreateOptions) (runtime.Object, error) {
 | 
				
			||||||
	if options == nil {
 | 
						if options == nil {
 | 
				
			||||||
		options = &metav1.CreateOptions{}
 | 
							options = &metav1.CreateOptions{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if m.ServerDryRun {
 | 
				
			||||||
 | 
							options.DryRun = []string{metav1.DryRunAll}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if modify {
 | 
						if modify {
 | 
				
			||||||
		// Attempt to version the object based on client logic.
 | 
							// Attempt to version the object based on client logic.
 | 
				
			||||||
		version, err := metadataAccessor.ResourceVersion(obj)
 | 
							version, err := metadataAccessor.ResourceVersion(obj)
 | 
				
			||||||
@@ -142,6 +170,9 @@ func (m *Helper) Patch(namespace, name string, pt types.PatchType, data []byte,
 | 
				
			|||||||
	if options == nil {
 | 
						if options == nil {
 | 
				
			||||||
		options = &metav1.PatchOptions{}
 | 
							options = &metav1.PatchOptions{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if m.ServerDryRun {
 | 
				
			||||||
 | 
							options.DryRun = []string{metav1.DryRunAll}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return m.RESTClient.Patch(pt).
 | 
						return m.RESTClient.Patch(pt).
 | 
				
			||||||
		NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
							NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
				
			||||||
		Resource(m.Resource).
 | 
							Resource(m.Resource).
 | 
				
			||||||
@@ -154,19 +185,23 @@ func (m *Helper) Patch(namespace, name string, pt types.PatchType, data []byte,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (m *Helper) Replace(namespace, name string, overwrite bool, obj runtime.Object) (runtime.Object, error) {
 | 
					func (m *Helper) Replace(namespace, name string, overwrite bool, obj runtime.Object) (runtime.Object, error) {
 | 
				
			||||||
	c := m.RESTClient
 | 
						c := m.RESTClient
 | 
				
			||||||
 | 
						var options = &metav1.UpdateOptions{}
 | 
				
			||||||
 | 
						if m.ServerDryRun {
 | 
				
			||||||
 | 
							options.DryRun = []string{metav1.DryRunAll}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Attempt to version the object based on client logic.
 | 
						// Attempt to version the object based on client logic.
 | 
				
			||||||
	version, err := metadataAccessor.ResourceVersion(obj)
 | 
						version, err := metadataAccessor.ResourceVersion(obj)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		// We don't know how to version this object, so send it to the server as is
 | 
							// We don't know how to version this object, so send it to the server as is
 | 
				
			||||||
		return m.replaceResource(c, m.Resource, namespace, name, obj)
 | 
							return m.replaceResource(c, m.Resource, namespace, name, obj, options)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if version == "" && overwrite {
 | 
						if version == "" && overwrite {
 | 
				
			||||||
		// Retrieve the current version of the object to overwrite the server object
 | 
							// Retrieve the current version of the object to overwrite the server object
 | 
				
			||||||
		serverObj, err := c.Get().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(m.Resource).Name(name).Do().Get()
 | 
							serverObj, err := c.Get().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(m.Resource).Name(name).Do().Get()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			// The object does not exist, but we want it to be created
 | 
								// The object does not exist, but we want it to be created
 | 
				
			||||||
			return m.replaceResource(c, m.Resource, namespace, name, obj)
 | 
								return m.replaceResource(c, m.Resource, namespace, name, obj, options)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		serverVersion, err := metadataAccessor.ResourceVersion(serverObj)
 | 
							serverVersion, err := metadataAccessor.ResourceVersion(serverObj)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -177,9 +212,16 @@ func (m *Helper) Replace(namespace, name string, overwrite bool, obj runtime.Obj
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return m.replaceResource(c, m.Resource, namespace, name, obj)
 | 
						return m.replaceResource(c, m.Resource, namespace, name, obj, options)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Helper) replaceResource(c RESTClient, resource, namespace, name string, obj runtime.Object) (runtime.Object, error) {
 | 
					func (m *Helper) replaceResource(c RESTClient, resource, namespace, name string, obj runtime.Object, options *metav1.UpdateOptions) (runtime.Object, error) {
 | 
				
			||||||
	return c.Put().NamespaceIfScoped(namespace, m.NamespaceScoped).Resource(resource).Name(name).Body(obj).Do().Get()
 | 
						return c.Put().
 | 
				
			||||||
 | 
							NamespaceIfScoped(namespace, m.NamespaceScoped).
 | 
				
			||||||
 | 
							Resource(resource).
 | 
				
			||||||
 | 
							Name(name).
 | 
				
			||||||
 | 
							VersionedParams(options, metav1.ParameterCodec).
 | 
				
			||||||
 | 
							Body(obj).
 | 
				
			||||||
 | 
							Do().
 | 
				
			||||||
 | 
							Get()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,7 +120,7 @@ func TestHelperDelete(t *testing.T) {
 | 
				
			|||||||
	for _, tt := range tests {
 | 
						for _, tt := range tests {
 | 
				
			||||||
		t.Run(tt.name, func(t *testing.T) {
 | 
							t.Run(tt.name, func(t *testing.T) {
 | 
				
			||||||
			client := &fake.RESTClient{
 | 
								client := &fake.RESTClient{
 | 
				
			||||||
				NegotiatedSerializer: scheme.Codecs,
 | 
									NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
 | 
				
			||||||
				Resp:                 tt.Resp,
 | 
									Resp:                 tt.Resp,
 | 
				
			||||||
				Err:                  tt.HttpErr,
 | 
									Err:                  tt.HttpErr,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -227,7 +227,7 @@ func TestHelperCreate(t *testing.T) {
 | 
				
			|||||||
				RESTClient:      client,
 | 
									RESTClient:      client,
 | 
				
			||||||
				NamespaceScoped: true,
 | 
									NamespaceScoped: true,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			_, err := modifier.Create("bar", tt.Modify, tt.Object, nil)
 | 
								_, err := modifier.Create("bar", tt.Modify, tt.Object)
 | 
				
			||||||
			if (err != nil) != tt.Err {
 | 
								if (err != nil) != tt.Err {
 | 
				
			||||||
				t.Errorf("%d: unexpected error: %t %v", i, tt.Err, err)
 | 
									t.Errorf("%d: unexpected error: %t %v", i, tt.Err, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -695,7 +695,7 @@ func RetrieveLazy(info *Info, err error) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CreateAndRefresh creates an object from input info and refreshes info with that object
 | 
					// CreateAndRefresh creates an object from input info and refreshes info with that object
 | 
				
			||||||
func CreateAndRefresh(info *Info) error {
 | 
					func CreateAndRefresh(info *Info) error {
 | 
				
			||||||
	obj, err := NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, nil)
 | 
						obj, err := NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,6 @@ go_test(
 | 
				
			|||||||
        "//staging/src/k8s.io/kubectl/pkg/cmd/util:go_default_library",
 | 
					        "//staging/src/k8s.io/kubectl/pkg/cmd/util:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/kubectl/pkg/scheme:go_default_library",
 | 
					        "//staging/src/k8s.io/kubectl/pkg/scheme:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/kubectl/pkg/util/openapi:go_default_library",
 | 
					        "//staging/src/k8s.io/kubectl/pkg/util/openapi:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
 | 
					 | 
				
			||||||
        "//vendor/github.com/spf13/cobra:go_default_library",
 | 
					        "//vendor/github.com/spf13/cobra:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/utils/pointer:go_default_library",
 | 
					        "//vendor/k8s.io/utils/pointer:go_default_library",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,6 @@ import (
 | 
				
			|||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
						"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/cli-runtime/pkg/genericclioptions"
 | 
						"k8s.io/cli-runtime/pkg/genericclioptions"
 | 
				
			||||||
@@ -207,10 +206,20 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Complete verifies if ApplyOptions are valid and without conflicts.
 | 
					// Complete verifies if ApplyOptions are valid and without conflicts.
 | 
				
			||||||
func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
 | 
					func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
	o.ServerSideApply = cmdutil.GetServerSideApplyFlag(cmd)
 | 
						o.ServerSideApply = cmdutil.GetServerSideApplyFlag(cmd)
 | 
				
			||||||
	o.ForceConflicts = cmdutil.GetForceConflictsFlag(cmd)
 | 
						o.ForceConflicts = cmdutil.GetForceConflictsFlag(cmd)
 | 
				
			||||||
	o.FieldManager = cmdutil.GetFieldManagerFlag(cmd)
 | 
						o.FieldManager = cmdutil.GetFieldManagerFlag(cmd)
 | 
				
			||||||
	o.DryRun = cmdutil.GetDryRunFlag(cmd)
 | 
						o.DryRun = cmdutil.GetDryRunFlag(cmd)
 | 
				
			||||||
 | 
						o.DynamicClient, err = f.DynamicClient()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						o.DiscoveryClient, err = f.ToDiscoveryClient()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if o.ForceConflicts && !o.ServerSideApply {
 | 
						if o.ForceConflicts && !o.ServerSideApply {
 | 
				
			||||||
		return fmt.Errorf("--force-conflicts only works with --server-side")
 | 
							return fmt.Errorf("--force-conflicts only works with --server-side")
 | 
				
			||||||
@@ -236,23 +245,13 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
 | 
				
			|||||||
		return o.PrintFlags.ToPrinter()
 | 
							return o.PrintFlags.ToPrinter()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
					 | 
				
			||||||
	o.RecordFlags.Complete(cmd)
 | 
						o.RecordFlags.Complete(cmd)
 | 
				
			||||||
	o.Recorder, err = o.RecordFlags.ToRecorder()
 | 
						o.Recorder, err = o.RecordFlags.ToRecorder()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.DiscoveryClient, err = f.ToDiscoveryClient()
 | 
						o.DeleteOptions = o.DeleteFlags.ToOptions(o.DynamicClient, o.IOStreams)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dynamicClient, err := f.DynamicClient()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	o.DeleteOptions = o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
 | 
					 | 
				
			||||||
	err = o.DeleteOptions.FilenameOptions.RequireFilenameOrKustomize()
 | 
						err = o.DeleteOptions.FilenameOptions.RequireFilenameOrKustomize()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -269,11 +268,6 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.DynamicClient, err = f.DynamicClient()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
 | 
						o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -360,11 +354,6 @@ func (o *ApplyOptions) SetObjects(infos []*resource.Info) {
 | 
				
			|||||||
// Run executes the `apply` command.
 | 
					// Run executes the `apply` command.
 | 
				
			||||||
func (o *ApplyOptions) Run() error {
 | 
					func (o *ApplyOptions) Run() error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dryRunVerifier := &DryRunVerifier{
 | 
					 | 
				
			||||||
		Finder:        cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(o.DynamicClient)),
 | 
					 | 
				
			||||||
		OpenAPIGetter: o.DiscoveryClient,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if o.PreProcessorFn != nil {
 | 
						if o.PreProcessorFn != nil {
 | 
				
			||||||
		klog.V(4).Infof("Running apply pre-processor function")
 | 
							klog.V(4).Infof("Running apply pre-processor function")
 | 
				
			||||||
		if err := o.PreProcessorFn(); err != nil {
 | 
							if err := o.PreProcessorFn(); err != nil {
 | 
				
			||||||
@@ -388,13 +377,6 @@ func (o *ApplyOptions) Run() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	for _, info := range infos {
 | 
						for _, info := range infos {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If server-dry-run is requested but the type doesn't support it, fail right away.
 | 
					 | 
				
			||||||
		if o.ServerDryRun {
 | 
					 | 
				
			||||||
			if err := dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		o.MarkNamespaceVisited(info)
 | 
							o.MarkNamespaceVisited(info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := o.Recorder.Record(info.Object); err != nil {
 | 
							if err := o.Recorder.Record(info.Object); err != nil {
 | 
				
			||||||
@@ -412,11 +394,15 @@ func (o *ApplyOptions) Run() error {
 | 
				
			|||||||
				Force:        &o.ForceConflicts,
 | 
									Force:        &o.ForceConflicts,
 | 
				
			||||||
				FieldManager: o.FieldManager,
 | 
									FieldManager: o.FieldManager,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if o.ServerDryRun {
 | 
					 | 
				
			||||||
				options.DryRun = []string{metav1.DryRunAll}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(
 | 
								helper := resource.NewHelper(info.Client, info.Mapping)
 | 
				
			||||||
 | 
								if o.ServerDryRun {
 | 
				
			||||||
 | 
									if err := resource.VerifyDryRun(info.Mapping.GroupVersionKind, o.DynamicClient, o.DiscoveryClient); err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									helper.DryRun(o.ServerDryRun)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								obj, err := helper.Patch(
 | 
				
			||||||
				info.Namespace,
 | 
									info.Namespace,
 | 
				
			||||||
				info.Name,
 | 
									info.Name,
 | 
				
			||||||
				types.ApplyPatchType,
 | 
									types.ApplyPatchType,
 | 
				
			||||||
@@ -486,11 +472,14 @@ See http://k8s.io/docs/reference/using-api/api-concepts/#conflicts`, err)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if !o.DryRun {
 | 
								if !o.DryRun {
 | 
				
			||||||
				// Then create the resource and skip the three-way merge
 | 
									// Then create the resource and skip the three-way merge
 | 
				
			||||||
				options := metav1.CreateOptions{}
 | 
									helper := resource.NewHelper(info.Client, info.Mapping)
 | 
				
			||||||
				if o.ServerDryRun {
 | 
									if o.ServerDryRun {
 | 
				
			||||||
					options.DryRun = []string{metav1.DryRunAll}
 | 
										if err := resource.VerifyDryRun(info.Mapping.GroupVersionKind, o.DynamicClient, o.DiscoveryClient); err != nil {
 | 
				
			||||||
 | 
											return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										helper.DryRun(o.ServerDryRun)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, &options)
 | 
									obj, err := helper.Create(info.Namespace, true, info.Object)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
										return cmdutil.AddSourceToErr("creating", info.Source, err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -526,7 +515,10 @@ See http://k8s.io/docs/reference/using-api/api-concepts/#conflicts`, err)
 | 
				
			|||||||
				fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
 | 
									fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			patcher := newPatcher(o, info)
 | 
								patcher, err := newPatcher(o, info)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			patchBytes, patchedObject, err := patcher.Patch(info.Object, modified, info.Source, info.Namespace, info.Name, o.ErrOut)
 | 
								patchBytes, patchedObject, err := patcher.Patch(info.Object, modified, info.Source, info.Namespace, info.Name, o.ErrOut)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
 | 
									return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
 | 
				
			||||||
@@ -663,42 +655,3 @@ func (o *ApplyOptions) PrintAndPrunePostProcessor() func() error {
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// DryRunVerifier verifies if a given group-version-kind supports DryRun
 | 
					 | 
				
			||||||
// against the current server. Sending dryRun requests to apiserver that
 | 
					 | 
				
			||||||
// don't support it will result in objects being unwillingly persisted.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// It reads the OpenAPI to see if the given GVK supports dryRun. If the
 | 
					 | 
				
			||||||
// GVK can not be found, we assume that CRDs will have the same level of
 | 
					 | 
				
			||||||
// support as "namespaces", and non-CRDs will not be supported. We
 | 
					 | 
				
			||||||
// delay the check for CRDs as much as possible though, since it
 | 
					 | 
				
			||||||
// requires an extra round-trip to the server.
 | 
					 | 
				
			||||||
type DryRunVerifier struct {
 | 
					 | 
				
			||||||
	Finder        cmdutil.CRDFinder
 | 
					 | 
				
			||||||
	OpenAPIGetter discovery.OpenAPISchemaInterface
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// HasSupport verifies if the given gvk supports DryRun. An error is
 | 
					 | 
				
			||||||
// returned if it doesn't.
 | 
					 | 
				
			||||||
func (v *DryRunVerifier) HasSupport(gvk schema.GroupVersionKind) error {
 | 
					 | 
				
			||||||
	oapi, err := v.OpenAPIGetter.OpenAPISchema()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("failed to download openapi: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	supports, err := openapi.SupportsDryRun(oapi, gvk)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		// We assume that we couldn't find the type, then check for namespace:
 | 
					 | 
				
			||||||
		supports, _ = openapi.SupportsDryRun(oapi, schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"})
 | 
					 | 
				
			||||||
		// If namespace supports dryRun, then we will support dryRun for CRDs only.
 | 
					 | 
				
			||||||
		if supports {
 | 
					 | 
				
			||||||
			supports, err = v.Finder.HasCRD(gvk.GroupKind())
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return fmt.Errorf("failed to check CRD: %v", err)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !supports {
 | 
					 | 
				
			||||||
		return fmt.Errorf("%v doesn't support dry-run", gvk)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,6 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/googleapis/gnostic/OpenAPIv2"
 | 
					 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	appsv1 "k8s.io/api/apps/v1"
 | 
						appsv1 "k8s.io/api/apps/v1"
 | 
				
			||||||
@@ -1389,75 +1388,3 @@ func TestForceApply(t *testing.T) {
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestDryRunVerifier(t *testing.T) {
 | 
					 | 
				
			||||||
	dryRunVerifier := DryRunVerifier{
 | 
					 | 
				
			||||||
		Finder: cmdutil.NewCRDFinder(func() ([]schema.GroupKind, error) {
 | 
					 | 
				
			||||||
			return []schema.GroupKind{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Group: "crd.com",
 | 
					 | 
				
			||||||
					Kind:  "MyCRD",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Group: "crd.com",
 | 
					 | 
				
			||||||
					Kind:  "MyNewCRD",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			}, nil
 | 
					 | 
				
			||||||
		}),
 | 
					 | 
				
			||||||
		OpenAPIGetter: &fakeSchema,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err := dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "NodeProxyOptions"})
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatalf("NodeProxyOptions doesn't support dry-run, yet no error found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Pod should support dry-run: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "MyCRD"})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("MyCRD should support dry-run: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "Random"})
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Random doesn't support dry-run, yet no error found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type EmptyOpenAPI struct{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (EmptyOpenAPI) OpenAPISchema() (*openapi_v2.Document, error) {
 | 
					 | 
				
			||||||
	return &openapi_v2.Document{}, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestDryRunVerifierNoOpenAPI(t *testing.T) {
 | 
					 | 
				
			||||||
	dryRunVerifier := DryRunVerifier{
 | 
					 | 
				
			||||||
		Finder: cmdutil.NewCRDFinder(func() ([]schema.GroupKind, error) {
 | 
					 | 
				
			||||||
			return []schema.GroupKind{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Group: "crd.com",
 | 
					 | 
				
			||||||
					Kind:  "MyCRD",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Group: "crd.com",
 | 
					 | 
				
			||||||
					Kind:  "MyNewCRD",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			}, nil
 | 
					 | 
				
			||||||
		}),
 | 
					 | 
				
			||||||
		OpenAPIGetter: EmptyOpenAPI{},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err := dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"})
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Pod doesn't support dry-run, yet no error found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = dryRunVerifier.HasSupport(schema.GroupVersionKind{Group: "crd.com", Version: "v1", Kind: "MyCRD"})
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatalf("MyCRD doesn't support dry-run, yet no error found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,6 @@ import (
 | 
				
			|||||||
	"github.com/jonboulle/clockwork"
 | 
						"github.com/jonboulle/clockwork"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						"k8s.io/apimachinery/pkg/api/meta"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
						"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
@@ -75,13 +74,19 @@ type Patcher struct {
 | 
				
			|||||||
	OpenapiSchema openapi.Resources
 | 
						OpenapiSchema openapi.Resources
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newPatcher(o *ApplyOptions, info *resource.Info) *Patcher {
 | 
					func newPatcher(o *ApplyOptions, info *resource.Info) (*Patcher, error) {
 | 
				
			||||||
	var openapiSchema openapi.Resources
 | 
						var openapiSchema openapi.Resources
 | 
				
			||||||
	if o.OpenAPIPatch {
 | 
						if o.OpenAPIPatch {
 | 
				
			||||||
		openapiSchema = o.OpenAPISchema
 | 
							openapiSchema = o.OpenAPISchema
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	helper := resource.NewHelper(info.Client, info.Mapping)
 | 
						helper := resource.NewHelper(info.Client, info.Mapping)
 | 
				
			||||||
 | 
						if o.ServerDryRun {
 | 
				
			||||||
 | 
							if err := resource.VerifyDryRun(info.Mapping.GroupVersionKind, o.DynamicClient, o.DiscoveryClient); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							helper.DryRun(o.ServerDryRun)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return &Patcher{
 | 
						return &Patcher{
 | 
				
			||||||
		Mapping:       info.Mapping,
 | 
							Mapping:       info.Mapping,
 | 
				
			||||||
		Helper:        helper,
 | 
							Helper:        helper,
 | 
				
			||||||
@@ -95,7 +100,7 @@ func newPatcher(o *ApplyOptions, info *resource.Info) *Patcher {
 | 
				
			|||||||
		ServerDryRun:  o.ServerDryRun,
 | 
							ServerDryRun:  o.ServerDryRun,
 | 
				
			||||||
		OpenapiSchema: openapiSchema,
 | 
							OpenapiSchema: openapiSchema,
 | 
				
			||||||
		Retries:       maxPatchRetry,
 | 
							Retries:       maxPatchRetry,
 | 
				
			||||||
	}
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *Patcher) delete(namespace, name string) error {
 | 
					func (p *Patcher) delete(namespace, name string) error {
 | 
				
			||||||
@@ -180,12 +185,7 @@ func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, source, names
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	options := metav1.PatchOptions{}
 | 
						patchedObj, err := p.Helper.Patch(namespace, name, patchType, patch, nil)
 | 
				
			||||||
	if p.ServerDryRun {
 | 
					 | 
				
			||||||
		options.DryRun = []string{metav1.DryRunAll}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	patchedObj, err := p.Helper.Patch(namespace, name, patchType, patch, &options)
 | 
					 | 
				
			||||||
	return patch, patchedObj, err
 | 
						return patch, patchedObj, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -230,15 +230,11 @@ func (p *Patcher) deleteAndCreate(original runtime.Object, modified []byte, name
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return modified, nil, err
 | 
							return modified, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	options := metav1.CreateOptions{}
 | 
						createdObject, err := p.Helper.Create(namespace, true, versionedObject)
 | 
				
			||||||
	if p.ServerDryRun {
 | 
					 | 
				
			||||||
		options.DryRun = []string{metav1.DryRunAll}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	createdObject, err := p.Helper.Create(namespace, true, versionedObject, &options)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		// restore the original object if we fail to create the new one
 | 
							// restore the original object if we fail to create the new one
 | 
				
			||||||
		// but still propagate and advertise error to user
 | 
							// but still propagate and advertise error to user
 | 
				
			||||||
		recreated, recreateErr := p.Helper.Create(namespace, true, original, &options)
 | 
							recreated, recreateErr := p.Helper.Create(namespace, true, original)
 | 
				
			||||||
		if recreateErr != nil {
 | 
							if recreateErr != nil {
 | 
				
			||||||
			err = fmt.Errorf("An error occurred force-replacing the existing object with the newly provided one:\n\n%v.\n\nAdditionally, an error occurred attempting to restore the original object:\n\n%v", err, recreateErr)
 | 
								err = fmt.Errorf("An error occurred force-replacing the existing object with the newly provided one:\n\n%v.\n\nAdditionally, an error occurred attempting to restore the original object:\n\n%v", err, recreateErr)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -299,7 +299,7 @@ func RunEditOnCreate(f cmdutil.Factory, printFlags *genericclioptions.PrintFlags
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// createAndRefresh creates an object from input info and refreshes info with that object
 | 
					// createAndRefresh creates an object from input info and refreshes info with that object
 | 
				
			||||||
func createAndRefresh(info *resource.Info) error {
 | 
					func createAndRefresh(info *resource.Info) error {
 | 
				
			||||||
	obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, nil)
 | 
						obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,7 +77,7 @@ type DiffOptions struct {
 | 
				
			|||||||
	OpenAPISchema    openapi.Resources
 | 
						OpenAPISchema    openapi.Resources
 | 
				
			||||||
	DiscoveryClient  discovery.DiscoveryInterface
 | 
						DiscoveryClient  discovery.DiscoveryInterface
 | 
				
			||||||
	DynamicClient    dynamic.Interface
 | 
						DynamicClient    dynamic.Interface
 | 
				
			||||||
	DryRunVerifier   *apply.DryRunVerifier
 | 
						DryRunVerifier   *resource.DryRunVerifier
 | 
				
			||||||
	CmdNamespace     string
 | 
						CmdNamespace     string
 | 
				
			||||||
	EnforceNamespace bool
 | 
						EnforceNamespace bool
 | 
				
			||||||
	Builder          *resource.Builder
 | 
						Builder          *resource.Builder
 | 
				
			||||||
@@ -295,7 +295,7 @@ func (obj InfoObject) Merged() (runtime.Object, error) {
 | 
				
			|||||||
	// Build the patcher, and then apply the patch with dry-run, unless the object doesn't exist, in which case we need to create it.
 | 
						// Build the patcher, and then apply the patch with dry-run, unless the object doesn't exist, in which case we need to create it.
 | 
				
			||||||
	if obj.Live() == nil {
 | 
						if obj.Live() == nil {
 | 
				
			||||||
		// Dry-run create if the object doesn't exist.
 | 
							// Dry-run create if the object doesn't exist.
 | 
				
			||||||
		return resource.NewHelper(obj.Info.Client, obj.Info.Mapping).Create(
 | 
							return resource.NewHelper(obj.Info.Client, obj.Info.Mapping).CreateWithOptions(
 | 
				
			||||||
			obj.Info.Namespace,
 | 
								obj.Info.Namespace,
 | 
				
			||||||
			true,
 | 
								true,
 | 
				
			||||||
			obj.LocalObj,
 | 
								obj.LocalObj,
 | 
				
			||||||
@@ -427,10 +427,7 @@ func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.DryRunVerifier = &apply.DryRunVerifier{
 | 
						o.DryRunVerifier = resource.NewDryRunVerifier(o.DynamicClient, o.DiscoveryClient)
 | 
				
			||||||
		Finder:        cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(o.DynamicClient)),
 | 
					 | 
				
			||||||
		OpenAPIGetter: o.DiscoveryClient,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	o.CmdNamespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
 | 
						o.CmdNamespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -355,7 +355,7 @@ func (o *ReplaceOptions) forceReplace() error {
 | 
				
			|||||||
			klog.V(4).Infof("error recording current command: %v", err)
 | 
								klog.V(4).Infof("error recording current command: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, nil)
 | 
							obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -708,7 +708,7 @@ func (o *RunOptions) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		actualObj, err = resource.NewHelper(client, mapping).Create(namespace, false, obj, nil)
 | 
							actualObj, err = resource.NewHelper(client, mapping).Create(namespace, false, obj)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 | 
				
			|||||||
go_library(
 | 
					go_library(
 | 
				
			||||||
    name = "go_default_library",
 | 
					    name = "go_default_library",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        "crdfinder.go",
 | 
					 | 
				
			||||||
        "factory.go",
 | 
					        "factory.go",
 | 
				
			||||||
        "factory_client_access.go",
 | 
					        "factory_client_access.go",
 | 
				
			||||||
        "helpers.go",
 | 
					        "helpers.go",
 | 
				
			||||||
@@ -18,7 +17,6 @@ go_library(
 | 
				
			|||||||
        "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
 | 
					 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
 | 
				
			||||||
        "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
 | 
					        "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
 | 
				
			||||||
@@ -48,10 +46,7 @@ go_library(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
go_test(
 | 
					go_test(
 | 
				
			||||||
    name = "go_default_test",
 | 
					    name = "go_default_test",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = ["helpers_test.go"],
 | 
				
			||||||
        "crdfinder_test.go",
 | 
					 | 
				
			||||||
        "helpers_test.go",
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    embed = [":go_default_library"],
 | 
					    embed = [":go_default_library"],
 | 
				
			||||||
    deps = [
 | 
					    deps = [
 | 
				
			||||||
        "//staging/src/k8s.io/api/core/v1:go_default_library",
 | 
					        "//staging/src/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ go_library(
 | 
				
			|||||||
    name = "go_default_library",
 | 
					    name = "go_default_library",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        "doc.go",
 | 
					        "doc.go",
 | 
				
			||||||
        "dryrun.go",
 | 
					 | 
				
			||||||
        "extensions.go",
 | 
					        "extensions.go",
 | 
				
			||||||
        "openapi.go",
 | 
					        "openapi.go",
 | 
				
			||||||
        "openapi_getter.go",
 | 
					        "openapi_getter.go",
 | 
				
			||||||
@@ -17,7 +16,6 @@ go_library(
 | 
				
			|||||||
        "//staging/src/k8s.io/client-go/discovery:go_default_library",
 | 
					        "//staging/src/k8s.io/client-go/discovery:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/go-openapi/spec:go_default_library",
 | 
					        "//vendor/github.com/go-openapi/spec:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
 | 
					        "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
 | 
				
			||||||
        "//vendor/gopkg.in/yaml.v2:go_default_library",
 | 
					 | 
				
			||||||
        "//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
 | 
					        "//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -25,7 +23,6 @@ go_library(
 | 
				
			|||||||
go_test(
 | 
					go_test(
 | 
				
			||||||
    name = "go_default_test",
 | 
					    name = "go_default_test",
 | 
				
			||||||
    srcs = [
 | 
					    srcs = [
 | 
				
			||||||
        "dryrun_test.go",
 | 
					 | 
				
			||||||
        "openapi_getter_test.go",
 | 
					        "openapi_getter_test.go",
 | 
				
			||||||
        "openapi_suite_test.go",
 | 
					        "openapi_suite_test.go",
 | 
				
			||||||
        "openapi_test.go",
 | 
					        "openapi_test.go",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,65 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
Copyright 2017 The Kubernetes Authors.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 openapi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
 | 
					 | 
				
			||||||
	yaml "gopkg.in/yaml.v2"
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func hasGVKExtension(extensions []*openapi_v2.NamedAny, gvk schema.GroupVersionKind) bool {
 | 
					 | 
				
			||||||
	for _, extension := range extensions {
 | 
					 | 
				
			||||||
		if extension.GetValue().GetYaml() == "" ||
 | 
					 | 
				
			||||||
			extension.GetName() != "x-kubernetes-group-version-kind" {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var value map[string]string
 | 
					 | 
				
			||||||
		err := yaml.Unmarshal([]byte(extension.GetValue().GetYaml()), &value)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if value["group"] == gvk.Group && value["kind"] == gvk.Kind && value["version"] == gvk.Version {
 | 
					 | 
				
			||||||
			return true
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// SupportsDryRun is a method that let's us look in the OpenAPI if the
 | 
					 | 
				
			||||||
// specific group-version-kind supports the dryRun query parameter for
 | 
					 | 
				
			||||||
// the PATCH end-point.
 | 
					 | 
				
			||||||
func SupportsDryRun(doc *openapi_v2.Document, gvk schema.GroupVersionKind) (bool, error) {
 | 
					 | 
				
			||||||
	for _, path := range doc.GetPaths().GetPath() {
 | 
					 | 
				
			||||||
		// Is this describing the gvk we're looking for?
 | 
					 | 
				
			||||||
		if !hasGVKExtension(path.GetValue().GetPatch().GetVendorExtension(), gvk) {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		for _, param := range path.GetValue().GetPatch().GetParameters() {
 | 
					 | 
				
			||||||
			if param.GetParameter().GetNonBodyParameter().GetQueryParameterSubSchema().GetName() == "dryRun" {
 | 
					 | 
				
			||||||
				return true, nil
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return false, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return false, errors.New("couldn't find GVK in openapi")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,80 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
Copyright 2018 The Kubernetes Authors.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 openapi_test
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime/schema"
 | 
					 | 
				
			||||||
	"k8s.io/kubectl/pkg/util/openapi"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestSupportsDryRun(t *testing.T) {
 | 
					 | 
				
			||||||
	doc, err := fakeSchema.OpenAPISchema()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Failed to get OpenAPI Schema: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
					 | 
				
			||||||
		gvk      schema.GroupVersionKind
 | 
					 | 
				
			||||||
		success  bool
 | 
					 | 
				
			||||||
		supports bool
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			gvk: schema.GroupVersionKind{
 | 
					 | 
				
			||||||
				Group:   "",
 | 
					 | 
				
			||||||
				Version: "v1",
 | 
					 | 
				
			||||||
				Kind:    "Pod",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			success:  true,
 | 
					 | 
				
			||||||
			supports: true,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			gvk: schema.GroupVersionKind{
 | 
					 | 
				
			||||||
				Group:   "",
 | 
					 | 
				
			||||||
				Version: "v1",
 | 
					 | 
				
			||||||
				Kind:    "UnknownKind",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			success:  false,
 | 
					 | 
				
			||||||
			supports: false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			gvk: schema.GroupVersionKind{
 | 
					 | 
				
			||||||
				Group:   "",
 | 
					 | 
				
			||||||
				Version: "v1",
 | 
					 | 
				
			||||||
				Kind:    "NodeProxyOptions",
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			success:  true,
 | 
					 | 
				
			||||||
			supports: false,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, test := range tests {
 | 
					 | 
				
			||||||
		supports, err := openapi.SupportsDryRun(doc, test.gvk)
 | 
					 | 
				
			||||||
		if supports != test.supports || ((err == nil) != test.success) {
 | 
					 | 
				
			||||||
			errStr := "nil"
 | 
					 | 
				
			||||||
			if test.success == false {
 | 
					 | 
				
			||||||
				errStr = "err"
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			t.Errorf("SupportsDryRun(doc, %v) = (%v, %v), expected (%v, %v)",
 | 
					 | 
				
			||||||
				test.gvk,
 | 
					 | 
				
			||||||
				supports, err,
 | 
					 | 
				
			||||||
				test.supports, errStr,
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user