From 8f9bae31cb520ebe9ca17a12a7cfbed6d9c81347 Mon Sep 17 00:00:00 2001 From: Sam Eiderman Date: Thu, 20 Oct 2022 09:15:43 +0300 Subject: [PATCH 1/4] Add DeletedWith resource option In many cases there is no need to delete resources if the container resource is going to be deleted as well. A few examples: * Database object (roles, tables) when database is being deleted * Cloud IAM bindings when user itself is being deleted This helps with: * Speeding the deletion process * Removing unnecessary calls to providers * Avoiding failed deletions when the pulumi user running the plan has access to the container resource but not the contained ones To avoid deleting contained resources, set the `DeletedWith` resource option to the container resource. TODO: Should we support DeletedWith with PendingDeletes? Special case might be when the contained resource is marked as pending deletion but we now want to delete the container resource, so ultimately there is no need to delete the contained anymore --- sdk/Pulumi/Deployment/Deployment_RegisterResource.cs | 1 + sdk/Pulumi/PublicAPI.Shipped.txt | 2 ++ sdk/Pulumi/Resources/ResourceOptions.cs | 6 ++++++ sdk/Pulumi/Resources/ResourceOptions_Copy.cs | 3 ++- sdk/Pulumi/Resources/ResourceOptions_Merge.cs | 1 + 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs index 8b98fbe4..1f2d631e 100644 --- a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs +++ b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs @@ -91,6 +91,7 @@ private static void PopulateRequest(RegisterResourceRequest request, PrepareResu }, Remote = remote, RetainOnDelete = options.RetainOnDelete ?? false, + DeletedWith = options.DeletedWith ?? false, }; if (customOpts != null) diff --git a/sdk/Pulumi/PublicAPI.Shipped.txt b/sdk/Pulumi/PublicAPI.Shipped.txt index bdc89965..fa8c52b5 100644 --- a/sdk/Pulumi/PublicAPI.Shipped.txt +++ b/sdk/Pulumi/PublicAPI.Shipped.txt @@ -200,6 +200,8 @@ Pulumi.ResourceOptions.PluginDownloadURL.get -> string Pulumi.ResourceOptions.PluginDownloadURL.set -> void Pulumi.ResourceOptions.RetainOnDelete.get -> bool? Pulumi.ResourceOptions.RetainOnDelete.set -> void +Pulumi.ResourceOptions.DeletedWith.get -> Pulumi.Resource +Pulumi.ResourceOptions.DeletedWith.set -> void Pulumi.ResourceTransformation Pulumi.ResourceTransformationArgs Pulumi.ResourceTransformationArgs.Args.get -> Pulumi.ResourceArgs diff --git a/sdk/Pulumi/Resources/ResourceOptions.cs b/sdk/Pulumi/Resources/ResourceOptions.cs index 4cbc4a52..916a7cd8 100644 --- a/sdk/Pulumi/Resources/ResourceOptions.cs +++ b/sdk/Pulumi/Resources/ResourceOptions.cs @@ -123,5 +123,11 @@ public List ReplaceOnChanges /// If set to True, the providers Delete method will not be called for this resource. /// public bool? RetainOnDelete { get; set; } + + /// + /// If set, the providers Delete method will not be called for this resource + /// if specified resource is being deleted as well. + /// + public Resource? DeletedWith { get; set; } } } diff --git a/sdk/Pulumi/Resources/ResourceOptions_Copy.cs b/sdk/Pulumi/Resources/ResourceOptions_Copy.cs index 844c4eea..d3388be7 100644 --- a/sdk/Pulumi/Resources/ResourceOptions_Copy.cs +++ b/sdk/Pulumi/Resources/ResourceOptions_Copy.cs @@ -23,7 +23,8 @@ internal static TResourceOptions CreateCopy(ResourceOptions op Urn = options.Urn, Version = options.Version, PluginDownloadURL = options.PluginDownloadURL, - RetainOnDelete = options.RetainOnDelete + RetainOnDelete = options.RetainOnDelete, + DeletedWith = options.DeletedWith }; internal static CustomResourceOptions CreateCustomResourceOptionsCopy(ResourceOptions? options) diff --git a/sdk/Pulumi/Resources/ResourceOptions_Merge.cs b/sdk/Pulumi/Resources/ResourceOptions_Merge.cs index 5ec6ee11..f8b91ca7 100644 --- a/sdk/Pulumi/Resources/ResourceOptions_Merge.cs +++ b/sdk/Pulumi/Resources/ResourceOptions_Merge.cs @@ -15,6 +15,7 @@ internal static void MergeNormalOptions(ResourceOptions options1, ResourceOption options1.Provider = options2.Provider ?? options1.Provider; options1.CustomTimeouts = options2.CustomTimeouts ?? options1.CustomTimeouts; options1.RetainOnDelete = options2.RetainOnDelete ?? options1.RetainOnDelete; + options1.DeletedWith = options2.DeletedWith ?? options1.DeletedWith; options1.IgnoreChanges.AddRange(options2.IgnoreChanges); options1.ResourceTransformations.AddRange(options2.ResourceTransformations); From cc3bf66f745b8583c798180f919cf5c19405da37 Mon Sep 17 00:00:00 2001 From: Sam Eiderman Date: Mon, 31 Oct 2022 23:36:29 +0200 Subject: [PATCH 2/4] Check supported feature DeletedWith before using --- sdk/Pulumi/Deployment/Deployment.cs | 5 +++++ sdk/Pulumi/Deployment/Deployment_RegisterResource.cs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/sdk/Pulumi/Deployment/Deployment.cs b/sdk/Pulumi/Deployment/Deployment.cs index 4ad5d4d2..0b45a562 100644 --- a/sdk/Pulumi/Deployment/Deployment.cs +++ b/sdk/Pulumi/Deployment/Deployment.cs @@ -217,6 +217,11 @@ internal Task MonitorSupportsOutputValues() return MonitorSupportsFeature("outputValues"); } + internal Task MonitorSupportsDeletedWith() + { + return MonitorSupportsFeature("deletedWith"); + } + // Because the secrets feature predates the Pulumi .NET SDK, we assume // that the monitor supports secrets. } diff --git a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs index 1f2d631e..32596971 100644 --- a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs +++ b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs @@ -21,6 +21,10 @@ public partial class Deployment var label = $"resource:{name}[{type}]"; Log.Debug($"Registering resource start: t={type}, name={name}, custom={custom}, remote={remote}"); + if (options.DeletedWith != null && !(await MonitorSupportsDeletedWith().ConfigureAwait(false))) { + throw new Exception("The Pulumi CLI does not support the DeletedWith option. Please update the Pulumi CLI.") + } + var request = CreateRegisterResourceRequest(type, name, custom, remote, options); Log.Debug($"Preparing resource: t={type}, name={name}, custom={custom}, remote={remote}"); From f36b43dade8f8cc088e6f48295eddc809de6749d Mon Sep 17 00:00:00 2001 From: Fraser Waters Date: Fri, 4 Nov 2022 12:51:33 +0000 Subject: [PATCH 3/4] Add missing ; --- sdk/Pulumi/Deployment/Deployment_RegisterResource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs index 32596971..99a25e9c 100644 --- a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs +++ b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs @@ -22,7 +22,7 @@ public partial class Deployment Log.Debug($"Registering resource start: t={type}, name={name}, custom={custom}, remote={remote}"); if (options.DeletedWith != null && !(await MonitorSupportsDeletedWith().ConfigureAwait(false))) { - throw new Exception("The Pulumi CLI does not support the DeletedWith option. Please update the Pulumi CLI.") + throw new Exception("The Pulumi CLI does not support the DeletedWith option. Please update the Pulumi CLI."); } var request = CreateRegisterResourceRequest(type, name, custom, remote, options); From 0d634ac9dbc898e177af51a92bdbb8e9e8407a11 Mon Sep 17 00:00:00 2001 From: Fraser Waters Date: Fri, 4 Nov 2022 12:56:40 +0000 Subject: [PATCH 4/4] Fix CreateRegisterResourceRequest --- sdk/Pulumi/Deployment/Deployment_RegisterResource.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs index 99a25e9c..494bda92 100644 --- a/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs +++ b/sdk/Pulumi/Deployment/Deployment_RegisterResource.cs @@ -25,7 +25,7 @@ public partial class Deployment throw new Exception("The Pulumi CLI does not support the DeletedWith option. Please update the Pulumi CLI."); } - var request = CreateRegisterResourceRequest(type, name, custom, remote, options); + var request = await CreateRegisterResourceRequest(type, name, custom, remote, options); Log.Debug($"Preparing resource: t={type}, name={name}, custom={custom}, remote={remote}"); var prepareResult = await PrepareResourceAsync(label, resource, custom, remote, args, options).ConfigureAwait(false); @@ -68,11 +68,15 @@ private static void PopulateRequest(RegisterResourceRequest request, PrepareResu } } - private static RegisterResourceRequest CreateRegisterResourceRequest( + private async static Task CreateRegisterResourceRequest( string type, string name, bool custom, bool remote, ResourceOptions options) { var customOpts = options as CustomResourceOptions; var deleteBeforeReplace = customOpts?.DeleteBeforeReplace; + var deletedWith = ""; + if (options.DeletedWith != null) { + deletedWith = await options.DeletedWith.Urn.GetValueAsync("").ConfigureAwait(false); + } var request = new RegisterResourceRequest { @@ -95,7 +99,7 @@ private static void PopulateRequest(RegisterResourceRequest request, PrepareResu }, Remote = remote, RetainOnDelete = options.RetainOnDelete ?? false, - DeletedWith = options.DeletedWith ?? false, + DeletedWith = deletedWith, }; if (customOpts != null)