From 3f19cfc745d04a08f392723d837022a6b7f4072d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BE=D0=BB=D0=B3=D0=B8=D0=B9=20=D0=90=D1=80=D1=82?= =?UTF-8?q?=D1=91=D0=BC?= Date: Sat, 11 Mar 2023 17:19:54 +0300 Subject: [PATCH] init --- .gitignore | 1 + blank_proxmoxer.py | 92 +++++++++++++++++++++++++++++ deploy_aldpro_vm.py | 70 +++++++++++++++++++++++ deploy_template_subprocess.py | 105 ++++++++++++++++++++++++++++++++++ vars.yaml | 49 ++++++++++++++++ 5 files changed, 317 insertions(+) create mode 100644 .gitignore create mode 100755 blank_proxmoxer.py create mode 100755 deploy_aldpro_vm.py create mode 100755 deploy_template_subprocess.py create mode 100644 vars.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f21b54 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/venv/ diff --git a/blank_proxmoxer.py b/blank_proxmoxer.py new file mode 100755 index 0000000..6a84b5b --- /dev/null +++ b/blank_proxmoxer.py @@ -0,0 +1,92 @@ +from proxmoxer import ProxmoxAPI +import yaml +import os.path +import urllib.request + + +with open('vars.yaml') as data: + vars_dict = yaml.safe_load(data) + +# параметры хоста Proxmox +proxmox_node = vars_dict['proxmox_node']['name'] +pve_host = vars_dict['proxmox_node']['host'] +pve_port = vars_dict['proxmox_node']['port'] +pve_admin = vars_dict['proxmox_node']['username'] +pve_passwd = vars_dict['proxmox_node']['password'] +pve_storage = vars_dict['proxmox_node']['storage'] +pve_net = vars_dict['proxmox_node']['net'] + +# параметры создаваемого шаблона +tmpl_id = vars_dict['template']['id'] +tmpl_name = vars_dict['template']['name'] +tmpl_cores = vars_dict['template']['cores'] +tmpl_memory = vars_dict['template']['memory'] +tmpl_user = vars_dict['template']['username'] +tmpl_passwd = vars_dict['template']['password'] + +# ссылка на образ +img_url = vars_dict['img']['url'] +img_name = vars_dict['img']['name'] + + +def download_img(name, url): + """ + Проверка наличия образа в текущей директории. + Если образа нет, он скачивается. + + Params: + name - (str), имя образа; + url - (str), url-ссылка на директорию с образом. + + Return: + None + """ + if os.path.isfile(name): + print(f'Файл с именем "{name}" присутствует в текущей директории') + else: + print(f'Образа "{name}" нет в текущей директории, скачиваю..') + urllib.request.urlretrieve(f'{url}/{name}', name) + print('Скачивание завершено.') + + +def create_vm(node, **kwargs): + """ + Создание шаблона ВМ из ранее скачанного образа. + + Params: + node - (class 'proxmoxer.core.ProxmoxResource'), хост Proxmox, + на котором создаётся шаблон. + + Return: + None + """ + node.qemu.create( + vmid=tmpl_id, name=tmpl_name, cores=tmpl_cores, memory=tmpl_memory, + net0=f'virtio,bridge={pve_net}', bootdisk='scsi0', + ide0=f'{pve_storage}:cloudinit', ide2='none,media=cdrom', vga='qxl', + ciuser=tmpl_user, cipassword=tmpl_passwd, agent=1) + + +def importdisk(node, img, stor, **kwargs): + """ + Импорт образа в ВМ. + + Params: + node - (class 'proxmoxer.core.ProxmoxResource'), хост Proxmox, + на котором создаётся шаблон. + + Return: + None + """ + node.qemu.importdisk(img, stor) + + +proxmox = ProxmoxAPI(host=pve_host, user=pve_admin, password=pve_passwd, port=pve_port, verify_ssl=True) +pve_node = proxmox.nodes(proxmox_node) + + +# download_img(name=img_name, url=img_url) +# create_vm(node=pve_node) +# importdisk(node=pve_node, img=img_name, stor=pve_storage) + +pve_node.qemu(f'disk import {tmpl_id} {img_name} {pve_storage},format=qcow2') diff --git a/deploy_aldpro_vm.py b/deploy_aldpro_vm.py new file mode 100755 index 0000000..703011b --- /dev/null +++ b/deploy_aldpro_vm.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import subprocess +from pprint import pprint + +import yaml + + +with open('vars.yaml') as data: + vars_dict = yaml.safe_load(data) + + +def shell_run(cmd): + """ + Выполнение shell команды. + + :param cmd: (str), команда. + :return: proc.stdout: (subprocess object), вывод команды + proc.stderr: (subprocess object), код завершения. + """ + proc = subprocess.run( + cmd.split(), capture_output=True, text=True, timeout=60) + if proc.stderr: + print(f'Команда - "{cmd}"') + print(proc.stderr) + exit(1) + return proc.stdout, proc.stderr + + +def gen_vm_commands(all_dict): + """ + Генерация списка команд для создания группировки ВМ ALD Pro. + :param all_dict: (dict), словарь с переменными для генерации. + :return: (dict), словарь списков команд. + """ + tmpl_id = all_dict['template']['id'] + gw = all_dict['proxmox_node']['vmbr_gw'] + commands = {} + for vm in vars_dict['vms']: + vm_cmds = [f'qm clone {tmpl_id} {vm["id"]} --name {vm["name"]} --full', + f'qm set {vm["id"]} --ipconfig0 ip={vm["ip"]}/24,gw={gw}', + f'qm resize {vm["id"]} scsi0 32G'] + if vm["name"] == 'dc01' or vm["name"] == 'dc02': + vm_cmds.append(f'qm set {vm["id"]} --cores 4 --memory 8192') + vm_cmds.remove(f'qm resize {vm["id"]} scsi0 32G') + vm_cmds.append(f'qm resize {vm["id"]} scsi0 64G') + elif vm["name"] == 'repo': + vm_cmds.remove(f'qm resize {vm["id"]} scsi0 32G') + vm_cmds.append(f'qm resize {vm["id"]} scsi0 64G') + commands.update({vm["name"]: vm_cmds}) + return commands + + +def create_vms(commands_dict): + """ + Создание группировки ВМ ALD Pro. + + :param commands_dict: (dict), словарь списков команд для создания ВМ. + :return: None + """ + for role in commands_dict.items(): + print(f'Создаётся ВМ - {role[0]}') + for cmd in role[1]: + shell_run(cmd) + + +if __name__ == "__main__": + cmds = gen_vm_commands(vars_dict) + create_vms(cmds) + # pprint(cmds) diff --git a/deploy_template_subprocess.py b/deploy_template_subprocess.py new file mode 100755 index 0000000..f308412 --- /dev/null +++ b/deploy_template_subprocess.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +import subprocess +import yaml +from pathlib import Path +import urllib.request + + +with open('vars.yaml') as data: + vars_dict = yaml.safe_load(data) + +# параметры хоста Proxmox +proxmox_node = vars_dict['proxmox_node']['name'] +pve_host = vars_dict['proxmox_node']['host'] +pve_port = vars_dict['proxmox_node']['port'] +pve_admin = vars_dict['proxmox_node']['username'] +pve_passwd = vars_dict['proxmox_node']['password'] +pve_storage = vars_dict['proxmox_node']['storage'] +pve_vmbr = vars_dict['proxmox_node']['vmbr'] + +# параметры создаваемого шаблона +tmpl_id = vars_dict['template']['id'] +tmpl_name = vars_dict['template']['name'] +tmpl_cores = vars_dict['template']['cores'] +tmpl_memory = vars_dict['template']['memory'] +tmpl_user = vars_dict['template']['username'] +tmpl_passwd = vars_dict['template']['password'] + +# ссылка на образ +img_url = vars_dict['img']['url'] +img_name = vars_dict['img']['name'] + + +def download_img(name, url): + """ + Проверка наличия образа в текущей директории. + Если образа нет, он скачивается. + + :param name: (str), имя образа; + :param url: (str), url-ссылка на директорию с образом. + :return: None. + """ + if Path(name).is_file(): + print(f'Файл с именем "{name}" присутствует в текущей директории') + else: + print(f'Образа "{name}" нет в текущей директории, скачиваю..') + urllib.request.urlretrieve(f'{url}/{name}', name) + print('Скачивание завершено.') + + +def del_img(name): + """ + Удаление образа из текущей директории. + + :param name: (str), имя образа. + :return: None + """ + if Path(name).is_file(): + proc = subprocess.run(f'rm -rf {name}'.split(), capture_output=True, text=True) + print(f'Образ "{name}" удалён из текущей директории') + if proc.stderr: + print(f'Команда - "rm -rf {name}"') + print(proc.stderr) + exit(1) + else: + print(f'Образа "{name}" нет в текущей директории, скачиваю..') + + +def deploy_template(list_commands): + """ + Функция поочерёдно выполняет shell команды, переданные списком. + + :param list_commands: (list), список команд, которые необходимо выполнить. + :return: None + """ + print(f'Создаю шаблон ВМ из образа') + for com in list_commands: + proc = subprocess.run(com.split(), capture_output=True, text=True) + if proc.stderr: + print(f'Команда - "{com}"') + print(proc.stderr) + exit(1) + # else: + # print(proc.stdout) + print('Шаблон создан.') + + +if __name__ == "__main__": + # в зависимости от типа и нахождения хранилища + # путь к создаваемому в процессе импорта диску указывается по-разному + # см. в WEB-интерфейсе примеры с других ВМ + commands = [f'qm create {tmpl_id} --name {tmpl_name}', + f'qm set {tmpl_id} --memory {tmpl_memory} --cores {tmpl_cores}', + f'qm set {tmpl_id} --net0 virtio,bridge={pve_vmbr} --scsihw virtio-scsi-pci', + f'qm disk import {tmpl_id} {img_name} {pve_storage} --format qcow2', + f'qm set {tmpl_id} --scsi0 {pve_storage}:{tmpl_id}/vm-{tmpl_id}-disk-0.qcow2', + f'qm set {tmpl_id} --bootdisk scsi0', + f'qm set {tmpl_id} --ide0 {pve_storage}:cloudinit --ide2 none,media=cdrom', + f'qm set {tmpl_id} --vga qxl --agent 1', + f'qm set {tmpl_id} --ciuser={tmpl_user} --cipassword={tmpl_passwd}', + f'qm template {tmpl_id}'] + + download_img(img_name, img_url) + deploy_template(commands) + del_img(img_name) diff --git a/vars.yaml b/vars.yaml new file mode 100644 index 0000000..c50c78c --- /dev/null +++ b/vars.yaml @@ -0,0 +1,49 @@ +--- +proxmox_node: + name: pve + ip: 192.168.13.19 + host: pve.da2001.ru + port: 443 + username: root@pam + password: KatIrina1 + storage: testvms + vmbr: vmbr1 + vmbr_gw: 10.1.1.9 + +template: + name: alse-1703-cloudinit-template + id: 400 + cores: 2 + memory: 2048 + username: sysadmin + password: KatIrina1 + +img: + name: alse-vanilla-1.7.3-cloud-max-mg9.1.2.qcow2 + url: https://vault.astralinux.ru/images/alse/cloud + +vms: + - name: dc01 + id: 401 + ip: 10.1.1.11 + - name: dc02 + id: 402 + ip: 10.1.1.12 + - name: repo + id: 403 + ip: 10.1.1.13 + - name: dhcp + id: 404 + ip: 10.1.1.14 + - name: pxe + id: 405 + ip: 10.1.1.15 + - name: nas + id: 406 + ip: 10.1.1.16 + - name: monitoring + id: 407 + ip: 10.1.1.17 + - name: printserver + id: 408 + ip: 10.1.1.18