示例#1
0
class ModeBulkDiscovery(WatoMode):
    @classmethod
    def name(cls):
        return "bulkinventory"

    @classmethod
    def permissions(cls):
        return ["hosts", "services"]

    @classmethod
    def parent_mode(cls) -> Optional[Type[WatoMode]]:
        return ModeFolder

    def _from_vars(self):
        self._start = bool(request.var("_save"))
        self._all = bool(request.var("all"))
        self._just_started = False
        self._get_bulk_discovery_params()
        self._job = BulkDiscoveryBackgroundJob()

    def _get_bulk_discovery_params(self):
        self._bulk_discovery_params = copy.deepcopy(config.bulk_discovery_default_settings)

        if self._start:
            # Only do this when the start form has been submitted
            bulk_discover_params = vs_bulk_discovery().from_html_vars("bulkinventory")
            vs_bulk_discovery().validate_value(bulk_discover_params, "bulkinventory")
            self._bulk_discovery_params.update(bulk_discover_params)

        # The cast is needed for the moment, because mypy does not understand our data structure here
        (self._recurse, self._only_failed, self._only_failed_invcheck, self._only_ok_agent) = cast(
            Tuple[bool, bool, bool, bool], self._bulk_discovery_params["selection"]
        )

        self._do_scan, self._bulk_size = self._get_performance_params()
        self._mode = self._bulk_discovery_params["mode"]
        self._error_handling = self._bulk_discovery_params["error_handling"]

    def _get_performance_params(self) -> Tuple[bool, int]:
        performance_params = self._bulk_discovery_params["performance"]
        assert isinstance(performance_params, tuple)

        if len(performance_params) == 3:
            # In previous Checkmk versions (< 2.0) there was a third performance parameter:
            # 'use_cache' in the first place.
            do_scan, bulk_size = performance_params[1:]
        else:
            do_scan, bulk_size = performance_params

        assert isinstance(do_scan, bool)
        assert isinstance(bulk_size, int)
        return do_scan, bulk_size

    def title(self):
        return _("Bulk discovery")

    def page_menu(self, breadcrumb: Breadcrumb) -> PageMenu:
        return make_simple_form_page_menu(
            _("Discovery"),
            breadcrumb,
            form_name="bulkinventory",
            button_name="_save",
            save_title=_("Start"),
        )

    def action(self) -> ActionResult:
        user.need_permission("wato.services")

        tasks = get_tasks(self._get_hosts_to_discover(), self._bulk_size)

        try:
            transactions.check_transaction()
            self._job.set_function(
                self._job.do_execute, self._mode, self._do_scan, self._error_handling, tasks
            )
            self._job.start()
        except Exception as e:
            if config.debug:
                raise
            logger.exception("Failed to start bulk discovery")
            raise MKUserError(
                None, _("Failed to start discovery: %s") % ("%s" % e).replace("\n", "\n<br>")
            )

        raise HTTPRedirect(self._job.detail_url())

    def page(self):
        user.need_permission("wato.services")

        job_status_snapshot = self._job.get_status_snapshot()
        if job_status_snapshot.is_active():
            html.show_message(
                _('Bulk discovery currently running in <a href="%s">background</a>.')
                % self._job.detail_url()
            )
            return

        self._show_start_form()

    def _show_start_form(self):
        html.begin_form("bulkinventory", method="POST")

        msgs = []
        if self._all:
            vs = vs_bulk_discovery(render_form=True)
        else:
            # "Include subfolders" does not make sense for a selection of hosts
            # which is already given in the following situations:
            # - in the current folder below 'Selected hosts: Discovery'
            # - Below 'Bulk import' a automatic service discovery for
            #   imported/selected hosts can be executed
            vs = vs_bulk_discovery(render_form=True, include_subfolders=False)
            msgs.append(
                _("You have selected <b>%d</b> hosts for bulk discovery.")
                % len(self._get_hosts_to_discover())
            )
            # The cast is needed for the moment, because mypy does not understand our data structure here
            selection = cast(
                Tuple[bool, bool, bool, bool], self._bulk_discovery_params["selection"]
            )
            self._bulk_discovery_params["selection"] = [False] + list(selection[1:])

        msgs.append(
            _(
                "The Checkmk discovery will automatically find and configure services "
                "to be checked on your hosts and may also discover host labels."
            )
        )
        html.open_p()
        html.write_text(" ".join(msgs))
        vs.render_input("bulkinventory", self._bulk_discovery_params)
        forms.end()

        html.hidden_fields()
        html.end_form()

    def _get_hosts_to_discover(self) -> List[DiscoveryHost]:
        if self._only_failed_invcheck:
            restrict_to_hosts = self._find_hosts_with_failed_discovery_check()
        else:
            restrict_to_hosts = None

        if self._only_ok_agent:
            skip_hosts = self._find_hosts_with_failed_agent()
        else:
            skip_hosts = []

        # 'all' not set -> only inventorize checked hosts
        hosts_to_discover = []

        if not self._all:
            filterfunc = None
            if self._only_failed:
                filterfunc = lambda host: host.discovery_failed()

            for host_name in get_hostnames_from_checkboxes(filterfunc):
                if restrict_to_hosts and host_name not in restrict_to_hosts:
                    continue
                if host_name in skip_hosts:
                    continue
                host = Folder.current().load_host(host_name)
                host.need_permission("write")
                hosts_to_discover.append(
                    DiscoveryHost(host.site_id(), host.folder().path(), host_name)
                )

        else:
            # all host in this folder, maybe recursively. New: we always group
            # a bunch of subsequent hosts of the same folder into one item.
            # That saves automation calls and speeds up mass inventories.
            entries = self._recurse_hosts(Folder.current())
            for host_name, folder in entries:
                if restrict_to_hosts is not None and host_name not in restrict_to_hosts:
                    continue
                if host_name in skip_hosts:
                    continue
                host = folder.host(host_name)
                host.need_permission("write")
                hosts_to_discover.append(
                    DiscoveryHost(host.site_id(), host.folder().path(), host_name)
                )

        return hosts_to_discover

    def _recurse_hosts(self, folder):
        entries = []
        for host_name, host in folder.hosts().items():
            if not self._only_failed or host.discovery_failed():
                entries.append((host_name, folder))
        if self._recurse:
            for subfolder in folder.subfolders():
                entries += self._recurse_hosts(subfolder)
        return entries

    def _find_hosts_with_failed_discovery_check(self):
        # Old service name "Check_MK inventory" needs to be kept because old
        # installations may still use that name
        return sites.live().query_column(
            "GET services\n"
            "Filter: description = Check_MK inventory\n"
            "Filter: description = Check_MK Discovery\n"
            "Or: 2\n"
            "Filter: state > 0\n"
            "Columns: host_name"
        )

    def _find_hosts_with_failed_agent(self):
        return sites.live().query_column(
            "GET services\n"
            "Filter: description = Check_MK\n"
            "Filter: state >= 2\n"
            "Columns: host_name"
        )
示例#2
0
class ModeBulkDiscovery(WatoMode):
    @classmethod
    def name(cls):
        return "bulkinventory"

    @classmethod
    def permissions(cls):
        return ["hosts", "services"]

    def _from_vars(self):
        self._start = bool(html.request.var("_start"))
        self._all = bool(html.request.var("all"))
        self._just_started = False
        self._get_bulk_discovery_params()
        self._job = BulkDiscoveryBackgroundJob()

    def _get_bulk_discovery_params(self):
        self._bulk_discovery_params = copy.deepcopy(
            config.bulk_discovery_default_settings)

        if self._start:
            # Only do this when the start form has been submitted
            bulk_discover_params = vs_bulk_discovery().from_html_vars(
                "bulkinventory")
            vs_bulk_discovery().validate_value(bulk_discover_params,
                                               "bulkinventory")
            self._bulk_discovery_params.update(bulk_discover_params)

        self._recurse, self._only_failed, self._only_failed_invcheck, \
            self._only_ok_agent = self._bulk_discovery_params["selection"]
        self._use_cache, self._do_scan, self._bulk_size = \
            self._bulk_discovery_params["performance"]
        self._mode = self._bulk_discovery_params["mode"]
        self._error_handling = self._bulk_discovery_params["error_handling"]

    def title(self):
        return _("Bulk Service Discovery")

    def buttons(self):
        html.context_button(_("Folder"), Folder.current().url(), "back")

    def action(self):
        config.user.need_permission("wato.services")

        tasks = get_tasks(self._get_hosts_to_discover(), self._bulk_size)

        try:
            html.check_transaction()
            self._job.set_function(self._job.do_execute, self._mode,
                                   self._use_cache, self._do_scan,
                                   self._error_handling, tasks)
            self._job.start()
        except Exception as e:
            if config.debug:
                raise
            logger.exception("Failed to start bulk discovery")
            raise MKUserError(
                None,
                _("Failed to start discovery: %s") %
                ("%s" % e).replace("\n", "\n<br>"))

        raise HTTPRedirect(self._job.detail_url())

    def page(self):
        config.user.need_permission("wato.services")

        job_status_snapshot = self._job.get_status_snapshot()
        if job_status_snapshot.is_running():
            html.message(
                _("Bulk discovery currently running in <a href=\"%s\">background</a>."
                  ) % self._job.detail_url())
            return

        self._show_start_form()

    def _show_start_form(self):
        html.begin_form("bulkinventory", method="POST")

        msgs = []
        if self._all:
            vs = vs_bulk_discovery(render_form=True)
        else:
            # "Include subfolders" does not make sense for a selection of hosts
            # which is already given in the following situations:
            # - in the current folder below 'Selected hosts: Discovery'
            # - Below 'Bulk import' a automatic service discovery for
            #   imported/selected hosts can be executed
            vs = vs_bulk_discovery(render_form=True, include_subfolders=False)
            msgs.append(
                _("You have selected <b>%d</b> hosts for bulk discovery.") %
                len(self._get_hosts_to_discover()))
            selection = self._bulk_discovery_params["selection"]
            self._bulk_discovery_params["selection"] = [False] + list(
                selection[1:])

        msgs.append(
            _("Check_MK service discovery will automatically find and "
              "configure services to be checked on your hosts."))
        html.open_p()
        html.write_text(" ".join(msgs))
        vs.render_input("bulkinventory", self._bulk_discovery_params)
        forms.end()

        html.button("_start", _("Start"))
        html.hidden_fields()
        html.end_form()

    def _get_hosts_to_discover(self):
        # type: () -> List[DiscoveryHost]
        if self._only_failed_invcheck:
            restrict_to_hosts = self._find_hosts_with_failed_discovery_check()
        else:
            restrict_to_hosts = None

        if self._only_ok_agent:
            skip_hosts = self._find_hosts_with_failed_agent()
        else:
            skip_hosts = []

        # 'all' not set -> only inventorize checked hosts
        hosts_to_discover = []

        if not self._all:
            if self._only_failed:
                filterfunc = lambda host: host.discovery_failed()
            else:
                filterfunc = None

            for host_name in get_hostnames_from_checkboxes(filterfunc):
                if restrict_to_hosts and host_name not in restrict_to_hosts:
                    continue
                if host_name in skip_hosts:
                    continue
                host = Folder.current().host(host_name)
                host.need_permission("write")
                hosts_to_discover.append(
                    DiscoveryHost(host.site_id(), host.folder(), host_name))

        else:
            # all host in this folder, maybe recursively. New: we always group
            # a bunch of subsequent hosts of the same folder into one item.
            # That saves automation calls and speeds up mass inventories.
            entries = self._recurse_hosts(Folder.current())
            for host_name, folder in entries:
                if restrict_to_hosts is not None and host_name not in restrict_to_hosts:
                    continue
                if host_name in skip_hosts:
                    continue
                host = folder.host(host_name)
                host.need_permission("write")
                hosts_to_discover.append(
                    DiscoveryHost(host.site_id(), host.folder(), host_name))

        return hosts_to_discover

    def _recurse_hosts(self, folder):
        entries = []
        for host_name, host in folder.hosts().items():
            if not self._only_failed or host.discovery_failed():
                entries.append((host_name, folder))
        if self._recurse:
            for subfolder in folder.all_subfolders().values():
                entries += self._recurse_hosts(subfolder)
        return entries

    def _find_hosts_with_failed_discovery_check(self):
        # Old service name "Check_MK inventory" needs to be kept because old
        # installations may still use that name
        return sites.live().query_column(
            "GET services\n"
            "Filter: description = Check_MK inventory\n"
            "Filter: description = Check_MK Discovery\n"
            "Or: 2\n"
            "Filter: state > 0\n"
            "Columns: host_name")

    def _find_hosts_with_failed_agent(self):
        return sites.live().query_column("GET services\n"
                                         "Filter: description = Check_MK\n"
                                         "Filter: state >= 2\n"
                                         "Columns: host_name")