Example #1
0
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)
Example #4
0
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
Example #5
0
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)