Exemplo n.º 1
0
    def clear_broadcast(self,
                        point_strings=None,
                        namespaces=None,
                        cancel_settings=None):
        """Clear broadcasts globally, or for listed namespaces and/or points.

        Return a tuple (modified_settings, bad_options), where:
        * modified_settings is similar to the return value of the "put" method,
          but for removed broadcasts.
        * bad_options is a dict in the form:
              {"point_strings": ["20020202", ..."], ...}
          The dict is only populated if there are options not associated with
          previous broadcasts. The keys can be:
          * point_strings: a list of bad point strings.
          * namespaces: a list of bad namespaces.
          * cancel: a list of tuples. Each tuple contains the keys of a bad
            setting.
        """
        # If cancel_settings defined, only clear specific broadcasts
        cancel_keys_list = self._settings_to_keys_list(cancel_settings)

        # Clear broadcasts
        modified_settings = []
        with self.lock:
            for point_string, point_string_settings in self.broadcasts.items():
                if point_strings and point_string not in point_strings:
                    continue
                for namespace, namespace_settings in (
                        point_string_settings.items()):
                    if namespaces and namespace not in namespaces:
                        continue
                    stuff_stack = [([], namespace_settings)]
                    while stuff_stack:
                        keys, stuff = stuff_stack.pop()
                        for key, value in stuff.items():
                            if isinstance(value, dict):
                                stuff_stack.append((keys + [key], value))
                            elif (not cancel_keys_list
                                  or keys + [key] in cancel_keys_list):
                                stuff[key] = None
                                setting = {key: value}
                                for rkey in reversed(keys):
                                    setting = {rkey: setting}
                                modified_settings.append(
                                    (point_string, namespace, setting))

        # Prune any empty branches
        bad_options = self._get_bad_options(self._prune(), point_strings,
                                            namespaces, cancel_keys_list)

        # Log the broadcast
        self.suite_db_mgr.put_broadcast(modified_settings, is_cancel=True)
        LOG.info(get_broadcast_change_report(modified_settings,
                                             is_cancel=True))
        if bad_options:
            LOG.error(get_broadcast_bad_options_report(bad_options))
        if modified_settings:
            self.data_store_mgr.delta_broadcast()
        return modified_settings, bad_options
Exemplo n.º 2
0
    def clear_broadcast(
            self, point_strings=None, namespaces=None, cancel_settings=None):
        """Clear broadcasts globally, or for listed namespaces and/or points.

        Return a tuple (modified_settings, bad_options), where:
        * modified_settings is similar to the return value of the "put" method,
          but for removed broadcasts.
        * bad_options is a dict in the form:
              {"point_strings": ["20020202", ..."], ...}
          The dict is only populated if there are options not associated with
          previous broadcasts. The keys can be:
          * point_strings: a list of bad point strings.
          * namespaces: a list of bad namespaces.
          * cancel: a list of tuples. Each tuple contains the keys of a bad
            setting.
        """
        # If cancel_settings defined, only clear specific broadcasts
        cancel_keys_list = self._settings_to_keys_list(cancel_settings)

        # Clear broadcasts
        modified_settings = []
        with self.lock:
            for point_string, point_string_settings in self.broadcasts.items():
                if point_strings and point_string not in point_strings:
                    continue
                for namespace, namespace_settings in (
                        point_string_settings.items()):
                    if namespaces and namespace not in namespaces:
                        continue
                    stuff_stack = [([], namespace_settings)]
                    while stuff_stack:
                        keys, stuff = stuff_stack.pop()
                        for key, value in stuff.items():
                            if isinstance(value, dict):
                                stuff_stack.append((keys + [key], value))
                            elif (not cancel_keys_list or
                                    keys + [key] in cancel_keys_list):
                                stuff[key] = None
                                setting = {key: value}
                                for rkey in reversed(keys):
                                    setting = {rkey: setting}
                                modified_settings.append(
                                    (point_string, namespace, setting))

        # Prune any empty branches
        bad_options = self._get_bad_options(
            self._prune(), point_strings, namespaces, cancel_keys_list)

        # Log the broadcast
        self.suite_db_mgr.put_broadcast(modified_settings, is_cancel=True)
        LOG.info(
            get_broadcast_change_report(modified_settings, is_cancel=True))
        if bad_options:
            LOG.error(get_broadcast_bad_options_report(bad_options))

        return modified_settings, bad_options
Exemplo n.º 3
0
    def put_broadcast(self,
                      point_strings=None,
                      namespaces=None,
                      settings=None):
        """Add new broadcast settings (server side interface).

        Return a tuple (modified_settings, bad_options) where:
          modified_settings is list of modified settings in the form:
            [("20200202", "foo", {"script": "true"}, ...]
          bad_options is as described in the docstring for self.clear().
        """
        modified_settings = []
        bad_point_strings = []
        bad_namespaces = []

        with self.lock:
            for setting in settings:
                for point_string in point_strings:
                    # Standardise the point and check its validity.
                    bad_point = False
                    try:
                        point_string = standardise_point_string(point_string)
                    except PointParsingError:
                        if point_string != '*':
                            bad_point_strings.append(point_string)
                            bad_point = True
                    if not bad_point and point_string not in self.broadcasts:
                        self.broadcasts[point_string] = {}
                    for namespace in namespaces:
                        if namespace not in self.linearized_ancestors:
                            bad_namespaces.append(namespace)
                        elif not bad_point:
                            if namespace not in self.broadcasts[point_string]:
                                self.broadcasts[point_string][namespace] = {}
                            addict(self.broadcasts[point_string][namespace],
                                   setting)
                            modified_settings.append(
                                (point_string, namespace, setting))

        # Log the broadcast
        self.suite_db_mgr.put_broadcast(modified_settings)
        LOG.info(get_broadcast_change_report(modified_settings))

        bad_options = {}
        if bad_point_strings:
            bad_options["point_strings"] = bad_point_strings
        if bad_namespaces:
            bad_options["namespaces"] = bad_namespaces
        if modified_settings:
            self.data_store_mgr.delta_broadcast()
        return modified_settings, bad_options
Exemplo n.º 4
0
    def put_broadcast(
            self, point_strings=None, namespaces=None, settings=None):
        """Add new broadcast settings (server side interface).

        Return a tuple (modified_settings, bad_options) where:
          modified_settings is list of modified settings in the form:
            [("20200202", "foo", {"script": "true"}, ...]
          bad_options is as described in the docstring for self.clear().
        """
        modified_settings = []
        bad_point_strings = []
        bad_namespaces = []

        with self.lock:
            for setting in settings:
                for point_string in point_strings:
                    # Standardise the point and check its validity.
                    bad_point = False
                    try:
                        point_string = standardise_point_string(point_string)
                    except PointParsingError:
                        if point_string != '*':
                            bad_point_strings.append(point_string)
                            bad_point = True
                    if not bad_point and point_string not in self.broadcasts:
                        self.broadcasts[point_string] = {}
                    for namespace in namespaces:
                        if namespace not in self.linearized_ancestors:
                            bad_namespaces.append(namespace)
                        elif not bad_point:
                            if namespace not in self.broadcasts[point_string]:
                                self.broadcasts[point_string][namespace] = {}
                            self._addict(
                                self.broadcasts[point_string][namespace],
                                setting)
                            modified_settings.append(
                                (point_string, namespace, setting))

        # Log the broadcast
        self.suite_db_mgr.put_broadcast(modified_settings)
        LOG.info(get_broadcast_change_report(modified_settings))

        bad_options = {}
        if bad_point_strings:
            bad_options["point_strings"] = bad_point_strings
        if bad_namespaces:
            bad_options["namespaces"] = bad_namespaces
        return modified_settings, bad_options
Exemplo n.º 5
0
def main(_, options, suite):
    """Implement cylc broadcast."""
    pclient = SuiteRuntimeClient(
        suite, options.owner, options.host, options.port,
        options.comms_timeout)

    if options.show or options.showtask:
        if options.showtask:
            try:
                TaskID.split(options.showtask)
            except ValueError:
                raise UserInputError("TASKID must be " + TaskID.SYNTAX)
        settings = pclient('get_broadcast', {'task_id': options.showtask})
        padding = get_padding(settings) * ' '
        if options.raw:
            print(str(settings))
        else:
            print_tree(settings, padding, options.unicode)
        sys.exit(0)

    if options.clear:
        modified_settings, bad_options = pclient(
            'clear_broadcast',
            {'point_strings': options.point_strings,
             'namespaces': options.namespaces}
        )
        if modified_settings:
            print(get_broadcast_change_report(
                modified_settings, is_cancel=True))
        sys.exit(report_bad_options(bad_options))

    if options.expire:
        modified_settings, bad_options = pclient(
            'expire_broadcast',
            {'cutoff': options.expire}
        )
        if modified_settings:
            print(get_broadcast_change_report(
                modified_settings, is_cancel=True))
        sys.exit(report_bad_options(bad_options))

    # implement namespace and cycle point defaults here
    namespaces = options.namespaces
    if not namespaces:
        namespaces = ["root"]
    point_strings = options.point_strings
    if not point_strings:
        point_strings = ["*"]

    if options.cancel or options.cancel_files:
        settings = []
        for option_item in options.cancel:
            if "=" in option_item:
                raise UserInputError(
                    "--cancel=[SEC]ITEM does not take a value")
            option_item = option_item.strip()
            setting = get_rdict(option_item)
            settings.append(setting)
        files_to_settings(settings, options.cancel_files, options.cancel)
        modified_settings, bad_options = pclient(
            'clear_broadcast',
            {'point_strings': point_strings,
             'namespaces': namespaces,
             'cancel_settings': settings}
        )
        if modified_settings:
            print(get_broadcast_change_report(
                modified_settings, is_cancel=True))
        sys.exit(report_bad_options(bad_options))

    if options.settings or options.setting_files:
        settings = []
        for option_item in options.settings:
            if "=" not in option_item:
                raise UserInputError(
                    "--set=[SEC]ITEM=VALUE requires a value")
            lhs, rhs = [s.strip() for s in option_item.split("=", 1)]
            setting = get_rdict(lhs, rhs)
            settings.append(setting)
        files_to_settings(settings, options.setting_files)
        modified_settings, bad_options = pclient(
            'put_broadcast',
            {'point_strings': point_strings,
             'namespaces': namespaces,
             'settings': settings
             }
        )
        print(get_broadcast_change_report(modified_settings))
        sys.exit(report_bad_options(bad_options, is_set=True))
Exemplo n.º 6
0
def main(_, options, suite):
    """Implement cylc broadcast."""
    pclient = SuiteRuntimeClient(suite, timeout=options.comms_timeout)

    mutation_kwargs = {
        'request_string': MUTATION,
        'variables': {
            'wFlows': [suite],
            'bMode': 'Set',
            'cPoints': options.point_strings,
            'nSpaces': options.namespaces,
            'bSettings': options.settings,
            'bCutoff': options.expire,
        }
    }

    query_kwargs = {
        'request_string': QUERY,
        'variables': {
            'wFlows': [suite],
            'nIds': []
        }
    }

    if options.show or options.showtask:
        if options.showtask:
            try:
                task, point = TaskID.split(options.showtask)
                query_kwargs['variables']['nIds'] = [
                    f'{point}{ID_DELIM}{task}'
                ]
            except ValueError:
                raise UserInputError("TASKID must be " + TaskID.SYNTAX)
        result = pclient('graphql', query_kwargs)
        for wflow in result['workflows']:
            settings = wflow['broadcasts']
            padding = get_padding(settings) * ' '
            if options.raw:
                print(str(settings))
            else:
                print_tree(settings, padding, options.unicode)
        sys.exit(0)

    report_cancel = True
    report_set = False
    if options.clear:
        mutation_kwargs['variables']['bMode'] = 'Clear'

    if options.expire:
        mutation_kwargs['variables']['bMode'] = 'Expire'

    # implement namespace and cycle point defaults here
    namespaces = options.namespaces
    if not namespaces:
        namespaces = ["root"]
    point_strings = options.point_strings
    if not point_strings:
        point_strings = ["*"]

    if options.cancel or options.cancel_files:
        settings = []
        for option_item in options.cancel:
            if "=" in option_item:
                raise UserInputError(
                    "--cancel=[SEC]ITEM does not take a value")
            option_item = option_item.strip()
            setting = get_rdict(option_item)
            settings.append(setting)
        files_to_settings(settings, options.cancel_files, options.cancel)
        mutation_kwargs['variables'].update({
            'bMode': 'Clear',
            'cPoints': point_strings,
            'nSpaces': namespaces,
            'bSettings': settings,
        })

    if options.settings or options.setting_files:
        settings = []
        for option_item in options.settings:
            if "=" not in option_item:
                raise UserInputError("--set=[SEC]ITEM=VALUE requires a value")
            lhs, rhs = [s.strip() for s in option_item.split("=", 1)]
            setting = get_rdict(lhs, rhs)
            settings.append(setting)
        files_to_settings(settings, options.setting_files)
        mutation_kwargs['variables'].update({
            'bMode': 'Set',
            'cPoints': point_strings,
            'nSpaces': namespaces,
            'bSettings': settings,
        })
        report_cancel = False
        report_set = True

    results = pclient('graphql', mutation_kwargs)
    for result in results['broadcast']['result']:
        modified_settings = result['response'][0]
        bad_options = result['response'][1]
        if modified_settings:
            print(
                get_broadcast_change_report(modified_settings,
                                            is_cancel=report_cancel))
    sys.exit(report_bad_options(bad_options, is_set=report_set))
Exemplo n.º 7
0
async def run(options: 'Values', workflow_id):
    """Implement cylc broadcast."""
    pclient = get_client(workflow_id, timeout=options.comms_timeout)

    ret: Dict[str, Any] = {
        'stdout': [],
        'stderr': [],
        'exit': 0,
    }

    mutation_kwargs: Dict[str, Any] = {
        'request_string': MUTATION,
        'variables': {
            'wFlows': [workflow_id],
            'bMode': 'Set',
            'cPoints': options.point_strings,
            'nSpaces': options.namespaces,
            'bSettings': options.settings,
            'bCutoff': options.expire,
        }
    }

    query_kwargs: Dict[str, Any] = {
        'request_string': QUERY,
        'variables': {
            'wFlows': [workflow_id],
            'nIds': []
        }
    }

    if options.show or options.showtask:
        if options.showtask:
            try:
                query_kwargs['variables']['nIds'] = [options.showtask]
            except ValueError:
                # TODO validate showtask?
                raise UserInputError(
                    'TASK_ID_GLOB must be in the format: cycle/task')
        result = await pclient.async_request('graphql', query_kwargs)
        for wflow in result['workflows']:
            settings = wflow['broadcasts']
            padding = get_padding(settings) * ' '
            if options.raw:
                ret['stdout'].append(str(settings))
            else:
                ret['stdout'].extend(
                    get_tree(settings, padding, options.unicode))
        return ret

    report_cancel = True
    report_set = False
    if options.clear:
        mutation_kwargs['variables']['bMode'] = 'Clear'

    if options.expire:
        mutation_kwargs['variables']['bMode'] = 'Expire'

    # implement namespace and cycle point defaults here
    namespaces = options.namespaces
    if not namespaces:
        namespaces = ["root"]
    point_strings = options.point_strings
    if not point_strings:
        point_strings = ["*"]

    if options.cancel or options.cancel_files:
        settings = []
        for option_item in options.cancel:
            if "=" in option_item:
                raise UserInputError(
                    "--cancel=[SEC]ITEM does not take a value")
            option_item = option_item.strip()
            setting = get_rdict(option_item)
            settings.append(setting)
        files_to_settings(settings, options.cancel_files, options.cancel)
        mutation_kwargs['variables'].update({
            'bMode': 'Clear',
            'cPoints': point_strings,
            'nSpaces': namespaces,
            'bSettings': settings,
        })

    if options.settings or options.setting_files:
        settings = []
        for option_item in options.settings:
            if "=" not in option_item:
                raise UserInputError("--set=[SEC]ITEM=VALUE requires a value")
            lhs, rhs = [s.strip() for s in option_item.split("=", 1)]
            setting = get_rdict(lhs, rhs)
            settings.append(setting)
        files_to_settings(settings, options.setting_files)
        mutation_kwargs['variables'].update({
            'bMode': 'Set',
            'cPoints': point_strings,
            'nSpaces': namespaces,
            'bSettings': settings,
        })
        report_cancel = False
        report_set = True

    results = await pclient.async_request('graphql', mutation_kwargs)
    for result in results['broadcast']['result']:
        modified_settings = result['response'][0]
        bad_options = result['response'][1]
        if modified_settings:
            ret['stdout'].append(
                get_broadcast_change_report(
                    modified_settings,
                    is_cancel=report_cancel,
                ))

    bad_opts = report_bad_options(bad_options, is_set=report_set)
    if bad_opts:
        ret['stderr'].append(f'ERROR: {bad_opts}')
        ret['exit'] = 1
    return ret