mirror of https://github.com/k3s-io/k3s
support force apply
parent
fbe29f43ea
commit
750449ba3c
|
@ -40,15 +40,18 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||||
|
"k8s.io/kubernetes/pkg/util/wait"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApplyOptions struct {
|
type ApplyOptions struct {
|
||||||
FilenameOptions resource.FilenameOptions
|
FilenameOptions resource.FilenameOptions
|
||||||
Selector string
|
Selector string
|
||||||
|
Force bool
|
||||||
Prune bool
|
Prune bool
|
||||||
Cascade bool
|
Cascade bool
|
||||||
GracePeriod int
|
GracePeriod int
|
||||||
PruneResources []pruneResource
|
PruneResources []pruneResource
|
||||||
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -101,6 +104,8 @@ func NewCmdApply(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
cmd.Flags().BoolVar(&options.Prune, "prune", false, "Automatically delete resource objects that do not appear in the configs")
|
cmd.Flags().BoolVar(&options.Prune, "prune", false, "Automatically delete resource objects that do not appear in the configs")
|
||||||
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "Only relevant during a prune. If true, cascade the deletion of the resources managed by pruned resources (e.g. Pods created by a ReplicationController).")
|
cmd.Flags().BoolVar(&options.Cascade, "cascade", true, "Only relevant during a prune. If true, cascade the deletion of the resources managed by pruned resources (e.g. Pods created by a ReplicationController).")
|
||||||
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Period of time in seconds given to pruned resources to terminate gracefully. Ignored if negative.")
|
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", -1, "Period of time in seconds given to pruned resources to terminate gracefully. Ignored if negative.")
|
||||||
|
cmd.Flags().BoolVar(&options.Force, "force", false, "Delete and re-create the specified resource")
|
||||||
|
cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "Only relevant during a force apply. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
|
||||||
cmdutil.AddValidateFlags(cmd)
|
cmdutil.AddValidateFlags(cmd)
|
||||||
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on")
|
cmd.Flags().StringVarP(&options.Selector, "selector", "l", "", "Selector (label query) to filter on")
|
||||||
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
|
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources.")
|
||||||
|
@ -246,7 +251,19 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
|
||||||
if !dryRun {
|
if !dryRun {
|
||||||
overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
|
overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
|
||||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||||
patcher := NewPatcher(encoder, decoder, info.Mapping, helper, overwrite)
|
patcher := &patcher{
|
||||||
|
encoder: encoder,
|
||||||
|
decoder: decoder,
|
||||||
|
mapping: info.Mapping,
|
||||||
|
helper: helper,
|
||||||
|
clientsetFunc: f.ClientSet,
|
||||||
|
overwrite: overwrite,
|
||||||
|
backOff: clockwork.NewRealClock(),
|
||||||
|
force: options.Force,
|
||||||
|
cascade: options.Cascade,
|
||||||
|
timeout: options.Timeout,
|
||||||
|
gracePeriod: options.GracePeriod,
|
||||||
|
}
|
||||||
|
|
||||||
patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
|
patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -438,10 +455,17 @@ func (p *pruner) prune(namespace string, mapping *meta.RESTMapping, shortOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient) error {
|
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient) error {
|
||||||
if !p.cascade {
|
return runDelete(namespace, name, mapping, c, nil, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||||
return resource.NewHelper(c, mapping).Delete(namespace, name)
|
}
|
||||||
|
|
||||||
|
func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient, helper *resource.Helper, cascade bool, gracePeriod int, clientsetFunc func() (*internalclientset.Clientset, error)) error {
|
||||||
|
if !cascade {
|
||||||
|
if helper == nil {
|
||||||
|
helper = resource.NewHelper(c, mapping)
|
||||||
|
}
|
||||||
|
return helper.Delete(namespace, name)
|
||||||
}
|
}
|
||||||
cs, err := p.clientsetFunc()
|
cs, err := clientsetFunc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -452,32 +476,35 @@ func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, c res
|
||||||
}
|
}
|
||||||
return resource.NewHelper(c, mapping).Delete(namespace, name)
|
return resource.NewHelper(c, mapping).Delete(namespace, name)
|
||||||
}
|
}
|
||||||
if err := r.Stop(namespace, name, 2*time.Minute, api.NewDeleteOptions(int64(p.gracePeriod))); err != nil {
|
var options *api.DeleteOptions
|
||||||
|
if gracePeriod >= 0 {
|
||||||
|
options = api.NewDeleteOptions(int64(gracePeriod))
|
||||||
|
}
|
||||||
|
if err := r.Stop(namespace, name, 2*time.Minute, options); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *patcher) delete(namespace, name string) error {
|
||||||
|
return runDelete(namespace, name, p.mapping, nil, p.helper, p.cascade, p.gracePeriod, p.clientsetFunc)
|
||||||
|
}
|
||||||
|
|
||||||
type patcher struct {
|
type patcher struct {
|
||||||
encoder runtime.Encoder
|
encoder runtime.Encoder
|
||||||
decoder runtime.Decoder
|
decoder runtime.Decoder
|
||||||
|
|
||||||
mapping *meta.RESTMapping
|
mapping *meta.RESTMapping
|
||||||
helper *resource.Helper
|
helper *resource.Helper
|
||||||
|
clientsetFunc func() (*internalclientset.Clientset, error)
|
||||||
|
|
||||||
overwrite bool
|
overwrite bool
|
||||||
backOff clockwork.Clock
|
backOff clockwork.Clock
|
||||||
}
|
|
||||||
|
|
||||||
func NewPatcher(encoder runtime.Encoder, decoder runtime.Decoder, mapping *meta.RESTMapping, helper *resource.Helper, overwrite bool) *patcher {
|
force bool
|
||||||
return &patcher{
|
cascade bool
|
||||||
encoder: encoder,
|
timeout time.Duration
|
||||||
decoder: decoder,
|
gracePeriod int
|
||||||
mapping: mapping,
|
|
||||||
helper: helper,
|
|
||||||
overwrite: overwrite,
|
|
||||||
backOff: clockwork.NewRealClock(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) {
|
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) {
|
||||||
|
@ -527,6 +554,30 @@ func (p *patcher) patch(current runtime.Object, modified []byte, source, namespa
|
||||||
}
|
}
|
||||||
patchBytes, err = p.patchSimple(current, modified, source, namespace, name)
|
patchBytes, err = p.patchSimple(current, modified, source, namespace, name)
|
||||||
}
|
}
|
||||||
|
if err != nil && p.force {
|
||||||
|
patchBytes, err = p.deleteAndCreate(modified, namespace, name)
|
||||||
|
}
|
||||||
return patchBytes, err
|
return patchBytes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *patcher) deleteAndCreate(modified []byte, namespace, name string) ([]byte, error) {
|
||||||
|
err := p.delete(namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return modified, err
|
||||||
|
}
|
||||||
|
err = wait.PollImmediate(kubectl.Interval, p.timeout, func() (bool, error) {
|
||||||
|
if _, err := p.helper.Get(namespace, name, false); !errors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return modified, err
|
||||||
|
}
|
||||||
|
versionedObject, _, err := p.decoder.Decode(modified, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return modified, err
|
||||||
|
}
|
||||||
|
_, err = p.helper.Create(namespace, true, versionedObject)
|
||||||
|
return modified, err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue