Ejemplo n.º 1
0
def _add_scanned_hosts_to_folder(folder: "CREFolder",
                                 found: NetworkScanFoundHosts) -> None:
    network_scan_properties = folder.attribute("network_scan")

    translation = network_scan_properties.get("translate_names", {})

    entries = []
    for host_name, ipaddr in found:
        host_name = translate_hostname(translation, host_name)

        attrs = update_metadata({}, created_by=_("Network scan"))

        if "tag_criticality" in network_scan_properties:
            attrs["tag_criticality"] = network_scan_properties.get(
                "tag_criticality", "offline")

        if network_scan_properties.get("set_ipaddress", True):
            attrs["ipaddress"] = ipaddr

        if not Host.host_exists(host_name):
            entries.append((host_name, attrs, None))

    with store.lock_checkmk_configuration():
        folder.create_hosts(entries)
        folder.save()
Ejemplo n.º 2
0
 def _init_new_host_object(cls):
     return Host(
         folder=Folder.current(),
         host_name=request.var("host"),
         attributes={},
         cluster_nodes=[],
     )
Ejemplo n.º 3
0
def bulk_delete(params):
    """Bulk delete hosts"""
    user.need_permission("wato.edit")
    body = params["body"]
    for host_name in body["entries"]:
        host = Host.load_host(host_name)
        host.folder().delete_hosts([host.name()], automation=delete_hosts)
    return Response(status=204)
Ejemplo n.º 4
0
 def is_ineffective(self):
     hosts = Host.all()
     for host_name, host in hosts.items():
         if self.matches_host_and_item(host.folder(),
                                       host_name,
                                       service_description=None):
             return False
     return True
Ejemplo n.º 5
0
def delete(params):
    """Delete a host"""
    user.need_permission("wato.edit")
    host_name = params["host_name"]
    # Parameters can't be validated through marshmallow yet.
    check_hostname(host_name, should_exist=True)
    host: CREHost = Host.load_host(host_name)
    host.folder().delete_hosts([host.name()], automation=delete_hosts)
    return Response(status=204)
Ejemplo n.º 6
0
def show_host(params) -> Response:
    """Show a host"""
    host = Host.load_host(params["host_name"])
    return constructors.serve_json(
        {
            "site": host.site_id(),
            "is_cluster": host.is_cluster(),
        }
    )
Ejemplo n.º 7
0
    def _get_cluster_nodes(self):
        if not self._is_cluster():
            return None

        cluster_nodes = self._vs_cluster_nodes().from_html_vars("nodes")
        self._vs_cluster_nodes().validate_value(cluster_nodes, "nodes")
        if len(cluster_nodes) < 1:
            raise MKUserError("nodes_0",
                              _("The cluster must have at least one node"))

        # Fake a cluster host in order to get calculated tag groups via effective attributes...
        cluster_computed_datasources = cmk.utils.tags.compute_datasources(
            Host(
                Folder.current(),
                self._host.name(),
                collect_attributes("cluster", new=False),
                [],
            ).tag_groups())

        for nr, cluster_node in enumerate(cluster_nodes):
            if cluster_node == self._host.name():
                raise MKUserError(
                    "nodes_%d" % nr,
                    _("The cluster can not be a node of it's own"))

            if not Host.host_exists(cluster_node):
                raise MKUserError(
                    "nodes_%d" % nr,
                    _("The node <b>%s</b> does not exist "
                      " (must be a host that is configured with WATO)") %
                    cluster_node,
                )

            node_computed_datasources = cmk.utils.tags.compute_datasources(
                Host.load_host(cluster_node).tag_groups())

            if datasource_differences := cluster_computed_datasources.get_differences_to(
                    node_computed_datasources):
                raise MKUserError(
                    "nodes_%d" % nr,
                    _("Cluster and nodes must have the same datasource. ") +
                    self._format_datasource_differences(
                        cluster_node, datasource_differences),
                )
Ejemplo n.º 8
0
    def is_ineffective(self):
        """Whether or not this rule does not match at all

        Interesting: This has always tried host matching. Whether or not a service ruleset
        does not match any service has never been tested. Probably because this would be
        too expensive."""
        hosts = Host.all()
        for host_name, host in hosts.items():
            if self.matches_host_conditions(host.folder(), host_name):
                return False
        return True
Ejemplo n.º 9
0
    def _validate(self, value):
        super()._validate(value)

        # Regex gets checked through the `pattern` of the String instance

        if self._should_exist is not None:
            host = Host.host(value)
            if self._should_exist and not host:
                raise self.make_error("should_exist", host_name=value)

            if not self._should_exist and host:
                raise self.make_error("should_not_exist", host_name=value)

        if self._should_be_cluster is not None and (
                host := Host.host(value)) is not None:
            if self._should_be_cluster and not host.is_cluster():
                raise self.make_error("should_be_cluster", host_name=value)

            if not self._should_be_cluster and host.is_cluster():
                raise self.make_error("should_not_be_cluster", host_name=value)
Ejemplo n.º 10
0
    def _get_hosts_from_request(self, request: Dict) -> List[DiscoveryHost]:
        if not request["hostnames"]:
            raise MKUserError(None, _("You have to specify some hosts"))

        hosts_to_discover = []
        for host_name in request["hostnames"]:
            host = Host.host(host_name)
            if host is None:
                raise MKUserError(None, _("The host '%s' does not exist") % host_name)
            host.need_permission("write")
            hosts_to_discover.append(DiscoveryHost(host.site_id(), host.folder().path(), host_name))
        return hosts_to_discover
Ejemplo n.º 11
0
def _get_object_reference(
        object_ref: Optional[ObjectRef]
) -> Tuple[Optional[str], Optional[str]]:
    if object_ref is None:
        return None, None

    if object_ref.object_type is ObjectRefType.Host:
        host = Host.host(object_ref.ident)
        if host:
            return host.edit_url(), host.name()
        return None, object_ref.ident

    if object_ref.object_type is ObjectRefType.Folder:
        if Folder.folder_exists(object_ref.ident):
            folder = Folder.folder(object_ref.ident)
            return folder.url(), folder.title()
        return None, object_ref.ident

    if object_ref.object_type is ObjectRefType.User:
        url = makeuri_contextless(
            request,
            [
                ("mode", "edit_user"),
                ("edit", object_ref.ident),
            ],
            filename="wato.py",
        )
        return url, object_ref.ident

    if object_ref.object_type is ObjectRefType.Rule:
        url = makeuri_contextless(
            request,
            [
                ("mode", "edit_rule"),
                ("varname", object_ref.labels["ruleset"]),
                ("rule_id", object_ref.ident),
            ],
            filename="wato.py",
        )
        return url, object_ref.ident

    if object_ref.object_type is ObjectRefType.Ruleset:
        url = makeuri_contextless(
            request,
            [
                ("mode", "edit_ruleset"),
                ("varname", object_ref.ident),
            ],
            filename="wato.py",
        )
        return url, object_ref.ident

    return None, object_ref.ident
Ejemplo n.º 12
0
def create_host(params):
    """Create a host"""
    user.need_permission("wato.edit")
    body = params["body"]
    host_name = body["host_name"]
    folder: CREFolder = body["folder"]

    # is_cluster is defined as "cluster_hosts is not None"
    folder.create_hosts([(host_name, body["attributes"], None)],
                        bake_hosts=params[BAKE_AGENT_PARAM_NAME])

    host = Host.load_host(host_name)
    return _serve_host(host, False)
Ejemplo n.º 13
0
def prepare_hosts_for_discovery(
        hostnames: Sequence[str]) -> List[DiscoveryHost]:
    hosts_to_discover = []
    for host_name in hostnames:
        host = Host.host(host_name)
        if host is None:
            raise MKUserError(None,
                              _("The host '%s' does not exist") % host_name)
        host.need_permission("write")
        hosts_to_discover.append(
            DiscoveryHost(host.site_id(),
                          host.folder().path(), host_name))
    return hosts_to_discover
Ejemplo n.º 14
0
def _known_ip_addresses():
    addresses = set()

    for host in Host.all().values():
        attributes = host.attributes()

        address = attributes.get("ipaddress")
        if address:
            addresses.add(address)

        addresses.update(attributes.get("additional_ipv4addresses", []))

    return addresses
Ejemplo n.º 15
0
    def action(self) -> ActionResult:
        folder = Folder.current()
        if not transactions.check_transaction():
            return redirect(mode_url("folder", folder=folder.path()))

        if request.var("_update_dns_cache") and self._should_use_dns_cache():
            user.need_permission("wato.update_dns_cache")
            update_dns_cache_result = update_dns_cache(self._host.site_id())
            infotext = (_("Successfully updated IP addresses of %d hosts.") %
                        update_dns_cache_result.n_updated)
            if update_dns_cache_result.failed_hosts:
                infotext += "<br><br><b>Hostnames failed to lookup:</b> " + ", ".join(
                    [
                        "<tt>%s</tt>" % h
                        for h in update_dns_cache_result.failed_hosts
                    ])
            flash(infotext)
            return None

        if request.var("delete"):  # Delete this host
            folder.delete_hosts([self._host.name()], automation=delete_hosts)
            return redirect(mode_url("folder", folder=folder.path()))

        if request.var("_remove_tls_registration"):
            remove_tls_registration(
                {self._host.site_id(): [self._host.name()]})
            return None

        attributes = collect_attributes(
            "host" if not self._is_cluster() else "cluster", new=False)
        host = Host.host(self._host.name())
        if host is None:
            flash(f"Host {self._host.name()} could not be found.")
            return None

        host.edit(attributes, self._get_cluster_nodes())
        self._host = folder.load_host(self._host.name())

        if request.var("_save"):
            return redirect(
                mode_url("inventory",
                         folder=folder.path(),
                         host=self._host.name()))
        if request.var("diag_host"):
            return redirect(
                mode_url("diag_host",
                         folder=folder.path(),
                         host=self._host.name(),
                         _start_on_load="1"))
        return redirect(mode_url("folder", folder=folder.path()))
Ejemplo n.º 16
0
def update_service_phase(params) -> Response:
    """Update the phase of a service"""
    body = params["body"]
    host = Host.load_host(params["host_name"])
    target_phase = body["target_phase"]
    check_type = body["check_type"]
    service_item = body["service_item"]
    _update_single_service_phase(
        SERVICE_DISCOVERY_PHASES[target_phase],
        host,
        check_type,
        service_item,
    )
    return Response(status=204)
Ejemplo n.º 17
0
def create_cluster_host(params):
    """Create a cluster host

    A cluster host groups many hosts (called nodes in this context) into a conceptual cluster.
    All the services of the individual nodes will be collated on the cluster host."""
    user.need_permission("wato.edit")
    body = params["body"]
    host_name = body["host_name"]
    folder: CREFolder = body["folder"]

    folder.create_hosts([(host_name, body["attributes"], body["nodes"])],
                        bake_hosts=params[BAKE_AGENT_PARAM_NAME])

    host = Host.load_host(host_name)
    return _serve_host(host, effective_attributes=False)
Ejemplo n.º 18
0
def config_hostname_autocompleter(value: str, params: Dict) -> Choices:
    """Return the matching list of dropdown choices
    Called by the webservice with the current input field value and the completions_params to get the list of choices"""
    all_hosts: Dict[str, CREHost] = Host.all()
    match_pattern = re.compile(value, re.IGNORECASE)
    match_list: Choices = []
    for host_name, host_object in all_hosts.items():
        if match_pattern.search(host_name) is not None and host_object.may(
                "read"):
            match_list.append((host_name, host_name))

    if not any(x[0] == value for x in match_list):
        match_list.insert(
            0, (value, value))  # User is allowed to enter anything they want

    return match_list
Ejemplo n.º 19
0
    def deserialize(cls, serialized: Dict[str, Any]) -> 'SiteRequest':
        enforce_host = EnforcedHostRequest(
            **serialized["enforce_host"]) if serialized["enforce_host"] else None

        if enforce_host:
            host = Host.host(enforce_host.host_name)
            if host is None:
                raise MKGeneralException(
                    _("Host %s does not exist on remote site %s. This "
                      "may be caused by a failed configuration synchronization. Have a look at "
                      "the <a href=\"wato.py?folder=&mode=changelog\">activate changes page</a> "
                      "for further information.") % (enforce_host.host_name, enforce_host.site_id))
            host.need_permission("read")

        newest_host_labels = serialized["newest_host_labels"]
        assert isinstance(newest_host_labels, float)
        return cls(newest_host_labels, enforce_host)
Ejemplo n.º 20
0
def update_nodes(params):
    """Update the nodes of a cluster host"""
    user.need_permission("wato.edit")
    user.need_permission("wato.edit_hosts")
    host_name = params["host_name"]
    body = params["body"]
    nodes = body["nodes"]
    host: CREHost = Host.load_host(host_name)
    _require_host_etag(host)
    host.edit(host.attributes(), nodes)

    return constructors.serve_json(
        constructors.object_sub_property(
            domain_type="host_config",
            ident=host_name,
            name="nodes",
            value=host.cluster_nodes(),
        ))
Ejemplo n.º 21
0
def bulk_update_hosts(params):
    """Bulk update hosts

    Please be aware that when doing bulk updates, it is not possible to prevent the
    [Updating Values]("lost update problem"), which is normally prevented by the ETag locking
    mechanism. Use at your own risk.
    """
    user.need_permission("wato.edit")
    user.need_permission("wato.edit_hosts")
    body = params["body"]
    entries = body["entries"]

    succeeded_hosts: List[CREHost] = []
    failed_hosts: Dict[HostName, str] = {}
    for update_detail in entries:
        host_name = update_detail["host_name"]
        new_attributes = update_detail["attributes"]
        update_attributes = update_detail["update_attributes"]
        remove_attributes = update_detail["remove_attributes"]
        check_hostname(host_name)
        host: CREHost = Host.load_host(host_name)
        if new_attributes:
            host.edit(new_attributes, None)

        if update_attributes:
            host.update_attributes(update_attributes)

        faulty_attributes = []
        for attribute in remove_attributes:
            if not host.has_explicit_attribute(attribute):
                faulty_attributes.append(attribute)

        if faulty_attributes:
            failed_hosts[
                host_name] = f"Failed to remove {', '.join(faulty_attributes)}"
            continue

        if remove_attributes:
            host.clean_attributes(remove_attributes)

        succeeded_hosts.append(host)

    return _bulk_host_action_response(failed_hosts, succeeded_hosts)
Ejemplo n.º 22
0
    def _renaming_collision_error(self, renamings):
        name_collisions = set()
        new_names = [new_name for _folder, _old_name, new_name in renamings]
        all_host_names = Host.all().keys()
        for name in new_names:
            if name in all_host_names:
                name_collisions.add(name)
        for name in new_names:
            if new_names.count(name) > 1:
                name_collisions.add(name)

        if name_collisions:
            warning = "<b>%s</b><ul>" % _(
                "You cannot do this renaming since the following host names would collide:"
            )
            for name in sorted(list(name_collisions)):
                warning += "<li>%s</li>" % name
            warning += "</ul>"
            return warning
        return None
Ejemplo n.º 23
0
def show_services(params) -> Response:
    """Show all services of specific phase"""
    host = Host.load_host(params["host_name"])
    discovery_request = StartDiscoveryRequest(
        host=host,
        folder=host.folder(),
        options=DiscoveryOptions(
            action="",
            show_checkboxes=False,
            show_parameters=False,
            show_discovered_labels=False,
            show_plugin_names=False,
            ignore_errors=True,
        ),
    )
    discovery_result = get_check_table(discovery_request)
    return _serve_services(
        host,
        discovery_result.check_table,
        [params["discovery_phase"]],
    )
Ejemplo n.º 24
0
def execute(params) -> Response:
    """Execute a service discovery on a host"""
    host = Host.load_host(params["host_name"])
    body = params["body"]
    discovery_request = StartDiscoveryRequest(
        host=host,
        folder=host.folder(),
        options=DiscoveryOptions(
            action=DISCOVERY_ACTION[body["mode"]],
            show_checkboxes=False,
            show_parameters=False,
            show_discovered_labels=False,
            show_plugin_names=False,
            ignore_errors=True,
        ),
    )
    discovery_result = get_check_table(discovery_request)
    return _serve_services(
        host,
        discovery_result.check_table,
        list(SERVICE_DISCOVERY_PHASES.keys()),
    )
Ejemplo n.º 25
0
def update_host(params):
    """Update a host"""
    user.need_permission("wato.edit")
    user.need_permission("wato.edit_hosts")
    host_name = params["host_name"]
    body = params["body"]
    new_attributes = body["attributes"]
    update_attributes = body["update_attributes"]
    remove_attributes = body["remove_attributes"]
    check_hostname(host_name, should_exist=True)
    host: CREHost = Host.load_host(host_name)
    _require_host_etag(host)

    if new_attributes:
        new_attributes["meta_data"] = host.attributes().get("meta_data", {})
        host.edit(new_attributes, None)

    if update_attributes:
        host.update_attributes(update_attributes)

    faulty_attributes = []
    for attribute in remove_attributes:
        if not host.has_explicit_attribute(attribute):
            faulty_attributes.append(attribute)

    if remove_attributes:
        host.clean_attributes(
            remove_attributes)  # silently ignores missing attributes

    if faulty_attributes:
        return problem(
            status=400,
            title="Some attributes were not removed",
            detail=
            f"The following attributes were not removed since they didn't exist: {', '.join(faulty_attributes)}",
        )

    return _serve_host(host, effective_attributes=False)
Ejemplo n.º 26
0
def validate_host_parents(host):
    for parent_name in host.parents():
        if parent_name == host.name():
            raise MKUserError(
                None,
                _("You configured the host to be it's own parent, which is not allowed."
                  ))

        parent = Host.host(parent_name)
        if not parent:
            raise MKUserError(
                None,
                _("You defined the non-existing host '%s' as a parent.") %
                parent_name)

        if host.site_id() != parent.site_id():
            raise MKUserError(
                None,
                _("The parent '%s' is monitored on site '%s' while the host itself "
                  "is monitored on site '%s'. Both must be monitored on the same site. Remember: The parent/child "
                  "relation is used to describe the reachability of hosts by one monitoring daemon."
                  ) % (parent_name, parent.site_id(), host.site_id()),
            )
Ejemplo n.º 27
0
def rename_host(params):
    """Rename a host"""
    user.need_permission("wato.edit")
    user.need_permission("wato.rename_hosts")
    if activate_changes.get_pending_changes_info():
        return problem(
            status=409,
            title="Pending changes are present",
            detail=
            "Please activate all pending changes before executing a host rename process",
        )
    host_name = params["host_name"]
    host: CREHost = Host.load_host(host_name)
    new_name = params["body"]["new_name"]
    _, auth_problems = perform_rename_hosts([(host.folder(), host_name,
                                              new_name)])
    if auth_problems:
        return problem(
            status=422,
            title="Rename process failed",
            detail=
            f"It was not possible to rename the host {host_name} to {new_name}",
        )
    return _serve_host(host, effective_attributes=False)
Ejemplo n.º 28
0
def perform_rename_hosts(renamings, job_interface=None):
    """Rename hosts mechanism

    Args:
        renamings:
            tuple consisting of folder, oldname, newname

        job_interface:
            only relevant for WATO interaction, allows to update the interface with the current
            update info
    """

    def update_interface(message: str) -> None:
        if job_interface is None:
            return
        job_interface.send_progress_update(message)

    actions = []
    all_hosts = Host.all()

    # 1. Fix WATO configuration itself ----------------
    auth_problems = []
    successful_renamings = []
    update_interface(_("Renaming WATO configuration..."))
    for folder, oldname, newname in renamings:
        try:
            this_host_actions = []
            update_interface(_("Renaming host(s) in folders..."))
            this_host_actions += _rename_host_in_folder(folder, oldname, newname)
            update_interface(_("Renaming host(s) in cluster nodes..."))
            this_host_actions += _rename_host_as_cluster_node(all_hosts, oldname, newname)
            update_interface(_("Renaming host(s) in parents..."))
            this_host_actions += _rename_host_in_parents(oldname, newname)
            update_interface(_("Renaming host(s) in rulesets..."))
            this_host_actions += _rename_host_in_rulesets(folder, oldname, newname)
            update_interface(_("Renaming host(s) in BI aggregations..."))
            this_host_actions += _rename_host_in_bi(oldname, newname)
            actions += this_host_actions
            successful_renamings.append((folder, oldname, newname))
        except MKAuthException as e:
            auth_problems.append((oldname, e))

    # 2. Checkmk stuff ------------------------------------------------
    update_interface(_("Renaming host(s) in base configuration, rrd, history files, etc."))
    update_interface(_("This might take some time and involves a core restart..."))
    action_counts = _rename_hosts_in_check_mk(successful_renamings)

    # 3. Notification settings ----------------------------------------------
    # Notification rules - both global and users' ones
    update_interface(_("Renaming host(s) in notification rules..."))
    for folder, oldname, newname in successful_renamings:
        actions += _rename_host_in_event_rules(oldname, newname)
        actions += _rename_host_in_multisite(oldname, newname)

    for action in actions:
        action_counts.setdefault(action, 0)
        action_counts[action] += 1

    update_interface(_("Calling final hooks"))
    call_hook_hosts_changed(Folder.root_folder())
    return action_counts, auth_problems
Ejemplo n.º 29
0
def show_host(params):
    """Show a host"""
    host_name = params["host_name"]
    host: CREHost = Host.load_host(host_name)
    return _serve_host(host,
                       effective_attributes=params["effective_attributes"])
Ejemplo n.º 30
0
 def is_ineffective(self):
     hosts = Host.all()
     for host_name, host in hosts.items():
         if self.matches_host_and_item(host.folder(), host_name, NO_ITEM):
             return False
     return True