Инструменты пользователя

Инструменты сайта


develop:pyton:practics

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Следующая версия
Предыдущая версия
develop:pyton:practics [2023/12/08 15:21]
admin создано
develop:pyton:practics [2024/07/15 05:32] (текущий)
admin
Строка 3: Строка 3:
  
 ===== Seller ===== ===== Seller =====
- 
- 
  
 <details> <details>
Строка 46: Строка 44:
  
  
 +
 +<details>
 +<summary>:!: Работа со словарями</summary>
  
 <code python> <code python>
 +  # Сортировка по значению
 +dict_result_successed = dict(sorted( dict_counted_acticles_successed.items(), key=lambda item: item[1], reverse=True))
 +
 +
 +  # Сумма значений (значение понятно int)
 +sum_successed = sum([ item for item in dict_counted_acticles_successed.values() ], 0)
 +
 +
 +  # Имея список с повторяющимися одиночными значениями, генерируем словарь с уникальными значениями и числом в value, начальное значение 0, далее будем считать
 +dict_counted_acticles = { key: value for (key, value) in (zip(set(ls_only_article), itertools.repeat(0))) }
 </code> </code>
 +</details>
 +
 +
 +<details>
 +<summary>:!: Работа со списками</summary>
 +
 +<code python>
 +  # В данном случае надо было из большого списка сформировать список с одиночными значениями плюс оставив только часть строки, вырезается регуляркой
 +reLabelSize = re.compile(r"-[\d]{1,2}$")
 +
 +  # Делаем список доставленных, но только артикулы, без размера
 +lsOnlyArticle = [ reLabelSize.sub("", item["Артикул"]) for item in lsSourceBigDicts ]
 +</code>
 +</details>
 +
  
  
  
 +===== Diagrams =====
 <details> <details>
-<summary>:!: </summary>+<summary>:!: модуль diagrams </summary> 
 +[[https://habr.com/ru/companies/skillfactory/articles/523140/|Статья]]\\ 
 +[[https://diagrams.mingrammer.com/|Дока]]\\ 
 + 
 +**Установка**\\ 
 +sudo apt install graphviz\\ 
 +pip install diagrams\\ 
 + 
 + 
 +**Использование**\\ 
 +:!: Группировка очень примитивная. После группировки нескольких элементов, хоть в коде и работаешь с одним объектом, группой, но стрелки рисуются с каждым элементом в группе, что добавляет не мало мусора, много мусора на самом деле добавляет\\ 
 + 
 +Рамка создается не всегда, только при использовании элемента "cluster" видимо, т.е. можно просто для краткости кода объединить в группу без отображения рамки\\ 
 + 
 +Внутри кластера так же можно устанавливать связи\\  
 +Вложенная группировка таже присутствует, ограничений нет, логика вроде ясна\\ 
 + 
 +:!: Параметры отображения вроде регулируются, относится к компоненту GraphViz\\ 
 + 
 +:!: Свои элементы тоже создаются\\ 
 + 
 +:!: [[https://diagrams.mingrammer.com/docs/nodes/aws| Перечень доступных узлов]]\\ 
 + 
 +:!: Направление соединения собсна << >> так же - без направления\\ 
 +Стрелки имеют три атрибута, цвет, тип и текст\\ 
 + 
 + 
 +<details> 
 +<summary>:!: Примеры</summary>
  
 <code python> <code python>
 +from diagrams import Diagram, Cluster, Edge
 +from diagrams.aws.compute import EC2
 +from diagrams.aws.network import ELB
 +from diagrams.aws.network import Route53
 +from diagrams.onprem.database import PostgreSQL
 +from diagrams.onprem.inmemory import Redis
 +
 +# Просто перечень узлов
 +with Diagram("./images/simple_diagram") as diag:
 +    dns = Route53("dns")
 +    load_balancer = ELB("Load Balancer")
 +    database = PostgreSQL("User Database")
 +    cache = Redis("Cache")
 +    svc_group = [ EC2("Webserver 1"),
 +                  EC2("Webserver 2"),
 +                  EC2("Webserver 3") ]
 +diag
 +
 +
 +# С группировкой
 +with Diagram("./images/simple_diagram") as diag:
 +    dns = Route53("dns")
 +    load_balancer = ELB("Load Balancer")
 +    database = PostgreSQL("User Database")
 +    cache = Redis("Cache")
 +    with Cluster("Web server cluster"):
 +        svc_group = [ EC2("Webserver 1"),
 +                      EC2("Webserver 2"),
 +                      EC2("Webserver 3") ]
 +diag
 +
 +
 +# Связи
 +with Diagram("./images/simple_diagram") as diag:
 +    dns = Route53("dns")
 +    load_balancer = ELB("Load Balancer")
 +    database = PostgreSQL("User Database")
 +    cache = Redis("Cache")
 +    # Объединение в группу
 +    with Cluster("Web server cluster"):
 +        svc_group = [ EC2("Webserver 1"), EC2("Webserver 2"), EC2("Webserver 3") ]
 +    # Связи между элементами
 +    dns >> load_balancer >> svc_group
 +    svc_group >> cache
 +    #svc_group >> database
 +diag
 +
 +
 +# Форматирование стрелок
 +with Diagram("./images/simple_diagram") as diag:
 +    dns = Route53("dns")
 +    load_balancer = ELB("Load Balancer")
 +    cache = Redis("Cache")
 +    # Объединение в группу
 +    with Cluster("Web server cluster"):
 +        svc_group = [ EC2("Webserver 1"), EC2("Webserver 2"), EC2("Webserver 3") ]
 +    # Связи между элементами
 +    dns >> Edge(color="red", style="bold") << load_balancer >> svc_group
 +    svc_group >> Edge(label="this text") >> cache
 +diag
 +
 +
 +# Пар-ры графика
 +    # Конструктор принимает:
 +    # outformat=["jpg", "png", "dot"] - формат выходного файла, можно сразу несколько
 +    # filename="my_diagram" - имя файла, show=False показ, direction="TB" - направление
 +    # Так же, можно задавать доп аттрибуты
 +graph_attr = {
 +    "fontsize": "45",
 +    "bgcolor": "transparent"
 +}
 +with Diagram("./images/simple_diagram", graph_attr = graph_attr) as diag:
 +    dns = Route53("dns")
 +    load_balancer = ELB("Load Balancer")
 +    cache = Redis("Cache")
 +    # Объединение в группу
 +    with Cluster("Web server cluster"):
 +        svc_group = [ EC2("Webserver 1"), EC2("Webserver 2"), EC2("Webserver 3") ]
 +    # Связи между элементами
 +    dns >> load_balancer >> svc_group
 +    svc_group >> cache
 +diag
 +
 +
 +# Связи внутри кластера
 +with Diagram("./images/Grouped Workers"):
 +    dns = Route53("dns")
 +    web = Redis("cache")
 +
 +    with Cluster("DB cluster"):
 +        db_primary = PostgreSQL("primary")
 +        db_primary - [PostgreSQL("replica1"), PostgreSQL("replica2")]
 +
 +    dns >> web >> db_primary
 </code> </code>
 +</details>
 </details> </details>
  
 +<details>
 +<summary>:!: Примеры</summary>
  
-=====  =====+<code python> 
 +from diagrams import Diagram, Cluster, Node
  
 +with Diagram('./output/output', show=False, outformat='svg') as d:
 + with Cluster('cluster'):
 + n1 = Node('A', height = '0.5', width = '5', labelloc = "c", fillcolor = 'purple', fontcolor = 'white', style = 'filled')
 + n2 = Node('B', height = '0.5', width = '5', labelloc = "c", fillcolor = 'purple', fontcolor = 'white', style = 'filled')
 +        n3 = Node('C', height='0.5', width='5', labelloc="c", fillcolor='purple', fontcolor='white', style='filled')
 +        n4 = Node('D', height='0.5', width='5', labelloc="c", fillcolor='purple', fontcolor='white', style='filled')
 +</code>
 +</details>
  
 +
 +
 +
 +===== Модули для Ansible =====
 +Располагаем **py** файлы по пути например "**.ansible\collections\ansible_collections\community\general\plugins\modules**" (в целом расположения указываются в конфиге). Тут можно сделать подпапку\\
  
 <details> <details>
-<summary>:!: </summary>+<summary>:!: Минимальный пример</summary> 
 +В данном примере файл "try_diagrams" в подпапке "my_diagrams"\\ 
 + 
 +<code yml> 
 +--- 
 +- name: "Show list" 
 +  community.general.my_diagrams.try_diagrams: 
 +    my_variable: 'dcdc' 
 +</code> 
  
 <code python> <code python>
 +#!/usr/bin/python
 +
 +from __future__ import (absolute_import, division, print_function)
 +__metaclass__ = type
 +from ansible.module_utils.basic import AnsibleModule
 +
 +
 +def main():
 +    module = AnsibleModule(
 +        argument_spec = dict(
 +            cluster_list = dict(type = 'str', required = True),
 +            mode = dict(type = 'str', default = 'first', choices = ['first', 'second'])
 +        ), 
 +        supports_check_mode = True)
 +
 +    # Полученные аргументы
 +    cluster_list = module.params['cluster_list']
 +    mode = module.params['mode']
 +
 +    # Возвращаемое значение
 +    # некоторые зарезервированы, такие как change, другие можно добавлять любые кастомные, в выводе видно при "-vvv", там уже как удобнее будет извлекать
 +    # module.exit_json(changed=True)
 +    module.exit_json(msg="this is mymsg", data = 'this is mydata', myvar = 'this my variable')
 +    
 +    # Для ошибки
 +    # module.fail_json(msg="Failed to send message")
 +
 +
 +# Класс для примера, тут не используется
 +class myClass():
 +    def get_list(self, name_screens):
 +        return name_screens + 'ddcdc'
 +
 +if __name__ == '__main__':
 +    main()
 </code> </code>
 </details> </details>
  
 +
 +
 +===== Скрины из заббикса=====
 +
 +Для получения графиков изображением есть несколько php скриптов (**"/usr/share/zabbix/chart*.php"**)\\
 +  * **chart.php** - рисует график по переданному массиву "itemids"
 +  * **chart2.php** - простой график по graphID (chart6.php тоже самое только круговой)
 +  * **chart4.php** - рисует график по триггеру, статистика
 +Организация простая, в начале скрипта сразу видно какие параметры принимает, тип, обязательность и т.д.\\
 +
 +<details>
 +<summary>:!: Еще работа с заббиксом</summary>
 +<code python>
 +  # Простой график
 +http://10.10.10.10/zabbix/chart2.php?graphid=15155&from=now-7d&to=now
 +http://10.10.10.10/zabbix/chart2.php?graphid=15155&from=now-24h&profileIdx=web.graphs.filter&to=now&width=1301
 +http://10.10.10.10/zabbix/chart2.php?period=from=now-10800&to=now&profileIdx=web.graphs.filter&graphid=15155&name=title&width=900&height=200&graphtype=0&legend=1
 +  # Триггер
 +http://10.10.10.10/zabbix/chart4.php?triggerid=22050
 +  # Массив итемов
 +http://10.10.10.10/zabbix/chart.php?itemids[]=55063&itemids[]=55064
 +</code>
 +</details>
 +
 +
 +<details>
 +<summary>:!: Пример скрипта </summary>
 +<code python>
 +#!/usr/bin/python3
 +""" Скрипт для получения изображения графиков заббикса
 +    Графики для поиска перечислены в конфиге, параметр "list_graphs_on_screen"
 +    Заббикс группа передается в аргументе, предполагается кластерная группа, но можно использовать любую существующую
 +    Изображение сохраняется в этой же директории, перезаписывается один и тот же файл
 +
 +Требуются пакеты:
 +    pip install Pillow
 +"""
 +
 +from PIL import Image
 +import requests
 +import json
 +import settings
 +import io
 +import math
 +import argparse
 +import re
 +
 +
 +def main():
 +    arg_parser = argparse.ArgumentParser()
 +    arg_parser.add_argument("-c", type = str, help = "Укажите имя кластера")
 +    args = arg_parser.parse_args()
 +    if not args.c:
 +        print("     Error: Укажите имя кластера для получения графиков")
 +        exit(1)
 +
 +    # Принимаем только цифро-буквы и нижнее подчеркивание
 +    args.c = re.sub('[^\w_]', '', args.c)
 +
 +    # Так же меняем префикс в имени кластера
 +    name_zabbix_group = args.c.replace("cl_", "GSC_")
 +
 +    # Получаем перечень ИД графиков, указанных в конфиге
 +    list_ids_graphs = get_list_id_graphs(name_zabbix_group)
 +
 +    if len(list_ids_graphs) > 0:
 +        # Получаем все изображения, собираем их в одно и сохраняем на диск
 +        image_path = get_screen_image(list_ids_graphs)
 +
 +        # Возвращаем имя файла
 +        print(image_path)
 +
 +
 +def get_list_id_graphs(name_zabbix_group):
 +    """ Здесь получаем перечень ИД графиков, указанного кластера
 +    """
 +    # Сначала узнаем ИД указанной заббикс группы
 +    id_zabbix_group = get_id_zabbix_group(name_zabbix_group)
 +    if len(id_zabbix_group) == 0:
 +        return []
 +
 +    query = """{"jsonrpc": "2.0",
 +        "method": "graph.get",
 +        "params": {
 +            "output": "graphid",
 +            "groupids": \""""+ id_zabbix_group +"""\",
 +            "sortfield": "name",
 +            "sortorder": "DESC",
 +            "filter": {
 +                "name": ["""+ settings.list_graphs_on_screen +"""]
 +            }
 +        }, "auth": \""""+ settings.zabbix_key +"""\","id": 1} """.replace('\n', '')
 +
 +    answer = requests.post(f'http://{settings.zabbix_url}/api_jsonrpc.php', json=json.loads(query))
 +
 +    if answer.status_code != 200:
 +        print(f"ZabbixAPI: Не удалось получить ответ от заббикса, ошибка: {answer.status_code}")
 +        return []
 +    else:
 +        # В результатах созвращается список словарей, с ключ-значение, нам нужен только список значений
 +        list_graphs_ids= [item['graphid'] for item in answer.json()['result']]
 +        return list_graphs_ids
 +
 +
 +def get_id_zabbix_group(name_zabbix_group):
 +    """ Получаем ИД заббикс группы по имени переданного кластера
 +    """
 +    query = """{"jsonrpc": "2.0",
 +        "method": "hostgroup.get",
 +        "params": {
 +            "output": "groupid",
 +            "filter": {
 +                "name": \""""+ name_zabbix_group +"""\"
 +            } 
 +        }, "auth": \""""+ settings.zabbix_key +"""\","id": 1} """.replace('\n', '')
 +    answer = requests.post(f'http://{settings.zabbix_url}/api_jsonrpc.php', json=json.loads(query))
 +
 +    if answer.status_code == 200 and len(answer.json()['result']) > 0:
 +        return answer.json()['result'][0]['groupid']
 +    else:
 +        print(f"ZabbixAPI: Ответ от заббикса пуст, код ответа: {answer.status_code}")
 +        return ""
 +
 +
 +def get_screen_image(list_id_graphs):
 +    """ Из переданного списка графиков собираем общий коллаж
 +    """
 +    # Получаем куки авторизации, здесь, чтобы не вызываться в цикле
 +    data_api = {"name": settings.zabbix_user, "password": settings.zabbix_passwd, "enter": "Sign in"}
 +    cookie = requests.post(f"http://{settings.zabbix_url}/", data = data_api).cookies
 +
 +    # Объект для итогового изображения, размер задается сразу
 +        # Ширина множится на два т.к. графики в два столбца
 +        # Высота - сумма всех, деленная на два т.к. в два столбца
 +    screen_image = Image.new("RGBA", ((settings.graph_width * 2), (settings.graph_height * math.ceil(len(list_id_graphs) / 2))))
 +    y_coordinate = 0
 +    x_coordinate = 0
 +
 +    # Обходим список ИД графиков, получаем изображение каждого
 +    for id_graph in list_id_graphs:
 +        graph_image_bytes = get_graph_image(id_graph, cookie)
 +        if len(graph_image_bytes) == 0:
 +            continue
 +
 +        # Ресайзим картинку и добавляем в общий коллаж
 +        graph_image = Image.open(io.BytesIO(graph_image_bytes)).resize((settings.graph_width, settings.graph_height))
 +        screen_image.paste(graph_image, (x_coordinate, y_coordinate))
 +
 +        # Устанавливаем координаты вставки для следующего изображения
 +        if x_coordinate == 0:
 +            x_coordinate = settings.graph_width
 +        else:
 +            x_coordinate = 0
 +            y_coordinate += settings.graph_height
 +
 +    # Сохраняем итоговое, общее изображение
 +        # Надобности хранить изображения нет, они сразу забираются
 +        # Есть надобность удалять старые
 +        # Выбран вариант перезаписывать один и тот же файл
 +    img_file_name = "zabbix_screen_image.png"
 +    screen_image.save(img_file_name)
 +    return img_file_name
 +
 +
 +def get_graph_image(id_graph, cookie):
 +    """ Получаем из заббикса изображение указанного ИД графика
 +    """    
 +    answer = requests.get(f"http://{settings.zabbix_url}/chart2.php?graphid={id_graph}&legend=1", cookies = cookie, verify = False)
 +
 +    # Возвращаем `content` только если код ответа успешный, в противном случае пустую строку
 +    if answer.status_code == 200:
 +        return answer.content
 +    else:
 +        print(f"ZabbixAPI: Не удалось получить изображение, ошибка: {answer.status_code}")
 +        return ""
 +
 +
 +if __name__ == "__main__":
 +    main()
 +</code>
 +
 +settings.py
 +<code python>
 +zabbix_url = '{{ slack_notify_zabbix_url }}'
 +list_graphs_on_screen = '{{ slack_notify_graphs_on_screen }}'
 +graph_width = {{ slack_notify_graph_width }}
 +graph_height = {{ slack_notify_graph_height }}
 +zabbix_user = '{{ slack_notify_zabbix_user }}'
 +zabbix_passwd = '{{ slack_notify_zabbix_passwd }}'
 +zabbix_key = '{{ slack_notify_zabbix_key }}'
 +</code>
 +</details>
 +
 +
 +
 +
 +===== Overall =====
 +<details>
 +<summary>:!: Сортировка</summary>
 +
 +Сортировка в списке словарей, по одному значению внутри словаря
 +<code python>
 +# Структура в таком виде
 +ls_finished_log_records.append({
 +   'current_name': current_filename,
 +   'clear_name': clear_file_name,
 +   'duration': int(duration)
 +})
 +
 +# Cортировкa по полю "duration"
 +ls_finished_log_records.sort(key=lambda item:item['duration'], reverse=True)
 +</code>
 +
 +Посчитать кол-во уникальных элементов в списке
 +<code python>
 +from collections import Counter
 +
 +ls_hosts = ['a','b','a']
 +
 +print(Counter(ls_hosts).keys())
 +print(Counter(ls_hosts).values())
 +
 +['a','b']
 +['2','1']
 +</code>
 +</details>
 +
 +
 +<details>
 +<summary>:!: Работа со строками</summary>
 +
 +Подстановка переменных в строку
 +<code python>
 +#
 +print(f'{var1}_{var2}')
 +
 +#
 +print('{}_{}'.format(var1,var2))
 +</code>
 +</details>
 +
 +
 +<details>
 +<summary>:!: Размер шрифта строки</summary>
 +
 +<code python>
 +from PIL import ImageFont
 +
 +font_path = "LiberationMono-Regular.ttf"
 +font_size=300
 +
 +ttf = ImageFont.truetype(font_path, font_size)
 +
 +txt = "Hello World!"
 +w, h = ttf.getsize(txt)
 +print(w, h)
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: Длинна самого длинного слова в строке</summary>
 +
 +<code python>
 +longest_word = max(text_in_node.split(), key=len)
 +</code>
 +</details>
  
  
Строка 82: Строка 560:
  
  
 +
 +<details>
 +<summary>:!: </summary>
 +
 +<code python>
 +</code>
 +</details>
  
 =====  ===== =====  =====
develop/pyton/practics.1702048891.txt.gz · Последнее изменение: 2023/12/08 15:21 — admin