def _check_mem_allocation(instance_id, new_mem, old_mem): ''' 物理机内存不超分(包括已经分配出去的内存) :param instance_id: :param new_mem: :param old_mem: :return: ''' host_data = ins_s.get_host_of_instance(instance_id) if not host_data: return False host_all_data = host_s_s.get_host_used(host_data) if host_all_data: # 保留内存GB -> MB hold_mem = host_data['hold_mem_gb'] * 1024 mem_size = host_all_data['mem_size'] allocate_mem = host_s.get_vm_assign_mem_of_host(host_data['id']) # 增量 < 总量 - 已分配(flavor的mem) - 保留 if long(new_mem) - long(old_mem) < long(mem_size) - long(allocate_mem) - long(hold_mem): return True return False
def hot_migrate_init(instance_id): ''' 获取迁移时满足条件的目标主机 :param instance_id: :return: ''' # def _check_init(): # 检测虚拟机本身是否符合迁移条件,暂时不做 # pass def _check_cpu(): #暂时不检测CPU型号 pass def _check_mem(host, instance_mem): ''' 检测host是否有足够的内存资源和磁盘资源 :param host: :param instance_mem: :return: ''' # host已分配内存 assign_mem = host_s.get_vm_assign_mem_of_host(host['host_id']) # 已分配 + 预分配 > 总大小 if assign_mem + int(instance_mem) >= int(host['mem_size']): logging.error( 'host %s assign mem %s + instance mem %s > mem size %s', host['host_id'], assign_mem, instance_mem, host['mem_size']) return False return True if not instance_id: logging.info('no instance id when get migrate hosts') return json_helper.format_api_resp(code=ErrorCode.PARAM_ERR, msg="参数错误") resp = MigrateHostsResp() ins_data = ins_s.InstanceService().get_instance_info(instance_id) if ins_data: resp.instance_name = ins_data['name'] resp.instance_status = ins_data['status'] ins_flavor_data = ins_s.get_flavor_of_instance(instance_id) if ins_flavor_data: resp.instance_cpu = ins_flavor_data['vcpu'] resp.instance_mem = ins_flavor_data['memory_mb'] resp.instance_disk = ins_flavor_data['root_disk_gb'] ins_ip_data = ins_s.get_ip_of_instance(instance_id) if ins_ip_data: resp.instance_ip = ins_ip_data['ip_address'] ins_host = ins_s.get_host_of_instance(instance_id) if not ins_host: logging.error( 'instance %s of host is not exist in db when get migrate host', instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机所在物理机信息") ins_group = ins_g_s.InstanceGroupService().get_instance_group_info( instance_id) if not ins_group: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机所在应用组信息") data_disk_status, data_disk_size = ins_s.get_data_disk_size_of_instance( instance_id) if not data_disk_status: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取被迁移虚拟机磁盘配置信息") instance_disk_size = int( ins_flavor_data['root_disk_gb']) + int(data_disk_size) # 同一集群 all_hosts_nums, all_hosts_data = host_s.HostService( ).get_available_hosts_of_hostpool(ins_host['hostpool_id']) if all_hosts_nums <= 0: logging.error('no host in hostpool %s when get migrate host', ins_host['hostpool_id']) return json_helper.format_api_resp(code=ErrorCode.SUCCESS, data={}, msg="集群下没有一台可用物理机") # 过滤host # 这里不核对host的cpu型号 hosts_after_filter = host_s_s.migrate_filter_hosts(all_hosts_data, int(all_hosts_nums)) if len(hosts_after_filter) == 0: logging.info('no available host when get migrate host') return json_helper.format_api_resp(code=ErrorCode.SUCCESS, data={}, msg="集群内其他物理机cpu、内存使用率超过阀值,暂时不能迁移") # VM分配给HOST看是否满足迁移 vm = { "vcpu": ins_flavor_data['vcpu'], "mem_MB": ins_flavor_data['memory_mb'], "disk_GB": instance_disk_size, } host_after_match = host_s_s.migrate_match_hosts(hosts_after_filter, vm, ins_group['group_id'], least_host_num=1, max_disk=2000) if len(host_after_match) == 0: logging.info('no available host when get migrate host') return json_helper.format_api_resp( code=ErrorCode.SUCCESS, data={}, msg="集群内其他物理机cpu、内存资源不足或者应用互斥,暂时不能迁移") ins_flavor = ins_s.get_flavor_of_instance(instance_id) if not ins_flavor: logging.error( 'instance %s flavor is not exist in db when get migrate host', instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="kvm平台未找到指定配置规格") for _host in host_after_match: # 去除本身host / 内存/磁盘分配足够 if _host['host_id'] != ins_host['id']: _h = { 'host_id': _host['host_id'], 'host_name': _host['name'], 'current_cpu_used': _host['current_cpu_used'], 'current_mem_used': _host['current_mem_used'], 'free_disk_space': int(_host["disk_size"]) * (100 - int(_host["current_disk_used"])) / 100 } resp.host_list.append(_h) return json_helper.format_api_resp(code=ErrorCode.SUCCESS, data=resp.to_json())
def instance_hot_migrate(instance_id, host_id): ''' 虚拟机迁移 :param instance_id: :param host_id: :return: ''' speed_limit = request.values.get('speed_limit') if not instance_id or not host_id or not speed_limit or int( speed_limit) < 0: logging.info('the params is invalid when migrate instance') return json_helper.format_api_resp(code=ErrorCode.PARAM_ERR, msg="参数错误") host_data_s = ins_s.get_host_of_instance(instance_id) if not host_data_s: logging.error( 'instance %s of host is not exist in db when migrate instance', str(instance_id)) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) host_data_d = host_s.HostService().get_host_info(host_id) if not host_data_d: logging.error( 'target host %s is not exist in db when migrate instance', str(instance_id)) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) if host_data_d['typestatus'] == HostTypeStatus.LOCK or host_data_d[ 'typestatus'] == HostTypeStatus.MAINTAIN: logging.error( 'target host %s is in invalid status %s when migrate instance', host_id, host_data_d['typestatus']) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='不能迁移到锁定或维护的主机上') ins_flavor_data = ins_s.get_flavor_of_instance(instance_id) if not ins_flavor_data: logging.error('hot migrate can not get instance %s flavor info' % str(instance_id)) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='无法获取被迁移虚拟机的基础配置信息') ins_group = ins_g_s.InstanceGroupService().get_instance_group_info( instance_id) if not ins_group: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机所在应用组信息") data_disk_status, data_disk_size = ins_s.get_data_disk_size_of_instance( instance_id) if not data_disk_status: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取被迁移虚拟机磁盘配置信息") instance_disk_size = int( ins_flavor_data['root_disk_gb']) + int(data_disk_size) # 获取物理机所在资源池可用物理机数量 all_hosts_nums, all_hosts_data = host_s.HostService( ).get_available_hosts_of_hostpool(host_data_d["hostpool_id"]) if all_hosts_nums < 1: return False, '集群物理机资源不足,无法满足虚拟机迁移' host_data_d_before_match = [] host_data_d_before_match.append(host_data_d) # 过滤host # 这里不核对host的cpu型号 hosts_after_filter = host_s_s.migrate_filter_hosts( host_data_d_before_match, int(all_hosts_nums)) if len(hosts_after_filter) == 0: logging.info('no available host when get migrate host') return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="集群内其他物理机cpu、内存使用率超过阀值,暂时不能迁移") # VM分配给HOST看是否满足迁移 vm = { "vcpu": ins_flavor_data['vcpu'], "mem_MB": ins_flavor_data['memory_mb'], "disk_GB": instance_disk_size, } host_after_match = host_s_s.migrate_match_hosts(hosts_after_filter, vm, ins_group['group_id'], least_host_num=1, max_disk=2000) if len(host_after_match) == 0: logging.info('no available host when get migrate host') return json_helper.format_api_resp( code=ErrorCode.SYS_ERR, msg="集群内其他物理机cpu、内存资源不足或者应用互斥,暂时不能迁移") # 不能本身 if host_data_s['id'] == host_id: logging.error('no allow migrate to the same host %s', host_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="不能迁移到原主机上") ins_data_s = ins_s.InstanceService().get_instance_info(instance_id) if not ins_data_s: logging.error('instance %s is not exist in db when migrate instance') return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) # 排除非法状态,vm只能在开机状态下才能热迁移 if ins_data_s['status'] != VMStatus.STARTUP or ins_data_s[ 'typestatus'] != VMTypeStatus.NORMAL: logging.error( 'instance status %s, typestatus %s is invalid when migrate instance', ins_data_s['status'], ins_data_s['typestatus']) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='只能在关机状态下执行热迁移') # 检测目标主机是否有迁入VM if not _check_has_migrate(host_id): logging.error( 'dest host %s has other migrating instance when migrate instance', host_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='目标主机现有正在迁入的虚机,不能迁移到该主机') # 将VM状态改为热迁移中 update_data = { 'status': VMStatus.MIGRATE, # 热迁移中 'updated_at': get_datetime_str() } where_data = {'id': instance_id} ret = ins_s.InstanceService().update_instance_info(update_data, where_data) if ret != 1: logging.error( 'update instance status error when cold migrate, update_data:%s, where_data:%s', update_data, where_data) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) ins_data = ins_s.InstanceService().get_instance_info(instance_id) # 新增一个instance_dsthost记录,dsthost为目标host的ip # 迁移过程中失败则删除这条新增的Instance_dsthost记录,迁移成功之后则删除Instance_srchost记录 # 迁移过程中前端vm页面不会显示这条新增的记录 instance_host_data = { 'instance_id': instance_id, 'instance_name': ins_data['name'], 'host_id': host_id, 'host_name': host_data_d['name'], 'isdeleted': '0', 'created_at': get_datetime_str() } ret_h = ins_h_s.InstanceHostService().add_instance_host_info( instance_host_data) if ret_h.get('row_num') <= 0: logging.error( 'add instance host info error when hot migrate, %instance_id,%host_id' ) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) # 在instance_migrate表中增加一条数据 insert_data = { 'instance_id': instance_id, 'src_host_id': host_data_s['id'], 'dst_host_id': host_id, 'migrate_status': MigrateStatus.DOING, 'created_at': get_datetime_str() } ret_m = ins_m_s.InstanceMigrateService().add_instance_migrate_info( insert_data) if ret_m.get('row_num') <= 0: logging.error( 'add instance migrate info error when cold migrate, insert_data:%s', insert_data) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) # 发送异步消息到队列 data = { "routing_key": "INSTANCE.HOTMIGRATE", "send_time": get_datetime_str(), "data": { "request_id": ins_s.generate_req_id(), "user_id": get_user()['user_id'], "migrate_tab_id": ret_m.get('last_id'), "task_id": ins_s.generate_task_id(), "speed_limit": speed_limit, "ins_data_s": { "id": ins_data_s['id'], "uuid": ins_data_s['uuid'], "name": ins_data_s['name'] }, "host_data_d": { "id": host_data_d['id'], "name": host_data_d['name'], "ipaddress": host_data_d['ipaddress'] }, "host_data_s": { "id": host_data_s['id'], "name": host_data_s['name'], "ipaddress": host_data_s['ipaddress'], "sn": host_data_s['sn'] } } } # todo:这里有可能发送不成功 ret_kafka = send_async_msg(KAFKA_TOPIC_NAME, data) return json_helper.format_api_resp(code=ErrorCode.SUCCESS)
def get_collect_request_multithreading(task_idapi, task_idkvm, vm_count, request_opr_user, request_api_origin): # 判断此工单是否有线程在追踪 try: params = { 'WHERE_AND': { '=': { 'taskid_kvm': task_idkvm, 'taskid_api': task_idapi, 'istraceing': '1' }, } } ret_traceing_nums, ret_traceing_data = request_r_s.RequestRecordService( ).request_db_query_data(**params) if ret_traceing_nums > 0: return # 标记工单为跟踪中 _update_data = { 'istraceing': '1', } _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService().update_request_status( _update_data, _where_data) if ret <= 0: logging.error('update request %s status to db failed' % task_idkvm) ret_request_re = request_r_s.RequestRecordService( ).get_request_record_info_by_taskid_kvm(task_idkvm) request_ip = ret_request_re["request_ip"] succeed_http_code = ['200', '500'] instance_actions_succeed_params = { 'WHERE_AND': { '=': { 'task_id': task_idkvm, 'action': 'instance_inject_data', 'status': 1 }, }, } # instance_actions_failed_params = { # 'WHERE_AND': { # '=': { # 'task_id': task_idkvm, # 'status': 2 # }, # '!=': { # 'action': 'image_sync_status' # }, # }, # } instance_timeout_failed_params = { 'WHERE_AND': { '=': { 'task_id': task_idkvm, 'status': VMStatus.CREATE_ERROR }, }, } vm_succeed_count_db_ret, vm_succeed_data = instance_a_s.InstanceActionsServices( ).query_data(**instance_actions_succeed_params) # vm_failed_count_db_ret, vm_failed_data = # instance_a_s.InstanceActionsServices().query_data(**instance_actions_failed_params) vm_createtimeout_count_db_ret, vm_createtimeout_failed_data = instance_s.InstanceService( ).query_data(**instance_timeout_failed_params) if not vm_succeed_count_db_ret: vm_succeed_count_db_ret = 0 if not vm_createtimeout_count_db_ret: vm_createtimeout_count_db_ret = 0 instances_uuid = [] if vm_succeed_count_db_ret > 0: for per_request_data in vm_succeed_data: instances_uuid.append(per_request_data['instance_uuid']) if vm_count == vm_succeed_count_db_ret: # 通过虚拟机uuid查询主机名、ip、物理机序列号 vm_datas = [] for instance_uuid in instances_uuid: ret_ins = instance_s.InstanceService( ).get_instance_info_by_uuid(instance_uuid) if ret_ins: ret_ins_host = instance_s.get_host_of_instance( ret_ins['id']) ret_ins_ip = instance_s.get_net_segment_info_of_instance( ret_ins['id']) if ret_ins_host and ret_ins_ip: vm_data = { 'instance_ids': ret_ins['id'], 'host_name': ret_ins['name'], 'ip': ret_ins_ip['ip_address'], 'ip_type': ret_ins_ip['segment_type'], 'sn': ret_ins_host['sn'], 'UUID': instance_uuid, 'net_name': ret_ins_ip['segment'], 'subnet_mask': ret_ins_ip['netmask'], 'gateway': ret_ins_ip['gateway_ip'], 'vlan_id': ret_ins_ip['vlan'], 'passWord': decrypt(ret_ins['password']) } vm_datas.append(vm_data) msg_detail = {'opUser': request_opr_user, 'vm': vm_datas} # 回调外部接口 response_to_api_status = '1' if request_api_origin == ApiOrigin.VISHNU: ret_code = msg_to_vishnu(task_idapi, VsJobStatus.SUCCEED, msg_detail, request_ip) elif request_api_origin == ApiOrigin.SFSLB: ret_code = msg_to_sfslb(task_idapi, VsJobStatus.SUCCEED, msg_detail, request_ip) elif request_api_origin == ApiOrigin.FWAF: ret_code = msg_to_fwaf(task_idapi, VsJobStatus.SUCCEED, msg_detail, request_ip) else: ret_code = msg_to_vishnu(task_idapi, VsJobStatus.SUCCEED, msg_detail, request_ip) if ret_code not in succeed_http_code: response_to_api_status = '0' update_db_time = get_datetime_str() _update_data = { 'task_status': '1', 'response_to_api': response_to_api_status, 'finish_time': update_db_time, 'request_status_collect_time': update_db_time, } _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService().update_request_status( _update_data, _where_data) if ret <= 0: logging.error('update request %s status to db failed' % task_idkvm) elif (vm_createtimeout_count_db_ret + vm_succeed_count_db_ret) == vm_count \ and vm_createtimeout_count_db_ret > vm_count * 0.2: # 回调外部接口 response_to_api_status = '1' if request_api_origin == ApiOrigin.VISHNU: ret_code = msg_to_vishnu(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) elif request_api_origin == ApiOrigin.SFSLB: ret_code = msg_to_sfslb(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) elif request_api_origin == ApiOrigin.FWAF: ret_code = msg_to_fwaf(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) else: ret_code = msg_to_vishnu(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) if ret_code not in succeed_http_code: response_to_api_status = '0' update_db_time = get_datetime_str() _update_data = { 'task_status': '2', 'response_to_api': response_to_api_status, 'finish_time': update_db_time, 'request_status_collect_time': update_db_time, } _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService().update_request_status( _update_data, _where_data) if ret <= 0: logging.error('update request %s status to db failed' % task_idkvm) else: if (vm_createtimeout_count_db_ret + vm_succeed_count_db_ret) == vm_count: # 把成功创建的虚拟机返回外部接口 """ vm_datas = [] for instance_uuid in instances_uuid: ret_ins = instance_s.InstanceService().get_instance_info_by_uuid(instance_uuid) if ret_ins: ret_ins_host = instance_s.get_host_of_instance(ret_ins['id']) ret_ins_ip = instance_s.get_net_segment_info_of_instance(ret_ins['id']) if ret_ins_host and ret_ins_ip: vm_data = { 'host_name': ret_ins['name'], 'ip': ret_ins_ip['ip_address'], 'sn': ret_ins_host['sn'], 'UUID': instance_uuid, 'net_name': ret_ins_ip['segment'], 'subnet_mask': ret_ins_ip['netmask'], 'gateway': ret_ins_ip['gateway_ip'], 'vlan_id': ret_ins_ip['vlan'] } vm_datas.append(vm_data) msg_detail = {'opUser': request_opr_user, 'vm': vm_datas} """ # 回调外部接口 response_to_api_status = '1' if request_api_origin == ApiOrigin.VISHNU: ret_code = msg_to_vishnu( task_idapi, VsJobStatus.FAILED, 'part of kvm instance create failed', request_ip) elif request_api_origin == ApiOrigin.SFSLB: ret_code = msg_to_sfslb( task_idapi, VsJobStatus.FAILED, 'part of kvm instance create failed', request_ip) elif request_api_origin == ApiOrigin.FWAF: ret_code = msg_to_fwaf( task_idapi, VsJobStatus.FAILED, 'part of kvm instance create failed', request_ip) else: ret_code = msg_to_vishnu( task_idapi, VsJobStatus.FAILED, 'part of kvm instance create failed', request_ip) if ret_code not in succeed_http_code: response_to_api_status = '0' update_db_time = get_datetime_str() _update_data = { 'task_status': '2', 'response_to_api': response_to_api_status, 'finish_time': update_db_time, 'request_status_collect_time': update_db_time, } _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService( ).update_request_status(_update_data, _where_data) if ret <= 0: logging.error('update request %s status to db failed' % task_idkvm) else: # 成功失败的总数量未等于count pass elif vm_createtimeout_count_db_ret > 0: # 全部虚拟机创建失败 if (vm_createtimeout_count_db_ret + vm_succeed_count_db_ret) == vm_count \ and vm_createtimeout_count_db_ret > vm_count * 0.2: # 回调外部接口 response_to_api_status = '1' if request_api_origin == ApiOrigin.VISHNU: ret_code = msg_to_vishnu(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) elif request_api_origin == ApiOrigin.SFSLB: ret_code = msg_to_sfslb(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) elif request_api_origin == ApiOrigin.FWAF: ret_code = msg_to_fwaf(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) else: ret_code = msg_to_vishnu(task_idapi, VsJobStatus.FAILED, 'all kvm instance create failed', request_ip) if ret_code not in succeed_http_code: response_to_api_status = '0' update_db_time = get_datetime_str() _update_data = { 'task_status': '2', 'response_to_api': response_to_api_status, 'finish_time': update_db_time, 'request_status_collect_time': update_db_time, } _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService().update_request_status( _update_data, _where_data) if ret <= 0: logging.error('update request %s status to db failed' % task_idkvm) else: update_db_time = get_datetime_str() _update_data = {'request_status_collect_time': update_db_time} _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService().update_request_status( _update_data, _where_data) if ret <= 0: logging.error('update request %s status to db failed' % task_idkvm) # 标记工单为完成追踪 _update_data = { 'istraceing': '0', } _where_data = { 'taskid_kvm': task_idkvm, } ret = request_r_s.RequestRecordService().update_request_status( _update_data, _where_data) if ret <= 0: logging.error( 'update request %s status to db failed when mark istraceing 1' % task_idkvm) return except Exception as e: logging.error('request {} threading exception error: {}'.format( task_idkvm, e)) return
def instance_configure(instance_id): ''' 虚机修改配置 规则: 热修改(开机状态):cpu disk 加 冷修改(关机状态):cpu mem 加减 disk 加 :param instance_id: :return: ''' n_flavor_id = request.values.get('flavor_id') n_app_info = request.values.get('app_info') n_owner = request.values.get('owner') n_group_id = request.values.get('group_id') n_net_conf_list_req = request.values.get('net_status_list') # start n_extend_list_req = request.values.get('extend_list') n_qemu_ga_update_req = request.values.get('qemu_ga_update') c_system = '' c_version = None # end if not instance_id or not n_flavor_id or not n_group_id: logging.error('params is invalid when change instance configure') return json_helper.format_api_resp(code=ErrorCode.PARAM_ERR) ins_data = ins_s.InstanceService().get_instance_info(instance_id) ###################################add 2017/09/29#############################3 uuid = ins_data['uuid'] user_id = get_user()['user_id'] request_id = ins_s.generate_req_id() if not ins_data: logging.error('the instance %s is not exist in db when change instance configure', instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) # --------------------edit 2017/11/13----------------------- if ins_data['create_source'] == '0': ins_images_data = ins_s.get_images_of_instance(instance_id) if ins_images_data: c_system = ins_images_data[0]['system'] else: ins_images_data = v2v_ins_s.V2VInstanceService().get_v2v_instance_info(instance_id) if ins_images_data: c_system = ins_images_data['os_type'] ins_status = ins_data['status'] # 获取虚拟机所在物理机信息 host_data = ins_s.get_host_of_instance(instance_id) ins_datacenter_info = ins_s.get_datacenter_of_instance(instance_id) if not host_data or not ins_datacenter_info: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机所在物理机信息、机房信息") ins_data['dc_type'] = ins_datacenter_info['dc_type'] # 新flavor信息 n_flavor_data = fla_s.FlavorService().get_flavor_info(n_flavor_id) if not n_flavor_data: logging.error('flavor %s is invalid in db when change instance configure', n_flavor_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='新的配置数据有误,无法修改配置') # 虚机现有flavor信息 c_flavor_data = ins_s.get_flavor_of_instance(instance_id) if not c_flavor_data: logging.error('instance %s flavor is invalid in db when change instance configure', instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) c_group_data = ins_s.get_group_of_instance(instance_id) if c_group_data and int(c_group_data['group_id']) != int(n_group_id): # 检查新应用组的配额 is_group_enough, req_msg = _check_change_group_quota(n_group_id, n_flavor_data, c_flavor_data) if not is_group_enough: logging.error('new group %s quota is not enough to change new flavor', n_group_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg=req_msg) params = {} if json_helper.loads(n_extend_list_req): # 检查当前应用组的配额 is_group_enough, req_msg = _check_change_group_quota(n_group_id, n_flavor_data, c_flavor_data, json_helper.loads(n_extend_list_req)) if not is_group_enough: logging.error('new group %s quota is not enough to change new flavor', n_group_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg=req_msg) # 检查物理机当前使用率情况是否满足扩容 is_host_available, ret_msg = __check_host_capacity(host_data, n_flavor_data, c_flavor_data , json_helper.loads(n_extend_list_req)) if not is_host_available: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg=ret_msg) vmname = ins_data['name'] uuid = '' host_ip = '' n_extend_list_req = json_helper.loads(n_extend_list_req) try: uuid = ins_data['uuid'] host_ip = ins_s.get_hostip_of_instance(instance_id) except: pass connect_instance = vmManager.libvirt_get_connect(host_ip, conn_type='instance', vmname=ins_data['name']) if not connect_instance: pass # 添加扩容开始action ins_a_s.update_instance_status(VMStatus.CONFIGURE_ING, instance_id) ins_a_s.add_disk_extend_action_to_database(uuid, request_id, user_id, InstaceActions.INSTANCE_DISK_EXTEND, ActionStatus.START, 'start') # 满足扩容条件 if n_qemu_ga_update_req: if c_system.strip() == 'linux': flag, msg = connect_instance.exec_qemu_command( "cat /proc/self/mounts | grep -w / | grep -v rootfs | awk '{print $3}'") if not flag: c_version = None c_version = CentOS_Version.CentOS_6 if msg.strip() == 'ext4' else CentOS_Version.CentOS_7 flag, result = ins_a_s.extend_mount_size(n_extend_list_req, host_ip, vmname, uuid, c_version, instance_id) elif c_system.strip() == 'windows': flag, result = ins_a_s.extend_dev_size(n_extend_list_req, host_ip, vmname, uuid, instance_id) else: flag = False if flag: msg = "扩容成功" ins_a_s.update_disk_action_to_database(request_id, InstaceActions.INSTANCE_DISK_EXTEND, ActionStatus.SUCCSESS, msg) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) else: msg = "扩容失败,{}".format(result) ins_a_s.update_disk_action_to_database(request_id, InstaceActions.INSTANCE_DISK_EXTEND, ActionStatus.FAILD, msg) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.ALL_FAIL, msg=msg) else : # 非linux系统,关机状态,qemu-guest-agent没有更新成功 msg = "非linux系统,扩容失败" ins_a_s.update_disk_action_to_database(request_id, InstaceActions.INSTANCE_DISK_EXTEND, ActionStatus.FAILD, msg) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.ALL_FAIL, msg=msg) else: pass if c_flavor_data['vcpu'] != n_flavor_data['vcpu'] or c_flavor_data['memory_mb'] != n_flavor_data['memory_mb']: # 检查当前应用组的配额 is_group_enough, req_msg = _check_change_group_quota(n_group_id, n_flavor_data, c_flavor_data) if not is_group_enough: logging.error('new group %s quota is not enough to change new flavor', n_group_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg=req_msg) # 检查物理机当前使用率情况是否满足扩容 is_host_available, ret_msg = __check_host_capacity(host_data, n_flavor_data, c_flavor_data) if not is_host_available: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg=ret_msg) # 关机状态 if ins_status == VMStatus.SHUTDOWN: pass elif ins_status == VMStatus.STARTUP: # 开机状态 # cpu只能增 if c_flavor_data['vcpu'] > n_flavor_data['vcpu']: logging.error('vcpu only be increase in startup status, now vcpu %s > new vcpu %s', c_flavor_data['vcpu'], n_flavor_data['vcpu']) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='开机状态下,CPU数量只能增加不能减少') # 内存不能修改 if c_flavor_data['memory_mb'] != n_flavor_data['memory_mb']: logging.error('memory only no allow be change in startup status, now mem %s, new mem %s', c_flavor_data['memory_mb'], n_flavor_data['memory_mb']) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='开机状态下,不能修改内存容量') else: logging.error('instance status %s is invalid when change instance configure', ins_status) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='只能在开机或关机状态下修改配置') if n_flavor_data['vcpu'] == c_flavor_data['vcpu']: pass else: params['new_vcpu'] = n_flavor_data['vcpu'] params['old_vcpu'] = c_flavor_data['vcpu'] new_mem = n_flavor_data['memory_mb'] old_mem = c_flavor_data['memory_mb'] if new_mem == old_mem: pass else: # 检查内存是否超分 if not _check_mem_allocation(instance_id, new_mem, old_mem): logging.error('instance %s mem has over allocation, new mem %s, old mem %s', instance_id, new_mem, old_mem) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg='物理内存不能超分') params['new_mem'] = new_mem params['old_mem'] = old_mem # 检查网络配置是否需要修改 n_net_conf_list = json_helper.loads(n_net_conf_list_req) if n_net_conf_list: params['net_status_list'] = n_net_conf_list # 没有一个指标可以修改 if not params: logging.error('vcpu, mem, disk no one can change when change instance configure') else: host_ip = ins_s.get_hostip_of_instance(ins_data['id']) if not host_ip: logging.error('instance %s has no host ip when change instance configure', ins_data['id']) ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) ret_flavor = ins_a_s.change_instance_configure(host_ip, ins_data, c_flavor_data['flavor_id'], n_flavor_id, ins_status, **params) if not ret_flavor: ins_a_s.update_instance_status(VMStatus.STARTUP, instance_id) return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) update_data_i = { 'app_info': n_app_info, 'owner': n_owner, 'updated_at': get_datetime_str() } where_data_i = { 'id': instance_id } ret_i = ins_s.InstanceService().update_instance_info(update_data_i, where_data_i) # if ret_i != 1: # logging.error('update instance info error when configure, update_data:%s, where_data:%s', # update_data_i, where_data_i) # return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) update_data_g = { 'group_id': n_group_id, 'updated_at': get_datetime_str() } where_data_g = { 'instance_id': instance_id } ret_g = ins_g_s.InstanceGroupService().update_instance_group_info(update_data_g, where_data_g) # if ret_g != 1: # logging.error('update group info error when configure, update_data:%s, where_data:%s', # update_data_g, where_data_g) # return json_helper.format_api_resp(code=ErrorCode.SYS_ERR) # if 'disk_gb_list' in params: # return json_helper.format_api_resp(code=ErrorCode.SUCCESS, msg='硬盘扩容任务发送成功') return json_helper.format_api_resp(code=ErrorCode.SUCCESS, msg='修改配置成功')
def instance_detail_for_miniarch(): ''' 返回miniarch虚拟机所在物理机ip、应用系统信息、cpu、mem、操作系统类型、操作系统版本、磁盘信息、网卡信息 :return: ''' instance_uuid = request.values.get('instance_uuid') if not instance_uuid: return json_helper.format_api_resp(code=ErrorCode.PARAM_ERR, msg="请求入参缺失") ins_data = instance_s.InstanceService().get_instance_info_by_uuid(instance_uuid) if not ins_data: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机信息") ins_host_data = instance_s.get_host_of_instance(ins_data['id']) if not ins_host_data: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机所在物理机信息") # vm_status = instanceManager.libvirt_instance_status(ins_host_data['ipaddress'], ins_data['name']) # # 虚拟机开机状态才可以做迁移 # if vm_status != VMLibvirtStatus.SHUTDOWN: # return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="只有关机状态虚拟机才可执行迁移") ins_flavor_data = instance_s.get_flavor_of_instance(ins_data['id']) if not ins_flavor_data: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机cpu、mem信息") ins_group_data = instance_s.get_group_of_instance(ins_data['id']) if not ins_group_data: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机应用组信息") ins_image_data = instance_s.get_images_of_instance(ins_data['id']) if not ins_image_data: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取虚拟机镜像信息") get_device_status, vm_disks_info = instanceManager.libvirt_get_instance_device(ins_host_data['ipaddress'], ins_data['name']) if get_device_status == -100: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法使用libvirtd获取虚拟机磁盘信息") for _vm_disk in vm_disks_info: if _vm_disk['dev'] == 'vda': _vm_disk['size_gb'] = 80 else: disk_detail = instance_s.get_a_disk_of_instance(ins_data['id'], _vm_disk['dev']) if not disk_detail or not disk_detail['size_gb']: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="获取虚拟机磁盘大小失败") _vm_disk['size_gb'] = disk_detail['size_gb'] netcard_list = [] ins_netcard_info = instance_s.get_net_info_of_instance(ins_data['id']) if not ins_netcard_info: return json_helper.format_api_resp(code=ErrorCode.SYS_ERR, msg="无法获取网卡信息") for _netcard in ins_netcard_info: netcard_params = { 'ip_address': _netcard['ip_address'], 'vlan': _netcard['vlan'], 'mac': _netcard['mac'] } netcard_list.append(netcard_params) instance_data = { 'instance_name': ins_data['name'], 'instance_group': ins_group_data['name'], 'instance_app_info': ins_data['app_info'], 'instance_password': ins_data['password'], 'cpu': ins_flavor_data['vcpu'], 'mem': ins_flavor_data['memory_mb'], 'os_system': ins_image_data[0]['system'], 'os_version': ins_image_data[0]['version'], 'image_name': ins_image_data[0]['name'], 'src_host_ip': ins_host_data['ipaddress'], 'disk': vm_disks_info, 'netcard': netcard_list } return json_helper.format_api_resp(code=ErrorCode.SUCCESS, data=instance_data)