[~] Renaming

[+] _create
This commit is contained in:
Maxim Khomutov 2024-07-18 02:53:20 +03:00
parent 03610dc117
commit 83c18c3f2c

View File

@ -11,6 +11,7 @@ import time
from datetime import datetime
from getpass import getpass
from pathlib import Path
from typing import Callable
from cryptography.fernet import Fernet, InvalidToken
from cryptography.hazmat.backends import default_backend
@ -18,10 +19,17 @@ 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
yaml = YAML()
workdir = Path.home() / ".vmker"
os.makedirs(workdir / "logs", exist_ok=True)
@ -35,8 +43,8 @@ logger.debug("Logger initialized")
class VMKer:
def __init__(self):
self.si = None
self.content = None
self.si: ServiceInstance = None
self.content: ServiceInstanceContent = None
self.config = None
@staticmethod
@ -74,13 +82,13 @@ class VMKer:
fernet = Fernet(key)
decrypted_text = fernet.decrypt(encrypted_text).decode()
if n:
logger.success("Password decrypted.")
logger.debug("Password decrypted.")
return decrypted_text
else:
return passphrase
except InvalidToken:
logger.error("Bad passphrase.")
logger.info("Use 'vmkey init' for drop it.")
logger.info(f"Use for drop it: {sys.argv[0]} init")
exit(1)
except Exception as e:
logger.exception(e)
@ -89,7 +97,7 @@ class VMKer:
def _load_config(self):
cf = workdir / "config.json"
if not cf.exists():
logger.info("Try 'vmkey init' before using program.")
logger.info(f"Init before using program: {sys.argv[0]} init")
exit(0)
with open(workdir / "config.json", "r") as f:
self.config = json.load(f)
@ -97,26 +105,26 @@ class VMKer:
def _connect(self):
try:
cfg = edict(self.config)
self.si = SmartConnect(host=cfg.server, user=cfg.user, pwd=self._decrypt_pass(),
sslContext=ssl._create_unverified_context())
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}")
return True
except vim.fault.VimFault as e:
logger.error(f"Error while connecting: {e.msg}")
# noinspection PyUnresolvedReferences
logger.error(f"ESXI Error: {e.msg}")
except ssl.SSLCertVerificationError as e:
logger.error(f"SSL Error: {e}")
except TimeoutError as e:
logger.error(f"TimeoutError: {e}")
return False
def _parse_yml(self):
pass
def configure(self, _first_init=False):
def _edit(self, _first_init=False):
self._load_config()
logger.info("Entered to configuration mode.")
def _get_arg(name, default, required, _i=input):
def _get_arg(name, default, required, _i: Callable = input):
while True:
i = _i(f"Enter {name}:{f' [{default}]' if default else ''} ")
if not i and not default and required:
@ -136,8 +144,10 @@ class VMKer:
if _first_init:
c = {
"server": _get_arg("serverIP", None, True), "user": _get_arg("user", None, True),
"password": self._encrypt_pass(_get_arg("password", None, True, getpass)), "insecure": True,
"server": _get_arg("serverIP", None, True),
"user": _get_arg("user", None, True),
"password": self._encrypt_pass(_get_arg("password", None, True, getpass)),
"insecure": True,
"datacenter": _get_arg('datacenter', 'ha-datacente', False),
"datastore": _get_arg('datastore', 'datastore1', False),
"resource_pool": _get_arg('resource pool', 'null', False)
@ -168,10 +178,8 @@ class VMKer:
return
else:
logger.error("Bad data.")
logger.info("Type help for edit configuration.")
else:
logger.info("Type help for more information.")
logger.info("Type help for more information.")
edited = False
while True:
i = input("> ").split(" ")
@ -232,22 +240,129 @@ class VMKer:
print("Unknown command.")
logger.info("Exited from configuration mode.")
def _create(self):
def _parse_yml(self):
pass
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
def _create(self):
if len(sys.argv) > 3:
self._load_config()
if not self._connect():
return
logger.info("Loading...")
datacenter = [dc for dc in self.content.rootFolder.childEntity if dc.name == self.config['datacenter']]
if not datacenter:
return logger.error(f"Datacenter not found: {self.config['datacenter']}")
datacenter = datacenter[0]
logger.debug("datacenter found")
new_name = sys.argv[3]
template, _new = self._search_vm(f"{sys.argv[2]}-template", new_name, datacenter)
if _new:
return logger.error(f"Error: {new_name!r} already exist.")
if not template:
return logger.error(f"Template not found: {sys.argv[2]}-template")
logger.debug("template found")
if self.config['resource_pool']:
resource_pool = \
[rp for rp in datacenter.hostFolder.childEntity[0].resourcePool.resourcePool if
rp.name == self.config['resource_pool']]
if not resource_pool:
return logger.error(f"Resource pool not found: {self.config['resource_pool']}")
resource_pool = resource_pool[0]
logger.debug("resource_pool found")
else:
resource_pool = datacenter.hostFolder.childEntity[0].resourcePool
logger.debug("Use default resource_pool")
datastore = [ds for ds in datacenter.datastore if ds.name == self.config['datastore']]
if not datastore:
return logger.error(f"Datastore not found: {self.config['datastore']}")
datastore = datastore[0]
logger.debug("datastore found")
logger.info(f"Cloning: {sys.argv[2]!r} > {new_name}")
destfolder = datacenter.vmFolder
relocate_spec = vim.vm.RelocateSpec()
relocate_spec.datastore = datastore
relocate_spec.pool = resource_pool
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
ipv4 = []
ipv6 = []
for nic in vm.guest.net:
if nic.ipConfig:
for ip in nic.ipConfig.ipAddress:
if ":" not in ip.ipAddress: # Skip IPv6 addresses
ipv4.append(ip.ipAddress)
else:
ipv6.append(ip.ipAddress)
logger.info(f"IPv4: {ipv4}")
logger.info(f"IPv6: {ipv6}")
if len(ipv4) == 0:
return logger.error("No IPv4 address found.")
# TODO: length
_pwd1 = ''.join(random.choice(chars) for _ in range(12))
_pwd2 = ''.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')
ssh.send_command(f'echo -e "{_pwd2}\n{_pwd2}" | passwd user')
logger.info(f"Password for root: {_pwd1}")
logger.info(f"Password for user: {_pwd2}")
# TODO: yml
logger.info("Executing %.yml")
ssh.disconnect()
else:
logger.info(
f"Usage: {sys.argv[0]} create <template_name> <new_name> [commands.yml | commands1.yml commands2.yml | ...]")
logger.info("Mark: template search on target host with '-template' suffix (%template_name%-template)")
def main(self):
logger.debug(f"{sys.argv=}")
try:
if len(sys.argv) > 1:
match sys.argv[1]:
case "init":
self.configure(True)
self._edit(True)
case "edit":
self._load_config()
self.configure()
self._edit()
case "create":
self._load_config()
self._create()
logger.warning("WIP")
case "help":
print("HELP")
case _:
@ -256,51 +371,6 @@ class VMKer:
logger.info("Exited by KeyboardInterrupt")
def clone_vm(si, template_name, vm_name, datacenter_name, datastore_name, resource_pool_name):
content = si.RetrieveContent()
template = None
for datacenter in content.rootFolder.childEntity:
if datacenter.name == datacenter_name:
view_manager = content.viewManager
container_view = view_manager.CreateContainerView(datacenter.vmFolder, [vim.VirtualMachine], True)
for vm in container_view.view:
if vm.name == template_name:
template = vm
break
container_view.Destroy()
break
if not template:
raise Exception("Template not found")
datacenter = [dc for dc in content.rootFolder.childEntity if dc.name == datacenter_name][0]
destfolder = datacenter.vmFolder
if resource_pool_name:
resource_pool = \
[rp for rp in datacenter.hostFolder.childEntity[0].resourcePool.resourcePool if
rp.name == resource_pool_name][
0]
else:
resource_pool = datacenter.hostFolder.childEntity[0].resourcePool
relocate_spec = vim.vm.RelocateSpec()
relocate_spec.datastore = [ds for ds in datacenter.datastore if ds.name == datastore_name][0]
relocate_spec.pool = resource_pool
clone_spec = vim.vm.CloneSpec()
clone_spec.location = relocate_spec
clone_spec.powerOn = True
task = template.Clone(name=vm_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:
raise task.info.error
return task.info.result
def generate_password(length=12):
chars = string.ascii_letters + string.digits + string.punctuation
return ''.join(random.choice(chars) for _ in range(length))
@ -316,4 +386,4 @@ def get_vm_ip(vm):
if __name__ == "__main__":
VMKer().main()
VMKer().main()