mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 10:53:34 +00:00
Fresh dep ensure
This commit is contained in:
93
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/BUILD
generated
vendored
Normal file
93
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/BUILD
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"apply.go",
|
||||
"apply_edit_last_applied.go",
|
||||
"apply_set_last_applied.go",
|
||||
"apply_view_last_applied.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/apply",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/delete:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/editor:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/kubectl/util/i18n:go_default_library",
|
||||
"//pkg/kubectl/util/templates:go_default_library",
|
||||
"//pkg/kubectl/validation:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1: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/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/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/jsonmergepatch:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/mergepatch:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
|
||||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/printers:go_default_library",
|
||||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/discovery:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/github.com/jonboulle/clockwork:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/util/proto:go_default_library",
|
||||
"//vendor/sigs.k8s.io/yaml:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["apply_test.go"],
|
||||
data = [
|
||||
"//api/openapi-spec:swagger-spec",
|
||||
"//test/fixtures",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/extensions/v1beta1: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/apis/meta/v1/unstructured: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/util/strategicpatch/testing:go_default_library",
|
||||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library",
|
||||
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions/resource:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/dynamic/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
910
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply.go
generated
vendored
Normal file
910
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply.go
generated
vendored
Normal file
@ -0,0 +1,910 @@
|
||||
/*
|
||||
Copyright 2014 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 apply
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"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/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/jsonmergepatch"
|
||||
"k8s.io/apimachinery/pkg/util/mergepatch"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/klog"
|
||||
oapi "k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/delete"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/templates"
|
||||
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||
)
|
||||
|
||||
type ApplyOptions struct {
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
ToPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
DeleteFlags *delete.DeleteFlags
|
||||
DeleteOptions *delete.DeleteOptions
|
||||
|
||||
Selector string
|
||||
DryRun bool
|
||||
ServerDryRun bool
|
||||
Prune bool
|
||||
PruneResources []pruneResource
|
||||
cmdBaseName string
|
||||
All bool
|
||||
Overwrite bool
|
||||
OpenApiPatch bool
|
||||
PruneWhitelist []string
|
||||
ShouldIncludeUninitialized bool
|
||||
|
||||
Validator validation.Schema
|
||||
Builder *resource.Builder
|
||||
Mapper meta.RESTMapper
|
||||
DynamicClient dynamic.Interface
|
||||
DiscoveryClient discovery.DiscoveryInterface
|
||||
OpenAPISchema openapi.Resources
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
const (
|
||||
// maxPatchRetry is the maximum number of conflicts retry for during a patch operation before returning failure
|
||||
maxPatchRetry = 5
|
||||
// backOffPeriod is the period to back off when apply patch resutls in error.
|
||||
backOffPeriod = 1 * time.Second
|
||||
// how many times we can retry before back off
|
||||
triesBeforeBackOff = 1
|
||||
)
|
||||
|
||||
var (
|
||||
applyLong = templates.LongDesc(i18n.T(`
|
||||
Apply a configuration to a resource by filename or stdin.
|
||||
The resource name must be specified. This resource will be created if it doesn't exist yet.
|
||||
To use 'apply', always create the resource initially with either 'apply' or 'create --save-config'.
|
||||
|
||||
JSON and YAML formats are accepted.
|
||||
|
||||
Alpha Disclaimer: the --prune functionality is not yet complete. Do not use unless you are aware of what the current state is. See https://issues.k8s.io/34274.`))
|
||||
|
||||
applyExample = templates.Examples(i18n.T(`
|
||||
# Apply the configuration in pod.json to a pod.
|
||||
kubectl apply -f ./pod.json
|
||||
|
||||
# Apply the JSON passed into stdin to a pod.
|
||||
cat pod.json | kubectl apply -f -
|
||||
|
||||
# Note: --prune is still in Alpha
|
||||
# Apply the configuration in manifest.yaml that matches label app=nginx and delete all the other resources that are not in the file and match label app=nginx.
|
||||
kubectl apply --prune -f manifest.yaml -l app=nginx
|
||||
|
||||
# Apply the configuration in manifest.yaml and delete all the other configmaps that are not in the file.
|
||||
kubectl apply --prune -f manifest.yaml --all --prune-whitelist=core/v1/ConfigMap`))
|
||||
|
||||
warningNoLastAppliedConfigAnnotation = "Warning: %[1]s apply should be used on resource created by either %[1]s create --save-config or %[1]s apply\n"
|
||||
)
|
||||
|
||||
func NewApplyOptions(ioStreams genericclioptions.IOStreams) *ApplyOptions {
|
||||
return &ApplyOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
DeleteFlags: delete.NewDeleteFlags("that contains the configuration to apply"),
|
||||
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
|
||||
|
||||
Overwrite: true,
|
||||
OpenApiPatch: true,
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewApplyOptions(ioStreams)
|
||||
|
||||
// Store baseName for use in printing warnings / messages involving the base command name.
|
||||
// This is useful for downstream command that wrap this one.
|
||||
o.cmdBaseName = baseName
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "apply -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Apply a configuration to a resource by filename or stdin"),
|
||||
Long: applyLong,
|
||||
Example: applyExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(validateArgs(cmd, args))
|
||||
cmdutil.CheckErr(validatePruneAll(o.Prune, o.All, o.Selector))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
|
||||
// bind flag structs
|
||||
o.DeleteFlags.AddFlags(cmd)
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
|
||||
cmd.Flags().BoolVar(&o.Prune, "prune", o.Prune, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources in the namespace of the specified resource types.")
|
||||
cmd.Flags().StringArrayVar(&o.PruneWhitelist, "prune-whitelist", o.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune")
|
||||
cmd.Flags().BoolVar(&o.OpenApiPatch, "openapi-patch", o.OpenApiPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
|
||||
cmd.Flags().BoolVar(&o.ServerDryRun, "server-dry-run", o.ServerDryRun, "If true, request will be sent to server with dry-run flag, which means the modifications won't be persisted. This is an alpha feature and flag.")
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
// apply subcommands
|
||||
cmd.AddCommand(NewCmdApplyViewLastApplied(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdApplySetLastApplied(f, ioStreams))
|
||||
cmd.AddCommand(NewCmdApplyEditLastApplied(f, ioStreams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if o.DryRun && o.ServerDryRun {
|
||||
return fmt.Errorf("--dry-run and --server-dry-run can't be used together")
|
||||
}
|
||||
|
||||
// allow for a success message operation to be specified at print time
|
||||
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
|
||||
o.PrintFlags.NamePrintFlags.Operation = operation
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
if o.ServerDryRun {
|
||||
o.PrintFlags.Complete("%s (server dry run)")
|
||||
}
|
||||
return o.PrintFlags.ToPrinter()
|
||||
}
|
||||
|
||||
var err error
|
||||
o.RecordFlags.Complete(cmd)
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DiscoveryClient, err = f.ToDiscoveryClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dynamicClient, err := f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.DeleteOptions = o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
|
||||
o.ShouldIncludeUninitialized = cmdutil.ShouldIncludeUninitialized(cmd, o.Prune)
|
||||
|
||||
o.OpenAPISchema, _ = f.OpenAPISchema()
|
||||
o.Validator, err = f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
o.Builder = f.NewBuilder()
|
||||
o.Mapper, err = f.ToRESTMapper()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DynamicClient, err = f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateArgs(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 0 {
|
||||
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePruneAll(prune, all bool, selector string) error {
|
||||
if all && len(selector) > 0 {
|
||||
return fmt.Errorf("cannot set --all and --selector at the same time")
|
||||
}
|
||||
if prune && !all && selector == "" {
|
||||
return fmt.Errorf("all resources selected for prune without explicitly passing --all. To prune all resources, pass the --all flag. If you did not mean to prune all resources, specify a label selector.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parsePruneResources(mapper meta.RESTMapper, gvks []string) ([]pruneResource, error) {
|
||||
pruneResources := []pruneResource{}
|
||||
for _, groupVersionKind := range gvks {
|
||||
gvk := strings.Split(groupVersionKind, "/")
|
||||
if len(gvk) != 3 {
|
||||
return nil, fmt.Errorf("invalid GroupVersionKind format: %v, please follow <group/version/kind>", groupVersionKind)
|
||||
}
|
||||
|
||||
if gvk[0] == "core" {
|
||||
gvk[0] = ""
|
||||
}
|
||||
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk[0], Kind: gvk[2]}, gvk[1])
|
||||
if err != nil {
|
||||
return pruneResources, err
|
||||
}
|
||||
var namespaced bool
|
||||
namespaceScope := mapping.Scope.Name()
|
||||
switch namespaceScope {
|
||||
case meta.RESTScopeNameNamespace:
|
||||
namespaced = true
|
||||
case meta.RESTScopeNameRoot:
|
||||
namespaced = false
|
||||
default:
|
||||
return pruneResources, fmt.Errorf("Unknown namespace scope: %q", namespaceScope)
|
||||
}
|
||||
|
||||
pruneResources = append(pruneResources, pruneResource{gvk[0], gvk[1], gvk[2], namespaced})
|
||||
}
|
||||
return pruneResources, nil
|
||||
}
|
||||
|
||||
func (o *ApplyOptions) Run() error {
|
||||
var openapiSchema openapi.Resources
|
||||
if o.OpenApiPatch {
|
||||
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
|
||||
// unless explicitly set --include-uninitialized=false
|
||||
r := o.Builder.
|
||||
Unstructured().
|
||||
Schema(o.Validator).
|
||||
ContinueOnError().
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
FilenameParam(o.EnforceNamespace, &o.DeleteOptions.FilenameOptions).
|
||||
LabelSelectorParam(o.Selector).
|
||||
IncludeUninitialized(o.ShouldIncludeUninitialized).
|
||||
Flatten().
|
||||
Do()
|
||||
if err := r.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
if o.Prune {
|
||||
o.PruneResources, err = parsePruneResources(o.Mapper, o.PruneWhitelist)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
output := *o.PrintFlags.OutputFormat
|
||||
shortOutput := output == "name"
|
||||
|
||||
visitedUids := sets.NewString()
|
||||
visitedNamespaces := sets.NewString()
|
||||
|
||||
var objs []runtime.Object
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.Namespaced() {
|
||||
visitedNamespaces.Insert(info.Namespace)
|
||||
}
|
||||
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
klog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
|
||||
// Get the modified configuration of the object. Embed the result
|
||||
// as an annotation in the modified configuration, so that it will appear
|
||||
// in the patch sent to the server.
|
||||
modified, err := kubectl.GetModifiedConfiguration(info.Object, true, unstructured.UnstructuredJSONScheme)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%s\nfor:", info.String()), info.Source, err)
|
||||
}
|
||||
|
||||
// Print object only if output format other than "name" is specified
|
||||
printObject := len(output) > 0 && !shortOutput
|
||||
|
||||
if err := info.Get(); err != nil {
|
||||
if !errors.IsNotFound(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
|
||||
// First, update the annotation used by kubectl apply
|
||||
if err := kubectl.CreateApplyAnnotation(info.Object, unstructured.UnstructuredJSONScheme); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
if !o.DryRun {
|
||||
// Then create the resource and skip the three-way merge
|
||||
options := metav1.CreateOptions{}
|
||||
if o.ServerDryRun {
|
||||
options.DryRun = []string{metav1.DryRunAll}
|
||||
}
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, &options)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
info.Refresh(obj, true)
|
||||
}
|
||||
|
||||
metadata, err := meta.Accessor(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
visitedUids.Insert(string(metadata.GetUID()))
|
||||
|
||||
count++
|
||||
|
||||
if printObject {
|
||||
objs = append(objs, info.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("created")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
}
|
||||
|
||||
metadata, err := meta.Accessor(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
visitedUids.Insert(string(metadata.GetUID()))
|
||||
|
||||
if !o.DryRun {
|
||||
annotationMap := metadata.GetAnnotations()
|
||||
if _, ok := annotationMap[corev1.LastAppliedConfigAnnotation]; !ok {
|
||||
fmt.Fprintf(o.ErrOut, warningNoLastAppliedConfigAnnotation, o.cmdBaseName)
|
||||
}
|
||||
|
||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||
patcher := &Patcher{
|
||||
Mapping: info.Mapping,
|
||||
Helper: helper,
|
||||
DynamicClient: o.DynamicClient,
|
||||
Overwrite: o.Overwrite,
|
||||
BackOff: clockwork.NewRealClock(),
|
||||
Force: o.DeleteOptions.ForceDeletion,
|
||||
Cascade: o.DeleteOptions.Cascade,
|
||||
Timeout: o.DeleteOptions.Timeout,
|
||||
GracePeriod: o.DeleteOptions.GracePeriod,
|
||||
ServerDryRun: o.ServerDryRun,
|
||||
OpenapiSchema: openapiSchema,
|
||||
Retries: maxPatchRetry,
|
||||
}
|
||||
|
||||
patchBytes, patchedObject, err := patcher.Patch(info.Object, modified, info.Source, info.Namespace, info.Name, o.ErrOut)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err)
|
||||
}
|
||||
|
||||
info.Refresh(patchedObject, true)
|
||||
|
||||
if string(patchBytes) == "{}" && !printObject {
|
||||
count++
|
||||
|
||||
printer, err := o.ToPrinter("unchanged")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
}
|
||||
}
|
||||
count++
|
||||
|
||||
if printObject {
|
||||
objs = append(objs, info.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
printer, err := o.ToPrinter("configured")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(info.Object, o.Out)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return fmt.Errorf("no objects passed to apply")
|
||||
}
|
||||
|
||||
// print objects
|
||||
if len(objs) > 0 {
|
||||
printer, err := o.ToPrinter("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objToPrint := objs[0]
|
||||
if len(objs) > 1 {
|
||||
list := &corev1.List{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "List",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ListMeta: metav1.ListMeta{},
|
||||
}
|
||||
if err := meta.SetList(list, objs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objToPrint = list
|
||||
}
|
||||
if err := printer.PrintObj(objToPrint, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !o.Prune {
|
||||
return nil
|
||||
}
|
||||
|
||||
p := pruner{
|
||||
mapper: o.Mapper,
|
||||
dynamicClient: o.DynamicClient,
|
||||
|
||||
labelSelector: o.Selector,
|
||||
visitedUids: visitedUids,
|
||||
|
||||
cascade: o.DeleteOptions.Cascade,
|
||||
dryRun: o.DryRun,
|
||||
serverDryRun: o.ServerDryRun,
|
||||
gracePeriod: o.DeleteOptions.GracePeriod,
|
||||
|
||||
toPrinter: o.ToPrinter,
|
||||
|
||||
out: o.Out,
|
||||
}
|
||||
|
||||
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(o.Mapper, &(o.PruneResources))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
|
||||
}
|
||||
|
||||
for n := range visitedNamespaces {
|
||||
for _, m := range namespacedRESTMappings {
|
||||
if err := p.prune(n, m, o.ShouldIncludeUninitialized); err != nil {
|
||||
return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, m := range nonNamespacedRESTMappings {
|
||||
if err := p.prune(metav1.NamespaceNone, m, o.ShouldIncludeUninitialized); err != nil {
|
||||
return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type pruneResource struct {
|
||||
group string
|
||||
version string
|
||||
kind string
|
||||
namespaced bool
|
||||
}
|
||||
|
||||
func (pr pruneResource) String() string {
|
||||
return fmt.Sprintf("%v/%v, Kind=%v, Namespaced=%v", pr.group, pr.version, pr.kind, pr.namespaced)
|
||||
}
|
||||
|
||||
func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (namespaced, nonNamespaced []*meta.RESTMapping, err error) {
|
||||
if len(*pruneResources) == 0 {
|
||||
// default whitelist
|
||||
// TODO: need to handle the older api versions - e.g. v1beta1 jobs. Github issue: #35991
|
||||
*pruneResources = []pruneResource{
|
||||
{"", "v1", "ConfigMap", true},
|
||||
{"", "v1", "Endpoints", true},
|
||||
{"", "v1", "Namespace", false},
|
||||
{"", "v1", "PersistentVolumeClaim", true},
|
||||
{"", "v1", "PersistentVolume", false},
|
||||
{"", "v1", "Pod", true},
|
||||
{"", "v1", "ReplicationController", true},
|
||||
{"", "v1", "Secret", true},
|
||||
{"", "v1", "Service", true},
|
||||
{"batch", "v1", "Job", true},
|
||||
{"batch", "v1beta1", "CronJob", true},
|
||||
{"extensions", "v1beta1", "DaemonSet", true},
|
||||
{"extensions", "v1beta1", "Deployment", true},
|
||||
{"extensions", "v1beta1", "Ingress", true},
|
||||
{"extensions", "v1beta1", "ReplicaSet", true},
|
||||
{"apps", "v1beta1", "StatefulSet", true},
|
||||
{"apps", "v1beta1", "Deployment", true},
|
||||
}
|
||||
}
|
||||
|
||||
for _, resource := range *pruneResources {
|
||||
addedMapping, err := mapper.RESTMapping(schema.GroupKind{Group: resource.group, Kind: resource.kind}, resource.version)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("invalid resource %v: %v", resource, err)
|
||||
}
|
||||
if resource.namespaced {
|
||||
namespaced = append(namespaced, addedMapping)
|
||||
} else {
|
||||
nonNamespaced = append(nonNamespaced, addedMapping)
|
||||
}
|
||||
}
|
||||
|
||||
return namespaced, nonNamespaced, nil
|
||||
}
|
||||
|
||||
type pruner struct {
|
||||
mapper meta.RESTMapper
|
||||
dynamicClient dynamic.Interface
|
||||
|
||||
visitedUids sets.String
|
||||
labelSelector string
|
||||
fieldSelector string
|
||||
|
||||
cascade bool
|
||||
serverDryRun bool
|
||||
dryRun bool
|
||||
gracePeriod int
|
||||
|
||||
toPrinter func(string) (printers.ResourcePrinter, error)
|
||||
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, includeUninitialized bool) error {
|
||||
objList, err := p.dynamicClient.Resource(mapping.Resource).
|
||||
Namespace(namespace).
|
||||
List(metav1.ListOptions{
|
||||
LabelSelector: p.labelSelector,
|
||||
FieldSelector: p.fieldSelector,
|
||||
IncludeUninitialized: includeUninitialized,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objs, err := meta.ExtractList(objList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, obj := range objs {
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
annots := metadata.GetAnnotations()
|
||||
if _, ok := annots[corev1.LastAppliedConfigAnnotation]; !ok {
|
||||
// don't prune resources not created with apply
|
||||
continue
|
||||
}
|
||||
uid := metadata.GetUID()
|
||||
if p.visitedUids.Has(string(uid)) {
|
||||
continue
|
||||
}
|
||||
name := metadata.GetName()
|
||||
if !p.dryRun {
|
||||
if err := p.delete(namespace, name, mapping); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
printer, err := p.toPrinter("pruned")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printer.PrintObj(obj, p.out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
|
||||
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod, p.serverDryRun)
|
||||
}
|
||||
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int, serverDryRun bool) error {
|
||||
options := &metav1.DeleteOptions{}
|
||||
if gracePeriod >= 0 {
|
||||
options = metav1.NewDeleteOptions(int64(gracePeriod))
|
||||
}
|
||||
if serverDryRun {
|
||||
options.DryRun = []string{metav1.DryRunAll}
|
||||
}
|
||||
policy := metav1.DeletePropagationForeground
|
||||
if !cascade {
|
||||
policy = metav1.DeletePropagationOrphan
|
||||
}
|
||||
options.PropagationPolicy = &policy
|
||||
return c.Resource(mapping.Resource).Namespace(namespace).Delete(name, options)
|
||||
}
|
||||
|
||||
func (p *Patcher) delete(namespace, name string) error {
|
||||
return runDelete(namespace, name, p.Mapping, p.DynamicClient, p.Cascade, p.GracePeriod, p.ServerDryRun)
|
||||
}
|
||||
|
||||
type Patcher struct {
|
||||
Mapping *meta.RESTMapping
|
||||
Helper *resource.Helper
|
||||
DynamicClient dynamic.Interface
|
||||
|
||||
Overwrite bool
|
||||
BackOff clockwork.Clock
|
||||
|
||||
Force bool
|
||||
Cascade bool
|
||||
Timeout time.Duration
|
||||
GracePeriod int
|
||||
ServerDryRun bool
|
||||
|
||||
// If set, forces the patch against a specific resourceVersion
|
||||
ResourceVersion *string
|
||||
|
||||
// Number of retries to make if the patch fails with conflict
|
||||
Retries int
|
||||
|
||||
OpenapiSchema openapi.Resources
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func addResourceVersion(patch []byte, rv string) ([]byte, error) {
|
||||
var patchMap map[string]interface{}
|
||||
err := json.Unmarshal(patch, &patchMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := unstructured.Unstructured{Object: patchMap}
|
||||
a, err := meta.Accessor(&u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.SetResourceVersion(rv)
|
||||
|
||||
return json.Marshal(patchMap)
|
||||
}
|
||||
|
||||
func (p *Patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
|
||||
// Serialize the current configuration of the object from the server.
|
||||
current, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("serializing current configuration from:\n%v\nfor:", obj), source, err)
|
||||
}
|
||||
|
||||
// Retrieve the original configuration of the object from the annotation.
|
||||
original, err := kubectl.GetOriginalConfiguration(obj)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("retrieving original configuration from:\n%v\nfor:", obj), source, err)
|
||||
}
|
||||
|
||||
var patchType types.PatchType
|
||||
var patch []byte
|
||||
var lookupPatchMeta strategicpatch.LookupPatchMeta
|
||||
var schema oapi.Schema
|
||||
createPatchErrFormat := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:"
|
||||
|
||||
// Create the versioned struct from the type defined in the restmapping
|
||||
// (which is the API version we'll be submitting the patch to)
|
||||
versionedObject, err := scheme.Scheme.New(p.Mapping.GroupVersionKind)
|
||||
switch {
|
||||
case runtime.IsNotRegisteredError(err):
|
||||
// fall back to generic JSON merge patch
|
||||
patchType = types.MergePatchType
|
||||
preconditions := []mergepatch.PreconditionFunc{mergepatch.RequireKeyUnchanged("apiVersion"),
|
||||
mergepatch.RequireKeyUnchanged("kind"), mergepatch.RequireMetadataKeyUnchanged("name")}
|
||||
patch, err = jsonmergepatch.CreateThreeWayJSONMergePatch(original, modified, current, preconditions...)
|
||||
if err != nil {
|
||||
if mergepatch.IsPreconditionFailed(err) {
|
||||
return nil, nil, fmt.Errorf("%s", "At least one of apiVersion, kind and name was changed")
|
||||
}
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf(createPatchErrFormat, original, modified, current), source, err)
|
||||
}
|
||||
case err != nil:
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf("getting instance of versioned object for %v:", p.Mapping.GroupVersionKind), source, err)
|
||||
case err == nil:
|
||||
// Compute a three way strategic merge patch to send to server.
|
||||
patchType = types.StrategicMergePatchType
|
||||
|
||||
// Try to use openapi first if the openapi spec is available and can successfully calculate the patch.
|
||||
// Otherwise, fall back to baked-in types.
|
||||
if p.OpenapiSchema != nil {
|
||||
if schema = p.OpenapiSchema.LookupResource(p.Mapping.GroupVersionKind); schema != nil {
|
||||
lookupPatchMeta = strategicpatch.PatchMetaFromOpenAPI{Schema: schema}
|
||||
if openapiPatch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, p.Overwrite); err != nil {
|
||||
fmt.Fprintf(errOut, "warning: error calculating patch from openapi spec: %v\n", err)
|
||||
} else {
|
||||
patchType = types.StrategicMergePatchType
|
||||
patch = openapiPatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if patch == nil {
|
||||
lookupPatchMeta, err = strategicpatch.NewPatchMetaFromStruct(versionedObject)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf(createPatchErrFormat, original, modified, current), source, err)
|
||||
}
|
||||
patch, err = strategicpatch.CreateThreeWayMergePatch(original, modified, current, lookupPatchMeta, p.Overwrite)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr(fmt.Sprintf(createPatchErrFormat, original, modified, current), source, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if string(patch) == "{}" {
|
||||
return patch, obj, nil
|
||||
}
|
||||
|
||||
if p.ResourceVersion != nil {
|
||||
patch, err = addResourceVersion(patch, *p.ResourceVersion)
|
||||
if err != nil {
|
||||
return nil, nil, cmdutil.AddSourceToErr("Failed to insert resourceVersion in patch", source, err)
|
||||
}
|
||||
}
|
||||
|
||||
options := metav1.UpdateOptions{}
|
||||
if p.ServerDryRun {
|
||||
options.DryRun = []string{metav1.DryRunAll}
|
||||
}
|
||||
|
||||
patchedObj, err := p.Helper.Patch(namespace, name, patchType, patch, &options)
|
||||
return patch, patchedObj, err
|
||||
}
|
||||
|
||||
func (p *Patcher) Patch(current runtime.Object, modified []byte, source, namespace, name string, errOut io.Writer) ([]byte, runtime.Object, error) {
|
||||
var getErr error
|
||||
patchBytes, patchObject, err := p.patchSimple(current, modified, source, namespace, name, errOut)
|
||||
if p.Retries == 0 {
|
||||
p.Retries = maxPatchRetry
|
||||
}
|
||||
for i := 1; i <= p.Retries && errors.IsConflict(err); i++ {
|
||||
if i > triesBeforeBackOff {
|
||||
p.BackOff.Sleep(backOffPeriod)
|
||||
}
|
||||
current, getErr = p.Helper.Get(namespace, name, false)
|
||||
if getErr != nil {
|
||||
return nil, nil, getErr
|
||||
}
|
||||
patchBytes, patchObject, err = p.patchSimple(current, modified, source, namespace, name, errOut)
|
||||
}
|
||||
if err != nil && (errors.IsConflict(err) || errors.IsInvalid(err)) && p.Force {
|
||||
patchBytes, patchObject, err = p.deleteAndCreate(current, modified, namespace, name)
|
||||
}
|
||||
return patchBytes, patchObject, err
|
||||
}
|
||||
|
||||
func (p *Patcher) deleteAndCreate(original runtime.Object, modified []byte, namespace, name string) ([]byte, runtime.Object, error) {
|
||||
if err := p.delete(namespace, name); err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
// TODO: use wait
|
||||
if err := wait.PollImmediate(1*time.Second, p.Timeout, func() (bool, error) {
|
||||
if _, err := p.Helper.Get(namespace, name, false); !errors.IsNotFound(err) {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}); err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
versionedObject, _, err := unstructured.UnstructuredJSONScheme.Decode(modified, nil, nil)
|
||||
if err != nil {
|
||||
return modified, nil, err
|
||||
}
|
||||
options := metav1.CreateOptions{}
|
||||
if p.ServerDryRun {
|
||||
options.DryRun = []string{metav1.DryRunAll}
|
||||
}
|
||||
createdObject, err := p.Helper.Create(namespace, true, versionedObject, &options)
|
||||
if err != nil {
|
||||
// restore the original object if we fail to create the new one
|
||||
// but still propagate and advertise error to user
|
||||
recreated, recreateErr := p.Helper.Create(namespace, true, original, &options)
|
||||
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\n", err, recreateErr)
|
||||
} else {
|
||||
createdObject = recreated
|
||||
}
|
||||
}
|
||||
return modified, createdObject, err
|
||||
}
|
88
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_edit_last_applied.go
generated
vendored
Normal file
88
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_edit_last_applied.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 apply
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/templates"
|
||||
)
|
||||
|
||||
var (
|
||||
applyEditLastAppliedLong = templates.LongDesc(`
|
||||
Edit the latest last-applied-configuration annotations of resources from the default editor.
|
||||
|
||||
The edit-last-applied command allows you to directly edit any API resource you can retrieve via the
|
||||
command line tools. It will open the editor defined by your KUBE_EDITOR, or EDITOR
|
||||
environment variables, or fall back to 'vi' for Linux or 'notepad' for Windows.
|
||||
You can edit multiple objects, although changes are applied one at a time. The command
|
||||
accepts filenames as well as command line arguments, although the files you point to must
|
||||
be previously saved versions of resources.
|
||||
|
||||
The default format is YAML. To edit in JSON, specify "-o json".
|
||||
|
||||
The flag --windows-line-endings can be used to force Windows line endings,
|
||||
otherwise the default for your operating system will be used.
|
||||
|
||||
In the event an error occurs while updating, a temporary file will be created on disk
|
||||
that contains your unapplied changes. The most common error when updating a resource
|
||||
is another editor changing the resource on the server. When this occurs, you will have
|
||||
to apply your changes to the newer version of the resource, or update your temporary
|
||||
saved copy to include the latest resource version.`)
|
||||
|
||||
applyEditLastAppliedExample = templates.Examples(`
|
||||
# Edit the last-applied-configuration annotations by type/name in YAML.
|
||||
kubectl apply edit-last-applied deployment/nginx
|
||||
|
||||
# Edit the last-applied-configuration annotations by file in JSON.
|
||||
kubectl apply edit-last-applied -f deploy.yaml -o json`)
|
||||
)
|
||||
|
||||
func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := editor.NewEditOptions(editor.ApplyEditMode, ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "edit-last-applied (RESOURCE/NAME | -f FILENAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: "Edit latest last-applied-configuration annotations of a resource/object",
|
||||
Long: applyEditLastAppliedLong,
|
||||
Example: applyEditLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := o.Complete(f, args, cmd); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
if err := o.Run(); err != nil {
|
||||
cmdutil.CheckErr(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// bind flag structs
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
usage := "to use to edit the resource"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings,
|
||||
"Defaults to the line ending native to your platform.")
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
213
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_set_last_applied.go
generated
vendored
Normal file
213
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_set_last_applied.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
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 apply
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/printers"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/templates"
|
||||
)
|
||||
|
||||
type SetLastAppliedOptions struct {
|
||||
CreateAnnotation bool
|
||||
|
||||
PrintFlags *genericclioptions.PrintFlags
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
||||
FilenameOptions resource.FilenameOptions
|
||||
|
||||
infoList []*resource.Info
|
||||
namespace string
|
||||
enforceNamespace bool
|
||||
dryRun bool
|
||||
shortOutput bool
|
||||
output string
|
||||
patchBufferList []PatchBuffer
|
||||
builder *resource.Builder
|
||||
unstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
type PatchBuffer struct {
|
||||
Patch []byte
|
||||
PatchType types.PatchType
|
||||
}
|
||||
|
||||
var (
|
||||
applySetLastAppliedLong = templates.LongDesc(i18n.T(`
|
||||
Set the latest last-applied-configuration annotations by setting it to match the contents of a file.
|
||||
This results in the last-applied-configuration being updated as though 'kubectl apply -f <file>' was run,
|
||||
without updating any other parts of the object.`))
|
||||
|
||||
applySetLastAppliedExample = templates.Examples(i18n.T(`
|
||||
# Set the last-applied-configuration of a resource to match the contents of a file.
|
||||
kubectl apply set-last-applied -f deploy.yaml
|
||||
|
||||
# Execute set-last-applied against each configuration file in a directory.
|
||||
kubectl apply set-last-applied -f path/
|
||||
|
||||
# Set the last-applied-configuration of a resource to match the contents of a file, will create the annotation if it does not already exist.
|
||||
kubectl apply set-last-applied -f deploy.yaml --create-annotation=true
|
||||
`))
|
||||
)
|
||||
|
||||
func NewSetLastAppliedOptions(ioStreams genericclioptions.IOStreams) *SetLastAppliedOptions {
|
||||
return &SetLastAppliedOptions{
|
||||
PrintFlags: genericclioptions.NewPrintFlags("configured").WithTypeSetter(scheme.Scheme),
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
o := NewSetLastAppliedOptions(ioStreams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "set-last-applied -f FILENAME",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Set the last-applied-configuration annotation on a live object to match the contents of a file."),
|
||||
Long: applySetLastAppliedLong,
|
||||
Example: applySetLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunSetLastApplied())
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmd.Flags().BoolVar(&o.CreateAnnotation, "create-annotation", o.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one")
|
||||
cmdutil.AddJsonFilenameFlag(cmd.Flags(), &o.FilenameOptions.Filenames, "Filename, directory, or URL to files that contains the last-applied-configuration annotations")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
o.dryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.shortOutput = o.output == "name"
|
||||
|
||||
var err error
|
||||
o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builder = f.NewBuilder()
|
||||
o.unstructuredClientForMapping = f.UnstructuredClientForMapping
|
||||
|
||||
if o.dryRun {
|
||||
// TODO(juanvallejo): This can be cleaned up even further by creating
|
||||
// a PrintFlags struct that binds the --dry-run flag, and whose
|
||||
// ToPrinter method returns a printer that understands how to print
|
||||
// this success message.
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
}
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.PrintObj = printer.PrintObj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) Validate() error {
|
||||
r := o.builder.
|
||||
Unstructured().
|
||||
NamespaceParam(o.namespace).DefaultNamespace().
|
||||
FilenameParam(o.enforceNamespace, &o.FilenameOptions).
|
||||
Flatten().
|
||||
Do()
|
||||
|
||||
err := r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.Object.(runtime.Unstructured))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify the object exists in the cluster before trying to patch it.
|
||||
if err := info.Get(); err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return err
|
||||
} else {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
}
|
||||
originalBuf, err := kubectl.GetOriginalConfiguration(info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%s\nfrom server for:", info.String()), info.Source, err)
|
||||
}
|
||||
if originalBuf == nil && !o.CreateAnnotation {
|
||||
return fmt.Errorf("no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
|
||||
}
|
||||
|
||||
//only add to PatchBufferList when changed
|
||||
if !bytes.Equal(cmdutil.StripComments(originalBuf), cmdutil.StripComments(diffBuf)) {
|
||||
p := PatchBuffer{Patch: patchBuf, PatchType: patchType}
|
||||
o.patchBufferList = append(o.patchBufferList, p)
|
||||
o.infoList = append(o.infoList, info)
|
||||
} else {
|
||||
fmt.Fprintf(o.Out, "set-last-applied %s: no changes required.\n", info.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *SetLastAppliedOptions) RunSetLastApplied() error {
|
||||
for i, patch := range o.patchBufferList {
|
||||
info := o.infoList[i]
|
||||
finalObj := info.Object
|
||||
|
||||
if !o.dryRun {
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := o.unstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
finalObj, err = helper.Patch(o.namespace, info.Name, patch.PatchType, patch.Patch, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := o.PrintObj(finalObj, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
1416
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_test.go
generated
vendored
Normal file
1416
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
166
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_view_last_applied.go
generated
vendored
Normal file
166
vendor/k8s.io/kubernetes/pkg/kubectl/cmd/apply/apply_view_last_applied.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
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 apply
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/templates"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
type ViewLastAppliedOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
Selector string
|
||||
LastAppliedConfigurationList []string
|
||||
OutputFormat string
|
||||
All bool
|
||||
Factory cmdutil.Factory
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
var (
|
||||
applyViewLastAppliedLong = templates.LongDesc(i18n.T(`
|
||||
View the latest last-applied-configuration annotations by type/name or file.
|
||||
|
||||
The default output will be printed to stdout in YAML format. One can use -o option
|
||||
to change output format.`))
|
||||
|
||||
applyViewLastAppliedExample = templates.Examples(i18n.T(`
|
||||
# View the last-applied-configuration annotations by type/name in YAML.
|
||||
kubectl apply view-last-applied deployment/nginx
|
||||
|
||||
# View the last-applied-configuration annotations by file in JSON
|
||||
kubectl apply view-last-applied -f deploy.yaml -o json`))
|
||||
)
|
||||
|
||||
func NewViewLastAppliedOptions(ioStreams genericclioptions.IOStreams) *ViewLastAppliedOptions {
|
||||
return &ViewLastAppliedOptions{
|
||||
OutputFormat: "yaml",
|
||||
|
||||
IOStreams: ioStreams,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := NewViewLastAppliedOptions(ioStreams)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view-last-applied (TYPE [NAME | -l label] | TYPE/NAME | -f FILENAME)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("View latest last-applied-configuration annotations of a resource/object"),
|
||||
Long: applyViewLastAppliedLong,
|
||||
Example: applyViewLastAppliedExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(cmd, f, args))
|
||||
cmdutil.CheckErr(options.Validate(cmd))
|
||||
cmdutil.CheckErr(options.RunApplyViewLastApplied(cmd))
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", options.OutputFormat, "Output format. Must be one of yaml|json")
|
||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types")
|
||||
usage := "that contains the last-applied-configuration annotations"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args []string) error {
|
||||
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := f.NewBuilder().
|
||||
Unstructured().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(enforceNamespace, args...).
|
||||
SelectAllParam(o.All).
|
||||
LabelSelectorParam(o.Selector).
|
||||
Latest().
|
||||
Flatten().
|
||||
Do()
|
||||
err = r.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configString, err := kubectl.GetOriginalConfiguration(info.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if configString == nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("no last-applied-configuration annotation found on resource: %s\n", info.Name), info.Source, err)
|
||||
}
|
||||
o.LastAppliedConfigurationList = append(o.LastAppliedConfigurationList, string(configString))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) Validate(cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *ViewLastAppliedOptions) RunApplyViewLastApplied(cmd *cobra.Command) error {
|
||||
for _, str := range o.LastAppliedConfigurationList {
|
||||
switch o.OutputFormat {
|
||||
case "json":
|
||||
jsonBuffer := &bytes.Buffer{}
|
||||
err := json.Indent(jsonBuffer, []byte(str), "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(o.Out, string(jsonBuffer.Bytes()))
|
||||
case "yaml":
|
||||
yamlOutput, err := yaml.JSONToYAML([]byte(str))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprint(o.Out, string(yamlOutput))
|
||||
default:
|
||||
return cmdutil.UsageErrorf(
|
||||
cmd,
|
||||
"Unexpected -o output mode: %s, the flag 'output' must be one of yaml|json",
|
||||
o.OutputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user