Azure / bicep

Bicep is a declarative language for describing and deploying Azure resources
MIT License
3.24k stars 748 forks source link

create proposal for "new or existing" pattern for resource creation #3252

Open alex-frankel opened 3 years ago

alex-frankel commented 3 years ago

Related to #3247

mgranell commented 3 years ago

For resources that do not like change (e.g. virtual machines, computerName properties/customData etc.), will this include the ability to not send through un-changed properties in the ARM template?

Alternatively, can this provide conditional capability to check for resource existence, combined with e.g. #387 to filter out attributes that cannot be sent once a resource has been created?

Agazoth commented 2 years ago

Any update on this?

We have VMs with customData, that have this issue. Initially we thought we cound do something like this:

resource exist 'Microsoft.Compute/virtualMachines@2021-07-01' existing = {
  name: vmName
}
var vmDoExists = length(exist.id) > 0

and then set the contentData to null if the resource existst - but it turns out, existing is set if the resource is deployed in the deployment - even if we set dependsOn [exist] on the vm resource. This means, that the method always nulls contentData even on new deployments.

bmoore-msft commented 2 years ago

For some clarity - this is not about checking to see if a resource exists at deployment time and altering the deployment. It's for a scenario where the user deploying the template makes a conscious decision to use an existing resource and providing the resourceId (or it's parts) prior to deployment.

Think of the scenario where the user wants put all VM boot diags in a particular storage account (rather than create a new one for every vm).

Agazoth commented 2 years ago

Let me also clarify the ussue.

When doing incremental deployments on Azure Virtual Desktop, the number of vms is often increased. When doing first deploy, a token is passed to customData. This is only required at first deploy and usually done by passing the token generated at runtime from the hostpool resource in the same deployment. When incrementing the number of vms and redeploying, the deployment fails, because customData cannot be updated.

Would it be possible to make bicep just warn on first-deploy-only properties and continue the deployment in stead of failing the entire deployment?

bmoore-msft commented 2 years ago

I'm with you... this issue is not aimed at solving that problem for you automatically - but providing a more elegant way for you to work with the resources in the language based on information passed in to the deployment (i.e. parameters).

In your case, you would pass in a parameter value that says whether or not this particular deployment is the first one and bicep would have simple patterns you can follow to choose the right path for those VMs.

The notion of a run-time capability to automatically discover state and change behavior from isn't idempotent - it's an anti-pattern in a declarative model... Unfortunately, not all resources appreciate this so we have this rock/hard place problem that really needs to be solved at the platform layer... so a slightly different issue than the title may suggest (which @alex-frankel may be able to fix)

alex-frankel commented 2 years ago

What we would want to enable is a code snippet like this:

var deployNewFoo = true

resource foo 'microsoft.foo/bar@2022-01-01' = if (deployNewFoo) {
  ...
} else existing {
  ...
}

output somePropFromEitherNewOrExisting string = foo.properties.baz

The main thing this enables is, like Brian said, allowing you to choose between creating/updating a resource or referencing an existing resource and then being allowed to use the same symbolic name (foo in this case).

This could also be extended to allow for two different property bags for a resource:

var deployNewFoo = true

resource foo 'microsoft.foo/bar@2022-01-01' = if (deployNewFoo) {
  name: 'foo'
  // properties for create/update if true
} else {
  name: 'baz'
  // properties for create/update if false
}

output somePropFromEitherNewOrExisting string = foo.properties.baz