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

feat: Expand usage of UDT for the AVNM Bicep Module - avm/res/network/network-manager #1584

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

ahmadabdalla
Copy link
Contributor

@ahmadabdalla ahmadabdalla commented Apr 6, 2024

Description

Introducing User Defined Types for the Azure Virtual Network Manager (AVNM) Bicep module. Additionally, expanded on the test cases for the maxium to increase test coverage for UDT validations.

Pipeline Reference

Pipeline
avm.res.network.network-manager

Type of Change

  • Update to CI Environment or utlities (Non-module effecting 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

Checklist

  • I'm sure there are no other open Pull Requests for the same update/change
  • I have run Set-AVMModule locally to generate the supporting module files.
  • My corresponding pipelines / checks run clean and green without any errors or warnings

@ahmadabdalla ahmadabdalla self-assigned this Apr 6, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Triage 🔍 Maintainers need to triage still Type: AVM 🅰️ ✌️ Ⓜ️ This is an AVM related issue labels Apr 6, 2024
@ahmadabdalla ahmadabdalla marked this pull request as ready for review April 6, 2024 23:37
@ahmadabdalla ahmadabdalla requested review from a team as code owners April 6, 2024 23:37
deleteExistingPeering: ('True' | 'False')?

@sys.description('Optional. Is global configuration.')
isGlobal: ('True' | 'False')?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is actually a new spec waiting in a PR that asks primitive types to be declared as such (e.g. use int instead if string for numbers, or boolean instead of string for true/false).
This would mean, this parameter should be changed to isGlobal: bool and the place where it is used needs to (optionally) cast the value to a string. I've seen implicit casts in the pasts, so we may not need it.

Same comment for the other string-boolean parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I would avoid hiding such things and align to the API as much as possible. That way its a standard consumption method from an API and IaC perspective and less abstraction code to maintain. But if that's the path that AVM is going to take then I will wait for that PR to be merged. Would be great to know if that's something that will be as a recommendation for the module owner or something that is a must have.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue it's probably a 'Should' that targets improved usability of the resource, which in many instances is just plain bad (case an point CMK or boolean strings 😄 )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @AlexanderSehr I have done some testing on the casting approach.

image

Here is an example PR: comparing the current UDT implementation as per this PR with an approach for casting.

It definetly took a toll on testing and validation a lot more than it was before. And seems more code to maintain for an owner. What are your thoughts on this? How has this been tested with other modules at a big scale?

I have some questions around the default behaviour for a UDT param of type bool. Because I had to use casting, I now am enforced in my test files to explicitly pass the parameter either true false compared to the past. Is there a specific pattern I should follow here as per AVM standards?

image

See above picture as an example. If I do not provide these values, my deployments now fail :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ahmadabdalla,
maybe we can find a slot some time to actually have a chat about the subject, as it's just easier to talk about than write 😄
Anyhow, the modules I've seen implement this on scale did usually not introduce much added code. Usually it was not much more than introducing e.g. a string(parameter) or '${parameter}' where a parameter was used an a string was expected, while in others it made the module actually easier as conditions didn't need to check for explicit string values in conditions like if(parameter == 'true'). But naturally, the argument you made (i.e., deviating from the API) was exactlythe discussion to have. In like 'is it worth it'. At least for now we opted for 'yes' on the backdrop that we want to improve/easy a deployments usuability when we can.

Regarding the default behavior - if a parameter is optional, you can still just make it nullable. Also booleans. Does this answer the question (not sure I fully understood it 😄)? Something else that speaks for a chat 😉

@sys.description('Required. List of network groups for configuration. An admin rule collection must be associated to at least one network group.')
appliesToGroups: {
@sys.description('Required. The resource ID of the network group.')
networkGroupId: string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should ideally be networkGroupResourceId

Please note, if changed to e.g. networkGroupResourceId, also the location where it is used must be updated wth a map function to map it to the expected networkGroupId`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also mind you, as you implemented the UDT in mutliple files, it would also need to be fixed in multiple files.

Looking forward to the time when types can simply be imported via a types.bicep (ref)

@matebarabas matebarabas changed the title feat: Expand usage of UDT for the AVNM Bicep Module feat: Expand usage of UDT for the AVNM Bicep Module - avm/res/network/network-manager Apr 10, 2024
@matebarabas matebarabas added Class: Resource Module 📦 This is a resource module and removed Needs: Triage 🔍 Maintainers need to triage still labels Apr 10, 2024
@@ -58,10 +58,10 @@ param priority int
param protocol string

@sys.description('Optional. List of destination port ranges. This specifies on which ports traffic will be allowed or denied by this rule. Provide an (*) to allow traffic on any port. Port ranges are between 1-65535.')
param sourcePortRanges array = []
param sourcePortRanges sourcePortRangesType?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as before

Suggested change
param sourcePortRanges sourcePortRangesType?
param sourcePortRanges string[]?

destinationPortRanges: contains(rule, 'destinationPortRanges') ? rule.destinationPortRanges : []
destinations: contains(rule, 'destinations') ? rule.destinations : []
description: rule.?description ?? ''
destinationPortRanges: rule.?destinationPortRanges ?? []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a suggestion (so feel free to just resolve), but you could actually leave the else case out when referencing the child module.

Example

  • If in the child module param destinationPortRanges has a default in the child, and this line here is just destinationPortRanges: rule.?destinationPortRanges, then it will automatically pick the default in the child
  • If in the child module param destinationPortRanges has no default but is nullable like in your case, then no value is passed through (which I guess also is fine)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Class: Resource Module 📦 This is a resource module Type: AVM 🅰️ ✌️ Ⓜ️ This is an AVM related issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants