Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request - deletion support for custom ARM and Bicep templates #785

Closed
jleechpe opened this issue Mar 30, 2023 · 12 comments · Fixed by #861
Closed

Feature request - deletion support for custom ARM and Bicep templates #785

jleechpe opened this issue Mar 30, 2023 · 12 comments · Fixed by #861
Assignees
Milestone

Comments

@jleechpe
Copy link

Describe the bug
Bicep files that are deleted do not get processed by Invoke-AzOpsPush.

The command lists the files as being in a deleted state however no changes are proposed for -WhatIf or processed if told to execute.

The deletion process uses the git-diff of deleted files then turns each file into a single-line string of name+content (https://github.com/Azure/AzOps/blob/main/src/functions/Invoke-AzOpsPush.ps1#L218).

For JSON files this behaves as expected since converting to a single line maintains valid syntax.
BICEP files do not compress to a single line since each property expects to be on a single line (default+examples), or have the property+value comma separated from the next pair.

Steps to reproduce

  1. Use bicep to define and deploy a resource.
  2. Commit the bicep file and let the pipeline deploy the resource based on file addition
  3. Delete the bicep file and commit the deletion
  4. Pipeline indicates the file is deleted but no actions are taken
    • Transpiling the bicep file to JSON so it exists in the repo and then deleting the JSON file does successfully delete the resource
@daltondhcp
Copy link
Contributor

daltondhcp commented Mar 30, 2023

Thank you for raising the issue.
Currently, the deletion feature only works for autogenerated ARM templates due to the non-deterministic nature of custom templates (Bicep or ARM). It is certainly on our radar to implement this but nothing we have in our short-term plans. I will repurpose this issue to track this.

See further details at https://github.com/Azure/AzOps/wiki/ResourceDeletion

@daltondhcp daltondhcp changed the title Bug Report - Invoke-AzOpsPush fails to process deleted bicep files. Feature request - deletion support for custom ARM and Bicep templates Mar 30, 2023
@Jefajers Jefajers added this to the v2.6.0 milestone Jan 23, 2024
@Jefajers Jefajers self-assigned this Jan 23, 2024
@Xitric
Copy link
Contributor

Xitric commented Feb 15, 2024

@Jefajers I can see that you added this to the next milestone. I was wondering if you were going to utilize deployment stacks to support deletion of arbitrary template files, or if other approaches have been considered?

This is also something that is quite interesting for us.

@Jefajers
Copy link
Member

Hi @Xitric, we are not basing the feature logic on Deployment stacks since it is still in preview and lacks What-if support.

With that said, at some point when Deployment stacks become GA, changes to the feature might be prudent.

The current development of this feature is utilizing the AzOps modules existing capability to correlate template and parameter files and then utilize Azure's What-if API to parse resource id's within a given template and parameter combination.

Once those resource id's are derived by the What-if API we check for resource existence and then attempt resource deletion.

@Xitric
Copy link
Contributor

Xitric commented Feb 21, 2024

Thanks for clarifying the approach @Jefajers, I totally understand why you would wait with adopting deployment stacks.

I guess the what-if approach becomes best effort, unless they have dramatically improved the coverage of what-if recently. I remember there being edge cases where depending on the parameters you pass to a Bicep module, that module and its contents could become invisible to what-if.

However, if the coverage has been improved, then the approach definitely sounds very interesting.

@Jefajers
Copy link
Member

You are correct there are instances where content could become "invisible" to what-if. We consider ARM deployments with linked templates as such a scenario.

If you have some example of a bicep edge case and invisible what-if it would be of great assistance if you could share that so we could have a look.

Besides this ofc What-if has its own limits.

@Xitric
Copy link
Contributor

Xitric commented Feb 26, 2024

I think one of the primary obstacles with what-if is this: Azure/arm-template-whatif#157

The gist of it all is that use of non-deterministic computed properties and template strings can cause modules and their resources to become invisible to what-if. For instance, say we have a module for creating a key vault using a templated name:

// kv.bicep
param location string

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: 'kv${uniqueString(deployment().name)}'
  location: location
  properties: {
    tenantId: tenant().tenantId
    sku: {
      name: 'standard'
      family: 'A'
    }
  }
}

output kvName string = keyVault.name
output uri string = keyVault.properties.vaultUri

And a module using that key vault (for the sake of the example, creating a secret):

// secret.bicep
param kvName string

@secure()
param secretValue string

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
  name: kvName

  resource secret 'secrets' = {
    name: 'mySecret${deployment().name}'
    properties: {
      value: secretValue
    }
  }
}

Then performing a what-if operation on the main module will detect creation of secret b, but not of secret c or d:

// main.bicep
param location string = resourceGroup().location

module kv 'kv.bicep' = {
  name: 'a'
  params: {
    location: location
  }
}

module b 'secret.bicep' = {
  name: 'b'
  params: {
    kvName: 'kv${uniqueString('a')}'
    secretValue: 'secret'
  }
}

module c 'secret.bicep' = {
  name: 'c'
  params: {
    kvName: kv.outputs.kvName
    secretValue: 'secret'
  }
}

module d 'secret.bicep' = {
  name: 'd'
  params: {
    kvName: kv.outputs.kvName
    secretValue: kv.outputs.uri
  }
}

If we hard-code the name of the key vault in kv.bicep, both secret b and c are tracked by what-if, but secret d is still invisible due to the non-deterministic computed property vaultUri.

At least, that is my understanding. Now of course, this example would not pose an issue for deletion of resources, since the secrets are child resources of the key vault. But the issue exists generally.

@Jefajers
Copy link
Member

Jefajers commented Mar 1, 2024

Thanks for sharing, I see your point. To clarify this version of the feature is not targeting selective deletion of child resources.

This feature is targeting to enable deletion of entire resource with custom templates (none AzOps generated files) with Remove-AzResource, given your example above it would be the entire Key Vault.

Once we have this capability and see how it pans out, we could revisit this in the future and triage the child resource scenario.

@Xitric
Copy link
Contributor

Xitric commented Mar 1, 2024

@Jefajers The parent-child relationship was merely a coincidence of my example. As mentioned above:

Now of course, this example would not pose an issue for deletion of resources, since the secrets are child resources of the key vault. But the issue exists generally.

What I mean by the last sentence is that the modules c and d are invisible to what-if, not because they deploy child resources of the key vault, but because they reference a template string and a non-deterministic computed property respectively. If the c and d modules would deploy, say, an app service, then the app service would be invisible to what-if and hence not be deleted :)

@Jefajers
Copy link
Member

Jefajers commented Mar 4, 2024

Got it, the issue you linked to regarding ARM and values generated at execution time cause resources dependent on them to become “hidden” from WhatIf just as your example with a secretValue referencing previous computed output property.

This was what I failed to refer to with nested, linked templates my apologies for not being clear. This is a known behavior and dependency towards ARM that we already have today.

However, the impact during a deployment and inaccurate (hidden) WhatIf still results in a “complete” deployment.

The impact during resource “deletion” could instead be that you get the impression that removing main.bicep

  1. would not affect a particular resource since it would not be a part of the WhatIf output.
    and/or
  2. does not delete the referenced resource in Azure.

So if one looks at WhatIf from this lens, I do understand your statement before in regards to "what-if approach becomes best effor".

@justinmchase
Copy link

It would be cool if you could just add a deleted keyword similar to existing, such that resource its applied to would delete it if it exists and do nothing if it doesn't exist. You'd also require the user to remove all properties from the resource.

// kv.bicep
param location string

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = deleted {
  name: 'kv${uniqueString(deployment().name)}'
  location: location
}

@Jefajers
Copy link
Member

Hi @justinmchase, this type of logic extension in AzOps to accept manipulation of a bicep template and take actions on it, is not something we are considering at this time.

@justinmchase
Copy link

Might be worth considering in the future. I would definitely like to use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

5 participants