def _create_disks_and_nics(self, vm): """Try to create disks and nics defined by template""" for i, data in enumerate(vm.template.vm_define_disk): if data: if i == 0 and not vm.is_hvm(): # Disk representation within a zone is created together with VM request = set_request_method(self.request, 'PUT') vm_define_disk = VmDefineDiskView(request) logger.info('Updating disk_id=%d for vm %s defined by template %s', i, vm, vm.template) res = vm_define_disk.put(vm, i, data) if res.status_code != scode.HTTP_200_OK: logger.warn('Failed (%s) to modify disk_id=%s in vm %s defined by template %s. ' 'Error: %s', res.status_code, i, vm, vm.template, res.data) else: request = set_request_method(self.request, 'POST') vm_define_disk = VmDefineDiskView(request) logger.info('Creating disk_id=%d for vm %s defined by template %s', i, vm, vm.template) res = vm_define_disk.post(vm, i, data) if res.status_code != scode.HTTP_201_CREATED: logger.warn('Failed (%s) to add disk_id=%s into vm %s defined by template %s. ' 'Error: %s', res.status_code, i, vm, vm.template, res.data) break request = set_request_method(self.request, 'POST') vm_define_nic = VmDefineNicView(request) for i, data in enumerate(vm.template.vm_define_nic): if data: logger.info('Creating nic_id=%d for vm %s defined by template %s', i, vm, vm.template) res = vm_define_nic.post(vm, i, data) if res.status_code != scode.HTTP_201_CREATED: logger.warn('Failed (%s) to add nic_id=%s into vm %s defined by template %s. ' 'Error: %s', res.status_code, i, vm, vm.template, res.data) break
def call_api_view(request, method, fun, *args, **kwargs): """ A handy wrapper for calling api view functions or classes. """ # We need a shallow copy of the request object because the original request object is still used by our caller request = copy(request) if method: request = set_request_method(request, method, copy_request=False) request.disable_throttling = kwargs.pop('disable_throttling', True) log_response = kwargs.pop('log_response', False) api_class = kwargs.pop('api_class', False) try: res = fun(request, *args, **kwargs) if api_class: res = res.response() except Exception as ex: res = exception_handler(ex, request) if res is None: raise res.exception = True finally: request.disable_throttling = False if log_response: logger.info( 'Called API view %s %s(%s, %s) by user %s in DC %s \n\twith response (%s): %s', method, fun.__name__, args, kwargs, request.user, request.dc, res.status_code, res.data) return res
def _create_disks_and_nics(self, vm): """Try to create disks and nics defined by template""" # WARNING: This will temporary change the request.method to POST request = set_request_method(self.request, 'POST') if not vm.json_get_disks(): vm_define_disk = VmDefineDiskView(request) for i, data in enumerate(vm.template.vm_define_disk): if data: if i == 0 and not vm.is_kvm(): # Non-global zone's 1st disk can be only modified logger.info('Updating disk_id=%d for vm %s defined by template %s', i, vm, vm.template) res = vm_define_disk.put(vm, i, data) if res.status_code != scode.HTTP_200_OK: logger.warn('Failed (%s) to modify disk_id=%s in vm %s defined by template %s. ' 'Error: %s', res.status_code, i, vm, vm.template, res.data) else: logger.info('Creating disk_id=%d for vm %s defined by template %s', i, vm, vm.template) res = vm_define_disk.post(vm, i, data) if res.status_code != scode.HTTP_201_CREATED: logger.warn('Failed (%s) to add disk_id=%s into vm %s defined by template %s. ' 'Error: %s', res.status_code, i, vm, vm.template, res.data) break if not vm.json_get_nics(): vm_define_nic = VmDefineNicView(request) for i, data in enumerate(vm.template.vm_define_nic): if data: logger.info('Creating nic_id=%d for vm %s defined by template %s', i, vm, vm.template) res = vm_define_nic.post(vm, i, data) if res.status_code != scode.HTTP_201_CREATED: logger.warn('Failed (%s) to add nic_id=%s into vm %s defined by template %s. ' 'Error: %s', res.status_code, i, vm, vm.template, res.data) break
def task_status_loop(request, response, task_id, stream=None): """ Loop and check for task result. Send keep-alive whitespace for every loop. TODO: Trailing headers are not supported, so status code cannot be changed. """ logger.debug('Starting APISyncMiddleware loop (%s)', request.path) logger.info('Waiting for pending task %s status in "%s" streaming loop', task_id, stream) elapsed = 0 task_status_request = set_request_method(request, 'GET') # Task check loop while elapsed < settings.API_SYNC_TIMEOUT: if elapsed > 1200: nap = 30 elif elapsed > 60: nap = 12 elif elapsed > 30: nap = 6 elif elapsed > 5: nap = 3 else: nap = 1 sleep(nap) elapsed += nap result, status = get_task_status(task_id, get_task_result) logger.debug('APISyncMiddleware loop (%s) status: %s', request.path, status) if status != HTTP_201_CREATED: logger.debug('APISyncMiddleware loop finished (%s) in %d seconds', request.path, elapsed) logger.info('Task %s finished', task_id) res = task_status(task_status_request, task_id=task_id) if stream == ES_STREAM_CLIENT: yield '%d\n' % res.status_code # new status code (es knows how to interpret this) yield res.rendered_content # will call render() break else: yield ' ' # keep-alive else: # Timeout logger.debug('APISyncMiddleware loop finished with timeout (%s)', request.path) logger.warning('Task %s is running too long; no point to wait', task_id) yield response # is already rendered
def import_for_vm(cls, request, ns, img, vm): """Import image required by VM. Return block_key or raise a FailedDependency API Exception (424).""" node = ns.node logger.warn( 'Image %s required for VM %s must be imported to node=%s, zpool=%s', img.name, vm, node, ns.zpool) img_ns_status = img.get_ns_status(ns) if img_ns_status == img.DELETING: # Someone is currently removing the image from node pool # We can't do anything about this raise ExpectationFailed( 'Required disk image is processed by another task') block_key = img.get_block_key(ns) if img_ns_status == img.IMPORTING: logger.warn( 'Image %s is being imported to node=%s, zpool=%s; vm_manage will be blocked by block_key=%s', img, node, ns.zpool, block_key) return block_key req = set_request_method(request, 'POST') try: res = cls(req, ns, img, None).post() except Exception as ex: res = exception_handler(ex, req) if res is None: raise ex res.exception = True if res.status_code in (200, 201): logger.warn( 'POST node_image(%s, %s, %s) was successful: %s; task will be blocked by block_key=%s', node.hostname, ns.zpool, img.name, res.data, block_key) return block_key else: logger.error( 'POST node_image(%s, %s, %s) failed: %s (%s): %s; raising 424 API exception', node.hostname, ns.zpool, img.name, res.status_code, res.status_text, res.data) errmsg = get_task_error_message(res.data) raise FailedDependency( 'Cannot import required image %s to node %s (%s: %s)' % (img.name, node.hostname, res.status_code, errmsg))
def create_from_template(cls, request, vm, vm_define_backup, log=logger): """Create backup definitions from vm.template.vm_define_backup list""" if vm_define_backup and isinstance(vm_define_backup, list): request = set_request_method(request, 'POST') for i, data in enumerate(vm_define_backup): try: try: bkpdef = data['bkpdef'] except KeyError: bkpdef = data['name'] disk_id, real_disk_id, zfs_filesystem = get_disk_id(request, vm, data) log.info('Creating backup definition [%d] "%s" for vm=%s, disk_id=%d defined by template %s', i, bkpdef, vm, disk_id, vm.template) define = get_object(request, BackupDefine, {'name': bkpdef, 'vm': vm, 'disk_id': real_disk_id}) res = cls(request, data=data).post(vm, define, vm_template=True) if res.status_code != scode.HTTP_201_CREATED: raise APIError('vm_define_backup error [%s]: %s' % (res.status_code, res.data)) except Exception as ex: log.warn('Failed to create backup definition [%d] for vm=%s defined by template %s with ' 'data="%s". Error: %s', i, vm, vm.template, data, ex)
def choose_node(self, vm): """Used by POST vm_manage when node needs to be chosen automatically""" new_node = Node.choose(vm) err = 'Could not find node with free resources' if not new_node: raise ExpectationFailed(err) old_request = self.request self.request = set_request_method(old_request, 'PUT') try: res = self.put(vm, {'node': new_node.hostname}) finally: self.request = old_request if res.status_code != scode.HTTP_200_OK: try: err = res.data['result']['node'] except Exception as e: logger.exception(e) raise ExpectationFailed(err) return new_node
def _set_vm_tags(self, vm, tags, task_id=None): from api.vm.define.vm_define import VmDefineView request = set_request_method(self.request, 'PUT') VmDefineView(request).put(vm, {'tags': list(tags)}, task_id=task_id)