Example #1
0
    def test_get_scan_items_from_fs_with_owner_active_only(
            self, mocked_getpwall, mocked_srv_files_mgr):
        """Test that only active suites are returned if so requested.
        Args:
            mocked_getpwall (object): mocked pwd.getpwall
            mocked_srv_files_mgr (object): mocked SuiteSrvFilesManager
        """
        # mock sr
        with TemporaryDirectory() as homedir:
            # mock pwd.getpwall
            mocked_getpwall.return_value = [
                self.pwentry('/bin/bash', 'root', homedir),
            ]
            mocked_srv_files_mgr.return_value.KEY_HOST = 'host'
            mocked_srv_files_mgr.return_value.KEY_PORT = 'port'

            # mock srv_files_mgr.load_contact_file
            def mocked_load_contact_file(reg, _):
                if reg == 'good':
                    return {'host': 'localhost', 'port': 9999}
                else:
                    raise SuiteServiceFileError(reg)

            mocked_srv_files_mgr.return_value.load_contact_file = \
                mocked_load_contact_file
            for suite_name in ["good", "bad", "ugly"]:
                suite_directory = Path(homedir, 'cylc-run', suite_name)
                suite_directory.mkdir(parents=True)
                # mock srv_files_mgr.load_contact_file
                owner_pattern = re.compile(pattern="^.oo.$")
                suites = list(
                    get_scan_items_from_fs(owner_pattern=owner_pattern,
                                           active_only=True))
                # will match blog/five but will stop once it finds log
                self.assertEqual([('good', 'localhost', 9999)], suites)
Example #2
0
 def test_get_scan_items_from_fs_with_owner_do_not_descend(
         self, mocked_getpwall, mocked_srv_files_mgr):
     """Test that it does not descend when it finds a directory called
     "log".
     Args:
         mocked_getpwall (object): mocked pwd.getpwall
         mocked_srv_files_mgr (object): mocked SuiteSrvFilesManager
     """
     with TemporaryDirectory() as homedir:
         # mock pwd.getpwall
         mocked_getpwall.return_value = [
             self.pwentry('/bin/bash', 'root', homedir),
         ]
         suite_directory = Path(homedir, 'cylc-run', 'blog', 'five', 'log',
                                'five')
         suite_directory.mkdir(parents=True)
         # mock srv_files_mgr.load_contact_file
         mocked_srv_files_mgr.return_value.get_suite_source_dir \
             .return_value = 'DIR'
         mocked_srv_files_mgr.return_value.get_suite_title \
             .return_value = 'TITLE'
         owner_pattern = re.compile(pattern="^.oo.$")
         reg_pattern = re.compile(pattern="^.*five$")
         suites = list(
             get_scan_items_from_fs(owner_pattern=owner_pattern,
                                    reg_pattern=reg_pattern,
                                    active_only=False))
         # will match blog/five, but will stop once it finds the log dir
         self.assertEqual([('blog/five', 'DIR', 'TITLE')], suites)
Example #3
0
 def test_get_scan_items_from_fs_with_owner_debug(self, mocked_sys):
     """Test that when debug is enabled.
     Args:
         mocked_sys (object): mocked sys
     """
     # mock sys.stderr.write
     flags.debug = True
     mocked_sys.stderr = CaptureStderr()
     # will include a debug message with the empty list
     owner_pattern = re.compile(pattern=".*__sheep__.*")
     list(get_scan_items_from_fs(owner_pattern=owner_pattern))
     self.assertTrue(len(mocked_sys.stderr.lines) > 0)
Example #4
0
 def test_get_scan_items_from_fs_with_owner_noshell(self, mocked_getpwall):
     """Test that passwd entries using shells that end with /false or
     /nologin are ignored.
     Args:
         mocked_getpwall (object): mocked pwd.getpwall
     """
     mocked_getpwall.return_value = [
         self.pwentry(shell, 'root', '/root')
         for shell in self._get_ignored_shells()
     ]
     owner_pattern = re.compile(pattern=".*")
     suites = list(get_scan_items_from_fs(owner_pattern=owner_pattern))
     self.assertEqual(0, len(suites))
Example #5
0
 def test_get_scan_items_from_fs_with_owner_pattern_mismatch(
         self, mocked_getpwall):
     """Test that passwd entries with users that do not match the pattern
     used are ignored.
     Args:
         mocked_getpwall (object): mocked pwd.getpwall
     """
     # mock pwd.getpwall
     mocked_getpwall.return_value = [
         self.pwentry('/bin/bash', 'root', '/root'),
         self.pwentry('/bin/bash', 'proot', '/root'),
         self.pwentry('/bin/bash', 'wheels', '/root'),
         self.pwentry('/bin/bash', 'docker', '/root')
     ]
     owner_pattern = re.compile(pattern=".*__sheep__.*")
     suites = list(get_scan_items_from_fs(owner_pattern=owner_pattern))
     self.assertEqual(0, len(suites))
Example #6
0
    def test_get_scan_items_from_fs_with_owner_active_only(
            self, mocked_getpwall, mocked_contact_file_fields,
            mocked_load_contact_file):
        """Test that only active suites are returned if so requested.
        Args:
            mocked_getpwall (object): mocked pwd.getpwall
            mocked_contact_file_fields (object): mocked ContactFileFields
            mocked_load_contact_file (function): mocked load_contact_file
        """
        # mock sr
        with TemporaryDirectory() as homedir:
            # mock pwd.getpwall
            mocked_getpwall.return_value = [
                self.pwentry('/bin/bash', 'root', homedir),
            ]
            mocked_contact_file_fields.API = 'api'
            mocked_contact_file_fields.HOST = 'host'
            mocked_contact_file_fields.PORT = 'port'
            mocked_contact_file_fields.PUBLISH_PORT = 'pub_port'

            # mock srv_files_mgr.load_contact_file
            def my_load_contact_file(reg, _):
                if reg == 'good':
                    return {
                        'host': 'localhost',
                        'port': 9999,
                        'pub_port': 1234,
                        'api': str(API),
                    }
                else:
                    raise SuiteServiceFileError(reg)

            mocked_load_contact_file.side_effect = my_load_contact_file
            for suite_name in ["good", "bad", "ugly"]:
                suite_directory = Path(homedir, 'cylc-run', suite_name)
                suite_directory.mkdir(parents=True)
                # mock srv_files_mgr.load_contact_file
                owner_pattern = re.compile(pattern="^.oo.$")
                suites = list(get_scan_items_from_fs(
                    owner_pattern=owner_pattern, active_only=True))
                # will match blog/five but will stop once it finds log
                self.assertEqual(
                    [('good', 'localhost', 9999, 1234, str(API))], suites)
    async def gather_workflows(self):
        scanflows = {}
        cre_owner, cre_name = re_compile_filters(None, ['.*'])
        scan_args = (
            (reg, host, port, CLIENT_TIMEOUT)
            for reg, host, port in get_scan_items_from_fs(cre_owner, cre_name))
        gathers = ()
        for arg in scan_args:
            gathers += (est_workflow(*arg), )
        items = await asyncio.gather(*gathers)
        for reg, host, port, client, info in items:
            if info is not None and info != MSG_TIMEOUT:
                owner = info['owner']
                scanflows[f"{owner}{ID_DELIM}{reg}"] = {
                    'name': info['name'],
                    'owner': owner,
                    'host': host,
                    'port': port,
                    'version': info['version'],
                    'req_client': client,
                }

        # Check existing against scan
        for w_id, info in list(self.workflows.items()):
            if w_id in scanflows:
                if (info['host'] == scanflows[w_id]['host']
                        and info['port'] == scanflows[w_id]['port']):
                    client = scanflows[w_id]['req_client']
                    with suppress(IOError):
                        client.socket.close()
                    scanflows.pop(w_id)
                continue
            client = self.workflows[w_id]['req_client']
            with suppress(IOError):
                client.socket.close()
            self.workflows.pop(w_id)

        # update with new
        self.workflows.update(scanflows)
Example #8
0
def main(parser, options):
    """Implement "cylc scan"."""
    if options.full:
        options.describe = options.state_totals = options.publisher = True
    if options.format in ['raw', 'json']:
        options.color = False

    # color settings
    if options.color in ['auto', 'always'] and terminal.supports_color():
        options.color = True
    else:
        options.color = False
    color_init(autoreset=True, strip=not options.color)

    # name and owner patterns
    if options.patterns_name:
        patterns_name = options.patterns_name
    else:
        patterns_name = ['.*']  # Any suite name.
    patterns_owner = None
    if options.patterns_owner:
        patterns_owner = options.patterns_owner
    try:  # Compile and check "name" and "owner" regular expressions
        cre_owner, cre_name = re_compile_filters(patterns_owner, patterns_name)
    except ValueError as exc:
        parser.error(str(exc))

    # list of endpoints to call
    methods = ['identify']
    if options.describe:
        methods.append('describe')
    if options.state_totals:
        methods.append('state_totals')

    # suite generator
    suites = scan_many(
        get_scan_items_from_fs(cre_owner, cre_name),
        timeout=options.comms_timeout,
        methods=methods,
        ordered=options.ordered
    )

    # determine output format
    if options.format == 'json':
        print(json.dumps(list(suites), indent=4))
    elif options.format == 'raw':
        formatter = format_raw
    elif options.format == 'plain':
        formatter = format_plain
    else:
        raise UserInputError('Unknown format: %s' % options.format)

    # output state legend if necessary
    state_legend = ""
    if options.color and options.state_totals:
        n_states = len(TASK_STATUSES_ORDERED)
        for index, state in enumerate(TASK_STATUSES_ORDERED):
            state_legend += get_status_prop(state, 'ascii_ctrl')
            if index == n_states / 2:
                state_legend += "\n"
        print(state_legend.rstrip() + "\n")

    # work through scan results one by one
    for reg, host, port, pub_port, api, info in suites:
        if isinstance(info, str):
            print(ERROR_STYLE + ' '.join([reg, host, port, info]))
        elif info is None:
            print(ERROR_STYLE +
                  ' '.join([reg, host, port, 'Error Connecting']))
        elif info[KEY_NAME] != reg:
            # TODO - should we do anything here, is this likely?
            print(ERROR_STYLE + 'Warning: suite has changed name %s => %s' % (
                reg, info[KEY_NAME]))
        else:
            formatter(reg, host, port, pub_port, api, info, options)
Example #9
0
def main(parser, options, regfilter=None):
    if regfilter:
        try:
            regfilter = re.compile(regfilter)
        except re.error as exc:
            raise ValueError("%s: %s" % (regfilter, exc))
    allsuites = list(
        get_scan_items_from_fs(reg_pattern=regfilter, active_only=False))
    if options.fail and not allsuites:
        raise SystemExit('ERROR: no suites matched.')
    if not options.tree:
        if options.align:
            maxlen_suite = 0
            maxlen_title = 0
            for suite, dir_, title in allsuites:
                if len(suite) > maxlen_suite:
                    maxlen_suite = len(suite)
                if len(title) > maxlen_title:
                    maxlen_title = len(title)
            spacer_suite = maxlen_suite * ' '
            spacer_title = maxlen_title * ' '
        for suite, dir_, title in allsuites:
            dir_ = re.sub('^' + os.environ['HOME'], '~', dir_)
            if options.align:
                suite = suite + spacer_suite[len(suite):]
                title = title + spacer_title[len(title):]
            if not options.x and not options.y:
                line = suite + ' | ' + title + ' | ' + dir_
            elif not options.y:
                line = suite + ' | ' + title
            elif not options.x:
                line = suite + ' | ' + dir_
            else:
                line = suite
            print(line)
    else:
        tree = {}
        if options.align:
            maxlen_title = 0
            for suite, dir_, title in allsuites:
                if len(title) > maxlen_title:
                    maxlen_title = len(title)
            spacer_title = maxlen_title * ' '

        for suite, dir_, title in allsuites:
            dir_ = re.sub('^' + os.environ['HOME'], '~', dir_)
            if options.align:
                title = title + spacer_title[len(title):]
            regpath = suite.split(REG_DELIM)
            sub = tree
            for key in regpath[:-1]:
                if key not in sub:
                    sub[key] = {}
                sub = sub[key]
            if not options.x and not options.y:
                line = title + ' | ' + dir_
            elif not options.y:
                line = ' ' + title
            elif not options.x:
                line = ' ' + dir_
            else:
                line = ''
            sub[regpath[-1]] = line

        pad = get_padding(allsuites)
        print_tree(tree, pad, options.unicode)