Exemple #1
0
def _get_dcos_auth(auth_scheme, username, password, hostname):
    """Get authentication flow for dcos acs auth and dcos oauth

    :param auth_scheme: authentication_scheme
    :type auth_scheme: str
    :param username: username user for authentication
    :type username: str
    :param password: password for authentication
    :type password: str
    :param hostname: hostname for credentials
    :type hostname: str
    :returns: DCOSAcsAuth
    :rtype: AuthBase
    """

    toml_config = config.get_config()
    token = config.get_config_val("core.dcos_acs_token", toml_config)
    if token is None:
        dcos_url = config.get_config_val("core.dcos_url", toml_config)
        if auth_scheme == "acsjwt":
            creds = _get_dcos_acs_auth_creds(username, password, hostname)
        else:
            creds = _get_dcos_oauth_creds(dcos_url)

        url = urllib.parse.urljoin(dcos_url, 'acs/api/v1/auth/login')
        response = _request('post', url, json=creds)

        if response.status_code == 200:
            token = response.json()['token']
            config.set_val("core.dcos_acs_token", token)

    return DCOSAcsAuth(token)
Exemple #2
0
def _is_request_to_dcos(url, toml_config=None):
    """Checks if a request is for the DC/OS cluster.

    :param url: URL of the request
    :type url: str
    :param toml_config: cluster config to use
    :type toml_config: Toml
    :return: whether the request is for the cluster
    :rtype: bool
    """

    if toml_config is None:
        toml_config = config.get_config()

    dcos_url = urlparse(config.get_config_val("core.dcos_url", toml_config))
    cosmos_url = urlparse(
        config.get_config_val("package.cosmos_url", toml_config))
    parsed_url = urlparse(url)

    # request should match scheme + netloc
    def _request_match(expected_url, actual_url):
        return expected_url.scheme == actual_url.scheme and \
                    expected_url.netloc == actual_url.netloc

    is_request_to_cluster = _request_match(dcos_url, parsed_url) or \
        _request_match(cosmos_url, parsed_url)

    return is_request_to_cluster
Exemple #3
0
def request(method,
            url,
            is_success=_default_is_success,
            timeout=None,
            verify=None,
            **kwargs):
    """Sends an HTTP request. If the server responds with a 401, ask the
    user for their credentials, and try request again (up to 3 times).

    :param method: method for the new Request object
    :type method: str
    :param url: URL for the new Request object
    :type url: str
    :param is_success: Defines successful status codes for the request
    :type is_success: Function from int to bool
    :param timeout: request timeout
    :type timeout: int
    :param verify: whether to verify SSL certs or path to cert(s)
    :type verify: bool | str
    :param kwargs: Additional arguments to requests.request
        (see http://docs.python-requests.org/en/latest/api/#requests.request)
    :type kwargs: dict
    :rtype: Response
    """

    toml_config = config.get_config()
    auth_token = config.get_config_val("core.dcos_acs_token", toml_config)
    dcos_url = urlparse(config.get_config_val("core.dcos_url", toml_config))
    parsed_url = urlparse(url)

    # only request with DC/OS Auth if request is to DC/OS cluster
    # request should match scheme + netloc
    scheme_eq = parsed_url.scheme == dcos_url.scheme
    netloc_eq = parsed_url.netloc == dcos_url.netloc
    if auth_token and scheme_eq and netloc_eq:
        auth = DCOSAcsAuth(auth_token)
    else:
        auth = None
    response = _request(method, url, is_success, timeout,
                        auth=auth, verify=verify, **kwargs)

    if is_success(response.status_code):
        return response
    elif response.status_code == 401:
        if auth_token is not None:
            msg = ("Your core.dcos_acs_token is invalid. "
                   "Please run: `dcos auth login`")
            raise DCOSAuthenticationException(msg)
        else:
            raise DCOSAuthenticationException(response)
    elif response.status_code == 422:
        raise DCOSUnprocessableException(response)
    elif response.status_code == 403:
        raise DCOSAuthorizationException(response)
    elif response.status_code == 400:
        raise DCOSBadRequest(response)
    else:
        raise DCOSHTTPException(response)
Exemple #4
0
    def __init__(self):
        toml_config = config.get_config()

        self._dcos_url = config.get_config_val("core.dcos_url", toml_config)
        if self._dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        self._mesos_master_url = config.get_config_val(
            'core.mesos_master_url', toml_config)

        self._timeout = config.get_config_val('core.timeout', toml_config)
Exemple #5
0
    def __init__(self):
        toml_config = config.get_config()

        self._dcos_url = config.get_config_val("core.dcos_url", toml_config)
        if self._dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        self._mesos_master_url = config.get_config_val('core.mesos_master_url',
                                                       toml_config)

        self._timeout = config.get_config_val('core.timeout', toml_config)
Exemple #6
0
def get_cosmos_url():
    """
    :returns: cosmos base url
    :rtype: str
    """
    toml_config = config.get_config()
    cosmos_url = config.get_config_val("package.cosmos_url", toml_config)
    if cosmos_url is None:
        cosmos_url = config.get_config_val("core.dcos_url", toml_config)
        if cosmos_url is None:
            raise config.missing_config_exception(["core.dcos_url"])
    return cosmos_url
Exemple #7
0
def get_cosmos_url():
    """
    :returns: cosmos base url
    :rtype: str
    """
    toml_config = config.get_config()
    cosmos_url = config.get_config_val("package.cosmos_url", toml_config)
    if cosmos_url is None:
        cosmos_url = config.get_config_val("core.dcos_url", toml_config)
        if cosmos_url is None:
            raise config.missing_config_exception(["core.dcos_url"])
    return cosmos_url
Exemple #8
0
def get_cosmos_url():
    """
    Gets the cosmos url

    :returns: cosmos base url
    :rtype: str
    """
    toml_config = config.get_config()
    cosmos_url = config.get_config_val('package.cosmos_url', toml_config)
    if cosmos_url is None:
        cosmos_url = config.get_config_val('core.dcos_url', toml_config)
        if cosmos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
    return cosmos_url
Exemple #9
0
def get_cosmos_url():
    """
    Gets the cosmos url

    :returns: cosmos base url
    :rtype: str
    """
    toml_config = config.get_config()
    cosmos_url = config.get_config_val('package.cosmos_url', toml_config)
    if cosmos_url is None:
        cosmos_url = config.get_config_val('core.dcos_url', toml_config)
        if cosmos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
    return cosmos_url
Exemple #10
0
def _do_request(url, method, timeout=None, stream=False, **kwargs):
    """
    make HTTP request

    :param url: url
    :type url: string
    :param method: HTTP method, GET or POST
    :type  method: string
    :param timeout: HTTP request timeout, default 3 seconds
    :type  timeout: integer
    :param stream: stream parameter for requests lib
    :type  stream: bool
    :return: http response
    :rtype: requests.Response
    """
    def _is_success(status_code):
        # consider 400 and 503 to be successful status codes.
        # API will return the error message.
        if status_code in [200, 400, 503]:
            return True
        return False

    # if timeout is not passed, try to read `core.timeout`
    # if `core.timeout` is not set, default to 3 min.
    if timeout is None:
        timeout = config.get_config_val('core.timeout')
        if not timeout:
            timeout = 180

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

    url = urllib.parse.urljoin(base_url, url)
    if method.lower() == 'get':
        http_response = http.get(url,
                                 is_success=_is_success,
                                 timeout=timeout,
                                 **kwargs)
    elif method.lower() == 'post':
        http_response = http.post(url,
                                  is_success=_is_success,
                                  timeout=timeout,
                                  stream=stream,
                                  **kwargs)
    else:
        raise DCOSException('Unsupported HTTP method: ' + method)
    return http_response
Exemple #11
0
    def overlay_info(self):
        # XXX This methodology is copied from the dcos.mesos package, this can
        # be removed once the upstream package has support for this field.

        url = self.dcos_client.master_url('overlay-agent/overlay')
        timeout = dcosconfig.get_config_val('core.timeout', dcosconfig.get_config())
        return dcoshttp.get(url, timeout=timeout).json()
Exemple #12
0
def get_arangodb_framework(name):
    url = config.get_config_val('core.dcos_url') + "/mesos/state.json"
    try:
        response = http.get(url, timeout=15)
    except DCOSException as e:
        print("cannot connect to '" + url + "'", e)
        sys.exit(1)

    if response.status_code >= 200 and response.status_code < 300:
        json = response.json()

        if 'frameworks' not in json:
            print(json)
            sys.exit(1)

        frameworks = json['frameworks']

        for framework in frameworks:
            if name == framework['name']:
                return framework

        print("ArangoDB framework '" + name + "' is not running yet.")
        sys.exit(1)
    else:
        print("Bad response getting master state. Status code: "
              + str(response.status_code))
        sys.exit(1)
def get_ssh_user(ssh_config_file, user):
    """Returns the SSH user name to use accessing cluster nodes. If an ssh
    config file provided, expects the username to be specified in the
    file and ignores any provided username. Username resolution
    follows this logic, use any username explicitly provided, else use
    the one in dcos cli config, else use default ssh user from constants.

    :param ssh_config_file: SSH options
    :type ssh_config_file: [str]
    :param user: SSH user
    :type user: str | None
    :rtype: str | None

    """

    if ssh_config_file:
        return None

    if user:
        return user

    dcos_config_ssh_user = config.get_config_val("core.ssh_user")
    if dcos_config_ssh_user:
        return dcos_config_ssh_user

    return constants.DEFAULT_SSH_USER
Exemple #14
0
def print_components(ip, use_json):
    """ Print components for a given node ip.
        The data is taked from 3dt endpoint:
        /system/health/v1/nodes/<ip>/units

    :param ip: DC/OS node ip address
    :type ip: str
    :param use_json: print components in json format
    :type use_json: bool
    """
    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 + '/system/health/v1/nodes/{}/units'.format(ip)
    response = http.get(url).json()
    if 'units' not in response:
        raise DCOSException(
            'Invalid response. Missing field `units`. {}'.format(response))

    if use_json:
        emitter.publish(response['units'])
    else:
        for component in response['units']:
            emitter.publish(component['id'])
Exemple #15
0
def _metrics(summary, task_id, json_):
    """
    Get metrics from the specified task.

    :param summary: summarise output if true, output all if false
    :type summary: bool
    :param task_id: mesos task id
    :type task_id: str
    :param json: print raw JSON
    :type json: bool
    :return: Process status
    :rtype: int
    """

    master = mesos.get_master()
    task = master.task(task_id)
    if 'slave_id' not in task:
        raise DCOSException(
            'Error finding agent associated with task: {}'.format(task_id))

    slave_id = task['slave_id']
    container_id = master.get_container_id(task_id)

    endpoint = '/system/v1/agent/{}/metrics/v0/containers/{}'.format(
        slave_id, container_id
    )
    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
    app_url = url + '/app'
    return metrics.print_task_metrics(url, app_url, summary, json_)
Exemple #16
0
def _get_default_base_url():
    """
    Gets the default service manager URL

    :returns: cosmos base url
    :rtype: str
    """
    toml_config = config.get_config()
    base_url = config.get_config_val('package.cosmos_url', toml_config)
    if base_url is None:
        base_url = config.get_config_val('core.dcos_url', toml_config)
        if base_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        else:
            base_url = urllib.parse.urljoin(base_url, 'cosmos/')
    return base_url
Exemple #17
0
def print_components(ip, use_json):
    """ Print components for a given node ip.
        The data is taked from 3dt endpoint:
        /system/health/v1/nodes/<ip>/units

    :param ip: DC/OS node ip address
    :type ip: str
    :param use_json: print components in json format
    :type use_json: bool
    """
    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 + '/system/health/v1/nodes/{}/units'.format(ip)
    response = http.get(url).json()
    if 'units' not in response:
        raise DCOSException(
            'Invalid response. Missing field `units`. {}'.format(response))

    if use_json:
        emitter.publish(response['units'])
    else:
        for component in response['units']:
            emitter.publish(component['id'])
Exemple #18
0
def logging_strategy():
    """ function returns logging strategy

    :return: logging strategy.
    :rtype: str
    """
    # default strategy is sandbox logging.
    strategy = 'logrotate'

    if not has_journald_capability():
        return strategy

    base_url = config.get_config_val("core.dcos_url")
    url = urllib.parse.urljoin(base_url, '/dcos-metadata/ui-config.json')

    if not base_url:
        raise config.missing_config_exception(['core.dcos_url'])

    try:
        response = http.get(url).json()
    except (DCOSAuthenticationException, DCOSAuthorizationException):
        raise
    except DCOSException:
        emitter.publish('Unable to determine logging mechanism for '
                        'your cluster. Defaulting to files API.')
        return strategy

    try:
        strategy = response['uiConfiguration']['plugins']['mesos'][
            'logging-strategy']  # noqa: ignore=F403,E501
    except Exception:
        pass

    return strategy
Exemple #19
0
def _main():
    signal.signal(signal.SIGINT, signal_handler)

    http.silence_requests_warnings()

    args = docopt.docopt(default_doc("dcos"), 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['--version']:
        return _get_versions(config.get_config_val("core.dcos_url"))

    command = args['<command>']

    if not command:
        command = "help"

    if command in subcommand.default_subcommands():
        sc = SubcommandMain(command, args['<args>'])
    else:
        executable = subcommand.command_executables(command)
        sc = subcommand.SubcommandProcess(
            executable, command, args['<args>'])

    exitcode, _ = sc.run_and_capture()
    return exitcode
Exemple #20
0
def _metrics(summary, task_id, json_):
    """
    Get metrics from the specified task.

    :param summary: summarise output if true, output all if false
    :type summary: bool
    :param task_id: mesos task id
    :type task_id: str
    :param json: print raw JSON
    :type json: bool
    :return: Process status
    :rtype: int
    """

    master = mesos.get_master()
    task = master.task(task_id)
    if 'slave_id' not in task:
        raise DCOSException(
            'Error finding agent associated with task: {}'.format(task_id))

    slave_id = task['slave_id']
    container_id = master.get_container_id(task_id)

    endpoint = '/system/v1/agent/{}/metrics/v0/containers/{}'.format(
        slave_id, container_id)
    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
    app_url = url + '/app'
    return metrics.print_task_metrics(url, app_url, summary, json_)
    def __init__(self, toml_config: Optional[Any] = None):
        super(DCOSClient, self).__init__()
        self.toml_config = toml_config
        if toml_config is None:
            self.toml_config = config.get_config()

        self._dcos_url = cast(ParseResult, urlparse(config.get_config_val("core.dcos_url", toml_config)))
Exemple #22
0
def _login():
    """
    :returns: process status
    :rtype: int
    """

    # every call to login will generate a new token if applicable
    _logout()
    dcos_url = config.get_config_val("core.dcos_url")
    if dcos_url is None:
        msg = ("Please provide the url to your DC/OS cluster: "
               "`dcos config set core.dcos_url`")
        raise DCOSException(msg)

    # hit protected endpoint which will prompt for auth if cluster has auth
    try:
        url = urllib.parse.urljoin(dcos_url, 'exhibitor')
        http.get(url)
    # if the user is authenticated, they have effectively "logged in" even if
    # they are not authorized for this endpoint
    except DCOSAuthorizationException:
        pass

    emitter.publish("Login successful!")
    return 0
Exemple #23
0
def _page(output, pager_command=None):
    """Conditionally pipes the supplied output through a pager.

    :param output:
    :type output: object
    :param pager_command:
    :type pager_command: str
    """

    output = six.text_type(output)

    if not sys.stdout.isatty() or util.is_windows_platform():
        print(output)
        return

    num_lines = output.count('\n')
    exceeds_tty_height = pager.getheight() - 1 < num_lines

    if pager_command is None:
        pager_command = 'less -R'

    paginate = config.get_config_val("core.pagination") or True
    if exceeds_tty_height and paginate and \
            spawn.find_executable(pager_command.split(' ')[0]) is not None:
        pydoc.pipepager(output, cmd=pager_command)
    else:
        print(output)
Exemple #24
0
def _verify_ssl(url, verify=None, toml_config=None):
    """Returns whether to verify ssl for the given url

    :param url: the target URL
    :type url: str
    :param verify: whether to verify SSL certs or path to cert(s)
    :type verify: bool | str
    :param toml_config: cluster config to use
    :type toml_config: Toml
    :return: whether to verify SSL certs or path to cert(s)
    :rtype: bool | str
    """

    if not _is_request_to_dcos(url, toml_config):
        # Leave verify to None if URL is outside the DC/OS cluster
        # https://jira.mesosphere.com/browse/DCOS_OSS-618
        return None

    if toml_config is None:
        toml_config = config.get_config()

    if verify is None:
        verify = config.get_config_val("core.ssl_verify", toml_config)
        if verify and verify.lower() == "true":
            verify = True
        elif verify and verify.lower() == "false":
            verify = False

    return verify
Exemple #25
0
def _main():
    signal.signal(signal.SIGINT, signal_handler)

    http.silence_requests_warnings()

    args = docopt.docopt(default_doc("dcos"), 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['--version']:
        return _get_versions(config.get_config_val("core.dcos_url"))

    command = args['<command>']

    if not command:
        if args['--help']:
            command = "help"
        else:
            return dcos_help()

    if command in subcommand.default_subcommands():
        sc = SubcommandMain(command, args['<args>'])
    else:
        executable = subcommand.command_executables(command)
        sc = subcommand.SubcommandProcess(executable, command, args['<args>'])

    exitcode, _ = sc.run_and_capture()
    return exitcode
Exemple #26
0
def _get_marathon_url(toml_config):
    """
    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: marathon base url
    :rtype: str
    """

    marathon_url = config.get_config_val('marathon.url', toml_config)
    if marathon_url is None:
        dcos_url = config.get_config_val('core.dcos_url', toml_config)
        if dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        marathon_url = urllib.parse.urljoin(dcos_url, 'service/marathon/')

    return marathon_url
Exemple #27
0
def _get_marathon_url(toml_config):
    """
    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: marathon base url
    :rtype: str
    """

    marathon_url = config.get_config_val('marathon.url', toml_config)
    if marathon_url is None:
        dcos_url = config.get_config_val('core.dcos_url', toml_config)
        if dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        marathon_url = urllib.parse.urljoin(dcos_url, 'service/marathon/')

    return marathon_url
Exemple #28
0
def _page(output, pager_command=None):
    """Conditionally pipes the supplied output through a pager.

    :param output:
    :type output: object
    :param pager_command:
    :type pager_command: str
    """

    output = six.text_type(output)

    if not sys.stdout.isatty() or util.is_windows_platform():
        print(output)
        sys.stdout.flush()
        return

    num_lines = output.count('\n')
    exceeds_tty_height = pager.getheight() - 1 < num_lines

    if pager_command is None:
        pager_command = 'less -R'

    try:
        paginate = config.get_config_val("core.pagination")
    except Exception:
        paginate = True
    if exceeds_tty_height and paginate and \
            spawn.find_executable(pager_command.split(' ')[0]) is not None:
        pydoc.pipepager(output, cmd=pager_command)
    else:
        print(output)
def _get_default_base_url():
    """
    Gets the default service manager URL

    :returns: cosmos base url
    :rtype: str
    """
    toml_config = config.get_config()
    base_url = config.get_config_val('package.cosmos_url', toml_config)
    if base_url is None:
        base_url = config.get_config_val('core.dcos_url', toml_config)
        if base_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        else:
            base_url = urllib.parse.urljoin(base_url, 'cosmos/')
    return base_url
Exemple #30
0
def _login(password_str, password_env, password_file, provider, username,
           key_path):
    """
    :param password_str: password
    :type password_str: str
    :param password_env: name of environment variable with password
    :type password_env: str
    :param password_file: path to file with password
    :type password_file: bool
    :param provider: name of provider to authentication with
    :type provider: str
    :param username: username
    :type username: str
    :param key_path: path to file with private key
    :type param: str
    :rtype: int
    """

    dcos_url = config.get_config_val("core.dcos_url")
    if dcos_url is None:
        msg = ("Please provide the url to your DC/OS cluster: "
               "`dcos config set core.dcos_url`")
        raise DCOSException(msg)

    # every call to login will generate a new token if applicable
    _logout()

    login(dcos_url, password_str, password_env, password_file, provider,
          username, key_path)

    emitter.publish("Login successful!")
    return 0
Exemple #31
0
def _unlink(name):
    """
    Unlink a DC/OS cluster.

    :param name: ID or name of the cluster
    :type name: str
    :returns: process status
    :rtype: int
    """

    c = cluster.get_cluster(name)
    if c:
        name = c.get_cluster_id()

    dcos_url = config.get_config_val('core.dcos_url')
    endpoint = urllib.parse.urljoin(dcos_url, '/cluster/v1/links/' + name)

    try:
        http.delete(endpoint)
    except DCOSHTTPException as e:
        if e.status() == 404:
            raise DCOSException('Unknown cluster link {}.'.format(name))
        raise

    return 0
Exemple #32
0
    def overlay_info(self):
        # XXX This methodology is copied from the dcos.mesos package, this can
        # be removed once the upstream package has support for this field.

        url = self.dcos_client.master_url('overlay-agent/overlay')
        timeout = dcosconfig.get_config_val('core.timeout',
                                            dcosconfig.get_config())
        return dcoshttp.get(url, timeout=timeout).json()
Exemple #33
0
def _do_request(url, method, timeout=None, stream=False, **kwargs):
    """
    make HTTP request

    :param url: url
    :type url: string
    :param method: HTTP method, GET or POST
    :type  method: string
    :param timeout: HTTP request timeout, default 3 seconds
    :type  timeout: integer
    :param stream: stream parameter for requests lib
    :type  stream: bool
    :return: http response
    :rtype: requests.Response
    """

    def _is_success(status_code):
        # consider 400 and 503 to be successful status codes.
        # API will return the error message.
        if status_code in [200, 400, 503]:
            return True
        return False

    # if timeout is not passed, try to read `core.timeout`
    # if `core.timeout` is not set, default to 3 min.
    if timeout is None:
        timeout = config.get_config_val('core.timeout')
        if not timeout:
            timeout = 180

    # POST to snapshot api
    base_url = config.get_config_val("core.dcos_url")
    if not base_url:
        raise config.missing_config_exception(['core.dcos_url'])

    url = urllib.parse.urljoin(base_url, url)
    if method.lower() == 'get':
        http_response = http.get(url, is_success=_is_success, timeout=timeout,
                                 **kwargs)
    elif method.lower() == 'post':
        http_response = http.post(url, is_success=_is_success, timeout=timeout,
                                  stream=stream, **kwargs)
    else:
        raise DCOSException('Unsupported HTTP method: ' + method)
    return http_response
Exemple #34
0
def update_marathon_client():
    global client
    global toml_config_o
    toml_config_o = config.get_config()
    dcos_url = config.get_config_val('core.dcos_url', toml_config_o)
    marathon_url = urllib.parse.urljoin(dcos_url, 'service/marathon-user/')
    config.set_val('marathon.url', marathon_url)
    toml_config_m = config.get_config()
    client = marathon.create_client(toml_config_m)
Exemple #35
0
def setup_env(env):
    # token will be removed when we change dcos_url
    token = config.get_config_val('core.dcos_acs_token')
    config_set("core.dcos_url", "https://dcos.snakeoil.mesosphere.com", env)
    config_set("core.dcos_acs_token", token, env)
    try:
        yield
    finally:
        config_set("core.dcos_url", "http://dcos.snakeoil.mesosphere.com", env)
        config_set("core.dcos_acs_token", token, env)
Exemple #36
0
def setup_env(env):
    # token will be removed when we change dcos_url
    token = config.get_config_val('core.dcos_acs_token')
    config_set("core.dcos_url", "https://dcos.snakeoil.mesosphere.com", env)
    config_set("core.dcos_acs_token", token, env)
    try:
        yield
    finally:
        config_set("core.dcos_url", "http://dcos.snakeoil.mesosphere.com", env)
        config_set("core.dcos_acs_token", token, env)
Exemple #37
0
def _request_with_auth(response,
                       method,
                       url,
                       is_success=_default_is_success,
                       timeout=None,
                       verify=None,
                       **kwargs):
    """Request with credentials

    :param response: requests.response
    :type response: requests.Response
    :param method: method for the new Request object
    :type method: str
    :param url: URL for the new Request object
    :type url: str
    :param is_success: Defines successful status codes for the request
    :type is_success: Function from int to bool
    :param timeout: request timeout
    :type timeout: int
    :param verify: whether to verify SSL certs or path to cert(s)
    :type verify: bool | str
    :param kwargs: Additional arguments to requests.request
        (see http://docs.python-requests.org/en/latest/api/#requests.request)
    :type kwargs: dict
    :rtype: requests.Response
    """

    parsed_url = urlparse(url)
    hostname = parsed_url.hostname
    auth_scheme, realm = get_auth_scheme(response)
    creds = (hostname, auth_scheme, realm)

    with lock:
        if creds not in AUTH_CREDS:
            auth = _get_http_auth(response, parsed_url, auth_scheme)
        else:
            auth = AUTH_CREDS[creds]

    response = _request(method, url, is_success, timeout, auth,
                        verify, **kwargs)

    # only store credentials if they're valid
    with lock:
        if creds not in AUTH_CREDS and response.status_code == 200:
            AUTH_CREDS[creds] = auth
        # acs invalid token
        elif response.status_code == 401 and \
                auth_scheme in ["acsjwt", "oauthjwt"]:

            if config.get_config_val("core.dcos_acs_token") is not None:
                msg = ("Your core.dcos_acs_token is invalid. "
                       "Please run: `dcos auth login`")
                raise DCOSException(msg)

    return response
Exemple #38
0
def _request_with_auth(response,
                       method,
                       url,
                       is_success=_default_is_success,
                       timeout=None,
                       verify=None,
                       **kwargs):
    """Request with credentials

    :param response: requests.response
    :type response: requests.Response
    :param method: method for the new Request object
    :type method: str
    :param url: URL for the new Request object
    :type url: str
    :param is_success: Defines successful status codes for the request
    :type is_success: Function from int to bool
    :param timeout: request timeout
    :type timeout: int
    :param verify: whether to verify SSL certs or path to cert(s)
    :type verify: bool | str
    :param kwargs: Additional arguments to requests.request
        (see http://docs.python-requests.org/en/latest/api/#requests.request)
    :type kwargs: dict
    :rtype: requests.Response
    """

    parsed_url = urlparse(url)
    hostname = parsed_url.hostname
    auth_scheme, realm = get_auth_scheme(response)
    creds = (hostname, auth_scheme, realm)

    with lock:
        if creds not in AUTH_CREDS:
            auth = _get_http_auth(response, parsed_url, auth_scheme)
        else:
            auth = AUTH_CREDS[creds]

    response = _request(method, url, is_success, timeout, auth, verify,
                        **kwargs)

    # only store credentials if they're valid
    with lock:
        if creds not in AUTH_CREDS and response.status_code == 200:
            AUTH_CREDS[creds] = auth
        # acs invalid token
        elif response.status_code == 401 and \
                auth_scheme in ["acsjwt", "oauthjwt"]:

            if config.get_config_val("core.dcos_acs_token") is not None:
                msg = ("Your core.dcos_acs_token is invalid. "
                       "Please run: `dcos auth login`")
                raise DCOSException(msg)

    return response
Exemple #39
0
def _get_metronome_url(toml_config=None):
    """
    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: metronome base url
    :rtype: str
    """
    if toml_config is None:
        toml_config = config.get_config()

    metronome_url = config.get_config_val('metronome.url', toml_config)
    if metronome_url is None:
        # dcos must be capable to use dcos_url
        _check_capability()
        dcos_url = config.get_config_val('core.dcos_url', toml_config)
        if dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        metronome_url = urllib.parse.urljoin(dcos_url, 'service/metronome/')

    return metronome_url
Exemple #40
0
def test_repo_list():
    repo_list = bytes(("test-universe: {test-universe}\n"
                       "helloworld-universe: {helloworld-universe}\n").format(
                           **UNIVERSE_TEST_REPOS), 'utf-8')

    assert_command(['dcos', 'package', 'repo', 'list'], stdout=repo_list)

    # test again, but override the dcos_url with a cosmos_url config
    dcos_url = config.get_config_val("core.dcos_url")
    with update_config('package.cosmos_url', dcos_url):
        assert_command(['dcos', 'package', 'repo', 'list'], stdout=repo_list)
Exemple #41
0
def _logout():
    """
    Logout the user from dcos acs auth or oauth

    :returns: process status
    :rtype: int
    """

    if config.get_config_val("core.dcos_acs_token") is not None:
        config.unset("core.dcos_acs_token")
    return 0
Exemple #42
0
def _get_metronome_url(toml_config=None):
    """
    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: metronome base url
    :rtype: str
    """
    if toml_config is None:
        toml_config = config.get_config()

    metronome_url = config.get_config_val('metronome.url', toml_config)
    if metronome_url is None:
        # dcos must be capable to use dcos_url
        _check_capability()
        dcos_url = config.get_config_val('core.dcos_url', toml_config)
        if dcos_url is None:
            raise config.missing_config_exception(['core.dcos_url'])
        metronome_url = urllib.parse.urljoin(dcos_url, 'service/metronome/')

    return metronome_url
Exemple #43
0
def test_get_cluster_name_ignore_env():
    with env():
        os.environ['DCOS_CLUSTER_NAME'] = 'fake-name'

        cluster_conf = config.Toml({
            'cluster': {'name': 'real-name'},
        })

        cluster_name = config.get_config_val('cluster.name', cluster_conf)

        assert cluster_name == 'real-name'
Exemple #44
0
def _get_timeout():
    """
    :returns: timout value for API calls
    :rtype: str
    """
    # if timeout is not passed, try to read `core.timeout`
    # if `core.timeout` is not set, default to 3 min.
    timeout = config.get_config_val('core.timeout')
    if not timeout:
        timeout = DEFAULT_TIMEOUT

    return timeout
Exemple #45
0
def _get_timeout():
    """
    :returns: timout value for API calls
    :rtype: str
    """
    # if timeout is not passed, try to read `core.timeout`
    # if `core.timeout` is not set, default to 3 min.
    timeout = config.get_config_val('core.timeout')
    if not timeout:
        timeout = DEFAULT_TIMEOUT

    return timeout
Exemple #46
0
def delete_zk_node(znode):
    """Delete Zookeeper node

    :param znode: znode to delete
    :type znode: str
    :rtype: None
    """

    dcos_url = config.get_config_val('core.dcos_url')
    znode_url = urllib.parse.urljoin(
        dcos_url,
        '/exhibitor/exhibitor/v1/explorer/znode/{}'.format(znode))
    http.delete(znode_url)
Exemple #47
0
def _get_dcos_auth(auth_scheme, username, password, hostname):
    """Get authentication flow for dcos acs auth and dcos oauth

    :param auth_scheme: authentication_scheme
    :type auth_scheme: str
    :param username: username user for authentication
    :type username: str
    :param password: password for authentication
    :type password: str
    :param hostname: hostname for credentials
    :type hostname: str
    :returns: DCOSAcsAuth
    :rtype: AuthBase
    """

    toml_config = config.get_config()
    token = config.get_config_val("core.dcos_acs_token", toml_config)
    if token is None:
        dcos_url = config.get_config_val("core.dcos_url", toml_config)
        if auth_scheme == "acsjwt":
            creds = _get_dcos_acs_auth_creds(username, password, hostname)
        else:
            creds = _get_dcos_oauth_creds(dcos_url)

        verify = _verify_ssl()
        # Silence 'Unverified HTTPS request' and 'SecurityWarning' for bad cert
        if verify is not None:
            silence_requests_warnings()

        url = urllib.parse.urljoin(dcos_url, 'acs/api/v1/auth/login')
        # using private method here, so we don't retry on this request
        # error here will be bubbled up to _request_with_auth
        response = _request('post', url, json=creds, verify=verify)

        if response.status_code == 200:
            token = response.json()['token']
            config.set_val("core.dcos_acs_token", token)

    return DCOSAcsAuth(token)
Exemple #48
0
def request(method,
            url,
            is_success=_default_is_success,
            timeout=None,
            verify=None,
            **kwargs):
    """Sends an HTTP request. If the server responds with a 401, ask the
    user for their credentials, and try request again (up to 3 times).

    :param method: method for the new Request object
    :type method: str
    :param url: URL for the new Request object
    :type url: str
    :param is_success: Defines successful status codes for the request
    :type is_success: Function from int to bool
    :param timeout: request timeout
    :type timeout: int
    :param verify: whether to verify SSL certs or path to cert(s)
    :type verify: bool | str
    :param kwargs: Additional arguments to requests.request
        (see http://docs.python-requests.org/en/latest/api/#requests.request)
    :type kwargs: dict
    :rtype: Response
    """

    auth_token = config.get_config_val(
        "core.dcos_acs_token", config.get_config())
    if auth_token is None:
        auth = None
    else:
        auth = DCOSAcsAuth(auth_token)
    response = _request(method, url, is_success, timeout,
                        auth=auth, verify=verify, **kwargs)

    if is_success(response.status_code):
        return response
    elif response.status_code == 401:
        if auth_token is not None:
            msg = ("Your core.dcos_acs_token is invalid. "
                   "Please run: `dcos auth login`")
            raise DCOSException(msg)
        else:
            raise DCOSAuthenticationException(response)
    elif response.status_code == 422:
        raise DCOSUnprocessableException(response)
    elif response.status_code == 403:
        raise DCOSAuthorizationException(response)
    elif response.status_code == 400:
        raise DCOSBadRequest(response)
    else:
        raise DCOSHTTPException(response)
Exemple #49
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)
Exemple #50
0
def create_client(toml_config=None):
    """Creates a Marathon client with the supplied configuration.

    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: Marathon client
    :rtype: dcos.marathon.Client
    """

    if toml_config is None:
        toml_config = config.get_config()

    marathon_url = _get_marathon_url(toml_config)
    timeout = config.get_config_val('core.timeout') or http.DEFAULT_TIMEOUT

    logger.info('Creating marathon client with: %r', marathon_url)
    return Client(marathon_url, timeout=timeout)
Exemple #51
0
def _verify_ssl(verify=None):
    """Returns whether to verify ssl

    :param verify: whether to verify SSL certs or path to cert(s)
    :type verify: bool | str
    :return: whether to verify SSL certs or path to cert(s)
    :rtype: bool | str
    """

    if verify is None:
        verify = config.get_config_val("core.ssl_verify")
        if verify and verify.lower() == "true":
            verify = True
        elif verify and verify.lower() == "false":
            verify = False

    return verify
Exemple #52
0
def marathon_on_marathon(name='marathon-user'):
    """ Context manager for altering the marathon client for MoM
    :param name: service name of MoM to use
    :type name: str
    """

    toml_config_o = config.get_config()
    dcos_url = config.get_config_val('core.dcos_url', toml_config_o)
    service_name = 'service/{}/'.format(name)
    marathon_url = urllib.parse.urljoin(dcos_url, service_name)
    config.set_val('marathon.url', marathon_url)

    try:
        yield
    finally:
        # return config to previous state
        config.save(toml_config_o)
Exemple #53
0
def create_client(toml_config=None):
    """Creates a Metronome client with the supplied configuration.

    :param toml_config: configuration dictionary
    :type toml_config: config.Toml
    :returns: Metronome client
    :rtype: dcos.metronome.Client
    """

    if toml_config is None:
        toml_config = config.get_config()

    metronome_url = _get_metronome_url(toml_config)
    timeout = config.get_config_val('core.timeout') or http.DEFAULT_TIMEOUT
    rpc_client = rpcclient.create_client(metronome_url, timeout)

    logger.info('Creating metronome client with: %r', metronome_url)
    return Client(rpc_client)
Exemple #54
0
def _metrics(summary, mesos_id, json_):
    """ Get metrics from the specified agent.

    :param summary: summarise output if true, output all if false
    :type summary: bool
    :param mesos_id: mesos node id
    :type mesos_id: str
    :param json_: print raw JSON
    :type json_: bool
    :returns: Process status
    :rtype: int
    """

    endpoint = '/system/v1/agent/{}/metrics/v0/node'.format(mesos_id)

    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
    return metrics.print_node_metrics(url, summary, json_)
Exemple #55
0
def get_providers():
    """
    Returns dict of providers configured on cluster

    :returns: configured providers
    :rtype: {}
    """

    dcos_url = config.get_config_val("core.dcos_url").rstrip('/')
    endpoint = '/acs/api/v1/auth/providers'
    url = urllib.parse.urljoin(dcos_url, endpoint)
    try:
        providers = http.get(url)
        return providers.json()
    # this endpoint should only have authentication in DC/OS 1.8
    except DCOSAuthenticationException:
        msg = "This command is not supported for your cluster"
        raise DCOSException(msg)
    except DCOSHTTPException as e:
        if e.response.status_code == 404:
            msg = "This command is not supported for your cluster"
            raise DCOSException(msg)

    return {}
Exemple #56
0
 def __init__(self, url=None):
     self.url = url or urllib.parse.urljoin(
         config.get_config_val('core.dcos_url'), '/mesos_dns/')
Exemple #57
0
def run(_args=[], configure_logging=True):
    # If we're being invoked via DC/OS then route our http
    # calls via its extension to the requests library. In
    # addition remove the 'conduct-dcos' and 'conduct' arg so that the conduct
    # sub-commands are positioned correctly, along with their
    # arguments.
    if sys.argv and Path(sys.argv[0]).name == constants.DCOS_COMMAND_PREFIX + 'conduct':
        dcos_mode = True
        _args = sys.argv[2:]
    else:
        dcos_mode = False
        if not _args:
            # Remove the 'conduct' arg so that we start with the sub command directly
            _args = sys.argv[1:]
    # Parse arguments
    parser = build_parser(dcos_mode)
    argcomplete.autocomplete(parser)
    args = parser.parse_args(_args)
    args.dcos_mode = dcos_mode
    if not vars(args).get('func'):
        if vars(args).get('dcos_info'):
            print('Lightbend ConductR sub commands. Type \'dcos conduct\' to see more.')
            exit(0)
        else:
            parser.print_help()
    else:
        # Offline functions are the functions which do not require network to run, e.g. `conduct version` or
        # `conduct setup-dcos`.
        offline_functions = ['version', 'setup']

        # Only setup network related args (i.e. host, bundle resolvers, basic auth, etc) for functions which requires
        # connectivity to ConductR.
        current_function = vars(args).get('func').__name__
        if current_function not in offline_functions:
            # Add custom plugin dir to import path
            custom_plugins_dir = vars(args).get('custom_plugins_dir')
            if custom_plugins_dir:
                sys.path.append(custom_plugins_dir)

            # DC/OS provides the location of ConductR...
            if dcos_mode:
                args.command = 'dcos conduct'
                dcos_url = urlparse(config.get_config_val('core.dcos_url'))
                args.scheme = dcos_url.scheme
                args.ip = dcos_url.hostname
                default_http_port = 80 if dcos_url.scheme == 'http' else 443
                args.port = dcos_url.port if dcos_url.port else default_http_port
                dcos_url_path = dcos_url.path if dcos_url.path else '/'
                args.base_path = dcos_url_path + 'service/{}/'.format(DEFAULT_DCOS_SERVICE)
            else:
                args.command = 'conduct'

            # Ensure ConductR host is not empty
            host_from_args = conduct_url.conductr_host(args)
            if not host_from_args:
                host_from_env = host.resolve_default_host()
                if host_from_env:
                    args.host = host_from_env
                else:
                    # Configure logging so error message can be logged properly before exiting with failure
                    logging_setup.configure_logging(args)
                    log = logging.getLogger(__name__)
                    log.error('ConductR host address is not specified')
                    log.error('Please ensure either `{}` environment is specified,'
                              ' or specify the ConductR host using `--host` argument'.format(CONDUCTR_HOST))
                    exit(1)
            else:
                args.local_connection = False

            args.cli_parameters = get_cli_parameters(args)
            args.custom_settings = custom_settings.load_from_file(args)

            args.conductr_auth = custom_settings.load_conductr_credentials(args)

            # Ensure HTTPS is used if authentication is configured
            if args.conductr_auth and not args.scheme == 'https':
                # Configure logging so error message can be logged properly before exiting with failure
                logging_setup.configure_logging(args)
                log = logging.getLogger(__name__)
                log.error('Unable to use Basic Auth over {}'.format(args.scheme))
                log.error('Please ensure either `{}` environment is set to `https`,'
                          ' or specify https using `--scheme https` argument'.format(CONDUCTR_SCHEME))
                exit(1)

            args.server_verification_file = custom_settings.load_server_ssl_verification_file(args)
            # Ensure verification file exists if specified
            if args.server_verification_file \
                    and not os.path.exists(args.server_verification_file):
                # Configure logging so error message can be logged properly before exiting with failure
                logging_setup.configure_logging(args)
                log = logging.getLogger(__name__)
                log.error('Ensure server SSL verification file exists: {}'.format(args.server_verification_file))
                exit(1)

            if not args.dcos_mode and args.scheme == 'https':
                disable_urllib3_warnings()

        if configure_logging:
            logging_setup.configure_logging(args)

        is_completed_without_error = args.func(args)
        if not is_completed_without_error:
            exit(1)
Exemple #58
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)