Example #1
0
def _dcos_log(follow, lines, leader, slave, component, filters):
    """ Print logs from dcos-log backend.

    :param follow: same as unix tail's -f
    :type follow: bool
    :param lines: number of lines to print
    :type lines: int
    :param leader: whether to print the leading master's log
    :type leader: bool
    :param slave: the slave ID to print
    :type slave: str | None
    :param component: DC/OS component name
    :type component: string
    :param filters: a list of filters ["key:value", ...]
    :type filters: list
    """
    if not log.dcos_log_enabled():
        raise DCOSException('dcos-log is not supported')

    filter_query = ''
    if component:
        filters.append('_SYSTEMD_UNIT:{}'.format(_get_unit_type(component)))

    for f in filters:
        key_value = f.split(':')
        if len(key_value) != 2:
            raise SystemExit('Invalid filter parameter {}. '
                             'Must be --filter=key:value'.format(f))
        filter_query += '&filter={}'.format(f)

    endpoint = '/system/v1'
    if leader:
        endpoint += '/logs/v1/'
    if slave:
        endpoint += '/agent/{}/logs/v1/'.format(slave)

    endpoint_type = 'range'
    if follow:
        endpoint_type = 'stream'

    dcos_url = config.get_config_val('core.dcos_url').rstrip("/")
    if not dcos_url:
        raise config.missing_config_exception(['core.dcos_url'])

    url = (dcos_url + endpoint + endpoint_type +
           '/?skip_prev={}'.format(lines) + filter_query)

    if follow:
        return log.follow_logs(url)
    return log.print_logs_range(url)
Example #2
0
def _dcos_log(follow, lines, leader, slave, component, filters):
    """ Print logs from dcos-log backend.

    :param follow: same as unix tail's -f
    :type follow: bool
    :param lines: number of lines to print
    :type lines: int
    :param leader: whether to print the leading master's log
    :type leader: bool
    :param slave: the slave ID to print
    :type slave: str | None
    :param component: DC/OS component name
    :type component: string
    :param filters: a list of filters ["key:value", ...]
    :type filters: list
    """

    filter_query = ''
    if component:
        filters.append('_SYSTEMD_UNIT:{}'.format(_get_unit_type(component)))

    for f in filters:
        key_value = f.split(':')
        if len(key_value) != 2:
            raise SystemExit('Invalid filter parameter {}. '
                             'Must be --filter=key:value'.format(f))
        filter_query += '&filter={}'.format(f)

    endpoint = '/system/v1'
    if leader:
        endpoint += _build_leader_url(component)
    elif slave:
        endpoint += '/agent/{}/logs/v1/'.format(slave)

    endpoint_type = 'range'
    if follow:
        endpoint_type = 'stream'

    dcos_url = config.get_config_val('core.dcos_url').rstrip("/")
    if not dcos_url:
        raise config.missing_config_exception(['core.dcos_url'])

    url = (dcos_url + endpoint + endpoint_type +
           '/?skip_prev={}'.format(lines) + filter_query)

    if follow:
        return log.follow_logs(url)
    return log.print_logs_range(url)
Example #3
0
def _dcos_log_v2(follow, lines, leader, slave, component, filters):
    """ Print logs from dcos-log v2 backend.

    :param follow: same as unix tail's -f
    :type follow: bool
    :param lines: number of lines to print
    :type lines: int
    :param leader: whether to print the leading master's log
    :type leader: bool
    :param slave: the slave ID to print
    :type slave: str | None
    :param component: DC/OS component name
    :type component: string
    :param filters: a list of filters ["key:value", ...]
    :type filters: list
    """

    filter_query = ''
    for f in filters:
        key_value = f.split(':')
        if len(key_value) != 2:
            raise DCOSException('Invalid filter parameter {}. '
                                'Must be --filter=key:value'.format(f))
        filter_query += '&filter={}'.format(f)

    endpoint = '/system/v1'
    if leader:
        endpoint += _build_leader_url(component, version=2)
    elif slave:
        endpoint += '/agent/{}/logs/v2/component'.format(slave)
        if component:
            component_with_type = _get_unit_type(component)
            endpoint += '/{}'.format(component_with_type)

    dcos_url = config.get_config_val('core.dcos_url').rstrip("/")
    if not dcos_url:
        raise config.missing_config_exception(['core.dcos_url'])

    # dcos-log v2 required the skip option be a negative integer
    if lines > 0:
        lines *= -1

    url = dcos_url + endpoint + '?skip={}'.format(lines) + filter_query

    if follow:
        return log.follow_logs(url)
    return log.print_logs_range(url)
Example #4
0
def _dcos_log_v2(follow, tasks, lines, file_):
    """ a client to dcos-log v2

    :param follow: same as unix tail's -f
    :type follow: bool
    :param tasks: tasks pattern to match
    :type tasks: list of str
    :param lines: number of lines to print
    :type lines: int
    :param file_: file path to read
    :type file_: str
    """

    if len(tasks) != 1:
        raise DCOSException(
            "found more than one task with the same name: {}. Please provide "
            "a unique task name.".format([task['id'] for task in tasks]))

    task = tasks[0]
    endpoint = '/system/v1/logs/v2/task/{}/file/{}'.format(task['id'], file_)
    dcos_url = config.get_config_val('core.dcos_url').rstrip('/')
    if not dcos_url:
        raise config.missing_config_exception(['core.dcos_url'])

    if lines:
        # according to dcos-log v2 API the skip parameter must be negative
        # integer. dcos-cli uses positive int to limit the number of last lines
        # use "lines * -1" to make it negative.
        if lines > 0:
            lines *= -1

        endpoint += '?cursor=END&skip={}'.format(lines)

    url = dcos_url + endpoint
    if follow:
        return log.follow_logs(url)
    return log.print_logs_range(url)
Example #5
0
def _dcos_log(follow, tasks, lines, file_, completed):
    """ a client to dcos-log

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

    # only stdout and stderr is supported
    if file_ not in ('stdout', 'stderr'):
        raise DCOSException('Expect file stdout or stderr. '
                            'Got {}'.format(file_))
    # state json may container tasks and completed_tasks fields. Based on
    # user request we should traverse the appropriate field.
    tasks_field = 'tasks'
    if completed:
        tasks_field = 'completed_tasks'

    for task in tasks:
        executor_info = task.executor()
        if not executor_info:
            continue
        if (tasks_field not in executor_info and
                not isinstance(executor_info[tasks_field], list)):
            logger.debug('Executor info: {}'.format(executor_info))
            raise DCOSException('Invalid executor info. '
                                'Missing field {}'.format(tasks_field))

        for t in executor_info[tasks_field]:
            container_id = get_nested_container_id(t)
            if not container_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing container id')

            # get slave_id field
            slave_id = t.get('slave_id')
            if not slave_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing field `slave_id`')

            framework_id = t.get('framework_id')
            if not framework_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing field `framework_id`')

            # try `executor_id` first.
            executor_id = t.get('executor_id')
            if not executor_id:
                # if `executor_id` is an empty string, default to `id`.
                executor_id = t.get('id')
            if not executor_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing executor id')

            dcos_url = config.get_config_val('core.dcos_url').rstrip('/')
            if not dcos_url:
                raise config.missing_config_exception(['core.dcos_url'])

            # dcos-log provides 2 base endpoints /range/ and /stream/
            # for range and streaming requests.
            endpoint_type = 'range'
            if follow:
                endpoint_type = 'stream'

            endpoint = ('/system/v1/agent/{}/logs/v1/{}/framework/{}'
                        '/executor/{}/container/{}'.format(slave_id,
                                                           endpoint_type,
                                                           framework_id,
                                                           executor_id,
                                                           container_id))
            # append request parameters.
            # `skip_prev` will move the cursor to -n lines.
            # `filter=STREAM:{STDOUT,STDERR}` will filter logs by label.
            url = (dcos_url + endpoint +
                   '?skip_prev={}&filter=STREAM:{}'.format(lines,
                                                           file_.upper()))

            if follow:
                return log.follow_logs(url)
            return log.print_logs_range(url)
Example #6
0
def _dcos_log(follow, tasks, lines, file_, completed):
    """ a client to dcos-log

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

    # only stdout and stderr is supported
    if file_ not in ('stdout', 'stderr'):
        raise DCOSException('Expect file stdout or stderr. '
                            'Got {}'.format(file_))
    # state json may container tasks and completed_tasks fields. Based on
    # user request we should traverse the appropriate field.
    tasks_field = 'tasks'
    if completed:
        tasks_field = 'completed_tasks'

    for task in tasks:
        executor_info = task.executor()
        if not executor_info:
            continue
        if (tasks_field not in executor_info and
                not isinstance(executor_info[tasks_field], list)):
            logger.debug('Executor info: {}'.format(executor_info))
            raise DCOSException('Invalid executor info. '
                                'Missing field {}'.format(tasks_field))

        for t in executor_info[tasks_field]:
            container_id = get_nested_container_id(t)
            if not container_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing container id')

            # get slave_id field
            slave_id = t.get('slave_id')
            if not slave_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing field `slave_id`')

            framework_id = t.get('framework_id')
            if not framework_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing field `framework_id`')

            # try `executor_id` first.
            executor_id = t.get('executor_id')
            if not executor_id:
                # if `executor_id` is an empty string, default to `id`.
                executor_id = t.get('id')
            if not executor_id:
                logger.debug('Executor info: {}'.format(executor_info))
                raise DCOSException(
                    'Invalid executor info. Missing executor id')

            dcos_url = config.get_config_val('core.dcos_url').rstrip('/')
            if not dcos_url:
                raise config.missing_config_exception(['core.dcos_url'])

            # dcos-log provides 2 base endpoints /range/ and /stream/
            # for range and streaming requests.
            endpoint_type = 'range'
            if follow:
                endpoint_type = 'stream'

            endpoint = ('/system/v1/agent/{}/logs/v1/{}/framework/{}'
                        '/executor/{}/container/{}'.format(slave_id,
                                                           endpoint_type,
                                                           framework_id,
                                                           executor_id,
                                                           container_id))
            # append request parameters.
            # `skip_prev` will move the cursor to -n lines.
            # `filter=STREAM:{STDOUT,STDERR}` will filter logs by label.
            url = (dcos_url + endpoint +
                   '?skip_prev={}&filter=STREAM:{}'.format(lines,
                                                           file_.upper()))

            if follow:
                return log.follow_logs(url)
            return log.print_logs_range(url)