-
Notifications
You must be signed in to change notification settings - Fork 3k
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
[ACR] Improve perf and fix permission in repository commands #4566
Conversation
/cc @sajayantony |
/cc @yuwaMSFT2 |
if username is None: | ||
auth = _bearer_auth_str(password) | ||
else: | ||
auth = _basic_auth_str(username, password) | ||
|
||
if is_manifest: |
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.
Can you break this out into its own function like AddManifestHeader
retry_times=3, # pylint: disable=unused-argument | ||
retry_interval=5): # pylint: disable=unused-argument | ||
registryEndpoint = 'https://' + login_server | ||
def _params(count=20): |
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 function name is too generic and will lead to ambiguity. Please make it more accurate.
else: | ||
raise CLIError(response.text) | ||
def _delete_data_from_registry(login_server, path, username, password, **kwargs): | ||
retry_times = kwargs['retry_times'] if 'retry_times' in kwargs else 3 |
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 retry_times
is a value given by user through command line option, the default value should be defined with the parameter.
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.
Otherwise, why not list retry_times
and retry_interval
as the parameter in the method signature and define default value along with it?
raise CLIError(response.text) | ||
def _delete_data_from_registry(login_server, path, username, password, **kwargs): | ||
retry_times = kwargs['retry_times'] if 'retry_times' in kwargs else 3 | ||
retry_interval = kwargs['retry_interval'] if 'retry_interval' in kwargs else 5 |
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.
Same as above.
|
||
if errorMessage: |
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.
Consider user for ... else
in this situation: https://docs.python.org/2/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops
headers=_headers(username, password) | ||
) | ||
|
||
if response.status_code == 200 or response.status_code == 202: |
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.
Is this condition too rigorous? Do the other status code in 2XX represents a failure?
def _obtain_data_from_registry(login_server, path, username, password, **kwargs): | ||
result_index = kwargs['result_index'] if 'result_index' in kwargs else '' | ||
retry_times = kwargs['retry_times'] if 'retry_times' in kwargs else 3 | ||
retry_interval = kwargs['retry_interval'] if 'retry_interval' in kwargs else 5 |
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.
Same as above.
@@ -130,9 +146,43 @@ def _obtain_data_from_registry(login_server, | |||
return resultList | |||
|
|||
|
|||
def _get_manifest_digest(login_server, path, username, password, **kwargs): | |||
retry_times = kwargs['retry_times'] if 'retry_times' in kwargs else 3 | |||
retry_interval = kwargs['retry_interval'] if 'retry_interval' in kwargs else 5 |
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.
Same as above.
try: | ||
errorMessage = None | ||
response = requests.get( | ||
'https://{}/{}'.format(login_server, path), |
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.
Are login_server and path from user input? If so, should this be validated before form this URL?
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.
login_server
is queried from ACR RP.
for i in range(0, retry_times): | ||
try: | ||
errorMessage = None | ||
response = requests.get( |
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.
Is this sending a manifest GET request? If you only want to know the digest from response header, you can send HEAD request to avoid transferring the body which you don't care.
@@ -226,6 +276,7 @@ def acr_repository_show_tags(registry_name, | |||
registry_name=registry_name, | |||
resource_group_name=resource_group_name, | |||
path='/v2/{}/tags/list'.format(repository), | |||
permission='pull', |
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.
one question: for CLI to send request to registry, does it first get a challenge response from registry? If we do, there is information in the challenge response on what permission is needed. If we are not getting challenge response but hard-code the permission, there is a concern that this may change from the server side (although unlikely, just keep in mind).
retry_times=3, # pylint: disable=unused-argument | ||
retry_interval=5): # pylint: disable=unused-argument | ||
registryEndpoint = 'https://' + login_server | ||
def _params(count=20): |
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 this query parameter is used for all list related API calls (list manifest, catalog, tag list)?
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.
Correct, all registry list calls will use this pagination count by default.
registryEndpoint + path, | ||
headers=_headers(username, password) | ||
) | ||
def _pagination_params(count): |
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.
A preferable method naming schema is verb + noun.
print(login_server) | ||
print(username) | ||
print(password) | ||
print(pagination) |
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.
Wait ... what's this? Please don't print password.
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.
Missed the cleanup here :-)
repository, | ||
tag, | ||
manifest, | ||
yes): |
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
is not a good parameter name. how about changes it to confirmed
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
is the parameter exposed to users so it seems natural to use it along the path rather than creating a new name internally.
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 believe "yes" is required by the CLI for confirmation... #2520
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.
Oh, my bad. But it is not a good name anyway. We may need to address this in the core.
path='/v2/{}/manifests/{}'.format(repository, tag), | ||
username=username, | ||
password=password | ||
) |
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.
The indentations and condition statement can be saved in the following form:
manifest = manifest or _get_manifest_digest(...)
|
||
|
||
class Unauthorized(Exception): | ||
class RetryableException(Exception): |
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.
Why do you define a new type of exception while there isn't any mechanism to treat this exception differently (for example, except RetryableException
.)?
Please avoid introducing new exception type unless there is specific logic build around it.
if errorMessage: | ||
raise CLIError(errorMessage) | ||
if errorMessage: | ||
raise CLIError(errorMessage) |
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.
Ugr, this is not a minor formatting update. This change the control flow. Please double check and make sure this is what you intended to do.
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 is an intended change, the error should be on the retry for loop.
@troydai Please merge this PR if there is no more comments, thank you. |
@troydai Can you please merge this? Thank you :-) |
list-manifests
call when users wish to force delete a manifest either by digest or tag.This checklist is used to make sure that common guidelines for a pull request are followed.
General Guidelines
Command Guidelines
(see Authoring Command Modules)