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

Shared Variables for Bicep Files #893

Closed
glloyd2010f opened this issue Nov 12, 2020 · 21 comments
Closed

Shared Variables for Bicep Files #893

glloyd2010f opened this issue Nov 12, 2020 · 21 comments
Labels
enhancement New feature or request Needs: Author Feedback Awaiting feedback from the author of the issue

Comments

@glloyd2010f
Copy link

glloyd2010f commented Nov 12, 2020

Within Azure DevOps we leverage variable files so that they can shared between many pipelines/workstreams. Will Bicep have the concept of a shared variables file so that teams can just import them? Would this be just another bicep module?

An ideal solution would be a common variables setup so that we don't require a linked template or bicep module with outputs that need to be referenced. This would be extremely valuable for easy re-use. This would be in addition to any inline variables.

Rough Example...

main.bicep
var inlineVariable = 'varValue'
var sharedVariables = './fileName.bicepVars'

@glloyd2010f glloyd2010f added the enhancement New feature or request label Nov 12, 2020
@ghost ghost added the Needs: Triage 🔍 label Nov 12, 2020
@alex-frankel
Copy link
Collaborator

Makes sense. Not the same, but related to #471

@alex-frankel alex-frankel added Needs: Author Feedback Awaiting feedback from the author of the issue and removed Needs: Triage 🔍 labels Nov 19, 2020
@glloyd2010f
Copy link
Author

What kind of feedback are you looking for?

@JFolberth
Copy link
Contributor

I actually had this same thought initially as it's what Terraform has; however, the more I thought about it the more I struggled to find a solution where this would adhere to best practice. What I mean by that is what would be put in a variable file that wouldn't normally (should) be passed in as a paramter via a deployment process? Tags was the only thought that came to mind as there is a strong use case to reuse tags across all modules and components being created but again that is something that could be passed in at deployment.

However to optimize a module for reuse most of the specifics could be passed in at deployment or defined in the main.bicep file. If using static variable reference I'd argue first why use a file vs the build in variable declaration process? Also defining variables inside the .bicep file provides for more flexibility to dynamically assign values based on coditions/concatenation.

@johndowns
Copy link
Contributor

I like this suggestion. I have come across a situation where this would be helpful - when deploying an APIM instance into a VNet, there are a lot of NSG rules that need to be set up to keep APIM happy. It would be really good to have these declared as a variable in another file to keep them together, and then my main NSG template would refer to that plus add any custom rules I need as well.

@majastrz
Copy link
Member

Linking to related discussion #1601.

@JustinGrote
Copy link

JustinGrote commented Feb 26, 2021

Similarly, while I do appreciate the defined "contracts" that modules provide, I have a lot of boilerplate in my main bicep that looks like this like I have in terraform as well.

module network './network.bicep' = if (empty(vnetName)) {
  name: '${deploymentName}-network'
  params: {
    vnetName: fgNamePrefix
    vnetAddressPrefixes: vnetAddressPrefixes
    internalSubnetPrefix: internalSubnetPrefix
    externalSubnetPrefix: externalSubnetPrefix
    internalSubnetName: internalSubnetName
    externalSubnetName: externalSubnetName
  }
}

This is not a major deal, but maybe a module property "inherit: true" that would match up variables to same-named parameters would be great to cut down on the boilerplate.

@Vegas588
Copy link

The concept of shared variables or Global variables where we can define something once is indeed very much needed. Just take the simple case of a name prefix that you use for your resources or Tags. I hate having to define them over and over again. Having the ability to declare a global variable, define it once and reference wherever needed is priceless.

@johnymachine
Copy link

@glloyd2010f By this you would be building templates with embeded variables, right?

@alex-frankel Is there any way to actually compose and build parameter files, so that the templates stay simle and flexible?

Example:

envdata.parameters.bicep

var env = "prd",
var locationShort = "we"

network.parameters.bicep

import envdata.parameters.bicep as envdata

var vnetname = $envdata.env + "-corenet-" +  $envdata.locationShort + "vnet"

Is it something like this currently possible for parameter files? Or am I missing something here?

We have fairly complex deployments and with json you cannot simply achieve this without building another templating layer. I was considering to use something like jsonnet or yaml and build the final parameter file. But since yaml is not native to powershell it both feels kinda wrong. Honestly this is even bigger pain than writting the tamplates in json, any cure for that?

@glloyd2010f
Copy link
Author

@johnymachine I think a similar comparison would be to the usage hiera within puppet. It would act as an imported file that can be referenced for standardized information. This way you can just grab pre-approved information and allow development teams to be more autonomous. Does that make sense?

@brwilkinson
Copy link
Collaborator

It appears this thread was related to below, which has now been implemented?

var config = json(loadTextContent('../bicepconfig.json'))
var item = config.analyzers

Notice you get intellisense/property discovery.

image

@JustinGrote
Copy link

Not exactly, because you still can't "splat" those into modules, you still have to match parameter to parameter.

@brwilkinson
Copy link
Collaborator

That should be covered in #1121 right?

@JQUINONES82
Copy link

@brwilkinson is this json(loadTextContent('../bicepconfig.json) updated in the Azure Bicep Documentation!?

@alex-frankel
Copy link
Collaborator

alex-frankel commented Sep 8, 2021

It's not there yet, but we are adding it shortly cc @tfitzmac / @stephaniezyen

Tom, we should make sure to cover the use case of combining json() with loadTextContent() which enables intellisense and property access in bicep.

@tfitzmac
Copy link

tfitzmac commented Sep 9, 2021

docs for loadTextContent has been published and includes an example of using json() with loadTextContent().

@jikuja
Copy link

jikuja commented Oct 20, 2021

json(loadTextContent()) is a nice addition but supports only static data. Using format() or replace() were suggested in #471 but they break Intellisense property access.

What I would like to see is following:

shared.json:

{
"VNetName": "${project}-${env}-vnet"
}

main.bicep:

param project string = 'foo'
param env string = 'dev'
var sharedNames = json(loadTextContent('shared.json'))
// data on sharedNames is not available

Or alternative approach

shared.bicep:

{
var VNetName = '${project}-${env}-vnet'
}

main.bicep:

param project string = 'foo'
param env string = 'dev'
includeBicep('shared.bicep')
// everything declared on shared.bicep is now available

this is much more complicated and probably does not make any sense because of the working module system.

@jikuja
Copy link

jikuja commented Oct 21, 2021

Update two:

I tried to offload my shared variable file generation outside of bicep: my pipeline knows what kind of replacement to do:


Failed try number 1: generated one single file containing resource names for all environments:

{
  "test": {
    "SQLServer": "xxx-test-sqlserver",
    "SQLDatabase": "db1"
  },
  "prod": {
    "SQLServer": "xxx-prod-sqlserver",
    "SQLDatabase": "db1",
    "VPNVNet": "xxx-vpn-prod-vnet"
  },
  "dev": {
    "SQLServer": "xxx-dev-sqlserver",
    "SQLDatabase": "db1"
  }
}

failed because:

var names = json(loadTextContent('../shared/names.json'))

intellisense on names will work only with the highest level of nesting. Nothing is suggested after typing names.test


failed number 2: I generated environment specific files containing resource naming for one environment

{
    "SQLServer": "xxx-prod-sqlserver",
    "SQLDatabase": "db1",
    "VPNVNet": "xxx-vpn-prod-vnet"
  }

with

var names = json(loadTextContent('../shared/names-${EnviromentName}.json'))

failed with The value must be a compile-time constant.bicep(BCP032)

TLDR: Looks like all workaroundd for dynamic shared variables seems to be more or flawed or lack of features like fully working IntelliSense.

Using precompiled to make try 2 might be one solution but is really hacky solution.

Am I missing something or is this really this difficult to achieve?

@anthony-c-martin
Copy link
Member

intellisense on names will work only with the highest level of nesting. Nothing is suggested after typing names.test

That's odd - I would expect this to work, and can't repro this locally using your shared JSON file:
image

@jikuja
Copy link

jikuja commented Oct 21, 2021

That's odd - I would expect this to work, and can't repro this locally using your shared JSON file:

True. I had an issue with my local file. But sadly using dot notation for property access is effective hardcoding.

Following should be used to pick up the correct set of names on deployment:

param environmentName string

var names = json(loadTextContent('names.json'))[environmentName]
var NameIWantToUsePlease = names.

and this definitely is not resolved by IntelliSense.

I did not test if this really works.


Summary for this now:

Pros:

  • Resource naming is in one file
  • Copy-pasting resource names from one single location is faster than finding a resource creation template
  • resource renaming will be faster. No need to grep whole project if changing resource name

Cons:

  • Requires external scripting
  • Using shared naming variables requires typing and good memory
  • or using shared naming variables requires copy-pasting instead of IntelliSense

Not sure if I'm just wasting my time with experimenting workarounds.


Calculating RoI for the final attempt with this kind of approach: https://dev.to/zakhenry/ensuring-accuracy-of-readme-code-snippets-525p

  • using a similar approach to include naming variables automatically from the file could be one so

pros:

  • should work

cons:

  • requires external tools to run on the local environment to run on CI pipeline
  • requires extra workflow when creating a new resource name
  • length of templates will be longer

@brwilkinson
Copy link
Collaborator

@jikuja This is being tracked in #4745

@ghost
Copy link

ghost commented May 19, 2023

Hi glloyd2010f, 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
Projects
Archived in project
Development

No branches or pull requests