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
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
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
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
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)
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
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 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
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
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
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
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
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
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()
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 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)
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
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)
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
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
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
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