Ejemplo n.º 1
0
class EchoCmd(HumanCallableCommandWithArgs):
    """Echo command"""

    CMD = "echo"
    ARGS = (arguments.String("text", "Input text"), )

    async def _execute(self):
        """Your pretty business logic is here ! :)"""
        await self.send_message(text=f"Your text is: '{self.text}'")
Ejemplo n.º 2
0
class TestDifferentBehaviorAdmin(HumanCallableCommandWithArgs):
    """Тестовая команда с разным поведением для админа и юзверя - вы админ"""

    ARGS = (arguments.String("adminArg", "админский аргумент"),)

    async def _execute(self):
        await self.send_message(
            subject=f"Вы админ. Ваш аргумент: {self.adminArg}",
        )
class ClassForTesting(HumanCallableCommandWithArgs):
    """Тестовая команда"""

    CMD = "test"
    ARGS = (
        arguments.String("arg1", "description 1"),
        arguments.String("arg2", "description 2"),
    )

    def _execute(self):
        ...

    def _validate(self):
        wrong_arguments = []
        if self.arg1 != ARG1_VALID:
            wrong_arguments.append(self.arg1)
        if self.arg2 != ARG2_VALID:
            wrong_arguments.append(self.arg2)
        return wrong_arguments
Ejemplo n.º 4
0
class TestTakeUserId(HumanCallableCommandWithArgs):
    """Возвращает ID пользователя телеграм"""

    CMD = "giveMeMyId"
    ARGS = (
        arguments.MyUser("user", "ID подписчика данного канала"),
        arguments.String("string", "какая-то строка"),
    )

    async def _execute(self):
        await self.send_message(subject=f"Получен ID {self.user}")
        class _ClassForTesting(HumanCallableCommandWithArgs):
            """Тестовая команда"""

            CMD = "test"
            ARGS = (
                arguments.Integer("arg1", "description 1", default=1),
                arguments.String("arg2", "description 2", default=2),
            )

            def _execute(self):
                ...
Ejemplo n.º 6
0
class TakeListWithArg(HumanCallableCommandWithArgs):
    """Получает обычный аргумент и список"""

    CMD = "argAndList"
    ARGS = (
        arguments.String("string", "Какая-то строка"),
        arguments.ListArg("listarg", "Какой-то список"),
    )

    async def _execute(self):
        await self.send_message(
            text=f"Получили такой аргумент: {self.string}\nи такой список: {self.listarg}"
        )
Ejemplo n.º 7
0
class TestHumanCallableCommandWithArgsChoose(HumanCallableCommandWithArgs):
    """Тестовая команда с выбором аргументов"""

    CMD = "HumanCallableChoose"
    ARGS = (
        arguments.String(
            "test_arg", "Тестовый аргумент с возможностью выбора", options=["val1", "val2", "val3"]
        ),
    )

    async def _execute(self):
        message = f"Вы выбрали test_arg = {self.test_arg}"
        await self.send_message(text=message)
Ejemplo n.º 8
0
class GetGraph(ZabbixCallableCommandWithArgs, WebInterfaceCommandMixin):
    """
    Get a graph of the values of an item.
    """
    CMD = 'graph'

    ARGS = (arguments.String("source",
                             "Data source",
                             example="item, graph",
                             options=["item", "graph"],
                             allow_options=True),
            arguments.Integer("item_id", "Item ID", example="Integer"),
            arguments.Integer("period",
                              "Period of interest in hours",
                              example="integer",
                              default=1,
                              options=[1, 2, 4, 8, 12, 24],
                              maximum=100))

    async def _execute(self):

        if self.source == "item":
            graphs_params = self.prepare_query_params(item_id=self.item_id,
                                                      period=self.period)
            template = load_template('get_items.json')
            template["params"]["itemids"] = self.item_id
        else:
            # self.source уже провалидирован на нужные значения
            graphs_params = self.prepare_query_params(graph_id=self.item_id,
                                                      period=self.period)
            template = load_template('get_graph.json')
            template["params"]["graphids"] = self.item_id

        # Узнаем название Item и Host
        element_info = await self.get_data_from_zabbix_api(template)
        try:
            element_name = element_info["result"][0]["name"]
            host_name = element_info["result"][0]["hosts"][0]["host"]
            subject = f"{host_name} - {element_name}\n"
            message_body = f">>repeat<< {self.reverse_command(self.__class__, self.source, self.item_id)}"
        except IndexError:
            subject = f">>WARNING<< No {self.source} for id {self.item_id}"
            message_body = ""

        graph = await self.load_graph(graphs_params, self.source)

        await self.send_message(subject=subject,
                                text=message_body,
                                images=[
                                    graph,
                                ])
Ejemplo n.º 9
0
class TestHumanCallableCommandWithArgs(HumanCallableCommandWithArgs):
    """Тестовая вызываемая команда с аргументами"""

    CMD = "HumanCallableArgs"
    ARGS = (
        arguments.Integer("arg1", "Тестовый аргумент из чисел", example="123"),
        arguments.String("arg2", "Тестовый аргумент из букв", example="abc"),
    )

    def _validate(self) -> list:
        wrong_commands = list()
        if not self.arg1.isdigit():
            wrong_commands.append(self.arg1)
        if not self.arg2.isalpha():
            wrong_commands.append(self.arg2)
        return wrong_commands

    async def _execute(self):
        await self.send_message(
            subject=">>info<< Test message with args",
            text=f"Arg with digits: {self.arg1}; Arg with words: {self.arg2}",
        )
Ejemplo n.º 10
0
class GetProblemTriggers(ZabbixCallableCommandWithArgs):
    """ Get information about triggers in a problem state """
    JSON_TMPL_FILE = 'get_all_problem_triggers.json'
    CMD = 'badtriggers'
    LINES = load_template('host_info.json')
    MAX_PRIORITY = 5
    ARGS = (arguments.String("direction",
                             "Filter condition",
                             default="ge",
                             options=['≤', '=', '≥'],
                             allowed=['≤', '=', '≥', 'le', 'eq', 'ge']),
            arguments.Integer("priority",
                              "Trigger Priority Lower Bound",
                              example="0 - 5",
                              default="1",
                              options=[i for i in range(MAX_PRIORITY + 1)],
                              allow_options=True),
            arguments.String("hostname",
                             "Filtering triggers by hostname",
                             example="Line1, Line4, All..",
                             default='All',
                             options=[line for line in LINES] + ['All']))

    # Для кнопок нужны красивые символы,
    # но их невозможно передать в макросах команд
    directions_translator = {
        '≤': 'le',
        '=': 'eq',
        '≥': 'ge',
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.zabbix_line_host = ""  # настоящее имя хоста в Zabbix для обращений по API
        self.hostname = self.hostname.strip().lower(
        )  # Зарегистрированное в 'host_info.json' имя
        # (для красоты кнопочек)
        self.LINES = {
            key.strip().lower(): value
            for key, value in self.LINES.items()
        }

    def _set_hostname(self):
        if self.hostname != 'all':
            # Отображаемые имена хостов (с большой буквы) и действительные
            # подгружаем из 'host_info.json'
            self.zabbix_line_host = self.LINES[self.hostname]['host']
            # В шаблон запроса к Zabbix-API подставляем действительное
            # имя хоста в Zabbix
            self.template['params']['host'] = self.zabbix_line_host
        else:
            # если нужно получить информацию для всех хостов - не трогаем шаблон.
            # В шаблоне значение - null. Т.е. без фильтрации по хостам.
            self.zabbix_line_host = self.hostname

    def _set_direction(self) -> None:
        # TODO: unittest
        """
        Устанавливает служебное-строковое значение directions и
        то, которое показывается пользователю
        """
        try:
            self.direction_str = self.directions_translator[self.direction]
        except KeyError:
            directions_translator_back = {
                value: key
                for key, value in self.directions_translator.items()
            }
            # На этом моменте должна быть пройдена валидация,
            # и self.direction - либо ключ, либо значение из словаря directions_translator
            self.direction_str, self.direction = \
                self.direction, directions_translator_back[self.direction]

    def _set_priority(self) -> None:
        # TODO: unittest
        priority = int(self.priority)
        priority_switch = {
            'le': lambda: list(range(priority + 1)),
            'eq': lambda: [
                priority,
            ],
            'ge': lambda: list(range(priority, self.MAX_PRIORITY + 1)),
        }
        priorities = priority_switch[self.direction_str]()
        self.template['params']['filter']['priority'] = priorities

    def _set_subject(self, host) -> str:
        subject = f"Problem triggers for priority {self.direction} {self.priority}, " \
                  f"host: {host if host else 'All'}"
        return subject

    async def _execute(self):
        self._set_hostname()
        self._set_direction()
        self._set_priority()

        problem_triggers_request = await self.get_data_from_zabbix_api(
            self.template)

        subject = self._set_subject(self.zabbix_line_host)

        problem_triggers_message = self.format_triggers_info(
            problem_triggers_request)

        await self.send_message(subject=subject, text=problem_triggers_message)

    def _validate(self) -> list:
        wrong_arguments = list()
        if self.hostname.lower() == 'all':
            return wrong_arguments
        if self.hostname.lower() not in self.LINES:
            wrong_arguments.append(self.hostname)
        return wrong_arguments
Ejemplo n.º 11
0
class GetHostInfo(ZabbixCallableCommandWithArgs, WebInterfaceCommandMixin):
    """ Get info about Host """
    CMD = "hostinfo"
    JSON_TMPL_FILE = 'host_info.json'
    HOSTS = {
        key.capitalize(): value
        for key, value in load_json_template(
            JSON_TMPL_FILE, ZabbixCallableCommand.PATH_TO_FILE).items()
    }
    ARGS = (arguments.String("host_name",
                             "Zabbix host name",
                             example="Line1",
                             options=list(HOSTS.keys())), )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Отображать названия линий на кнопках надо с большой буквы,
        # но работать команда должна при любом регистре атрибутов
        self.host_name = self.host_name.strip().lower()
        self.template = {
            key.strip().lower(): value
            for key, value in self.template.items()
        }

    async def _execute(self):
        template = self.template[self.host_name]
        host = template["host"]
        message_subject = f"Host info for {host}"
        message_body = ""
        main_image = None

        # Есть сработавшие триггеры? Если да - добавляем кнопки
        triggers_template = load_template('get_all_problem_triggers.json')
        triggers_template["params"]["host"] = host
        triggers = await self.get_data_from_zabbix_api(triggers_template)
        triggers = triggers['result']

        info_triggers = list(
            filter(lambda x: int(x['priority']) <= 2, triggers))
        problem_triggers = list(
            filter(lambda x: int(x['priority']) > 2, triggers))

        if problem_triggers:
            message_body += \
                f">>fire<< <i>Problem-triggers: <b>{len(problem_triggers)}</b></i>\n"
            self.add_inline_button(GetProblemTriggers, ">>fire<< Bad Triggers",
                                   "ge", "3", self.host_name)
        else:
            message_body += \
                f">>OK<< <i>No problems on line</i>\n"

        message_body += \
            f">>info<< <i>Info-triggers: <b>{len(info_triggers)}</b></i>\n"
        if info_triggers:
            self.add_inline_button(GetProblemTriggers,
                                   ">>info<< Info Triggers", "le", "2",
                                   self.host_name)

        # Zabbix items? Если да - добавляем их в текст
        if template["items"]:
            items_template = load_json_template(
                'get_items.json', ZabbixCallableCommand.PATH_TO_FILE)
            items_template["params"]["itemids"] = template["items"]
            items = await self.get_data_from_zabbix_api(items_template)
            items = self.format_items_info(items)

            message_body += "\n<b>Items overview:</b>\n"
            message_body += items

        # Изображение в сообщении?
        if template["main_image"]:
            image_type = template["main_image"]["source"]
            element_id = template["main_image"]["id"]
            if image_type == "graph":
                graph_params = self.prepare_query_params(graph_id=element_id)
                main_image = await self.load_graph(graph_params, image_type)
            elif image_type == "item":
                graph_params = self.prepare_query_params(item_id=element_id)
                main_image = await self.load_graph(graph_params, image_type)
            else:
                _LOGGER.warning("Wrong image type!")
                # Типы графиков указываются в шаблоне команды
                raise BadCommandTemplateException(self.TMPL_FILE)

            message_body += "\n<b>Graph:</b>\n"
            message_body += f">>lupa<< 2h:: {self.reverse_command(GetGraph, image_type, element_id, '2')}\n"
            message_body += f">>lupa<< 4h:: {self.reverse_command(GetGraph, image_type, element_id, '4')}\n"

        message_body += f"\n>>repeat<< {self.reverse_command(GetHostInfo, self.host_name)}"

        # Добавляем кнопки для всех графиков
        for graph_name, graph_id in template["graphs"].items():
            self.add_inline_button(GetGraph, f">>graph1<< {graph_name}",
                                   "graph", graph_id)
        for item_name, item_id in template["item_graphs"].items():
            self.add_inline_button(GetGraph, f">>graph2<< {item_name}", "item",
                                   item_id)

        await self.send_message(subject=message_subject,
                                text=message_body,
                                images=[
                                    main_image,
                                ],
                                reply_markup=self.inline_buttons)

    def _validate(self) -> list:
        wrong_commands = list()
        if self.host_name.capitalize() not in self.HOSTS:
            wrong_commands.append(self.host_name)
        return wrong_commands