示例#1
0
def events(args):
    """`conduct events` command"""

    log = logging.getLogger(__name__)
    request_url = conduct_url.url('bundles/{}/events?count={}'.format(quote_plus(args.bundle), args.lines), args)
    response = conduct_request.get(args.dcos_mode, conductr_host(args), request_url, auth=args.conductr_auth,
                                   verify=args.server_verification_file, timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    data = [
        {
            'time': validation.format_timestamp(event['timestamp'], args),
            'event': event['event'],
            'description': event['description']
        } for event in json.loads(response.text)
    ]
    data.insert(0, {'time': 'TIME', 'event': 'EVENT', 'description': 'DESC'})

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data), **{'padding': ' ' * padding})

    for row in data:
        log.screen('''\
{time: <{time_width}}{padding}\
{event: <{event_width}}{padding}\
{description: <{description_width}}{padding}'''.format(**dict(row, **column_widths)).rstrip())

    return True
示例#2
0
def events(args):
    """`conduct events` command"""

    log = logging.getLogger(__name__)
    request_url = conduct_url.url(
        'bundles/{}/events?count={}'.format(quote_plus(args.bundle),
                                            args.lines), args)
    response = conduct_request.get(args.dcos_mode,
                                   conductr_host(args),
                                   request_url,
                                   auth=args.conductr_auth,
                                   verify=args.server_verification_file,
                                   timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    data = [{
        'time': validation.format_timestamp(event['timestamp'], args),
        'event': event['event'],
        'description': event['description']
    } for event in json.loads(response.text)]
    data.insert(0, {'time': 'TIME', 'event': 'EVENT', 'description': 'DESC'})

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data),
                         **{'padding': ' ' * padding})

    for row in data:
        log.screen('''\
{time: <{time_width}}{padding}\
{event: <{event_width}}{padding}\
{description: <{description_width}}{padding}'''.format(
            **dict(row, **column_widths)).rstrip())

    return True
示例#3
0
def acls(args):
    """`conduct acls` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode,
                                   conductr_host(args),
                                   url,
                                   timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    def get_system_version(bundle):
        if 'systemVersion' in bundle['attributes']:
            return bundle['attributes']['systemVersion']
        else:
            return bundle['attributes']['system'].split('-')[-1]

    def is_started(bundle_executions):
        for execution in bundle_executions:
            if execution['isStarted']:
                return 'Running'
        return 'Starting'

    all_acls = [{
        'acl':
        acl,
        'system':
        bundle['attributes']['system'],
        'system_version':
        get_system_version(bundle),
        'endpoint_name':
        endpoint_name,
        'bundle_id':
        bundle['bundleId']
        if args.long_ids else bundle_utils.short_id(bundle['bundleId']),
        'bundle_name':
        bundle['attributes']['bundleName'],
        'status':
        is_started(bundle['bundleExecutions'])
    } for bundle in json.loads(response.text) if bundle['bundleExecutions']
                for endpoint_name, endpoint in bundle['bundleConfig']
                ['endpoints'].items() if 'acls' in endpoint
                for acl in endpoint['acls']]

    if args.protocol_family == 'http':
        http_acls = [acl for acl in all_acls if 'http' in acl['acl']]
        display_http_acls(log, http_acls)

    elif args.protocol_family == 'tcp':
        tcp_acls = [acl for acl in all_acls if 'tcp' in acl['acl']]
        display_tcp_acls(log, tcp_acls)

    return True
示例#4
0
def get_deployment_state(deployment_id, args):
    deployment_state_url = conduct_url.url('deployments/{}'.format(deployment_id), args)
    response = conduct_request.get(args.dcos_mode, conduct_url.conductr_host(args), deployment_state_url,
                                   auth=args.conductr_auth, verify=args.server_verification_file)
    if response.status_code == 404:
        return None
    else:
        response.raise_for_status()
        deployment_state = json.loads(response.text)
        return deployment_state
示例#5
0
    def connect(self):
        sse_request_input = dict(SSE_REQUEST_INPUT)
        if self.headers:
            sse_request_input['headers'].update(self.headers)

        kwargs_all = {}
        kwargs_all.update(self.kwargs)
        kwargs_all.update(sse_request_input)

        response = conduct_request.get(self.dcos_mode, self.host, self.url, stream=True, **kwargs_all)
        response.raise_for_status()
        self.responseIter = response.iter_content(decode_unicode=True)
示例#6
0
def wait_for_conductr(args, current_retry, max_retries, interval):
    log = logging.getLogger(__name__)
    last_message = 'Waiting for ConductR to start'
    log.progress(last_message, flush=False)
    for attempt in range(0, max_retries):
        time.sleep(interval)

        last_message = '{}.'.format(last_message)
        log.progress(last_message, flush=False)

        conduct_args = ConductArgs(args.vm_type)
        url = conduct_url.url('members', conduct_args)
        try:
            conduct_request.get(dcos_mode=False, host=conduct_args.ip, url=url, timeout=DEFAULT_HTTP_TIMEOUT)
            break
        except ConnectionError:
            current_retry += 1

    # Reprint previous message with flush to go to next line
    log.progress(last_message, flush=True)
    return True if current_retry < max_retries else False
示例#7
0
def count_installations(bundle_id, args):
    bundles_url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode, conduct_url.conductr_host(args), bundles_url,
                                   auth=args.conductr_auth, verify=args.server_verification_file)
    response.raise_for_status()
    bundles = json.loads(response.text)
    matching_bundles = [bundle for bundle in bundles if bundle['bundleId'] == bundle_id]
    if matching_bundles:
        matching_bundle = matching_bundles[0]
        if 'bundleInstallations' in matching_bundle:
            return len(matching_bundle['bundleInstallations'])

    return 0
示例#8
0
def info(args):
    """`conduct info` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url("bundles", args)
    response = conduct_request.get(
        args.dcos_mode,
        conductr_host(args),
        url,
        auth=args.conductr_auth,
        verify=args.server_verification_file,
        timeout=DEFAULT_HTTP_TIMEOUT,
    )
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    data = [
        {
            "id": ("! " if bundle.get("hasError", False) else "")
            + (bundle["bundleId"] if args.long_ids else bundle_utils.short_id(bundle["bundleId"])),
            "name": bundle["attributes"]["bundleName"],
            "replications": len(bundle["bundleInstallations"]),
            "starting": sum([not execution["isStarted"] for execution in bundle["bundleExecutions"]]),
            "executions": sum([execution["isStarted"] for execution in bundle["bundleExecutions"]]),
        }
        for bundle in json.loads(response.text)
    ]
    data.insert(0, {"id": "ID", "name": "NAME", "replications": "#REP", "starting": "#STR", "executions": "#RUN"})

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data), **{"padding": " " * padding})
    has_error = False
    for row in data:
        has_error |= "!" in row["id"]
        log.screen(
            """\
{id: <{id_width}}{padding}\
{name: <{name_width}}{padding}\
{replications: >{replications_width}}{padding}\
{starting: >{starting_width}}{padding}\
{executions: >{executions_width}}""".format(
                **dict(row, **column_widths)
            ).rstrip()
        )

    if has_error:
        log.screen("There are errors: use `conduct events` or `conduct logs` for further information")

    return True
示例#9
0
def get_deployment_events(deployment_id, args):
    deployment_state_url = conduct_url.url(
        'deployments/{}'.format(deployment_id), args)
    response = conduct_request.get(args.dcos_mode,
                                   conduct_url.conductr_host(args),
                                   deployment_state_url,
                                   auth=args.conductr_auth,
                                   verify=args.server_verification_file)
    if response.status_code == 404:
        return None
    else:
        response.raise_for_status()
        deployment_state = json.loads(response.text)
        return deployment_state
示例#10
0
def wait_for_conductr(run_result, current_retry, max_retries, interval):
    log = logging.getLogger(__name__)
    last_message = 'Waiting for ConductR to start'
    log.progress(last_message, flush=False)
    for attempt in range(0, max_retries):
        time.sleep(interval)

        last_message = '{}.'.format(last_message)
        log.progress(last_message, flush=False)

        url = conduct_url.url('members', run_result)
        try:
            conduct_request.get(dcos_mode=False,
                                host=run_result.host,
                                url=url,
                                timeout=DEFAULT_HTTP_TIMEOUT)
            break
        except ConnectionError:
            current_retry += 1

    # Reprint previous message with flush to go to next line
    log.progress(last_message, flush=True)
    return True if current_retry < max_retries else False
示例#11
0
def get_scale(bundle_id, args):
    bundles_url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode, conduct_url.conductr_host(args), bundles_url,
                                   auth=args.conductr_auth, verify=args.server_verification_file)
    response.raise_for_status()
    bundles = json.loads(response.text)
    matching_bundles = [bundle for bundle in bundles if bundle['bundleId'] == bundle_id]
    if matching_bundles:
        matching_bundle = matching_bundles[0]
        if 'bundleExecutions' in matching_bundle:
            started_executions = [bundle_execution
                                  for bundle_execution in matching_bundle['bundleExecutions']
                                  if bundle_execution['isStarted']]
            return len(started_executions)

    return 0
示例#12
0
def acls(args):
    """`conduct acls` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode, conductr_host(args), url, timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    def get_system_version(bundle):
        if 'systemVersion' in bundle['attributes']:
            return bundle['attributes']['systemVersion']
        else:
            return bundle['attributes']['system'].split('-')[-1]

    def is_started(bundle_executions):
        for execution in bundle_executions:
            if execution['isStarted']:
                return 'Running'
        return 'Starting'

    all_acls = [
        {
            'acl': acl,
            'system': bundle['attributes']['system'],
            'system_version': get_system_version(bundle),
            'endpoint_name': endpoint_name,
            'bundle_id': bundle['bundleId'] if args.long_ids else bundle_utils.short_id(bundle['bundleId']),
            'bundle_name': bundle['attributes']['bundleName'],
            'status': is_started(bundle['bundleExecutions'])
        }
        for bundle in json.loads(response.text) if bundle['bundleExecutions']
        for endpoint_name, endpoint in bundle['bundleConfig']['endpoints'].items() if 'acls' in endpoint
        for acl in endpoint['acls']
    ]

    if args.protocol_family == 'http':
        http_acls = [acl for acl in all_acls if 'http' in acl['acl']]
        display_http_acls(log, http_acls)

    elif args.protocol_family == 'tcp':
        tcp_acls = [acl for acl in all_acls if 'tcp' in acl['acl']]
        display_tcp_acls(log, tcp_acls)

    return True
示例#13
0
def count_installations(bundle_id, args):
    bundles_url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode,
                                   conduct_url.conductr_host(args),
                                   bundles_url,
                                   auth=args.conductr_auth,
                                   verify=args.server_verification_file)
    response.raise_for_status()
    bundles = json.loads(response.text)
    matching_bundles = [
        bundle for bundle in bundles if bundle['bundleId'] == bundle_id
    ]
    if matching_bundles:
        matching_bundle = matching_bundles[0]
        if 'bundleInstallations' in matching_bundle:
            return len(matching_bundle['bundleInstallations'])

    return 0
def service_names(args):
    """`conduct service-names` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode,
                                   conductr_host(args),
                                   url,
                                   timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    bundles = json.loads(response.text)
    data, duplicate_endpoints = get_service_names_from_bundles(args, bundles)
    display_service_names(log, data, duplicate_endpoints)
    return True
示例#15
0
    def test_get(self):
        enriched_args = {'enriched': 'args'}
        enrich_args_mock = MagicMock(return_value=enriched_args)

        dcos_http_response = 'dcos_http_response'
        dcos_http_mock = MagicMock(return_value=dcos_http_response)

        requests_http_response = 'requests_http_response'
        requests_http_mock = MagicMock(return_value=requests_http_response)

        with patch('conductr_cli.conduct_request.enrich_args', enrich_args_mock), \
                patch('dcos.http.get', dcos_http_mock), \
                patch('requests.get', requests_http_mock):
            result = conduct_request.get(self.dcos_mode, self.host, self.url, **self.kwargs)
            self.assertEqual(requests_http_response, result)

        enrich_args_mock.assert_called_with(self.host, **self.kwargs)
        requests_http_mock.assert_called_with(self.url, **enriched_args)
        dcos_http_mock.assert_not_called()
示例#16
0
def agents(args):
    """`conduct agents` command"""

    log = logging.getLogger(__name__)

    request_url = conduct_url.url('agents', args)
    response = conduct_request.get(args.dcos_mode, conductr_host(args), request_url, auth=args.conductr_auth,
                                   verify=args.server_verification_file, timeout=DEFAULT_HTTP_TIMEOUT)

    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    raw_data = json.loads(response.text)

    data = [
        {
            'address': 'ADDRESS',
            'roles': 'ROLES',
            'observed': 'OBSERVED BY'
        }
    ]

    for entry in raw_data:
        if args.role is None or args.role in entry['roles']:
            data.append({
                'address': entry['address'],
                'roles': ','.join(entry['roles']),
                'observed': ','.join(map(lambda e: e['node']['address'], entry['observedBy']))
            })

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data), **{'padding': ' ' * padding})

    for row in data:
        log.screen('''\
{address: <{address_width}}{padding}\
{roles: <{roles_width}}{padding}\
{observed: >{observed_width}}{padding}'''.format(**dict(row, **column_widths)).rstrip())

    return True
    def test_get(self):
        enriched_args = {'enriched': 'args'}
        enrich_args_mock = MagicMock(return_value=enriched_args)

        dcos_http_response = 'dcos_http_response'
        dcos_http_mock = MagicMock(return_value=dcos_http_response)

        requests_http_response = 'requests_http_response'
        requests_http_mock = MagicMock(return_value=requests_http_response)

        with patch('conductr_cli.conduct_request.enrich_args', enrich_args_mock), \
                patch('dcos.http.get', dcos_http_mock), \
                patch('requests.get', requests_http_mock):
            result = conduct_request.get(self.dcos_mode, self.host, self.url,
                                         **self.kwargs)
            self.assertEqual(requests_http_response, result)

        enrich_args_mock.assert_called_with(self.host, **self.kwargs)
        requests_http_mock.assert_called_with(self.url, **enriched_args)
        dcos_http_mock.assert_not_called()
示例#18
0
def info(args):
    """`conduct info` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode,
                                   conductr_host(args),
                                   url,
                                   auth=args.conductr_auth,
                                   verify=args.server_verification_file,
                                   timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    bundles = json.loads(response.text)
    if args.bundle:
        return conduct_info_inspect.display_bundle(args, bundles, args.bundle)
    else:
        return conduct_info_list.display_bundles(args, bundles)
示例#19
0
def info(args):
    """`conduct info` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode, conductr_host(args), url, auth=args.conductr_auth,
                                   verify=args.server_verification_file, timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    data = [
        {
            'id': ('! ' if bundle.get('hasError', False) else '') +
                  (bundle['bundleId'] if args.long_ids else bundle_utils.short_id(bundle['bundleId'])),
            'name': bundle['attributes']['bundleName'],
            'replications': len(bundle['bundleInstallations']),
            'starting': sum([not execution['isStarted'] for execution in bundle['bundleExecutions']]),
            'executions': sum([execution['isStarted'] for execution in bundle['bundleExecutions']])
        } for bundle in json.loads(response.text)
    ]
    data.insert(0, {'id': 'ID', 'name': 'NAME', 'replications': '#REP', 'starting': '#STR', 'executions': '#RUN'})

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data), **{'padding': ' ' * padding})
    has_error = False
    for row in data:
        has_error |= '!' in row['id']
        log.screen('''\
{id: <{id_width}}{padding}\
{name: <{name_width}}{padding}\
{replications: >{replications_width}}{padding}\
{starting: >{starting_width}}{padding}\
{executions: >{executions_width}}'''.format(**dict(row, **column_widths)).rstrip())

    if has_error:
        log.screen('There are errors: use `conduct events` or `conduct logs` for further information')

    return True
示例#20
0
def download_license(args, save_to):
    """
    Downloads license from Lightbend.com.
    :param args: input args obtained from argparse.
    :param save_to: the path where downloaded license will be saved to.
    :return: path to the license file.
    """

    log = logging.getLogger(__name__)

    cached_token = license_auth.get_cached_auth_token()
    if cached_token:
        auth_token = cached_token
    else:
        auth_token = license_auth.prompt_for_auth_token()

    license_download_host = urlparse(args.license_download_url).hostname
    auth_token_b64_bytes = base64.b64encode(bytes(auth_token, 'UTF-8'))
    auth_token_b64 = auth_token_b64_bytes.decode('UTF-8')

    auth_header = {'Authorization': 'Bearer {}'.format(auth_token_b64)}
    response = conduct_request.get(args.dcos_mode, license_download_host, args.license_download_url,
                                   headers=auth_header,
                                   verify=args.server_verification_file)

    if log.is_verbose_enabled():
        log.verbose(response.text)

    if response.status_code == 401 or response.status_code == 303:
        license_auth.remove_cached_auth_token()
        raise LicenseDownloadError([response.text])

    elif response.status_code == 403:
        raise LicenseDownloadError([response.text])

    validation.raise_for_status_inc_3xx(response)

    license_auth.save_auth_token(auth_token)
    save_license_data(response.text, save_to)
示例#21
0
def get_license(args):
    """
    Get license from ConductR.
    Returns a tuple of Boolean, get_license_payload. The following return values are allowed
    - False, None: License endpoint does not exist at the ConductR control protocol
    - True, None: No license has been uploaded to ConductR
    - True, license_data: Returns the current license from ConductR
    :param args: input args obtained from argparse
    """
    url = conduct_url.url('license', args)
    try:
        response = conduct_request.get(args.dcos_mode, conductr_host(args), url, auth=args.conductr_auth)
        if response.status_code == 404 or response.status_code == 503:
            return False, None
        else:
            validation.raise_for_status_inc_3xx(response)
            return True, json.loads(response.text)
    except DCOSHTTPException as e:
        if e.response.status_code == 404 or e.response.status_code == 503:
            return False, None
        else:
            raise e
示例#22
0
def get_scale(bundle_id, wait_for_is_active, args):
    bundles_url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode,
                                   conduct_url.conductr_host(args),
                                   bundles_url,
                                   auth=args.conductr_auth,
                                   verify=args.server_verification_file)
    response.raise_for_status()
    bundles = json.loads(response.text)
    matching_bundles = [
        bundle for bundle in bundles if bundle['bundleId'] == bundle_id
    ]
    if matching_bundles:
        matching_bundle = matching_bundles[0]
        if 'bundleExecutions' in matching_bundle:
            started_executions = [
                bundle_execution
                for bundle_execution in matching_bundle['bundleExecutions']
                if not wait_for_is_active or bundle_execution['isStarted']
            ]
            return len(started_executions)

    return 0
示例#23
0
def acls(args):
    """`conduct acls` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode,
                                   conductr_host(args),
                                   url,
                                   timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    bundles = json.loads(response.text)
    all_acls, http_acls, tcp_acls = get_acls_from_bundles(args, bundles)

    if args.protocol_family == 'http':
        display_http_acls(log, http_acls)

    elif args.protocol_family == 'tcp':
        display_tcp_acls(log, tcp_acls)

    return True
示例#24
0
def members(args):
    """`conduct members` command"""

    log = logging.getLogger(__name__)

    request_url = conduct_url.url('members', args)
    response = conduct_request.get(args.dcos_mode,
                                   conductr_host(args),
                                   request_url,
                                   auth=args.conductr_auth,
                                   verify=args.server_verification_file,
                                   timeout=DEFAULT_HTTP_TIMEOUT)

    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    raw_data = json.loads(response.text)

    data = [{
        'address': 'ADDRESS',
        'uid': 'UID',
        'roles': 'ROLES',
        'status': 'STATUS',
        'reachable': 'REACHABLE'
    }]

    unreachable_nodes = []

    for entry in raw_data['unreachable']:
        unreachable_nodes.append(entry['node'])

    for entry in raw_data['members']:
        if args.role is None or args.role in entry['roles']:
            data.append({
                'address':
                entry['node']['address'],
                'uid':
                entry['node']['uid'],
                'roles':
                ','.join(entry['roles']),
                'status':
                entry['status'],
                'reachable':
                'Yes' if entry['node'] not in unreachable_nodes else 'No'
            })

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data),
                         **{'padding': ' ' * padding})

    for row in data:
        log.screen('''\
{uid: <{uid_width}}{padding}\
{address: <{address_width}}{padding}\
{roles: <{roles_width}}{padding}\
{status: <{status_width}}{padding}\
{reachable: >{reachable_width}}'''.format(
            **dict(row, **column_widths)).rstrip())

    return True
def service_names(args):
    """`conduct service-names` command"""

    log = logging.getLogger(__name__)
    url = conduct_url.url('bundles', args)
    response = conduct_request.get(args.dcos_mode, conductr_host(args), url, timeout=DEFAULT_HTTP_TIMEOUT)
    validation.raise_for_status_inc_3xx(response)

    if log.is_verbose_enabled():
        log.verbose(validation.pretty_json(response.text))

    def execution_status(bundle_executions):
        for execution in bundle_executions:
            if execution['isStarted']:
                return 'Running'
        return 'Starting'

    def get_service_name_from_service_uri(service_uri):
        paths = urlparse(service_uri).path.split('/')
        if len(paths) > 1:
            return paths[1]
        else:
            return ''

    data_from_service_uri = [
        (
            {
                'service_name': get_service_name_from_service_uri(service_uri),
                'service_uri': service_uri,
                'bundle_id': bundle['bundleId'] if args.long_ids else bundle_utils.short_id(
                    bundle['bundleId']),
                'bundle_name': bundle['attributes']['bundleName'],
                'status': execution_status(bundle['bundleExecutions'])
            }
        )
        for bundle in json.loads(response.text) if bundle['bundleExecutions']
        for endpoint_name, endpoint in bundle['bundleConfig']['endpoints'].items() if 'services' in endpoint
        for service_uri in endpoint['services']
    ]

    data_from_service_name = [
        (
            {
                'service_name': endpoint['serviceName'],
                'service_uri': None,
                'bundle_id': bundle['bundleId'] if args.long_ids else bundle_utils.short_id(
                    bundle['bundleId']),
                'bundle_name': bundle['attributes']['bundleName'],
                'status': execution_status(bundle['bundleExecutions'])
            }
        )
        for bundle in json.loads(response.text) if bundle['bundleExecutions']
        for endpoint_name, endpoint in bundle['bundleConfig']['endpoints'].items() if 'serviceName' in endpoint
    ]

    data = data_from_service_uri + data_from_service_name
    data = sorted([entry for entry in data if entry['service_name']], key=lambda line: line['service_name'])

    service_endpoints = {}
    for service in data:
        url = urlparse(service['service_uri'])
        if not (url.path == '' or url.path == '/'):
            try:
                service_endpoints[url.path] |= {service['service_uri']}
            except KeyError:
                service_endpoints[url.path] = {service['service_uri']}
    duplicate_endpoints = [service for (service, endpoint) in service_endpoints.items() if len(endpoint) > 1] \
        if len(service_endpoints) > 0 else []

    data.insert(0, {'service_name': 'SERVICE NAME', 'bundle_id': 'BUNDLE ID', 'bundle_name': 'BUNDLE NAME', 'status': 'STATUS'})

    padding = 2
    column_widths = dict(screen_utils.calc_column_widths(data), **{'padding': ' ' * padding})
    for row in data:
        log.screen(
            '{service_name: <{service_name_width}}{padding}'
            '{bundle_id: <{bundle_id_width}}{padding}'
            '{bundle_name: <{bundle_name_width}}{padding}'
            '{status: <{status_width}}'.format(**dict(row, **column_widths)).rstrip())

    if len(duplicate_endpoints) > 0:
        log.screen('')
        log.warning('Multiple endpoints found for the following services: {}'.format(', '.join(duplicate_endpoints)))
        log.warning('Service resolution for these services is undefined.')

    return True