)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":36867,"name":"Zalan","display_name":"Zalan","email":"zalan.blenessy@volvocars.com","username":"zbleness"},"change_message_id":"1f843f3c0d0e38280f56da78e5d1569a73ca3848","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"71673dd5_d57b1d99","updated":"2024-04-08 11:21:19.000000000","message":"Hi James! Do you have an ETA. when this will be released ?","commit_id":"50d0fb788c9f55a80777886dd73bf35133655185"}],"doc/source/azure.rst":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"dab43cdd2fdfd4f4f09d538cf2e3af169d0a7169","unresolved":true,"context_lines":[{"line_number":762,"context_line":""},{"line_number":763,"context_line":"                The name of the User-assigned Managed Identity."},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"             .. attr:: resource-group"},{"line_number":766,"context_line":"                :type: str"},{"line_number":767,"context_line":""},{"line_number":768,"context_line":"                Overrides :attr:`providers.[azure].resource-group`."}],"source_content_type":"text/x-rst","patch_set":2,"id":"d9b77bf3_1eb3543f","line":765,"updated":"2024-03-11 15:55:47.000000000","message":"You could say `:default: The provider\u0027s resource group` -- we do that elsewhere in this file.","commit_id":"f5c931463835c1fe04aa7b742f566459cd4629ee"},{"author":{"_account_id":36867,"name":"Zalan","display_name":"Zalan","email":"zalan.blenessy@volvocars.com","username":"zbleness"},"change_message_id":"a14ef65b60689f3c85fa085e07a5e1bd21d83646","unresolved":false,"context_lines":[{"line_number":762,"context_line":""},{"line_number":763,"context_line":"                The name of the User-assigned Managed Identity."},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"             .. attr:: resource-group"},{"line_number":766,"context_line":"                :type: str"},{"line_number":767,"context_line":""},{"line_number":768,"context_line":"                Overrides :attr:`providers.[azure].resource-group`."}],"source_content_type":"text/x-rst","patch_set":2,"id":"33a9d23d_80e0c58f","line":765,"in_reply_to":"d9b77bf3_1eb3543f","updated":"2024-03-12 08:09:20.000000000","message":"Done","commit_id":"f5c931463835c1fe04aa7b742f566459cd4629ee"}],"nodepool/driver/azure/adapter.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"1d7d8a93c4a21189975aa3ebc47228ee155af775","unresolved":false,"context_lines":[{"line_number":662,"context_line":"        for managed_identity in self._listManagedIdentities():"},{"line_number":663,"context_line":"            mi_id \u003d managed_identity[\u0027properties\u0027][\u0027clientId\u0027]"},{"line_number":664,"context_line":"            if mi_id in label.user_assigned_identities:"},{"line_number":665,"context_line":"                managed_identities[mi_id] \u003d managed_identity"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"        # fail if some identities are not found"},{"line_number":668,"context_line":"        if len(managed_identities) \u003c len(label.user_assigned_identities):"}],"source_content_type":"text/x-python","patch_set":1,"id":"2a0643b0_556ecd9c","line":665,"updated":"2024-03-08 15:11:01.000000000","message":"It looks like we really need to get the managed identity by id.  So rather than fetch the list of identities, why don\u0027t we use the pattern we use with images.  So instead of implementing _listManagedIdentities, implement _getManagedIdentity like _getImage.  In a system with, say, 10 identities used by nodepool, it will be a little slower at first because we\u0027ll make 10 api calls.  But there should be no reason to expire them from the cache since the only thing we\u0027re using is the id, and that isn\u0027t going to change.  So once we perform a get for each one, we never have to do another request.  And in a system with 1000 managed identities, that will be much faster.\n\nOR (and this might be even better) you could do no validation of the managed identities at all.  For example, we ask users to provide a subnet id, and we don\u0027t check whether it exists or not, because azure will tell us that.  The same is true here too -- in line 671 we\u0027ll raise an exception if we can\u0027t find a managed ID.  But if we removed all this checking, then Azure will throw an error just a little later in line 684.\n\nAs long as we don\u0027t need any more information than the ID, I would recommend the second approach; it\u0027s much simpler.\n\nRegardless of which approach you take, we should update at least one of the tests to create a node with a user-assigned-identity so that we exercise the new code.","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"},{"author":{"_account_id":36867,"name":"Zalan","display_name":"Zalan","email":"zalan.blenessy@volvocars.com","username":"zbleness"},"change_message_id":"d041adc7ac691489498534fb91b423316bf37d6f","unresolved":true,"context_lines":[{"line_number":662,"context_line":"        for managed_identity in self._listManagedIdentities():"},{"line_number":663,"context_line":"            mi_id \u003d managed_identity[\u0027properties\u0027][\u0027clientId\u0027]"},{"line_number":664,"context_line":"            if mi_id in label.user_assigned_identities:"},{"line_number":665,"context_line":"                managed_identities[mi_id] \u003d managed_identity"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"        # fail if some identities are not found"},{"line_number":668,"context_line":"        if len(managed_identities) \u003c len(label.user_assigned_identities):"}],"source_content_type":"text/x-python","patch_set":1,"id":"a565b35c_75b41564","line":665,"in_reply_to":"14e537aa_938c454b","updated":"2024-03-11 13:26:38.000000000","message":"Ok I think I got it right now - please check my PS2.\n\nThe only thing I left out was early validation of user managed identities. Although it makes perfect sense for subnets (which cannot be delete while you have VMs running in it), user identities can be deleted at any time.","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"},{"author":{"_account_id":36867,"name":"Zalan","display_name":"Zalan","email":"zalan.blenessy@volvocars.com","username":"zbleness"},"change_message_id":"0e7233ac50e1a99bea217b9771daf078754ca4e4","unresolved":true,"context_lines":[{"line_number":662,"context_line":"        for managed_identity in self._listManagedIdentities():"},{"line_number":663,"context_line":"            mi_id \u003d managed_identity[\u0027properties\u0027][\u0027clientId\u0027]"},{"line_number":664,"context_line":"            if mi_id in label.user_assigned_identities:"},{"line_number":665,"context_line":"                managed_identities[mi_id] \u003d managed_identity"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"        # fail if some identities are not found"},{"line_number":668,"context_line":"        if len(managed_identities) \u003c len(label.user_assigned_identities):"}],"source_content_type":"text/x-python","patch_set":1,"id":"eba8e41a_a334d4c8","line":665,"in_reply_to":"2a0643b0_556ecd9c","updated":"2024-03-08 15:51:07.000000000","message":"Thanks for your quick comments James!\n\nI actually started off with your second (simpler) approach but quickly realised that the Compute API forces us to specify the User-assigned Managed Identity as ARM Resource ID: https://learn.microsoft.com/en-us/rest/api/compute/virtual-machines/create-or-update?view\u003drest-compute-2023-10-02\u0026tabs\u003dHTTP#virtualmachineidentity\n\nSo a fundamental limitation is that we need to build the ARM Resource ID of the identities we want to use. The ARM Resource Id of a User-assigned Managed Identity is composed of:\n\n* Subscription Id\n* Resource Group Id\n* User-assigned Managed Identity Name\n\nIt is pretty safe to assume that the subscription will be the same, but what about the Resource Group ... can we assume that all managed identities will be found in providers.[azure].resource-group or should we give the possibility to specify different resource groups as well? Something like this:\n\n```\n            user-assigned-identities:\n              - name: userManagedIdentity1\n                resource-group: rg-non-default1\n              - name: userManagedIdentity2\n```\n\n(Assume providers.[azure].resource-group if resource-group is omitted)","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"},{"author":{"_account_id":36867,"name":"Zalan","display_name":"Zalan","email":"zalan.blenessy@volvocars.com","username":"zbleness"},"change_message_id":"61cdea133790b31df18a136a052a2e66a47d90bc","unresolved":true,"context_lines":[{"line_number":662,"context_line":"        for managed_identity in self._listManagedIdentities():"},{"line_number":663,"context_line":"            mi_id \u003d managed_identity[\u0027properties\u0027][\u0027clientId\u0027]"},{"line_number":664,"context_line":"            if mi_id in label.user_assigned_identities:"},{"line_number":665,"context_line":"                managed_identities[mi_id] \u003d managed_identity"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"        # fail if some identities are not found"},{"line_number":668,"context_line":"        if len(managed_identities) \u003c len(label.user_assigned_identities):"}],"source_content_type":"text/x-python","patch_set":1,"id":"ad63117e_d0ef80a8","line":665,"in_reply_to":"91659bdb_e38d39f8","updated":"2024-03-12 08:10:21.000000000","message":"I would probably not get this right on the first try so please help.","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"dab43cdd2fdfd4f4f09d538cf2e3af169d0a7169","unresolved":true,"context_lines":[{"line_number":662,"context_line":"        for managed_identity in self._listManagedIdentities():"},{"line_number":663,"context_line":"            mi_id \u003d managed_identity[\u0027properties\u0027][\u0027clientId\u0027]"},{"line_number":664,"context_line":"            if mi_id in label.user_assigned_identities:"},{"line_number":665,"context_line":"                managed_identities[mi_id] \u003d managed_identity"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"        # fail if some identities are not found"},{"line_number":668,"context_line":"        if len(managed_identities) \u003c len(label.user_assigned_identities):"}],"source_content_type":"text/x-python","patch_set":1,"id":"91659bdb_e38d39f8","line":665,"in_reply_to":"a565b35c_75b41564","updated":"2024-03-11 15:55:47.000000000","message":"That works for me.  I think the only thing missing at this point is a test that exercises the new code.  If it\u0027s not clear how to do that, I can add one; just let me know.","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"},{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"1b52adf24506c57012f0a8194bbd2664676502c7","unresolved":true,"context_lines":[{"line_number":662,"context_line":"        for managed_identity in self._listManagedIdentities():"},{"line_number":663,"context_line":"            mi_id \u003d managed_identity[\u0027properties\u0027][\u0027clientId\u0027]"},{"line_number":664,"context_line":"            if mi_id in label.user_assigned_identities:"},{"line_number":665,"context_line":"                managed_identities[mi_id] \u003d managed_identity"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"        # fail if some identities are not found"},{"line_number":668,"context_line":"        if len(managed_identities) \u003c len(label.user_assigned_identities):"}],"source_content_type":"text/x-python","patch_set":1,"id":"14e537aa_938c454b","line":665,"in_reply_to":"eba8e41a_a334d4c8","updated":"2024-03-09 19:53:56.000000000","message":"I think your second idea sounds good.  It mirrors how we handle subnets with {network: {resource-group: foo, network: bar}}\n\nAlso, I think it\u0027s better to use the resource-group + identity name rather than the identity client id, since the client id is randomly generated so the user would have to go look it up.  An alternative would be to ask the user to supply the ARM, which you can look up using the web ui in azure, but it\u0027s not as obvious, and I don\u0027t think we\u0027ve done that yet in nodepool, so this is better.\n\nSide note: we do perform validation that we can resolve the subnet by getting the network object from azure and then storing its id (rather than constructing the id blind).  But we perform that validation at startup rather than at instance creation time, so if there\u0027s a problem it\u0027s caught early.  I do still think it\u0027s okay to construct the user assigned identity ARM blind and catch the error at launch time, but if you did want to validate the ARM using a get call like I suggested earlier, you might consider doing it at startup right after we do that for the networks.  That would have the benefit of performing validation before any launches happen.\n\nI wrote a lot of extra info here; the only important part is the first sentence of this comment.  :)","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"}],"nodepool/driver/azure/azul.py":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"1b52adf24506c57012f0a8194bbd2664676502c7","unresolved":true,"context_lines":[{"line_number":277,"context_line":"            apiVersion\u003d\u00272019-04-01\u0027)"},{"line_number":278,"context_line":"        self.managed_identities \u003d AzureManagedIdentityCRUD("},{"line_number":279,"context_line":"            self,"},{"line_number":280,"context_line":"            apiVersion\u003d\u00272018-11-30\u0027)"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    def get(self, url, codes\u003d[200]):"},{"line_number":283,"context_line":"        return self.request(\u0027GET\u0027, url, None, codes)"}],"source_content_type":"text/x-python","patch_set":1,"id":"a900897f_444e80af","line":280,"range":{"start_line":280,"start_character":34,"end_line":280,"end_character":36},"updated":"2024-03-09 19:53:56.000000000","message":"If this stays, there\u0027s a later revision we might want to start with: 2023-01-31.","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"},{"author":{"_account_id":36867,"name":"Zalan","display_name":"Zalan","email":"zalan.blenessy@volvocars.com","username":"zbleness"},"change_message_id":"d041adc7ac691489498534fb91b423316bf37d6f","unresolved":true,"context_lines":[{"line_number":277,"context_line":"            apiVersion\u003d\u00272019-04-01\u0027)"},{"line_number":278,"context_line":"        self.managed_identities \u003d AzureManagedIdentityCRUD("},{"line_number":279,"context_line":"            self,"},{"line_number":280,"context_line":"            apiVersion\u003d\u00272018-11-30\u0027)"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    def get(self, url, codes\u003d[200]):"},{"line_number":283,"context_line":"        return self.request(\u0027GET\u0027, url, None, codes)"}],"source_content_type":"text/x-python","patch_set":1,"id":"74f7cc47_b8e90222","line":280,"range":{"start_line":280,"start_character":34,"end_line":280,"end_character":36},"in_reply_to":"a900897f_444e80af","updated":"2024-03-11 13:26:38.000000000","message":"Done","commit_id":"0db05eba83b08633ea04cbd6ec9598d8cf73ad05"}]}
