Exemplo n.º 1
0
def install_dependencies(config):
    num_of_retries = 5
    sleep_interval_in_sec = 5
    working_folder = config['AgentWorkingFolder']
    install_dependencies_path = os.path.join(
        working_folder, Constants.install_dependencies_script)
    for i in range(num_of_retries):
        install_dependencies_proc = subprocess.Popen(install_dependencies_path,
                                                     stdout=subprocess.PIPE,
                                                     stderr=subprocess.PIPE)
        install_out, install_err = install_dependencies_proc.communicate()
        return_code = install_dependencies_proc.returncode
        handler_utility.log(
            'Install dependencies process exit code : {0}'.format(return_code))
        handler_utility.log('stdout : {0}'.format(install_out))
        handler_utility.log('srderr : {0}'.format(install_err))
        if (return_code == 0):
            handler_utility.log('Dependencies installed successfully.')
            break
        else:
            error_message = 'Installing dependencies failed with error : {0}'.format(
                install_err)
            if (i == (num_of_retries - 1)):
                raise Exception(error_message)
            else:
                handler_utility.log(error_message)
        sleep(sleep_interval_in_sec)
    handler_utility.add_handler_sub_status(
        Util.HandlerSubStatus('InstalledDependencies'))
Exemplo n.º 2
0
def enable():
    handler_utility.set_handler_status(Util.HandlerStatus('Installing'))
    pre_validation_checks()
    config = get_configuration_from_settings()
    if (config.get('IsPipelinesAgent') != None):
        enable_pipelines_agent(config)
        return

    compare_sequence_number()
    settings_are_same = test_extension_settings_are_same_as_disabled_version()
    if (settings_are_same):
        handler_utility.log("Skipping extension enable.")
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus(
                'SkippingEnableSameSettingsAsDisabledVersion'))
    else:
        validate_inputs(config)
        ConfigureDeploymentAgent.set_logger(handler_utility.log)
        DownloadDeploymentAgent.set_logger(handler_utility.log)
        execute_agent_pre_check(config)
        remove_existing_agent_if_required(config)
        download_agent_if_required(config)
        configure_agent_if_required(config)
        handler_utility.set_handler_status(Util.HandlerStatus('Installed'))
        add_agent_tags(config)
        handler_utility.log('Extension is enabled.')

    handler_utility.set_handler_status(Util.HandlerStatus(
        'Enabled', 'success'))

    set_last_sequence_number()
    handler_utility.log('Removing disable markup file..')
    remove_extension_disabled_markup()
Exemplo n.º 3
0
def remove_existing_agent(config):
    try:
        handler_utility.log('Agent removal started')
        try:
            ConfigureDeploymentAgent.remove_existing_agent(
                config['AgentWorkingFolder'])

            handler_utility.add_handler_sub_status(
                Util.HandlerSubStatus('RemovedAgent'))

            if (os.access(config['AgentWorkingFolder'], os.F_OK)):
                DownloadDeploymentAgent.clean_agent_folder(
                    config['AgentWorkingFolder'])
            else:
                raise Exception(
                    'Cannot cleanup the agent working folder. Access not granted'
                )

        except Exception as e:
            handler_utility.log('An unexpected error occured: {0}'.format(
                getattr(e, 'message')))
            raise e
        ConfigureDeploymentAgent.setting_params = {}
    except Exception as e:
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status['Uninstalling']
            ['operationName'], 7)
Exemplo n.º 4
0
def download_agent_if_required(config):
    global configured_agent_exists
    if (configured_agent_exists == False):
        get_agent(config)
    else:
        handler_utility.log('Skipping agent download as agent already exists.')
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('SkippingDownloadDeploymentAgent'))
Exemplo n.º 5
0
def execute_agent_pre_check(config):
    global configured_agent_exists, agent_configuration_required
    try:
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('PreCheckingDeploymentAgent'))
        configured_agent_exists = ConfigureDeploymentAgent.is_agent_configured(
            config['AgentWorkingFolder'])
        if (configured_agent_exists == True):
            agent_configuration_required = test_agent_configuration_required(
                config)
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('PreCheckedDeploymentAgent'))
    except Exception as e:
        set_error_status_and_error_exit(
            e,
            RMExtensionStatus.rm_extension_status['PreCheckingDeploymentAgent']
            ['operationName'], 3)
Exemplo n.º 6
0
def register_agent(config):
    global configured_agent_exists
    try:

        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('ConfiguringDeploymentAgent'))
        handler_utility.log('Configuring agent...')
        ConfigureDeploymentAgent.configure_agent(config['VSTSUrl'], config['PATToken'], config['TeamProject'], \
          config['DeploymentGroup'], config['ConfigureAgentAsUserName'], config['AgentName'], config['AgentWorkingFolder'])
        handler_utility.log('Agent configured successfully')

        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('ConfiguredDeploymentAgent'))
    except Exception as e:
        set_error_status_and_error_exit(
            e,
            RMExtensionStatus.rm_extension_status['ConfiguringDeploymentAgent']
            ['operationName'], 6)
Exemplo n.º 7
0
def enable_pipelines_agent(config):
    try:

        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('DownloadPipelinesAgent'))
        agentFolder = config["AgentFolder"]

        # download the agent tar file
        downloadUrl = config["AgentDownloadUrl"]
        agentFile = os.path.join(agentFolder, os.path.basename(downloadUrl))
        urllib.urlretrieve(downloadUrl, agentFile)

        # download the enable script
        downloadUrl = config["EnableScriptDownloadUrl"]
        enableFile = os.path.join(agentFolder, os.path.basename(downloadUrl))
        urllib.urlretrieve(downloadUrl, enableFile)

    except Exception as e:
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status[
                'DownloadPipelinesAgentError']['operationName'],
            getattr(e, 'message'))

    try:
        # run the enable script
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('EnablePipelinesAgent'))
        enableParameters = config["EnableScriptParameters"]
        enableProcess = subprocess.Popen(
            ['/bin/bash', '-c', enableFile, enableParameters])

        # wait for the script to complete
        installProcess.communicate()

    except Exception as e:
        set_error_status_and_error_exit(
            e,
            RMExtensionStatus.rm_extension_status['EnablePipelinesAgentError']
            ['operationName'], getattr(e, 'message'))

    handler_utility.add_handler_sub_status(
        Util.HandlerSubStatus('EnablePipelinesAgentSuccess'))
    handler_utility.set_handler_status(Util.HandlerStatus('Enabled'))
    handler_utility.log('Pipelines Agent is enabled.')
Exemplo n.º 8
0
def configure_agent_if_required(config):
    if (agent_configuration_required):
        install_dependencies(config)
        register_agent(config)
    else:
        handler_utility.log(
            'Agent is already configured with given set of parameters. Skipping agent configuration.'
        )
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('SkippingAgentConfiguration'))
Exemplo n.º 9
0
def get_agent(config):
    try:
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('DownloadingDeploymentAgent'))

        handler_utility.log(
            'Invoking function to download Deployment agent package...')
        DownloadDeploymentAgent.download_deployment_agent(
            config['VSTSUrl'], config['PATToken'],
            config['AgentWorkingFolder'])
        handler_utility.log('Agent package downloaded and extracted')

        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('DownloadedDeploymentAgent'))
    except Exception as e:
        set_error_status_and_error_exit(
            e,
            RMExtensionStatus.rm_extension_status['DownloadingDeploymentAgent']
            ['operationName'], 5)
Exemplo n.º 10
0
def add_agent_tags(config):

    try:
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('AddingAgentTags'))

        if (config['Tags'] != None and len(config['Tags']) > 0):
            handler_utility.log('Adding tags to configured agent - {0}'.format(
                str(config['Tags'])))
            tags_string = json.dumps(config['Tags'], ensure_ascii=False)
            ConfigureDeploymentAgent.add_agent_tags(config['VSTSUrl'], config['TeamProject'], \
            config['PATToken'], config['AgentWorkingFolder'], tags_string)

            handler_utility.add_handler_sub_status(
                Util.HandlerSubStatus('AgentTagsAdded'))
        else:
            handler_utility.log('No tags provided for agent')
    except Exception as e:
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status['AddingAgentTags']
            ['operationName'], 8)
Exemplo n.º 11
0
def pre_validation_checks():
    try:
        validate_os()
        check_python_version()
        check_systemd_exists()
    except Exception as e:
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status['PreValidationCheck']
            ['operationName'], getattr(e, 'Code'))

    handler_utility.add_handler_sub_status(
        Util.HandlerSubStatus('PreValidationCheckSuccess'))
Exemplo n.º 12
0
def disable():
    ConfigureDeploymentAgent.set_logger(handler_utility.log)
    config = get_configuration_from_settings()

    if (config.get('IsPipelinesAgent') != None):
        return

    handler_utility.log('Disable command is no-op for agent')
    handler_utility.log(
        'Disabling extension handler. Creating a markup file..')
    set_extension_disabled_markup()

    handler_utility.add_handler_sub_status(Util.HandlerSubStatus('Disabled'))

    handler_utility.set_handler_status(
        Util.HandlerStatus('Disabled', 'success'))
Exemplo n.º 13
0
def compare_sequence_number():
    try:
        sequence_number = int(handler_utility._context._seq_no)
        last_sequence_number = get_last_sequence_number()
        if ((sequence_number == last_sequence_number)
                and not (test_extension_disabled_markup())):
            handler_utility.log(
                RMExtensionStatus.rm_extension_status['SkippedInstallation']
                ['Message'])
            handler_utility.log(
                'Skipping enable since seq numbers match. Seq number: {0}.'.
                format(sequence_number))
            handler_utility.add_handler_sub_status(
                Util.HandlerSubStatus('SkippedInstallation'))
            handler_utility.set_handler_status(
                Util.HandlerStatus('Enabled', 'success'))
            exit_with_code(0)

    except Exception as e:
        handler_utility.log('Sequence number check failed: {0}.'.format(
            getattr(e, 'message')))
Exemplo n.º 14
0
def enable_pipelines_agent(config):
    try:
        handler_utility.log('Enable Pipelines Agent')

        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('DownloadPipelinesAgent'))
        agentFolder = config["AgentFolder"]
        handler_utility.log(agentFolder)

        if (not os.path.isdir(agentFolder)):
            handler_utility.log('Agent folder does not exist. Creating it.')
            os.makedirs(agentFolder, 0o777)

        # download the agent tar file
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('DownloadPipelinesZip'))
        handler_utility.log('Download Pipelines Zip')
        downloadUrl = config["AgentDownloadUrl"]
        handler_utility.log(downloadUrl)
        filename = os.path.basename(downloadUrl)
        agentFile = os.path.join(agentFolder, filename)
        urllib.urlretrieve(downloadUrl, agentFile)

        # download the enable script
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('DownloadPipelinesScript'))
        handler_utility.log('Download Pipelines Script')
        downloadUrl = config["EnableScriptDownloadUrl"]
        handler_utility.log(downloadUrl)
        filename = os.path.basename(downloadUrl)
        enableFile = os.path.join(agentFolder, filename)
        urllib.urlretrieve(downloadUrl, enableFile)

    except Exception as e:
        handler_utility.log(getattr(e, 'message'))
        handler_utility.log(e)
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status[
                'DownloadPipelinesAgentError']['operationName'],
            getattr(e, 'message'))
        return

    try:
        # grant executable access to the script
        os.chmod(enableFile, 0o777)

        # run the enable script
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('EnablePipelinesAgent'))
        handler_utility.log('Run Pipelines Script')
        handler_utility.log(enableFile)
        enableParameters = config["EnableScriptParameters"]

        # run the script and wait for it to complete
        handler_utility.log("running script")
        argList = ['/bin/bash', enableFile] + shlex.split(enableParameters)
        enableProcess = subprocess.Popen(argList)
        enableProcess.communicate()

    except Exception as e:
        handler_utility.log(getattr(e, 'message'))
        handler_utility.log(e)
        set_error_status_and_error_exit(
            e,
            RMExtensionStatus.rm_extension_status['EnablePipelinesAgentError']
            ['operationName'], getattr(e, 'message'))
        return

    handler_utility.add_handler_sub_status(
        Util.HandlerSubStatus('EnablePipelinesAgentSuccess'))
    handler_utility.set_handler_status(Util.HandlerStatus(
        'Enabled', 'success'))
    handler_utility.log('Pipelines Agent is enabled.')
Exemplo n.º 15
0
def get_configuration_from_settings():
    try:
        public_settings = handler_utility.get_public_settings()
        if (public_settings == None):
            public_settings = {}
        handler_utility.verify_public_settings_is_dict(public_settings)

        protected_settings = handler_utility.get_protected_settings()
        if (protected_settings == None):
            protected_settings = {}

        handler_utility.log("get_configuration_from_settings")
        ####################################################################################################################################
        ####################################################################################################################################
        # If this is a pipelines agent, read the settings and return quickly
        # Note that the pipelines settings come over as camelCase
        if (public_settings.has_key('isPipelinesAgent')):
            handler_utility.log("Is Pipelines Agent")

            # read pipelines agent settings
            agentDownloadUrl = public_settings['agentDownloadUrl']
            handler_utility.verify_input_not_null('agentDownloadUrl',
                                                  agentDownloadUrl)

            agentFolder = public_settings['agentFolder']
            handler_utility.verify_input_not_null('agentFolder', agentFolder)

            enableScriptDownloadUrl = public_settings[
                'enableScriptDownloadUrl']
            handler_utility.verify_input_not_null('enableScriptDownloadUrl',
                                                  enableScriptDownloadUrl)

            # for testing, first try to get the script parameters from the public settings
            # in production they will be in the protected settings
            handler_utility.log("looking for enableScriptParameters")

            if (protected_settings.has_key('enableScriptParameters')):
                handler_utility.log("protected enableScriptParameters")
                enableScriptParameters = protected_settings[
                    'enableScriptParameters']

            if (public_settings.has_key('enableScriptParameters')):
                handler_utility.log("public enableScriptParameters")
                enableScriptParameters = public_settings[
                    'enableScriptParameters']

            handler_utility.log("validating enableScriptParameters")

            handler_utility.verify_input_not_null('enableScriptParameters',
                                                  enableScriptParameters)

            return {
                'IsPipelinesAgent': 'true',
                'AgentDownloadUrl': agentDownloadUrl,
                'AgentFolder': agentFolder,
                'EnableScriptDownloadUrl': enableScriptDownloadUrl,
                'EnableScriptParameters': enableScriptParameters
            }

        ####################################################################################################################################
        ####################################################################################################################################
        # continue with deployment agent settings
        handler_utility.log("Is Deployment Agent")
        pat_token = ''
        if ((protected_settings.__class__.__name__ == 'dict')
                and protected_settings.has_key('PATToken')):
            pat_token = protected_settings['PATToken']
        if ((pat_token == '') and (public_settings.has_key('PATToken'))):
            pat_token = public_settings['PATToken']

        vsts_account_url = ''
        if (public_settings.has_key('AzureDevOpsOrganizationUrl')):
            vsts_account_url = public_settings[
                'AzureDevOpsOrganizationUrl'].strip('/')
        elif (public_settings.has_key('VSTSAccountUrl')):
            vsts_account_url = public_settings['VSTSAccountUrl'].strip('/')
        elif (public_settings.has_key('VSTSAccountName')):
            vsts_account_url = public_settings['VSTSAccountName'].strip('/')
        handler_utility.verify_input_not_null('AzureDevOpsOrganizationUrl',
                                              vsts_account_url)
        vsts_url = vsts_account_url

        vsts_url = parse_account_name(vsts_account_url, pat_token)
        handler_utility.log(
            'Azure DevOps Organization Url : {0}'.format(vsts_url))

        team_project_name = ''
        if (public_settings.has_key('TeamProject')):
            team_project_name = public_settings['TeamProject']
        handler_utility.verify_input_not_null('TeamProject', team_project_name)
        handler_utility.log('Team Project : {0}'.format(team_project_name))

        deployment_group_name = ''
        if (public_settings.has_key('DeploymentGroup')):
            deployment_group_name = public_settings['DeploymentGroup']
        elif (public_settings.has_key('MachineGroup')):
            deployment_group_name = public_settings['MachineGroup']
        handler_utility.verify_input_not_null('DeploymentGroup',
                                              deployment_group_name)
        handler_utility.log(
            'Deployment Group : {0}'.format(deployment_group_name))

        agent_name = ''
        if (public_settings.has_key('AgentName')):
            agent_name = public_settings['AgentName']
        handler_utility.log('Agent Name : {0}'.format(agent_name))

        tags_input = []
        if (public_settings.has_key('Tags')):
            tags_input = public_settings['Tags']
        handler_utility.log('Tags : {0}'.format(tags_input))
        tags = format_tags_input(tags_input)

        configure_agent_as_username = ''
        if (public_settings.has_key('UserName')):
            configure_agent_as_username = public_settings['UserName']

        handler_utility.log('Done reading config settings from file...')
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('SuccessfullyReadSettings'))
        return {
            'VSTSUrl': vsts_url,
            'PATToken': pat_token,
            'TeamProject': team_project_name,
            'DeploymentGroup': deployment_group_name,
            'AgentName': agent_name,
            'Tags': tags,
            'AgentWorkingFolder': Constants.agent_working_folder,
            'ConfigureAgentAsUserName': configure_agent_as_username
        }
    except Exception as e:
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status['ReadingSettings']
            ['operationName'],
            RMExtensionStatus.rm_extension_status['InputConfigurationError'])
Exemplo n.º 16
0
def validate_inputs(config):
    try:
        invalid_pat_error_message = "Please make sure that the Personal Access Token entered is valid and has 'Deployment Groups - Read & manage' scope."
        inputs_validation_error_code = RMExtensionStatus.rm_extension_status[
            'InputConfigurationError']
        unexpected_error_message = "Some unexpected error occured. Status code : {0}"
        error_message_initial_part = "Could not verify that the deployment group '" + config[
            'DeploymentGroup'] + "' exists in the project '" + config[
                'TeamProject'] + "' in the specified organization '" + config[
                    'VSTSUrl'] + "'. Status: {0} Error: {1}. "

        # Verify the deployment group exists and the PAT has the required(Deployment Groups - Read & manage) scope
        # This is the first validation http call, so using Invoke-WebRequest instead of Invoke-RestMethod, because if the PAT provided is not a token at all(not even an unauthorized one) and some random value, then the call
        # would redirect to sign in page and not throw an exception. So, to handle this case.

        specific_error_message = ""
        get_deployment_group_url = "{0}/{1}/_apis/distributedtask/deploymentgroups?name={2}&api-version={3}".format(
            config['VSTSUrl'], quote(config['TeamProject']),
            quote(config['DeploymentGroup']), Constants.projectAPIVersion)

        handler_utility.log(
            "Get deployment group url - {0}".format(get_deployment_group_url))

        response = Util.make_http_call(get_deployment_group_url, 'GET', None,
                                       None, config['PATToken'])

        if (response.status != Constants.HTTP_OK):
            if (response.status == Constants.HTTP_FOUND):
                specific_error_message = invalid_pat_error_message
            elif (response.status == Constants.HTTP_UNAUTHORIZED):
                specific_error_message = invalid_pat_error_message
            elif (response.status == Constants.HTTP_FORBIDDEN):
                specific_error_message = "Please ensure that the user has 'View project-level information' permissions on the project '{0}'.".format(
                    config['TeamProject'])
            elif (response.status == Constants.HTTP_NOTFOUND):
                specific_error_message = "Please make sure that you enter the correct organization name and verify that the project exists in the organization."
            else:
                specific_error_message = unexpected_error_message.format(
                    response.status)
                inputs_validation_error_code = RMExtensionStatus.rm_extension_status[
                    'GenericError']
            error_message = error_message_initial_part.format(
                response.status, specific_error_message)

            raise RMExtensionStatus.new_handler_terminating_error(
                inputs_validation_error_code, error_message)

        deployment_group_data = json.loads(response.read())

        if (('value' not in deployment_group_data)
                or len(deployment_group_data['value']) == 0):
            specific_error_message = "Please make sure that the deployment group {0} exists in the project {1}, and the user has 'Manage' permissions on the deployment group.".format(
                config['DeploymentGroup'], config['TeamProject'])
            raise RMExtensionStatus.new_handler_terminating_error(
                inputs_validation_error_code,
                error_message_initial_part.format(response.status,
                                                  specific_error_message))

        deployment_group_id = deployment_group_data['value'][0]['id']
        handler_utility.log(
            "Validated that the deployment group {0} exists".format(
                config['DeploymentGroup']))

        headers = {}
        headers['Content-Type'] = 'application/json'
        body = "{'name': '" + config['DeploymentGroup'] + "'}"
        patch_deployment_group_url = "{0}/{1}/_apis/distributedtask/deploymentgroups/{2}?api-version={3}".format(
            config['VSTSUrl'], quote(config['TeamProject']),
            deployment_group_id, Constants.projectAPIVersion)

        handler_utility.log("Patch deployment group url - {0}".format(
            patch_deployment_group_url))
        response = Util.make_http_call(patch_deployment_group_url, 'PATCH',
                                       body, headers, config['PATToken'])

        if (response.status != Constants.HTTP_OK):
            if (response.status == Constants.HTTP_FORBIDDEN):
                specific_error_message = "Please ensure that the user has 'Manage' permissions on the deployment group {0}".format(
                    config['DeploymentGroup'])
            else:
                specific_error_message = unexpected_error_message.format(
                    str(response.status))
                inputs_validation_error_code = RMExtensionStatus.rm_extension_status[
                    'GenericError']

            raise RMExtensionStatus.new_handler_terminating_error(
                inputs_validation_error_code,
                error_message_initial_part.format(
                    response.status, response.reason) + specific_error_message)

        handler_utility.log(
            "Validated that the user has 'Manage' permissions on the deployment group '{0}'"
            .format(config['DeploymentGroup']))
        handler_utility.log("Done validating inputs...")
        handler_utility.add_handler_sub_status(
            Util.HandlerSubStatus('SuccessfullyValidatedInputs'))

    except Exception as e:
        set_error_status_and_error_exit(
            e, RMExtensionStatus.rm_extension_status['ValidatingInputs']
            ['operationName'], getattr(e, 'Code'))