Ejemplo n.º 1
0
def _validate_whl_extension(ext_file):
    tmp_dir = tempfile.mkdtemp()
    zip_ref = zipfile.ZipFile(ext_file, 'r')
    zip_ref.extractall(tmp_dir)
    zip_ref.close()
    azext_metadata = WheelExtension.get_azext_metadata(tmp_dir)
    rmtree_with_retry(tmp_dir)
    check_version_compatibility(azext_metadata)
Ejemplo n.º 2
0
def update_extension(cmd=None,
                     extension_name=None,
                     index_url=None,
                     pip_extra_index_urls=None,
                     pip_proxy=None,
                     cli_ctx=None,
                     version=None):
    try:
        cmd_cli_ctx = cli_ctx or cmd.cli_ctx
        ext = get_extension(extension_name, ext_type=WheelExtension)
        cur_version = ext.get_version()
        try:
            download_url, ext_sha256 = resolve_from_index(
                extension_name,
                cur_version=cur_version,
                index_url=index_url,
                target_version=version,
                cli_ctx=cmd_cli_ctx)
            _, ext_version = _get_extension_info_from_source(download_url)
            set_extension_management_detail(extension_name, ext_version)
        except NoExtensionCandidatesError as err:
            logger.debug(err)
            msg = "Extension {} with version {} not found.".format(
                extension_name, version
            ) if version else "No updates available for '{}'. Use --debug for more information.".format(
                extension_name)
            logger.warning(msg)
            return
        # Copy current version of extension to tmp directory in case we need to restore it after a failed install.
        backup_dir = os.path.join(tempfile.mkdtemp(), extension_name)
        extension_path = ext.path
        logger.debug('Backing up the current extension: %s to %s',
                     extension_path, backup_dir)
        shutil.copytree(extension_path, backup_dir)
        # Remove current version of the extension
        rmtree_with_retry(extension_path)
        # Install newer version
        try:
            _add_whl_ext(cli_ctx=cmd_cli_ctx,
                         source=download_url,
                         ext_sha256=ext_sha256,
                         pip_extra_index_urls=pip_extra_index_urls,
                         pip_proxy=pip_proxy)
            logger.debug('Deleting backup of old extension at %s', backup_dir)
            rmtree_with_retry(backup_dir)
        except Exception as err:
            logger.error('An error occurred whilst updating.')
            logger.error(err)
            logger.debug('Copying %s to %s', backup_dir, extension_path)
            shutil.copytree(backup_dir, extension_path)
            raise CLIError('Failed to update. Rolled {} back to {}.'.format(
                extension_name, cur_version))
        CommandIndex().invalidate()
    except ExtensionNotInstalledException as e:
        raise CLIError(e)
Ejemplo n.º 3
0
def remove_extension(extension_name):
    try:
        # Get the extension and it will raise an error if it doesn't exist
        ext = get_extension(extension_name)
        if ext and isinstance(ext, DevExtension):
            raise CLIError(
                "Extension '{name}' was installed in development mode. Remove using "
                "`azdev extension remove {name}`".format(name=extension_name))
        # We call this just before we remove the extension so we can get the metadata before it is gone
        _augment_telemetry_with_ext_info(extension_name, ext)
        rmtree_with_retry(ext.path)
        CommandIndex().invalidate()
    except ExtensionNotInstalledException as e:
        raise CLIError(e)
Ejemplo n.º 4
0
def _upgrade_on_windows():
    """Download MSI to a temp folder and install it with msiexec.exe.
    Directly installing from URL may be blocked by policy: https://github.com/Azure/azure-cli/issues/19171
    This also gives the user a chance to manually install the MSI in case of msiexec.exe failure.
    """
    logger.warning(
        "Updating Azure CLI with MSI from https://aka.ms/installazurecliwindows"
    )
    tmp_dir, msi_path = _download_from_url(
        'https://aka.ms/installazurecliwindows')

    logger.warning("Installing MSI")
    import subprocess
    exit_code = subprocess.call(['msiexec.exe', '/i', msi_path])

    if exit_code:
        logger.warning("Installation Failed. You may manually install %s",
                       msi_path)
    else:
        from azure.cli.core.util import rmtree_with_retry
        logger.warning("Succeeded. Deleting %s", tmp_dir)
        rmtree_with_retry(tmp_dir)
    return exit_code
Ejemplo n.º 5
0
def _add_whl_ext(cli_ctx, source, ext_sha256=None, pip_extra_index_urls=None, pip_proxy=None, system=None):  # pylint: disable=too-many-statements
    cli_ctx.get_progress_controller().add(message='Analyzing')
    if not source.endswith('.whl'):
        raise ValueError('Unknown extension type. Only Python wheels are supported.')
    url_parse_result = urlparse(source)
    is_url = (url_parse_result.scheme == 'http' or url_parse_result.scheme == 'https')
    logger.debug('Extension source is url? %s', is_url)
    whl_filename = os.path.basename(url_parse_result.path) if is_url else os.path.basename(source)
    parsed_filename = WHEEL_INFO_RE(whl_filename)
    # Extension names can have - but .whl format changes it to _ (PEP 0427). Undo this.
    extension_name = parsed_filename.groupdict().get('name').replace('_', '-') if parsed_filename else None
    if not extension_name:
        raise CLIError('Unable to determine extension name from {}. Is the file name correct?'.format(source))
    if extension_exists(extension_name, ext_type=WheelExtension):
        raise CLIError('The extension {} already exists.'.format(extension_name))
    if extension_name == 'rdbms-connect':
        _install_deps_for_psycopg2()
    ext_file = None
    if is_url:
        # Download from URL
        tmp_dir = tempfile.mkdtemp()
        ext_file = os.path.join(tmp_dir, whl_filename)
        logger.debug('Downloading %s to %s', source, ext_file)
        import requests
        try:
            cli_ctx.get_progress_controller().add(message='Downloading')
            _whl_download_from_url(url_parse_result, ext_file)
        except (requests.exceptions.ConnectionError, requests.exceptions.HTTPError) as err:
            raise CLIError('Please ensure you have network connection. Error detail: {}'.format(str(err)))
        logger.debug('Downloaded to %s', ext_file)
    else:
        # Get file path
        ext_file = os.path.realpath(os.path.expanduser(source))
        if not os.path.isfile(ext_file):
            raise CLIError("File {} not found.".format(source))
    # Validate the extension
    logger.debug('Validating the extension %s', ext_file)
    if ext_sha256:
        valid_checksum, computed_checksum = is_valid_sha256sum(ext_file, ext_sha256)
        if valid_checksum:
            logger.debug("Checksum of %s is OK", ext_file)
        else:
            logger.debug("Invalid checksum for %s. Expected '%s', computed '%s'.",
                         ext_file, ext_sha256, computed_checksum)
            raise CLIError("The checksum of the extension does not match the expected value. "
                           "Use --debug for more information.")
    try:
        cli_ctx.get_progress_controller().add(message='Validating')
        _validate_whl_extension(ext_file)
    except AssertionError:
        logger.debug(traceback.format_exc())
        raise CLIError('The extension is invalid. Use --debug for more information.')
    except CLIError as e:
        raise e
    logger.debug('Validation successful on %s', ext_file)
    # Check for distro consistency
    check_distro_consistency()
    cli_ctx.get_progress_controller().add(message='Installing')
    # Install with pip
    extension_path = build_extension_path(extension_name, system)
    pip_args = ['install', '--target', extension_path, ext_file]

    if pip_proxy:
        pip_args = pip_args + ['--proxy', pip_proxy]
    if pip_extra_index_urls:
        for extra_index_url in pip_extra_index_urls:
            pip_args = pip_args + ['--extra-index-url', extra_index_url]

    logger.debug('Executing pip with args: %s', pip_args)
    with HomebrewPipPatch():
        pip_status_code = _run_pip(pip_args, extension_path)
    if pip_status_code > 0:
        logger.debug('Pip failed so deleting anything we might have installed at %s', extension_path)
        rmtree_with_retry(extension_path)
        raise CLIError('An error occurred. Pip failed with status code {}. '
                       'Use --debug for more information.'.format(pip_status_code))
    # Save the whl we used to install the extension in the extension dir.
    dst = os.path.join(extension_path, whl_filename)
    shutil.copyfile(ext_file, dst)
    logger.debug('Saved the whl to %s', dst)

    return extension_name