Beispiel #1
0
def update_ssh_key(uuid):

    guest = Guest()
    guest.uuid = uuid
    guest.get_by('uuid')

    # 不支持更新离线虚拟机的 SSH-KEY
    if guest.status != GuestState.running.value:
        return

    os_template_image = OSTemplateImage()
    os_template_profile = OSTemplateProfile()

    os_template_image.id = guest.os_template_image_id
    os_template_image.get()

    os_template_profile.id = os_template_image.os_template_profile_id
    os_template_profile.get()

    # 不支持更新 Windows 虚拟机的 SSH-KEY
    if os_template_profile.os_type == 'windows':
        return

    rows, _ = SSHKeyGuestMapping.get_by_filter(
        filter_str=':'.join(['guest_uuid', 'eq', uuid]))

    ssh_keys_id = list()
    for row in rows:
        ssh_keys_id.append(row['ssh_key_id'].__str__())

    ssh_keys = list()

    if ssh_keys_id.__len__() > 0:
        rows, _ = SSHKey.get_by_filter(
            filter_str=':'.join(['id', 'in', ','.join(ssh_keys_id)]))
        for row in rows:
            ssh_keys.append(row['public_key'])

    else:
        ssh_keys.append('')

    message = {
        '_object': 'guest',
        'uuid': uuid,
        'node_id': guest.node_id,
        'action': 'update_ssh_key',
        'ssh_keys': ssh_keys,
        'os_type': os_template_profile.os_type,
        'passback_parameters': {
            'uuid': uuid,
            'ssh_keys': ssh_keys,
            'os_type': os_template_profile.os_type
        }
    }

    Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))
Beispiel #2
0
def r_reset_password(uuids, password):

    args_rules = [
        Rules.UUIDS.value,
        Rules.PASSWORD.value
    ]

    try:
        ji.Check.previewing(args_rules, {'uuids': uuids, 'password': password})

        guest = Guest()
        os_template_image = OSTemplateImage()
        os_template_profile = OSTemplateProfile()

        # 检测所指定的 UUDIs 实例都存在
        for uuid in uuids.split(','):
            guest.uuid = uuid
            guest.get_by('uuid')

        for uuid in uuids.split(','):
            guest.uuid = uuid
            guest.get_by('uuid')

            os_template_image.id = guest.os_template_image_id
            os_template_image.get()

            os_template_profile.id = os_template_image.os_template_profile_id
            os_template_profile.get()

            user = '******'

            if os_template_profile.os_type == 'windows':
                user = '******'

            # guest.password 由 guest 事件处理机更新。参见 @models/event_processory.py:189 附近。

            message = {
                '_object': 'guest',
                'action': 'reset_password',
                'uuid': guest.uuid,
                'node_id': guest.node_id,
                'os_type': os_template_profile.os_type,
                'user': user,
                'password': password,
                'passback_parameters': {'password': password}
            }

            Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))

        ret = dict()
        ret['state'] = ji.Common.exchange_state(20000)
        return ret

    except ji.PreviewingError, e:
        return json.loads(e.message)
Beispiel #3
0
def r_convert_to_os_template_image(snapshot_id, disk_uuid):

    args_rules = [
        Rules.SNAPSHOT_ID.value,
        Rules.DISK_UUID.value,
        Rules.LABEL.value
    ]

    try:
        ret = dict()
        ret['state'] = ji.Common.exchange_state(20000)

        ji.Check.previewing(args_rules, {'snapshot_id': snapshot_id, 'disk_uuid': disk_uuid,
                                         'label': request.json.get('label')})

        rows, _ = SnapshotDiskMapping.get_by_filter(filter_str=':'.join(['snapshot_id', 'eq', snapshot_id]))

        disks_uuid = list()

        for row in rows:
            disks_uuid.append(row['disk_uuid'])

        if disk_uuid not in disks_uuid:
            ret['state'] = ji.Common.exchange_state(40401)
            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], u': 未在快照: ',
                                                    snapshot_id, u' 中找到磁盘:', disk_uuid])
            return ret

        config = Config()
        config.id = 1
        config.get()

        snapshot = Snapshot()
        os_template_image = OSTemplateImage()
        guest = Guest()
        disk = Disk()

        snapshot.snapshot_id = snapshot_id
        snapshot.get_by('snapshot_id')
        snapshot.progress = 252

        guest.uuid = snapshot.guest_uuid
        guest.get_by('uuid')

        disk.uuid = disk_uuid
        disk.get_by('uuid')

        os_template_image.id = guest.os_template_image_id
        os_template_image.get()

        image_name = '_'.join([snapshot.snapshot_id, disk.uuid]) + '.' + disk.format

        os_template_image.id = 0
        os_template_image.label = request.json.get('label')
        os_template_image.path = '/'.join([os.path.dirname(os_template_image.path), image_name])
        os_template_image.kind = OSTemplateImageKind.custom.value
        os_template_image.progress = 0
        os_template_image.create_time = ji.Common.tus()

        if os_template_image.exist_by('path'):
            ret['state'] = ji.Common.exchange_state(40901)
            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template_image.path])
            return ret

        os_template_image.create()
        os_template_image.get_by('path')

        message = {
            '_object': 'snapshot',
            'action': 'convert',
            'uuid': disk.guest_uuid,
            'snapshot_id': snapshot.snapshot_id,
            'storage_mode': config.storage_mode,
            'dfs_volume': config.dfs_volume,
            'node_id': disk.node_id,
            'snapshot_path': disk.path,
            'template_path': os_template_image.path,
            'os_template_image_id': os_template_image.id,
            'passback_parameters': {'id': snapshot.snapshot_id, 'os_template_image_id': os_template_image.id}
        }

        Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))

        snapshot.update()

        return ret

    except ji.PreviewingError, e:
        return json.loads(e.message)
Beispiel #4
0
class EventProcessor(object):
    message = None
    log = Log()
    guest = Guest()
    guest_migrate_info = GuestMigrateInfo()
    disk = Disk()
    snapshot = Snapshot()
    snapshot_disk_mapping = SnapshotDiskMapping()
    os_template_image = OSTemplateImage()
    config = Config()
    config.id = 1
    guest_cpu_memory = GuestCPUMemory()
    guest_traffic = GuestTraffic()
    guest_disk_io = GuestDiskIO()
    host_cpu_memory = HostCPUMemory()
    host_traffic = HostTraffic()
    host_disk_usage_io = HostDiskUsageIO()

    @classmethod
    def log_processor(cls):
        cls.log.set(type=cls.message['type'],
                    timestamp=cls.message['timestamp'],
                    host=cls.message['host'],
                    message=cls.message['message'],
                    full_message='' if cls.message['message'].__len__() < 255
                    else cls.message['message'])

        cls.log.create()

    @classmethod
    def guest_event_processor(cls):
        cls.guest.uuid = cls.message['message']['uuid']
        cls.guest.get_by('uuid')
        cls.guest.node_id = cls.message['node_id']
        last_status = cls.guest.status
        cls.guest.status = cls.message['type']

        if cls.message['type'] == GuestState.update.value:
            # 更新事件不改变 Guest 的状态
            cls.guest.status = last_status
            cls.guest.xml = cls.message['message']['xml']

        elif cls.guest.status == GuestState.migrating.value:
            try:
                cls.guest_migrate_info.uuid = cls.guest.uuid
                cls.guest_migrate_info.get_by('uuid')

                cls.guest_migrate_info.type = cls.message['message'][
                    'migrating_info']['type']
                cls.guest_migrate_info.time_elapsed = cls.message['message'][
                    'migrating_info']['time_elapsed']
                cls.guest_migrate_info.time_remaining = cls.message['message'][
                    'migrating_info']['time_remaining']
                cls.guest_migrate_info.data_total = cls.message['message'][
                    'migrating_info']['data_total']
                cls.guest_migrate_info.data_processed = cls.message['message'][
                    'migrating_info']['data_processed']
                cls.guest_migrate_info.data_remaining = cls.message['message'][
                    'migrating_info']['data_remaining']
                cls.guest_migrate_info.mem_total = cls.message['message'][
                    'migrating_info']['mem_total']
                cls.guest_migrate_info.mem_processed = cls.message['message'][
                    'migrating_info']['mem_processed']
                cls.guest_migrate_info.mem_remaining = cls.message['message'][
                    'migrating_info']['mem_remaining']
                cls.guest_migrate_info.file_total = cls.message['message'][
                    'migrating_info']['file_total']
                cls.guest_migrate_info.file_processed = cls.message['message'][
                    'migrating_info']['file_processed']
                cls.guest_migrate_info.file_remaining = cls.message['message'][
                    'migrating_info']['file_remaining']

                cls.guest_migrate_info.update()

            except ji.PreviewingError as e:
                ret = json.loads(e.message)
                if ret['state']['code'] == '404':
                    cls.guest_migrate_info.type = cls.message['message'][
                        'migrating_info']['type']
                    cls.guest_migrate_info.time_elapsed = cls.message[
                        'message']['migrating_info']['time_elapsed']
                    cls.guest_migrate_info.time_remaining = cls.message[
                        'message']['migrating_info']['time_remaining']
                    cls.guest_migrate_info.data_total = cls.message['message'][
                        'migrating_info']['data_total']
                    cls.guest_migrate_info.data_processed = cls.message[
                        'message']['migrating_info']['data_processed']
                    cls.guest_migrate_info.data_remaining = cls.message[
                        'message']['migrating_info']['data_remaining']
                    cls.guest_migrate_info.mem_total = cls.message['message'][
                        'migrating_info']['mem_total']
                    cls.guest_migrate_info.mem_processed = cls.message[
                        'message']['migrating_info']['mem_processed']
                    cls.guest_migrate_info.mem_remaining = cls.message[
                        'message']['migrating_info']['mem_remaining']
                    cls.guest_migrate_info.file_total = cls.message['message'][
                        'migrating_info']['file_total']
                    cls.guest_migrate_info.file_processed = cls.message[
                        'message']['migrating_info']['file_processed']
                    cls.guest_migrate_info.file_remaining = cls.message[
                        'message']['migrating_info']['file_remaining']

                    cls.guest_migrate_info.create()

        elif cls.guest.status == GuestState.creating.value:
            if cls.message['message']['progress'] <= cls.guest.progress:
                return

            cls.guest.progress = cls.message['message']['progress']

        elif cls.guest.status == GuestState.snapshot_converting.value:
            cls.os_template_image.id = cls.message['message'][
                'os_template_image_id']
            cls.os_template_image.get()

            if cls.message['message'][
                    'progress'] <= cls.os_template_image.progress:
                return

            cls.os_template_image.progress = cls.message['message']['progress']
            cls.os_template_image.update()
            return

        cls.guest.update()

        # 限定特殊情况下更新磁盘所属 Guest,避免迁移、创建时频繁被无意义的更新
        if cls.guest.status in [
                GuestState.running.value, GuestState.shutoff.value
        ]:
            cls.disk.update_by_filter({'node_id': cls.guest.node_id},
                                      filter_str='guest_uuid:eq:' +
                                      cls.guest.uuid)

    @classmethod
    def host_event_processor(cls):
        key = cls.message['message']['node_id']
        value = {
            'hostname': cls.message['host'],
            'cpu': cls.message['message']['cpu'],
            'system_load': cls.message['message']['system_load'],
            'memory': cls.message['message']['memory'],
            'memory_available': cls.message['message']['memory_available'],
            'interfaces': cls.message['message']['interfaces'],
            'disks': cls.message['message']['disks'],
            'boot_time': cls.message['message']['boot_time'],
            'nonrandom': False,
            'threads_status': cls.message['message']['threads_status'],
            'timestamp': ji.Common.ts()
        }

        db.r.hset(app.config['hosts_info'],
                  key=key,
                  value=json.dumps(value, ensure_ascii=False))

    @classmethod
    def response_processor(cls):
        _object = cls.message['message']['_object']
        action = cls.message['message']['action']
        uuid = cls.message['message']['uuid']
        state = cls.message['type']
        data = cls.message['message']['data']
        node_id = cls.message['node_id']

        if _object == 'guest':
            if action == 'create':
                if state == ResponseState.success.value:
                    # 系统盘的 UUID 与其 Guest 的 UUID 相同
                    cls.disk.uuid = uuid
                    cls.disk.get_by('uuid')
                    cls.disk.guest_uuid = uuid
                    cls.disk.state = DiskState.mounted.value
                    # disk_info['virtual-size'] 的单位为Byte,需要除以 1024 的 3 次方,换算成单位为 GB 的值
                    cls.disk.size = data['disk_info']['virtual-size'] / (1024**
                                                                         3)
                    cls.disk.update()

                else:
                    cls.guest.uuid = uuid
                    cls.guest.get_by('uuid')
                    cls.guest.status = GuestState.dirty.value
                    cls.guest.update()

            elif action == 'migrate':
                pass

            elif action == 'delete':
                if state == ResponseState.success.value:
                    cls.config.get()
                    cls.guest.uuid = uuid
                    cls.guest.get_by('uuid')

                    if IP(cls.config.start_ip).int() <= IP(
                            cls.guest.ip).int() <= IP(cls.config.end_ip).int():
                        if db.r.srem(app.config['ip_used_set'], cls.guest.ip):
                            db.r.sadd(app.config['ip_available_set'],
                                      cls.guest.ip)

                    if (cls.guest.vnc_port - cls.config.start_vnc_port) <= \
                            (IP(cls.config.end_ip).int() - IP(cls.config.start_ip).int()):
                        if db.r.srem(app.config['vnc_port_used_set'],
                                     cls.guest.vnc_port):
                            db.r.sadd(app.config['vnc_port_available_set'],
                                      cls.guest.vnc_port)

                    cls.guest.delete()

                    # TODO: 加入是否删除使用的数据磁盘开关,如果为True,则顺便删除使用的磁盘。否则解除该磁盘被使用的状态。
                    cls.disk.uuid = uuid
                    cls.disk.get_by('uuid')
                    cls.disk.delete()
                    cls.disk.update_by_filter(
                        {
                            'guest_uuid': '',
                            'sequence': -1,
                            'state': DiskState.idle.value
                        },
                        filter_str='guest_uuid:eq:' + cls.guest.uuid)

                    SSHKeyGuestMapping.delete_by_filter(filter_str=':'.join(
                        ['guest_uuid', 'eq', cls.guest.uuid]))

            elif action == 'reset_password':
                if state == ResponseState.success.value:
                    cls.guest.uuid = uuid
                    cls.guest.get_by('uuid')
                    cls.guest.password = cls.message['message'][
                        'passback_parameters']['password']
                    cls.guest.update()

            elif action == 'attach_disk':
                cls.disk.uuid = cls.message['message']['passback_parameters'][
                    'disk_uuid']
                cls.disk.get_by('uuid')
                if state == ResponseState.success.value:
                    cls.disk.guest_uuid = uuid
                    cls.disk.sequence = cls.message['message'][
                        'passback_parameters']['sequence']
                    cls.disk.state = DiskState.mounted.value
                    cls.disk.update()

            elif action == 'detach_disk':
                cls.disk.uuid = cls.message['message']['passback_parameters'][
                    'disk_uuid']
                cls.disk.get_by('uuid')
                if state == ResponseState.success.value:
                    cls.disk.guest_uuid = ''
                    cls.disk.sequence = -1
                    cls.disk.state = DiskState.idle.value
                    cls.disk.update()

            elif action == 'boot':

                if state == ResponseState.success.value:
                    pass

        elif _object == 'disk':
            if action == 'create':
                cls.disk.uuid = uuid
                cls.disk.get_by('uuid')
                cls.disk.node_id = node_id
                if state == ResponseState.success.value:
                    cls.disk.state = DiskState.idle.value

                else:
                    cls.disk.state = DiskState.dirty.value

                cls.disk.update()

            elif action == 'resize':
                if state == ResponseState.success.value:
                    cls.config.get()
                    cls.disk.uuid = uuid
                    cls.disk.get_by('uuid')
                    cls.disk.size = cls.message['message'][
                        'passback_parameters']['size']
                    cls.disk.quota(config=cls.config)
                    cls.disk.update()

            elif action == 'delete':
                cls.disk.uuid = uuid
                cls.disk.get_by('uuid')
                cls.disk.delete()

        elif _object == 'snapshot':
            if action == 'create':
                cls.snapshot.id = cls.message['message'][
                    'passback_parameters']['id']
                cls.snapshot.get()

                if state == ResponseState.success.value:
                    cls.snapshot.snapshot_id = data['snapshot_id']
                    cls.snapshot.parent_id = data['parent_id']
                    cls.snapshot.xml = data['xml']
                    cls.snapshot.progress = 100
                    cls.snapshot.update()

                    disks, _ = Disk.get_by_filter(filter_str='guest_uuid:eq:' +
                                                  cls.snapshot.guest_uuid)

                    for disk in disks:
                        cls.snapshot_disk_mapping.snapshot_id = cls.snapshot.snapshot_id
                        cls.snapshot_disk_mapping.disk_uuid = disk['uuid']
                        cls.snapshot_disk_mapping.create()

                else:
                    cls.snapshot.progress = 255
                    cls.snapshot.update()

            if action == 'delete':
                if state == ResponseState.success.value:
                    cls.snapshot.id = cls.message['message'][
                        'passback_parameters']['id']
                    cls.snapshot.get()

                    # 更新子快照的 parent_id 为,当前快照的 parent_id。因为当前快照已被删除。
                    Snapshot.update_by_filter(
                        {'parent_id': cls.snapshot.parent_id},
                        filter_str='parent_id:eq:' + cls.snapshot.snapshot_id)

                    SnapshotDiskMapping.delete_by_filter(filter_str=':'.join(
                        ['snapshot_id', 'eq', cls.snapshot.snapshot_id]))

                    cls.snapshot.delete()

                else:
                    pass

            if action == 'revert':
                # 不论恢复成功与否,都使快照恢复至正常状态。
                cls.snapshot.id = cls.message['message'][
                    'passback_parameters']['id']
                cls.snapshot.get()
                cls.snapshot.progress = 100
                cls.snapshot.update()

            if action == 'convert':
                cls.snapshot.snapshot_id = cls.message['message'][
                    'passback_parameters']['id']
                cls.snapshot.get_by('snapshot_id')
                cls.snapshot.progress = 100
                cls.snapshot.update()

                cls.os_template_image.id = cls.message['message'][
                    'passback_parameters']['os_template_image_id']
                cls.os_template_image.get()

                if state == ResponseState.success.value:
                    cls.os_template_image.progress = 100

                else:
                    cls.os_template_image.progress = 255

                cls.os_template_image.update()

        elif _object == 'os_template_image':
            if action == 'delete':
                cls.os_template_image.id = cls.message['message'][
                    'passback_parameters']['id']
                cls.os_template_image.get()

                if state == ResponseState.success.value:
                    cls.os_template_image.delete()

                else:
                    pass

        else:
            pass

    @classmethod
    def guest_collection_performance_processor(cls):
        data_kind = cls.message['type']
        timestamp = ji.Common.ts()
        timestamp -= (timestamp % 60)
        data = cls.message['message']['data']

        if data_kind == GuestCollectionPerformanceDataKind.cpu_memory.value:
            for item in data:
                cls.guest_cpu_memory.guest_uuid = item['guest_uuid']
                cls.guest_cpu_memory.cpu_load = item['cpu_load']
                cls.guest_cpu_memory.memory_available = item[
                    'memory_available']
                cls.guest_cpu_memory.memory_unused = item['memory_unused']
                cls.guest_cpu_memory.timestamp = timestamp
                cls.guest_cpu_memory.create()

        if data_kind == GuestCollectionPerformanceDataKind.traffic.value:
            for item in data:
                cls.guest_traffic.guest_uuid = item['guest_uuid']
                cls.guest_traffic.name = item['name']
                cls.guest_traffic.rx_bytes = item['rx_bytes']
                cls.guest_traffic.rx_packets = item['rx_packets']
                cls.guest_traffic.rx_errs = item['rx_errs']
                cls.guest_traffic.rx_drop = item['rx_drop']
                cls.guest_traffic.tx_bytes = item['tx_bytes']
                cls.guest_traffic.tx_packets = item['tx_packets']
                cls.guest_traffic.tx_errs = item['tx_errs']
                cls.guest_traffic.tx_drop = item['tx_drop']
                cls.guest_traffic.timestamp = timestamp
                cls.guest_traffic.create()

        if data_kind == GuestCollectionPerformanceDataKind.disk_io.value:
            for item in data:
                cls.guest_disk_io.disk_uuid = item['disk_uuid']
                cls.guest_disk_io.rd_req = item['rd_req']
                cls.guest_disk_io.rd_bytes = item['rd_bytes']
                cls.guest_disk_io.wr_req = item['wr_req']
                cls.guest_disk_io.wr_bytes = item['wr_bytes']
                cls.guest_disk_io.timestamp = timestamp
                cls.guest_disk_io.create()

        else:
            pass

    @classmethod
    def host_collection_performance_processor(cls):
        data_kind = cls.message['type']
        timestamp = ji.Common.ts()
        timestamp -= (timestamp % 60)
        data = cls.message['message']['data']

        if data_kind == HostCollectionPerformanceDataKind.cpu_memory.value:
            cls.host_cpu_memory.node_id = data['node_id']
            cls.host_cpu_memory.cpu_load = data['cpu_load']
            cls.host_cpu_memory.memory_available = data['memory_available']
            cls.host_cpu_memory.timestamp = timestamp
            cls.host_cpu_memory.create()

        if data_kind == HostCollectionPerformanceDataKind.traffic.value:
            for item in data:
                cls.host_traffic.node_id = item['node_id']
                cls.host_traffic.name = item['name']
                cls.host_traffic.rx_bytes = item['rx_bytes']
                cls.host_traffic.rx_packets = item['rx_packets']
                cls.host_traffic.rx_errs = item['rx_errs']
                cls.host_traffic.rx_drop = item['rx_drop']
                cls.host_traffic.tx_bytes = item['tx_bytes']
                cls.host_traffic.tx_packets = item['tx_packets']
                cls.host_traffic.tx_errs = item['tx_errs']
                cls.host_traffic.tx_drop = item['tx_drop']
                cls.host_traffic.timestamp = timestamp
                cls.host_traffic.create()

        if data_kind == HostCollectionPerformanceDataKind.disk_usage_io.value:
            for item in data:
                cls.host_disk_usage_io.node_id = item['node_id']
                cls.host_disk_usage_io.mountpoint = item['mountpoint']
                cls.host_disk_usage_io.used = item['used']
                cls.host_disk_usage_io.rd_req = item['rd_req']
                cls.host_disk_usage_io.rd_bytes = item['rd_bytes']
                cls.host_disk_usage_io.wr_req = item['wr_req']
                cls.host_disk_usage_io.wr_bytes = item['wr_bytes']
                cls.host_disk_usage_io.timestamp = timestamp
                cls.host_disk_usage_io.create()

        else:
            pass

    @classmethod
    def launch(cls):
        logger.info(msg='Thread EventProcessor is launched.')
        while True:
            if Utils.exit_flag:
                msg = 'Thread EventProcessor say bye-bye'
                print msg
                logger.info(msg=msg)

                return

            try:
                report = db.r.lpop(app.config['upstream_queue'])

                if report is None:
                    time.sleep(1)
                    continue

                cls.message = json.loads(report)

                if cls.message['kind'] == EmitKind.log.value:
                    cls.log_processor()

                elif cls.message['kind'] == EmitKind.guest_event.value:
                    cls.guest_event_processor()

                elif cls.message['kind'] == EmitKind.host_event.value:
                    cls.host_event_processor()

                elif cls.message['kind'] == EmitKind.response.value:
                    cls.response_processor()

                elif cls.message[
                        'kind'] == EmitKind.guest_collection_performance.value:
                    cls.guest_collection_performance_processor()

                elif cls.message[
                        'kind'] == EmitKind.host_collection_performance.value:
                    cls.host_collection_performance_processor()

                else:
                    pass

            except Exception as e:
                logger.error(traceback.format_exc())
                time.sleep(1)
Beispiel #5
0
def r_create():

    args_rules = [
        Rules.CPU.value,
        Rules.MEMORY.value,
        Rules.BANDWIDTH.value,
        Rules.BANDWIDTH_UNIT.value,
        Rules.OS_TEMPLATE_IMAGE_ID.value,
        Rules.QUANTITY.value,
        Rules.REMARK.value,
        Rules.PASSWORD.value,
        Rules.LEASE_TERM.value
    ]

    if 'node_id' in request.json:
        args_rules.append(
            Rules.NODE_ID.value
        )

    if 'ssh_keys_id' in request.json:
        args_rules.append(
            Rules.SSH_KEYS_ID.value
        )

    try:
        ret = dict()
        ret['state'] = ji.Common.exchange_state(20000)

        ji.Check.previewing(args_rules, request.json)

        config = Config()
        config.id = 1
        config.get()

        os_template_image = OSTemplateImage()
        os_template_profile = OSTemplateProfile()

        os_template_image.id = request.json.get('os_template_image_id')
        if not os_template_image.exist():
            ret['state'] = ji.Common.exchange_state(40450)
            ret['state']['sub']['zh-cn'] = ''.join([ret['state']['sub']['zh-cn'], ': ', os_template_image.id.__str__()])
            return ret

        os_template_image.get()
        os_template_profile.id = os_template_image.os_template_profile_id
        os_template_profile.get()

        os_template_initialize_operates, os_template_initialize_operates_count = \
            OSTemplateInitializeOperate.get_by_filter(
                filter_str='os_template_initialize_operate_set_id:eq:' +
                           os_template_profile.os_template_initialize_operate_set_id.__str__())

        if db.r.scard(app.config['ip_available_set']) < 1:
            ret['state'] = ji.Common.exchange_state(50350)
            return ret

        node_id = request.json.get('node_id', None)

        # 默认只取可随机分配虚拟机的 hosts
        available_hosts = Host.get_available_hosts(nonrandom=False)

        # 当指定了 host 时,取全部活着的 hosts
        if node_id is not None:
            available_hosts = Host.get_available_hosts(nonrandom=None)

        if available_hosts.__len__() == 0:
            ret['state'] = ji.Common.exchange_state(50351)
            return ret

        available_hosts_mapping_by_node_id = dict()

        for host in available_hosts:
            if host['node_id'] not in available_hosts_mapping_by_node_id:
                available_hosts_mapping_by_node_id[host['node_id']] = host

        if node_id is not None and node_id not in available_hosts_mapping_by_node_id:
            ret['state'] = ji.Common.exchange_state(50351)
            return ret

        ssh_keys_id = request.json.get('ssh_keys_id', list())
        ssh_keys = list()
        ssh_key_guest_mapping = SSHKeyGuestMapping()

        if ssh_keys_id.__len__() > 0:
            rows, _ = SSHKey.get_by_filter(
                filter_str=':'.join(['id', 'in', ','.join(_id.__str__() for _id in ssh_keys_id)]))

            for row in rows:
                ssh_keys.append(row['public_key'])

        bandwidth = request.json.get('bandwidth')
        bandwidth_unit = request.json.get('bandwidth_unit')

        if bandwidth_unit == 'k':
            bandwidth = bandwidth * 1000

        elif bandwidth_unit == 'm':
            bandwidth = bandwidth * 1000 ** 2

        elif bandwidth_unit == 'g':
            bandwidth = bandwidth * 1000 ** 3

        else:
            ret = dict()
            ret['state'] = ji.Common.exchange_state(41203)
            raise ji.PreviewingError(json.dumps(ret, ensure_ascii=False))

        # http://man7.org/linux/man-pages/man8/tc.8.html
        # 如果带宽大于 tc 所控最大速率,则置其为无限带宽
        # 34359738360 等于 tc 最大可控字节速率,换算出的比特位
        if bandwidth > 34359738360:
            bandwidth = 0

        quantity = request.json.get('quantity')

        while quantity:
            quantity -= 1
            guest = Guest()
            guest.uuid = uuid4().__str__()
            guest.cpu = request.json.get('cpu')
            # 虚拟机内存单位,模板生成方法中已置其为GiB
            guest.memory = request.json.get('memory')
            guest.bandwidth = bandwidth
            guest.os_template_image_id = request.json.get('os_template_image_id')
            guest.label = ji.Common.generate_random_code(length=8)
            guest.remark = request.json.get('remark', '')

            guest.password = request.json.get('password')
            if guest.password is None or guest.password.__len__() < 1:
                guest.password = ji.Common.generate_random_code(length=16)

            guest.ip = db.r.spop(app.config['ip_available_set'])
            db.r.sadd(app.config['ip_used_set'], guest.ip)

            guest.network = config.vm_network
            guest.manage_network = config.vm_manage_network

            guest.vnc_port = db.r.spop(app.config['vnc_port_available_set'])
            db.r.sadd(app.config['vnc_port_used_set'], guest.vnc_port)

            guest.vnc_password = ji.Common.generate_random_code(length=16)

            disk = Disk()
            disk.uuid = guest.uuid
            disk.remark = guest.label.__str__() + '_SystemImage'
            disk.format = 'qcow2'
            disk.sequence = 0
            disk.size = 0
            disk.path = config.storage_path + '/' + disk.uuid + '.' + disk.format
            disk.guest_uuid = ''
            # disk.node_id 由 guest 事件处理机更新。涉及迁移时,其所属 node_id 会变更。参见 @models/event_processory.py:111 附近。
            disk.node_id = 0
            disk.quota(config=config)
            disk.create()

            if node_id is None:
                # 在可用计算节点中平均分配任务
                chosen_host = available_hosts[quantity % available_hosts.__len__()]

            else:
                chosen_host = available_hosts_mapping_by_node_id[node_id]

            guest.node_id = chosen_host['node_id']

            guest_xml = GuestXML(host=chosen_host, guest=guest, disk=disk, config=config,
                                 os_type=os_template_profile.os_type)
            guest.xml = guest_xml.get_domain()

            guest.node_id = int(guest.node_id)
            guest.create()

            ssh_key_guest_mapping.guest_uuid = guest.uuid

            if ssh_keys_id.__len__() > 0:
                for ssh_key_id in ssh_keys_id:
                    ssh_key_guest_mapping.ssh_key_id = ssh_key_id
                    ssh_key_guest_mapping.create()

            # 替换占位符为有效内容
            _os_template_initialize_operates = copy.deepcopy(os_template_initialize_operates)
            for k, v in enumerate(_os_template_initialize_operates):
                _os_template_initialize_operates[k]['content'] = v['content'].replace('{IP}', guest.ip).\
                    replace('{HOSTNAME}', guest.label). \
                    replace('{PASSWORD}', guest.password). \
                    replace('{NETMASK}', config.netmask).\
                    replace('{GATEWAY}', config.gateway).\
                    replace('{DNS1}', config.dns1).\
                    replace('{DNS2}', config.dns2). \
                    replace('{SSH-KEY}', '\n'.join(ssh_keys))

                _os_template_initialize_operates[k]['command'] = v['command'].replace('{IP}', guest.ip). \
                    replace('{HOSTNAME}', guest.label). \
                    replace('{PASSWORD}', guest.password). \
                    replace('{NETMASK}', config.netmask). \
                    replace('{GATEWAY}', config.gateway). \
                    replace('{DNS1}', config.dns1). \
                    replace('{DNS2}', config.dns2). \
                    replace('{SSH-KEY}', '\n'.join(ssh_keys))

            message = {
                '_object': 'guest',
                'action': 'create',
                'uuid': guest.uuid,
                'storage_mode': config.storage_mode,
                'dfs_volume': config.dfs_volume,
                'node_id': guest.node_id,
                'name': guest.label,
                'template_path': os_template_image.path,
                'os_type': os_template_profile.os_type,
                'disks': [disk.__dict__],
                'xml': guest_xml.get_domain(),
                'os_template_initialize_operates': _os_template_initialize_operates,
                'passback_parameters': {}
            }

            Utils.emit_instruction(message=json.dumps(message, ensure_ascii=False))

        return ret

    except ji.PreviewingError, e:
        return json.loads(e.message)
Beispiel #6
0
def r_update(_id):

    os_template_image = OSTemplateImage()

    args_rules = [Rules.ID.value]

    if 'label' in request.json:
        args_rules.append(Rules.LABEL.value, )

    if 'description' in request.json:
        args_rules.append(Rules.DESCRIPTION.value, )

    if 'path' in request.json:
        args_rules.append(Rules.PATH.value, )

    if 'active' in request.json:
        args_rules.append(Rules.ACTIVE.value, )

    if 'logo' in request.json:
        args_rules.append(Rules.LOGO.value, )

    if 'os_template_profile_id' in request.json:
        args_rules.append(Rules.OS_TEMPLATE_PROFILE_ID_EXT.value, )

    if 'kind' in request.json:
        args_rules.append(Rules.OS_TEMPLATE_IMAGE_KIND.value, )

    if args_rules.__len__() < 2:
        ret = dict()
        ret['state'] = ji.Common.exchange_state(20000)
        return ret

    request.json['id'] = _id

    try:
        ji.Check.previewing(args_rules, request.json)
        os_template_image.id = request.json.get('id')

        os_template_image.get()
        os_template_image.label = request.json.get('label',
                                                   os_template_image.label)
        os_template_image.description = request.json.get(
            'description', os_template_image.description)
        os_template_image.path = request.json.get('path',
                                                  os_template_image.path)
        os_template_image.active = request.json.get('active',
                                                    os_template_image.active)
        os_template_image.logo = request.json.get('logo',
                                                  os_template_image.logo)
        os_template_image.os_template_profile_id = \
            request.json.get('os_template_profile_id', os_template_image.os_template_profile_id)
        os_template_image.kind = request.json.get('kind',
                                                  os_template_image.kind)

        os_template_image.update()
        os_template_image.get()

        ret = dict()
        ret['state'] = ji.Common.exchange_state(20000)
        ret['data'] = os_template_image.__dict__
        return ret
    except ji.PreviewingError, e:
        return json.loads(e.message)
Beispiel #7
0
def r_create():

    os_template_image = OSTemplateImage()

    args_rules = [
        Rules.LABEL.value, Rules.DESCRIPTION.value, Rules.PATH.value,
        Rules.LOGO.value, Rules.OS_TEMPLATE_PROFILE_ID_EXT.value,
        Rules.ACTIVE.value, Rules.OS_TEMPLATE_IMAGE_KIND.value
    ]

    os_template_image.label = request.json.get('label')
    os_template_image.description = request.json.get('description')
    os_template_image.path = request.json.get('path')
    os_template_image.logo = request.json.get('logo')
    os_template_image.active = bool(int(request.json.get('active', 1)))
    os_template_image.os_template_profile_id = request.json.get(
        'os_template_profile_id')
    os_template_image.kind = request.json.get('kind')
    os_template_image.progress = 100

    try:
        ji.Check.previewing(args_rules, os_template_image.__dict__)

        ret = dict()
        ret['state'] = ji.Common.exchange_state(20000)

        if os_template_image.exist_by('path'):
            ret['state'] = ji.Common.exchange_state(40901)
            ret['state']['sub']['zh-cn'] = ''.join(
                [ret['state']['sub']['zh-cn'], ': ', os_template_image.path])
            return ret

        os_template_profile = OSTemplateProfile()
        os_template_profile.id = os_template_image.os_template_profile_id
        if not os_template_profile.exist():
            ret['state'] = ji.Common.exchange_state(40401)
            ret['state']['sub']['zh-cn'] = ''.join([
                ret['state']['sub']['zh-cn'], u': 操作系统模板描述文件ID: ',
                os_template_image.os_template_profile_id.__str__()
            ])
            return ret

        os_template_image.create()
        os_template_image.get_by('path')
        ret['data'] = os_template_image.__dict__
        return ret
    except ji.PreviewingError, e:
        return json.loads(e.message)
Beispiel #8
0
def r_delete(ids):
    ret = dict()
    ret['state'] = ji.Common.exchange_state(20000)

    config = Config()
    config.id = 1
    config.get()

    # 取全部活着的 hosts
    available_hosts = Host.get_available_hosts(nonrandom=None)

    if available_hosts.__len__() == 0:
        ret['state'] = ji.Common.exchange_state(50351)
        return ret

    chosen_host = available_hosts[0]
    node_id = chosen_host['node_id']

    os_template_image = OSTemplateImage()

    # TODO: 加入对,是否有被 Guest 引用的判断
    for _id in ids.split(','):
        os_template_image.id = _id
        os_template_image.get()

    for _id in ids.split(','):
        os_template_image.id = _id
        os_template_image.get()

        # 暂时不支持从计算节点上,删除公共镜像
        if os_template_image.kind == OSTemplateImageKind.public.value:
            os_template_image.delete()
            continue

        elif os_template_image.kind == OSTemplateImageKind.custom.value:
            os_template_image.progress = 254

            message = {
                '_object': 'os_template_image',
                'action': 'delete',
                'storage_mode': config.storage_mode,
                'dfs_volume': config.dfs_volume,
                'template_path': os_template_image.path,
                # uuid 这里没有实际意义,仅仅是为了迁就 JimV-C 的个命令格式
                'uuid': None,
                'node_id': node_id,
                'os_template_image_id': os_template_image.id,
                'passback_parameters': {
                    'id': os_template_image.id
                }
            }

            Utils.emit_instruction(message=json.dumps(message))

            os_template_image.update()

    return ret