def _log(follow, completed, lines, task, file_): """ Tail a file in the task's sandbox. :param follow: same as unix tail's -f :type follow: bool :param completed: whether to include completed tasks :type completed: bool :param lines: number of lines to print :type lines: int :param task: task pattern to match :type task: str :param file_: file path to read :type file_: str :returns: process return code :rtype: int """ fltr = task if file_ is None: file_ = 'stdout' if lines is None: lines = 10 lines = util.parse_int(lines) # get tasks client = mesos.DCOSClient() master = mesos.Master(client.get_master_state()) tasks = master.tasks(completed=completed, fltr=fltr) if not tasks: if not fltr: raise DCOSException("No tasks found. Exiting.") elif not completed: completed_tasks = master.tasks(completed=True, fltr=fltr) if completed_tasks: msg = 'No running tasks match ID [{}]; however, there '.format( fltr) if len(completed_tasks) > 1: msg += 'are {} matching completed tasks. '.format( len(completed_tasks)) else: msg += 'is 1 matching completed task. ' msg += 'Run with --completed to see these logs.' raise DCOSException(msg) raise DCOSException('No matching tasks. Exiting.') mesos_files = _mesos_files(tasks, file_, client) if not mesos_files: if fltr is None: msg = "No tasks found. Exiting" else: msg = "No matching tasks. Exiting." raise DCOSException('No matching tasks. Exiting.') log.log_files(mesos_files, follow, lines) return 0
def test_task_exact_match(): """Test a task gets returned if it is an exact match, even if it is a substring of another task. """ with patch('dcos.mesos.Master.slaves', return_value=[{"id": "foo"}, {"id": "foobar"}]): master = mesos.Master(None) assert master.slave("foo") == {"id": "foo"}
def get_tasks(task_id='', completed=True): """ Get a list of tasks, optionally filtered by task name. :param task_id: task ID :type task_id: str :param completed: include completed tasks? :type completed: bool :return: a tuple of tasks :rtype: tuple """ client = mesos.DCOSClient() master = mesos.Master(client.get_master_state()) tasks = master.tasks(completed=completed, fltr=task_id) return tasks
def get_tasks(task_id='', completed=True): """ Get a list of tasks, optionally filtered by task id. The task_id can be the abbrevated. Example: If a task named 'sleep' is scaled to 3 in marathon, there will be be 3 tasks starting with 'sleep.' :param task_id: task ID :type task_id: str :param completed: include completed tasks? :type completed: bool :return: a list of tasks :rtype: [] """ client = mesos.DCOSClient() master = mesos.Master(client.get_master_state()) mesos_tasks = master.tasks(completed=completed, fltr=task_id) return [task.__dict__['_task'] for task in mesos_tasks]
def _log(all_, follow, completed, lines, task, file_): """ Tail a file in the task's sandbox. :param all_: If True, include all tasks :type all_: bool :param follow: same as unix tail's -f :type follow: bool :param completed: whether to include completed tasks :type completed: bool :param lines: number of lines to print :type lines: int :param task: task pattern to match :type task: str :param file_: file path to read :type file_: str :returns: process return code :rtype: int """ fltr = task if file_ is None: file_ = 'stdout' if lines is None: lines = 10 lines = util.parse_int(lines) # get tasks client = mesos.DCOSClient() master = mesos.Master(client.get_master_state()) tasks = master.tasks(fltr=fltr, completed=completed, all_=all_) if not tasks: if not fltr: raise DCOSException("No tasks found. Exiting.") elif not completed: completed_tasks = master.tasks(completed=True, fltr=fltr) if completed_tasks: msg = 'No running tasks match ID [{}]; however, there '.format( fltr) if len(completed_tasks) > 1: msg += 'are {} matching completed tasks. '.format( len(completed_tasks)) else: msg += 'is 1 matching completed task. ' msg += 'Run with --completed to see these logs.' raise DCOSException(msg) raise DCOSException('No matching tasks. Exiting.') # if journald logging is disabled, read files API and exit. if not log.dcos_log_enabled(): mesos_files = _mesos_files(tasks, file_, client) if not mesos_files: if fltr is None: msg = "No tasks found. Exiting." else: msg = "No matching tasks. Exiting." raise DCOSException(msg) log.log_files(mesos_files, follow, lines) return 0 # otherwise if file_ in ('stdout', 'stderr'): _dcos_log(follow, tasks, lines, file_, completed) return 0 raise DCOSException('Invalid file {}. dcos-log only ' 'supports stdout/stderr'.format(file_)) return 1
def uninstall_app(app_name, remove_all, app_id, init_client, dcos_client): """Uninstalls an app. :param app_name: The app to uninstall :type app_name: str :param remove_all: Whether to remove all instances of the named app :type remove_all: boolean :param app_id: App ID of the app instance to uninstall :type app_id: str :param init_client: The program to use to run the app :type init_client: object :param dcos_client: the DCOS client :type dcos_client: dcos.mesos.DCOSClient :returns: number of apps uninstalled :rtype: int """ apps = init_client.get_apps() def is_match(app): encoding = 'utf-8' # We normalize encoding for byte-wise comparison name_label = app.get('labels', {}).get(PACKAGE_NAME_KEY, u'') name_label_enc = name_label.encode(encoding) app_name_enc = app_name.encode(encoding) name_matches = name_label_enc == app_name_enc if app_id is not None: pkg_app_id = app.get('id', '') normalized_app_id = init_client.normalize_app_id(app_id) return name_matches and pkg_app_id == normalized_app_id else: return name_matches matching_apps = [a for a in apps if is_match(a)] if not remove_all and len(matching_apps) > 1: app_ids = [a.get('id') for a in matching_apps] raise DCOSException( ("Multiple apps named [{}] are installed: [{}].\n" + "Please use --app-id to specify the ID of the app to uninstall," + " or use --all to uninstall all apps.").format( app_name, ', '.join(app_ids))) for app in matching_apps: package_json = _decode_and_add_context( app['id'], app.get('labels', {})) # First, remove the app from Marathon init_client.remove_app(app['id'], force=True) # Second, shutdown the framework with Mesos framework_name = app.get('labels', {}).get(PACKAGE_FRAMEWORK_NAME_KEY) if framework_name is not None: logger.info( 'Trying to shutdown framework {}'.format(framework_name)) frameworks = mesos.Master(dcos_client.get_master_state()) \ .frameworks(inactive=True) # Look up all the framework names framework_ids = [ framework['id'] for framework in frameworks if framework['name'] == framework_name ] logger.info( 'Found the following frameworks: {}'.format(framework_ids)) # Emit post uninstall notes emitter.publish( DefaultError( 'Uninstalled package [{}] version [{}]'.format( package_json['name'], package_json['version']))) if 'postUninstallNotes' in package_json: emitter.publish( DefaultError(package_json['postUninstallNotes'])) if len(framework_ids) == 1: dcos_client.shutdown_framework(framework_ids[0]) elif len(framework_ids) > 1: raise DCOSException( "Unable to shutdown the framework for [{}] because there " "are multiple frameworks with the same name: [{}]. " "Manually shut them down using 'dcos service " "shutdown'.".format( framework_name, ', '.join(framework_ids))) return len(matching_apps)