Exemple #1
0
def run_postflight(config,
                   dcos_diag=None,
                   block=False,
                   state_json_dir=None,
                   async_delegate=None,
                   retry=False,
                   options=None):
    targets = []
    for host in config['master_list']:
        s = Node(host, {'role': 'master'})
        targets += [s]

    for host in config['agent_list']:
        s = Node(host, {'role': 'agent'})
        targets += [s]

    pf = get_async_runner(config, targets, async_delegate=async_delegate)
    postflight_chain = ssh.utils.CommandChain('postflight')
    add_pre_action(postflight_chain, pf.ssh_user)

    if dcos_diag is None:
        dcos_diag = """
#!/usr/bin/env bash
# Run the DC/OS diagnostic script for up to 15 minutes (900 seconds) to ensure
# we do not return ERROR on a cluster that hasn't fully achieved quorum.
T=900
until OUT=$(/opt/mesosphere/bin/./3dt -diag) || [[ T -eq 0 ]]; do
    sleep 1
    let T=T-1
done
RETCODE=$?
for value in $OUT; do
    echo $value
done
exit $RETCODE"""

    postflight_chain.add_execute(
        [dcos_diag],
        comment='Executing local post-flight check for DC/OS servces...')
    add_post_action(postflight_chain)

    # Setup the cleanup chain
    cleanup_chain = ssh.utils.CommandChain('postflight_cleanup')
    add_post_action(cleanup_chain)

    master_agent_count = {
        'total_masters': len(config['master_list']),
        'total_agents': len(config['agent_list'])
    }

    result = yield from pf.run_commands_chain_async(
        [postflight_chain, cleanup_chain],
        block=block,
        state_json_dir=state_json_dir,
        delegate_extra_params=master_agent_count)
    return result
def test_tags_async(sshd_manager, loop):
    with sshd_manager.run(1) as sshd_ports:
        workspace = str(sshd_manager.tmpdir)
        host_ports = ['127.0.0.1:{}'.format(port) for port in sshd_ports]

        targets = []
        for _port in sshd_ports:
            _host = Node('127.0.0.1:{}'.format(_port), {
                'tag1': 'test1',
                'tag2': 'test2'
            })
            targets.append(_host)
        runner = MultiRunner(targets,
                             ssh_user=getpass.getuser(),
                             ssh_key_path=workspace + '/host_key')

        chain = CommandChain('test')
        chain.add_execute(['sleep', '1'])
        try:
            loop.run_until_complete(
                runner.run_commands_chain_async([chain],
                                                block=True,
                                                state_json_dir=workspace))
        finally:
            loop.close()

        with open(workspace + '/test.json') as fh:
            result_json = json.load(fh)
            for host_port in host_ports:
                assert 'tags' in result_json['hosts'][host_port]
                assert len(result_json['hosts'][host_port]['tags']) == 2
                assert result_json['hosts'][host_port]['tags'][
                    'tag1'] == 'test1'
                assert result_json['hosts'][host_port]['tags'][
                    'tag2'] == 'test2'
                assert result_json['hosts'][host_port]['commands'][0][
                    'cmd'] == [
                        "/usr/bin/ssh", "-oConnectTimeout=10",
                        "-oStrictHostKeyChecking=no",
                        "-oUserKnownHostsFile=/dev/null", "-oBatchMode=yes",
                        "-oPasswordAuthentication=no",
                        "-p{}".format(sshd_ports[0]), "-i",
                        "{}/host_key".format(workspace), "-tt",
                        "{}@127.0.0.1".format(getpass.getuser()), "sleep", "1"
                    ]
Exemple #3
0
 def add_nodes(nodes, tag):
     return [Node(node, tag) for node in nodes]
Exemple #4
0
def install_dcos(config,
                 block=False,
                 state_json_dir=None,
                 hosts=None,
                 async_delegate=None,
                 try_remove_stale_dcos=False,
                 **kwargs):
    if hosts is None:
        hosts = []
    assert isinstance(hosts, list)

    # Role specific parameters
    role_params = {
        'master': {
            'tags': {
                'role': 'master',
                'dcos_install_param': 'master'
            },
            'hosts': config['master_list']
        },
        'agent': {
            'tags': {
                'role': 'agent',
                'dcos_install_param': 'slave'
            },
            'hosts': config.hacky_default_get('agent_list', [])
        },
        'public_agent': {
            'tags': {
                'role': 'public_agent',
                'dcos_install_param': 'slave_public'
            },
            'hosts': config.hacky_default_get('public_agent_list', [])
        }
    }

    bootstrap_tarball = _get_bootstrap_tarball()
    log.debug("Local bootstrap found: %s", bootstrap_tarball)

    targets = []
    if hosts:
        targets = hosts
    else:
        for role, params in role_params.items():
            targets += [Node(node, params['tags']) for node in params['hosts']]

    runner = get_async_runner(config, targets, async_delegate=async_delegate)
    chains = []
    if try_remove_stale_dcos:
        pkgpanda_uninstall_chain = ssh.utils.CommandChain('remove_stale_dcos')
        pkgpanda_uninstall_chain.add_execute(
            ['sudo', '-i', '/opt/mesosphere/bin/pkgpanda', 'uninstall'],
            stage='Trying pkgpanda uninstall')
        chains.append(pkgpanda_uninstall_chain)

        remove_dcos_chain = ssh.utils.CommandChain('remove_stale_dcos')
        remove_dcos_chain.add_execute(
            ['rm', '-rf', '/opt/mesosphere', '/etc/mesosphere'],
            stage="Removing DC/OS files")
        chains.append(remove_dcos_chain)

    chain = ssh.utils.CommandChain('deploy')
    chains.append(chain)

    add_pre_action(chain, runner.ssh_user)
    _add_copy_dcos_install(chain)
    _add_copy_packages(chain)
    _add_copy_bootstap(chain, bootstrap_tarball)

    chain.add_execute(lambda node: ('sudo bash {}/dcos_install.sh {}'.format(
        REMOTE_TEMP_DIR, node.tags['dcos_install_param'])).split(),
                      stage=lambda node: 'Installing DC/OS')

    # UI expects total_masters, total_agents to be top level keys in deploy.json
    delegate_extra_params = nodes_count_by_type(config)
    if kwargs.get('retry') and state_json_dir:
        state_file_path = os.path.join(state_json_dir, 'deploy.json')
        log.debug('retry executed for a state file deploy.json')
        for _host in hosts:
            _remove_host(state_file_path, '{}:{}'.format(_host.ip, _host.port))

        # We also need to update total number of hosts
        json_state = _read_state_file(state_file_path)
        delegate_extra_params['total_hosts'] = json_state['total_hosts']

    # Setup the cleanup chain
    cleanup_chain = ssh.utils.CommandChain('deploy_cleanup')
    add_post_action(cleanup_chain)
    chains.append(cleanup_chain)

    result = yield from runner.run_commands_chain_async(
        chains,
        block=block,
        state_json_dir=state_json_dir,
        delegate_extra_params=delegate_extra_params)
    return result
Exemple #5
0
def action_action_name(request):
    """Return /action/<action_name>

    :param request: a web requeest object.
    :type request: request | None
    """
    action_name = request.match_info['action_name']

    # Update the global action
    json_state = read_json_state(action_name)
    app['current_action'] = action_name

    if request.method == 'GET':
        log.info('GET {}'.format(action_name))

        if json_state:
            return web.json_response(json_state)
        return web.json_response({})

    elif request.method == 'POST':
        log.info('POST {}'.format(action_name))
        action = action_map.get(action_name)
        # If the action name is preflight, attempt to run configuration
        # generation. If genconf fails, present the UI with a usable error
        # for the end-user
        if action_name == 'preflight':
            try:
                print_header("GENERATING CONFIGURATION")
                backend.do_configure()
            except:
                genconf_failure = {
                    "errors": "Configuration generation failed, please see command line for details"
                }
                return web.json_response(genconf_failure, status=400)

        params = yield from request.post()

        if json_state:
            if action_name == 'deploy' and 'retry' in params:
                if 'hosts' in json_state:
                    failed_hosts = []
                    for deploy_host, deploy_params in json_state['hosts'].items():
                        if deploy_params['host_status'] != 'success':
                            failed_hosts.append(Node(deploy_host, tags=deploy_params['tags']))
                    log.debug('failed hosts: {}'.format(failed_hosts))
                    if failed_hosts:
                        yield from asyncio.async(
                            action(
                                backend.get_config(),
                                state_json_dir=STATE_DIR,
                                hosts=failed_hosts,
                                try_remove_stale_dcos=True,
                                **params))
                        return web.json_response({
                            'status': 'retried',
                            'details': sorted(['{}:{}'.format(node.ip, node.port) for node in failed_hosts])
                        })

            if action_name not in remove_on_done:
                return web.json_response({'status': '{} was already executed, skipping'.format(action_name)})

            running = False
            for host, attributes in json_state['hosts'].items():
                if attributes['host_status'].lower() == 'running':
                    running = True

            log.debug('is action running: {}'.format(running))
            if running:
                return web.json_response({'status': '{} is running, skipping'.format(action_name)})
            else:
                unlink_state_file(action_name)

        yield from asyncio.async(action(backend.get_config(), state_json_dir=STATE_DIR, options=options, **params))
        return web.json_response({'status': '{} started'.format(action_name)})
Exemple #6
0
def run_preflight(config,
                  pf_script_path='/genconf/serve/dcos_install.sh',
                  block=False,
                  state_json_dir=None,
                  async_delegate=None,
                  retry=False,
                  options=None):
    '''
    Copies preflight.sh to target hosts and executes the script. Gathers
    stdout, sterr and return codes and logs them to disk via SSH library.
    :param config: Dict, loaded config file from /genconf/config.yaml
    :param pf_script_path: preflight.sh script location on a local host
    :param preflight_remote_path: destination location
    '''
    if not os.path.isfile(pf_script_path):
        log.error(
            "genconf/serve/dcos_install.sh does not exist. Please run --genconf before executing preflight."
        )
        raise FileNotFoundError('genconf/serve/dcos_install.sh does not exist')
    targets = []
    for host in config['master_list']:
        s = Node(host, {'role': 'master'})
        targets += [s]

    for host in config['agent_list']:
        s = Node(host, {'role': 'agent'})
        targets += [s]

    pf = get_async_runner(config, targets, async_delegate=async_delegate)
    chains = []

    preflight_chain = ssh.utils.CommandChain('preflight')
    # In web mode run if no --offline flag used.
    if options.web:
        if options.offline:
            log.debug(
                'Offline mode used. Do not install prerequisites on CentOS7, RHEL7 in web mode'
            )
        else:
            _add_prereqs_script(preflight_chain)

    add_pre_action(preflight_chain, pf.ssh_user)
    preflight_chain.add_copy(pf_script_path,
                             REMOTE_TEMP_DIR,
                             comment='COPYING PREFLIGHT SCRIPT TO TARGETS')

    preflight_chain.add_execute('sudo bash {} --preflight-only master'.format(
        os.path.join(REMOTE_TEMP_DIR,
                     os.path.basename(pf_script_path))).split(),
                                comment='EXECUTING PREFLIGHT CHECK ON TARGETS')
    chains.append(preflight_chain)

    # Setup the cleanup chain
    cleanup_chain = ssh.utils.CommandChain('preflight_cleanup')
    add_post_action(cleanup_chain)

    chains.append(cleanup_chain)
    master_agent_count = {
        'total_masters': len(config['master_list']),
        'total_agents': len(config['agent_list'])
    }

    result = yield from pf.run_commands_chain_async(
        chains,
        block=block,
        state_json_dir=state_json_dir,
        delegate_extra_params=master_agent_count)
    return result
Exemple #7
0
def install_dcos(config,
                 block=False,
                 state_json_dir=None,
                 hosts=[],
                 async_delegate=None,
                 try_remove_stale_dcos=False,
                 roles=None,
                 **kwargs):
    if roles is None:
        roles = ['master', 'agent']

    # Role specific parameters
    role_params = {
        'master': {
            'tags': {
                'role': 'master',
                'dcos_install_param': 'master'
            },
            'hosts': hosts if hosts else config['master_list']
        },
        'agent': {
            'tags': {
                'role': 'agent',
                'dcos_install_param': 'slave'
            },
            'hosts': hosts if hosts else config['agent_list']
        }
    }

    bootstrap_tarball = _get_bootstrap_tarball()

    log.debug("Local bootstrap found: %s", bootstrap_tarball)

    targets = []
    for role in roles:
        default_params = role_params[role]
        for host in default_params['hosts']:
            node = Node(host, default_params['tags'])
            targets += [node]

    log.debug('Got {} hosts'.format(targets))
    runner = get_async_runner(config, targets, async_delegate=async_delegate)
    chains = []
    if try_remove_stale_dcos:
        pkgpanda_uninstall_chain = ssh.utils.CommandChain('remove_stale_dcos')
        pkgpanda_uninstall_chain.add_execute(
            ['sudo', '-i', '/opt/mesosphere/bin/pkgpanda', 'uninstall'],
            comment='TRYING pkgpanda uninstall')
        chains.append(pkgpanda_uninstall_chain)

        remove_dcos_chain = ssh.utils.CommandChain('remove_stale_dcos')
        remove_dcos_chain.add_execute(
            ['rm', '-rf', '/opt/mesosphere', '/etc/mesosphere'])
        chains.append(remove_dcos_chain)

    chain = ssh.utils.CommandChain('deploy')
    chains.append(chain)

    add_pre_action(chain, runner.ssh_user)
    _add_copy_dcos_install(chain)
    _add_copy_packages(chain)
    _add_copy_bootstap(chain, bootstrap_tarball)

    chain.add_execute(
        lambda node: ('sudo bash {}/dcos_install.sh {}'.format(
            REMOTE_TEMP_DIR, node.tags['dcos_install_param'])).split(),
        comment=lambda node: 'INSTALLING DC/OS ON NODE {}, ROLE {}'.format(
            node.ip, node.tags['role']))

    # UI expects total_masters, total_agents to be top level keys in deploy.json
    delegate_extra_params = {
        'total_masters': len(config['master_list']),
        'total_agents': len(config['agent_list'])
    }
    if kwargs.get('retry') and state_json_dir:
        state_file_path = os.path.join(state_json_dir, 'deploy.json')
        log.debug('retry executed for a state file deploy.json')
        for _host in hosts:
            _remove_host(state_file_path, _host)

        # We also need to update total number of hosts
        json_state = _read_state_file(state_file_path)
        delegate_extra_params['total_hosts'] = json_state['total_hosts']

    # Setup the cleanup chain
    cleanup_chain = ssh.utils.CommandChain('deploy_cleanup')
    add_post_action(cleanup_chain)
    chains.append(cleanup_chain)

    result = yield from runner.run_commands_chain_async(
        chains,
        block=block,
        state_json_dir=state_json_dir,
        delegate_extra_params=delegate_extra_params)
    return result