diff --git a/backends.py b/backends.py new file mode 100644 index 0000000000000000000000000000000000000000..24808d1fe89185e571fbb0136bc06fa63878ecd6 --- /dev/null +++ b/backends.py @@ -0,0 +1,226 @@ +import json +import time +import random + +from os_win import constants as os_win_const +from os_win import exceptions as os_win_exc +from os_win.utils.compute import vmutils10 +from os_win import utilsfactory +from oslo_utils import uuidutils + +from eulerlauncher.utils import objs +from eulerlauncher.utils import constants +from eulerlauncher.utils import utils as omni_utils +from eulerlauncher.backends.win import powershell +from os_win.utils.storage.virtdisk import VHDUtils + +SWITCH_NAME = 'Default Switch' + + +class VMUtils_omni(vmutils10.VMUtils10): + + def __init__(self) -> None: + super().__init__() + + def get_instance_notes(self, instance_name): + instance_notes = self._get_instance_notes(instance_name) + return instance_notes + + def get_vm_nic_uids(self, vm_name): + nics = self._get_vm_nics(vm_name) + return nics + + +class Flavor(object): + def __init__(self, flavor_name, cpucores_num, ram_capacity, disk_capacity, flavor_id=None): + self.flavor_id = flavor_id or self.generate_unique_id() # 初始化虚拟机规格的唯一ID + self.flavor_name = flavor_name # 虚拟机规格名称 + self.cpucores_num = str(cpucores_num) # CPU核心数(转换为字符串类型) + self.ram_capacity = ram_capacity # 内存大小(MB) + self.disk_capacity = disk_capacity # 磁盘大小(GB) + + def generate_unique_id(self): + # 生成唯一ID的方法,使用时间戳和随机数结合 + timestamp = int(time.time() * 1000) # 当前时间的毫秒级别时间戳 + random_part = random.randint(0, 1000) # 0到1000之间的随机数 + return f'{timestamp}-{random_part}' + + def to_dict(self): + # 将Flavor对象转换为字典 + return { + 'flavor_id': self.flavor_id, + 'flavor_name': self.flavor_name, + 'cpucores_num': self.cpucores_num, + 'ram_capacity': self.ram_capacity, + 'disk_capacity': self.disk_capacity + } + + @classmethod + def from_dict(cls, data): + # 从字典创建Flavor对象的类方法 + return cls(data['flavor_name'], int(data['cpucores_num']), data['ram_capacity'], data['disk_capacity'], + data.get('flavor_id')) + + +class VMOps(object): + _ROOT_DISK_CTRL_ADDR = 0 + + def __init__(self, virtapi=None): + self._virtapi = virtapi + self._vmutils = VMUtils_omni() + self._netutils = utilsfactory.get_networkutils() + self._hostutils = utilsfactory.get_hostutils() + + def create_flavor(self, flavor_name, cpucores_num, ram_capacity, disk_capacity): + # 创建虚拟机规格 + flavor = Flavor(flavor_name, cpucores_num, ram_capacity, disk_capacity) + self.save_flavor(flavor) + + def delete_flavor(self, flavor_id): + # 删除虚拟机规格 + flavors = self.load_flavors() + flavor_to_delete = None + + # 查找要删除的虚拟机规格 + for flavor in flavors: + if flavor.flavor_id == flavor_id: + flavor_to_delete = flavor + break + + if flavor_to_delete: + flavors.remove(flavor_to_delete) + self.save_flavors(flavors) + print(f"Flavor with flavor_id {flavor_id} has been deleted.") + else: + print(f"Flavor with flavor_id {flavor_id} not found.") + + def save_flavor(self, flavor): + # 将Flavor对象保存到配置文件 + flavors = self.load_flavors() + flavors.append(flavor.to_dict()) + with open('flavors.json', 'w') as f: + json.dump(flavors, f) + + def load_flavors(self): + try: + # 从配置文件加载Flavor对象列表 + with open('flavors.json', 'r') as f: + data = json.load(f) + return [Flavor.from_dict(item) for item in data] + except FileNotFoundError: + return [] # 如果配置文件不存在,返回空列表 + + def print_all_flavors(self): + flavors = self.load_flavors() + if not flavors: + print("No virtual machine flavors found.") + return + + print("All Virtual Machine Flavors:") + for flavor in flavors: + print(f"Flavor ID: {flavor.flavor_id}") + print(f"Flavor Name: {flavor.flavor_name}") + print(f"CPU Cores: {flavor.cpucores_num}") + print(f"RAM Capacity: {flavor.ram_capacity} MB") + print(f"Disk Capacity: {flavor.disk_capacity} GB") + print("-------------") + + + def create_vm(self, vm_name, vnuma_enabled, vm_gen, instance_path, meta_data): + # 创建虚拟机 + self._vmutils.create_vm(vm_name, + vnuma_enabled, + vm_gen, + instance_path, + [json.dumps(meta_data)]) + + def build_and_run_vm(self, vm_name, uuid, image_name, vnuma_enabled, vm_gen, instance_path, root_disk_path, flavor): + # 指定规格创建并启动虚拟机 + meta_data = { + 'uuid': uuid, + 'image': image_name, + 'creator': 'eulerlauncher' + } + + # 使用传入的虚拟机规格创建虚拟机 + self.create_vm(vm_name, vnuma_enabled, vm_gen, instance_path, meta_data) + # Create a scsi controller for this instance + self._vmutils.create_scsi_controller(vm_name) + + # 创建规定大小的磁盘文件 + # 创建一个VHDUtils实例 + vhd_utils = VHDUtils() + # 调用create_vhd方法 + vhd_utils.create_vhd(root_disk_path, constants.VHD_TYPE_FIXED, + max_internal_size=flavor.disk_capacity * 1024 * 1024 * 1024) + # Attach the root disk to the driver + self.attach_disk(vm_name, root_disk_path, constants.DISK) + + # 设置虚拟机的 CPU、内存 + self._vmutils.update_vm(vm_name, flavor.ram_capacity, 0, flavor.cpucores_num, 0, False, 0) + + # Start the instance + self.power_up(vm_name) + nic_name = vm_name + '_eth0' + self.add_nic(vm_name, nic_name) + self.connect_vnic_to_switch(SWITCH_NAME, nic_name) + return 0 + + + def delete_instance(self, vm_name): + # 删除虚拟机 + # Stop the VM first. + self._vmutils.stop_vm_jobs(vm_name) + self._vmutils.set_vm_state(vm_name, os_win_const.HYPERV_VM_STATE_DISABLED) + self._vmutils.destroy_vm(vm_name) + + while (1): + if not self._vmutils.vm_exists(vm_name): + break + return 0 + + def get_vm_disks(self, vm_name): + return self._vmutils.get_vm_disks(vm_name) + + def attach_disk(self, instance_name, path, drive_type): + # 挂载磁盘 + self._vmutils.attach_scsi_drive(instance_name, path, drive_type) + + def power_up(self, instance_name): + # 启动虚拟机 + req_state = os_win_const.HYPERV_VM_STATE_ENABLED + self._vmutils.set_vm_state(instance_name, req_state) + + def start_vm(self, vm_name): + # 启动虚拟机并连接网络 + self.power_up(vm_name) + + # 添加并配置网络适配器 + nic_name = vm_name + '_eth0' + self.add_nic(vm_name, nic_name) + + # 连接虚拟机的网络适配器到指定的交换机 + self.connect_vnic_to_switch(SWITCH_NAME, nic_name) + + def stop_vm(self, vm_name): + # 停止虚拟机 + self._vmutils.soft_shutdown_vm(vm_name) + + def detach_disk(self, vm_name, disk_path=None, is_physical=True, serial=None): + # 卸载虚拟机磁盘,如果不传入disk_path的话则默认会分离所有磁盘资源 + self._vmutils.detach_vm_disk(vm_name, disk_path, is_physical, serial) + + def add_nic(self, instance_name, nic_name): + # 添加并配置网络适配器 + self._vmutils.create_nic(instance_name, nic_name) + + def get_vm_nics(self, instance_name, nic_name): + # 获取虚拟机的网络适配器 + return self._vmutils._get_nic_data_by_name(nic_name) + + + def connect_vnic_to_switch(self, switch_name, vnic_name): + # 连接虚拟机的网络适配器到指定的交换机 + self._netutils.connect_vnic_to_vswitch(switch_name, vnic_name) + + diff --git a/vm_operations.proto b/vm_operations.proto new file mode 100644 index 0000000000000000000000000000000000000000..2809985928409826f7f24c67ee8e93efc4fae13a --- /dev/null +++ b/vm_operations.proto @@ -0,0 +1,66 @@ +// vm_operations.proto + +syntax = "proto3"; + +package vmoperations; + +service VmOperationsService { + rpc CreateVm(CreateVmRequest) returns (VmResponse); + rpc StartVm(StartVmRequest) returns (VmResponse); + rpc StopVm(StopVmRequest) returns (VmResponse); + rpc AttachDisk(AttachDiskRequest) returns (VmResponse); + rpc DetachDisk(DetachDiskRequest) returns (VmResponse); + rpc CreateFlavor(CreateFlavorRequest) returns (VmResponse); + rpc DeleteFlavor(DeleteFlavorRequest) returns (VmResponse); +} + +message CreateVmRequest { + string vm_name = 1; + bool vnuma_enabled = 2; + string vm_gen = 3; + string instance_path = 4; + string root_disk_path = 5; + Flavor flavor = 6; +} + +message StartVmRequest { + string vm_name = 1; +} + +message StopVmRequest { + string vm_name = 1; +} + +message AttachDiskRequest { + string vm_name = 1; + string disk_path = 2; + string drive_type = 3; +} + +message DetachDiskRequest { + string vm_name = 1; + string disk_path = 2; +} + +message CreateFlavorRequest { + string flavor_name = 1; + string cpucores_num = 2; + string ram_capacity = 3; + string disk_capacity = 4; +} + +message DeleteFlavorRequest { + string flavor_id = 1; +} + +message VmResponse { + string message = 1; +} + +message Flavor { + string flavor_id = 1; + string flavor_name = 2; + string cpucores_num = 3; + string ram_capacity = 4; + string disk_capacity = 5; +} \ No newline at end of file diff --git a/vm_operations_client.py b/vm_operations_client.py new file mode 100644 index 0000000000000000000000000000000000000000..1f38b43bcebecc30f732eedb3bd68091cd087d34 --- /dev/null +++ b/vm_operations_client.py @@ -0,0 +1,79 @@ +# vm_operations_client.py + +import grpc +import vm_operations_pb2 +import vm_operations_pb2_grpc + +def create_vm(grpc_client, vm_name, vnuma_enabled, vm_gen, instance_path, root_disk_path, flavor_name, cpucores_num, ram_capacity, disk_capacity): + # 创建虚拟机 + request = vm_operations_pb2.CreateVmRequest( + vm_name=vm_name, + vnuma_enabled=vnuma_enabled, + vm_gen=vm_gen, + instance_path=instance_path, + root_disk_path=root_disk_path, + flavor=vm_operations_pb2.Flavor( + flavor_name=flavor_name, + cpucores_num=cpucores_num, + ram_capacity=ram_capacity, + disk_capacity=disk_capacity + ) + ) + response = grpc_client.CreateVm(request) + print(f"Create VM Response: {response.message}") + +def start_vm(grpc_client, vm_name): + # 启动虚拟机 + request = vm_operations_pb2.StartVmRequest(vm_name=vm_name) + response = grpc_client.StartVm(request) + print(f"Start VM Response: {response.message}") + +def stop_vm(grpc_client, vm_name): + # 停止虚拟机 + request = vm_operations_pb2.StopVmRequest(vm_name=vm_name) + response = grpc_client.StopVm(request) + print(f"Stop VM Response: {response.message}") + +def attach_disk(grpc_client, vm_name, disk_path, drive_type): + # 挂载磁盘 + request = vm_operations_pb2.AttachDiskRequest( + vm_name=vm_name, + disk_path=disk_path, + drive_type=drive_type + ) + response = grpc_client.AttachDisk(request) + print(f"Attach Disk Response: {response.message}") + +def detach_disk(grpc_client, vm_name, disk_path): + # 卸载磁盘 + request = vm_operations_pb2.DetachDiskRequest( + vm_name=vm_name, + disk_path=disk_path + ) + response = grpc_client.DetachDisk(request) + print(f"Detach Disk Response: {response.message}") + +def create_flavor(grpc_client, flavor_name, cpucores_num, ram_capacity, disk_capacity): + # 创建虚拟机规格 + request = vm_operations_pb2.CreateFlavorRequest( + flavor_name=flavor_name, + cpucores_num=cpucores_num, + ram_capacity=ram_capacity, + disk_capacity=disk_capacity + ) + response = grpc_client.CreateFlavor(request) + print(f"Create Flavor Response: {response.message}") + +def delete_flavor(grpc_client, flavor_id): + # 删除虚拟机规格 + request = vm_operations_pb2.DeleteFlavorRequest(flavor_id=flavor_id) + response = grpc_client.DeleteFlavor(request) + print(f"Delete Flavor Response: {response.message}") + +def main(): + with grpc.insecure_channel('localhost:50051') as channel: + grpc_client = vm_operations_pb2_grpc.VmOperationsServiceStub(channel) + # 解析命令行参数并调用相应的 gRPC 方法 + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/vm_operations_pb2.py b/vm_operations_pb2.py new file mode 100644 index 0000000000000000000000000000000000000000..0067f92eb0864a477af81dceeea8d8cb2080b7ed --- /dev/null +++ b/vm_operations_pb2.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: vm_operations.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13vm_operations.proto\x12\x0cvmoperations\"\x9e\x01\n\x0f\x43reateVmRequest\x12\x0f\n\x07vm_name\x18\x01 \x01(\t\x12\x15\n\rvnuma_enabled\x18\x02 \x01(\x08\x12\x0e\n\x06vm_gen\x18\x03 \x01(\t\x12\x15\n\rinstance_path\x18\x04 \x01(\t\x12\x16\n\x0eroot_disk_path\x18\x05 \x01(\t\x12$\n\x06\x66lavor\x18\x06 \x01(\x0b\x32\x14.vmoperations.Flavor\"!\n\x0eStartVmRequest\x12\x0f\n\x07vm_name\x18\x01 \x01(\t\" \n\rStopVmRequest\x12\x0f\n\x07vm_name\x18\x01 \x01(\t\"K\n\x11\x41ttachDiskRequest\x12\x0f\n\x07vm_name\x18\x01 \x01(\t\x12\x11\n\tdisk_path\x18\x02 \x01(\t\x12\x12\n\ndrive_type\x18\x03 \x01(\t\"7\n\x11\x44\x65tachDiskRequest\x12\x0f\n\x07vm_name\x18\x01 \x01(\t\x12\x11\n\tdisk_path\x18\x02 \x01(\t\"m\n\x13\x43reateFlavorRequest\x12\x13\n\x0b\x66lavor_name\x18\x01 \x01(\t\x12\x14\n\x0c\x63pucores_num\x18\x02 \x01(\t\x12\x14\n\x0cram_capacity\x18\x03 \x01(\t\x12\x15\n\rdisk_capacity\x18\x04 \x01(\t\"(\n\x13\x44\x65leteFlavorRequest\x12\x11\n\tflavor_id\x18\x01 \x01(\t\"\x1d\n\nVmResponse\x12\x0f\n\x07message\x18\x01 \x01(\t\"s\n\x06\x46lavor\x12\x11\n\tflavor_id\x18\x01 \x01(\t\x12\x13\n\x0b\x66lavor_name\x18\x02 \x01(\t\x12\x14\n\x0c\x63pucores_num\x18\x03 \x01(\t\x12\x14\n\x0cram_capacity\x18\x04 \x01(\t\x12\x15\n\rdisk_capacity\x18\x05 \x01(\t2\x8a\x04\n\x13VmOperationsService\x12\x43\n\x08\x43reateVm\x12\x1d.vmoperations.CreateVmRequest\x1a\x18.vmoperations.VmResponse\x12\x41\n\x07StartVm\x12\x1c.vmoperations.StartVmRequest\x1a\x18.vmoperations.VmResponse\x12?\n\x06StopVm\x12\x1b.vmoperations.StopVmRequest\x1a\x18.vmoperations.VmResponse\x12G\n\nAttachDisk\x12\x1f.vmoperations.AttachDiskRequest\x1a\x18.vmoperations.VmResponse\x12G\n\nDetachDisk\x12\x1f.vmoperations.DetachDiskRequest\x1a\x18.vmoperations.VmResponse\x12K\n\x0c\x43reateFlavor\x12!.vmoperations.CreateFlavorRequest\x1a\x18.vmoperations.VmResponse\x12K\n\x0c\x44\x65leteFlavor\x12!.vmoperations.DeleteFlavorRequest\x1a\x18.vmoperations.VmResponseb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'vm_operations_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _globals['_CREATEVMREQUEST']._serialized_start=38 + _globals['_CREATEVMREQUEST']._serialized_end=196 + _globals['_STARTVMREQUEST']._serialized_start=198 + _globals['_STARTVMREQUEST']._serialized_end=231 + _globals['_STOPVMREQUEST']._serialized_start=233 + _globals['_STOPVMREQUEST']._serialized_end=265 + _globals['_ATTACHDISKREQUEST']._serialized_start=267 + _globals['_ATTACHDISKREQUEST']._serialized_end=342 + _globals['_DETACHDISKREQUEST']._serialized_start=344 + _globals['_DETACHDISKREQUEST']._serialized_end=399 + _globals['_CREATEFLAVORREQUEST']._serialized_start=401 + _globals['_CREATEFLAVORREQUEST']._serialized_end=510 + _globals['_DELETEFLAVORREQUEST']._serialized_start=512 + _globals['_DELETEFLAVORREQUEST']._serialized_end=552 + _globals['_VMRESPONSE']._serialized_start=554 + _globals['_VMRESPONSE']._serialized_end=583 + _globals['_FLAVOR']._serialized_start=585 + _globals['_FLAVOR']._serialized_end=700 + _globals['_VMOPERATIONSSERVICE']._serialized_start=703 + _globals['_VMOPERATIONSSERVICE']._serialized_end=1225 +# @@protoc_insertion_point(module_scope) diff --git a/vm_operations_pb2_grpc.py b/vm_operations_pb2_grpc.py new file mode 100644 index 0000000000000000000000000000000000000000..a256eb6c83f9ada639df4521d490a35651426354 --- /dev/null +++ b/vm_operations_pb2_grpc.py @@ -0,0 +1,264 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import vm_operations_pb2 as vm__operations__pb2 + + +class VmOperationsServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.CreateVm = channel.unary_unary( + '/vmoperations.VmOperationsService/CreateVm', + request_serializer=vm__operations__pb2.CreateVmRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + self.StartVm = channel.unary_unary( + '/vmoperations.VmOperationsService/StartVm', + request_serializer=vm__operations__pb2.StartVmRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + self.StopVm = channel.unary_unary( + '/vmoperations.VmOperationsService/StopVm', + request_serializer=vm__operations__pb2.StopVmRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + self.AttachDisk = channel.unary_unary( + '/vmoperations.VmOperationsService/AttachDisk', + request_serializer=vm__operations__pb2.AttachDiskRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + self.DetachDisk = channel.unary_unary( + '/vmoperations.VmOperationsService/DetachDisk', + request_serializer=vm__operations__pb2.DetachDiskRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + self.CreateFlavor = channel.unary_unary( + '/vmoperations.VmOperationsService/CreateFlavor', + request_serializer=vm__operations__pb2.CreateFlavorRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + self.DeleteFlavor = channel.unary_unary( + '/vmoperations.VmOperationsService/DeleteFlavor', + request_serializer=vm__operations__pb2.DeleteFlavorRequest.SerializeToString, + response_deserializer=vm__operations__pb2.VmResponse.FromString, + ) + + +class VmOperationsServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def CreateVm(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def StartVm(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def StopVm(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def AttachDisk(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DetachDisk(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CreateFlavor(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeleteFlavor(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_VmOperationsServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'CreateVm': grpc.unary_unary_rpc_method_handler( + servicer.CreateVm, + request_deserializer=vm__operations__pb2.CreateVmRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + 'StartVm': grpc.unary_unary_rpc_method_handler( + servicer.StartVm, + request_deserializer=vm__operations__pb2.StartVmRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + 'StopVm': grpc.unary_unary_rpc_method_handler( + servicer.StopVm, + request_deserializer=vm__operations__pb2.StopVmRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + 'AttachDisk': grpc.unary_unary_rpc_method_handler( + servicer.AttachDisk, + request_deserializer=vm__operations__pb2.AttachDiskRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + 'DetachDisk': grpc.unary_unary_rpc_method_handler( + servicer.DetachDisk, + request_deserializer=vm__operations__pb2.DetachDiskRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + 'CreateFlavor': grpc.unary_unary_rpc_method_handler( + servicer.CreateFlavor, + request_deserializer=vm__operations__pb2.CreateFlavorRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + 'DeleteFlavor': grpc.unary_unary_rpc_method_handler( + servicer.DeleteFlavor, + request_deserializer=vm__operations__pb2.DeleteFlavorRequest.FromString, + response_serializer=vm__operations__pb2.VmResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'vmoperations.VmOperationsService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class VmOperationsService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def CreateVm(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/CreateVm', + vm__operations__pb2.CreateVmRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def StartVm(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/StartVm', + vm__operations__pb2.StartVmRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def StopVm(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/StopVm', + vm__operations__pb2.StopVmRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def AttachDisk(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/AttachDisk', + vm__operations__pb2.AttachDiskRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def DetachDisk(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/DetachDisk', + vm__operations__pb2.DetachDiskRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def CreateFlavor(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/CreateFlavor', + vm__operations__pb2.CreateFlavorRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def DeleteFlavor(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/vmoperations.VmOperationsService/DeleteFlavor', + vm__operations__pb2.DeleteFlavorRequest.SerializeToString, + vm__operations__pb2.VmResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/vm_operations_service.py b/vm_operations_service.py new file mode 100644 index 0000000000000000000000000000000000000000..21d25718b4f8a60b69ae56beae97ada354cf6c2d --- /dev/null +++ b/vm_operations_service.py @@ -0,0 +1,81 @@ +# vm_operations_service.py + +import grpc +from concurrent import futures +import vm_operations_pb2 +import vm_operations_pb2_grpc + +# 导入你的后端代码中的相关类和方法 +from backends import VMOps, Flavor + +class VmOperationsService(vm_operations_pb2_grpc.VmOperationsServiceServicer): + def __init__(self): + # 初始化后端代码的对象 + self.vm_ops = VMOps() + + def CreateVm(self, request, context): + # 调用后端代码中的创建虚拟机方法 + # 这里需要根据请求中的参数构造适当的参数 + vm_name = request.vm_name + vnuma_enabled = request.vnuma_enabled + vm_gen = request.vm_gen + instance_path = request.instance_path + root_disk_path = request.root_disk_path + flavor_data = request.flavor + flavor = Flavor(flavor_data.flavor_name, flavor_data.cpucores_num, flavor_data.ram_capacity, flavor_data.disk_capacity) + response_message = self.vm_ops.build_and_run_vm(vm_name, uuid, image_name, vnuma_enabled, vm_gen, instance_path, root_disk_path, flavor) + return vm_operations_pb2.VmResponse(message=response_message) + + def StartVm(self, request, context): + # 实现启动虚拟机方法 + vm_name = request.vm_name + response_message = self.vm_ops.start_vm(vm_name) # 调用后端代码中的启动虚拟机方法 + return vm_operations_pb2.VmResponse(message=response_message) + + def StopVm(self, request, context): + # 实现停止虚拟机方法 + vm_name = request.vm_name + response_message = self.vm_ops.stop_vm(vm_name) # 调用后端代码中的停止虚拟机方法 + return vm_operations_pb2.VmResponse(message=response_message) + + def AttachDisk(self, request, context): + # 实现挂载磁盘方法 + vm_name = request.vm_name + disk_path = request.disk_path + drive_type = request.drive_type + response_message = self.vm_ops.attach_disk(vm_name, disk_path, drive_type) # 调用后端代码中的挂载磁盘方法 + return vm_operations_pb2.VmResponse(message=response_message) + + def DetachDisk(self, request, context): + # 实现卸载磁盘方法 + vm_name = request.vm_name + disk_path = request.disk_path + response_message = self.vm_ops.detach_disk(vm_name, disk_path) # 调用后端代码中的卸载磁盘方法 + return vm_operations_pb2.VmResponse(message=response_message) + + def CreateFlavor(self, request, context): + # 实现创建虚拟机规格方法 + flavor_name = request.flavor_name + cpucores_num = request.cpucores_num + ram_capacity = request.ram_capacity + disk_capacity = request.disk_capacity + response_message = self.vm_ops.create_flavor(flavor_name, cpucores_num, ram_capacity, disk_capacity) + # 调用后端代码中的创建虚拟机规格方法 + return vm_operations_pb2.VmResponse(message=response_message) + + def DeleteFlavor(self, request, context): + # 实现删除虚拟机规格方法 + flavor_id = request.flavor_id + response_message = self.vm_ops.delete_flavor(flavor_id) # 调用后端代码中的删除虚拟机规格方法 + return vm_operations_pb2.VmResponse(message=response_message) + + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + vm_operations_pb2_grpc.add_VmOperationsServiceServicer_to_server(VmOperationsService(), server) + server.add_insecure_port('[::]:50051') + server.start() + server.wait_for_termination() + +if __name__ == '__main__': + serve() \ No newline at end of file