Skip to content

Conversation

@fengzhou-msft
Copy link
Member

@fengzhou-msft fengzhou-msft commented Apr 2, 2020

Description of PR (Mandatory)
(Why this PR? What is changed? What is the effect? etc. A high-quality description can accelerate the review process)
Resolve #9831.
Currently users can set AZURE_EXTENSION_DIR env variable to install extensions in a customized path. But this has a limit to install all extensions in one directory.

This PR adds an option --system to az extension add. So users can choose to install an extension in either a user path or a system path, but not able to install the same extension in both paths. az will search and load all the extensions in both paths. On Windows, users need to open the shell as Administrator to install extensions with --system.

The system directory is also configurable by env var AZURE_EXTENSION_SYS_DIR. The default is the azure-cli-extensions folder under the lib path of the python that az is using.
On windows with MSI, the directory is:
C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\lib\site-packages\azure-cli-extensions
On Ubuntu:
/opt/az/lib/python3.6/site-packages/azure-cli-extensions
On CentOS:
/usr/lib/python3.6/site-packages/azure-cli-extensions
On MacOS:
/usr/local/Cellar/azure-cli/2.3.1/libexec/lib/python3.8/site-packages/azure-cli-extensions

This PR also reduces the invoke of get_extension when possible since it will load all extensions.

Testing Guide
(Example commands with explanations)
az extension add -n extension-name --system
az extension show -n extension-name

History Notes:
(Fill in the following template if multiple notes are needed, otherwise PR title will be used for history note.)

[Extension] az extension add: Add --system to enable installing extensions in a system path


This checklist is used to make sure that common guidelines for a pull request are followed.

'cliextensions')
DEV_EXTENSION_SOURCES = _DEV_EXTENSION_SOURCES.split(',') if _DEV_EXTENSION_SOURCES else []
EXTENSIONS_SYS_DIR = os.path.join(get_python_lib(), 'azure-cli-extensions') if sys.platform.startswith('linux') else ""
EXTENSIONS_SYS_DIR = os.path.expanduser(_CUSTOM_EXT_SYS_DIR) if _CUSTOM_EXT_SYS_DIR else os.path.join(get_python_lib(), 'azure-cli-extensions')
Copy link
Member Author

Choose a reason for hiding this comment

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

Need to test if this also works on Windows and Mac.

Copy link
Member Author

Choose a reason for hiding this comment

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

On windows, users need to open the shell as administrator. I have added message when users encounter the permission error.

Copy link
Member

Choose a reason for hiding this comment

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

run as admin only required when user set customized install dir right? if yes, then less concern since no change to existing behavoir

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, not affecting default extension installation.

Comment on lines 223 to 234
extension_name = _add_whl_ext(cmd=cmd, source=source, ext_sha256=ext_sha256,
pip_extra_index_urls=pip_extra_index_urls, pip_proxy=pip_proxy)
_augment_telemetry_with_ext_info(extension_name)
pip_extra_index_urls=pip_extra_index_urls, pip_proxy=pip_proxy, system=system)
ext = get_extension(extension_name)
_augment_telemetry_with_ext_info(extension_name, ext)
try:
if extension_name and get_extension(extension_name).experimental:
if extension_name and ext.experimental:
logger.warning("The installed extension '%s' is experimental and not covered by customer support. "
"Please use with discretion.", extension_name)
elif extension_name and get_extension(extension_name).preview:
elif extension_name and ext.preview:
logger.warning("The installed extension '%s' is in preview.", extension_name)
Copy link
Member Author

Choose a reason for hiding this comment

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

get_extension calls get_extensions to load all extension, then fetch the extension with the name, we should avoid calling it mulitple times.

@fengzhou-msft fengzhou-msft force-pushed the install_system_extension branch from a40c461 to 5c6e0c3 Compare April 3, 2020 02:52
@yonzhan yonzhan added this to the S168 milestone Apr 11, 2020
@yonzhan
Copy link
Collaborator

yonzhan commented Apr 11, 2020

add to S168

@fengzhou-msft fengzhou-msft changed the title [WIP][Extension] Support installing extensions in a system directory [Extension] Support installing extensions in a system directory Apr 14, 2020
return os.path.join(EXTENSIONS_DIR, ext_name)
ext_sys_path = os.path.join(EXTENSIONS_SYS_DIR, ext_name)
ext_path = os.path.join(EXTENSIONS_DIR, ext_name)
return ext_path if os.path.isdir(ext_path) else (
Copy link
Contributor

Choose a reason for hiding this comment

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

add os.path.isdir(ext_path) check here, is it because previous code may case potential bug ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Previous code use get_extension_path both before install when this path does not exist and when loading extensions. I splitted it to use the below build_extension_path for building the path before install, and to use this get_extension_path only for loading extensions. So we can add the isdir check here now.

try:
if extension_name and get_extension(extension_name).experimental:
ext = get_extension(extension_name)
_augment_telemetry_with_ext_info(extension_name, ext)
Copy link
Contributor

Choose a reason for hiding this comment

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

move telemetry part into the try/except, so if get_extension throw exception, it will not be executed, right ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. get_extension was also called in _augment_telemetry_with_ext_info in previous code and it will be catched inside. And I think it's the same flow.

'cliextensions')
DEV_EXTENSION_SOURCES = _DEV_EXTENSION_SOURCES.split(',') if _DEV_EXTENSION_SOURCES else []
EXTENSIONS_SYS_DIR = os.path.join(get_python_lib(), 'azure-cli-extensions') if sys.platform.startswith('linux') else ""
EXTENSIONS_SYS_DIR = os.path.expanduser(_CUSTOM_EXT_SYS_DIR) if _CUSTOM_EXT_SYS_DIR else os.path.join(get_python_lib(), 'azure-cli-extensions')
Copy link
Member

Choose a reason for hiding this comment

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

run as admin only required when user set customized install dir right? if yes, then less concern since no change to existing behavoir

except CalledProcessError as e:
logger.debug(e.output)
logger.debug(e)
if "PermissionError: [WinError 5]" in e.output:
Copy link
Member

Choose a reason for hiding this comment

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

what's default install path after the change? suppose no change

Copy link
Member Author

Choose a reason for hiding this comment

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

yes. no change for the default extension path.

_print("Extensions directory '{}'".format(EXTENSIONS_DIR))
import os
if os.path.isdir(EXTENSIONS_SYS_DIR) and os.listdir(EXTENSIONS_SYS_DIR):
_print("Extensions system directory '{}'".format(EXTENSIONS_SYS_DIR))
Copy link
Member

Choose a reason for hiding this comment

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

it's little confusing, how about direct show as Extensions directory

Copy link
Member Author

Choose a reason for hiding this comment

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

The idea is to have no impact on users who don't use --system to install extensions. This will only be shown when users have installed at least one extension with --system.

@yonzhan yonzhan modified the milestones: S168, S169 - For Build Apr 18, 2020
@haroldrandom
Copy link
Contributor

haroldrandom commented Apr 29, 2020

Would it be better install to inside site-package/ directly?

@fengzhou-msft
Copy link
Member Author

Would it be better install to inside site-package/ directly?

I think it's more organized with the azure-cli-extensions folder. What's the benefit of installing inside site-package/ directly?

@haroldrandom
Copy link
Contributor

haroldrandom commented May 1, 2020

What's the benefit of installing inside site-package/ directly?

a dedicated folder will do as this PR #12367.
This feature wild make #12367 also work on Windows.

BTW, we should consider the way how user are developing extension. #13286

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

az extension add should give an option to install extension for all users (i.e. at a machine level)

6 participants