Esempio n. 1
0
def test_node_decommission():
    agents = mesos.DCOSClient().get_state_summary()['slaves']
    agents_count = len(agents)
    assert agents_count > 0

    agent_id = agents[0]['id']

    returncode, stdout, stderr = exec_command(
        ['dcos', 'node', 'decommission', agent_id])

    exp_stdout = "Agent {} has been marked as gone.\n".format(agent_id)

    assert returncode == 0
    assert stdout.decode('utf-8') == exp_stdout
    assert stderr == b''

    new_agents = mesos.DCOSClient().get_state_summary()['slaves']
    assert (agents_count - 1) == len(new_agents)
Esempio n. 2
0
def test_log_master_unavailable(config_mock):
    config_mock.return_value = {'core.dcos_url': 'foo'}
    """ Test master's state.json being unavailable """
    client = mesos.DCOSClient()
    client.get_master_state = _mock_exception()

    with patch('dcos.mesos.DCOSClient', return_value=client):
        args = ['task', 'log', '_']
        assert_mock(main, args, returncode=1, stderr=(b"exception\n"))
Esempio n. 3
0
 def __init__(self, ssh_client, r_addroute, r_delroute, disablevips,
              disableoverlay):
     self.dcos_client = mesos.DCOSClient()
     self.dns_client = mesos.MesosDNSClient()
     self.ssh_client = ssh_client
     self.addroute = marshal_networks(r_addroute)
     self.delroute = marshal_networks(r_delroute)
     self.disablevips = disablevips
     self.disableoverlay = disableoverlay
Esempio n. 4
0
def get_host(host):
    if not host:
        dcos_client = mesos.DCOSClient()
        host = dcos_client.metadata().get('PUBLIC_IPV4')
    if not host:
        host = mesos.MesosDNSClient().hosts('leader.mesos.')[0]['ip']
    if not host:
        raise DCOSException("*** No host detected. Please set one manually.")
    return host
Esempio n. 5
0
def _log(follow, completed, lines, task, file_):
    """ Tail a file in the task's sandbox.

    :param follow: same as unix tail's -f
    :type follow: bool
    :param completed: whether to include completed tasks
    :type completed: bool
    :param lines: number of lines to print
    :type lines: int
    :param task: task pattern to match
    :type task: str
    :param file_: file path to read
    :type file_: str
    :returns: process return code
    :rtype: int
    """

    if task is None:
        fltr = ""
    else:
        fltr = task

    if file_ is None:
        file_ = 'stdout'

    if lines is None:
        lines = 10
    lines = util.parse_int(lines)

    # get tasks
    client = mesos.DCOSClient()
    master = mesos.Master(client.get_master_state())
    tasks = master.tasks(completed=completed, fltr=fltr)

    if not tasks:
        if not completed:
            completed_tasks = master.tasks(completed=True, fltr=fltr)
            if completed_tasks:
                msg = 'No running tasks match ID [{}]; however, there '.format(
                    fltr)
                if len(completed_tasks) > 1:
                    msg += 'are {} matching completed tasks. '.format(
                        len(completed_tasks))
                else:
                    msg += 'is 1 matching completed task. '
                msg += 'Run with --completed to see these logs.'
                raise DCOSException(msg)
        raise DCOSException('No matching tasks. Exiting.')

    mesos_files = _mesos_files(tasks, file_, client)
    if not mesos_files:
        raise DCOSException('No matching tasks. Exiting.')

    log.log_files(mesos_files, follow, lines)

    return 0
Esempio n. 6
0
def _ls(task, path, all_, long_, completed):
    """ List files in a task's sandbox.

    :param task: task pattern to match
    :type task: str
    :param path: file path to read
    :type path: str
    :param long_: whether to use a long listing format
    :type long_: bool
    :param all_: If True, include all tasks
    :type all_: bool
    :param completed: If True, include completed tasks
    :type completed: bool
    :returns: process return code
    :rtype: int
    """

    if path is None:
        path = '.'
    if path.startswith('/'):
        path = path[1:]

    dcos_client = mesos.DCOSClient()
    task_objects = mesos.get_master(dcos_client).tasks(
        fltr=task, completed=completed, all_=all_)

    if len(task_objects) == 0:
        if task is None:
            raise DCOSException("No tasks found")
        else:
            raise DCOSException(
                'Cannot find a task with ID containing "{}"'.format(task))

    try:
        all_files = []
        for task_obj in task_objects:
            dir_ = posixpath.join(task_obj.directory(), path)
            all_files += [
                (task_obj['id'], dcos_client.browse(task_obj.slave(), dir_))]
    except DCOSHTTPException as e:
        if e.response.status_code == 404:
            raise DCOSException(
                'Cannot access [{}]: No such file or directory'.format(path))
        else:
            raise

    add_header = len(all_files) > 1
    for (task_id, files) in all_files:
        if add_header:
            emitter.publish('===> {} <==='.format(task_id))
        if long_:
            emitter.publish(tables.ls_long_table(files))
        else:
            emitter.publish(
                '  '.join(posixpath.basename(file_['path'])
                          for file_ in files))
Esempio n. 7
0
def test_log_slave_unavailable():
    """ Test slave's state.json being unavailable """
    client = mesos.DCOSClient()
    client.get_slave_state = _mock_exception()

    with patch('dcos.mesos.DCOSClient', return_value=client):
        args = ['task', 'log', 'test-app1']
        stderr = (b"""Error accessing slave: exception\n"""
                  b"""No matching tasks. Exiting.\n""")
        assert_mock(main, args, returncode=1, stderr=stderr)
Esempio n. 8
0
def _decommission(mesos_id):
    try:
        mesos.DCOSClient().mark_agent_gone(mesos_id)
    except errors.DCOSException as e:
        emitter.publish(
            DefaultError("Couldn't mark agent {} as gone :\n\n{}".format(
                mesos_id, e)))
        return 1

    emitter.publish("Agent {} has been marked as gone.".format(mesos_id))
Esempio n. 9
0
def _shutdown(service_id):
    """Shuts down a service

    :param service_id: the id for the service
    :type service_id: str
    :returns: process return code
    :rtype: int
    """

    mesos.DCOSClient().shutdown_framework(service_id)
    return 0
Esempio n. 10
0
def log_job(args):
    dcos_client = mesos.DCOSClient()
    task = mesos.get_master(dcos_client).task(args['<submissionId>'])
    log_file = args.get('--file', "stdout")
    if log_file is None:
        log_file = "stdout"
    mesos_file = mesos.MesosFile(log_file, task=task, dcos_client=dcos_client)
    lines_count = args.get('--lines_count', "10")
    if lines_count is None:
        lines_count = "10"
    return log.log_files([mesos_file], args['--follow'], int(lines_count))
Esempio n. 11
0
def _list(json_, extra_field_names):
    """List DC/OS nodes

    :param json_: If true, output json.
        Otherwise, output a human readable table.
    :type json_: bool
    :param extra_field_names: List of additional field names to include in
        table output
    :type extra_field_names: [str]
    :returns: process return code
    :rtype: int
    """

    client = mesos.DCOSClient()
    masters = mesos.MesosDNSClient().masters()
    master_state = client.get_master_state()
    slaves = client.get_state_summary()['slaves']
    for master in masters:
        if master['ip'] == master_state['hostname']:
            master['type'] = 'master (leader)'
            region, zone = util.get_fault_domain(master_state)
            master['region'] = region
            master['zone'] = zone
            for key in ('id', 'pid', 'version'):
                master[key] = master_state.get(key)
        else:
            master['type'] = 'master'
    for slave in slaves:
        region, zone = util.get_fault_domain(slave)
        slave['type'] = 'agent'
        slave['region'] = region
        slave['zone'] = zone
    nodes = masters + slaves
    if json_:
        emitter.publish(nodes)
    else:
        for extra_field_name in extra_field_names:
            field_name = extra_field_name.split(':')[-1]
            if len(slaves) > 0:
                try:
                    tables._dotted_itemgetter(field_name)(slaves[0])
                except KeyError:
                    emitter.publish(
                        errors.DefaultError('Field "%s" is invalid.' %
                                            field_name))
                    return
        table = tables.node_table(nodes, extra_field_names)
        output = six.text_type(table)
        if output:
            emitter.publish(output)
        else:
            emitter.publish(errors.DefaultError('No agents found.'))
Esempio n. 12
0
def _main():
    signal.signal(signal.SIGINT, signal_handler)

    args = docopt.docopt(_doc(),
                         version='dcos version {}'.format(dcoscli.version),
                         options_first=True)

    log_level = args['--log-level']
    if log_level and not _config_log_level_environ(log_level):
        return 1

    if args['--debug']:
        os.environ[constants.DCOS_DEBUG_ENV] = 'true'

    util.configure_process_from_environ()

    if args['<command>'] != 'config' and \
       not auth.check_if_user_authenticated():
        auth.force_auth()

    config = util.get_config()
    set_ssl_info_env_vars(config)

    command = args['<command>']
    http.silence_requests_warnings()

    if not command:
        command = "help"

    executable = subcommand.command_executables(command)

    cluster_id = None
    if dcoscli.version != 'SNAPSHOT' and command and \
            command not in ["config", "help"]:
        try:
            cluster_id = mesos.DCOSClient().metadata().get('CLUSTER_ID')
        except DCOSAuthenticationException:
            raise
        except:
            msg = 'Unable to get the cluster_id of the cluster.'
            logger.exception(msg)

    # the call to retrieve cluster_id must happen before we run the subcommand
    # so that if you have auth enabled we don't ask for user/pass multiple
    # times (with the text being out of order) before we can cache the auth
    # token
    subproc = Popen([executable, command] + args['<args>'], stderr=PIPE)

    if dcoscli.version != 'SNAPSHOT':
        return analytics.wait_and_track(subproc, cluster_id)
    else:
        return analytics.wait_and_capture(subproc)[0]
Esempio n. 13
0
    def __init__(self, hosts=[]):
        self.dcos_client = mesos.DCOSClient()
        self.agents = []
        self.scheduled = None
        self.maintenance_status = None
        self.machine_ids = []
        self.full_maintenance_status = []

        self.get_agents()
        self.get_scheduled()
        self.get_maintenance_status()
        self.get_machines_ids(hosts)
        self.get_full_maintenance_status()
Esempio n. 14
0
def get_tasks(task_id='', completed=True):
    """ Get a list of tasks, optionally filtered by task name.

        :param task_id: task ID
        :type task_id: str
        :param completed: include completed tasks?
        :type completed: bool

        :return: a tuple of tasks
        :rtype: tuple
    """

    client = mesos.DCOSClient()
    master = mesos.Master(client.get_master_state())
    tasks = master.tasks(completed=completed, fltr=task_id)

    return tasks
Esempio n. 15
0
def get_ssh_proxy_options(ssh_options,
                          user_options='',
                          proxy_ip=None,
                          master_proxy=False):
    """Returns the SSH proxy arguments for the given parameters.

    :param ssh_options: SSH options
    :type ssh_options: str
    :param user_option: SSH user option string
    :type user_option: str
    :param proxy_ip: SSH proxy node
    :type proxy_ip: str | None
    :param master_proxy: Use master nodes as proxy
    :type master_proxy: boolean
    :rtype: str

    """

    if not proxy_ip:
        dcos_config_proxy_ip = config.get_config_val("core.ssh_proxy_ip")
        if dcos_config_proxy_ip:
            proxy_ip = dcos_config_proxy_ip
        elif master_proxy:
            dcos_client = mesos.DCOSClient()
            master_public_ip = dcos_client.metadata().get('PUBLIC_IPV4')
            if not master_public_ip:
                raise DCOSException(("Cannot use --master-proxy.  Failed to "
                                     "find 'PUBLIC_IPV4' at {}").format(
                                         dcos_client.get_dcos_url('metadata')))
            proxy_ip = master_public_ip

    if not proxy_ip:
        return ''

    if proxy_ip and not os.environ.get('SSH_AUTH_SOCK') and not ssh_options:
        raise DCOSException(
            "There is no SSH_AUTH_SOCK env variable, which likely means "
            "you aren't running `ssh-agent`.  `dcos node ssh "
            "--master-proxy/--proxy-ip` depends on `ssh-agent` to safely "
            "use your private key to hop between nodes in your cluster.  "
            "Please run `ssh-agent`, then add your private key with "
            "`ssh-add`.")

    proxy_options = '-A -t {0} {1} {2} -- ssh'.format(ssh_options,
                                                      user_options, proxy_ip)
    return proxy_options
Esempio n. 16
0
def get_tasks(task_id='', completed=True):
    """ Get a list of tasks, optionally filtered by task id.
        The task_id can be the abbrevated.  Example: If a task named 'sleep' is
        scaled to 3 in marathon, there will be be 3 tasks starting with 'sleep.'

        :param task_id: task ID
        :type task_id: str
        :param completed: include completed tasks?
        :type completed: bool

        :return: a list of tasks
        :rtype: []
    """

    client = mesos.DCOSClient()
    master = mesos.Master(client.get_master_state())
    mesos_tasks = master.tasks(completed=completed, fltr=task_id)
    return [task.__dict__['_task'] for task in mesos_tasks]
Esempio n. 17
0
def _log_task(task_id, follow, lines, file_):
    """Prints the contents of the logs for a given task ID.

    :param task_id: task ID
    :type task_id: str
    :param follow: same as unix tail's -f
    :type follow: bool
    :param lines: number of lines to print
    :type lines: int
    :param file_: file path to read
    :type file_: str
    :returns: process return code
    :rtype: int
    """

    dcos_client = mesos.DCOSClient()
    task = mesos.get_master(dcos_client).task(task_id)
    mesos_file = mesos.MesosFile(file_, task=task, dcos_client=dcos_client)
    return log.log_files([mesos_file], follow, lines)
Esempio n. 18
0
def _log_marathon(follow, lines, ssh_config_file):
    """Prints the contents of the marathon logs. Proxy through the master
    because marathon only runs on the master.

    :param follow: same as unix tail's -f
    :type follow: bool
    :param lines: number of lines to print
    :type lines: int
    :param ssh_config_file: SSH config file.
    :type ssh_config_file: str | None
    ;:returns: process return code
    :rtype: int
    """

    ssh_options = util.get_ssh_options(ssh_config_file, [])

    journalctl_args = ''
    if follow:
        journalctl_args += '-f '
    if lines:
        journalctl_args += '-n {} '.format(lines)

    leader_ip = marathon.create_client().get_leader().split(':')[0]
    user_string = 'core@'
    if ssh_config_file:
        user_string = ''

    dcos_client = mesos.DCOSClient()
    master_public_ip = dcos_client.metadata().get('PUBLIC_IPV4')
    service = 'dcos-marathon'

    cmd = "ssh -At {0}{1}{2} ssh -At {0}{1}{3} journalctl {4}-u {5}".format(
        ssh_options,
        user_string,
        master_public_ip,
        leader_ip,
        journalctl_args,
        service)

    emitter.publish(DefaultError("Running `{}`".format(cmd)))

    return subprocess.Subproc().call(cmd, shell=True)
Esempio n. 19
0
def gen_hosts(ssh_client):
    dcos_client = mesos.DCOSClient()
    mesos_hosts = []
    dns_hosts = []

    for host in mesos.MesosDNSClient().hosts('master.mesos.'):
        mesos_hosts.append(host['ip'])

    summary = dcos_client.get_state_summary()
    for host in summary['slaves']:
        mesos_hosts.append(host['hostname'])

    scom = 'cat /etc/resolv.conf'
    _, query_stdout, _ = ssh_client.exec_command(scom, get_pty=True)
    for line in query_stdout.readlines():
        if line.startswith('nameserver'):
            host = line.strip().split()[1]
            dns_hosts.append(host)

    return (mesos_hosts, dns_hosts)
Esempio n. 20
0
def _base_properties(conf=None):
    """
    These properties are sent with every analytics event.

    :param conf: dcos config file
    :type conf: Toml
    :rtype: dict
    """

    if not conf:
        conf = util.get_config()

    if len(sys.argv) > 1:
        cmd = 'dcos ' + _command()
        full_cmd = 'dcos ' + ' '.join(sys.argv[1:])
    else:
        cmd = 'dcos'
        full_cmd = 'dcos'

    try:
        dcos_hostname = six.moves.urllib.parse.urlparse(
            conf.get('core.dcos_url')).hostname
    except:
        logger.exception('Unable to find the hostname of the cluster.')
        dcos_hostname = None

    try:
        cluster_id = mesos.DCOSClient().metadata().get('CLUSTER_ID')
    except:
        logger.exception('Unable to get the cluster_id of the cluster.')
        cluster_id = None

    return {
        'cmd': cmd,
        'full_cmd': full_cmd,
        'dcoscli.version': dcoscli.version,
        'python_version': str(sys.version_info),
        'config': json.dumps(list(conf.property_items())),
        'DCOS_HOSTNAME': dcos_hostname,
        'CLUSTER_ID': cluster_id
    }
Esempio n. 21
0
def uninstall(package_name, remove_all, app_id, cli, app):
    """Uninstalls a package.

    :param package_name: The package to uninstall
    :type package_name: str
    :param remove_all: Whether to remove all instances of the named app
    :type remove_all: boolean
    :param app_id: App ID of the app instance to uninstall
    :type app_id: str
    :param init_client: The program to use to run the app
    :type init_client: object
    :rtype: None
    """

    if cli is False and app is False:
        cli = app = True

    uninstalled = False
    if cli:
        if subcommand.uninstall(package_name):
            uninstalled = True

    if app:
        num_apps = uninstall_app(
            package_name,
            remove_all,
            app_id,
            marathon.create_client(),
            mesos.DCOSClient())

        if num_apps > 0:
            uninstalled = True

    if uninstalled:
        return None
    else:
        msg = 'Package [{}]'.format(package_name)
        if app_id is not None:
            msg += " with id [{}]".format(app_id)
        msg += " is not installed."
        raise DCOSException(msg)
Esempio n. 22
0
def _ssh(master, slave, option, config_file, user):
    """SSH into a DCOS node using the IP addresses found in master's
       state.json

    :param master: True if the user has opted to SSH into the leading
                   master
    :type master: bool | None
    :param slave: The slave ID if the user has opted to SSH into a slave
    :type slave: str | None
    :param option: SSH option
    :type option: [str]
    :param config_file: SSH config file
    :type config_file: str | None
    :param user: SSH user
    :type user: str | None
    :rtype: int
    :returns: process return code
    """

    ssh_options = util.get_ssh_options(config_file, option)

    if master:
        host = mesos.MesosDNSClient().hosts('leader.mesos.')[0]['ip']
    else:
        summary = mesos.DCOSClient().get_state_summary()
        slave_obj = next((slave_ for slave_ in summary['slaves']
                          if slave_['id'] == slave),
                         None)
        if slave_obj:
            host = mesos.parse_pid(slave_obj['pid'])[1]
        else:
            raise DCOSException('No slave found with ID [{}]'.format(slave))

    cmd = "ssh -t {0}{1}@{2}".format(
        ssh_options,
        user,
        host)

    emitter.publish(DefaultError("Running `{}`".format(cmd)))

    return subprocess.call(cmd, shell=True)
Esempio n. 23
0
def _list(json_):
    """List DC/OS nodes

    :param json_: If true, output json.
        Otherwise, output a human readable table.
    :type json_: bool
    :returns: process return code
    :rtype: int
    """

    client = mesos.DCOSClient()
    slaves = client.get_state_summary()['slaves']
    if json_:
        emitter.publish(slaves)
    else:
        table = tables.slave_table(slaves)
        output = six.text_type(table)
        if output:
            emitter.publish(output)
        else:
            emitter.publish(errors.DefaultError('No slaves found.'))
Esempio n. 24
0
def _ls(task, path, long_, completed):
    """ List files in a task's sandbox.

    :param task: task pattern to match
    :type task: str
    :param path: file path to read
    :type path: str
    :param long_: whether to use a long listing format
    :type long_: bool
    :param completed: If True, include completed tasks
    :type completed: bool
    :returns: process return code
    :rtype: int
    """

    if path is None:
        path = '.'
    if path.startswith('/'):
        path = path[1:]

    dcos_client = mesos.DCOSClient()
    task_obj = mesos.get_master(dcos_client).task(fltr=task,
                                                  completed=completed)
    dir_ = posixpath.join(task_obj.directory(), path)

    try:
        files = dcos_client.browse(task_obj.slave(), dir_)
    except DCOSHTTPException as e:
        if e.response.status_code == 404:
            raise DCOSException(
                'Cannot access [{}]: No such file or directory'.format(path))
        else:
            raise

    if files:
        if long_:
            emitter.publish(tables.ls_long_table(files))
        else:
            emitter.publish('  '.join(
                posixpath.basename(file_['path']) for file_ in files))
Esempio n. 25
0
 def __init__(self, ctx):
     self._master_url = None
     self._zk_url = None
     self._marathon_url = None
     self._framework_url = None
     self.ctx = ctx
     try:
         self.ctx.vlog('Attempting to create DCOSClient')
         dcos_client = mesos.DCOSClient()
         self.client = dcos_client
         dcos_url = self.client.get_dcos_url('')
         ssl_verify = dcos_config.get_config().get('core.ssl_verify')
         self.ctx.vlog('DCOS core.ssl_verify value = ' + ssl_verify)
         if ssl_verify is not None and (not ssl_verify
                                        or ssl_verify == 'false'):
             self.ctx.vlog('Setting insecure_ssl to True')
             self.ctx.insecure_ssl = True
         if dcos_url is None:
             raise Exception("Unable to find DCOS server URL")
         dcos_url.rstrip('/')
         self.dcos_url = dcos_url
     except dcos_errors.DCOSException:
         raise Exception("DCOS is not configured properly")
Esempio n. 26
0
def test_node_ssh_slave_with_private_ip():
    slave_ip = mesos.DCOSClient().get_state_summary()['slaves'][0]['hostname']
    _node_ssh(['--private-ip={}'.format(slave_ip), '--master-proxy'])
Esempio n. 27
0
def __get_all_agents():
    """Provides all agent json in the cluster which can be used for filtering"""

    client = mesos.DCOSClient()
    agents = client.get_state_summary()['slaves']
    return agents
Esempio n. 28
0
def _log(all_, follow, completed, lines, task, file_):
    """ Tail a file in the task's sandbox.

    :param all_: If True, include all tasks
    :type all_: bool
    :param follow: same as unix tail's -f
    :type follow: bool
    :param completed: whether to include completed tasks
    :type completed: bool
    :param lines: number of lines to print
    :type lines: int
    :param task: task pattern to match
    :type task: str
    :param file_: file path to read
    :type file_: str
    :returns: process return code
    :rtype: int
    """

    fltr = task

    if file_ is None:
        file_ = 'stdout'

    if lines is None:
        lines = 10
    lines = util.parse_int(lines)

    # get tasks
    client = mesos.DCOSClient()
    master = mesos.Master(client.get_master_state())
    tasks = master.tasks(fltr=fltr, completed=completed, all_=all_)

    if not tasks:
        if not fltr:
            raise DCOSException("No tasks found. Exiting.")
        elif not completed:
            completed_tasks = master.tasks(completed=True, fltr=fltr)
            if completed_tasks:
                msg = 'No running tasks match ID [{}]; however, there '.format(
                    fltr)
                if len(completed_tasks) > 1:
                    msg += 'are {} matching completed tasks. '.format(
                        len(completed_tasks))
                else:
                    msg += 'is 1 matching completed task. '
                msg += 'Run with --completed to see these logs.'
                raise DCOSException(msg)
        raise DCOSException('No matching tasks. Exiting.')

    # if journald logging is disabled, read files API and exit.
    if not log.dcos_log_enabled():
        mesos_files = _mesos_files(tasks, file_, client)
        if not mesos_files:
            if fltr is None:
                msg = "No tasks found. Exiting."
            else:
                msg = "No matching tasks. Exiting."
            raise DCOSException(msg)

        log.log_files(mesos_files, follow, lines)
        return 0

    # otherwise
    if file_ in ('stdout', 'stderr'):
        _dcos_log(follow, tasks, lines, file_, completed)
        return 0

    raise DCOSException('Invalid file {}. dcos-log only '
                        'supports stdout/stderr'.format(file_))
    return 1
Esempio n. 29
0
def test_node_ssh_slave_with_command():
    slave = mesos.DCOSClient().get_state_summary()['slaves'][0]
    _node_ssh([
        '--mesos-id={}'.format(slave['id']), '--master-proxy',
        '/opt/mesosphere/bin/detect_ip'
    ], 0, slave['hostname'])
Esempio n. 30
0
def test_node_ssh_with_command():
    leader_hostname = mesos.DCOSClient().get_state_summary()['hostname']
    _node_ssh(['--leader', '--master-proxy', '/opt/mesosphere/bin/detect_ip'],
              0, leader_hostname)