API Machinery, Kubectl and tests
This commit is contained in:
@@ -30,8 +30,11 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/apply"
|
||||
@@ -67,21 +70,38 @@ const maxRetries = 4
|
||||
|
||||
type DiffOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
|
||||
ServerSideApply bool
|
||||
ForceConflicts bool
|
||||
|
||||
OpenAPISchema openapi.Resources
|
||||
DiscoveryClient discovery.DiscoveryInterface
|
||||
DynamicClient dynamic.Interface
|
||||
DryRunVerifier *apply.DryRunVerifier
|
||||
CmdNamespace string
|
||||
EnforceNamespace bool
|
||||
Builder *resource.Builder
|
||||
Diff *DiffProgram
|
||||
}
|
||||
|
||||
func checkDiffArgs(cmd *cobra.Command, args []string) error {
|
||||
func validateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
var options DiffOptions
|
||||
diff := DiffProgram{
|
||||
Exec: exec.New(),
|
||||
IOStreams: streams,
|
||||
func NewDiffOptions(ioStreams genericclioptions.IOStreams) *DiffOptions {
|
||||
return &DiffOptions{
|
||||
Diff: &DiffProgram{
|
||||
Exec: exec.New(),
|
||||
IOStreams: ioStreams,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewDiffOptions(streams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "diff -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
@@ -89,13 +109,15 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
|
||||
Long: diffLong,
|
||||
Example: diffExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(checkDiffArgs(cmd, args))
|
||||
cmdutil.CheckErr(RunDiff(f, &diff, &options))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckErr(validateArgs(cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
},
|
||||
}
|
||||
|
||||
usage := "contains the configuration to diff"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddServerSideApplyFlags(cmd)
|
||||
cmd.MarkFlagRequired("filename")
|
||||
|
||||
return cmd
|
||||
@@ -229,11 +251,13 @@ type Object interface {
|
||||
// InfoObject is an implementation of the Object interface. It gets all
|
||||
// the information from the Info object.
|
||||
type InfoObject struct {
|
||||
LocalObj runtime.Object
|
||||
Info *resource.Info
|
||||
Encoder runtime.Encoder
|
||||
OpenAPI openapi.Resources
|
||||
Force bool
|
||||
LocalObj runtime.Object
|
||||
Info *resource.Info
|
||||
Encoder runtime.Encoder
|
||||
OpenAPI openapi.Resources
|
||||
Force bool
|
||||
ServerSideApply bool
|
||||
ForceConflicts bool
|
||||
}
|
||||
|
||||
var _ Object = &InfoObject{}
|
||||
@@ -246,6 +270,24 @@ func (obj InfoObject) Live() runtime.Object {
|
||||
// Returns the "merged" object, as it would look like if applied or
|
||||
// created.
|
||||
func (obj InfoObject) Merged() (runtime.Object, error) {
|
||||
if obj.ServerSideApply {
|
||||
data, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj.LocalObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := metav1.PatchOptions{
|
||||
Force: &obj.ForceConflicts,
|
||||
DryRun: []string{metav1.DryRunAll},
|
||||
}
|
||||
return resource.NewHelper(obj.Info.Client, obj.Info.Mapping).Patch(
|
||||
obj.Info.Namespace,
|
||||
obj.Info.Name,
|
||||
types.ApplyPatchType,
|
||||
data,
|
||||
&options,
|
||||
)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// Dry-run create if the object doesn't exist.
|
||||
@@ -350,30 +392,50 @@ func isConflict(err error) bool {
|
||||
return err != nil && errors.IsConflict(err)
|
||||
}
|
||||
|
||||
func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
var err error
|
||||
|
||||
o.ServerSideApply = cmdutil.GetServerSideApplyFlag(cmd)
|
||||
o.ForceConflicts = cmdutil.GetForceConflictsFlag(cmd)
|
||||
if o.ForceConflicts && !o.ServerSideApply {
|
||||
return fmt.Errorf("--force-conflicts only works with --server-side")
|
||||
}
|
||||
|
||||
if !o.ServerSideApply {
|
||||
o.OpenAPISchema, err = f.OpenAPISchema()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
o.DiscoveryClient, err = f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DryRunVerifier = &apply.DryRunVerifier{
|
||||
Finder: cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(o.DynamicClient)),
|
||||
OpenAPIGetter: o.DiscoveryClient,
|
||||
}
|
||||
|
||||
o.CmdNamespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Builder = f.NewBuilder()
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunDiff uses the factory to parse file arguments, find the version to
|
||||
// diff, and find each Info object for each files, and runs against the
|
||||
// differ.
|
||||
func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
|
||||
schema, err := f.OpenAPISchema()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
discovery, err := f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dynamic, err := f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dryRunVerifier := &apply.DryRunVerifier{
|
||||
Finder: cmdutil.NewCRDFinder(cmdutil.CRDFromDynamic(dynamic)),
|
||||
OpenAPIGetter: discovery,
|
||||
}
|
||||
|
||||
func (o *DiffOptions) Run() error {
|
||||
differ, err := NewDiffer("LIVE", "MERGED")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -382,15 +444,10 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
|
||||
|
||||
printer := Printer{}
|
||||
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
r := o.Builder.
|
||||
Unstructured().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
NamespaceParam(o.CmdNamespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
@@ -402,7 +459,7 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
|
||||
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -424,11 +481,13 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
|
||||
)
|
||||
}
|
||||
obj := InfoObject{
|
||||
LocalObj: local,
|
||||
Info: info,
|
||||
Encoder: scheme.DefaultJSONEncoder(),
|
||||
OpenAPI: schema,
|
||||
Force: force,
|
||||
LocalObj: local,
|
||||
Info: info,
|
||||
Encoder: scheme.DefaultJSONEncoder(),
|
||||
OpenAPI: o.OpenAPISchema,
|
||||
Force: force,
|
||||
ServerSideApply: o.ServerSideApply,
|
||||
ForceConflicts: o.ForceConflicts,
|
||||
}
|
||||
|
||||
err = differ.Diff(obj, printer)
|
||||
@@ -442,5 +501,5 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return differ.Run(diff)
|
||||
return differ.Run(o.Diff)
|
||||
}
|
||||
|
Reference in New Issue
Block a user