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

Shortcut for referencing "this" resource when setting dependency IDs #724

Closed
WhitWaldo opened this issue Oct 23, 2020 · 9 comments
Closed
Labels
discussion This is a discussion issue and not a change proposal. enhancement New feature or request

Comments

@WhitWaldo
Copy link

Is your feature request related to a problem? Please describe.
Several resources in ARM have all sorts of children defined in the properties that each reference one anothers' IDs. Take the following ARM template when filling out properties for a LoadBalancer (many parts omitted for brevity):

variables: {
  'lbID0': "[resourceId('Microsoft.Network/loadBalancers', concat('LB-',parameters('something'))]",
  'lbHttpProbeID0': '[concat(variables('lbID0'),'/probes/ProbeA')]'
},
'resources': [
  {
    'type': 'Microsoft.Network/loadBalancers',
    'properties': {
      loadBalancingRules: [
       {
         'name': 'MyRule',
         'properties': {
            'enableFloatingIP': 'false',
            'probe': {
                'id': "[variables('lbHttpProbeID0')]"
             }
          }
       }
      ],
      probes: [
        {
          'name': 'ProbeA',
          'properties': {
             //....
           }
        }
      ]
    }
  }
]

Notably, I'm having to specify the probe, and in another variable, I'm setting up the resource ID for the parent load balancer just so I can dig right back into a child resource within the same object.

I think it'd be handy to have an option like that available in SASS or SCSS that essentially symbolizes 'this' as a single ampersand and a delimiting mark so the resource ID can be calculated out at build time instead of dealt with through the use of several variables

Describe the solution you'd like

Here's an example of what I have in mind written in Bicep to yield the above result using this symbol:

var probeName = 'Something'
resource loadBalancer 'Microsoft.Network/loadBalancer@2020-05-01' = {
  name: 'lb0'
  location: location
  properties: {
    loadBalancingRules: [
      name: 'MyRule'
      properties: {
         probe: {
           id: '&.probes.${probeName}' //This is where the change lies that I'm proposing
         }
      }
    ]
    probes: [
        {
          'name': probeName
          'properties': {
             //....
           }
        }
      ]
  }
}

Note the use of the & at loadBalancer.properties.loadBalancingRules.properties.probe.id - ideally, & would point directly to the outer-most resource currently being defined so its ID could be inferred and utilized there, but also support implicit pathing within it along with string interpolation so variables and parameters could be referenced as well.

This change would serve to eliminate some typing (always a plus in ARM template), eliminate a source for resource ID errors and cut down on the number of variables that exist for no other reason than to simplify this referencing.

Thank you for your consideration.

@WhitWaldo WhitWaldo added the enhancement New feature or request label Oct 23, 2020
@ghost ghost added the Needs: Triage 🔍 label Oct 23, 2020
@majastrz majastrz added the discussion This is a discussion issue and not a change proposal. label Oct 24, 2020
@majastrz
Copy link
Member

I like the idea overall. Anything to reduce typing is great! A couple of thoughts...

  1. For deeper nesting situations, I think we would need the ability to reference the immediate parent instead of just the outermost parent. I think I'd prefer to use the same syntax for both instead of introducing another syntax to cover the immediate parent. In your example, it could be something like &.&.foo.

  2. I'm a little hesitant to have a special character for this because it's not immediately obvious to the user. & specifically is typically used as a bit-wise AND operator in C-style languages, which could add to confusion. I think if we used parent or some other full (but short) word as the keyword, it would work rather well and be self-describing and self-documenting. We are considering an alternative syntax for deploying nested resources and parent would fit with that as well. The downside of using a word would be that the chosen identifier would have to be reserved in the local namespace.

@WhitWaldo
Copy link
Author

WhitWaldo commented Oct 24, 2020

1, I'd agree that there's often a need to access the immediate relative parent as well as the outermost parent, but I would separate those out to two separate symbols for clarity. I'm in the camp that self-documenting code is nice for those scenarios when you type something up and don't come back to it for a while, so having nested syntax may be less clear than not. That said, rich Intellisense can assist here if it can show what level is currently referenced.

So if you stuck with symbols then, I'd propose that a suitable symbol be used for the outermost parent (originally proposed as &) and a separate symbol for just going up to the immediate parent (^). Once the syntax is understood in the context of the Bicep language (as in SASS), I would propose it's clearer and shorter at a first glance to read &.foo and ^.foo or even ^.^.foo.

  1. Given that it's used in the context of a string and not as part of the syntax of the outer statement, I'd be more inclined to limit any reserved keywords within the string as much as possible, especially if this is the first proposal that uses mid-string keywords. While there may be some initial confusion requiring careful consideration of which symbol to use, I'd lean more towards single characters to convey the operation than words, because again, the goal is less typing in the first place.

That said, it would eliminate having to learn special symbolic syntax in the first place to use text, so if you went this route, might I propose something like (to use the same earlier examples) <root>.foo and <parent>.foo or <parent>.<parent>.foo?

Putting the keyword in brackets could eliminate any need to have reserved keywords and.. you might have a compiler option to warn about possible unintended use if you saw "parent" or "root" used without the brackets.

@WhitWaldo
Copy link
Author

WhitWaldo commented Oct 24, 2020

Another thought as I sit here jamming through load balancers in my file.. the availability of such a syntax (symbolic or not) would be hugely beneficial in the upcoming looping functionality. Otherwise, I'd run into issues figuring out how to reference the parent resource IDs within the loop to reference the children (rendering loops far less useful).

@alex-frankel
Copy link
Collaborator

Related to #565

@alex-frankel
Copy link
Collaborator

Just +1-ing a word + symbol instead of just symbol. Maybe just one leading character instead of wrapping characters though:

^this / $this
^parent / $parent

@anthony-c-martin
Copy link
Member

Just to play devil's advocate a bit here:

  1. It's going to be possible to get into some strange cyclic dependencies (e.g. with two properties that reference each other).
  2. There may be some confusion over what can be referenced with this - I won't be able to reference 'read-only' properties (which are only returned on a resource GET), and there may be small differences in behavior between myRes.propThatIsModifiedOnAGet and this.propThatIsModifiedOnAGet (referenced inside myRes). I also wouldn't be able to do e.g. this.listKeys(). We need to consider whether these subtle differences in behavior may confuse users.
  3. In most cases it's going to be possible to achieve the same effect by refactoring (e.g. using intermediary variables) - in fact the main cases I can think of that are interesting are this.id, this.apiVersion, and this.type, because they can't be easily refactored.
  4. This scenario is highly unique to ARM, and specifically to the Microsoft.Network RP. The API design of referencing 'resource-like' elements which can be declared inside the parent resource using fully qualified resourceIds feels suboptimal in the first place, and not a pattern I would expect newer RPs to implement.

@alex-frankel
Copy link
Collaborator

We'd like to see if there are other concrete examples of this issue manifesting in other RPs besides Microsoft.Network before we pick this up

@JustinGrote
Copy link

JustinGrote commented Feb 25, 2021

For those coming here, there is an available workaround using resourceId(), it works with subresources as well.
#1470 (comment)

@alex-frankel
Copy link
Collaborator

Closing and tracking with #1470. I think we are going to allow you to reference compile-time properties like *.id

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
discussion This is a discussion issue and not a change proposal. enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants