mirror of https://github.com/kubernetes/kops.git
Merge pull request #16293 from justinsb/deletion_processing_mode
refactor: Introduce DeletionProcessingMode
This commit is contained in:
commit
2e0115171d
|
@ -714,6 +714,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
||||||
var target fi.CloudupTarget
|
var target fi.CloudupTarget
|
||||||
shouldPrecreateDNS := true
|
shouldPrecreateDNS := true
|
||||||
|
|
||||||
|
deletionProcessingMode := fi.DeletionProcessingModeDeleteIfNotDeferrred
|
||||||
switch c.TargetName {
|
switch c.TargetName {
|
||||||
case TargetDirect:
|
case TargetDirect:
|
||||||
switch cluster.Spec.GetCloudProvider() {
|
switch cluster.Spec.GetCloudProvider() {
|
||||||
|
@ -764,6 +765,9 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
||||||
// Can cause conflicts with terraform management
|
// Can cause conflicts with terraform management
|
||||||
shouldPrecreateDNS = false
|
shouldPrecreateDNS = false
|
||||||
|
|
||||||
|
// Terraform tracks & performs deletions itself
|
||||||
|
deletionProcessingMode = fi.DeletionProcessingModeIgnore
|
||||||
|
|
||||||
case TargetDryRun:
|
case TargetDryRun:
|
||||||
var out io.Writer = os.Stdout
|
var out io.Writer = os.Stdout
|
||||||
if c.GetAssets {
|
if c.GetAssets {
|
||||||
|
@ -786,7 +790,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context, err := fi.NewCloudupContext(ctx, target, cluster, cloud, keyStore, secretStore, configBase, c.TaskMap)
|
context, err := fi.NewCloudupContext(ctx, deletionProcessingMode, target, cluster, cloud, keyStore, secretStore, configBase, c.TaskMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error building context: %v", err)
|
return fmt.Errorf("error building context: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ func runTasks(t *testing.T, cloud awsup.AWSCloud, allTasks map[string]fi.Cloudup
|
||||||
Cloud: cloud,
|
Cloud: cloud,
|
||||||
}
|
}
|
||||||
|
|
||||||
context, err := fi.NewCloudupContext(ctx, target, nil, cloud, nil, nil, nil, allTasks)
|
context, err := fi.NewCloudupContext(ctx, fi.DeletionProcessingModeDeleteIncludingDeferred, target, nil, cloud, nil, nil, nil, allTasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error building context: %v", err)
|
t.Fatalf("error building context: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ func checkNoChanges(t *testing.T, ctx context.Context, cloud fi.Cloud, allTasks
|
||||||
}
|
}
|
||||||
assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
|
assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
|
||||||
target := fi.NewCloudupDryRunTarget(assetBuilder, os.Stderr)
|
target := fi.NewCloudupDryRunTarget(assetBuilder, os.Stderr)
|
||||||
context, err := fi.NewCloudupContext(ctx, target, nil, cloud, nil, nil, nil, allTasks)
|
context, err := fi.NewCloudupContext(ctx, fi.DeletionProcessingModeDeleteIncludingDeferred, target, nil, cloud, nil, nil, nil, allTasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error building context: %v", err)
|
t.Fatalf("error building context: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,6 @@ func NewAWSAPITarget(cloud AWSCloud) *AWSAPITarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *AWSAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *AWSAPITarget) DefaultCheckExisting() bool {
|
func (t *AWSAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,6 @@ func (t *AzureAPITarget) Finish(taskMap map[string]fi.CloudupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessDeletions returns true if we should delete resources.
|
|
||||||
func (t *AzureAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *AzureAPITarget) DefaultCheckExisting() bool {
|
func (t *AzureAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,6 @@ func (t *DOAPITarget) Finish(taskMap map[string]fi.CloudupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DOAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DOAPITarget) DefaultCheckExisting() bool {
|
func (t *DOAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,6 @@ func (t *GCEAPITarget) Finish(taskMap map[string]fi.CloudupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *GCEAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *GCEAPITarget) DefaultCheckExisting() bool {
|
func (t *GCEAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ func checkHasChanges(t *testing.T, ctx context.Context, cloud fi.Cloud, allTasks
|
||||||
func runTasks(t *testing.T, ctx context.Context, cloud gce.GCECloud, allTasks map[string]fi.CloudupTask) {
|
func runTasks(t *testing.T, ctx context.Context, cloud gce.GCECloud, allTasks map[string]fi.CloudupTask) {
|
||||||
target := gce.NewGCEAPITarget(cloud)
|
target := gce.NewGCEAPITarget(cloud)
|
||||||
|
|
||||||
context, err := fi.NewCloudupContext(ctx, target, nil, cloud, nil, nil, nil, allTasks)
|
context, err := fi.NewCloudupContext(ctx, fi.DeletionProcessingModeDeleteIncludingDeferred, target, nil, cloud, nil, nil, nil, allTasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error building context: %v", err)
|
t.Fatalf("error building context: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func doDryRun(t *testing.T, ctx context.Context, cloud fi.Cloud, allTasks map[st
|
||||||
}
|
}
|
||||||
assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
|
assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
|
||||||
target := fi.NewCloudupDryRunTarget(assetBuilder, os.Stderr)
|
target := fi.NewCloudupDryRunTarget(assetBuilder, os.Stderr)
|
||||||
context, err := fi.NewCloudupContext(ctx, target, nil, cloud, nil, nil, nil, allTasks)
|
context, err := fi.NewCloudupContext(ctx, fi.DeletionProcessingModeDeleteIncludingDeferred, target, nil, cloud, nil, nil, nil, allTasks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error building context: %v", err)
|
t.Fatalf("error building context: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,6 @@ func (t *HetznerAPITarget) Finish(taskMap map[string]fi.CloudupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HetznerAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *HetznerAPITarget) DefaultCheckExisting() bool {
|
func (t *HetznerAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,6 @@ func (t *OpenstackAPITarget) Finish(taskMap map[string]fi.CloudupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *OpenstackAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *OpenstackAPITarget) DefaultCheckExisting() bool {
|
func (t *OpenstackAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,6 @@ func (s ScwAPITarget) Finish(taskMap map[string]fi.CloudupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ScwAPITarget) ProcessDeletions() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ScwAPITarget) DefaultCheckExisting() bool {
|
func (t *ScwAPITarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,11 +63,6 @@ func (t *TerraformTarget) AddFileResource(resourceType string, resourceName stri
|
||||||
return t.AddFileBytes(resourceType, resourceName, key, d, base64)
|
return t.AddFileBytes(resourceType, resourceName, key, d, base64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TerraformTarget) ProcessDeletions() bool {
|
|
||||||
// Terraform tracks & performs deletions itself
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TerraformTarget) DefaultCheckExisting() bool {
|
func (t *TerraformTarget) DefaultCheckExisting() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ type Context[T SubContext] struct {
|
||||||
tasks map[string]Task[T]
|
tasks map[string]Task[T]
|
||||||
warnings []*Warning[T]
|
warnings []*Warning[T]
|
||||||
|
|
||||||
|
deletionProcessingMode DeletionProcessingMode
|
||||||
|
|
||||||
T T
|
T T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,31 +76,40 @@ type Warning[T SubContext] struct {
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext[T SubContext](ctx context.Context, target Target[T], sub T, tasks map[string]Task[T]) (*Context[T], error) {
|
func newContext[T SubContext](ctx context.Context, deletionProcessingMode DeletionProcessingMode, target Target[T], sub T, tasks map[string]Task[T]) (*Context[T], error) {
|
||||||
c := &Context[T]{
|
c := &Context[T]{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
Target: target,
|
Target: target,
|
||||||
tasks: tasks,
|
tasks: tasks,
|
||||||
T: sub,
|
T: sub,
|
||||||
|
|
||||||
|
deletionProcessingMode: deletionProcessingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstallContext(ctx context.Context, target InstallTarget, tasks map[string]InstallTask) (*InstallContext, error) {
|
func NewInstallContext(ctx context.Context, target InstallTarget, tasks map[string]InstallTask) (*InstallContext, error) {
|
||||||
|
// We don't expect deletions, but we would be the one to handle them.
|
||||||
|
deletionProcessingMode := DeletionProcessingModeDeleteIncludingDeferred
|
||||||
|
|
||||||
sub := InstallSubContext{}
|
sub := InstallSubContext{}
|
||||||
return newContext[InstallSubContext](ctx, target, sub, tasks)
|
return newContext[InstallSubContext](ctx, deletionProcessingMode, target, sub, tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeupContext(ctx context.Context, target NodeupTarget, keystore KeystoreReader, bootConfig *nodeup.BootConfig, nodeupConfig *nodeup.Config, tasks map[string]NodeupTask) (*NodeupContext, error) {
|
func NewNodeupContext(ctx context.Context, target NodeupTarget, keystore KeystoreReader, bootConfig *nodeup.BootConfig, nodeupConfig *nodeup.Config, tasks map[string]NodeupTask) (*NodeupContext, error) {
|
||||||
|
// We don't expect deletions, but we would be the one to handle them.
|
||||||
|
deletionProcessingMode := DeletionProcessingModeDeleteIncludingDeferred
|
||||||
|
|
||||||
sub := NodeupSubContext{
|
sub := NodeupSubContext{
|
||||||
BootConfig: bootConfig,
|
BootConfig: bootConfig,
|
||||||
NodeupConfig: nodeupConfig,
|
NodeupConfig: nodeupConfig,
|
||||||
Keystore: keystore,
|
Keystore: keystore,
|
||||||
}
|
}
|
||||||
return newContext[NodeupSubContext](ctx, target, sub, tasks)
|
return newContext[NodeupSubContext](ctx, deletionProcessingMode, target, sub, tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCloudupContext(ctx context.Context, target CloudupTarget, cluster *kops.Cluster, cloud Cloud, keystore Keystore, secretStore SecretStore, clusterConfigBase vfs.Path, tasks map[string]CloudupTask) (*CloudupContext, error) {
|
func NewCloudupContext(ctx context.Context, deletionProcessingMode DeletionProcessingMode, target CloudupTarget, cluster *kops.Cluster, cloud Cloud, keystore Keystore, secretStore SecretStore, clusterConfigBase vfs.Path, tasks map[string]CloudupTask) (*CloudupContext, error) {
|
||||||
sub := CloudupSubContext{
|
sub := CloudupSubContext{
|
||||||
Cloud: cloud,
|
Cloud: cloud,
|
||||||
Cluster: cluster,
|
Cluster: cluster,
|
||||||
|
@ -106,7 +117,7 @@ func NewCloudupContext(ctx context.Context, target CloudupTarget, cluster *kops.
|
||||||
Keystore: keystore,
|
Keystore: keystore,
|
||||||
SecretStore: secretStore,
|
SecretStore: secretStore,
|
||||||
}
|
}
|
||||||
return newContext[CloudupSubContext](ctx, target, sub, tasks)
|
return newContext[CloudupSubContext](ctx, deletionProcessingMode, target, sub, tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context[T]) AllTasks() map[string]Task[T] {
|
func (c *Context[T]) AllTasks() map[string]Task[T] {
|
||||||
|
|
|
@ -104,22 +104,20 @@ func defaultDeltaRunMethod[T SubContext](e Task[T], c *Context[T]) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if producesDeletions, ok := e.(ProducesDeletions[T]); ok && c.Target.ProcessDeletions() {
|
if producesDeletions, ok := e.(ProducesDeletions[T]); ok && c.deletionProcessingMode != DeletionProcessingModeIgnore {
|
||||||
var deletions []Deletion[T]
|
deletions, err := producesDeletions.FindDeletions(c)
|
||||||
deletions, err = producesDeletions.FindDeletions(c)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, deletion := range deletions {
|
for _, deletion := range deletions {
|
||||||
if _, ok := c.Target.(*DryRunTarget[T]); ok {
|
if _, ok := c.Target.(*DryRunTarget[T]); ok {
|
||||||
err = c.Target.(*DryRunTarget[T]).Delete(deletion)
|
if err := c.Target.(*DryRunTarget[T]).RecordDeletion(deletion); err != nil {
|
||||||
} else if _, ok := c.Target.(*DryRunTarget[T]); ok {
|
return err
|
||||||
err = c.Target.(*DryRunTarget[T]).Delete(deletion)
|
}
|
||||||
} else {
|
} else {
|
||||||
err = deletion.Delete(c.Target)
|
if err := deletion.Delete(c.Target); err != nil {
|
||||||
}
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,18 @@ limitations under the License.
|
||||||
|
|
||||||
package fi
|
package fi
|
||||||
|
|
||||||
|
type DeletionProcessingMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DeletionProcessingModeIgnore will ignore all deletion tasks.
|
||||||
|
DeletionProcessingModeIgnore DeletionProcessingMode = "Ignore"
|
||||||
|
// TODO: implement deferred-deletion in the tasks!
|
||||||
|
// DeletionProcessingModeDeleteIfNotDeferrred will delete resources only if they are not marked for deferred-deletion.
|
||||||
|
DeletionProcessingModeDeleteIfNotDeferrred DeletionProcessingMode = "IfNotDeferred"
|
||||||
|
// DeletionProcessingModeDeleteIncludingDeferrred will delete resources including those marked for deferred-deletion.
|
||||||
|
DeletionProcessingModeDeleteIncludingDeferred DeletionProcessingMode = "DeleteIncludingDeferred"
|
||||||
|
)
|
||||||
|
|
||||||
type ProducesDeletions[T SubContext] interface {
|
type ProducesDeletions[T SubContext] interface {
|
||||||
FindDeletions(*Context[T]) ([]Deletion[T], error)
|
FindDeletions(*Context[T]) ([]Deletion[T], error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,11 +92,6 @@ func NewNodeupDryRunTarget(assetBuilder *assets.AssetBuilder, out io.Writer) *No
|
||||||
return newDryRunTarget[NodeupSubContext](assetBuilder, out)
|
return newDryRunTarget[NodeupSubContext](assetBuilder, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DryRunTarget[T]) ProcessDeletions() bool {
|
|
||||||
// We display deletions
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *DryRunTarget[T]) DefaultCheckExisting() bool {
|
func (t *DryRunTarget[T]) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -117,7 +112,7 @@ func (t *DryRunTarget[T]) Render(a, e, changes Task[T]) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DryRunTarget[T]) Delete(deletion Deletion[T]) error {
|
func (t *DryRunTarget[T]) RecordDeletion(deletion Deletion[T]) error {
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
defer t.mutex.Unlock()
|
defer t.mutex.Unlock()
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,6 @@ func (t *InstallTarget) Finish(taskMap map[string]fi.InstallTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *InstallTarget) ProcessDeletions() bool {
|
|
||||||
// We don't expect any, but it would be our job to process them
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *InstallTarget) DefaultCheckExisting() bool {
|
func (t *InstallTarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,11 +33,6 @@ func (t *LocalTarget) Finish(taskMap map[string]fi.NodeupTask) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *LocalTarget) ProcessDeletions() bool {
|
|
||||||
// We don't expect any, but it would be our job to process them
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *LocalTarget) DefaultCheckExisting() bool {
|
func (t *LocalTarget) DefaultCheckExisting() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,6 @@ type Target[T SubContext] interface {
|
||||||
// Lifecycle methods, called by the driver
|
// Lifecycle methods, called by the driver
|
||||||
Finish(taskMap map[string]Task[T]) error
|
Finish(taskMap map[string]Task[T]) error
|
||||||
|
|
||||||
// ProcessDeletions returns true if we should delete resources
|
|
||||||
// Some providers (e.g. Terraform) actively keep state, and will delete resources automatically
|
|
||||||
ProcessDeletions() bool
|
|
||||||
|
|
||||||
// DefaultCheckExisting returns true if DefaultDeltaRun tasks which aren't HasCheckExisting
|
// DefaultCheckExisting returns true if DefaultDeltaRun tasks which aren't HasCheckExisting
|
||||||
// should invoke Find() when running against this Target.
|
// should invoke Find() when running against this Target.
|
||||||
DefaultCheckExisting() bool
|
DefaultCheckExisting() bool
|
||||||
|
|
Loading…
Reference in New Issue