コード例 #1
0
ファイル: _docker_utils.py プロジェクト: shurd/azure-cli
def _get_aad_token(cli_ctx,
                   login_server,
                   only_refresh_token,
                   repository=None,
                   artifact_repository=None,
                   permission=None):
    """Obtains refresh and access tokens for an AAD-enabled registry.
    :param str login_server: The registry login server URL to log in to
    :param bool only_refresh_token: Whether to ask for only refresh token, or for both refresh and access tokens
    :param str repository: Repository for which the access token is requested
    :param str artifact_repository: Artifact repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    if repository and artifact_repository:
        raise ValueError(
            "Only one of repository and artifact_repository can be provided.")

    if (repository or
            artifact_repository) and permission not in ACCESS_TOKEN_PERMISSION:
        raise ValueError(
            "Permission is required for a repository or artifact_repository. Allowed access token permission: {}"
            .format(ACCESS_TOKEN_PERMISSION))

    login_server = login_server.rstrip('/')

    challenge = requests.get('https://' + login_server + '/v2/',
                             verify=(not should_disable_connection_verify()))
    if challenge.status_code not in [
            401
    ] or 'WWW-Authenticate' not in challenge.headers:
        raise CLIError(
            "Registry '{}' did not issue a challenge.".format(login_server))

    authenticate = challenge.headers['WWW-Authenticate']

    tokens = authenticate.split(' ', 2)
    if len(tokens) < 2 or tokens[0].lower() != 'bearer':
        raise CLIError(
            "Registry '{}' does not support AAD login.".format(login_server))

    params = {
        y[0]: y[1].strip('"')
        for y in (x.strip().split('=', 2) for x in tokens[1].split(','))
    }
    if 'realm' not in params or 'service' not in params:
        raise CLIError(
            "Registry '{}' does not support AAD login.".format(login_server))

    authurl = urlparse(params['realm'])
    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/exchange', '', '', ''))

    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cli_ctx)
    creds, _, tenant = profile.get_raw_token()

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    content = {
        'grant_type': 'access_token',
        'service': params['service'],
        'tenant': tenant,
        'access_token': creds[1]
    }

    response = requests.post(authhost,
                             urlencode(content),
                             headers=headers,
                             verify=(not should_disable_connection_verify()))

    if response.status_code not in [200]:
        raise CLIError(
            "Access to registry '{}' was denied. Response code: {}.".format(
                login_server, response.status_code))

    refresh_token = loads(response.content.decode("utf-8"))["refresh_token"]
    if only_refresh_token:
        return refresh_token

    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/token', '', '', ''))

    if repository:
        scope = 'repository:{}:{}'.format(repository, permission)
    elif artifact_repository:
        scope = 'artifact-repository:{}:{}'.format(artifact_repository,
                                                   permission)
    else:
        # catalog only has * as permission, even for a read operation
        scope = 'registry:catalog:*'

    content = {
        'grant_type': 'refresh_token',
        'service': login_server,
        'scope': scope,
        'refresh_token': refresh_token
    }
    response = requests.post(authhost,
                             urlencode(content),
                             headers=headers,
                             verify=(not should_disable_connection_verify()))
    access_token = loads(response.content.decode("utf-8"))["access_token"]

    return access_token
コード例 #2
0
ファイル: _utils.py プロジェクト: ymasaoka/azure-cli
def _invalid_sku_downgrade():
    raise CLIError(
        "Managed registries could not be downgraded to Classic SKU.")
コード例 #3
0
def get_one_of_subscription_locations(cli_ctx):
    result = get_subscription_locations(cli_ctx)
    if result:
        return next((r.name for r in result if r.name.lower() == 'westus'),
                    result[0].name)
    raise CLIError('Current subscription does not have valid location list')
コード例 #4
0
def _build_odata_filter(default_filter, field_name, field_value, field_label):
    if not field_value:
        from knack.util import CLIError
        raise CLIError('Value for {} can not be empty.'.format(field_name))

    return _add_condition(default_filter, field_label, field_value)
コード例 #5
0
def validate_timeout_value(namespace):
    """Validates that zip deployment timeout is set to a reasonable min value"""
    if isinstance(namespace.timeout, int):
        if namespace.timeout <= 29:
            raise CLIError('--timeout value should be a positive value in seconds and should be at least 30')
コード例 #6
0
def create_pull_request(project=None,
                        repository=None,
                        source_branch=None,
                        target_branch=None,
                        title=None,
                        description=None,
                        auto_complete=False,
                        squash=False,
                        delete_source_branch=False,
                        bypass_policy=False,
                        bypass_policy_reason=None,
                        merge_commit_message=None,
                        reviewers=None,
                        work_items=None,
                        draft=None,
                        open=False,
                        organization=None,
                        detect=None,
                        transition_work_items=False):  # pylint: disable=redefined-builtin
    """Create a pull request.
    :param project: Name or ID of the team project.
    :type project: str
    :param repository: Name or ID of the repository to create the pull request in.
    :type repository: str
    :param source_branch: Name of the source branch. Example: "dev".
    :type source_branch: str
    :param target_branch: Name of the target branch. If not specified, defaults to the
                          default branch of the target repository.
    :type target_branch: str
    :param title: Title for the new pull request.
    :type title: str
    :param draft: Use this flag to create the pull request in draft/work in progress mode.
    :type draft: bool
    :param description: Description for the new pull request. Can include markdown.
                        Each value sent to this arg will be a new line.
                        For example: --description "First Line" "Second Line"
    :type description: list of str
    :param auto_complete: Set the pull request to complete automatically when all policies have passed and
                          the source branch can be merged into the target branch.
    :type auto_complete: bool
    :param squash: Squash the commits in the source branch when merging into the target branch.
    :type squash: bool
    :param delete_source_branch: Delete the source branch after the pull request has been completed
                                 and merged into the target branch.
    :type delete_source_branch: bool
    :param bypass_policy: Bypass required policies (if any) and completes the pull request once it
                          can be merged.
    :type bypass_policy: bool
    :param bypass_policy_reason: Reason for bypassing the required policies.
    :type bypass_policy_reason: str
    :param merge_commit_message: Message displayed when commits are merged.
    :type merge_commit_message: str
    :param reviewers: Additional users or groups to include as reviewers on the new pull request.
                      Space separated.
    :type reviewers: list of str
    :param work_items: IDs of the work items to link to the new pull request. Space separated.
    :type work_items: list of str
    :param open: Open the pull request in your web browser.
    :type open: bool
    :param transition_work_items: Transition any work items linked to the pull request into the next logical state.
                   (e.g. Active -> Resolved)
    :type transition_work_items: bool
    :rtype: :class:`GitPullRequest <v5_0.git.models.GitPullRequest>`
    """
    organization, project, repository = resolve_instance_project_and_repo(
        detect=detect,
        organization=organization,
        project=project,
        repo=repository)
    source_branch, target_branch = _get_branches_for_pull_request(
        organization, project, repository, source_branch, target_branch,
        detect)
    client = get_git_client(organization)
    multi_line_description = None
    if description is not None:
        multi_line_description = '\n'.join(description)
    pr = GitPullRequest(description=multi_line_description,
                        source_ref_name=source_branch,
                        target_ref_name=target_branch)
    if draft is not None:
        pr.is_draft = draft
    if title is not None:
        pr.title = title
    else:
        pr.title = 'Merge ' + source_branch + ' to ' + target_branch
    pr.source_ref_name = resolve_git_ref_heads(source_branch)
    pr.target_ref_name = resolve_git_ref_heads(target_branch)
    if pr.source_ref_name == pr.target_ref_name:
        raise CLIError(
            'The source branch, "{}", can not be the same as the target branch.'
            .format(pr.source_ref_name))
    pr.reviewers = _resolve_reviewers_as_refs(reviewers, organization)
    if work_items is not None and work_items:
        resolved_work_items = []
        for work_item in work_items:
            resolved_work_items.append(ResourceRef(id=work_item))
        pr.work_item_refs = resolved_work_items
    pr = client.create_pull_request(git_pull_request_to_create=pr,
                                    project=project,
                                    repository_id=repository)
    title_from_commit = None
    if title is None:
        # if title wasn't specified and only one commit, we will set the PR title to the comment of that commit
        commits = client.get_pull_request_commits(
            repository_id=repository,
            pull_request_id=pr.pull_request_id,
            project=project)
        if len(commits) == 1:
            title_from_commit = commits[0].comment
    set_completion_options = (bypass_policy or bypass_policy_reason is not None
                              or squash or merge_commit_message is not None
                              or delete_source_branch or transition_work_items)
    if auto_complete or set_completion_options or title_from_commit is not None:
        pr_for_update = GitPullRequest()
        if auto_complete:
            # auto-complete will not get set on create, so a subsequent update is required.
            pr_for_update.auto_complete_set_by = IdentityRef(
                id=resolve_identity_as_id(ME, organization))
        if set_completion_options:
            completion_options = GitPullRequestCompletionOptions()
            completion_options.bypass_policy = bypass_policy
            completion_options.bypass_reason = bypass_policy_reason
            completion_options.delete_source_branch = delete_source_branch
            completion_options.squash_merge = squash
            completion_options.merge_commit_message = merge_commit_message
            completion_options.transition_work_items = transition_work_items
            pr_for_update.completion_options = completion_options
        if title_from_commit is not None:
            pr_for_update.title = title_from_commit
        pr = client.update_pull_request(
            git_pull_request_to_update=pr_for_update,
            project=pr.repository.project.id,
            repository_id=pr.repository.id,
            pull_request_id=pr.pull_request_id)
    if open:
        _open_pull_request(pr, organization)
    return pr
コード例 #7
0
def process_ts_create_or_update_namespace(namespace):
    from azure.cli.core.commands.validators import validate_tags
    validate_tags(namespace)
    if namespace.template_file and not os.path.isfile(namespace.template_file):
        raise CLIError('Please enter a valid file path')
コード例 #8
0
def send_raw_request(
        cli_ctx,
        method,
        url,
        headers=None,
        uri_parameters=None,  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
        body=None,
        skip_authorization_header=False,
        resource=None,
        output_file=None,
        generated_client_request_id_name='x-ms-client-request-id'):
    import uuid
    from requests import Session, Request
    from requests.structures import CaseInsensitiveDict

    result = CaseInsensitiveDict()
    for s in headers or []:
        try:
            temp = shell_safe_json_parse(s)
            result.update(temp)
        except CLIError:
            key, value = s.split('=', 1)
            result[key] = value
    headers = result

    # If Authorization header is already provided, don't bother with the token
    if 'Authorization' in headers:
        skip_authorization_header = True

    # Handle User-Agent
    agents = [get_az_user_agent()]

    # Borrow AZURE_HTTP_USER_AGENT from msrest
    # https://github.com/Azure/msrest-for-python/blob/4cc8bc84e96036f03b34716466230fb257e27b36/msrest/pipeline/universal.py#L70
    _ENV_ADDITIONAL_USER_AGENT = 'AZURE_HTTP_USER_AGENT'
    import os
    if _ENV_ADDITIONAL_USER_AGENT in os.environ:
        agents.append(os.environ[_ENV_ADDITIONAL_USER_AGENT])

    # Custom User-Agent provided as command argument
    if 'User-Agent' in headers:
        agents.append(headers['User-Agent'])
    headers['User-Agent'] = ' '.join(agents)

    if generated_client_request_id_name:
        headers[generated_client_request_id_name] = str(uuid.uuid4())

    # try to figure out the correct content type
    if body:
        try:
            _ = shell_safe_json_parse(body)
            if 'Content-Type' not in headers:
                headers['Content-Type'] = 'application/json'
        except Exception:  # pylint: disable=broad-except
            pass

    # add telemetry
    headers['CommandName'] = cli_ctx.data['command']
    if cli_ctx.data.get('safe_params'):
        headers['ParameterSetName'] = ' '.join(cli_ctx.data['safe_params'])

    result = {}
    for s in uri_parameters or []:
        try:
            temp = shell_safe_json_parse(s)
            result.update(temp)
        except CLIError:
            key, value = s.split('=', 1)
            result[key] = value
    uri_parameters = result or None

    endpoints = cli_ctx.cloud.endpoints
    # If url is an ARM resource ID, like /subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01,
    # default to Azure Resource Manager.
    # https://management.azure.com + /subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01
    if '://' not in url:
        url = endpoints.resource_manager.rstrip('/') + url

    # Replace common tokens with real values. It is for smooth experience if users copy and paste the url from
    # Azure Rest API doc
    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cli_ctx)
    if '{subscriptionId}' in url:
        url = url.replace(
            '{subscriptionId}', cli_ctx.data['subscription_id']
            or profile.get_subscription_id())

    # Prepare the Bearer token for `Authorization` header
    if not skip_authorization_header and url.lower().startswith('https://'):
        # Prepare `resource` for `get_raw_token`
        if not resource:
            # If url starts with ARM endpoint, like `https://management.azure.com/`,
            # use `active_directory_resource_id` for resource, like `https://management.core.windows.net/`.
            # This follows the same behavior as `azure.cli.core.commands.client_factory._get_mgmt_service_client`
            if url.lower().startswith(endpoints.resource_manager.rstrip('/')):
                resource = endpoints.active_directory_resource_id
            else:
                from azure.cli.core.cloud import CloudEndpointNotSetException
                for p in [x for x in dir(endpoints) if not x.startswith('_')]:
                    try:
                        value = getattr(endpoints, p)
                    except CloudEndpointNotSetException:
                        continue
                    if isinstance(value,
                                  six.string_types) and url.lower().startswith(
                                      value.lower()):
                        resource = value
                        break
        if resource:
            # Prepare `subscription` for `get_raw_token`
            # If this is an ARM request, try to extract subscription ID from the URL.
            # But there are APIs which don't require subscription ID, like /subscriptions, /tenants
            # TODO: In the future when multi-tenant subscription is supported, we won't be able to uniquely identify
            #   the token from subscription anymore.
            token_subscription = None
            if url.lower().startswith(endpoints.resource_manager.rstrip('/')):
                token_subscription = _extract_subscription_id(url)
            if token_subscription:
                logger.debug(
                    'Retrieving token for resource %s, subscription %s',
                    resource, token_subscription)
                token_info, _, _ = profile.get_raw_token(
                    resource, subscription=token_subscription)
            else:
                logger.debug('Retrieving token for resource %s', resource)
                token_info, _, _ = profile.get_raw_token(resource)
            token_type, token, _ = token_info
            headers = headers or {}
            headers['Authorization'] = '{} {}'.format(token_type, token)
        else:
            logger.warning(
                "Can't derive appropriate Azure AD resource from --url to acquire an access token. "
                "If access token is required, use --resource to specify the resource"
            )
    try:
        # https://requests.readthedocs.io/en/latest/user/advanced/#prepared-requests
        s = Session()
        req = Request(method=method,
                      url=url,
                      headers=headers,
                      params=uri_parameters,
                      data=body)
        prepped = s.prepare_request(req)

        # Merge environment settings into session
        settings = s.merge_environment_settings(
            prepped.url, {}, None, not should_disable_connection_verify(),
            None)
        _log_request(prepped)
        r = s.send(prepped, **settings)
        _log_response(r)
    except Exception as ex:  # pylint: disable=broad-except
        raise CLIError(ex)

    if not r.ok:
        reason = r.reason
        if r.text:
            reason += '({})'.format(r.text)
        raise CLIError(reason)
    if output_file:
        with open(output_file, 'wb') as fd:
            for chunk in r.iter_content(chunk_size=128):
                fd.write(chunk)
    return r
コード例 #9
0
 def _check_stale(self):
     if self.is_stale:
         message = "command authoring error: argument context '{}' is stale! " \
                   "Check that the subsequent block for has a corresponding `as` statement.".format(self.scope)
         logger.error(message)
         raise CLIError(message)
コード例 #10
0
ファイル: repository.py プロジェクト: wnjenkin/azure-cli
def acr_repository_delete(cmd,
                          registry_name,
                          repository=None,
                          image=None,
                          tag=None,
                          manifest=None,
                          resource_group_name=None,
                          username=None,
                          password=None,
                          yes=False):
    if bool(repository) == bool(image):
        raise CLIError('Usage error: --image IMAGE | --repository REPOSITORY')

    # Check if this is a legacy command. --manifest can be used as a flag so None is checked.
    if repository and (tag or manifest is not None):
        return _legacy_delete(cmd=cmd,
                              registry_name=registry_name,
                              repository=repository,
                              tag=tag,
                              manifest=manifest,
                              resource_group_name=resource_group_name,
                              username=username,
                              password=password,
                              yes=yes)

    # At this point the specified command must not be a legacy command so we process it as a new command.
    # If --tag/--manifest are specified with --repository, it's a legacy command handled above.
    # If --tag/--manifest are specified with --image, error out here.
    if tag:
        raise CLIError("The parameter --tag is redundant and deprecated. Please use --image to delete an image.")
    if manifest is not None:
        raise CLIError("The parameter --manifest is redundant and deprecated. Please use --image to delete an image.")

    _, resource_group_name = validate_managed_registry(
        cmd.cli_ctx, registry_name, resource_group_name, DELETE_NOT_SUPPORTED)

    if image:
        # If --image is specified, repository/tag/manifest must be empty.
        repository, tag, manifest = _parse_image_name(image, allow_digest=True)

    login_server, username, password = get_access_credentials(
        cli_ctx=cmd.cli_ctx,
        registry_name=registry_name,
        resource_group_name=resource_group_name,
        username=username,
        password=password,
        repository=repository,
        permission='*')

    if tag or manifest:
        manifest = _delete_manifest_confirmation(
            login_server=login_server,
            username=username,
            password=password,
            repository=repository,
            tag=tag,
            manifest=manifest,
            yes=yes)
        path = '/v2/{}/manifests/{}'.format(repository, manifest)
    else:
        _user_confirmation("Are you sure you want to delete the repository '{}' "
                           "and all images under it?".format(repository), yes)
        path = '/v2/_acr/{}/repository'.format(repository)

    return _delete_data_from_registry(
        login_server=login_server,
        path=path,
        username=username,
        password=password)
コード例 #11
0
ファイル: repository.py プロジェクト: wnjenkin/azure-cli
def _legacy_delete(cmd,
                   registry_name,
                   repository,
                   tag=None,
                   manifest=None,
                   resource_group_name=None,
                   username=None,
                   password=None,
                   yes=False):
    _, resource_group_name = validate_managed_registry(
        cmd.cli_ctx, registry_name, resource_group_name, DELETE_NOT_SUPPORTED)

    login_server, username, password = get_access_credentials(
        cli_ctx=cmd.cli_ctx,
        registry_name=registry_name,
        resource_group_name=resource_group_name,
        username=username,
        password=password,
        repository=repository,
        permission='*')

    _INVALID = "Please specify either a tag name with --tag or a manifest digest with --manifest."

    # If manifest is not specified
    if manifest is None:
        if not tag:
            _user_confirmation("Are you sure you want to delete the repository '{}' "
                               "and all images under it?".format(repository), yes)
            path = '/v2/_acr/{}/repository'.format(repository)
        else:
            logger.warning(
                "This command is deprecated. The new command for this operation "
                "is 'az acr repository untag --name %s --image %s:%s'.",
                registry_name, repository, tag)
            _user_confirmation("Are you sure you want to delete the tag '{}:{}'?".format(repository, tag), yes)
            path = '/v2/_acr/{}/tags/{}'.format(repository, tag)
    # If --manifest is specified as a flag
    elif not manifest:
        # Raise if --tag is empty
        if not tag:
            raise CLIError(_INVALID)
        logger.warning(
            "This command is deprecated. The new command for this operation "
            "is 'az acr repository delete --name %s --image %s:%s'.",
            registry_name, repository, tag)
        manifest = _delete_manifest_confirmation(
            login_server=login_server,
            username=username,
            password=password,
            repository=repository,
            tag=tag,
            manifest=manifest,
            yes=yes)
        path = '/v2/{}/manifests/{}'.format(repository, manifest)
    # If --manifest is specified with a value
    else:
        # Raise if --tag is not empty
        if tag:
            raise CLIError(_INVALID)
        logger.warning(
            "This command is deprecated. The new command for this operation "
            "is 'az acr repository delete --name %s --image %s@%s'.",
            registry_name, repository, manifest)
        manifest = _delete_manifest_confirmation(
            login_server=login_server,
            username=username,
            password=password,
            repository=repository,
            tag=tag,
            manifest=manifest,
            yes=yes)
        path = '/v2/{}/manifests/{}'.format(repository, manifest)

    return _delete_data_from_registry(
        login_server=login_server,
        path=path,
        username=username,
        password=password)
コード例 #12
0
def acr_connected_registry_repo(cmd,
                                client,
                                connected_registry_name,
                                registry_name,
                                add_repos=None,
                                remove_repos=None,
                                resource_group_name=None):
    if not (add_repos or remove_repos):
        raise CLIError('No repository permissions to update.')
    _, resource_group_name = validate_managed_registry(cmd, registry_name,
                                                       resource_group_name)

    add_repos_set = set(add_repos) if add_repos is not None else set()
    remove_repos_set = set(remove_repos) if remove_repos is not None else set()
    duplicate_repos = set.intersection(add_repos_set, remove_repos_set)
    if duplicate_repos:
        errors = sorted(
            map(lambda action: action[action.rfind('/') + 1:],
                duplicate_repos))
        raise CLIError(
            'Update ambiguity. Duplicate repository names were provided with '
            + '--add and --remove arguments.\n{}'.format(errors))

    connected_registry_list = list(
        client.list(resource_group_name, registry_name))
    family_tree, target_connected_registry = _get_family_tree(
        connected_registry_list, connected_registry_name)
    if target_connected_registry is None:
        raise CLIError("Connected registry '{}' doesn't exist.".format(
            connected_registry_name))

    # remove repo permissions from connected registry descendants.
    remove_actions = REPO_SCOPES_BY_MODE[ConnectedRegistryModes.REGISTRY.value]
    if remove_repos is not None:
        remove_repos_txt = ", ".join(remove_repos)
        remove_repos_set = _get_scope_map_actions_set(remove_repos,
                                                      remove_actions)
        descendants = _get_descendants(family_tree,
                                       target_connected_registry.id)
        for connected_registry in descendants:
            msg = "Removing '{}' permissions from {}".format(
                remove_repos_txt, connected_registry.name)
            _update_repo_permissions(cmd,
                                     resource_group_name,
                                     registry_name,
                                     connected_registry,
                                     set(),
                                     remove_repos_set,
                                     msg=msg)
    else:
        remove_repos_set = set()

    # add repo permissions to ancestors.
    add_actions = REPO_SCOPES_BY_MODE[target_connected_registry.mode]
    if add_repos is not None:
        add_repos_txt = ", ".join(add_repos)
        add_repos_set = _get_scope_map_actions_set(add_repos, add_actions)
        parent_id = target_connected_registry.parent.id
        while parent_id and not parent_id.isspace():
            connected_registry = family_tree[parent_id]["connectedRegistry"]
            msg = "Adding '{}' permissions to {}".format(
                add_repos_txt, connected_registry.name)
            _update_repo_permissions(cmd,
                                     resource_group_name,
                                     registry_name,
                                     connected_registry,
                                     add_repos_set,
                                     set(),
                                     msg=msg)
            parent_id = connected_registry.parent.id
    else:
        add_repos_set = set()

    # update target connected registry repo permissions.
    if add_repos and remove_repos:
        msg = "Adding '{}' and removing '{}' permissions in {}".format(
            add_repos_txt, remove_repos_txt, target_connected_registry.name)
    elif add_repos:
        msg = "Adding '{}' permissions to {}".format(
            add_repos_txt, target_connected_registry.name)
    else:
        msg = "Removing '{}' permissions from {}".format(
            remove_repos_txt, target_connected_registry.name)
    _update_repo_permissions(cmd,
                             resource_group_name,
                             registry_name,
                             target_connected_registry,
                             add_repos_set,
                             remove_repos_set,
                             msg=msg)
コード例 #13
0
def acr_connected_registry_create(
        cmd,  # pylint: disable=too-many-locals, too-many-statements
        client,
        registry_name,
        connected_registry_name,
        repositories=None,
        sync_token_name=None,
        client_token_list=None,
        resource_group_name=None,
        mode=None,
        parent_name=None,
        sync_schedule=None,
        sync_message_ttl=None,
        sync_window=None,
        log_level=None,
        sync_audit_logs_enabled=False):

    if bool(sync_token_name) == bool(repositories):
        raise CLIError(
            "usage error: you need to provide either --sync-token-name or --repository, but not both."
        )
    registry, resource_group_name = get_registry_by_name(
        cmd.cli_ctx, registry_name, resource_group_name)
    subscription_id = get_subscription_id(cmd.cli_ctx)

    if not registry.data_endpoint_enabled:
        raise CLIError(
            "Can't create the connected registry '{}' ".format(
                connected_registry_name) +
            "because the cloud registry '{}' data endpoint is disabled. ".
            format(registry_name) +
            "Enabling the data endpoint might affect your firewall rules.\nTo enable data endpoint run:"
            + "\n\taz acr update -n {} --data-endpoint-enabled true".format(
                registry_name))

    ErrorResponseException = cmd.get_models('ErrorResponseException')
    parent = None
    mode = mode.capitalize()
    if parent_name:
        try:
            parent = acr_connected_registry_show(cmd, client, parent_name,
                                                 registry_name,
                                                 resource_group_name)
            connected_registry_list = list(
                client.list(resource_group_name, registry_name))
            family_tree, _ = _get_family_tree(connected_registry_list, None)
        except ErrorResponseException as ex:
            if ex.response.status_code == 404:
                raise CLIError(
                    "The parent connected registry '{}' could not be found.".
                    format(parent_name))
            raise CLIError(ex)
        if parent.mode != ConnectedRegistryModes.REGISTRY.value and parent.mode != mode:
            raise CLIError(
                "Can't create the registry '{}' with mode '{}' ".format(
                    connected_registry_name, mode) +
                "when the connected registry parent '{}' mode is '{}'. ".
                format(parent_name, parent.mode) +
                "For more information on connected registries " +
                "please visit https://aka.ms/acr/connected-registry.")
        _update_ancestor_permissions(cmd, family_tree, resource_group_name,
                                     registry_name, parent.id,
                                     connected_registry_name, repositories,
                                     mode, False)

    if sync_token_name:
        sync_token_id = build_token_id(subscription_id, resource_group_name,
                                       registry_name, sync_token_name)
    else:
        sync_token_id = _create_sync_token(cmd, resource_group_name,
                                           registry_name,
                                           connected_registry_name,
                                           repositories, mode)

    if client_token_list is not None:
        for i, client_token_name in enumerate(client_token_list):
            client_token_list[i] = build_token_id(subscription_id,
                                                  resource_group_name,
                                                  registry_name,
                                                  client_token_name)

    ConnectedRegistry, LoggingProperties, SyncProperties, ParentProperties = cmd.get_models(
        'ConnectedRegistry', 'LoggingProperties', 'SyncProperties',
        'ParentProperties')
    connected_registry_create_parameters = ConnectedRegistry(
        provisioning_state=None,
        mode=mode,
        parent=ParentProperties(id=parent.id if parent else None,
                                sync_properties=SyncProperties(
                                    token_id=sync_token_id,
                                    schedule=sync_schedule,
                                    message_ttl=sync_message_ttl,
                                    sync_window=sync_window)),
        client_token_ids=client_token_list,
        logging=LoggingProperties(log_level=log_level,
                                  audit_log_status='Enabled'
                                  if sync_audit_logs_enabled else 'Disabled'))

    try:
        return client.create(subscription_id=subscription_id,
                             resource_group_name=resource_group_name,
                             registry_name=registry_name,
                             connected_registry_name=connected_registry_name,
                             connected_registry_create_parameters=
                             connected_registry_create_parameters)
    except ValidationError as e:
        raise CLIError(e)
コード例 #14
0
def acr_connected_registry_update(
        cmd,  # pylint: disable=too-many-locals, too-many-statements
        client,
        registry_name,
        connected_registry_name,
        add_client_token_list=None,
        remove_client_token_list=None,
        resource_group_name=None,
        sync_schedule=None,
        sync_window=None,
        log_level=None,
        sync_message_ttl=None,
        sync_audit_logs_enabled=None):
    _, resource_group_name = validate_managed_registry(cmd, registry_name,
                                                       resource_group_name)
    subscription_id = get_subscription_id(cmd.cli_ctx)
    current_connected_registry = acr_connected_registry_show(
        cmd, client, connected_registry_name, registry_name,
        resource_group_name)

    # Add or remove from the current client token id list
    if add_client_token_list is not None:
        for i, client_token_name in enumerate(add_client_token_list):
            add_client_token_list[i] = build_token_id(subscription_id,
                                                      resource_group_name,
                                                      registry_name,
                                                      client_token_name)
        add_client_token_set = set(add_client_token_list)
    else:
        add_client_token_set = set()
    if remove_client_token_list is not None:
        for i, client_token_name in enumerate(remove_client_token_list):
            remove_client_token_list[i] = build_token_id(
                subscription_id, resource_group_name, registry_name,
                client_token_name)
        remove_client_token_set = set(remove_client_token_list)
    else:
        remove_client_token_set = set()

    duplicate_client_token = set.intersection(add_client_token_set,
                                              remove_client_token_set)
    if duplicate_client_token:
        errors = sorted(
            map(lambda action: action[action.rfind('/') + 1:],
                duplicate_client_token))
        raise CLIError(
            'Update ambiguity. Duplicate client token ids were provided with '
            + '--add-client-tokens and --remove-client-tokens arguments.\n{}'.
            format(errors))

    current_client_token_set = set(current_connected_registry.client_token_ids) \
        if current_connected_registry.client_token_ids else set()
    client_token_set = current_client_token_set.union(
        add_client_token_set).difference(remove_client_token_set)

    client_token_list = list(
        client_token_set
    ) if client_token_set != current_client_token_set else None

    ConnectedRegistryUpdateParameters, SyncUpdateProperties, LoggingProperties = cmd.get_models(
        'ConnectedRegistryUpdateParameters', 'SyncUpdateProperties',
        'LoggingProperties')
    connected_registry_update_parameters = ConnectedRegistryUpdateParameters(
        sync_properties=SyncUpdateProperties(
            token_id=current_connected_registry.parent.sync_properties.
            token_id,
            schedule=sync_schedule,
            message_ttl=sync_message_ttl,
            sync_window=sync_window),
        logging=LoggingProperties(log_level=log_level,
                                  audit_log_status=sync_audit_logs_enabled),
        client_token_ids=client_token_list)

    try:
        return client.update(resource_group_name=resource_group_name,
                             registry_name=registry_name,
                             connected_registry_name=connected_registry_name,
                             connected_registry_update_parameters=
                             connected_registry_update_parameters)
    except ValidationError as e:
        raise CLIError(e)
コード例 #15
0
def _get_aad_token_after_challenge(cli_ctx, token_params, login_server,
                                   only_refresh_token, repository,
                                   artifact_repository, permission,
                                   is_diagnostics_context):
    authurl = urlparse(token_params['realm'])
    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/exchange', '', '', ''))

    from azure.cli.core._profile import Profile
    profile = Profile(cli_ctx=cli_ctx)
    creds, _, tenant = profile.get_raw_token()

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    content = {
        'grant_type': 'access_token',
        'service': token_params['service'],
        'tenant': tenant,
        'access_token': creds[1]
    }

    response = requests.post(authhost,
                             urlencode(content),
                             headers=headers,
                             verify=(not should_disable_connection_verify()))

    if response.status_code not in [200]:
        from ._errors import CONNECTIVITY_REFRESH_TOKEN_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_REFRESH_TOKEN_ERROR.format_error_message(
                login_server, response.status_code)
        raise CLIError(
            CONNECTIVITY_REFRESH_TOKEN_ERROR.format_error_message(
                login_server, response.status_code).get_error_message())

    refresh_token = loads(response.content.decode("utf-8"))["refresh_token"]
    if only_refresh_token:
        return refresh_token

    authhost = urlunparse(
        (authurl[0], authurl[1], '/oauth2/token', '', '', ''))

    if repository:
        scope = 'repository:{}:{}'.format(repository, permission)
    elif artifact_repository:
        scope = 'artifact-repository:{}:{}'.format(artifact_repository,
                                                   permission)
    else:
        # catalog only has * as permission, even for a read operation
        scope = 'registry:catalog:*'

    content = {
        'grant_type': 'refresh_token',
        'service': login_server,
        'scope': scope,
        'refresh_token': refresh_token
    }
    response = requests.post(authhost,
                             urlencode(content),
                             headers=headers,
                             verify=(not should_disable_connection_verify()))

    if response.status_code not in [200]:
        from ._errors import CONNECTIVITY_ACCESS_TOKEN_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_ACCESS_TOKEN_ERROR.format_error_message(
                login_server, response.status_code)
        raise CLIError(
            CONNECTIVITY_ACCESS_TOKEN_ERROR.format_error_message(
                login_server, response.status_code).get_error_message())

    return loads(response.content.decode("utf-8"))["access_token"]
コード例 #16
0
def validate_worker_count(namespace):
    if namespace.worker_count:
        if namespace.worker_count < 3:
            raise CLIError(
                '--worker-count must be greater than or equal to 3.')
コード例 #17
0
def acr_import(cmd,
               client,
               registry_name,
               source_image,
               source_registry=None,
               source_registry_username=None,
               source_registry_password=None,
               target_tags=None,
               resource_group_name=None,
               repository=None,
               force=False):

    if source_registry_username and not source_registry_password:
        raise CLIError(CREDENTIALS_INVALID)

    _, resource_group_name = validate_managed_registry(cmd, registry_name,
                                                       resource_group_name,
                                                       IMPORT_NOT_SUPPORTED)

    ImportImageParameters, ImportSource, ImportMode = cmd.get_models(
        'ImportImageParameters', 'ImportSource', 'ImportMode')

    registry = None
    if source_registry:
        if is_valid_resource_id(source_registry):
            source = ImportSource(resource_id=source_registry,
                                  source_image=source_image)

        else:
            registry = get_registry_from_name_or_login_server(
                cmd.cli_ctx, source_registry, source_registry)
            if registry:
                # For Azure container registry
                source = ImportSource(resource_id=registry.id,
                                      source_image=source_image)
            else:
                # For non-Azure container registry
                raise CLIError(SOURCE_REGISTRY_NOT_FOUND)

    else:
        registry_uri, source_image = _split_registry_and_image(source_image)
        if source_registry_password:
            ImportSourceCredentials = cmd.get_models('ImportSourceCredentials')
            source = ImportSource(registry_uri=registry_uri,
                                  source_image=source_image,
                                  credentials=ImportSourceCredentials(
                                      password=source_registry_password,
                                      username=source_registry_username))
        else:
            registry = get_registry_from_name_or_login_server(
                cmd.cli_ctx, registry_uri)
            if registry:
                # For Azure container registry
                source = ImportSource(resource_id=registry.id,
                                      source_image=source_image)
            else:
                # For non-Azure container registry
                source = ImportSource(registry_uri=registry_uri,
                                      source_image=source_image)

    if not target_tags and not repository:
        index = source_image.find("@")
        if index > 0:
            target_tags = [source_image[:index]]
        else:
            target_tags = [source_image]

    import_parameters = ImportImageParameters(
        source=source,
        target_tags=target_tags,
        untagged_target_repositories=repository,
        mode=ImportMode.force.value if force else ImportMode.no_force.value)
    result_poller = client.import_image(
        resource_group_name=resource_group_name,
        registry_name=registry_name,
        parameters=import_parameters)

    return _handle_result(cmd, result_poller, source_registry, source_image,
                          registry)
コード例 #18
0
def validate_worker_vm_disk_size_gb(namespace):
    if namespace.worker_vm_disk_size_gb:
        if namespace.worker_vm_disk_size_gb < 128:
            raise CLIError(
                '--worker-vm-disk-size-gb must be greater than or equal to 128.')
コード例 #19
0
def validate_subscription_lock(namespace):
    if getattr(namespace, 'ids', None):
        for lock_id in getattr(namespace, 'ids'):
            if _parse_lock_id(lock_id).get('resource_group'):
                raise CLIError('{} is not a valid subscription-level lock id.'.format(lock_id))
コード例 #20
0
def validate_client_secret(namespace):
    if namespace.client_secret is not None:
        if namespace.client_id is None or not str(namespace.client_id):
            raise CLIError('Must specify --client-id with --client-secret.')
コード例 #21
0
def _validate_template_spec_out(namespace):
    _validate_template_spec(namespace)
    if namespace.output_folder and not os.path.isdir(namespace.output_folder):
        raise CLIError('Please enter a valid output folder')
コード例 #22
0
def parse_zone_file(text, zone_name, ignore_invalid=False):
    """
    Parse a zonefile into a dict
    """

    text = _remove_comments(text)
    text = _flatten(text)
    text = _add_record_names(text)

    zone_obj = OrderedDict()
    record_lines = text.split("\n")
    current_origin = zone_name.rstrip('.') + '.'
    current_ttl = 3600
    soa_processed = False

    for record_line in record_lines:
        parse_match = False
        record = None
        for record_type, regex in _COMPILED_REGEX.items():
            match = regex.match(record_line)
            if not match:
                continue

            parse_match = True
            record = match.groupdict()

        if not parse_match and not ignore_invalid:
            raise CLIError('Unable to parse: {}'.format(record_line))

        record_type = record['delim'].lower()
        if record_type == '$origin':
            origin_value = record['val']
            if not origin_value.endswith('.'):
                logger.warning(
                    "$ORIGIN '{}' should have terminating dot.".format(
                        origin_value))
            current_origin = origin_value.rstrip('.') + '.'
        elif record_type == '$ttl':
            current_ttl = _convert_to_seconds(record['val'])
        else:
            record_name = record['name']
            if '@' in record_name:
                record_name = record_name.replace('@', current_origin)
            elif not record_name.endswith('.'):
                record_name = '{}.{}'.format(record_name, current_origin)
            print(current_origin, record_name)

            # special record-specific fix-ups
            if record_type == 'ptr':
                record['fullname'] = record_name + '.' + current_origin
            elif record_type == 'soa':
                for key in ['refresh', 'retry', 'expire', 'minimum']:
                    record[key] = _convert_to_seconds(record[key])
                _expand_with_origin(record, 'email', current_origin)
            elif record_type == 'cname':
                _expand_with_origin(record, 'alias', current_origin)
            elif record_type == 'mx':
                _expand_with_origin(record, 'host', current_origin)
            elif record_type == 'ns':
                _expand_with_origin(record, 'host', current_origin)
            elif record_type == 'srv':
                _expand_with_origin(record, 'target', current_origin)
            elif record_type == 'spf':
                record_type = 'txt'
            record['ttl'] = _convert_to_seconds(record['ttl'] or current_ttl)

            # handle quotes for CAA and TXT
            if record_type == 'caa':
                _post_process_caa_record(record)
            elif record_type == 'txt':
                # handle TXT concatenation and splitting separately
                _post_process_txt_record(record)

            if record_name not in zone_obj:
                zone_obj[record_name] = OrderedDict()

            if record_type == 'soa':
                if soa_processed:
                    raise CLIError(
                        'Zone file can contain only one SOA record.')
                if record_name != current_origin:
                    raise CLIError("Zone SOA record must be at the apex '@'.")
                zone_obj[record_name][record_type] = record
                soa_processed = True
                continue

            if not soa_processed:
                raise CLIError('First record in zone file must be SOA.')

            if record_type == 'cname':
                if record_type in zone_obj[record_name]:
                    logger.warning(
                        "CNAME record already exists for '{}'. Ignoring '{}'.".
                        format(record_name, record['alias']))
                    continue
                zone_obj[record_name][record_type] = record
                continue

            # any other record can have multiple entries
            if record_type not in zone_obj[record_name]:
                zone_obj[record_name][record_type] = []
            zone_obj[record_name][record_type].append(record)

    _post_process_ttl(zone_obj)
    _post_check_names(zone_obj)
    return zone_obj
コード例 #23
0
def publish_app(cmd, client, resource_group_name, resource_name, code_dir=None, proj_name=None, version='v3'):
    """Publish local bot code to Azure.

    This method is directly called via "bot publish"

    :param cmd:
    :param client:
    :param resource_group_name:
    :param resource_name:
    :param code_dir:
    :param proj_name:
    :param version:
    :return:
    """
    if version == 'v3':
        return publish_appv3(cmd, client, resource_group_name, resource_name, code_dir)

    # Get the bot information and ensure it's not only a registration bot.
    bot = client.bots.get(
        resource_group_name=resource_group_name,
        resource_name=resource_name
    )
    if bot.kind == 'bot':
        raise CLIError('Bot kind is \'bot\', meaning it is a registration bot. '
                       'Source publish is not supported for registration only bots.')

    # If the user does not pass in a path to the local bot project, get the current working directory.
    if not code_dir:
        code_dir = os.getcwd()

        logger.info('Parameter --code-dir not provided, defaulting to current working directory, %s. '
                    'For more information, run \'az bot publish -h\'', code_dir)

    if not os.path.isdir(code_dir):
        raise CLIError('The path %s is not a valid directory. '
                       'Please supply a valid directory path containing your source code.' % code_dir)

    # Ensure that the directory contains appropriate post deploy scripts folder
    if 'PostDeployScripts' not in os.listdir(code_dir):
        BotPublishPrep.prepare_publish_v4(logger, code_dir, proj_name)

    logger.info('Creating upload zip file.')
    zip_filepath = BotPublishPrep.create_upload_zip(logger, code_dir, include_node_modules=False)
    logger.info('Zip file path created, at %s.', zip_filepath)

    kudu_client = KuduClient(cmd, resource_group_name, resource_name, bot)
    output = kudu_client.publish(zip_filepath)
    logger.info('Bot source published. Preparing bot application to run the new source.')
    os.remove('upload.zip')
    if os.path.exists(os.path.join('.', 'package.json')):
        logger.info('Detected language javascript. Installing node dependencies in remote bot.')
        __install_node_dependencies(kudu_client)

    if output.get('active'):
        logger.info('Deployment successful!')

    if not output.get('active'):
        scm_url = output.get('url')
        deployment_id = output.get('id')
        # Instead of replacing "latest", which would could be in the bot name, we replace "deployments/latest"
        deployment_url = scm_url.replace('deployments/latest', 'deployments/%s' % deployment_id)
        logger.error('Deployment failed. To find out more information about this deployment, please visit %s.'
                     % deployment_url)

    return output
コード例 #24
0
def _get_aad_token(cli_ctx,
                   login_server,
                   only_refresh_token,
                   repository=None,
                   artifact_repository=None,
                   permission=None,
                   is_diagnostics_context=False):
    """Obtains refresh and access tokens for an AAD-enabled registry.
    :param str login_server: The registry login server URL to log in to
    :param bool only_refresh_token: Whether to ask for only refresh token, or for both refresh and access tokens
    :param str repository: Repository for which the access token is requested
    :param str artifact_repository: Artifact repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    if repository and artifact_repository:
        raise ValueError(
            "Only one of repository and artifact_repository can be provided.")

    if (repository or
            artifact_repository) and permission not in ACCESS_TOKEN_PERMISSION:
        raise ValueError(
            "Permission is required for a repository or artifact_repository. Allowed access token permission: {}"
            .format(ACCESS_TOKEN_PERMISSION))

    login_server = login_server.rstrip('/')

    challenge = requests.get('https://' + login_server + '/v2/',
                             verify=(not should_disable_connection_verify()))
    if challenge.status_code not in [
            401
    ] or 'WWW-Authenticate' not in challenge.headers:
        from ._errors import CONNECTIVITY_CHALLENGE_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_CHALLENGE_ERROR.format_error_message(
                login_server)
        raise CLIError(
            CONNECTIVITY_CHALLENGE_ERROR.format_error_message(
                login_server).get_error_message())

    authenticate = challenge.headers['WWW-Authenticate']

    tokens = authenticate.split(' ', 2)
    if len(tokens) < 2 or tokens[0].lower() != 'bearer':
        from ._errors import CONNECTIVITY_AAD_LOGIN_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_AAD_LOGIN_ERROR.format_error_message(
                login_server)
        raise CLIError(
            CONNECTIVITY_AAD_LOGIN_ERROR.format_error_message(
                login_server).get_error_message())

    token_params = {
        y[0]: y[1].strip('"')
        for y in (x.strip().split('=', 2) for x in tokens[1].split(','))
    }
    if 'realm' not in token_params or 'service' not in token_params:
        from ._errors import CONNECTIVITY_AAD_LOGIN_ERROR
        if is_diagnostics_context:
            return CONNECTIVITY_AAD_LOGIN_ERROR.format_error_message(
                login_server)
        raise CLIError(
            CONNECTIVITY_AAD_LOGIN_ERROR.format_error_message(
                login_server).get_error_message())

    return _get_aad_token_after_challenge(cli_ctx, token_params, login_server,
                                          only_refresh_token, repository,
                                          artifact_repository, permission,
                                          is_diagnostics_context)
コード例 #25
0
ファイル: _utils.py プロジェクト: ymasaoka/azure-cli
def _invalid_sku_update(cmd):
    raise CLIError("Please specify SKU by '--sku SKU' or '--set sku.name=SKU'. Allowed SKUs: {0}".format(
        get_managed_sku(cmd)))
コード例 #26
0
def _get_credentials(
        cmd,  # pylint: disable=too-many-statements
        registry_name,
        tenant_suffix,
        username,
        password,
        only_refresh_token,
        repository=None,
        artifact_repository=None,
        permission=None):
    """Try to get AAD authorization tokens or admin user credentials.
    :param str registry_name: The name of container registry
    :param str tenant_suffix: The registry login server tenant suffix
    :param str username: The username used to log into the container registry
    :param str password: The password used to log into the container registry
    :param bool only_refresh_token: Whether to ask for only refresh token, or for both refresh and access tokens
    :param str repository: Repository for which the access token is requested
    :param str artifact_repository: Artifact repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    # Raise an error if password is specified but username isn't
    if not username and password:
        raise CLIError(
            'Please also specify username if password is specified.')

    cli_ctx = cmd.cli_ctx
    resource_not_found, registry = None, None
    try:
        registry, resource_group_name = get_registry_by_name(
            cli_ctx, registry_name)
        login_server = registry.login_server
        if tenant_suffix:
            logger.warning(
                "Obtained registry login server '%s' from service. The specified suffix '%s' is ignored.",
                login_server, tenant_suffix)
    except (ResourceNotFound, CLIError) as e:
        resource_not_found = str(e)
        logger.debug("Could not get registry from service. Exception: %s",
                     resource_not_found)
        if not isinstance(e, ResourceNotFound
                          ) and _AZ_LOGIN_MESSAGE not in resource_not_found:
            raise
        # Try to use the pre-defined login server suffix to construct login server from registry name.
        login_server_suffix = get_login_server_suffix(cli_ctx)
        if not login_server_suffix:
            raise
        login_server = '{}{}{}'.format(
            registry_name,
            '-{}'.format(tenant_suffix) if tenant_suffix else '',
            login_server_suffix).lower()

    # Validate the login server is reachable
    url = 'https://' + login_server + '/v2/'
    try:
        challenge = requests.get(
            url, verify=(not should_disable_connection_verify()))
        if challenge.status_code in [403]:
            raise CLIError(
                "Looks like you don't have access to registry '{}'. "
                "Are firewalls and virtual networks enabled?".format(
                    login_server))
    except RequestException as e:
        logger.debug(
            "Could not connect to registry login server. Exception: %s",
            str(e))
        if resource_not_found:
            logger.warning(
                "%s\nUsing '%s' as the default registry login server.",
                resource_not_found, login_server)
        raise CLIError(
            "Could not connect to the registry login server '{}'. ".format(
                login_server) + "Please verify that the registry exists and " +
            "the URL '{}' is reachable from your environment.".format(url))

    # 1. if username was specified, verify that password was also specified
    if username:
        if not password:
            try:
                password = prompt_pass(msg='Password: '******'Please specify both username and password in non-interactive mode.'
                )

        return login_server, username, password

    # 2. if we don't yet have credentials, attempt to get a refresh token
    if not registry or registry.sku.name in get_managed_sku(cmd):
        try:
            return login_server, EMPTY_GUID, _get_aad_token(
                cli_ctx, login_server, only_refresh_token, repository,
                artifact_repository, permission)
        except CLIError as e:
            logger.warning("%s: %s", AAD_TOKEN_BASE_ERROR_MESSAGE, str(e))

    # 3. if we still don't have credentials, attempt to get the admin credentials (if enabled)
    if registry:
        if registry.admin_user_enabled:
            try:
                cred = cf_acr_registries(cli_ctx).list_credentials(
                    resource_group_name, registry_name)
                return login_server, cred.username, cred.passwords[0].value
            except CLIError as e:
                logger.warning("%s: %s", ADMIN_USER_BASE_ERROR_MESSAGE, str(e))
        else:
            logger.warning("%s: %s", ADMIN_USER_BASE_ERROR_MESSAGE,
                           "Admin user is disabled.")
    else:
        logger.warning("%s: %s", ADMIN_USER_BASE_ERROR_MESSAGE,
                       resource_not_found)

    # 4. if we still don't have credentials, prompt the user
    try:
        username = prompt('Username: '******'Password: '******'Unable to authenticate using AAD or admin login credentials. ' +
            'Please specify both username and password in non-interactive mode.'
        )

    return login_server, None, None
コード例 #27
0
ファイル: validators.py プロジェクト: ranisha2/azure-cli-1
def validate_claim_vm(namespace):
    if namespace.name is None and namespace.lab_name is None or namespace.resource_group_name is None:
        raise CLIError(
            "usage error: --ids IDs | --lab-name LabName --resource-group ResourceGroup --name VMName"
            " | --lab-name LabName --resource-group ResourceGroup")
コード例 #28
0
def request_data_from_registry(http_method,
                               login_server,
                               path,
                               username,
                               password,
                               result_index=None,
                               json_payload=None,
                               file_payload=None,
                               params=None,
                               retry_times=3,
                               retry_interval=5):
    if http_method not in ALLOWED_HTTP_METHOD:
        raise ValueError("Allowed http method: {}".format(ALLOWED_HTTP_METHOD))

    if json_payload and file_payload:
        raise ValueError(
            "One of json_payload and file_payload can be specified.")

    if http_method in ['get', 'delete'] and (json_payload or file_payload):
        raise ValueError(
            "Empty payload is required for http method: {}".format(
                http_method))

    if http_method in ['patch', 'put'] and not (json_payload or file_payload):
        raise ValueError(
            "Non-empty payload is required for http method: {}".format(
                http_method))

    url = 'https://{}{}'.format(login_server, path)
    headers = get_authorization_header(username, password)

    for i in range(0, retry_times):
        errorMessage = None
        try:
            if file_payload:
                with open(file_payload, 'rb') as data_payload:
                    response = requests.request(
                        method=http_method,
                        url=url,
                        headers=headers,
                        params=params,
                        data=data_payload,
                        verify=(not should_disable_connection_verify()))
            else:
                response = requests.request(
                    method=http_method,
                    url=url,
                    headers=headers,
                    params=params,
                    json=json_payload,
                    verify=(not should_disable_connection_verify()))

            log_registry_response(response)

            if response.status_code == 200:
                result = response.json(
                )[result_index] if result_index else response.json()
                next_link = response.headers[
                    'link'] if 'link' in response.headers else None
                return result, next_link
            elif response.status_code == 201 or response.status_code == 202:
                result = None
                try:
                    result = response.json(
                    )[result_index] if result_index else response.json()
                except ValueError as e:
                    logger.debug(
                        'Response is empty or is not a valid json. Exception: %s',
                        str(e))
                return result, None
            elif response.status_code == 204:
                return None, None
            elif response.status_code == 401:
                raise RegistryException(
                    parse_error_message('Authentication required.', response),
                    response.status_code)
            elif response.status_code == 404:
                raise RegistryException(
                    parse_error_message('The requested data does not exist.',
                                        response), response.status_code)
            elif response.status_code == 405:
                raise RegistryException(
                    parse_error_message('This operation is not supported.',
                                        response), response.status_code)
            elif response.status_code == 409:
                raise RegistryException(
                    parse_error_message(
                        'Failed to request data due to a conflict.', response),
                    response.status_code)
            else:
                raise Exception(
                    parse_error_message(
                        'Could not {} the requested data.'.format(http_method),
                        response))
        except CLIError:
            raise
        except Exception as e:  # pylint: disable=broad-except
            errorMessage = str(e)
            logger.debug('Retrying %s with exception %s', i + 1, errorMessage)
            time.sleep(retry_interval)

    raise CLIError(errorMessage)
コード例 #29
0
def _create_package(prefix,
                    repo_path,
                    is_ext,
                    name='test',
                    display_name=None,
                    display_name_plural=None,
                    required_sdk=None,
                    client_name=None,
                    operation_name=None,
                    sdk_property=None,
                    not_preview=False,
                    local_sdk=None):
    from jinja2 import Environment, PackageLoader

    if local_sdk and required_sdk:
        raise CLIError(
            'usage error: --local-sdk PATH | --required-sdk NAME==VER')

    if name.startswith(prefix):
        name = name[len(prefix):]

    heading('Create CLI {}: {}{}'.format('Extension' if is_ext else 'Module',
                                         prefix, name))

    # package_name is how the item should show up in `pip list`
    package_name = '{}{}'.format(prefix, name.replace(
        '_', '-')) if not is_ext else name
    display_name = display_name or name.capitalize()

    kwargs = {
        'name':
        name,
        'mod_path':
        '{}{}'.format(prefix, name)
        if is_ext else 'azure.cli.command_modules.{}'.format(name),
        'display_name':
        display_name,
        'display_name_plural':
        display_name_plural or '{}s'.format(display_name),
        'loader_name':
        '{}CommandsLoader'.format(name.capitalize()),
        'pkg_name':
        package_name,
        'ext_long_name':
        '{}{}'.format(prefix, name) if is_ext else None,
        'is_ext':
        is_ext,
        'is_preview':
        not not_preview
    }

    new_package_path = os.path.join(repo_path, package_name)
    if os.path.isdir(new_package_path):
        if not prompt_y_n("{} '{}' already exists. Overwrite?".format(
                'Extension' if is_ext else 'Module', package_name),
                          default='n'):
            raise CLIError('aborted by user')

    ext_folder = '{}{}'.format(prefix, name) if is_ext else None

    # create folder tree
    if is_ext:
        _ensure_dir(
            os.path.join(new_package_path, ext_folder, 'tests', 'latest'))
        _ensure_dir(os.path.join(new_package_path, ext_folder,
                                 'vendored_sdks'))
    else:
        _ensure_dir(os.path.join(new_package_path, 'tests', 'latest'))
    env = Environment(loader=PackageLoader('azdev', 'mod_templates'))

    # determine dependencies
    dependencies = []
    if is_ext:
        dependencies.append("'azure-cli-core'")
        if required_sdk:
            _download_vendored_sdk(required_sdk,
                                   path=os.path.join(new_package_path,
                                                     ext_folder,
                                                     'vendored_sdks'))
        elif local_sdk:
            _copy_vendored_sdk(
                local_sdk,
                os.path.join(new_package_path, ext_folder, 'vendored_sdks'))
        sdk_path = None
        if any([local_sdk, required_sdk]):
            sdk_path = '{}{}.vendored_sdks'.format(prefix, package_name)
        kwargs.update({
            'sdk_path': sdk_path,
            'client_name': client_name,
            'operation_name': operation_name,
            'sdk_property': sdk_property or '{}_name'.format(name)
        })
    else:
        if required_sdk:
            version_regex = r'(?P<name>[a-zA-Z-]+)(?P<op>[~<>=]*)(?P<version>[\d.]*)'
            version_comps = re.compile(version_regex).match(required_sdk)
            sdk_kwargs = version_comps.groupdict()
            kwargs.update({
                'sdk_path': sdk_kwargs['name'].replace('-', '.'),
                'client_name': client_name,
                'operation_name': operation_name,
            })
            dependencies.append("'{}'".format(required_sdk))
        else:
            dependencies.append('# TODO: azure-mgmt-<NAME>==<VERSION>')
        kwargs.update({'sdk_property': sdk_property or '{}_name'.format(name)})

    kwargs['dependencies'] = dependencies

    # generate code for root level
    dest_path = new_package_path
    root_files = [
        'HISTORY.rst', 'MANIFEST.in', 'README.rst', 'setup.cfg', 'setup.py'
    ]
    if not is_ext:
        root_files.append('azure_bdist_wheel.py')
    _generate_files(env, kwargs, root_files, dest_path)

    dest_path = dest_path if not is_ext else os.path.join(
        dest_path, ext_folder)
    module_files = [{
        'name': '__init__.py',
        'template': 'module__init__.py'
    }, '_client_factory.py', '_help.py', '_params.py', '_validators.py',
                    'commands.py', 'custom.py']
    if is_ext:
        module_files.append('azext_metadata.json')
    _generate_files(env, kwargs, module_files, dest_path)

    dest_path = os.path.join(dest_path, 'tests')
    blank_init = {'name': '__init__.py', 'template': 'blank__init__.py'}
    _generate_files(env, kwargs, blank_init, dest_path)

    dest_path = os.path.join(dest_path, 'latest')
    test_files = [
        blank_init, {
            'name': 'test_{}_scenario.py'.format(name),
            'template': 'test_service_scenario.py'
        }
    ]
    _generate_files(env, kwargs, test_files, dest_path)

    if is_ext:
        result = pip_cmd('install -e {}'.format(new_package_path),
                         "Installing `{}{}`...".format(prefix, name))
        if result.error:
            raise result.error  # pylint: disable=raising-bad-type
コード例 #30
0
ファイル: _docker_utils.py プロジェクト: shurd/azure-cli
def _get_credentials(cli_ctx,
                     registry_name,
                     resource_group_name,
                     username,
                     password,
                     only_refresh_token,
                     repository=None,
                     artifact_repository=None,
                     permission=None):
    """Try to get AAD authorization tokens or admin user credentials.
    :param str registry_name: The name of container registry
    :param str resource_group_name: The name of resource group
    :param str username: The username used to log into the container registry
    :param str password: The password used to log into the container registry
    :param bool only_refresh_token: Whether to ask for only refresh token, or for both refresh and access tokens
    :param str repository: Repository for which the access token is requested
    :param str artifact_repository: Artifact repository for which the access token is requested
    :param str permission: The requested permission on the repository, '*' or 'pull'
    """
    # 1. if username was specified, verify that password was also specified
    if username:
        # Try to use the pre-defined login server suffix to construct login server from registry name.
        # This is to avoid a management server request if username/password are already provided.
        # In all other cases, including the suffix not defined, login server will be obtained from server.
        login_server_suffix = get_login_server_suffix(cli_ctx)
        if login_server_suffix:
            login_server = '{}{}'.format(registry_name, login_server_suffix)
        else:
            registry, _ = get_registry_by_name(cli_ctx, registry_name,
                                               resource_group_name)
            login_server = registry.login_server

        if not password:
            try:
                password = prompt_pass(msg='Password: '******'Please specify both username and password in non-interactive mode.'
                )

        return login_server, username, password

    registry, resource_group_name = get_registry_by_name(
        cli_ctx, registry_name, resource_group_name)
    login_server = registry.login_server

    # 2. if we don't yet have credentials, attempt to get a refresh token
    if not password and registry.sku.name in MANAGED_REGISTRY_SKU:
        try:
            password = _get_aad_token(cli_ctx, login_server,
                                      only_refresh_token, repository,
                                      artifact_repository, permission)
            return login_server, EMPTY_GUID, password
        except CLIError as e:
            logger.warning(
                "Unable to get AAD authorization tokens with message: %s",
                str(e))

    # 3. if we still don't have credentials, attempt to get the admin credentials (if enabled)
    if not password and registry.admin_user_enabled:
        try:
            cred = cf_acr_registries(cli_ctx).list_credentials(
                resource_group_name, registry_name)
            username = cred.username
            password = cred.passwords[0].value
            return login_server, username, password
        except CLIError as e:
            logger.warning(
                "Unable to get admin user credentials with message: %s",
                str(e))

    # 4. if we still don't have credentials, prompt the user
    if not password:
        try:
            username = prompt('Username: '******'Password: '******'Unable to authenticate using AAD or admin login credentials. '
                +
                'Please specify both username and password in non-interactive mode.'
            )

    return login_server, None, None