def instruction_process_engine(self): ps = r.pubsub(ignore_subscribe_messages=False) ps.subscribe(config['instruction_channel']) while True: if Utils.exit_flag: msg = 'Thread instruction_process_engine say bye-bye' print msg logger.info(msg=msg) return threads_status['instruction_process_engine'] = { 'timestamp': ji.Common.ts() } msg = dict() extend_data = dict() try: msg = ps.get_message(timeout=config['engine_cycle_interval']) if msg is None or 'data' not in msg or not isinstance( msg['data'], basestring): continue try: msg = json.loads(msg['data']) if msg['action'] == 'pong': continue if msg['action'] == 'ping': # 通过 ping pong 来刷存在感。因为经过实际测试发现,当订阅频道长时间没有数据来往,那么订阅者会被自动退出。 r.publish(config['instruction_channel'], message=json.dumps({'action': 'pong'})) continue except ValueError as e: log_emit.error(e.message) continue if 'node_id' in msg and int(msg['node_id']) != self.node_id: continue # 下列语句繁琐写法如 <code>if '_object' not in msg or 'action' not in msg:</code> if not all([key in msg for key in ['_object', 'action']]): continue logger.info(msg=msg) if msg['_object'] == 'guest': self.refresh_dom_mapping() if msg['action'] not in ['create']: self.dom = self.dom_mapping_by_uuid[msg['uuid']] assert isinstance(self.dom, libvirt.virDomain) if msg['action'] == 'create': t = threading.Thread(target=Guest.create, args=(self.conn, msg)) t.setDaemon(False) t.start() continue elif msg['action'] == 'reboot': Guest.reboot(dom=self.dom) elif msg['action'] == 'force_reboot': Guest.force_reboot(dom=self.dom, msg=msg) elif msg['action'] == 'shutdown': Guest.shutdown(dom=self.dom) elif msg['action'] == 'force_shutdown': Guest.force_shutdown(dom=self.dom) elif msg['action'] == 'boot': Guest.boot(dom=self.dom, msg=msg) elif msg['action'] == 'suspend': Guest.suspend(dom=self.dom) elif msg['action'] == 'resume': Guest.resume(dom=self.dom) elif msg['action'] == 'delete': Guest.delete(dom=self.dom, msg=msg) elif msg['action'] == 'reset_password': Guest.reset_password(dom=self.dom, msg=msg) elif msg['action'] == 'attach_disk': Guest.attach_disk(dom=self.dom, msg=msg) elif msg['action'] == 'detach_disk': Guest.detach_disk(dom=self.dom, msg=msg) elif msg['action'] == 'update_ssh_key': Guest.update_ssh_key(dom=self.dom, msg=msg) elif msg['action'] == 'allocate_bandwidth': t = threading.Thread(target=Guest.allocate_bandwidth, args=(self.dom, msg)) t.setDaemon(False) t.start() continue elif msg['action'] == 'adjust_ability': t = threading.Thread(target=Guest.adjust_ability, args=(self.dom, msg)) t.setDaemon(False) t.start() continue elif msg['action'] == 'migrate': Guest().migrate(dom=self.dom, msg=msg) elif msg['_object'] == 'disk': if msg['action'] == 'create': Storage(storage_mode=msg['storage_mode'], dfs_volume=msg['dfs_volume']).make_image( path=msg['image_path'], size=msg['size']) elif msg['action'] == 'delete': Storage(storage_mode=msg['storage_mode'], dfs_volume=msg['dfs_volume']).delete_image( path=msg['image_path']) elif msg['action'] == 'resize': mounted = True if msg['guest_uuid'].__len__( ) == 36 else False if mounted: self.refresh_dom_mapping() self.dom = self.dom_mapping_by_uuid[ msg['guest_uuid']] # 在线磁盘扩容 if mounted and self.dom.isActive(): # 磁盘大小默认单位为KB,乘以两个 1024,使其单位达到 GiB msg['size'] = int(msg['size']) * 1024 * 1024 # https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainBlockResize self.dom.blockResize(disk=msg['device_node'], size=msg['size']) Guest.quota(dom=self.dom, msg=msg) # 离线磁盘扩容 else: Storage(storage_mode=msg['storage_mode'], dfs_volume=msg['dfs_volume']).resize_image( path=msg['image_path'], size=msg['size']) elif msg['action'] == 'quota': self.refresh_dom_mapping() self.dom = self.dom_mapping_by_uuid[msg['guest_uuid']] Guest.quota(dom=self.dom, msg=msg) elif msg['_object'] == 'snapshot': self.refresh_dom_mapping() self.dom = self.dom_mapping_by_uuid[msg['uuid']] if msg['action'] == 'create': t = threading.Thread(target=Guest.create_snapshot, args=(self.dom, msg)) t.setDaemon(False) t.start() continue elif msg['action'] == 'delete': t = threading.Thread(target=Guest.delete_snapshot, args=(self.dom, msg)) t.setDaemon(False) t.start() continue elif msg['action'] == 'revert': t = threading.Thread(target=Guest.revert_snapshot, args=(self.dom, msg)) t.setDaemon(False) t.start() continue elif msg['action'] == 'convert': t = threading.Thread(target=Guest.convert_snapshot, args=(msg, )) t.setDaemon(False) t.start() continue elif msg['_object'] == 'os_template_image': if msg['action'] == 'delete': Storage(storage_mode=msg['storage_mode'], dfs_volume=msg['dfs_volume']).delete_image( path=msg['template_path']) elif msg['_object'] == 'global': if msg['action'] == 'refresh_guest_state': t = threading.Thread(target=Host().refresh_guest_state, args=()) t.setDaemon(False) t.start() continue if msg['action'] == 'upgrade': try: log = self.upgrade(msg['url']) log_emit.info(msg=log) except subprocess.CalledProcessError as e: log_emit.warn(e.output) self.rollback() continue log = self.restart() log_emit.info(msg=log) if msg['action'] == 'restart': log = self.restart() log_emit.info(msg=log) else: err = u'未支持的 _object:' + msg['_object'] log_emit.error(err) response_emit.success( _object=msg['_object'], action=msg['action'], uuid=msg['uuid'], data=extend_data, passback_parameters=msg.get('passback_parameters')) except KeyError as e: log_emit.warn(e.message) if msg['_object'] == 'guest': if msg['action'] == 'delete': response_emit.success( _object=msg['_object'], action=msg['action'], uuid=msg['uuid'], data=extend_data, passback_parameters=msg.get('passback_parameters')) except: # 防止循环线程,在redis连接断开时,混水写入日志 time.sleep(5) log_emit.error(traceback.format_exc()) response_emit.failure( _object=msg['_object'], action=msg.get('action'), uuid=msg.get('uuid'), passback_parameters=msg.get('passback_parameters'))