diff --git a/.gitignore b/.gitignore index 135af53..82aecaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .env/** +.env +__pycache__ __pycache__/** \ No newline at end of file diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..86ff5bb --- /dev/null +++ b/config.yml @@ -0,0 +1,5 @@ +server_port: 5000 +server_url: "http://localhost" +server_password: "sekret_password" +server_access_username: "user" +client_loglevel: "DEBUG" \ No newline at end of file diff --git a/images/valhalla/cool-image-name/v0.0.2alpha/image.qcow2 b/images/valhalla/cool-image-name/v0.0.2alpha/image.qcow2 new file mode 100644 index 0000000..c8bdf25 --- /dev/null +++ b/images/valhalla/cool-image-name/v0.0.2alpha/image.qcow2 @@ -0,0 +1,4 @@ +duiuwqhdiuhwqiudhewiufhwieuhiuwhfiuiueyr837r87438r3iuh87duihew8732roh87yro3r +ry398yr983yr937yr743tfhuieh9843ty347nv743nyv34[9yt34 +4yv9[843qyt9843yt98439843ry3948feiuh9843fy934t +ru09438ur9843ur9843ut9834tup43349]] \ No newline at end of file diff --git a/network/ValhallaServer.py b/network/ValhallaServer.py index 1fee919..b4a1e4e 100644 --- a/network/ValhallaServer.py +++ b/network/ValhallaServer.py @@ -1,37 +1,201 @@ import requests as req import logging -import json +import os +import time +import urllib3 +import shutil -class ValhallaServer(): +from utils.MachineData import MachineData - def __init__(self, server_address: str, server_port: str, server_user: str, server_access_password: str, logging_level: str): + +class ValhallaServer: + def __init__( + self, + server_address: str, + server_port: str, + server_user: str, + server_access_password: str, + logging_level: str, + ): self.server_address = server_address self.server_port = server_port self.server_user = server_user + self.server_name = "not connected" + self.server_version = "not_connected" self.server_access_password = server_access_password self.logging_level = logging_level self.logger = logging.getLogger(__name__) self.bearer_token = "" + self.auth_headers = {} + self.user_id = 0 + self.vm_ids_list_from_server = [] + self.vms_metadata = {} log_level_mapping_dict = { - "NOTSET": 0, - "DEBUG": 10, - "INFO": 20, - "WARNING": 30, - "ERROR": 40, - "CRITICAL": 50, - } + "NOTSET": 0, + "DEBUG": 10, + "INFO": 20, + "WARNING": 30, + "ERROR": 40, + "CRITICAL": 50, + } self.logger.setLevel(log_level_mapping_dict[logging_level]) - + def authenticate(self): try: login_data = { "username": self.server_user, - "password": self.server_access_password + "password": self.server_access_password, } headers = {"Content-Type": "application/json"} - print(json.dumps(login_data)) - response = req.post(url=f"{self.server_address}:{self.server_port}/login", json=login_data, headers=headers) - self.logger.info(str(response.json())) + response = req.post( + url=f"{self.server_address}:{self.server_port}/login", + json=login_data, + headers=headers, + ) + # self.logger.info(str(response.json())) + if response.status_code == 202: + user_data = response.json() + self.bearer_token = user_data["token"] + self.user_id = user_data["user_id"] + self.auth_headers = {"Authorization": f"Bearer {self.bearer_token}"} + else: + raise Exception("Bad input or server not responding") + except Exception as ex: + self.logger.error(f"{str(ex)}") + + def get_server_data(self): + try: + response = req.get( + url=f"{self.server_address}:{self.server_port}/", + headers=self.auth_headers, + ) print(str(response.json())) + if response.status_code == 200: + server_data = response.json() + self.server_version = server_data["server_version"] + self.server_name = server_data["server_name"] except Exception as ex: self.logger.error(f"{str(ex)}") + + def update_machine_data_on_server(self, machine_data: MachineData): + try: + response = req.get( + url=f"{self.server_address}:{self.server_port}/clients/{machine_data.mac_address}", + headers=self.auth_headers, + ) + if response.status_code == 401: + self.authenticate() + print(self.bearer_token) + response = req.get( + url=f"{self.server_address}:{self.server_port}/clients/{machine_data.mac_address}", + headers=self.auth_headers, + ) + print(f"{str(response.json())}") + client_data = { + "mac_address": machine_data.mac_address, + "ip_address": machine_data.ip_address, + "hostname": machine_data.hostname, + "client_version": machine_data.client_version, + "vm_list_on_machine": [], + } + if response.status_code == 404: + print("Client not registered, registering now...") + for i in range(1, 5): + register_response = req.post( + url=f"{self.server_address}:{self.server_port}/clients", + headers=self.auth_headers, + json=client_data, + ) + if register_response == 201: + print("Registered successfully") + break + else: + print("Failed to register, waiting 5s before trying again...") + time.sleep(5) + continue + + if response.status_code == 200: + client_data_from_server = response.json() + try: + client_data.pop("vm_list_on_machine") + except KeyError: + pass + if client_data_from_server != client_data: + print("Client data needs updating, updating now...") + for i in range(1, 5): + register_response = req.put( + url=f"{self.server_address}:{self.server_port}/clients", + headers=self.auth_headers, + json=client_data, + ) + if register_response.status_code == 202: + print("Updated successfully") + break + elif response.status_code == 401: + print("Reauthentication needed...") + self.authenticate() + else: + print("Failed to update, waiting 5s before trying again...") + time.sleep(5) + continue + + except Exception as ex: + self.logger.error(f"{str(ex)}") + + def get_vm_list_from_server(self, machine_data: MachineData): + try: + response = req.get( + url=f"{self.server_address}:{self.server_port}/clients/{machine_data.mac_address}/vms", + headers=self.auth_headers, + ) + if response.status_code == 401: + self.authenticate() + response = req.get( + url=f"{self.server_address}:{self.server_port}/clients/{machine_data.mac_address}/vms", + headers=self.auth_headers, + ) + if response.status_code == 200: + vm_list = response.json() + self.vm_ids_list_from_server = vm_list + return vm_list + else: + print(f"Error getting data from remote server: {response.json()}") + except Exception as ex: + pass + + def get_vms_data_from_server(self): + try: + vms_data = {} + for image_id in self.vm_ids_list_from_server: + response = req.get( + url=f"{self.server_address}:{self.server_port}/images/{image_id}", + headers=self.auth_headers, + ) + if response.status_code == 200: + data = response.json() + vms_data[f"{image_id}"] = data + self.vms_metadata = vms_data + except Exception as ex: + print(str(ex)) + + def update_vms_images_from_server(self): + try: + for image_id in self.vm_ids_list_from_server: + image_data = self.vms_metadata[f"{image_id}"] + print(f"{image_data['image_name']} download") + http = urllib3.PoolManager() + self.authenticate() + filename = f"images/{self.server_name}/{image_data['image_name']}/{image_data['image_version']}/image.qcow2" + os.makedirs(os.path.dirname(filename), exist_ok=True) + with http.request( + method="GET", + url=f"{self.server_address}:{self.server_port}/images/{image_id}/download", + preload_content=False, + headers=self.auth_headers, + ) as r, open( + filename, + "wb", + ) as out_file: + shutil.copyfileobj(r, out_file) + except Exception as ex: + print(str(ex)) diff --git a/network/__pycache__/ValhallaServer.cpython-310.pyc b/network/__pycache__/ValhallaServer.cpython-310.pyc index 33acd81..23d3323 100644 Binary files a/network/__pycache__/ValhallaServer.cpython-310.pyc and b/network/__pycache__/ValhallaServer.cpython-310.pyc differ diff --git a/utils/MachineData.py b/utils/MachineData.py new file mode 100644 index 0000000..7eaefa1 --- /dev/null +++ b/utils/MachineData.py @@ -0,0 +1,72 @@ +from getmac import get_mac_address as gma +import socket +import yaml +import os +import psutil + +class MachineData(): + + def get_ip_address(self): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + return s.getsockname()[0] + + def __init__(self): + self.mac_address = gma() + self.ip_address = str(self.get_ip_address()) + self.hostname = socket.gethostname() + self.client_version = "v0.0.1alpha" + self.cpu_count = os.cpu_count() + self.ram_size = (psutil.virtual_memory().total / 1024) / 1024 + + try: + with open("config.yml", "r") as stream: + try: + config_file = yaml.safe_load(stream) + except Exception as e: + print(e) + except FileNotFoundError as e: + print(str(e)) + exit(-1) + config = config_file + + try: + server_url_override = os.environ.get("VALHALLA_SERVER_URL") + server_port_override = os.environ.get("VALHALLA_SERVER_PORT") + server_password_override = os.environ.get("VALHALLA_SERVER_PASSWORD") + server_access_username_override = os.environ.get( + "VALHALLA_SERVER_ACCESS_USERNAME") + client_logging_override = os.environ.get("VALHALLA_CLIENT_LOGLEVEL") + + if server_port_override: + config["server_port"] = server_port_override + + if server_url_override: + config["server_url"] = server_url_override + + if server_password_override: + config["server_password"] = server_password_override + + if server_access_username_override: + config["server_access_username"] = server_access_username_override + + if client_logging_override: + config["client_loglevel"] = client_logging_override + + self.server_url = config["server_url"] + self.server_port = config["server_port"] + self.server_password = config["server_password"] + self.server_access_username = config["server_access_username"] + self.client_loglevel = config["client_loglevel"] + except KeyError as ke: + print(str(ke)) + pass + except TypeError as te: + print(str(te)) + pass + except Exception as e: + print(str(e)) + exit(-1) + +class VirtualmachineConfig(): + def __init__(cpu_count: int, memory_size: int, ): diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..f453450 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1 @@ +from . import MachineData \ No newline at end of file diff --git a/valhalla-client b/valhalla-client index 3c10ddc..92627b0 100644 --- a/valhalla-client +++ b/valhalla-client @@ -1,7 +1,28 @@ from network.ValhallaServer import ValhallaServer +from utils.MachineData import MachineData -server = ValhallaServer(server_address="http://localhost", server_port=str(5000), server_user="user", server_access_password="sekret_password", logging_level="DEBUG") +machine_data = MachineData() + +server = ValhallaServer( + server_address=machine_data.server_url, + server_port=machine_data.server_port, + server_user=machine_data.server_access_username, + server_access_password=machine_data.server_password, + logging_level=machine_data.client_loglevel, +) server.authenticate() +server.get_server_data() + +server.update_machine_data_on_server(machine_data=machine_data) + +vm_list = server.get_vm_list_from_server(machine_data=machine_data) + +print(vm_list) + +server.get_vms_data_from_server() + +server.update_vms_images_from_server() + # vim:ft=py \ No newline at end of file