-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Support custom resource types being added to API_PROFILES #6173
Conversation
View a preview at https://prompt.ws/r/Azure/azure-cli/6173 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be helpful for extensions. Just comments about how this will be used.
super(StorageCommandsLoader, self).__init__(cli_ctx=cli_ctx, | ||
resource_type=ResourceType.DATA_STORAGE, | ||
custom_resource_types=custom_resource_types, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind of strange adding it here. The other kwargs are more sort of defaults that the commands from this loader will use.
The custom_resource_types
kwargs is used to inject new resourcetypes to the CLI.
Calling a function from core might make more sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to calling a function.
from azure.cli.core.profiles import API_PROFILES | ||
for profile, v in custom_resource_types.items(): | ||
if profile in API_PROFILES: | ||
API_PROFILES[profile].update(v) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of here, how about adding this update as a callable function in azure.cli.core.profiles?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've gone with that approach.
class StorageCommandsLoader(AzCommandsLoader): | ||
def __init__(self, cli_ctx=None): | ||
from azure.cli.core.commands import CliCommandType | ||
|
||
storage_custom = CliCommandType(operations_tmpl='azure.cli.command_modules.storage.custom#{}') | ||
custom_resource_types = {'latest': {CUSTOM_MGMT_STORAGE: '2015-06-15'}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This structure isn't really intuitive. It should be validated in the init. Otherwise an error will likely result in a stack trace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be resolved with Willie's suggestion.
3f36f10
to
40e5a10
Compare
Addressed feedback, please take another look. Usage would be something like this:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments on the augment_api_profile
syntax.
@@ -89,3 +89,15 @@ def get_sdk(cli_ctx, resource_type, *attr_args, **kwargs): | |||
'latest': AZURE_API_PROFILES['latest'], | |||
'2017-03-09-profile': AZURE_API_PROFILES['2017-03-09-profile'] | |||
} | |||
|
|||
|
|||
def augment_api_profiles(profile_name, resource_type, api_version): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if I wanted to add a resource type to multiple profiles I would have:
augment_api_profiles('latest', MY_RESOURCE_TYPE, '2016-05-01')
augment_api_profiles('2017-01-01-profile', MY_RESOURCE_TYPE, '2016-05-01')
...
A more concise syntax to consider:
register_resource_type(MY_RESOURCE_TYPE, {
'latest': '2016-05-01',
'2017-01-01-profile': '2016-05-01'
})
Essentially you specify the resource type once and then a dictionary of profile: version
pairs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requiring a dictionary argument seems confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @williexu, the dict format seems confusing and that was an original comment in my first implementation that allowed users to pass in a dict.
I could potentially change the method name from augment_api_profiles
to register_resource_type
if that's better for everyone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes to register_resource_type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see anything wrong with the dictionary implementation in the original. I don't like that I would have to repeat so much code repeatedly calling "augment_api_profiles" (or "register_resource_type") once for each resource type and each profile. I'd be curious what @troydai thinks here.
Something that looks closest to the API profile structure seems most logical to me (I have a feeling that's probably what your original implementation looked like--but I didn't have problems with that).
register_resource_types({
'latest': {
MY_RT_1: '2018-01-01',
MY_RT_2: '2018-01-01'
}
'2018-01-01-profile': {
MY_RT_1: '2018-01-01',
MY_RT_2: '2018-01-01'
}
})
It's essentially just a profile dictionary merge. I don't think that's necessarily confusing--just would just need to validate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tjprescott why not:
for profile in 'latest', '2018-...':
for rt in RT_1, RT_2:
register_resource_type(profile, rt, version)
@@ -24,6 +24,12 @@ def __str__(self): | |||
PROFILE_TYPE = object() | |||
|
|||
|
|||
class CustomResourceType(object): # pylint: disable=too-few-public-methods |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, what if you have to add an endpoint type in addition to or instead of a resource type? How would that be supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be part of #4786 which this does not address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it not make sense to implement these both at the same time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't block this, but I think we should tackle both resource types and endpoints at the same time so that the mechanisms are similar, and we should consider a mechanism that reduces the amount of duplication. Something that favors the natural profile dict structure makes sense to me.
While Profiles and Endpoints for clouds are related, they are intentionally separated in the source code because you can use the same profile with multiple clouds and there's no relation between the two in terms of Azure. That's why the cloud and profile code lives separately: I can take a look at adding support for that next though... |
from azure.cli.core.profiles._shared import get_versioned_sdk_path | ||
|
||
for rt in ResourceType: | ||
resource_types_in_profile = AZURE_API_PROFILES[self.cli_ctx.cloud.profile].keys() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if AZURE_API_PROFILE
is a map, you don't need the .keys()
here. Iterate a map is iterating on its keys.
>>> m={'a':1,'b':2}
>>> for i in m:
... print(i)
...
a
b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any chance a KeyError
throws here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed use of .keys()
a8366bd
to
5648f00
Compare
…mmits) Squashed commits: [9e2b19ca3] Fix style [70e140f49] Undo the changes used to test [40e5a10ba] Address feedback and add tests (+1 squashed commit) Squashed commits: [3f36f10ca] Support custom resource types being added to API_PROFILES - Only list through RTs in the current profile instead of all (no need to go through all)
5648f00
to
6b6a9ac
Compare
Marked as DNM for now to get feedback and also, it includes a change to storage that we wouldn't want to actually merge.