Skip to content

Commit

Permalink
fix: Improved resiliency of removal logic (#3006)
Browse files Browse the repository at this point in the history
## Description

- Updated removal order as image templates must be removed before e.g.,
permissions are revoked
- Updated 'alreadyProcessed' logic to not accidently exclude resources
that contain a name as a substring, aber are an actual sub-resource
- Updated logic to fetch deployment operations as the previous logic did
also include 'existing' resources in specific situations. It's now using
REST and filters those out (i.e., 'read' Operations)
- Enabled the removal logic to deal with cases where no resources are
deployed (e.g., later utl modules)
- The logic now differentiates in between 'I can not find a deployment'
and 'I can find a deployment, but it has no resources linked' (before it
was only the former)
- Finally, the logic was slightly altered to not give up as soon as no
deployment is found, but instead try and find as many as possible and
only throw an exception after the removal logic ran end to end.

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |

[![avm.ptn.aca-lza.hosting-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.aca-lza.hosting-environment.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.aca-lza.hosting-environment.yml)

[![avm.ptn.ai-platform.baseline](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.ai-platform.baseline.yml)

[![avm.ptn.authorization.policy-assignment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.policy-assignment.yml)

[![avm.ptn.authorization.resource-role-assignment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.resource-role-assignment.yml)

[![avm.ptn.authorization.role-assignment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.authorization.role-assignment.yml)

[![avm.ptn.deployment-script.import-image-to-acr](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.deployment-script.import-image-to-acr.yml)

[![avm.ptn.finops-toolkit.finops-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.finops-toolkit.finops-hub.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.finops-toolkit.finops-hub.yml)

[![avm.ptn.lz.sub-vending](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.lz.sub-vending.yml)

[![avm.ptn.network.private-link-private-dns-zones](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.network.private-link-private-dns-zones.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.network.private-link-private-dns-zones.yml)

[![avm.ptn.policy-insights.remediation](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.policy-insights.remediation.yml)

[![avm.ptn.security.security-center](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.security.security-center.yml)

[![avm.res.aad.domain-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.aad.domain-service.yml)

[![avm.res.alerts-management.action-rule](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.alerts-management.action-rule.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.alerts-management.action-rule.yml)

[![avm.res.analysis-services.server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.analysis-services.server.yml)

[![avm.res.api-management.service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml)

[![avm.res.app-configuration.configuration-store](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app-configuration.configuration-store.yml)

[![avm.res.app.container-app](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.container-app.yml)

[![avm.res.app.job](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.job.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.job.yml)

[![avm.res.app.managed-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.app.managed-environment.yml)

[![avm.res.automation.automation-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.automation.automation-account.yml)

[![avm.res.batch.batch-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.batch.batch-account.yml)

[![avm.res.cache.redis](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cache.redis.yml)

[![avm.res.cdn.profile](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cdn.profile.yml)

[![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml)

[![avm.res.communication.communication-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.communication-service.yml)

[![avm.res.communication.email-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.communication.email-service.yml)

[![avm.res.compute.availability-set](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.availability-set.yml)

[![avm.res.compute.disk-encryption-set](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk-encryption-set.yml)

[![avm.res.compute.disk](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.disk.yml)

[![avm.res.compute.gallery](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.gallery.yml)

[![avm.res.compute.image](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.image.yml)

[![avm.res.compute.proximity-placement-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.proximity-placement-group.yml)

[![avm.res.compute.ssh-public-key](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.ssh-public-key.yml)

[![avm.res.compute.virtual-machine-scale-set](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine-scale-set.yml)

[![avm.res.compute.virtual-machine](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.compute.virtual-machine.yml)

[![avm.res.consumption.budget](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.consumption.budget.yml)

[![avm.res.container-instance.container-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml)
(unrelated)

[![avm.res.container-registry.registry](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-registry.registry.yml)

[![avm.res.container-service.managed-cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-service.managed-cluster.yml)

[![avm.res.data-factory.factory](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-factory.factory.yml)

[![avm.res.data-protection.backup-vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.data-protection.backup-vault.yml)

[![avm.res.databricks.access-connector](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.access-connector.yml)

[![avm.res.databricks.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.databricks.workspace.yml)

[![avm.res.db-for-my-sql.flexible-server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-my-sql.flexible-server.yml)

[![avm.res.db-for-postgre-sql.flexible-server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.db-for-postgre-sql.flexible-server.yml)

[![avm.res.desktop-virtualization.application-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.application-group.yml)

[![avm.res.desktop-virtualization.host-pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.host-pool.yml)

[![avm.res.desktop-virtualization.scaling-plan](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.scaling-plan.yml)

[![avm.res.desktop-virtualization.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.desktop-virtualization.workspace.yml)

[![avm.res.dev-test-lab.lab](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-test-lab.lab.yml)

[![avm.res.digital-twins.digital-twins-instance](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.digital-twins.digital-twins-instance.yml)
(unrelated)

[![avm.res.document-db.database-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.document-db.database-account.yml)

[![avm.res.event-grid.domain](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.domain.yml)

[![avm.res.event-grid.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.namespace.yml)

[![avm.res.event-grid.system-topic](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.system-topic.yml)

[![avm.res.event-grid.topic](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-grid.topic.yml)

[![avm.res.event-hub.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.event-hub.namespace.yml)

[![avm.res.health-bot.health-bot](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.health-bot.health-bot.yml)

[![avm.res.healthcare-apis.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.healthcare-apis.workspace.yml)

[![avm.res.hybrid-compute.machine](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.hybrid-compute.machine.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.hybrid-compute.machine.yml)

[![avm.res.insights.action-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.action-group.yml)

[![avm.res.insights.activity-log-alert](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.activity-log-alert.yml)

[![avm.res.insights.component](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.component.yml)

[![avm.res.insights.data-collection-endpoint](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-endpoint.yml)

[![avm.res.insights.data-collection-rule](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.data-collection-rule.yml)

[![avm.res.insights.diagnostic-setting](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.diagnostic-setting.yml)

[![avm.res.insights.metric-alert](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.metric-alert.yml)

[![avm.res.insights.private-link-scope](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.private-link-scope.yml)

[![avm.res.insights.scheduled-query-rule](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.scheduled-query-rule.yml)

[![avm.res.insights.webtest](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml)

[![avm.res.key-vault.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.key-vault.vault.yml)

[![avm.res.kubernetes-configuration.extension](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.extension.yml)

[![avm.res.kubernetes-configuration.flux-configuration](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kubernetes-configuration.flux-configuration.yml)

[![avm.res.kusto.cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kusto.cluster.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.kusto.cluster.yml)

[![avm.res.load-test-service.load-test](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.load-test-service.load-test.yml)

[![avm.res.logic.workflow](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.logic.workflow.yml)

[![avm.res.machine-learning-services.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.machine-learning-services.workspace.yml)

[![avm.res.maintenance.maintenance-configuration](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.maintenance.maintenance-configuration.yml)

[![avm.res.managed-identity.user-assigned-identity](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-identity.user-assigned-identity.yml)

[![avm.res.managed-services.registration-definition](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.managed-services.registration-definition.yml)

[![avm.res.management.management-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.management.management-group.yml)

[![avm.res.net-app.net-app-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml)

[![avm.res.network.application-gateway-web-application-firewall-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway-web-application-firewall-policy.yml)

[![avm.res.network.application-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-gateway.yml)

[![avm.res.network.application-security-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.application-security-group.yml)

[![avm.res.network.azure-firewall](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml)

[![avm.res.network.bastion-host](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.bastion-host.yml)

[![avm.res.network.connection](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.connection.yml)

[![avm.res.network.ddos-protection-plan](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ddos-protection-plan.yml)

[![avm.res.network.dns-forwarding-ruleset](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-forwarding-ruleset.yml)

[![avm.res.network.dns-resolver](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-resolver.yml)

[![avm.res.network.dns-zone](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.dns-zone.yml)

[![avm.res.network.express-route-circuit](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-circuit.yml)

[![avm.res.network.express-route-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.express-route-gateway.yml)

[![avm.res.network.firewall-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.firewall-policy.yml)

[![avm.res.network.front-door-web-application-firewall-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door-web-application-firewall-policy.yml)

[![avm.res.network.front-door](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.front-door.yml)

[![avm.res.network.ip-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.ip-group.yml)

[![avm.res.network.load-balancer](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.load-balancer.yml)

[![avm.res.network.local-network-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.local-network-gateway.yml)

[![avm.res.network.nat-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.nat-gateway.yml)

[![avm.res.network.network-interface](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-interface.yml)

[![avm.res.network.network-manager](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-manager.yml)

[![avm.res.network.network-security-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-security-group.yml)

[![avm.res.network.network-watcher](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.network-watcher.yml)

[![avm.res.network.private-dns-zone](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-dns-zone.yml)

[![avm.res.network.private-endpoint](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-endpoint.yml)

[![avm.res.network.private-link-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.private-link-service.yml)

[![avm.res.network.public-ip-address](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-address.yml)

[![avm.res.network.public-ip-prefix](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.public-ip-prefix.yml)

[![avm.res.network.route-table](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.route-table.yml)

[![avm.res.network.service-endpoint-policy](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.service-endpoint-policy.yml)

[![avm.res.network.trafficmanagerprofile](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.trafficmanagerprofile.yml)

[![avm.res.network.virtual-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-hub.yml)

[![avm.res.network.virtual-network-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network-gateway.yml)

[![avm.res.network.virtual-network](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml)

[![avm.res.network.virtual-wan](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-wan.yml)

[![avm.res.network.vpn-gateway](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-gateway.yml)

[![avm.res.network.vpn-site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.vpn-site.yml)

[![avm.res.operational-insights.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operational-insights.workspace.yml)

[![avm.res.operations-management.solution](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.operations-management.solution.yml)

[![avm.res.portal.dashboard](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.portal.dashboard.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.portal.dashboard.yml)

[![avm.res.power-bi-dedicated.capacity](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.power-bi-dedicated.capacity.yml)
(unrelated)

[![avm.res.purview.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.purview.account.yml)

[![avm.res.recovery-services.vault](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.recovery-services.vault.yml)

[![avm.res.relay.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.relay.namespace.yml)

[![avm.res.resource-graph.query](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resource-graph.query.yml)

[![avm.res.resources.deployment-script](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.deployment-script.yml)

[![avm.res.resources.resource-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.resources.resource-group.yml)

[![avm.res.search.search-service](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.search.search-service.yml)

[![avm.res.service-bus.namespace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-bus.namespace.yml)

[![avm.res.service-fabric.cluster](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.service-fabric.cluster.yml)

[![avm.res.signal-r-service.signal-r](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.signal-r.yml)

[![avm.res.signal-r-service.web-pub-sub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.signal-r-service.web-pub-sub.yml)

[![avm.res.sql.instance-pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.instance-pool.yml)

[![avm.res.sql.managed-instance](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.managed-instance.yml)

[![avm.res.sql.server](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.sql.server.yml)

[![avm.res.storage.storage-account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.storage.storage-account.yml)

[![avm.res.synapse.private-link-hub](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.private-link-hub.yml)

[![avm.res.synapse.workspace](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.synapse.workspace.yml)

[![avm.res.virtual-machine-images.image-template](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.virtual-machine-images.image-template.yml)

[![avm.res.web.connection](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.connection.yml)

[![avm.res.web.hosting-environment](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.hosting-environment.yml)
(unrelated)

[![avm.res.web.serverfarm](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.serverfarm.yml)

[![avm.res.web.site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.site.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.site.yml)

[![avm.res.web.static-site](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml/badge.svg?branch=users%2Falsehr%2FremovalResiliency&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.web.static-site.yml)

## Type of Change

<!-- Use the checkboxes [x] on the options that are relevant. -->

- [x] Update to CI Environment or utilities (Non-module affecting
changes)
- [ ] Azure Verified Module updates:
- [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT
bumped the MAJOR or MINOR version in `version.json`:
- [ ] Someone has opened a bug report issue, and I have included "Closes
#{bug_report_issue_number}" in the PR description.
- [ ] The bug was found by the module author, and no one has opened an
issue to report it yet.
- [ ] Feature update backwards compatible feature updates, and I have
bumped the MINOR version in `version.json`.
- [ ] Breaking changes and I have bumped the MAJOR version in
`version.json`.
  - [ ] Update to documentation
  • Loading branch information
AlexanderSehr authored Aug 12, 2024
1 parent e006349 commit 72b4d0c
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function Initialize-DeploymentRemoval {
# The initial sequence is a general order-recommendation
$RemoveFirstSequence = @(
'Microsoft.Authorization/locks',
'Microsoft.VirtualMachineImages/imageTemplates', # Must be removed before their MSI & should be removed before its entities permissions are removed
'Microsoft.Authorization/roleAssignments',
'Microsoft.Insights/diagnosticSettings',
'Microsoft.Network/privateEndpoints/privateDnsZoneGroups',
Expand All @@ -91,7 +92,6 @@ function Initialize-DeploymentRemoval {
'Microsoft.MachineLearningServices/workspaces',
'Microsoft.Compute/virtualMachines',
'Microsoft.ContainerInstance/containerGroups' # Must be removed before their MSI
'Microsoft.VirtualMachineImages/imageTemplates', # Must be removed before their MSI
'Microsoft.ManagedIdentity/userAssignedIdentities',
'Microsoft.Databricks/workspaces'
'Microsoft.Resources/resourceGroups'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,109 @@
#region helper
<#
.SYNOPSIS
Get all deployment operations at a given scope
.DESCRIPTION
Get all deployment oeprations at a given scope. By default, the results are filtered down to 'create' operations (i.e., excluding 'read' operations that would correspond to 'existing' resources).
.PARAMETER Name
Mandatory. The deployment name to search for
.PARAMETER ResourceGroupName
Optional. The name of the resource group for scope 'resourcegroup'. Relevant for resource-group-level deployments.
.PARAMETER SubscriptionId
Optional. The ID of the subscription to fetch deployments from. Relevant for subscription- & resource-group-level deployments.
.PARAMETER ManagementGroupId
Optional. The ID of the management group to fetch deployments from. Relevant for management-group-level deployments.
.PARAMETER Scope
Mandatory. The scope to search in
.PARAMETER ProvisioningOperationsToInclude
Optional. The provisioning operations to include in the result set. By default, only 'create' operations are included.
.EXAMPLE
Get-DeploymentOperationAtScope -Scope 'subscription' -Name 'v73rhp24d7jya-test-apvmiaiboaai'
Get all deployment operations for a deployment with name 'v73rhp24d7jya-test-apvmiaiboaai' at scope 'subscription'
.NOTES
This function is a standin for the Get-AzDeploymentOperation cmdlet, which does not provide the ability to filter by provisioning operation.
As such, it was also returning 'existing' resources (i.e., with provisioningOperation=Read).
#>
function Get-DeploymentOperationAtScope {

[CmdletBinding()]
param (
[Parameter(Mandatory)]
[Alias('DeploymentName')]
[string] $Name,

[Parameter(Mandatory = $false)]
[string] $ResourceGroupName,

[Parameter(Mandatory = $false)]
[string] $SubscriptionId,

[Parameter(Mandatory = $false)]
[string] $ManagementGroupId,

[Parameter(Mandatory = $false)]
[ValidateSet(
'Create', # any resource creation
'Read', # E.g., 'existing' resources
'EvaluateDeploymentOutput' # Nobody knows
)]
[string[]] $ProvisioningOperationsToInclude = @('Create'),

[Parameter(Mandatory)]
[ValidateSet(
'resourcegroup',
'subscription',
'managementgroup',
'tenant'
)]
[string] $Scope
)


switch ($Scope) {
'resourcegroup' {
$path = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Resources/deployments/{2}/operations?api-version=2021-04-01' -f $SubscriptionId, $ResourceGroupName, $name
break
}
'subscription' {
$path = '/subscriptions/{0}/providers/Microsoft.Resources/deployments/{1}/operations?api-version=2021-04-01' -f $SubscriptionId, $name
break
}
'managementgroup' {
$path = '/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Resources/deployments/{1}/operations?api-version=2021-04-01' -f $ManagementGroupId, $name
break
}
'tenant' {
$path = '/providers/Microsoft.Resources/deployments/{0}/operations?api-version=2021-04-01' -f $name
break
}
}

##############################################
# Get all deployment children based on scope #
##############################################

$response = Invoke-AzRestMethod -Method 'GET' -Path $path

if ($response.StatusCode -ne 200) {
Write-Error ('Failed to fetch deployment operations for deployment [{0}] in scope [{1}]' -f $name, $scope)
return
} else {
$deploymentOperations = ($response.content | ConvertFrom-Json).value.properties
$deploymentOperationsFiltered = $deploymentOperations | Where-Object { $_.provisioningOperation -in $ProvisioningOperationsToInclude }
return $deploymentOperationsFiltered ?? $true # Returning true to indicate that the deployment was found, but did not contain any relevant operations
}
}

<#
.SYNOPSIS
Get all deployments that match a given deployment name in a given scope
Expand Down Expand Up @@ -63,10 +168,18 @@ function Get-DeploymentTargetResourceListInner {
##############################################
# Get all deployment children based on scope #
##############################################
$baseInputObject = @{
Scope = $Scope
DeploymentName = $Name
}
switch ($Scope) {
'resourcegroup' {
if (Get-AzResourceGroup -Name $resourceGroupName -ErrorAction 'SilentlyContinue') {
[array]$deploymentTargets = (Get-AzResourceGroupDeploymentOperation -DeploymentName $name -ResourceGroupName $resourceGroupName).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique
if ($op = Get-DeploymentOperationAtScope @baseInputObject -ResourceGroupName $resourceGroupName -SubscriptionId $currentContext.Subscription.Id) {
[array]$deploymentTargets = $op.TargetResource.id | Where-Object { $_ -ne $null } | Select-Object -Unique
} else {
throw 'NoDeploymentFound'
}
} else {
# In case the resource group itself was already deleted, there is no need to try and fetch deployments from it
# In case we already have any such resources in the list, we should remove them
Expand All @@ -75,15 +188,27 @@ function Get-DeploymentTargetResourceListInner {
break
}
'subscription' {
[array]$deploymentTargets = (Get-AzDeploymentOperation -DeploymentName $name).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique
if ($op = Get-DeploymentOperationAtScope @baseInputObject -SubscriptionId $currentContext.Subscription.Id) {
[array]$deploymentTargets = $op.TargetResource.id | Where-Object { $_ -ne $null } | Select-Object -Unique
} else {
throw 'NoDeploymentFound'
}
break
}
'managementgroup' {
[array]$deploymentTargets = (Get-AzManagementGroupDeploymentOperation -DeploymentName $name -ManagementGroupId $ManagementGroupId).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique
if ($op = Get-DeploymentOperationAtScope @baseInputObject -ManagementGroupId $ManagementGroupId) {
[array]$deploymentTargets = $op.TargetResource.id | Where-Object { $_ -ne $null } | Select-Object -Unique
} else {
throw 'NoDeploymentFound'
}
break
}
'tenant' {
[array]$deploymentTargets = (Get-AzTenantDeploymentOperation -DeploymentName $name).TargetResource | Where-Object { $_ -ne $null } | Select-Object -Unique
if ($op = Get-DeploymentOperationAtScope @baseInputObject) {
[array]$deploymentTargets = $op.TargetResource.id | Where-Object { $_ -ne $null } | Select-Object -Unique
} else {
throw 'NoDeploymentFound'
}
break
}
}
Expand Down Expand Up @@ -235,30 +360,35 @@ function Get-DeploymentTargetResourceList {
if (-not [String]::IsNullOrEmpty($ManagementGroupId)) {
$innerInputObject['ManagementGroupId'] = $ManagementGroupId
}

[array]$targetResources = Get-DeploymentTargetResourceListInner @innerInputObject
if ($targetResources.Count -gt 0) {
Write-Verbose ('Found & resolved deployment [{0}]' -f $deploymentNameObject.Name) -Verbose
try {
$targetResources = Get-DeploymentTargetResourceListInner @innerInputObject
Write-Verbose ('Found & resolved deployment [{0}]. [{1}] resources found to remove.' -f $deploymentNameObject.Name, $targetResources.Count) -Verbose
$deploymentNameObject.Resolved = $true
$resourcesToRemove += $targetResources
} catch {
$remainingDeploymentNames = ($deploymentNameObjects | Where-Object { -not $_.Resolved }).Name
Write-Verbose ('No deployment found by name(s) [{0}] in scope [{1}]. Retrying in [{2}] seconds [{3}/{4}]' -f ($remainingDeploymentNames -join ', '), $scope, $searchRetryInterval, $searchRetryCount, $searchRetryLimit) -Verbose
Start-Sleep $searchRetryInterval
$searchRetryCount++
}
}

# Break check
if ($deploymentNameObjects.Resolved -notcontains $false) {
break
}
} while ($searchRetryCount -le $searchRetryLimit)

if ($searchRetryCount -gt $searchRetryLimit) {
$remainingDeploymentNames = ($deploymentNameObjects | Where-Object { -not $_.Resolved }).Name
Write-Verbose ('No deployment found by name(s) [{0}] in scope [{1}]. Retrying in [{2}] seconds [{3}/{4}]' -f ($remainingDeploymentNames -join ', '), $scope, $searchRetryInterval, $searchRetryCount, $searchRetryLimit) -Verbose
Start-Sleep $searchRetryInterval
$searchRetryCount++
} while ($searchRetryCount -le $searchRetryLimit)

if (-not $resourcesToRemove) {
Write-Warning ('No deployment target resources found for [{0}]' -f ($DeploymentNames -join ', '))
return @()
# We don't want to outright throw an exception as we want to remove as many resources as possible before failing the script in the calling function
return @{
resolveError = ('No deployment for the deployment name(s) [{0}] found' -f ($remainingDeploymentNames -join ', '))
resourcesToRemove = $resourcesToRemove
}
}
return @{
resourcesToRemove = $resourcesToRemove
}

return $resourcesToRemove
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,21 @@ function Remove-Deployment {
if (-not [String]::IsNullOrEmpty($ManagementGroupId)) {
$deploymentsInputObject['ManagementGroupId'] = $ManagementGroupId
}
$deployedTargetResources += Get-DeploymentTargetResourceList @deploymentsInputObject

if ($deployedTargetResources.Count -eq 0) {
throw 'No deployment target resources found.'
}
# In case the function also returns an error, we'll throw a corresponding exception at the end of this script (see below)
$resolveResult = Get-DeploymentTargetResourceList @deploymentsInputObject
$deployedTargetResources += $resolveResult.resourcesToRemove
}

[array] $deployedTargetResources = $deployedTargetResources | Select-Object -Unique

Write-Verbose ('Total number of deployment target resources after fetching deployments [{0}]' -f $deployedTargetResources.Count) -Verbose

if (-not $deployedTargetResources) {
# Nothing to do
return
}

# Pre-Filter & order items
# ========================
$rawTargetResourceIdsToRemove = $deployedTargetResources | Sort-Object -Culture 'en-US' -Property { $_.Split('/').Count } -Descending | Select-Object -Unique
Expand All @@ -121,10 +125,6 @@ function Remove-Deployment {
[array] $resourcesToRemove = Get-ResourceIdsAsFormattedObjectList -ResourceIds $rawTargetResourceIdsToRemove
Write-Verbose ('Total number of deployment target resources after formatting items [{0}]' -f $resourcesToRemove.Count) -Verbose

if ($resourcesToRemove.Count -eq 0) {
return
}

# Filter resources
# ================

Expand Down Expand Up @@ -172,6 +172,11 @@ function Remove-Deployment {
} else {
Write-Verbose 'Found [0] resources to remove'
}

# In case any deployment was not resolved as planned we finally want to throw an exception to make this visible in the pipeline
if ($resolveResult.resolveError) {
throw ('The following error was thrown while resolving the original deployment names: [{0}]' -f $resolveResult.resolveError)
}
}

end {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function Remove-ResourceListInner {

foreach ($resource in $resourcesToRemove) {
$resourceName = Split-Path $resource.resourceId -Leaf
$alreadyProcessed = $processedResources.count -gt 0 ? (($processedResources | Where-Object { $resource.resourceId -like ('{0}*' -f $_) }).Count -gt 0) : $false
$alreadyProcessed = $processedResources.count -gt 0 ? (($processedResources | Where-Object { $resource.resourceId -like ('{0}/*' -f $_) }).Count -gt 0) : $false

if ($alreadyProcessed) {
# Skipping
Expand Down Expand Up @@ -130,6 +130,6 @@ function Remove-ResourceList {
if ($resourcesToRetry.Count -gt 0) {
throw ('The removal failed for resources [{0}]' -f ((Split-Path $resourcesToRetry.resourceId -Leaf) -join ', '))
} else {
Write-Verbose 'The removal completed successfully'
Write-Verbose ('The removal of the [{0}] completed successfully' -f $ResourcesToRemove.Count)
}
}

0 comments on commit 72b4d0c

Please sign in to comment.