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

Proposal: versioning of types for Azure #6641

Closed
rynowak opened this issue Apr 24, 2022 · 20 comments
Closed

Proposal: versioning of types for Azure #6641

rynowak opened this issue Apr 24, 2022 · 20 comments
Labels
enhancement New feature or request Needs: Author Feedback Awaiting feedback from the author of the issue types

Comments

@rynowak
Copy link
Contributor

rynowak commented Apr 24, 2022

Versioning of types for Azure

This is a propose to revamp the versioning of Azure's types as part of Bicep and the use of API versions in code. Have you thought much about resource types in Bicep? The definitions of Azure's types change over time as:

  • New types are added
  • New versions are added
  • Existing type/versions have bugs fixed or documentation added

These type definitions are used to power the compiler's validation and the completion/documentation features of the editor. Right now these type definitions are shipped as as part of the compiler, so you only get updates to Azure's type definitions when the team updates the compiler/language.

As Bicep matures further we're planning to:

  • Introduce an extensibility model so "providers" can be built (examples: Kubernetes, AAD, Storage)
  • Ship updates to Azure's resource types on a separate schedule from updates to the language and compiler

Decoupling the versioning of Azure's types from the compiler presents an opportunity to streamline the experience of working with Azure API versions for users. The goal of this proposal is to simplify the authoring and maintenance of Bicep files by reducing the number of places API versions need to be configured, while also introducing the flexibility we need to ship the compiler and extensibility features.

While developing the proposal for how to package and version Azure's types, it occurred to us that most users could rely on the versioning of the types package and reduce the number of places they have to choose a version. Azure API guidelines should provide enough stability that we feel comfortable simplifying the guidance and default behavior, while still supporting explicit API versions for exact control.

This proposal should result in the following simplified guidance for users:

  • Avoid specifying the API version on a resource unless you have a reason to do so.
  • Use the latest version of the az types when you author the file. Feel free to update this on your own cadence with confidence that the upgrades are safe.

Proposal

As we're adding extensibility, we're thinking about a provider model whether each provider has its own versioning. It's possible to think about Azure's types using this framework as the az provider.

This proposal changes the az provider from automatically-imported to opt-in - and will automatically assign the API versions of Azure resources based on the version of the provider. This should result in an import az ... statement in most files, but overall will reduce the concept count and number of places that versions appear.

This proposal makes the following language changes:

  • An import az ... declaration will be required to access Azure resource types.
  • The import az ... declaration will be used to configuration the version of az provider.
  • Azure resource declarations can now automatically select the best API Version version based on the version of the az provider.
  • The import az ... configuration block will be used to configure the target scope. This replaces the dedicated targetScope statement.

Note: we're still deciding on the best syntax for this. See the comments for some of the options we're considering. While this is still being considered, the examples in this issue will use import '[email protected] - az is the provider name, and 0.6.0 is the version. We would love input on this.

Example Before/After

This sample deploys a storage account, server farm, and website. This is taken from the following documentation here. This sample is a resource-group scoped deployment and uses the implicit default of targetScope = 'resourceGroup'.

Before

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-08-01' = {
  name: 'toylaunchstorage'
  location: 'westus3'
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

resource appServicePlan 'Microsoft.Web/serverFarms@2021-03-01' = {
  name: 'toy-product-launch-plan-starter'
  location: 'westus3'
  sku: {
    name: 'F1'
  }
}

resource appServiceApp 'Microsoft.Web/sites@2021-03-01' = {
  name: 'toy-product-launch-1'
  location: 'westus3'
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
  }
}

Note that version numbers appear as part of every type declaration. The user had to select a version of each resource type to type out this file, whether they have a strong opinion about which version to use or not.

We've been looking for a long time for ways to simplify interactions with API versions when authoring Bicep files. While API versioning is important as a mechanism, making a specific version choice often feels arbitrary.

After

import '[email protected]'

resource storageAccount 'Microsoft.Storage/storageAccounts' = {
  name: 'toylaunchstorage'
  location: 'westus3'
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

resource appServicePlan 'Microsoft.Web/serverFarms' = {
  name: 'toy-product-launch-plan-starter'
  location: 'westus3'
  sku: {
    name: 'F1'
  }
}

resource appServiceApp 'Microsoft.Web/sites' = {
  name: 'toy-product-launch-1'
  location: 'westus3'
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
  }
}

Note that are there is one and only one version number in the file - the version of the az provider. The user does not need to choose a separate version of each resource type - they get a recommended version by default.

The after version of the sample should result in the same compilation output as the before version - assuming a hypothetical 0.6.1 version of the Bicep az provider.

Details of the proposal

Import az

The import 'az@<version>' declaration becomes required to resolve Azure's resource types. We'll be able to provide a version selection/completion experience in the editor so users don't need to memorize version numbers.

Note: we're still deciding on the best syntax for this. See the comments for some of the options we're considering. While this is still being considered, the examples in this issue will use import '[email protected] - az is the provider name, and 0.6.0 is the version. We would love input on this.

Without the import 'az@<version>' declaration, Azure types would produce a diagnostic with a compiler fix to add the provider. This is similar to the experience in a language like C# when you type in a reference to a type without its using statement.

API Versions

import 'az@<version>' will include a version as required configuration. The code-fix described above would automatically choose the latest available version.

Since the version of the az provider is pinned for the file by the import declaration, we are able to simplify the resource declarations. The az provider will designate a stable API version for each resource type. A resource declaration may specify an API version explicitly; otherwise the corresponding stable version will be used. Users are free to specify the version if they want to choose something different - in particular if they want to choose a preview version

import '[email protected]'

// Users are still free to specify the API version explicitly
resource appServicePlan 'Microsoft.Web/serverFarms@2021-03-01' = {
  name: 'toy-product-launch-plan-starter'
  location: 'westus3'
  sku: {
    name: 'F1'
  }
}

// This will result in the *stable* version of 2021-03-01 based on the provider
resource appServiceApp 'Microsoft.Web/sites' = {
  name: 'toy-product-launch-1'
  location: 'westus3'
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
  }
}

Note: There may be cases where the team special-cases a specific API version as the stable version of for a resource type. In general the stable version will be the latest non-preview release at the time the provider was updated.

Hovering over a declaration in VS Code will include the API version in the tooltip. The API versions are still there, you just don't need to spend time on them unless you have a reason.

This change removes a concept from the process of adding a resource to the file. Having already declared the provider version you no longer need to choose an API Version when adding a resource.

Versioning of the Provider

The az provider (and all providers) will follow a versioning scheme similar to semantic versioning. Azure's API guidelines prevent teams from making breaking changes to their APIs - even when they introduce new API versions - so major version releases will be rare.

Upgrading the version of the az provider will upgrade the effective API version of resources in the file - and we do not consider this a breaking-change. A live at HEAD philosophy for versioning makes it easy for users to discover and use new features without having to guess at the right API version. We expect these upgrades to be safe, based on Azure's policies for API governance.

Target Scope

The selection of target scope will also be part of the configuration of the az provider instead of a language keyword/statement.

import '[email protected]' { 
  targetScope: 'subscription' 
}

This simplifies the language by removing a statement. As part of the work to introduce extensibility we're adding the ability for a provider to specify strongly-typed configuration. targetScope is better suited for this feature rather than being a feature built into the language. resourceGroup will still be the default, so most files will not need this configuration.

We will make this change at the same time we introduce import az to make the migration easier for users.

Integration Process

This will be a breaking change to Bicep as we're removing a language keyword and also changing the type resolution rules. If we make this change, will roll it out gradually over several releases and driven by our tools to reduce the cost for users to migrate.

We would first introduce a warning when Azure types are used without the import or when the targetScope statement is used. This will come with a code fix to add the import statement using the latest types package and the existing value of targetScope. We will ship Bicep in this state for a 1-2 releases and gather feedback on the new design. During this period the old design and new design will exist side-by-side and it is up to users to update at their own pace. Since this is just a warning, users will have the ability to suppress or ignore the diagnostic.

Once we're confident that the new design is having the desired impact we will remove support for the old design in a future release. The mandatory change for users is to add import 'az@<version>' and replace the targetScope statement. It's up to users to choose whether they want to un-pin their resource declarations - both styles will be valid.

FAQ

Q: Why not use a configuration file for this? We can support this in the future via a config file if that is desired. It seems more actionable for us to do this first via Bicep because we have the ability to do code-fixes and display warnings easily. We don't want to make a configuration file required to use Bicep so code is the logical starting point.

Q: Why are you using semver for provider versioning? We wanted to avoid using dates for versioning of the provider because they feel arbitrary. Users are more familiar with semver as a set of principles.

Q: Will you require an exact version to be specified or will you allow floating versions? Right now we plan to require explicit versions to be specified. We want to avoid any situation where deployments of Bicep code are non-repeatable - your files and configuration should result in the same behavior 6 months from now. This is similar to why we don't allow the API versions of resources to float today in Bicep code.

It's likely that if we introduced floating versions we'd also need to introduce a lock file - similar to NPM's package-lock.json to make things repeatable. This adds a lot of complexity for new users, and we want to make sure a single-file works well for Bicep.

If we roll out this proposal this is definitely an area where we will want feedback.

Q: What happens when I upgrade/downgrade the az Provider? Changing the version of the az provider may change the versions of the resources declared in the file - but this is always the result of a conscious choice from the user to make a change. If users prefer the old approach they are free to pin the version of each resource.

Q: How does this interact with modules? Each module is understood separately by the compiler and can version independently. There's no problem with using many different versions of az across modules.

Q: How will you distribute versions of the Azure types (or other extensibility)? We plan to host these using OCI artifacts like the module gallery.

Q: What will happen if I have no internet connection? The tools will be able to use cached versions of the az types but will require an internet connection to download new versions. It's likely we'll implement a fallback code path that behaves reasonably in the event that you cannot resolve the right version. We don't want the tools to fail completely in this case.

@ghost ghost added the Needs: Triage 🔍 label Apr 24, 2022
@rynowak
Copy link
Contributor Author

rynowak commented Apr 24, 2022

Options for import syntax

We want feedback on the best syntax for imports and versions.

The solution we choose needs to meet the following requirements:

  • Needs to support a great tooling experience so we can do things to auto-complete versions
  • Needs to match conceptually with other Bicep constructs
  • Needs to feel right based on user's subjective opinions

Inputs

We want imports to be able to specify all of the following:

  • A provider name - eg: az for Azure
  • A provider alias (ability to rename a provider)- eg: import kubernetes as my_cluster
  • A provider version
  • A configuration block - eg: set the targetScope for Azure, or set the kubernetes credentials

As an added detail, sometimes some of this information needs to be design-time constant, meaning the compiler needs to be able to compute the value to provide the right tooling experience. The version of a provider or the targetScope for Azure fit in into this category, the tools need to know the values of these.

Options

Here's some of the options we talked through while writing this proposal. More suggestions are welcome!

Option 1

import '[email protected]' as azure
import '[email protected]' as azure {
  targetScope: 'subscription'
}

This proposal uses a string to specify both the provider and version. We'd still be able to provide completion here for the version like we can do with API versions on resources.

What I like about this proposal is that it uses existing syntax (@version). What I dislike is inconsistency with existing syntax - az is actually a symbol/variable that's being introduced.

Option 2

import az with '0.6.0'
import az with '0.6.0' as azure
import az with '0.6.0' as azure {
  targetScope: 'subscription'
}

This proposal introduces a new contextual keyword with to specify a version.

What I like about this proposal is that it solves the string/symbol confusion.

What I dislike about this proposal is that the ordering of with and as is ambiguous. If we have both of these clauses, is there a specific order that has to be enforced? This could be confusing.

Option 3

import az { version: '0.6.0 }
import az as azure { version: '0.6.0 }
import az as azure { 
  version: '0.6.0 
  targetScope: 'subscription'
}

This option makes the configuration block mandatory and used to specify the version.

What I like about this proposal is that it doesn't introduce any new constructs, and lets the configuration block do the work. We know that we'll need a configuration block for some use cases. If we do this one we might want to do single-line-objects as well to streamline it.


Based on that option we also mapped out a few variants:

3A

import az { version: '0.6.0 }

3B

import az = { version: '0.6.0 }

3C

import az with { version: '0.6.0 }

@skeeler
Copy link

skeeler commented Apr 29, 2022

Suggestion: add support for import az@latest to specify the latest available version

@skeeler
Copy link

skeeler commented Apr 29, 2022

Suggestion: while you're adding the import keyword, consider adding a location keyword (at same top-level scope) that can be used to specify a default location attribute value for resources (if none explicitly given). Quite often the same location attribute is used repeatedly throughout many resources, so it would be convenient to be able to specify it just once. Not strictly related to the version but related in terms of file scope keywords.

@pacodelacruz
Copy link

While I like the idea of removing complexity, I believe that this change can introduce undesired complexities.

Undesired complexity 1:
Now as a developer, I need to understand the mapping of the Azure provider (e.g. '[email protected]') to the hundreds of RP APIs latest versions for that provider release.

Undesired complexity 2:
Let's say we want to maintain a large bicep file that was created a year ago. I need to update an azure resource to introduce new service capabilities.
Happy path: I update the import statement to the latest Azure provider version, and update the one Azure service to make use of the new resource properties. Everything else works as expected.
Unhappy path: I update the import statement to the latest Azure provider version, and when I try to update the one Azure service to make use of the new resource properties, I receive errors and warnings in the other multiple services due to breaking changes in multiple APIs. Now I need to also think of complexity 1 and review documentation for each RP and API version.

Unsure if making this import optional would make things better or not.

@rjygraham
Copy link

I like this proposal and the decoupling of Bicep compiler releases from the Azure type updates.

My preference is Option 3:

import az as azure { 
  version: '0.6.0 
  targetScope: 'subscription'
}

This particular syntax feels the most native to Bicep AND sets up for future extensibility.

Concern

Having said that, while removing the need to include API versions with the declared resource is a benefit, I do agree with the concerns raised by the community members in the April Community Call.

Many customers, especially those in regulated industries (Financial Services, Healthcare, etc), will need/want control over the versions of the types that are deployed (especially if the service version is public preview). To do this properly, these customers would author Azure Policy to deny the deployment of unapproved resources or versions of resources.

However, this can lead to a poor authoring/deployment experience given the following scenario:

  1. A customer engineering team is using '[email protected]' and not explicitly setting resource versions in their Bicep files
  2. A new Azure service has GAd, customer's security team approves of the service, customer engineering team updates Bicep to '[email protected]' to get access to new GAd service
  3. Customer engineering team experiences deployment failures due to existing resources implicitly using latest resource API version which has been blocked via Azure Policy by customer security team
  4. Customer engineering team wastes several hours trying to track down why a previous deployment that succeeded is now failing despite no code changes to that part of the template

Suggestion

Enable defining allowed/disallowed resource types and versions in an external configuration file. This file could be managed by a central team and pushed to Bicep module registry when changes occur.

Benefits

  1. Avoids the scenario outlined above
  2. "Push left" the feedback loop of authoring and deploying. An engineering team would now get warnings in their Bicep file that a resource or version is not allowed vs finding out only at time of deployment
  3. Would allow teams to automatically take advantage of new resource types and resource API versions as they are vetted and approved by security/risk teams

@slavizh
Copy link
Contributor

slavizh commented May 5, 2022

As far as I understand this will be optional in addition to the current method we use. If that is the case I do not have anything against this being implemented but I think it would be useful only if it works properly and the following things are present:

  • import is done per provider instead of importing every provider in Azure. For example instead of import [email protected], it should be import [email protected], import [email protected], etc.
  • Detailed change log to be provided for every version. This means not only that you document that for example microsoft.compute/virtualMachines was increased from 2020-01-01 to 2020-06-01 but also if there are new properties added/removed in those RPs, default values changed, etc. Basically the changes happening on API level
  • Ability to define your own version on resource even if import for specific version is defined
  • the API version is exposed somewhere - for example on hover over the resource. If the version is not seen inside the compiled ARM template information should be added in the metadata of the compiled template.

From proposed syntax option 3 seems the best from all proposed.

About the breaking change for targetScope. Would be nice if there are a few versions that allows you to have the old way and the new way at the same time. That way you can migrate over time without having to be stuck at particular version.

@majastrz
Copy link
Member

We also need to consider how pulling in types from private registries will work. Having that capability will help with:

  • Internal RPs and private preview RPs (although this may require additional semantics for "appending" types to an already imported provider)
  • Validation of types themselves (whether for the az provider or others)

@alex-frankel
Copy link
Collaborator

Some notes from Wednesday's discussion:

  • We are closed on the syntax for target scope:
import az {
  targetScope: 'subscription'
}
  • We still need to close on the syntax to express the version of types and the syntax. This will be discussed in the next Bicep discussion (probably on wednesday, I will be OOF on Monday). Once we have closed on this syntax, we can start implementation of all of these changes.
  • We are good starting the process for introducing the new syntax for target scope (once we have closed on the version)
    • this will follow how we've done other breaking changes (introduce the new syntax while still supporting the old one for at least one release)
  • We are not ready to introduce the breaking change for not importing az by default. This means that, when we release this new syntax, we will always still import az and we will pull the latest types wherever they exist.
    • It also means that resource will require their own api version unless the az provider has been configured with a specific version. It will remain possible to import az and not configure a specific version. If you have not configured a version and a resource type does not specify its own version, this will result in an error.

@brwilkinson
Copy link
Collaborator

Adding a comment here to ensure there is some symmetry in style between the following:

  • Resource Provider Type versions (discussed above)
  • Module version references to/from registry (not discussed above)

@shenglol
Copy link
Contributor

shenglol commented Sep 24, 2022

We are finally closed on the provider version syntax:

import 'az@v1'
import 'kubernetes@v2'

We also revisited the syntax for setting target scope type, and made some updates since last time (#6641 (comment)). The new syntax looks like this:

import 'az@v1' with {
  scopeType: 'subscription'
}

The main difference is that a with keyword is added a separator between the provider and the configuration object. In the future, the with keyword may also be used to override object literals.

Another change is that now scopeType can take an array of scopes, so that users may use the common resource types available from those scopes, for example:

// main.bicep
import 'az@v1' with {
  scopeType: ['resourceGroup', 'subscription']
}

resource roleAssignment 'Microsoft.Authorization/roleAssignment@2020-01-01' = { ... }

We also explored some alternative options for supporting multiple target scopes, but they each have some major drawbacks. For transparency, I would like to share the options:

Union import

import 'az/resourceGroup@v1' | 'az/subscription@v1'

Import decorator

@[sys.]config({
  scopeType: ['resourceGroup', 'subscription]
})
import 'az@v1'

Exact import

import 'az/resourceGroupOrSubscription@v1'

Implicit scope type

import 'az@v1' // scope types(s) is inferred by checking what resource types are declared in the module.

If you find some of the options particularly interesting and wonder why we did not choose it, feel free to comment and I'd be happy to explain the reason in detail 🙂.

@slavizh
Copy link
Contributor

slavizh commented Sep 26, 2022

I still would like to see importing version by specific provider. For example I would only want to specify the version for Virtual Machines provider rather for the whole Az.

Array of scopes is good.

@shenglol
Copy link
Contributor

For example I would only want to specify the version for Virtual Machines provider rather for the whole Az

One thing I'm not sure about this approach is that API versions are bound to resource types, not Azure resource providers. For example, virtual machine has an API version 2021-01-01, but virtual machine extension may not.

@slavizh
Copy link
Contributor

slavizh commented Sep 29, 2022

@shenglol that is true but also az@v1 is not API version like 2021-01-01. So let's say if you define az.compute/virtualMachines@v1, v1 will contain different API versions for each resource under microsoft.compute/virtualMachines.

@shenglol
Copy link
Contributor

shenglol commented Sep 29, 2022

Got it, this makes more sense to me now. I thought the proposal was to use an API version as the import version, like az.compute/virtualMachines@2021-01-01. I think sub namespace import can be a useful feature, but I'd prefer putting the namespace after the version:

import 'az@v1/Microsoft.Compute'

resource vm 'virtualMachines@2021-01-01' = { ... }

However, we'll need to understand the implication on scopeType, since scopeType is now limited by the namespace.

Setting scopeType to a scope other than resource group for Microsoft.Compute should be cause an error and be blocked:

import 'az@v1/Microsoft.Compute' with {
  scopeType: 'managementGroup'
}

Selecting scopeType for namespaces such as Microsoft.Authorization and Microsoft.Blueprint could work:

import 'az@v1/Microsoft.Authorization' with {
  scopeType: 'subscription'
}

import 'az@v1/Microsoft.Blueprint' with {
  scopeType: 'subscription'
}

, but having to override the scopeType for every import seems verbose, which makes me think that implicit scope type is a better solution in this case.

Another thing we might want to think about is the influence on import aliases. For example, if there are multiple namespaces imported in a module, it might not make sense to set aliases for both imports:

import 'az@v1/Microsoft.Compute' as az
import 'az@v1/Microsoft.Network' as az // ???

@ChristopherGLewis
Copy link
Contributor

Some things I'm pleased with and some concerned with.

The @, in general, is the most confusing aspect of Bicep to new developers and abstracting that away would be great. However, as @pacodelacruz and others have pointed out, you've now created an artificial tie of the 100's of APIs to a single bicep AZ version - with no easy way to understand that mapping.

I'm going to have to somehow know that Import [email protected] ties to [email protected] and [email protected].

And again, for a new developer, this is a nightmare.

My main concern behind this proposal is the existence of import az at all.

I can see the desire to have a specific version - import az@v1 as a good desire to tie your bicep file to an az version (assuming there's some way to list what specific API version v1 is linked to).

But please, please don't make the Import AZ required. This is a monstrous breaking change that I can't even fathom why you think this is a good idea.

One of the basic premises from the start of Bicep has been that Bicep deploys Azure resources. ("Bicep is a Domain Specific Language (DSL) for deploying Azure resources declaratively.") Adding other providers for import exposes the need for addressing the import az command, but I would hope that all bicep files should import the latest AZ unless an EXPLICIT version is stated through an import az@v1 command. Anything other than this is a fundamental change to the foundation of Bicep.

There was mention in the September CC that this could be added to a bicepconfig.json to work through this but this then breaks the concept of bicep files/modules being distributable - you now would have to have a X.bicep file and a bicepconfig.json file that makes it work. Code sharing is now effectively broken and you have a huge "Works on my machine" problem. Not to mention now that a module from a repo may distribute a bicepconfig.json file which can have a potential impact to other resources in your deploy.

Please keep with the mindset that Bicep deploys Azure FIRST and don't break my code!

@slavizh
Copy link
Contributor

slavizh commented Sep 30, 2022

@shenglol yeah my proposal was very fast example that was just to show what I mean rather propose actual syntax. I have suggested granularity per resource provider for versioning since it the versioning was introduced to us but may be somehow got slip upon implementation. I think many have agreed that this is needed. As you show than scope becomes a problem. I do not think that defining scope per resource provider is good approach. May be an option like this would be better:

import 'az' with {
  scopeType: ['resourceGroup', 'subscription']
  import 'az@v1/Microsoft.Authorization'
}

That way you define scope once. You import az without specific version but you import Authorization RP with specific version. So for every resource that you define for Authorization RP API version will be optional only if you want to change it from the API version defined in v1 and for other RPs you will have to specify version.

I am not good of creating syntaxes so the above is just to demonstrate the most flexible way to define things without having to write a bunch of unneeded code. I am better of picking a syntax when multiple such are proposed :)

Overall I understand the desired change to have one version for Az, although for me at this point I prefer defining API version per resource. For me there are a few things that this syntax should allow:

  • Define major version for az
  • Even when major version is defined for az still to be able to define version per resource.
  • Ability to define version per resource provider with or without having to define the az version
  • Defining scope only once. After all scope is mainly used for one thing - intellisense. I currently have templates that are defined at scope subscription but they deploy just fine at management group level as well because the resource I deploy are available for both scopes and I have written the code in a way that the small differences between the scopes for the same resources are accommodated.
  • Define scopes without having to define Az version
  • Ability to define other version for specific RP even when the version of az is different.

@shenglol
Copy link
Contributor

shenglol commented Sep 30, 2022

But please, please don't make the Import AZ required. This is a monstrous breaking change that I can't even fathom why you think this is a good idea.

@ChristopherGLewis The rationale behind the import story is to decouple resource providers and the Bicep compiler to support extensibility. Ideally, users should be able to pull providers and their resource types from a registry, including az. We had an discussion in our team about whether we should treat all providers equally, and the implication would be that all providers should be imported explicitly. I would like to clarify that we didn't come to a conclusion during our internal discussion, and all of us thought this was something we need to go over with the community. I think the feedback we got clearly indicated that az should, by any means, be imported by default.

One of the basic premises from the start of Bicep has been that Bicep deploys Azure resources. ("Bicep is a Domain Specific Language (DSL) for deploying Azure resources declaratively.") Adding other providers for import exposes the need for addressing the import az command, but I would hope that all bicep files should import the latest AZ unless an EXPLICIT version is stated through an import az@v1 command. Anything other than this is a fundamental change to the foundation of Bicep.

This matches our design. The default az import shipped with Bicep will always have the latest version, but users may override the version if they want to.

There was mention in the September CC that this could be added to a bicepconfig.json to work through this but this then breaks the concept of bicep files/modules being distributable - you now would have to have a X.bicep file and a bicepconfig.json file that makes it work. Code sharing is now effectively broken and you have a huge "Works on my machine" problem. Not to mention now that a module from a repo may distribute a bicepconfig.json file which can have a potential impact to other resources in your deploy.

In Bicep, there is a built-in configuration file that is always loaded by the Bicep compiler. The file is invisible to users, and all custom Bicep configuration files are essentially overriding values in the built-in configuration file. We are actually thinking about adding az as a default import to the built-in configuration file. This is more of an implementation change. From a user's perspective, there is no change, and they can use Azure resources as usual without the need for creating a Bicep configuration file to add az as a default import, because it already existing in the built-in configuration, and hence there is no "Works on my machine" problem. They do have the option to override the default imports (say, remove az and add kubernetes), but in that case they are doing what they want.

@elygre
Copy link

elygre commented Oct 12, 2022

Re-listening to the community call, I would also like to advocate for a solution where "no import statement" means "automatic import of az", while "any import statement" means "import only what is specified".

@slavizh
Copy link
Contributor

slavizh commented Oct 13, 2022

May be this can be solved like this:

  • az is imported by default and you do not have to define anything in the files or in bicep CLI command
  • In case your bicep templates you use resource foo 'Microsoft.Compute/virtualMachines' = ... - without specifying the version linter rule warn you (or error out) that it is recommended to have import statement with specific az version.

This way all existing bicep files will not require change as they already use specific version when they define a resource and for them it will not matter what is the default az version.
That way also in the future you can safely increases the az version (this also increases versions of different RPs) with bicep CLI new versions even when the RP versions that come with that particular az version contain breaking changes.

Of course as you want to make a change on how scope is defined that will be a breaking change for existing templates where the target scope is explicitly defined.

Even with this proposal my previous proposal of being able to define version per RP (az.compute for example) and defining multiple scopes in an easy as well stays.

@ghost
Copy link

ghost commented May 19, 2023

Hi rynowak, this issue has been marked as stale because it was labeled as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. Thanks for contributing to bicep! 😄 🦾

@ghost ghost closed this as completed May 22, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Jun 21, 2023
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request Needs: Author Feedback Awaiting feedback from the author of the issue types
Projects
Archived in project
Development

No branches or pull requests