예제 #1
0
 def test_prompt_choice_list_question_no_help_string(self, _):
     a_list = ['red', 'blue', 'yellow', 'green']
     with mock.patch('logging.Logger.warning') as mock_log_warn:
         with self.assertRaises(StopIteration):
             with mock.patch('knack.prompting._input', side_effect=['?']):
                 prompt_choice_list('What is your favourite color?', a_list)
         mock_log_warn.assert_called_once_with('Valid values are %s',
                                               mock.ANY)
예제 #2
0
def init_environment(cmd,
                     prompt=True,
                     management_cluster_name=None,
                     resource_group_name=None,
                     location=None):
    check_prereqs(cmd, install=True)
    # Create a management cluster if needed
    use_new_cluster = False
    pre_prompt = None
    try:
        find_management_cluster_retry(cmd)
        cluster_name = find_cluster_in_current_context()
        if prompt and not prompt_y_n(
                f"Do you want to use {cluster_name} as the management cluster?"
        ):
            use_new_cluster = True
        else:
            return True
    except ResourceNotFoundError as err:
        error_msg = err.error_msg
        if management_cluster_components_missing_matching_expressions(
                error_msg):
            choices = [
                "Create a new management cluster",
                "Use default kuberenetes cluster found and install CAPI required components",
                "Exit"
            ]
            msg = "The default kubernetes cluster found is missing required components for a management cluster.\
                   \nDo you want to:"

            index_choice = 0
            if prompt:
                index_choice = prompt_choice_list(msg, choices)
            if index_choice == 0:
                use_new_cluster = True
            elif index_choice != 1:
                return False
        else:
            raise UnclassifiedUserFault(err) from err
    except subprocess.CalledProcessError:
        pre_prompt = """
No Kubernetes cluster was found using the default configuration.

Cluster API needs a "management cluster" to run its components.
Learn more from the Cluster API Book:
https://cluster-api.sigs.k8s.io/user/concepts.html
"""
        use_new_cluster = True
    if use_new_cluster and not create_new_management_cluster(
            cmd,
            management_cluster_name,
            resource_group_name,
            location,
            pre_prompt_text=pre_prompt,
            prompt=prompt):
        return False

    _create_azure_identity_secret(cmd)
    _install_capi_provider_components(cmd)
    return True
    def _create_organization(self):
        self.logger.info(
            "Starting process to create a new Azure DevOps organization")
        regions = self.adbp.list_regions()
        region_names = sorted(
            [region.display_name for region in regions.value])
        self.logger.info(
            "The region for an Azure DevOps organization is where the organization will be located. "
            "Try locate it near your other resources and your location")
        choice_index = prompt_choice_list(
            'Please select a region for the new organization: ', region_names)
        region = [
            region for region in regions.value
            if region.display_name == region_names[choice_index]
        ][0]

        while True:
            organization_name = prompt(
                "Please enter a name for your new organization: ")
            new_organization = self.adbp.create_organization(
                organization_name, region.name)
            if new_organization.valid is False:
                self.logger.warning(new_organization.message)
                self.logger.warning("Note: all names must be globally unique")
            else:
                break

        self.organization_name = new_organization.name
예제 #4
0
    def _create_organization(self):
        self.logger.info(
            "Starting process to create a new Azure DevOps organization")
        regions = self.adbp.list_regions()
        region_names = sorted(
            [region.display_name for region in regions.value])
        self.logger.info("The region for an Azure DevOps organization is where the organization will be located. Try locate it near your other resources and your location")  # pylint: disable=line-too-long
        choice_index = prompt_choice_list(
            'Please select a region for the new organization: ', region_names)
        region = [
            region for region in regions.value
            if region.display_name == region_names[choice_index]
        ][0]

        while True:
            organization_name = prompt(
                "Please enter the name of the new organization: ")
            new_organization = self.adbp.create_organization(
                organization_name, region.name)
            if new_organization.valid is False:
                self.logger.warning(new_organization.message)
                self.logger.warning("Note: any name must be globally unique")
            else:
                break
        url = "https://dev.azure.com/" + new_organization.name + "/"
        self.logger.info(
            "Finished creating the new organization. Click the link to see your new organization: %s",
            url)
        self.organization_name = new_organization.name
예제 #5
0
def resolve_port_or_expose_list(ports, name):
    if len(ports) > 1:
        message = f"You have more than one {name} mapping defined in your docker-compose file."
        message += " Which port would you like to use? "
        choice_index = prompt_choice_list(message, ports)

    return ports[choice_index]
예제 #6
0
def _handle_global_configuration(config):
    # print location of global configuration
    print(MSG_GLOBAL_SETTINGS_LOCATION.format(config.config_path))
    # set up the config parsers
    file_config = config.config_parser
    config_exists = file_config.read([config.config_path])
    should_modify_global_config = False
    if config_exists:
        # print current config and prompt to allow global config modification
        _print_cur_configuration(file_config)
        should_modify_global_config = prompt_y_n(MSG_PROMPT_MANAGE_GLOBAL, default='n')
        answers['modify_global_prompt'] = should_modify_global_config
    if not config_exists or should_modify_global_config:
        # no config exists yet so configure global config or user wants to modify global config
        output_index = prompt_choice_list(MSG_PROMPT_GLOBAL_OUTPUT, OUTPUT_LIST,
                                          default=get_default_from_config(config.config_parser,
                                                                          'core', 'output',
                                                                          OUTPUT_LIST))
        answers['output_type_prompt'] = output_index
        answers['output_type_options'] = str(OUTPUT_LIST)
        enable_file_logging = prompt_y_n(MSG_PROMPT_FILE_LOGGING, default='n')
        allow_telemetry = prompt_y_n(MSG_PROMPT_TELEMETRY, default='y')
        answers['telemetry_prompt'] = allow_telemetry
        # save the global config
        try:
            config.config_parser.add_section('core')
        except configparser.DuplicateSectionError:
            pass
        try:
            config.config_parser.add_section('logging')
        except configparser.DuplicateSectionError:
            pass
        config.set_value('core', 'output', OUTPUT_LIST[output_index]['name'])
        config.set_value('core', 'collect_telemetry', 'yes' if allow_telemetry else 'no')
        config.set_value('logging', 'enable_log_file', 'yes' if enable_file_logging else 'no')
예제 #7
0
def _handle_global_configuration():
    # print location of global configuration
    print(MSG_GLOBAL_SETTINGS_LOCATION.format(GLOBAL_CONFIG_PATH))
    # set up the config parsers
    file_config = get_config_parser()
    config_exists = file_config.read([GLOBAL_CONFIG_PATH])
    global_config = get_config_parser()
    global_config.read(GLOBAL_CONFIG_PATH)
    should_modify_global_config = False
    if config_exists:
        # print current config and prompt to allow global config modification
        print(MSG_HEADING_CURRENT_CONFIG_INFO)
        print_current_configuration(file_config)
        should_modify_global_config = prompt_y_n(MSG_PROMPT_MANAGE_GLOBAL,
                                                 default='n')
        answers['modify_global_prompt'] = should_modify_global_config
    if not config_exists or should_modify_global_config:
        # no config exists yet so configure global config or user wants to modify global config
        output_index = prompt_choice_list(MSG_PROMPT_GLOBAL_OUTPUT,
                                          OUTPUT_LIST,
                                          default=get_default_from_config(
                                              global_config, 'core', 'output',
                                              OUTPUT_LIST))
        answers['output_type_prompt'] = output_index
        answers['output_type_options'] = str(OUTPUT_LIST)
        try:
            from vsts.cli.code.common.git_alias import setup_git_aliases, are_git_aliases_setup
            if not are_git_aliases_setup():
                setup_aliases = prompt_y_n(MSG_PROMPT_GIT_ALIAS, default='y')
                if setup_aliases:
                    answers['git_aliases'] = True
                    setup_git_aliases()
                else:
                    answers['git_aliases'] = False
            else:
                answers['git_aliases'] = True
        except (ModuleNotFoundError, CLIError):
            logging.debug(
                'Skipping git alias configuration, because module was not found.'
            )
        enable_file_logging = prompt_y_n(MSG_PROMPT_FILE_LOGGING, default='n')
        allow_telemetry = prompt_y_n(MSG_PROMPT_TELEMETRY, default='y')
        answers['telemetry_prompt'] = allow_telemetry
        # save the global config
        try:
            global_config.add_section('core')
        except configparser.DuplicateSectionError:
            pass
        try:
            global_config.add_section('logging')
        except configparser.DuplicateSectionError:
            pass
        global_config.set('core', 'output', OUTPUT_LIST[output_index]['name'])
        global_config.set('core', 'collect_telemetry',
                          'yes' if allow_telemetry else 'no')
        global_config.set('logging', 'enable_log_file',
                          'yes' if enable_file_logging else 'no')
        set_global_config(global_config)
예제 #8
0
def init_environment(cmd, prompt=True):
    check_prereqs(cmd, install=True)
    # Create a management cluster if needed
    try:
        find_management_cluster_retry(cmd)
    except ResourceNotFoundError as err:
        if str(err) == "No Cluster API installation found":
            _install_capz_components(cmd)
    except subprocess.CalledProcessError:
        if prompt:
            choices = ["kind - a local Docker container-based cluster",
                       "AKS - a managed cluster in the Azure cloud",
                       "exit - don't create a management cluster"]
            prompt = """
No Kubernetes cluster was found using the default configuration.

Cluster API needs a "management cluster" to run its components.
Learn more from the Cluster API Book:
https://cluster-api.sigs.k8s.io/user/concepts.html

Where do you want to create a management cluster?
"""
            choice_index = prompt_choice_list(prompt, choices)
        else:
            choice_index = 0
        cluster_name = "capi-manager"
        if choice_index == 0:
            check_kind(cmd, install=not prompt)
            begin_msg = 'Creating local management cluster "{}" with kind'.format(cluster_name)
            end_msg = '✓ Created local management cluster "{}"'.format(cluster_name)
            with Spinner(cmd, begin_msg, end_msg):
                command = ["kind", "create", "cluster", "--name", cluster_name]
                try:
                    # if --verbose, don't capture stderr
                    stderr = None if is_verbose() else subprocess.STDOUT
                    output = subprocess.check_output(command, universal_newlines=True, stderr=stderr)
                    logger.info("%s returned:\n%s", " ".join(command), output)
                except subprocess.CalledProcessError as err:
                    raise UnclassifiedUserFault("Couldn't create kind management cluster") from err
        elif choice_index == 1:
            with Spinner(cmd, "Creating Azure resource group", "✓ Created Azure resource group"):
                command = ["az", "group", "create", "-l", "southcentralus", "--name", cluster_name]
                try:
                    output = subprocess.check_output(command, universal_newlines=True)
                    logger.info("%s returned:\n%s", " ".join(command), output)
                except subprocess.CalledProcessError as err:
                    raise UnclassifiedUserFault("Couldn't create Azure resource group") from err
            with Spinner(cmd, "Creating Azure management cluster with AKS", "✓ Created AKS management cluster"):
                command = ["az", "aks", "create", "-g", cluster_name, "--name", cluster_name]
                try:
                    output = subprocess.check_output(command, universal_newlines=True)
                    logger.info("%s returned:\n%s", " ".join(command), output)
                except subprocess.CalledProcessError as err:
                    raise UnclassifiedUserFault("Couldn't create AKS management cluster") from err
        else:
            return
        _install_capz_components(cmd)
 def check_scenario(self):
     if self.repository_name:
         self.scenario = 'AZURE_DEVOPS'
     elif self.github_pat or self.github_repository:
         self.scenario = 'GITHUB_INTEGRATION'
     else:
         choice_index = prompt_choice_list(
             'Please choose Azure function source code location: ',
             SUPPORTED_SOURCECODE_LOCATIONS)
         self.scenario = SUPPORTED_SCENARIOS[choice_index]
     return self.scenario
예제 #10
0
 def test_prompt_choice_list_question_with_help_string(self, _):
     a_list = ['red', 'blue', 'yellow', 'green']
     with mock.patch('knack.prompting._input', side_effect=['?', '1']):
         with mock.patch('sys.stdout',
                         new_callable=StringIO) as mock_stdout:
             actual_result = prompt_choice_list(
                 'What is your favourite color?',
                 a_list,
                 help_string='Your real favourite.')
             self.assertEqual(0, actual_result)
         self.assertIn('Your real favourite.', mock_stdout.getvalue())
예제 #11
0
 def _select_project(self):
     projects = self.adbp.list_projects(self.organization_name)
     if projects.count > 0:
         project_names = sorted([project.name for project in projects.value])
         choice_index = prompt_choice_list('Please select your project: ', project_names)
         project = [project for project in projects.value if project.name == project_names[choice_index]][0]
         self.project_name = project.name
     else:
         self.logger.warning("There are no existing projects in this organization. "
                             "You need to create a new project.")
         self._create_project()
예제 #12
0
 def _select_organization(self):
     organizations = self.adbp.list_organizations()
     organization_names = sorted([organization.accountName for organization in organizations.value])
     if not organization_names:
         self.logger.warning("There are no existing organizations, you need to create a new organization.")
         self._create_organization()
         self.created_organization = True
     else:
         choice_index = prompt_choice_list('Please choose the organization: ', organization_names)
         organization_match = [organization for organization in organizations.value
                               if organization.accountName == organization_names[choice_index]][0]
         self.organization_name = organization_match.accountName
예제 #13
0
def select_version():
    supported_versions = ['v1.0', 'beta']
    profile = read_profile()

    selected = prompt_choice_list('Select graph version', supported_versions)
    selected_version = supported_versions[selected]

    profile.update({'version': selected_version})
    write_profile(
        profile,
        error_msg='An error occured while setting the selected version')

    print(f'Version {selected_version} selected')
예제 #14
0
def _handle_global_configuration(config, cloud_forbid_telemetry):
    # print location of global configuration
    print(MSG_GLOBAL_SETTINGS_LOCATION.format(config.config_path))
    # set up the config parsers
    file_config = configparser.ConfigParser()
    config_exists = file_config.read([config.config_path])
    should_modify_global_config = False
    if config_exists:
        # print current config and prompt to allow global config modification
        _print_cur_configuration(file_config)
        should_modify_global_config = prompt_y_n(MSG_PROMPT_MANAGE_GLOBAL,
                                                 default='n')
        answers['modify_global_prompt'] = should_modify_global_config
    if not config_exists or should_modify_global_config:
        # no config exists yet so configure global config or user wants to modify global config
        with ConfiguredDefaultSetter(config, False):
            output_index = prompt_choice_list(MSG_PROMPT_GLOBAL_OUTPUT,
                                              OUTPUT_LIST,
                                              default=get_default_from_config(
                                                  config, 'core', 'output',
                                                  OUTPUT_LIST))
            answers['output_type_prompt'] = output_index
            answers['output_type_options'] = str(OUTPUT_LIST)
            enable_file_logging = prompt_y_n(MSG_PROMPT_FILE_LOGGING,
                                             default='n')
            if cloud_forbid_telemetry:
                allow_telemetry = False
            else:
                allow_telemetry = prompt_y_n(MSG_PROMPT_TELEMETRY, default='y')
            answers['telemetry_prompt'] = allow_telemetry
            cache_ttl = None
            while not cache_ttl:
                try:
                    cache_ttl = prompt(
                        MSG_PROMPT_CACHE_TTL) or DEFAULT_CACHE_TTL
                    # ensure valid int by casting
                    cache_value = int(cache_ttl)
                    if cache_value < 1:
                        raise ValueError
                except ValueError:
                    logger.error('TTL must be a positive integer')
                    cache_ttl = None
            # save the global config
            config.set_value('core', 'output',
                             OUTPUT_LIST[output_index]['name'])
            config.set_value('core', 'collect_telemetry',
                             'yes' if allow_telemetry else 'no')
            config.set_value('core', 'cache_ttl', cache_ttl)
            config.set_value('logging', 'enable_log_file',
                             'yes' if enable_file_logging else 'no')
예제 #15
0
    def process_git_exists(self):
        self.logger.warning("There is a local git file.")

        if self.local_git is None:
            self.logger.warning("1. Chosing the add remote will create a new remote to the build repository but otherwise preserve your local git")  # pylint: disable=line-too-long
            self.logger.warning("2. Chosing the add new repository will delete your local git file and create a new one with a reference to the build repository.")  # pylint: disable=line-too-long
            self.logger.warning("3. Choosing the use existing will use the repository you are referencing to do the build. Only choose use existing if your local git file is referencing an azure repository that you can create a build with.")  # pylint: disable=line-too-long
            command_options = ['AddRemote', 'AddNewRepository', 'UseExisting']
            choice_index = prompt_choice_list(
                'Please choose the action you would like to take: ',
                command_options)
            command = command_options[choice_index]
        else:
            command = self.local_git

        if command == 'AddNewRepository':
            self.logger.info("Removing your old, adding a new repository.")
            # https://docs.python.org/3/library/os.html#os.name (if os.name is nt it is windows)
            if os.name == 'nt':
                os.system("rmdir /s /q .git")
            else:
                os.system("rm -rf .git")
            self.process_git_doesnt_exist()
        elif command == 'AddRemote':
            self.process_remote()
        else:
            # default is to try and use the existing azure repo
            repository_type = self.find_type_repository()
            self.logger.info(
                "We have detected that you have a %s type of repository",
                repository_type)
            if repository_type == 'azure repos':
                # Figure out what the repository information is for their current azure repos account
                lines = (check_output('git remote show origin'.split())
                         ).decode('utf-8').split('\n')
                for line in lines:
                    if re.search('Push', line):
                        m = re.search('http.*', line)
                        url = m.group(0)
                        segs = url.split('/')
                        organization_name = segs[2].split('.')[0]
                        project_name = segs[3]
                        repository_name = segs[5]
                # We don't need to push to it as it is all currently there
                self.organization_name = organization_name
                self.project_name = project_name
                self.repository_name = repository_name
            else:
                self.logger.critical("We don't support any other repositories except for azure repos. We cannot setup a build with these repositories.")  # pylint: disable=line-too-long
                exit(1)
예제 #16
0
def _config_env_public_azure(cli_ctx, _):
    from adal.adal_error import AdalError
    from azure.cli.core.commands.client_factory import get_mgmt_service_client
    from azure.cli.core._profile import Profile
    from azure.cli.core.profiles import ResourceType
    # Determine if user logged in

    try:
        list(
            get_mgmt_service_client(
                cli_ctx,
                ResourceType.MGMT_RESOURCE_RESOURCES).resources.list())
    except CLIError:
        # Not logged in
        login_successful = False
        while not login_successful:
            method_index = prompt_choice_list(MSG_PROMPT_LOGIN,
                                              LOGIN_METHOD_LIST)
            answers['login_index'] = method_index
            answers['login_options'] = str(LOGIN_METHOD_LIST)
            profile = Profile(cli_ctx=cli_ctx)
            interactive = False
            username = None
            password = None
            service_principal = None
            tenant = None
            if method_index == 0:  # device auth
                interactive = True
            elif method_index == 1:  # username and password
                username = prompt('Username: '******'Password: '******'Service principal: ')
                tenant = prompt('Tenant: ')
                password = prompt_pass(msg='Client secret: ')
            elif method_index == 3:  # skip
                return
            try:
                profile.find_subscriptions_on_login(interactive, username,
                                                    password,
                                                    service_principal, tenant)
                login_successful = True
                logger.warning('Login successful!')
            except AdalError as err:
                logger.error('Login error!')
                logger.error(err)
예제 #17
0
def _config_env_public_azure(cli_ctx, _):
    from adal.adal_error import AdalError
    from azure.cli.core.commands.client_factory import get_mgmt_service_client
    from azure.mgmt.resource import ResourceManagementClient
    from azure.cli.core._profile import Profile
    # Determine if user logged in
    try:
        list(get_mgmt_service_client(cli_ctx, ResourceManagementClient).resources.list())
    except CLIError:
        # Not logged in
        login_successful = False
        while not login_successful:
            method_index = prompt_choice_list(MSG_PROMPT_LOGIN, LOGIN_METHOD_LIST)
            answers['login_index'] = method_index
            answers['login_options'] = str(LOGIN_METHOD_LIST)
            profile = Profile(cli_ctx=cli_ctx)
            interactive = False
            username = None
            password = None
            service_principal = None
            tenant = None
            if method_index == 0:  # device auth
                interactive = True
            elif method_index == 1:  # username and password
                username = prompt('Username: '******'Password: '******'Service principal: ')
                tenant = prompt('Tenant: ')
                password = prompt_pass(msg='Client secret: ')
            elif method_index == 3:  # skip
                return
            try:
                profile.find_subscriptions_on_login(
                    interactive,
                    username,
                    password,
                    service_principal,
                    tenant)
                login_successful = True
                logger.warning('Login successful!')
            except AdalError as err:
                logger.error('Login error!')
                logger.error(err)
예제 #18
0
 def test_prompt_choice_list_with_name_desc(self, _):
     a_list = [{
         'name': 'red',
         'desc': ' A desc.'
     }, {
         'name': 'blue',
         'desc': ' A desc.'
     }, {
         'name': 'yellow',
         'desc': ' A desc.'
     }, {
         'name': 'green',
         'desc': ' A desc.'
     }]
     with mock.patch('knack.prompting._input', return_value='2'):
         actual_result = prompt_choice_list('What is your favourite color?',
                                            a_list)
         self.assertEqual(1, actual_result)
예제 #19
0
 def _select_functionapp(self):
     self.logger.info("Retrieving functionapp names.")
     functionapps = list_function_app(self.cmd)
     functionapp_names = sorted([functionapp.name for functionapp in functionapps])
     if not functionapp_names:
         raise CLIError("You do not have any existing function apps associated with this account subscription.{ls}"
                        "1. Please make sure you are logged into the right azure account by "
                        "running 'az account show' and checking the user.{ls}"
                        "2. If you are logged in as the right account please check the subscription you are using. "
                        "Run 'az account show' and view the name.{ls}"
                        "   If you need to set the subscription run "
                        "'az account set --subscription <subscription name or id>'{ls}"
                        "3. If you do not have a function app please create one".format(ls=os.linesep))
     choice_index = prompt_choice_list('Please select the target function app: ', functionapp_names)
     functionapp = [functionapp for functionapp in functionapps
                    if functionapp.name == functionapp_names[choice_index]][0]
     self.logger.info("Selected functionapp %s", functionapp.name)
     return functionapp
예제 #20
0
def select_cloud():
    supported_clouds = cloud_manager.get_clouds()
    formatted = []

    for cloud_name in supported_clouds:
        cloud = supported_clouds[cloud_name]
        formatted.append({
            'name':
            cloud.get('name'),
            'desc':
            f"""Graph Endpoint: {cloud.get('graph_endpoint')} - Azure AD Endpoint: {cloud.get('azure_ad_endpoint')}
            """
        })

    selected = prompt_choice_list('Select a cloud \n', formatted)
    name = formatted[selected].get('name')

    cloud_manager.set_current_cloud(name)
    print(f'{name} cloud selected')
예제 #21
0
def get_environment(flow_rp):
    """
    Prompt for environment if not provided.
    """
    environments_val = flow_rp.get_environments()
    environments_list = environments_val[_VALUE]
    environments = {
        env[_PROPERTIES][_DISPLAY_NAME]: env[_NAME]
        for env in environments_list
    }

    environment_keys = list(environments.keys())

    sid = prompt_choice_list('Please select an environment:', environment_keys)
    environment = environments[environment_keys[sid]]

    print('Environment selected: {}'.format(environment_keys[sid]))

    return environment
예제 #22
0
def get_connector_id(powerapps_rp, environment):
    """
    Select connector id if not provided.
    """
    connectors_val = powerapps_rp.get_all_connectors(environment)
    connectors_list = connectors_val[_VALUE]
    custom_connectors = filter(lambda conn: conn[_PROPERTIES][_IS_CUSTOM_API], connectors_list)
    connectors = {
        conn[_PROPERTIES][_DISPLAY_NAME] + ' - ' + conn[_PROPERTIES][_CREATED_BY][_DISPLAY_NAME]: conn[_NAME]
        for conn in custom_connectors
    }

    connectors_keys = list(connectors.keys())

    sid = prompt_choice_list('Please select a connector:', connectors_keys)
    connector_id = connectors[connectors_keys[sid]]

    print('Connector selected: {}'.format(connectors_keys[sid]))

    return connector_id
예제 #23
0
def create_new_management_cluster(cmd,
                                  cluster_name=None,
                                  resource_group_name=None,
                                  location=None,
                                  pre_prompt_text=None,
                                  prompt=True):
    choices = [
        "azure - a management cluster in the Azure cloud",
        "local - a local Docker container-based management cluster",
        "exit - don't create a management cluster"
    ]
    default_cluster_name = "capi-manager"
    if prompt:
        prompt_text = pre_prompt_text if pre_prompt_text else ""
        prompt_text += """
Where do you want to create a management cluster?
"""
        choice_index = prompt_choice_list(prompt_text, choices)
        if choice_index != 2 and not cluster_name:
            cluster_name = get_cluster_name_by_user_prompt(
                default_cluster_name)
    else:
        if not cluster_name:
            cluster_name = default_cluster_name
        choice_index = 0
    if choice_index == 0:
        if not create_aks_management_cluster(
                cmd, cluster_name, resource_group_name, location,
                yes=not prompt):
            return False
    elif choice_index == 1:
        check_kind(cmd, install=not prompt)
        begin_msg = f'Creating local management cluster "{cluster_name}" with kind'
        end_msg = f'✓ Created local management cluster "{cluster_name}"'
        command = ["kind", "create", "cluster", "--name", cluster_name]
        try_command_with_spinner(cmd, command, begin_msg, end_msg,
                                 "Couldn't create kind management cluster")
    else:
        return False
    return True
예제 #24
0
 def _select_functionapp(self):
     self.logger.info("Retrieving functionapp names.")
     functionapps = list_function_app(self.cmd)
     functionapp_names = sorted(
         [functionapp.name for functionapp in functionapps])
     if len(functionapp_names) < 1:
         self.logger.critical(
             "You do not have any existing functionapps associated with this account subscription."
         )
         self.logger.critical("1. Please make sure you are logged into the right azure account by running `az account show` and checking the user.")  # pylint: disable=line-too-long
         self.logger.critical("2. If you are logged in as the right account please check the subscription you are using. Run `az account show` and view the name.")  # pylint: disable=line-too-long
         self.logger.critical("   If you need to set the subscription run `az account set --subscription \"{SUBSCRIPTION_NAME}\"`")  # pylint: disable=line-too-long
         self.logger.critical(
             "3. If you do not have a functionapp please create one in the portal."
         )
         exit(1)
     choice_index = prompt_choice_list('Please choose the functionapp: ',
                                       functionapp_names)
     functionapp = [
         functionapp for functionapp in functionapps
         if functionapp.name == functionapp_names[choice_index]
     ][0]
     self.logger.info("Selected functionapp %s", functionapp.name)
     return functionapp
예제 #25
0
def init_environment(cmd):
    check_preqreqs(cmd, install=True)
    # Create a management cluster if needed
    try:
        find_management_cluster_retry(cmd.cli_ctx)
    except ResourceNotFoundError as err:
        if str(err) == "No CAPZ installation found":
            _install_capz_components()
    except subprocess.CalledProcessError:
        providers = [
            'AKS - a managed cluster in Azure',
            'kind - a local docker-based cluster',
            "exit - don't create a management cluster"
        ]
        prompt = """\
No Kubernetes cluster was found using the default configuration.

Cluster API needs a "management cluster" to run its components.
Learn more from the Cluster API Book:
  https://cluster-api.sigs.k8s.io/user/concepts.html

Where should we create a management cluster?
"""
        choice_index = prompt_choice_list(prompt, providers)
        random_id = ''.join(
            random.choices(string.ascii_lowercase + string.digits, k=6))
        cluster_name = "capi-manager-" + random_id
        if choice_index == 0:
            logger.info("AKS management cluster")
            cmd = [
                "az", "group", "create", "-l", "southcentralus", "--name",
                cluster_name
            ]
            try:
                output = subprocess.check_output(cmd, universal_newlines=True)
                logger.info("%s returned:\n%s", " ".join(cmd), output)
            except subprocess.CalledProcessError as err:
                raise UnclassifiedUserFault(err)
            cmd = [
                "az", "aks", "create", "-g", cluster_name, "--name",
                cluster_name
            ]
            try:
                output = subprocess.check_output(cmd, universal_newlines=True)
                logger.info("%s returned:\n%s", " ".join(cmd), output)
            except subprocess.CalledProcessError as err:
                raise UnclassifiedUserFault(err)
        elif choice_index == 1:
            logger.info("kind management cluster")
            # Install kind
            kind_path = "kind"
            if not which("kind"):
                kind_path = install_kind(cmd)
            cmd = [kind_path, "create", "cluster", "--name", cluster_name]
            try:
                output = subprocess.check_output(cmd, universal_newlines=True)
                logger.info("%s returned:\n%s", " ".join(cmd), output)
            except subprocess.CalledProcessError as err:
                raise UnclassifiedUserFault(err)
        else:
            return
        _install_capz_components()
예제 #26
0
파일: parser.py 프로젝트: gossion/azure-cli
    def _check_value(self, action, value):  # pylint: disable=too-many-statements, too-many-locals, too-many-branches
        # Override to customize the error message when a argument is not among the available choices
        # converted value must be one of the choices (if specified)
        if action.choices is not None and value not in action.choices:  # pylint: disable=too-many-nested-blocks
            # self.cli_ctx is None when self.prog is beyond 'az', such as 'az iot'.
            # use cli_ctx from cli_help which is not lost.
            cli_ctx = self.cli_ctx or (self.cli_help.cli_ctx
                                       if self.cli_help else None)

            caused_by_extension_not_installed = False
            command_name_inferred = self.prog
            error_msg = None
            if not self.command_source:
                candidates = []
                args = self.prog.split() + self._raw_arguments
                use_dynamic_install = self._get_extension_use_dynamic_install_config(
                )
                if use_dynamic_install != 'no':
                    # Check if the command is from an extension
                    from azure.cli.core.util import roughly_parse_command
                    command_str = roughly_parse_command(args[1:])
                    ext_name = self._search_in_extension_commands(command_str)
                    # The input command matches the prefix of one or more extension commands
                    if isinstance(ext_name, list):
                        if len(ext_name) > 1:
                            from knack.prompting import prompt_choice_list, NoTTYException
                            try:
                                prompt_msg = "The command requires the latest version of one of the following " \
                                    "extensions. You need to pick one to install:"
                                choice_idx = prompt_choice_list(
                                    prompt_msg, ext_name)
                                ext_name = ext_name[choice_idx]
                                use_dynamic_install = 'yes_without_prompt'
                            except NoTTYException:
                                error_msg = "{}{}\nUnable to prompt for selection as no tty available. Please " \
                                    "update or install the extension with 'az extension add --upgrade -n " \
                                    "<extension-name>'.".format(prompt_msg, ext_name)
                                logger.error(error_msg)
                                telemetry.set_user_fault(error_msg)
                                self.exit(2)
                        else:
                            ext_name = ext_name[0]

                    if ext_name:
                        caused_by_extension_not_installed = True
                        telemetry.set_command_details(
                            command_str,
                            parameters=AzCliCommandInvoker.
                            _extract_parameter_names(args),  # pylint: disable=protected-access
                            extension_name=ext_name)
                        run_after_extension_installed = self._get_extension_run_after_dynamic_install_config(
                        )
                        prompt_info = ""
                        if use_dynamic_install == 'yes_without_prompt':
                            logger.warning(
                                'The command requires the extension %s. '
                                'It will be installed first.', ext_name)
                            go_on = True
                        else:
                            from knack.prompting import prompt_y_n, NoTTYException
                            prompt_msg = 'The command requires the extension {}. ' \
                                'Do you want to install it now?'.format(ext_name)
                            if run_after_extension_installed:
                                prompt_msg = '{} The command will continue to run after the extension is installed.' \
                                    .format(prompt_msg)
                            NO_PROMPT_CONFIG_MSG = "Run 'az config set extension.use_dynamic_install=" \
                                "yes_without_prompt' to allow installing extensions without prompt."
                            try:
                                go_on = prompt_y_n(prompt_msg, default='y')
                                if go_on:
                                    prompt_info = " with prompt"
                                    logger.warning(NO_PROMPT_CONFIG_MSG)
                            except NoTTYException:
                                error_msg = "The command requires the extension {}. " \
                                            "Unable to prompt for extension install confirmation as no tty " \
                                            "available. {}".format(ext_name, NO_PROMPT_CONFIG_MSG)
                                go_on = False
                        if go_on:
                            from azure.cli.core.extension.operations import add_extension
                            add_extension(cli_ctx=cli_ctx,
                                          extension_name=ext_name,
                                          upgrade=True)
                            if run_after_extension_installed:
                                import subprocess
                                import platform
                                exit_code = subprocess.call(
                                    args, shell=platform.system() == 'Windows')
                                error_msg = (
                                    "Extension {} dynamically installed{} and commands will be "
                                    "rerun automatically.").format(
                                        ext_name, prompt_info)
                                telemetry.set_user_fault(error_msg)
                                self.exit(exit_code)
                            else:
                                with CommandLoggerContext(logger):
                                    error_msg = 'Extension {} installed{}. Please rerun your command.' \
                                        .format(ext_name, prompt_info)
                                    logger.error(error_msg)
                                    telemetry.set_user_fault(error_msg)
                                self.exit(2)
                        else:
                            error_msg = "The command requires the latest version of extension {ext_name}. " \
                                "To install, run 'az extension add --upgrade -n {ext_name}'.".format(
                                    ext_name=ext_name) if not error_msg else error_msg
                if not error_msg:
                    # parser has no `command_source`, value is part of command itself
                    error_msg = "'{value}' is misspelled or not recognized by the system.".format(
                        value=value)
                az_error = CommandNotFoundError(error_msg)
                if not caused_by_extension_not_installed:
                    candidates = difflib.get_close_matches(value,
                                                           action.choices,
                                                           cutoff=0.7)
                    if candidates:
                        # use the most likely candidate to replace the misspelled command
                        args_inferred = [
                            item if item != value else candidates[0]
                            for item in args
                        ]
                        command_name_inferred = ' '.join(args_inferred).split(
                            '-')[0]

            else:
                # `command_source` indicates command values have been parsed, value is an argument
                parameter = action.option_strings[
                    0] if action.option_strings else action.dest
                error_msg = "{prog}: '{value}' is not a valid value for '{param}'.".format(
                    prog=self.prog, value=value, param=parameter)
                candidates = difflib.get_close_matches(value,
                                                       action.choices,
                                                       cutoff=0.7)
                az_error = InvalidArgumentValueError(error_msg)

            command_arguments = self._get_failure_recovery_arguments(action)
            if candidates:
                az_error.set_recommendation("Did you mean '{}' ?".format(
                    candidates[0]))

            # recommend a command for user
            if not caused_by_extension_not_installed:
                recommender = CommandRecommender(*command_arguments, error_msg,
                                                 cli_ctx)
                recommender.set_help_examples(
                    self.get_examples(command_name_inferred))
                recommended_command = recommender.recommend_a_command()
                if recommended_command:
                    az_error.set_recommendation(
                        "Try this: '{}'".format(recommended_command))

                # remind user to check extensions if we can not find a command to recommend
                if isinstance(az_error, CommandNotFoundError) \
                        and not az_error.recommendations and self.prog == 'az' \
                        and use_dynamic_install == 'no':
                    az_error.set_recommendation(EXTENSION_REFERENCE)

                az_error.set_recommendation(
                    OVERVIEW_REFERENCE.format(command=self.prog))

            az_error.print_error()
            az_error.send_telemetry()

            self.exit(2)
예제 #27
0
def bind_webapp_postgres(cmd,
                         resource_group,
                         appname,
                         server,
                         database,
                         name=None,
                         client_id=None,
                         client_secret=None,
                         username=None,
                         password=None,
                         authtype='Secret',
                         permission=None):
    try:
        if authtype == 'Secret':
            if not username:
                username = prompt('Username: '******'Password: '******'{0}_{1}_{2}_{3}_{4}'.format(appname, server, database,
                                                int(time.time()),
                                                random.randint(10000, 99999))
        subscription = get_subscription_id(cmd.cli_ctx)
        scope = '/subscriptions/{0}/resourceGroups/{1}'.format(
            subscription, resource_group)
        source = '{0}/providers/Microsoft.Web/sites/{1}'.format(scope, appname)
        target = _get_target_id(scope, postgres=server, database=database)
        succeeded = False
        for i in range(3):
            try:
                result = _bind(cmd, subscription, resource_group, name, source,
                               target, authtype, permission, client_id,
                               client_secret, username, password)
            except Exception as e:
                s = str(e)
                if s.find('\"UnauthorizedResourceAccess\"'
                          ) and authtype == 'Secret':
                    print('Admin username or password error, retry left: {0}'.
                          format(3 - i))
                    choice_list = [
                        're-input the password for the admin user \"{0}\"'.
                        format(username),
                        'Change the password for the admin user \"{0}\"'.
                        format(username)
                    ]
                    choice = prompt_choice_list(
                        'Select re-input the admin password or change the admin password',
                        choice_list)
                    if choice == 0:
                        password = prompt_pass(msg='Password: '******'New password: ')
                        _update_postgres_server(target, password)
                    continue
            else:
                succeeded = True
                print(json.dumps(result, indent=2))
                break
        if not succeeded:
            result = _bind(cmd, subscription, resource_group, name, source,
                           target, authtype, permission, client_id,
                           client_secret, username, password)
            print(json.dumps(result, indent=2))
    except Exception as e:
        print(e)
        logger.error(e)
        sys.exit(1)
예제 #28
0
def _check_value_in_extensions(cli_ctx, parser, args, no_prompt):  # pylint: disable=too-many-statements, too-many-locals
    """Check if the command args can be found in extension commands.
       Exit command if the error is caused by an extension not installed.
       Otherwise return.
    """
    # Check if the command is from an extension
    from azure.cli.core.util import roughly_parse_command
    from azure.cli.core.azclierror import NoTTYError
    exit_code = 2
    command_str = roughly_parse_command(args[1:])
    allow_prefix_match = args[-1] == '-h' or args[-1] == '--help'
    ext_name = _search_in_extension_commands(cli_ctx, command_str, allow_prefix_match=allow_prefix_match)
    # ext_name is a list if the input command matches the prefix of one or more extension commands,
    # for instance: `az blueprint` when running `az blueprint -h`
    # ext_name is a str if the input command matches a complete command of an extension,
    # for instance: `az blueprint create`
    if isinstance(ext_name, list):
        if len(ext_name) > 1:
            from knack.prompting import prompt_choice_list, NoTTYException
            prompt_msg = "The command requires the latest version of one of the following " \
                "extensions. You need to pick one to install:"
            try:
                choice_idx = prompt_choice_list(prompt_msg, ext_name)
                ext_name = ext_name[choice_idx]
                no_prompt = True
            except NoTTYException:
                tty_err_msg = "{}{}\nUnable to prompt for selection as no tty available. Please update or " \
                    "install the extension with 'az extension add --upgrade -n <extension-name>'." \
                    .format(prompt_msg, ext_name)
                az_error = NoTTYError(tty_err_msg)
                az_error.print_error()
                az_error.send_telemetry()
                parser.exit(exit_code)
        else:
            ext_name = ext_name[0]
    if not ext_name:
        return

    # If a valid command has parser error, it may be caused by CLI running on a profile that is
    # not 'latest' and the command is not supported in that profile. If this command exists in an extension,
    # CLI will try to download the extension and rerun the command. But the parser will fail again and try to
    # install the extension and rerun the command infinitely. So we need to check if the latest version of the
    # extension is already installed and return if yes as the error is not caused by extension not installed.
    from azure.cli.core.extension import get_extension, ExtensionNotInstalledException
    from azure.cli.core.extension._resolve import resolve_from_index, NoExtensionCandidatesError
    try:
        ext = get_extension(ext_name)
    except ExtensionNotInstalledException:
        pass
    else:
        try:
            resolve_from_index(ext_name, cur_version=ext.version, cli_ctx=cli_ctx)
        except NoExtensionCandidatesError:
            return

    telemetry.set_command_details(command_str,
                                  parameters=AzCliCommandInvoker._extract_parameter_names(args),  # pylint: disable=protected-access
                                  extension_name=ext_name)
    run_after_extension_installed = _get_extension_run_after_dynamic_install_config(cli_ctx)
    prompt_info = ""
    if no_prompt:
        logger.warning('The command requires the extension %s. It will be installed first.', ext_name)
        install_ext = True
    else:  # yes_prompt
        from knack.prompting import prompt_y_n, NoTTYException
        prompt_msg = 'The command requires the extension {}. Do you want to install it now?'.format(ext_name)
        if run_after_extension_installed:
            prompt_msg = '{} The command will continue to run after the extension is installed.' \
                .format(prompt_msg)
        NO_PROMPT_CONFIG_MSG = "Run 'az config set extension.use_dynamic_install=" \
            "yes_without_prompt' to allow installing extensions without prompt."
        try:
            install_ext = prompt_y_n(prompt_msg, default='y')
            if install_ext:
                prompt_info = " with prompt"
                logger.warning(NO_PROMPT_CONFIG_MSG)
        except NoTTYException:
            tty_err_msg = "The command requires the extension {}. " \
                          "Unable to prompt for extension install confirmation as no tty " \
                          "available. {}".format(ext_name, NO_PROMPT_CONFIG_MSG)
            az_error = NoTTYError(tty_err_msg)
            az_error.print_error()
            az_error.send_telemetry()
            parser.exit(exit_code)

    print_error = True
    if install_ext:
        from azure.cli.core.extension.operations import add_extension
        add_extension(cli_ctx=cli_ctx, extension_name=ext_name, upgrade=True)
        if run_after_extension_installed:
            import subprocess
            import platform
            exit_code = subprocess.call(args, shell=platform.system() == 'Windows')
            # In this case, error msg is for telemetry recording purpose only.
            # From UX perspective, the command will rerun in subprocess. Whether it succeeds or fails,
            # mesages will be shown from the subprocess and this process should not print more message to
            # interrupt that.
            print_error = False
            error_msg = ("Extension {} dynamically installed{} and commands will be "
                         "rerun automatically.").format(ext_name, prompt_info)
        else:
            error_msg = 'Extension {} installed{}. Please rerun your command.' \
                .format(ext_name, prompt_info)
    else:
        error_msg = "The command requires the latest version of extension {ext_name}. " \
            "To install, run 'az extension add --upgrade -n {ext_name}'.".format(
                ext_name=ext_name)
    az_error = CommandNotFoundError(error_msg)
    if print_error:
        az_error.print_error()
    az_error.send_telemetry()
    parser.exit(exit_code)
예제 #29
0
 def test_prompt_choice_list(self, _):
     a_list = ['red', 'blue', 'yellow', 'green']
     with mock.patch('knack.prompting._input', return_value='3'):
         actual_result = prompt_choice_list('What is your favourite color?',
                                            a_list)
         self.assertEqual(2, actual_result)
예제 #30
0
def _prompt_for_parameters(missing_parameters, fail_on_no_tty=True):  # pylint: disable=too-many-statements

    prompt_list = missing_parameters.keys() if isinstance(missing_parameters, OrderedDict) \
        else sorted(missing_parameters)
    result = OrderedDict()
    no_tty = False
    for param_name in prompt_list:
        param = missing_parameters[param_name]
        param_type = param.get('type', 'string')
        description = 'Missing description'
        metadata = param.get('metadata', None)
        if metadata is not None:
            description = metadata.get('description', description)
        allowed_values = param.get('allowedValues', None)

        prompt_str = "Please provide {} value for '{}' (? for help): ".format(
            param_type, param_name)
        while True:
            if allowed_values is not None:
                try:
                    ix = prompt_choice_list(prompt_str,
                                            allowed_values,
                                            help_string=description)
                    result[param_name] = allowed_values[ix]
                except NoTTYException:
                    result[param_name] = None
                    no_tty = True
                break
            elif param_type == 'securestring':
                try:
                    value = prompt_pass(prompt_str, help_string=description)
                except NoTTYException:
                    value = None
                    no_tty = True
                result[param_name] = value
                break
            elif param_type == 'int':
                try:
                    int_value = prompt_int(prompt_str, help_string=description)
                    result[param_name] = int_value
                except NoTTYException:
                    result[param_name] = 0
                    no_tty = True
                break
            elif param_type == 'bool':
                try:
                    value = prompt_t_f(prompt_str, help_string=description)
                    result[param_name] = value
                except NoTTYException:
                    result[param_name] = False
                    no_tty = True
                break
            elif param_type in ['object', 'array']:
                try:
                    value = prompt(prompt_str, help_string=description)
                except NoTTYException:
                    value = ''
                    no_tty = True

                if value == '':
                    value = {} if param_type == 'object' else []
                else:
                    try:
                        value = shell_safe_json_parse(value)
                    except Exception as ex:  # pylint: disable=broad-except
                        logger.error(ex)
                        continue
                result[param_name] = value
                break
            else:
                try:
                    result[param_name] = prompt(prompt_str,
                                                help_string=description)
                except NoTTYException:
                    result[param_name] = None
                    no_tty = True
                break
    if no_tty and fail_on_no_tty:
        raise NoTTYException
    return result
예제 #31
0
def _prompt_for_parameters(missing_parameters, fail_on_no_tty=True):  # pylint: disable=too-many-statements

    prompt_list = missing_parameters.keys() if isinstance(missing_parameters, OrderedDict) \
        else sorted(missing_parameters)
    result = OrderedDict()
    no_tty = False
    for param_name in prompt_list:
        param = missing_parameters[param_name]
        param_type = param.get('type', 'string')
        description = 'Missing description'
        metadata = param.get('metadata', None)
        if metadata is not None:
            description = metadata.get('description', description)
        allowed_values = param.get('allowedValues', None)

        prompt_str = "Please provide {} value for '{}' (? for help): ".format(param_type, param_name)
        while True:
            if allowed_values is not None:
                try:
                    ix = prompt_choice_list(prompt_str, allowed_values, help_string=description)
                    result[param_name] = allowed_values[ix]
                except NoTTYException:
                    result[param_name] = None
                    no_tty = True
                break
            elif param_type == 'securestring':
                try:
                    value = prompt_pass(prompt_str, help_string=description)
                except NoTTYException:
                    value = None
                    no_tty = True
                result[param_name] = value
                break
            elif param_type == 'int':
                try:
                    int_value = prompt_int(prompt_str, help_string=description)
                    result[param_name] = int_value
                except NoTTYException:
                    result[param_name] = 0
                    no_tty = True
                break
            elif param_type == 'bool':
                try:
                    value = prompt_t_f(prompt_str, help_string=description)
                    result[param_name] = value
                except NoTTYException:
                    result[param_name] = False
                    no_tty = True
                break
            elif param_type in ['object', 'array']:
                try:
                    value = prompt(prompt_str, help_string=description)
                except NoTTYException:
                    value = ''
                    no_tty = True

                if value == '':
                    value = {} if param_type == 'object' else []
                else:
                    try:
                        value = shell_safe_json_parse(value)
                    except Exception as ex:  # pylint: disable=broad-except
                        logger.error(ex)
                        continue
                result[param_name] = value
                break
            else:
                try:
                    result[param_name] = prompt(prompt_str, help_string=description)
                except NoTTYException:
                    result[param_name] = None
                    no_tty = True
                break
    if no_tty and fail_on_no_tty:
        raise NoTTYException
    return result