Merge pull request #16293 from justinsb/deletion_processing_mode

refactor: Introduce DeletionProcessingMode
This commit is contained in:
Kubernetes Prow Robot 2024-02-15 07:07:11 -08:00 committed by GitHub
commit 2e0115171d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 46 additions and 74 deletions

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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] {

View File

@ -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
} }
} }
} }

View File

@ -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)
} }

View File

@ -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()

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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