[ACR] check-health: add support to verify dns routings to private endpoints #17746
[ACR] check-health: add support to verify dns routings to private endpoints #17746fengzhou-msft merged 17 commits intoAzure:devfrom
Conversation
There was a problem hiding this comment.
@toddysm, please check out the description and error messages below and see whether it makes sense and friendly to users
There was a problem hiding this comment.
@yugangw-msft Correct me if I'm wrong - please double-check the usage of VNET throughout the code. Users are expected to provide the Subnet Resource ID or (Subnet name and Vnet name). If they provide the VNET ID, the code may not work since subnetID != VnetID.
Vnet Resource ID: /subscriptions/{subID}/resourceGroups/{resourceGroup}/providers/Microsoft.Network/virtualNetworks/{vnetName}
Subnet Resource ID:
/subscriptions/{subId}/resourceGroups/adupadhyRG/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}
Usually, subnet name is default but it could be different based on what subnet users create.
There was a problem hiding this comment.
--subnet is more accurate, which I can follow your suggestion.
The context of only matching vnet is having 2+ PE in the same vnet (even different subnet) is an anti-pattern we want to capture, as dns routing might become unpredictable.
So, it is your call. Let me know we go with vnet or subnet
There was a problem hiding this comment.
Makes sense, let's go with VNET.
There was a problem hiding this comment.
How expensive is an instantiation of network_client? It might be better to instantiate one network client outside the loop and use it for all requests.
There was a problem hiding this comment.
It is cheap. The reason of initializing each time is PE can be cross tenant which mean the subscription value might be different. We can use dictionary with keying on subscription for cache, but that might be overkill.
There was a problem hiding this comment.
Makes sense, I missed the res['subscription'] part.
There was a problem hiding this comment.
sorry my python knowledge might be a bit rusty. If we're only extracting resource Ids, shouldn't this have an if condition at the end? Does e.private_endpoint and e.private_endpoint.id achieve the same as the code below?
[e.private_endpoint.id for e in registry.private_endpoint_connections if e.private_endpoint]
There was a problem hiding this comment.
python's and is a bit different with non boolean value, but I can use your suggestion for better code maintainability
There was a problem hiding this comment.
Trying to understand why we're using not in here. result will contain IP V4 address string right? dns_mappings[fqdn] is also string not a list. Any reason for not doing if result != dns_mappings[fqdn]:?
Also, if an invalid/non-existing FQDN is passed to socket.gethostbyname, it leads to an error. Should the error be caught?
There was a problem hiding this comment.
Will address both comments
There was a problem hiding this comment.
Using a regex module might be overkill. Can we do vnet_of_private_endpoint.lower() == pe.subnet.id.lower()?
Also, variable name subnet_of_private_endpoint might avoid confusions?
There was a problem hiding this comment.
I see why you used regex module here. re.match will return non-null object if vnet resource ID is a part of subnet resource ID. I would do a simple prefix matching to make it more readable but either of the two options is fine.
pe.subnet.id.lower().startswith(vnet_of_private_endpoint.lower())
There was a problem hiding this comment.
@yugangw-msft Correct me if I'm wrong - please double-check the usage of VNET throughout the code. Users are expected to provide the Subnet Resource ID or (Subnet name and Vnet name). If they provide the VNET ID, the code may not work since subnetID != VnetID.
Vnet Resource ID: /subscriptions/{subID}/resourceGroups/{resourceGroup}/providers/Microsoft.Network/virtualNetworks/{vnetName}
Subnet Resource ID:
/subscriptions/{subId}/resourceGroups/adupadhyRG/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}
Usually, subnet name is default but it could be different based on what subnet users create.
There was a problem hiding this comment.
Correct, like I mentioned, we mainly care about the vnet
There was a problem hiding this comment.
@yugangw-msft Do you think we should validate if the user has entered a valid VNET resource ID? Right now, we only check if it's a valid resource ID.
For instance, if a user (by mistake) provides a non-VNET resource ID, the current code flow will log an error: Registry ... doesn't have private endpoints in the vnet of {nonVnetResourceId}
If invalid, we can request user to enter the VNET resource ID in the format /subscriptions/{subID}/resourceGroups/{resGroup}/providers/Microsoft.Network/virtualNetworks/{Vnet}
There was a problem hiding this comment.
--subnet is more accurate, which I can follow your suggestion.
The context of only matching vnet is having 2+ PE in the same vnet (even different subnet) is an anti-pattern we want to capture, as dns routing might become unpredictable.
So, it is your call. Let me know we go with vnet or subnet
There was a problem hiding this comment.
Correct, like I mentioned, we mainly care about the vnet
There was a problem hiding this comment.
python's and is a bit different with non boolean value, but I can use your suggestion for better code maintainability
There was a problem hiding this comment.
It is cheap. The reason of initializing each time is PE can be cross tenant which mean the subscription value might be different. We can use dictionary with keying on subscription for cache, but that might be overkill.
There was a problem hiding this comment.
Will address both comments
There was a problem hiding this comment.
Makes sense, let's go with VNET.
There was a problem hiding this comment.
Makes sense, I missed the res['subscription'] part.
There was a problem hiding this comment.
I see why you used regex module here. re.match will return non-null object if vnet resource ID is a part of subnet resource ID. I would do a simple prefix matching to make it more readable but either of the two options is fine.
pe.subnet.id.lower().startswith(vnet_of_private_endpoint.lower())
There was a problem hiding this comment.
Question only: Do you see any value in printing the DNS mappings for ok scenarios?
registry.azurecr.io 10.0.0.1
registry.eastus.data.azurecr.io 10.0.0.2
registry.westus.data.azurecr.io 10.0.0.3
There was a problem hiding this comment.
Right now we only have stderr for non structured info(stdout is for json data), I suggest keep it terse so error can be spotted easily.
However if feedback shows users don't get the error easily, we can incorporate errors in the pretty formating
registry.azurecr.io 10.0.0.1
registry.eastus.data.azurecr.io 10.0.0.2
registry.westus.data.azurecr.io 10.0.0.3
registry.westeurope.data.azurecr.io (dns routing error)
There was a problem hiding this comment.
@yugangw-msft Overall LGTM. Last two things.
- Please confirm the Help text and description for the
--vnetcommand line arg - Please evaluate if we need to validate if
vnet_resource_idis a valid VNET resource id. Right now, we only verify if it's a valid ARM resource ID.
|
@fengzhou-msft, please review, and merge if you are happy |



The PR title and description has followed the guideline in Submitting Pull Requests.
I adhere to the Command Guidelines.
I adhere to the Error Handling Guidelines.