====== Practics ====== ===== Seller =====
:!: Работа с csv /pandas Штатный вариант\\ Возвращает каждую строку в формате List\\ import csv with open('docs/orders_mini.csv', newline='') as csvfile: for row in _reader: print(type(row)) print(row) Вариант с pandas\\ Библиотека конечно матерая, но есть увеличенный порог входа, там все свое, куча собственный типов/форматов данных, во всем этом надо какое то время еще разбираться\\ import pandas as pd data = pd.read_csv("docs/orders_mini2.csv", delimiter=';') # собственный формат dataFrame print(type(data)) print(data) # кортеж со строками, тоже матерый формат for label, content in data.items(): print(f'label: {label}') print(f'content: {content}') # так столбцы, в виде строк for content in data.keys(): print(f'content: {content}') # и еще очень много всяких функций/вариантов
:!: Работа со словарями # Сортировка по значению 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))) }
:!: Работа со списками # В данном случае надо было из большого списка сформировать список с одиночными значениями плюс оставив только часть строки, вырезается регуляркой reLabelSize = re.compile(r"-[\d]{1,2}$") # Делаем список доставленных, но только артикулы, без размера lsOnlyArticle = [ reLabelSize.sub("", item["Артикул"]) for item in lsSourceBigDicts ]
===== Diagrams =====
:!: модуль diagrams [[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| Перечень доступных узлов]]\\ :!: Направление соединения собсна << >> так же - без направления\\ Стрелки имеют три атрибута, цвет, тип и текст\\
:!: Примеры 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
:!: Примеры 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')
===== Модули для Ansible ===== Располагаем **py** файлы по пути например "**.ansible\collections\ansible_collections\community\general\plugins\modules**" (в целом расположения указываются в конфиге). Тут можно сделать подпапку\\
:!: Минимальный пример В данном примере файл "try_diagrams" в подпапке "my_diagrams"\\ --- - name: "Show list" community.general.my_diagrams.try_diagrams: my_variable: 'dcdc' #!/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()
===== Скрины из заббикса===== Для получения графиков изображением есть несколько php скриптов (**"/usr/share/zabbix/chart*.php"**)\\ * **chart.php** - рисует график по переданному массиву "itemids" * **chart2.php** - простой график по graphID (chart6.php тоже самое только круговой) * **chart4.php** - рисует график по триггеру, статистика Организация простая, в начале скрипта сразу видно какие параметры принимает, тип, обязательность и т.д.\\
:!: Еще работа с заббиксом # Простой график 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
:!: Пример скрипта #!/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() settings.py 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 }}'
===== Overall =====
:!: Сортировка Сортировка в списке словарей, по одному значению внутри словаря # Структура в таком виде 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) Посчитать кол-во уникальных элементов в списке from collections import Counter ls_hosts = ['a','b','a'] print(Counter(ls_hosts).keys()) print(Counter(ls_hosts).values()) ['a','b'] ['2','1']
:!: Работа со строками Подстановка переменных в строку # print(f'{var1}_{var2}') # print('{}_{}'.format(var1,var2))
:!: Размер шрифта строки 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)
:!: Длинна самого длинного слова в строке longest_word = max(text_in_node.split(), key=len)
:!:
:!:
===== =====