====== 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)
:!:
:!:
===== =====