class ABCTagMode(WatoMode, abc.ABC): def __init__(self): super().__init__() self._tag_config_file = TagConfigFile() self._load_effective_config() def _save_tags_and_update_hosts(self, tag_config): self._tag_config_file.save(tag_config) load_config() watolib.Folder.invalidate_caches() watolib.Folder.root_folder().rewrite_hosts_files() def _load_effective_config(self): self._builtin_config = cmk.utils.tags.BuiltinTagConfig() self._tag_config = cmk.utils.tags.TagConfig() self._tag_config.parse_config(self._tag_config_file.load_for_reading()) self._effective_config = cmk.utils.tags.TagConfig() self._effective_config.parse_config(self._tag_config.get_dict_format()) self._effective_config += self._builtin_config def _get_tags_using_aux_tag(self, aux_tag: cmk.utils.tags.AuxTag) -> Set[cmk.utils.tags.GroupedTag]: return { tag # for tag_group in self._effective_config.tag_groups for tag in tag_group.tags if aux_tag.id in tag.aux_tag_ids }
class ABCTagMode(WatoMode, metaclass=abc.ABCMeta): # NOTE: This class is obviously still abstract, but pylint fails to see # this, even in the presence of the meta class assignment below, see # https://github.com/PyCQA/pylint/issues/179. # pylint: disable=abstract-method def __init__(self): super(ABCTagMode, self).__init__() self._tag_config_file = TagConfigFile() self._load_effective_config() def _save_tags_and_update_hosts(self, tag_config): self._tag_config_file.save(tag_config) config.load_config() watolib.Folder.invalidate_caches() watolib.Folder.root_folder().rewrite_hosts_files() def _load_effective_config(self): self._builtin_config = cmk.utils.tags.BuiltinTagConfig() self._tag_config = cmk.utils.tags.TagConfig() self._tag_config.parse_config(self._tag_config_file.load_for_reading()) self._effective_config = cmk.utils.tags.TagConfig() self._effective_config.parse_config(self._tag_config.get_dict_format()) self._effective_config += self._builtin_config def _get_tags_using_aux_tag(self, aux_tag): # type: (cmk.utils.tags.AuxTag) -> Set[cmk.utils.tags.GroupedTag] return { tag # for tag_group in self._effective_config.tag_groups for tag in tag_group.tags if aux_tag.id in tag.aux_tag_ids }
class ABCTagMode(WatoMode): # NOTE: This class is obviously still abstract, but pylint fails to see # this, even in the presence of the meta class assignment below, see # https://github.com/PyCQA/pylint/issues/179. # pylint: disable=abstract-method __metaclass__ = abc.ABCMeta def __init__(self): super(ABCTagMode, self).__init__() self._tag_config_file = TagConfigFile() self._load_effective_config() def _save_tags_and_update_hosts(self, tag_config): self._tag_config_file.save(tag_config) config.load_config() watolib.Folder.invalidate_caches() watolib.Folder.root_folder().rewrite_hosts_files() def _load_effective_config(self): self._builtin_config = cmk.utils.tags.BuiltinTagConfig() self._tag_config = cmk.utils.tags.TagConfig() self._tag_config.parse_config(self._tag_config_file.load_for_reading()) self._effective_config = cmk.utils.tags.TagConfig() self._effective_config.parse_config(self._tag_config.get_dict_format()) self._effective_config += self._builtin_config
def test_tag_config_save(mocker): export_mock = mocker.patch.object(cmk.gui.watolib.tags, "_export_hosttags_to_php") config_file = TagConfigFile() base_config_mock = mocker.patch.object(config_file, "_save_base_config") cfg = tags.TagConfig() cfg.insert_tag_group( tags.TagGroup.from_config( { "id": "tgid2", "topic": "Topics", "title": "titlor", "tags": [{"id": "tgid2", "title": "tagid2", "aux_tags": []}], } ) ) config_file.save(cfg.get_dict_format()) export_mock.assert_called_once() base_config_mock.assert_called_once() cfg = tags.TagConfig.from_config(config_file.load_for_reading()) assert len(cfg.tag_groups) == 1 assert cfg.tag_groups[0].id == "tgid2"
def test_tag_config_save(mocker): export_mock = mocker.patch.object(cmk.gui.watolib.tags, "_export_hosttags_to_php") config_file = TagConfigFile() cfg = tags.TagConfig() cfg.insert_tag_group(tags.TagGroup(("tgid2", "Topics/titlor", [("tgid2", "tagid2", [])]))) config_file.save(cfg.get_dict_format()) export_mock.assert_called_once() cfg = tags.TagConfig() cfg.parse_config(config_file.load_for_reading()) assert len(cfg.tag_groups) == 1 assert cfg.tag_groups[0].id == "tgid2"
def _set(self, request): tag_config_file = TagConfigFile() hosttags_config = cmk.utils.tags.TagConfig() hosttags_config.parse_config(tag_config_file.load_for_modification()) hosttags_dict = hosttags_config.get_dict_format() if "configuration_hash" in request: validate_config_hash(request["configuration_hash"], hosttags_dict) del request["configuration_hash"] changed_hosttags_config = cmk.utils.tags.TagConfig() changed_hosttags_config.parse_config(request) changed_hosttags_config.validate_config() self._verify_no_used_tags_missing(changed_hosttags_config) tag_config_file.save(changed_hosttags_config.get_dict_format()) watolib.add_change("edit-hosttags", _("Updated host tags through Web-API"))
def _set(self, request): tag_config_file = TagConfigFile() hosttags_config = cmk.utils.tags.TagConfig() hosttags_config.parse_config(tag_config_file.load_for_modification()) hosttags_dict = hosttags_config.get_dict_format() if "configuration_hash" in request: validate_config_hash(request["configuration_hash"], hosttags_dict) del request["configuration_hash"] # Check for conflicts with existing configuration # Tags may be either specified grouped in a host/folder configuration, e.g agent/cmk-agent, # or specified as the plain id in rules. We need to check both variants.. used_tags = self._get_used_grouped_tags() used_tags.update(self._get_used_rule_tags()) changed_hosttags_config = cmk.utils.tags.TagConfig() changed_hosttags_config.parse_config(request) changed_hosttags_config.validate_config() new_tags = changed_hosttags_config.get_tag_ids() new_tags.update( changed_hosttags_config.get_tag_ids_with_group_prefix()) # Remove the builtin hoststags from the list of used_tags builtin_config = cmk.utils.tags.BuiltinTagConfig() used_tags.discard(builtin_config.get_tag_ids_with_group_prefix()) missing_tags = used_tags - new_tags if missing_tags: raise MKUserError( None, _("Unable to apply new hosttag configuration. The following tags " "are still in use, but not mentioned in the updated " "configuration: %s") % ", ".join(missing_tags)) tag_config_file.save(changed_hosttags_config.get_dict_format()) watolib.add_change("edit-hosttags", _("Updated host tags through Web-API"))
class ABCTagMode(WatoMode): __metaclass__ = abc.ABCMeta def __init__(self): super(ABCTagMode, self).__init__() self._tag_config_file = TagConfigFile() self._load_effective_config() def _save_tags_and_update_hosts(self, tag_config): self._tag_config_file.save(tag_config) config.load_config() watolib.Folder.invalidate_caches() watolib.Folder.root_folder().rewrite_hosts_files() def _load_effective_config(self): self._builtin_config = cmk.utils.tags.BuiltinTagConfig() self._tag_config = cmk.utils.tags.TagConfig() self._tag_config.parse_config(self._tag_config_file.load_for_reading()) self._effective_config = cmk.utils.tags.TagConfig() self._effective_config.parse_config(self._tag_config.get_dict_format()) self._effective_config += self._builtin_config
class ModeTags(WatoMode): @classmethod def name(cls): return "tags" @classmethod def permissions(cls): return ["hosttags"] def __init__(self): super(ModeTags, self).__init__() self._builtin_config = config.BuiltinTagConfig() self._tag_config_file = TagConfigFile() self._tag_config = cmk.gui.tags.TagConfig() self._tag_config.parse_config(self._tag_config_file.load_for_reading()) self._effective_config = cmk.gui.tags.TagConfig() self._effective_config.parse_config(self._tag_config.get_dict_format()) self._effective_config += self._builtin_config def title(self): return _("Tag groups") def buttons(self): global_buttons() html.context_button( _("New tag group"), watolib.folder_preserving_link([("mode", "edit_tag")]), "new") html.context_button( _("New aux tag"), watolib.folder_preserving_link([("mode", "edit_auxtag")]), "new") def action(self): if html.request.has_var("_delete"): return self._delete_tag_group() if html.request.has_var("_del_aux"): return self._delete_aux_tag() if html.request.var("_move") and html.check_transaction(): return self._move_tag_group() def _delete_tag_group(self): del_id = html.get_item_input("_delete", dict(self._tag_config.get_tag_group_choices()))[1] tag_group = self._tag_config.get_tag_group(del_id) if tag_group: operations = list(tag_group.get_tag_ids()) else: operations = None message = _rename_tags_after_confirmation(del_id, operations) if message is True: # no confirmation yet c = wato_confirm( _("Confirm deletion of the tag group '%s'") % del_id, _("Do you really want to delete the tag group '%s'?") % del_id) if c is False: return "" elif c is None: return None if message: self._tag_config.remove_tag_group(del_id) self._tag_config.validate_config() self._tag_config_file.save(self._tag_config.get_dict_format()) watolib.Folder.invalidate_caches() watolib.Folder.root_folder().rewrite_hosts_files() add_change("edit-tags", _("Removed tag group %s (%s)") % (message, del_id)) return "tags", message != True and message or None def _delete_aux_tag(self): del_id = html.get_item_input("_del_aux", dict(self._tag_config.aux_tag_list.get_choices()))[1] # Make sure that this aux tag is not begin used by any tag group for group in self._tag_config.tag_groups: for grouped_tag in group.tags: if del_id in grouped_tag.aux_tag_ids: raise MKUserError( None, _("You cannot delete this auxiliary tag. " "It is being used in the tag group <b>%s</b>.") % group.title) operations = {del_id: False} message = _rename_tags_after_confirmation(None, operations) if message is True: # no confirmation yet c = wato_confirm( _("Confirm deletion of the auxiliary tag '%s'") % del_id, _("Do you really want to delete the auxiliary tag '%s'?") % del_id) if c is False: return "" elif c is None: return None if message: self._tag_config.aux_tag_list.remove(del_id) self._tag_config.validate_config() self._tag_config_file.save(self._tag_config.get_dict_format()) watolib.Folder.invalidate_caches() watolib.Folder.root_folder().rewrite_hosts_files() add_change("edit-tags", _("Removed auxiliary tag %s (%s)") % (message, del_id)) return "tags", message != True and message or None def _move_tag_group(self): move_nr = html.get_integer_input("_move") move_to = html.get_integer_input("_index") moved = self._tag_config.tag_groups.pop(move_nr) self._tag_config.tag_groups.insert(move_to, moved) self._tag_config.validate_config() self._tag_config_file.save(self._tag_config.get_dict_format()) watolib.add_change("edit-tags", _("Changed order of tag groups")) def page(self): if not self._tag_config.tag_groups + self._tag_config.get_aux_tags(): MainMenu([ MenuItem( "edit_ttag", _("Create new tag group"), "new", "hosttags", _("Each tag group will create one dropdown choice in the host configuration.")), MenuItem( "edit_auxtag", _("Create new auxiliary tag"), "new", "hosttags", _("You can have these tags automatically added if certain primary tags are set." )), ]).show() return self._render_tag_list() self._render_aux_tag_list() def _render_tag_list(self): with table_element( "tags", _("Tag groups"), help=(_("Tags are the basis of Check_MK's rule based configuration. " "If the first step you define arbitrary tag groups. A host " "has assigned exactly one tag out of each group. These tags can " "later be used for defining parameters for hosts and services, " "such as <i>disable notifications for all hosts with the tags " "<b>Network device</b> and <b>Test</b></i>.")), empty_text=_("You haven't defined any tag groups yet."), searchable=False, sortable=False) as table: for nr, tag_group in enumerate(self._effective_config.tag_groups): table.row() table.cell(_("Actions"), css="buttons") self._show_tag_icons(tag_group, nr) table.text_cell(_("ID"), tag_group.id) table.text_cell(_("Title"), tag_group.title) table.text_cell(_("Topic"), tag_group.topic or _("Tags")) table.cell(_("Demonstration"), sortable=False) html.begin_form("tag_%s" % tag_group.id) watolib.host_attribute("tag_%s" % tag_group.id).render_input("", None) html.end_form() def _show_tag_icons(self, tag_group, nr): if self._builtin_config.tag_group_exists(tag_group.id): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_tag"), ("edit", tag_group.id)]) html.icon_button(edit_url, _("Edit this tag group"), "edit") html.element_dragger_url("tr", base_url=make_action_link([("mode", "tags"), ("_move", nr)])) delete_url = make_action_link([("mode", "tags"), ("_delete", tag_group.id)]) html.icon_button(delete_url, _("Delete this tag group"), "delete") def _render_aux_tag_list(self): with table_element( "auxtags", _("Auxiliary tags"), help=_("Auxiliary tags can be attached to other tags. That way " "you can for example have all hosts with the tag <tt>cmk-agent</tt> " "get also the tag <tt>tcp</tt>. This makes the configuration of " "your hosts easier."), empty_text=_("You haven't defined any auxiliary tags."), searchable=False) as table: for aux_tag in self._effective_config.aux_tag_list.get_tags(): table.row() table.cell(_("Actions"), css="buttons") if aux_tag.id in self._builtin_config.aux_tag_list.get_tag_ids(): html.i("(%s)" % _("builtin")) else: edit_url = watolib.folder_preserving_link([("mode", "edit_auxtag"), ("edit", aux_tag.id)]) delete_url = make_action_link([("mode", "tags"), ("_del_aux", aux_tag.id)]) html.icon_button(edit_url, _("Edit this auxiliary tag"), "edit") html.icon_button(delete_url, _("Delete this auxiliary tag"), "delete") table.text_cell(_("ID"), aux_tag.id) table.text_cell(_("Title"), _u(aux_tag.title)) table.text_cell(_("Topic"), _u(aux_tag.topic) or _("Tags")) table.text_cell( _("Tags using this auxiliary tag"), ", ".join( self._get_tags_using_aux_tag(aux_tag))) def _get_tags_using_aux_tag(self, aux_tag): used_tags = set() for tag_group in self._effective_config.tag_groups: for tag in tag_group.tags: if aux_tag in tag.aux_tag_ids: used_tags.add(aux_tag.id) return sorted(used_tags)