[+] log by new_name

[-] edict
[~] Separate _create to _create and _clone
[~] Preparing for multi-UP
[~] Change cache principe
This commit is contained in:
2024-07-18 15:26:39 +03:00
parent cc50f639c6
commit 6bb06575ac

View File

@@ -13,39 +13,37 @@ from getpass import getpass
from pathlib import Path
from typing import Callable
import netmiko
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from easydict import EasyDict as edict
from loguru import logger
from netmiko import ConnectHandler
from pyVim.connect import SmartConnect, Disconnect
from pyVmomi import vim
from ruamel.yaml import YAML
try:
from pyVmomi.vim import ServiceInstanceContent, ServiceInstance
except ImportError:
pass
chars = string.ascii_letters + string.digits + string.punctuation
chars = string.ascii_letters + string.digits
yaml = YAML()
workdir = Path.home() / ".vmker"
os.makedirs(workdir / "logs", exist_ok=True)
logdir = workdir / "logs"
os.makedirs(logdir / "by-new_name", exist_ok=True)
logger.remove()
logger.add(sys.stdout, level="INFO", backtrace=False, diagnose=False,
format="\r<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | {message}")
logger.add(workdir / "logs" / f"debug-{datetime.now().strftime('%d.%m.%Y_%H-%M.%S')}.log", level=0)
logger.add(logdir / f"debug-{datetime.now().strftime('%d.%m.%Y_%H-%M.%S')}.log", level=0)
logger.debug("Logger initialized")
class VMKer:
def __init__(self):
self.si: ServiceInstance = None
self.content: ServiceInstanceContent = None
self.si = None
self.content = None
self.config = None
self.vm = set()
self.template = None
@staticmethod
def generate_key_from_password(password: str, salt: bytes) -> bytes:
@@ -104,12 +102,12 @@ class VMKer:
def _connect(self):
try:
cfg = edict(self.config)
self.si = SmartConnect(host=cfg.server, user=cfg.user, pwd=self._decrypt_pass(),
disableSslCertValidation=cfg.insecure)
cfg = self.config
self.si = SmartConnect(host=cfg['server'], user=cfg['user'], pwd=self._decrypt_pass(),
disableSslCertValidation=cfg['insecure'])
atexit.register(Disconnect, self.si)
self.content = self.si.RetrieveContent()
logger.success(f"Connected to {self.content.about.fullName}({cfg.server}) as {cfg.user}")
logger.success(f"Connected to {self.content.about.fullName}({cfg['server']}) as {cfg['user']}")
return True
except vim.fault.VimFault as e:
# noinspection PyUnresolvedReferences
@@ -240,20 +238,6 @@ class VMKer:
print("Unknown command.")
logger.info("Exited from configuration mode.")
def _search_vm(self, _template_name, _new_name, datacenter):
logger.debug("Checking VMs.")
vm = None
new = None
container_view = self.content.viewManager.CreateContainerView(datacenter.vmFolder, [vim.VirtualMachine], True)
for _vm in container_view.view:
if _vm.name == _template_name:
vm = _vm
if _vm.name == _new_name:
new = _vm
container_view.Destroy()
return vm, new
@staticmethod
def _get_vm_ip(vm):
ipv4 = []
@@ -267,11 +251,80 @@ class VMKer:
ipv6.append(ip.ipAddress)
return ipv4, ipv6
def _parse_yml(self):
def _parse_yml(self, ssh):
pass
def _clone(self, new_name, destfolder, clone_spec):
logger.info(f"Cloning: {self.template.name!r} > {new_name!r}")
task = self.template.Clone(name=new_name, folder=destfolder, spec=clone_spec)
while task.info.state == vim.TaskInfo.State.running:
time.sleep(1)
if task.info.state != vim.TaskInfo.State.success:
logger.error(f"Error while cloning")
logger.exception(task.info.error)
logger.success("Cloned")
logger.info("Waiting IP VirtualMachine..")
vm = task.info.result
t = 0
while True:
ipv4, ipv6 = self._get_vm_ip(vm)
if len(ipv4) > 0:
break
time.sleep(1)
t += 1
if t > 120:
return logger.error("No IPv4 address found.")
logger.info(f"IPv4: {', '.join(ipv4)}")
logger.info(f"IPv6: {', '.join(ipv6)}")
try:
# TODO: Default user
# TODO: key file
ssh = ConnectHandler(
device_type='linux',
host=ipv4[0],
username="root",
use_keys=True,
key_file="rsa"
)
except netmiko.exceptions.NetmikoAuthenticationException as e:
return logger.error(f"SSH Error: Authentication. ({e})")
# TODO: length
_pwd = ''.join(random.choice(chars) for _ in range(12))
ssh.send_command(f'echo -e "{_pwd}\n{_pwd}" | passwd root')
logger.info(f"Password for root: {_pwd}")
ssh.send_command(f'echo {new_name} > /etc/hostname')
# TODO: yml
logger.info("Executing %.yml")
ssh.disconnect()
def _cache_vms(self, template_name, datacenter):
logger.debug("Checking VMs.")
self.vm = set()
self.template = None
container_view = self.content.viewManager.CreateContainerView(datacenter.vmFolder, [vim.VirtualMachine], True)
for _vm in container_view.view:
if _vm.name == template_name:
self.template = _vm
self.vm.add(_vm.name)
container_view.Destroy()
def _create(self):
if len(sys.argv) > 3:
new_name = sys.argv[3]
template_name = f"{sys.argv[2]}-template"
_logfile = logdir / "by-new_vm_name" / f"{new_name}.log"
i = 0
while True:
i += 1
if not _logfile.exists():
break
_logfile = logdir / "by-new_vm_name" / f"{new_name} ({i}).log"
logger.add(_logfile, level=0)
self._load_config()
if not self._connect():
return
@@ -282,13 +335,13 @@ class VMKer:
return logger.error(f"Datacenter not found: {self.config['datacenter']}")
datacenter = datacenter[0]
logger.debug("datacenter found")
self._cache_vms(template_name, datacenter)
template_name = f"{sys.argv[2]}-template"
new_name = sys.argv[3]
template, _new = self._search_vm(template_name, new_name, datacenter)
if _new:
return logger.error(f"Error: {new_name!r} already exist.")
if not template:
new_names = [f'{new_name}-{i+1}' for i in range(1)]
for n in new_names:
if n in self.vm:
return logger.error(f"Error: {n!r} already exist.")
if not template_name not in self.vm:
return logger.error(f"Template not found: {template_name}")
logger.debug("template found")
@@ -310,7 +363,6 @@ class VMKer:
datastore = datastore[0]
logger.debug("datastore found")
logger.info(f"Cloning: {template_name!r} > {new_name!r}")
destfolder = datacenter.vmFolder
relocate_spec = vim.vm.RelocateSpec()
relocate_spec.datastore = datastore
@@ -318,47 +370,8 @@ class VMKer:
clone_spec = vim.vm.CloneSpec()
clone_spec.location = relocate_spec
clone_spec.powerOn = True
task = template.Clone(name=new_name, folder=destfolder, spec=clone_spec)
while task.info.state == vim.TaskInfo.State.running:
time.sleep(1)
if task.info.state != vim.TaskInfo.State.success:
return logger.error(f"Error while cloning: {task.info.error}")
logger.success("Cloned")
vm = task.info.result
logger.info("Waiting to PowerOn..")
t = 0
while True:
ipv4, ipv6 = self._get_vm_ip(vm)
if len(ipv4) > 0:
break
time.sleep(1)
t += 1
if t > 120:
return logger.error("No IPv4 address found.")
logger.info(f"IPv4: {', '.join(ipv4)}")
logger.info(f"IPv6: {', '.join(ipv6)}")
# TODO: length
_pwd1 = ''.join(random.choice(chars) for _ in range(12))
# TODO: Default user
ssh = ConnectHandler(
device_type='linux',
host=ipv4[0],
username="root",
password="toor",
)
ssh.send_command(f'echo -e "{_pwd1}\n{_pwd1}" | passwd root')
logger.info(f"Password for root: {_pwd1}")
# TODO: yml
logger.info("Executing %.yml")
ssh.disconnect()
for n in new_names:
self._clone(n, destfolder, clone_spec)
else:
logger.info(
f"Usage: {sys.argv[0]} create <template_name> <new_name> [commands.yml | commands1.yml commands2.yml | ...]")