| 
									
										
										
										
											2019-11-18 22:39:57 +05:00
										 |  |  | from contextlib import contextmanager | 
					
						
							|  |  |  | from datetime import datetime | 
					
						
							|  |  |  | from os.path import join | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .classes import SpecificEtcdEntryBase | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VMStatus: | 
					
						
							|  |  |  |     stopped = "STOPPED"  # After requested_shutdown | 
					
						
							|  |  |  |     killed = "KILLED"  # either host died or vm died itself | 
					
						
							|  |  |  |     running = "RUNNING" | 
					
						
							|  |  |  |     error = "ERROR"  # An error occurred that cannot be resolved automatically | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-28 15:39:11 +05:00
										 |  |  | def declare_stopped(vm): | 
					
						
							| 
									
										
										
										
											2019-12-30 14:35:07 +05:00
										 |  |  |     vm["hostname"] = "" | 
					
						
							|  |  |  |     vm["in_migration"] = False | 
					
						
							|  |  |  |     vm["status"] = VMStatus.stopped | 
					
						
							| 
									
										
										
										
											2019-12-28 15:39:11 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 22:39:57 +05:00
										 |  |  | class VMEntry(SpecificEtcdEntryBase): | 
					
						
							|  |  |  |     def __init__(self, e): | 
					
						
							|  |  |  |         self.owner = None  # type: str | 
					
						
							|  |  |  |         self.specs = None  # type: dict | 
					
						
							|  |  |  |         self.hostname = None  # type: str | 
					
						
							|  |  |  |         self.status = None  # type: str | 
					
						
							|  |  |  |         self.image_uuid = None  # type: str | 
					
						
							|  |  |  |         self.log = None  # type: list | 
					
						
							|  |  |  |         self.in_migration = None  # type: bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         super().__init__(e) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def uuid(self): | 
					
						
							|  |  |  |         return self.key.split("/")[-1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def declare_killed(self): | 
					
						
							|  |  |  |         self.hostname = "" | 
					
						
							|  |  |  |         self.in_migration = False | 
					
						
							|  |  |  |         if self.status == VMStatus.running: | 
					
						
							|  |  |  |             self.status = VMStatus.killed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def declare_stopped(self): | 
					
						
							|  |  |  |         self.hostname = "" | 
					
						
							|  |  |  |         self.in_migration = False | 
					
						
							|  |  |  |         self.status = VMStatus.stopped | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def add_log(self, msg): | 
					
						
							|  |  |  |         self.log = self.log[:5] | 
					
						
							| 
									
										
										
										
											2019-12-30 14:35:07 +05:00
										 |  |  |         self.log.append( | 
					
						
							|  |  |  |             "{} - {}".format(datetime.now().isoformat(), msg) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2019-11-18 22:39:57 +05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class VmPool: | 
					
						
							|  |  |  |     def __init__(self, etcd_client, vm_prefix): | 
					
						
							|  |  |  |         self.client = etcd_client | 
					
						
							|  |  |  |         self.prefix = vm_prefix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def vms(self): | 
					
						
							|  |  |  |         _vms = self.client.get_prefix(self.prefix, value_in_json=True) | 
					
						
							|  |  |  |         return [VMEntry(vm) for vm in _vms] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def by_host(self, host, _vms=None): | 
					
						
							|  |  |  |         if _vms is None: | 
					
						
							|  |  |  |             _vms = self.vms | 
					
						
							|  |  |  |         return list(filter(lambda x: x.hostname == host, _vms)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def by_status(self, status, _vms=None): | 
					
						
							|  |  |  |         if _vms is None: | 
					
						
							|  |  |  |             _vms = self.vms | 
					
						
							|  |  |  |         return list(filter(lambda x: x.status == status, _vms)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-05 18:30:41 +05:00
										 |  |  |     def by_owner(self, owner, _vms=None): | 
					
						
							|  |  |  |         if _vms is None: | 
					
						
							|  |  |  |             _vms = self.vms | 
					
						
							|  |  |  |         return list(filter(lambda x: x.owner == owner, _vms)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 22:39:57 +05:00
										 |  |  |     def except_status(self, status, _vms=None): | 
					
						
							|  |  |  |         if _vms is None: | 
					
						
							|  |  |  |             _vms = self.vms | 
					
						
							|  |  |  |         return list(filter(lambda x: x.status != status, _vms)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get(self, key): | 
					
						
							|  |  |  |         if not key.startswith(self.prefix): | 
					
						
							|  |  |  |             key = join(self.prefix, key) | 
					
						
							|  |  |  |         v = self.client.get(key, value_in_json=True) | 
					
						
							|  |  |  |         if v: | 
					
						
							|  |  |  |             return VMEntry(v) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def put(self, obj: VMEntry): | 
					
						
							|  |  |  |         self.client.put(obj.key, obj.value, value_in_json=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextmanager | 
					
						
							|  |  |  |     def get_put(self, key) -> VMEntry: | 
					
						
							|  |  |  |         # Updates object at key on exit | 
					
						
							|  |  |  |         obj = self.get(key) | 
					
						
							|  |  |  |         yield obj | 
					
						
							|  |  |  |         if obj: | 
					
						
							|  |  |  |             self.put(obj) |