implemented host status, ceph integeration, monkey patched vnc port number

This commit is contained in:
ahmadbilalkhalid 2019-07-18 15:56:46 +05:00
parent ebbd04ad03
commit b021d63a3e
4 changed files with 288 additions and 38 deletions

View file

@ -4,10 +4,12 @@ url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
bandit = "*"
[packages]
python-decouple = "*"
etcd3 = "*"
cython = "*"
[requires]
python_version = "3.7"

210
Pipfile.lock generated Normal file
View file

@ -0,0 +1,210 @@
{
"_meta": {
"hash": {
"sha256": "60ec9dd9adb030a2f5c569016cd23b6d3c2bf29c3ee746531017928b0b496fe7"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"cython": {
"hashes": [
"sha256:04ebf16df9406d3279a2489c3327803c782d9e17637d525bfb44ecf5ec65850f",
"sha256:1486ec88d1c73dea3846a5640054018b002608e04a791ccbd2082a47bce4440a",
"sha256:20da832a5e9a8e93d1e1eb64650258956723940968eb585506531719b55b804f",
"sha256:2464688b523d7a133b52cf1343c1c595b92fc6554af1015f74b9e49951e992d4",
"sha256:27827b68a8359e9ab6bf683c68d8ee79863a0c94a577acf56aa02cc302e16f51",
"sha256:27deeeeca0fd8933af07923e809c8fed0763d150a4fdd4082932a33b8c874ed6",
"sha256:31f4da785d5e09deb852ea59795a629c5befb6040929e7880c6f63e6668246ce",
"sha256:4828cf8fa638c35139e643f30201b240c0d156b1b9967a7321ae42d721d7224c",
"sha256:48b365e32cc5639ae2c239d7bd4f8a1d920a13a7ae92113c4c938903c9400147",
"sha256:4eb71856c1d1b33083df9318fd30143470ad6f0d1b9ad2ee61a120710842d28b",
"sha256:5b06ef8422d27d8128f8f80bdefa111eadcab246fba1d668720af4f0b97b7a0e",
"sha256:71c553640e1ddaaf143e38dbc6cd1863fa3c0738fb1830a9aaffba9a51838f30",
"sha256:73e2742ee1f923c5f213183bf493901f9630e395634fce5b739a53b7dc5d64be",
"sha256:82a632bc02063eff0b8e7ff3089aa3d912d1c7499709f51c8f04f57c8832cfe6",
"sha256:977ca1ac059e4d4a4bf5fe2224986baf42b69290453eda44822606f4deae6515",
"sha256:a7e6217d0dd864a7cc4f457172766864496efd64d24d4980df1521f75f992761",
"sha256:ad0ed7dd5dff76eb3aae8c18d95b1c9f885a91a92132728051a704fb8060d08c",
"sha256:b1b8eda9e931f0ca1aadb95a890811bdf530407e48c962643b85675329d99abf",
"sha256:cec99c79205131da3ee75becea1f3f55c57bf6a1c500431de9ae7a32ac8a5cc4",
"sha256:d4bbdaa6f61ce2ef26535a7d473d6ffa6e413013c5c580af999546bf1627ae11",
"sha256:d8bdb4208975b12048bdace46e9dd8e3dda3872432f95b53789700a1330e6060",
"sha256:dce0362ff9b61f8411d1efc9e16fc528dadbd3707a557561992457f5cb446297",
"sha256:defbbbf5653629ce5cc54091ce49c6830da8d3104de53ed2169c9efcb0720f27",
"sha256:e0c53a7e2b6d82ec3c26c009c937fc88eb8c7edf000c54334261beaf56bb08f2",
"sha256:e1065bacfe5303f107896e63263537dee90920d26050f2e23c4af12c37da2db6",
"sha256:e142837c4212c0b2c71e6773cb6740828922806b4c00ee4215be3ceb558671e6",
"sha256:f4cbbab28c93ffee6ec929cf0826f0b11d2488e53a708d51142a5e62f8cd9806",
"sha256:fa8f63b6551621eea9efea4db37ae401104352f0ebaee32f7d20be88cbe589c3"
],
"index": "pypi",
"version": "==0.29.12"
},
"etcd3": {
"hashes": [
"sha256:25a524b9f032c6631ff0097532907dea81243eaa63c3744510fd1598cc4e0e87"
],
"index": "pypi",
"version": "==0.10.0"
},
"grpcio": {
"hashes": [
"sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2",
"sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce",
"sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb",
"sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e",
"sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941",
"sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e",
"sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce",
"sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf",
"sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f",
"sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303",
"sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2",
"sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf",
"sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e",
"sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369",
"sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87",
"sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e",
"sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97",
"sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2",
"sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369",
"sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67",
"sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174",
"sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f",
"sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b",
"sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e",
"sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0",
"sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad",
"sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa",
"sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03",
"sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1",
"sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348",
"sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530",
"sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc"
],
"version": "==1.22.0"
},
"protobuf": {
"hashes": [
"sha256:05c36022fef3c7d3562ac22402965c0c2b9fe8421f459bb377323598996e407f",
"sha256:139b7eadcca0a861d60b523cb37d9475505e0dfb07972436b15407c2b968d87e",
"sha256:15f683006cb77fb849b1f561e509b03dd2b7dcc749086b8dd1831090d0ba4740",
"sha256:2ad566b7b7cdd8717c7af1825e19f09e8fef2787b77fcb979588944657679604",
"sha256:35cfcf97642ef62108e10a9431c77733ec7eaab8e32fe4653de20403429907cb",
"sha256:387822859ecdd012fdc25ec879f7f487da6e1d5b1ae6115e227e6be208836f71",
"sha256:4df14cbe1e7134afcfdbb9f058949e31c466de27d9b2f7fb4da9e0b67231b538",
"sha256:586c4ca37a7146d4822c700059f150ac3445ce0aef6f3ea258640838bb892dc2",
"sha256:58b11e530e954d29ab3180c48dc558a409f705bf16739fd4e0d3e07924ad7add",
"sha256:63c8c98ccb8c95f41c18fb829aeeab21c6249adee4ed75354125bdc44488f30e",
"sha256:72edcbacd0c73eef507d2ff1af99a6c27df18e66a3ff4351e401182e4de62b03",
"sha256:83dc8a561b3b954fd7002c690bb83278b8d1742a1e28abba9aaef28b0c8b437d",
"sha256:913171ecc84c2726b86574e40549a0ea619d569657c5a5ff782a3be7d81401a5",
"sha256:aabb7c741d3416671c3e6fe7c52970a226e6a8274417a97d7d795f953fadef36",
"sha256:b3452bbda12b1cbe2187d416779de07b2ab4c497d83a050e43c344778763721d",
"sha256:c5d5b8d4a9212338297fa1fa44589f69b470c0ba1d38168b432d577176b386a8",
"sha256:d86ee389c2c4fc3cebabb8ce83a8e97b6b3b5dc727b7419c1ccdc7b6e545a233",
"sha256:f2db8c754de788ab8be5e108e1e967c774c0942342b4f8aaaf14063889a6cfdc"
],
"version": "==3.9.0"
},
"python-decouple": {
"hashes": [
"sha256:1317df14b43efee4337a4aa02914bf004f010cd56d6c4bd894e6474ec8c4fe2d"
],
"index": "pypi",
"version": "==3.1"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"tenacity": {
"hashes": [
"sha256:a0c3c5f7ae0c33f5556c775ca059c12d6fd8ab7121613a713e8b7d649908571b",
"sha256:b87c1934daa0b2ccc7db153c37b8bf91d12f165936ade8628e7b962b92dc7705"
],
"version": "==5.0.4"
}
},
"develop": {
"bandit": {
"hashes": [
"sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952",
"sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"
],
"index": "pypi",
"version": "==1.6.2"
},
"gitdb2": {
"hashes": [
"sha256:83361131a1836661a155172932a13c08bda2db3674e4caa32368aa6eb02f38c2",
"sha256:e3a0141c5f2a3f635c7209d56c496ebe1ad35da82fe4d3ec4aaa36278d70648a"
],
"version": "==2.0.5"
},
"gitpython": {
"hashes": [
"sha256:563221e5a44369c6b79172f455584c9ebbb122a13368cc82cb4b5addff788f82",
"sha256:8237dc5bfd6f1366abeee5624111b9d6879393d84745a507de0fda86043b65a8"
],
"version": "==2.1.11"
},
"pbr": {
"hashes": [
"sha256:0ca44dc9fd3b04a22297c2a91082d8df2894862e8f4c86a49dac69eae9e85ca0",
"sha256:4aed6c1b1fa5020def0f22aed663d87b81bb3235f112490b07d2643d7a98c5b5"
],
"version": "==5.4.1"
},
"pyyaml": {
"hashes": [
"sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3",
"sha256:588c94b3d16b76cfed8e0be54932e5729cc185caffaa5a451e7ad2f7ed8b4043",
"sha256:68c8dd247f29f9a0d09375c9c6b8fdc64b60810ebf07ba4cdd64ceee3a58c7b7",
"sha256:70d9818f1c9cd5c48bb87804f2efc8692f1023dac7f1a1a5c61d454043c1d265",
"sha256:86a93cccd50f8c125286e637328ff4eef108400dd7089b46a7be3445eecfa391",
"sha256:a0f329125a926876f647c9fa0ef32801587a12328b4a3c741270464e3e4fa778",
"sha256:a3c252ab0fa1bb0d5a3f6449a4826732f3eb6c0270925548cac342bc9b22c225",
"sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955",
"sha256:cd0618c5ba5bda5f4039b9398bb7fb6a317bb8298218c3de25c47c4740e4b95e",
"sha256:ceacb9e5f8474dcf45b940578591c7f3d960e82f926c707788a570b51ba59190",
"sha256:fe6a88094b64132c4bb3b631412e90032e8cfe9745a58370462240b8cb7553cd"
],
"version": "==5.1.1"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"smmap2": {
"hashes": [
"sha256:0555a7bf4df71d1ef4218e4807bbf9b201f910174e6e08af2e138d4e517b4dde",
"sha256:29a9ffa0497e7f2be94ca0ed1ca1aa3cd4cf25a1f6b4f5f87f74b46ed91d609a"
],
"version": "==2.0.5"
},
"stevedore": {
"hashes": [
"sha256:7be098ff53d87f23d798a7ce7ae5c31f094f3deb92ba18059b1aeb1ca9fec0a0",
"sha256:7d1ce610a87d26f53c087da61f06f9b7f7e552efad2a7f6d2322632b5f932ea2"
],
"version": "==1.30.1"
}
}
}

111
main.py
View file

@ -1,4 +1,7 @@
# TODO
# TODO: Use Unix File Socket for VNC instead of TCP
# QEMU Manual
# https://qemu.weilnetz.de/doc/qemu-doc.html
# For QEMU Monitor Protocol Commands Information, See
# https://qemu.weilnetz.de/doc/qemu-doc.html#pcsys_005fmonitor
@ -8,15 +11,19 @@ import argparse
import qmp
import logging
import os
import shutil
import subprocess
import atexit
import signal
from etcd3_wrapper import Etcd3Wrapper
from dataclasses import dataclass
from typing import Union
from functools import wraps
from decouple import config
from datetime import datetime
running_vms = []
vnc_port_pool = list(range(5900, 6000))
client = Etcd3Wrapper()
@ -35,6 +42,14 @@ logging.basicConfig(
)
def goodbye(host):
host.value["status"] = "DEAD"
host.value["last_heartbeat"] = datetime.utcnow().isoformat()
client.put(host.key, json.dumps(host.value))
logging.info(f"Host {host.key} dead! at {host.value['last_heartbeat']}")
os.kill(os.getpid(), signal.SIGKILL)
def need_running_vm(func):
@wraps(func)
def wrapper(e):
@ -53,7 +68,7 @@ def need_running_vm(func):
return wrapper
def create_vm(owner_dir, vm_uuid, e):
def create_vm(vm_uuid, e):
image = client.get(
f"/v1/image/{e.value['image_uuid']}", value_in_json=True
)
@ -62,25 +77,34 @@ def create_vm(owner_dir, vm_uuid, e):
image_uuid = e.value["image_uuid"]
logging.info("Creating New VM...")
_command_to_create = f"rbd clone images/{image_uuid}@protected uservms/{vm_uuid}"
subprocess.call(_command_to_create.split(" "))
os.makedirs(f"{owner_dir}/.vm", exist_ok=True)
# DELETEME: Delete when CEPH integeration is complete
if not os.path.isfile(f"{owner_dir}/.vm/{vm_uuid}.raw"):
shutil.copy(
f"/var/vm/{image_uuid}.raw", f"{owner_dir}/.vm/{vm_uuid}.raw"
)
# os.makedirs(f"{owner_dir}/.vm", exist_ok=True)
# if not os.path.isfile(f"{owner_dir}/.vm/{vm_uuid}.raw"):
# shutil.copy(
# f"/var/vm/{image_uuid}.raw", f"{owner_dir}/.vm/{vm_uuid}.raw"
# )
e.value["status"] = "REQUESTED_START"
client.put(e.key, json.dumps(e.value))
def start_vm(vm_path, e):
if not os.path.isfile(vm_path):
logging.info(f"Image file of vm {e.key} does not exists")
logging.info(f"Setting vm {e.key} status to DELETED")
e.value["status"] = "DELETED"
client.put(e.key, json.dumps(e.value))
return
# FIXME: Assume for the moment that the image exists
# Use librados to list files that exists in
# uservms pool then checkwhether the e.key.split("/").pop()
# exists in rbd_ls(uservms_pool)
# if not os.path.isfile(vm_path):
# logging.info(f"Image file of vm {e.key} does not exists")
# logging.info(f"Setting vm {e.key} status to DELETED")
# e.value["status"] = "DELETED"
# client.put(e.key, json.dumps(e.value))
# return
_vm = get_vm(running_vms, e.key)
if _vm:
@ -89,21 +113,16 @@ def start_vm(vm_path, e):
client.put(e.key, json.dumps(e.value))
return
# FIXME: There should be better vnc port allocation scheme
vm = qmp.QEMUMachine(
"/usr/bin/qemu-system-x86_64",
test_dir="vm_socklog",
args=[
vm_path,
"-boot",
"c",
"-net",
"nic",
"-net",
"user",
"-m",
"1024",
"-vnc",
f":{len(running_vms)}",
"-boot", "c", # First Boot Hard drive
"-m", "1024", # RAM limit
# Ever growing port number
"-vnc", f":{vnc_port_pool.pop(0)}", # Allow VNC
],
)
try:
@ -118,7 +137,8 @@ def start_vm(vm_path, e):
client.put(e.key, e.value, value_in_json=True)
return
except (qmp.QEMUMachineError, TypeError):
logging.info(f"Machine Error Occurred on {e.key}")
logging.info()
logging.exception(f"Machine Error Occurred on {e.key}")
e.value["status"] = "KILLED"
client.put(e.key, e.value, value_in_json=True)
else:
@ -181,7 +201,17 @@ def get_vm(vm_list: list, vm_key) -> Union[VM, None]:
return next((vm for vm in vm_list if vm.key == vm_key), None)
def main(hostname):
def main():
argparser = argparse.ArgumentParser()
argparser.add_argument("hostname", help="Name of this host. e.g /v1/host/1")
args = argparser.parse_args()
host = client.get(args.hostname, value_in_json=True)
host.value["status"] = "ALIVE"
host.value["last_heartbeat"] = datetime.utcnow().isoformat()
atexit.register(goodbye, host=host)
events = client.watch_prefix("/v1/vm/", timeout=10)
# events = client.get_prefix("/v1/vm/")
@ -196,8 +226,9 @@ def main(hostname):
if e_status == "TIMEOUT":
logging.info("Timeout")
_vms = filter(lambda v: v.value["hostname"] == hostname, client.get_prefix("/v1/vm", value_in_json=True))
_vms = filter(lambda v: v.value["hostname"] == args.hostname, client.get_prefix("/v1/vm", value_in_json=True))
alleged_running_vms = filter(lambda v: v.value["status"] == "RUNNING", _vms)
should_be_running = filter(lambda v: v.value["status"] == "REQUESTED_START", _vms)
for vm in alleged_running_vms:
_vm = get_vm(running_vms, vm.key)
if (_vm and not _vm.vm.is_running()) or _vm is None:
@ -206,20 +237,28 @@ def main(hostname):
logging.info(f"Updating {vm.key} status to KILLED")
vm.value["status"] = "KILLED"
client.put(vm.key, json.dumps(vm.value))
for vm in should_be_running:
vm_path = f"rbd:uservms/{vm.key.split('/')[-1]}"
start_vm(vm_path, e)
host.value["status"] = "ALIVE"
host.value["last_heartbeat"] = datetime.utcnow().isoformat()
client.put(host.key, json.dumps(host.value))
logging.info(f"Updated last heartbeat time {host.value['last_heartbeat']}")
continue
e_hostname = e.value["hostname"]
vm_uuid = e.key.split("/")[-1]
owner_dir = f"{config('BASE_DIR')}/{e.value['owner']}"
# If it is not for me then skip it
if e_hostname != hostname:
if e_hostname != args.hostname:
continue
logging.debug(f"EVENT: {e}")
if e_status == "SCHEDULED_DEPLOY":
create_vm(owner_dir, vm_uuid, e)
create_vm(vm_uuid, e)
elif e_status == "REQUESTED_SUSPEND":
suspend_vm(e)
@ -228,7 +267,11 @@ def main(hostname):
resume_vm(e)
elif e_status == "REQUESTED_START":
vm_path = f"{owner_dir}/.vm/{vm_uuid}.raw"
# DELETEME: Delete when CEPH integeration is complete
# vm_path = f"{owner_dir}/.vm/{vm_uuid}.raw"
vm_path = f"rbd:uservms/{vm_uuid}"
start_vm(vm_path, e)
elif e_status == "REQUESTED_SHUTDOWN":
@ -240,8 +283,4 @@ def main(hostname):
logging.info(f"Running VMs {running_vms}")
argparser = argparse.ArgumentParser()
argparser.add_argument("hostname", help="Name of this host. e.g /v1/host/1")
args = argparser.parse_args()
main(args.hostname)
main()

View file

@ -234,8 +234,7 @@ class QEMUMachine(object):
else:
moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
args = ['-chardev', moncdev,
'-mon', 'chardev=mon,mode=control',
'-display', 'none', '-vga', 'none']
'-mon', 'chardev=mon,mode=control']
if self._machine is not None:
args.extend(['-machine', self._machine])
if self._console_set: