Files
netbox-scripts/add_tenant_with_prefix.py

259 lines
9.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
from tenancy.models import Tenant, TenantGroup, Contact, ContactRole, ContactAssignment
from ipam.models import Prefix, VRF, Role
from extras.scripts import Script, StringVar, IPNetworkVar, ChoiceVar, ObjectVar
from django.core.exceptions import ValidationError
from extras.models import CustomField
def slugify(text: str):
CYRILLIC_TO_LATIN = {
"а": "a",
"б": "b",
"в": "v",
"г": "g",
"д": "d",
"е": "e",
"ё": "e",
"ж": "zh",
"з": "z",
"и": "i",
"й": "i",
"к": "k",
"л": "l",
"м": "m",
"н": "n",
"о": "o",
"п": "p",
"р": "r",
"с": "s",
"т": "t",
"у": "u",
"ф": "f",
"х": "h",
"ц": "c",
"ч": "ch",
"ш": "sh",
"щ": "shch",
"ъ": "",
"ы": "y",
"ь": "",
"э": "e",
"ю": "yu",
"я": "ya",
"А": "A",
"Б": "B",
"В": "V",
"Г": "G",
"Д": "D",
"Е": "E",
"Ё": "E",
"Ж": "ZH",
"З": "Z",
"И": "I",
"Й": "I",
"К": "K",
"Л": "L",
"М": "M",
"Н": "N",
"О": "O",
"П": "P",
"Р": "R",
"С": "S",
"Т": "T",
"У": "U",
"Ф": "F",
"Х": "H",
"Ц": "C",
"Ч": "CH",
"Ш": "SH",
"Щ": "SHCH",
"Ъ": "",
"Ы": "Y",
"Ь": "",
"Э": "E",
"Ю": "YU",
"Я": "YA",
}
text = text.replace("ООО", "").lstrip()
text = "".join(CYRILLIC_TO_LATIN.get(c, c) for c in text)
text = text.lower()
text = re.sub(r"\s+", "_", text)
text = re.sub(r"[^a-z0-9_-]", "", text)
text = re.sub(r"[-_]{2,}", "_", text).strip("_-")
return text
class CreateTenant(Script):
class Meta:
name = "Создание Оператора"
description = "Создание оператора и связанного префикса"
fieldsets = (
(
"Оператор",
(
"tenant_name",
"tenant_group",
"tenant_connection_type",
"tenant_description",
),
),
(
"Префикс",
("prefix_cidr", "prefix_vrf", "prefix_role", "prefix_description"),
),
("Документы", ("tenant_contract", "tenant_prefix_task", "tenant_tr")),
("Контакты", ("contacts_fio", "contacts_phone", "contacts_email")),
)
connection_types = CustomField.objects.get(name="connection_type_tenant")
tenant_name = StringVar(label="Имя оператора")
tenant_group = ObjectVar(
label="Группа оператора", model=TenantGroup, required=False
)
tenant_connection_type = ChoiceVar(
label="Тип подключения", choices=connection_types.choices, required=True
)
tenant_description = StringVar(label="Описание оператора", required=False)
tenant_contract = StringVar(
label="Договор",
description="Номер договора на разработку комплекса",
required=False,
)
tenant_tr = StringVar(
label="Проект/ТР", description="Пример: DOCXXXXX", required=False
)
tenant_prefix_task = StringVar(
label="Задача",
description="URL или номер задачи из redmine, jira, CRM",
required=False,
)
prefix_cidr = IPNetworkVar(label="Префикс (CIDR)")
prefix_vrf = ObjectVar(label="VRF проекта", model=VRF, required=True)
prefix_role = ObjectVar(label="Роль", model=Role, required=True)
prefix_description = StringVar(label="Описание префикса", required=False)
contacts_fio = StringVar(label="ФИО", required=False)
contacts_phone = StringVar(label="Номер тел.", required=False)
contacts_email = StringVar(label="E-mail", required=False)
contacts_role = ObjectVar(label="Роль контакта", model=ContactRole, required=False)
def run(self, data, commit):
try:
tenant_slug = slugify(data["tenant_name"])
if Tenant.objects.filter(name=data["tenant_name"]).exists():
self.log_failure(
f"Оператор с именем '{data['tenant_name']}' уже существует"
)
return
if Tenant.objects.filter(slug=tenant_slug).exists():
self.log_failure(
f"Оператор со slug '{data['tenant_slug']}' уже существует"
)
return
tenant_data = {
"name": data["tenant_name"],
"slug": tenant_slug,
"group": data["tenant_group"],
}
if data.get("tenant_description"):
tenant_data["description"] = data["tenant_description"]
tenant = Tenant(**tenant_data)
tenant.custom_field_data["dogovor"] = data["tenant_contract"]
tenant.custom_field_data["connection_type_tenant"] = data["tenant_connection_type"]
tenant.custom_field_data["link_on_docs"] = data["tenant_tr"]
tenant.full_clean()
if commit:
tenant.save()
self.log_success(
f"Создан новый оператор: {tenant.name} - {tenant.slug}"
)
if Prefix.objects.filter(prefix=data["prefix_cidr"]).exists():
self.log_warning(f"Префикс {data['prefix_cidr']} уже существует")
return
prefix = Prefix(
prefix=data["prefix_cidr"],
tenant=tenant,
description=data.get("prefix_description") or "",
vrf=data["prefix_vrf"],
role=data["prefix_role"],
)
prefix.custom_field_data["Project"] = data["tenant_tr"]
prefix.custom_field_data["zadacha"] = data["tenant_prefix_task"]
prefix.full_clean()
prefix.save()
self.log_success(
f"Создан префикс {prefix.prefix} для оператора: {tenant.name}"
)
if data.get("contacts_fio"):
contact = Contact(
name=data["contacts_fio"],
phone=data["contacts_phone"],
email=data["contacts_email"],
)
try:
contact.full_clean()
contact.save()
self.log_success(f"Создан контакт: {contact.name}")
except Exception as e:
self.log_failure(f"Ошибка при создании контакта: {e}")
try:
role = data.get("contacts_role") or ContactRole.objects.first()
assignment = ContactAssignment(
contact=contact,
role=role,
object=tenant,
)
assignment.full_clean()
assignment.save()
self.log_success(
f"Связан контакт {contact.name} с оператором: {tenant.name}"
)
except Exception as e:
self.log_failure(
f"Ошибка при связывании контакта с оператором: {e}"
)
else:
self.log_info(
f"Тестовый режим: Будет создан оператор: {tenant.name} (slug: {tenant.slug})"
)
self.log_info(
f"Тестовый режим: Будет создан префикс: {data['prefix_cidr']}"
)
try:
tenant.full_clean()
prefix = Prefix(
prefix=data["prefix_cidr"],
tenant=tenant,
description=data.get("prefix_description") or "",
)
prefix.full_clean()
contact = Contact(
name=data["contacts_fio"],
phone=data["contacts_phone"],
email=data["contacts_email"],
)
contact.full_clean()
role = data.get("contacts_role") or ContactRole.objects.first()
assignment = ContactAssignment(
contact=contact,
role=role,
object=tenant,
)
assignment.full_clean()
self.log_success("Все данные валидны")
except ValidationError as e:
self.log_failure(f"Ошибка валидации: {e}")
except Exception as e:
self.log_failure(f"Ошибка при выполнении скрипта: {e}")
if commit:
self.log_failure("Изменения отменены из-за ошибки")