Merge pull request #69745 from apelisse/check-dryrun-on-create

kubectl dry-run: Check for server didn't work on create
This commit is contained in:
k8s-ci-robot 2018-10-12 22:31:28 -07:00 committed by GitHub
commit d84c43120e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 46 deletions

View File

@ -25,7 +25,6 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/jonboulle/clockwork" "github.com/jonboulle/clockwork"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
@ -300,6 +299,11 @@ func (o *ApplyOptions) Run() error {
openapiSchema = o.OpenAPISchema openapiSchema = o.OpenAPISchema
} }
dryRunVerifier := &DryRunVerifier{
Finder: cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(o.DynamicClient)),
OpenAPIGetter: o.DiscoveryClient,
}
// include the uninitialized objects by default if --prune is true // include the uninitialized objects by default if --prune is true
// unless explicitly set --include-uninitialized=false // unless explicitly set --include-uninitialized=false
r := o.Builder. r := o.Builder.
@ -361,6 +365,13 @@ func (o *ApplyOptions) Run() error {
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err) return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
} }
// 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
}
}
// Create the resource if it doesn't exist // Create the resource if it doesn't exist
// First, update the annotation used by kubectl apply // First, update the annotation used by kubectl apply
if err := kubectl.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil { if err := kubectl.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil {
@ -410,25 +421,19 @@ func (o *ApplyOptions) Run() error {
fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName) fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
} }
dryRunVerifier := &DryRunVerifier{
Finder: cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(o.DynamicClient)),
OpenAPIGetter: o.DiscoveryClient,
}
helper := resource.NewHelper(info.Client, info.Mapping) helper := resource.NewHelper(info.Client, info.Mapping)
patcher := &Patcher{ patcher := &Patcher{
Mapping: info.Mapping, Mapping: info.Mapping,
Helper: helper, Helper: helper,
DynamicClient: o.DynamicClient, DynamicClient: o.DynamicClient,
DryRunVerifier: dryRunVerifier, Overwrite: o.Overwrite,
Overwrite: o.Overwrite, BackOff: clockwork.NewRealClock(),
BackOff: clockwork.NewRealClock(), Force: o.DeleteOptions.ForceDeletion,
Force: o.DeleteOptions.ForceDeletion, Cascade: o.DeleteOptions.Cascade,
Cascade: o.DeleteOptions.Cascade, Timeout: o.DeleteOptions.Timeout,
Timeout: o.DeleteOptions.Timeout, GracePeriod: o.DeleteOptions.GracePeriod,
GracePeriod: o.DeleteOptions.GracePeriod, ServerDryRun: o.ServerDryRun,
ServerDryRun: o.ServerDryRun, OpenapiSchema: openapiSchema,
OpenapiSchema: openapiSchema,
} }
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)
@ -681,10 +686,9 @@ func (p *Patcher) delete(namespace, name string) error {
} }
type Patcher struct { type Patcher struct {
Mapping *meta.RESTMapping Mapping *meta.RESTMapping
Helper *resource.Helper Helper *resource.Helper
DynamicClient dynamic.Interface DynamicClient dynamic.Interface
DryRunVerifier *DryRunVerifier
Overwrite bool Overwrite bool
BackOff clockwork.Clock BackOff clockwork.Clock
@ -738,12 +742,6 @@ func (v *DryRunVerifier) HasSupport(gvk schema.GroupVersionKind) error {
} }
func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) { func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
if p.ServerDryRun {
if err := p.DryRunVerifier.HasSupport(p.Mapping.GroupVersionKind); err != nil {
return nil, nil, err
}
}
// Serialize the current configuration of the object from the server. // Serialize the current configuration of the object from the server.
current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
if err != nil { if err != nil {

View File

@ -26,7 +26,6 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/jonboulle/clockwork" "github.com/jonboulle/clockwork"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
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"
@ -226,11 +225,10 @@ type Object interface {
// InfoObject is an implementation of the Object interface. It gets all // InfoObject is an implementation of the Object interface. It gets all
// the information from the Info object. // the information from the Info object.
type InfoObject struct { type InfoObject struct {
LocalObj runtime.Object LocalObj runtime.Object
Info *resource.Info Info *resource.Info
Encoder runtime.Encoder Encoder runtime.Encoder
OpenAPI openapi.Resources OpenAPI openapi.Resources
DryRunVerifier *apply.DryRunVerifier
} }
var _ Object = &InfoObject{} var _ Object = &InfoObject{}
@ -262,13 +260,12 @@ func (obj InfoObject) Merged() (runtime.Object, error) {
// This is using the patcher from apply, to keep the same behavior. // This is using the patcher from apply, to keep the same behavior.
// We plan on replacing this with server-side apply when it becomes available. // We plan on replacing this with server-side apply when it becomes available.
patcher := &apply.Patcher{ patcher := &apply.Patcher{
DryRunVerifier: obj.DryRunVerifier, Mapping: obj.Info.Mapping,
Mapping: obj.Info.Mapping, Helper: resource.NewHelper(obj.Info.Client, obj.Info.Mapping),
Helper: resource.NewHelper(obj.Info.Client, obj.Info.Mapping), Overwrite: true,
Overwrite: true, BackOff: clockwork.NewRealClock(),
BackOff: clockwork.NewRealClock(), ServerDryRun: true,
ServerDryRun: true, OpenapiSchema: obj.OpenAPI,
OpenapiSchema: obj.OpenAPI,
} }
_, result, err := patcher.Patch(obj.Info.Object, modified, obj.Info.Source, obj.Info.Namespace, obj.Info.Name, nil) _, result, err := patcher.Patch(obj.Info.Object, modified, obj.Info.Source, obj.Info.Namespace, obj.Info.Name, nil)
@ -375,6 +372,10 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
return err return err
} }
if err := dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
local := info.Object.DeepCopyObject() local := info.Object.DeepCopyObject()
if err := info.Get(); err != nil { if err := info.Get(); err != nil {
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
@ -384,11 +385,10 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
} }
obj := InfoObject{ obj := InfoObject{
LocalObj: local, LocalObj: local,
Info: info, Info: info,
Encoder: scheme.DefaultJSONEncoder(), Encoder: scheme.DefaultJSONEncoder(),
OpenAPI: schema, OpenAPI: schema,
DryRunVerifier: dryRunVerifier,
} }
return differ.Diff(obj, printer) return differ.Diff(obj, printer)