def wrapper(vm, *args, **kwargs): user_id = for_user if user_id is None: user_id = vm.userid validate_server_action(vm, action) vm.action = action commission_name = "client: api, resource: %s" % vm quotas.handle_resource_commission(vm, action=action, action_fields=action_fields, commission_name=commission_name, for_user=user_id) vm.save() # XXX: Special case for server creation! if action == "BUILD": serial = vm.serial serial.pending = False serial.accept = True serial.save() # Perform a commit, because the VirtualMachine must be saved to # DB before the OP_INSTANCE_CREATE job in enqueued in Ganeti. # Otherwise, messages will arrive from snf-dispatcher about # this instance, before the VM is stored in DB. transaction.commit() # After committing the locks are released. Refetch the instance # to guarantee x-lock. vm = VirtualMachine.objects.select_for_update().get(id=vm.id) # XXX: Special case for server creation: we must accept the # commission because the VM has been stored in DB. Also, if # communication with Ganeti fails, the job will never reach # Ganeti, and the commission will never be resolved. quotas.accept_resource_serial(vm) # Send the job to Ganeti and get the associated jobID try: job_id = func(vm, *args, **kwargs) except Exception as e: if vm.serial is not None and action != "BUILD": # Since the job never reached Ganeti, reject the commission log.debug("Rejecting commission: '%s', could not perform" " action '%s': %s" % (vm.serial, action, e)) transaction.rollback() quotas.reject_serial(vm.serial) transaction.commit() raise log.info("user: %s, vm: %s, action: %s, job_id: %s, serial: %s", user_id, vm.id, action, job_id, vm.serial) # store the new task in the VM if job_id is not None: vm.task = action vm.task_job_id = job_id vm.save() return vm
def wrapper(vm, *args, **kwargs): user_id = vm.userid validate_server_action(vm, action) vm.action = action commission_name = "client: api, resource: %s" % vm quotas.handle_resource_commission(vm, action=action, action_fields=action_fields, commission_name=commission_name) vm.save() # XXX: Special case for server creation! if action == "BUILD": serial = vm.serial serial.pending = False serial.accept = True serial.save() # Perform a commit, because the VirtualMachine must be saved to # DB before the OP_INSTANCE_CREATE job in enqueued in Ganeti. # Otherwise, messages will arrive from snf-dispatcher about # this instance, before the VM is stored in DB. transaction.commit() # After committing the locks are released. Refetch the instance # to guarantee x-lock. vm = VirtualMachine.objects.select_for_update().get(id=vm.id) # XXX: Special case for server creation: we must accept the # commission because the VM has been stored in DB. Also, if # communication with Ganeti fails, the job will never reach # Ganeti, and the commission will never be resolved. quotas.accept_resource_serial(vm) # Send the job to Ganeti and get the associated jobID try: job_id = func(vm, *args, **kwargs) except Exception as e: if vm.serial is not None and action != "BUILD": # Since the job never reached Ganeti, reject the commission log.debug("Rejecting commission: '%s', could not perform" " action '%s': %s" % (vm.serial, action, e)) transaction.rollback() quotas.reject_serial(vm.serial) transaction.commit() raise log.info("user: %s, vm: %s, action: %s, job_id: %s, serial: %s", user_id, vm.id, action, job_id, vm.serial) # store the new task in the VM if job_id is not None: vm.task = action vm.task_job_id = job_id vm.save() return vm
def __init__(self, action, vm, credentials=None, atomic_context=None, action_fields=None, for_user=None): if not isinstance(vm, models.VirtualMachine): vm = util.get_vm(vm, credentials, for_update=True, non_deleted=True, non_suspended=not credentials.is_admin) self.vm = vm user_id = for_user if user_id is None: user_id = vm.userid if action == "BUILD": raise AssertionError("decorator does not support action 'BUILD'") validate_server_action(vm, action) vm.action = action commission_name = "client: api, resource: %s" % vm serial = quotas.handle_resource_commission( vm, action=action, action_fields=action_fields, commission_name=commission_name, for_user=user_id) if serial is not None: quotas.set_serial(atomic_context, serial)
def handle_vm_quotas(vm, job_id, job_opcode, job_status, job_fields): """Handle quotas for updated VirtualMachine. Update quotas for the updated VirtualMachine based on the job that run on the Ganeti backend. If a commission has been already issued for this job, then this commission is just accepted or rejected based on the job status. Otherwise, a new commission for the given change is issued, that is also in force and auto-accept mode. In this case, previous commissions are rejected, since they reflect a previous state of the VM. """ if job_status not in rapi.JOB_STATUS_FINALIZED: return vm print vm print vm # Check successful completion of a job will trigger any quotable change in # the VM state. action = utils.get_action_from_opcode(job_opcode, job_fields) if action == "BUILD": # Quotas for new VMs are automatically accepted by the API return vm if vm.task_job_id == job_id and vm.serial is not None: # Commission for this change has already been issued. So just # accept/reject it. Special case is OP_INSTANCE_CREATE, which even # if fails, must be accepted, as the user must manually remove the # failed server serial = vm.serial if job_status == rapi.JOB_STATUS_SUCCESS: quotas.accept_resource_serial(vm) elif job_status in [rapi.JOB_STATUS_ERROR, rapi.JOB_STATUS_CANCELED]: log.debug("Job %s failed. Rejecting related serial %s", job_id, serial) quotas.reject_resource_serial(vm) elif job_status == rapi.JOB_STATUS_SUCCESS: commission_info = quotas.get_commission_info(resource=vm, action=action, action_fields=job_fields) if commission_info is not None: # Commission for this change has not been issued, or the issued # commission was unaware of the current change. Reject all previous # commissions and create a new one in forced mode! log.debug("Expected job was %s. Processing job %s. " "Attached serial %s", vm.task_job_id, job_id, vm.serial) reason = ("client: dispatcher, resource: %s, ganeti_job: %s" % (vm, job_id)) serial = quotas.handle_resource_commission( vm, action, action_fields=job_fields, commission_name=reason, force=True, auto_accept=True) log.debug("Issued new commission: %s", serial) return vm
def handle_vm_quotas(vm, job_id, job_opcode, job_status, job_fields): """Handle quotas for updated VirtualMachine. Update quotas for the updated VirtualMachine based on the job that run on the Ganeti backend. If a commission has been already issued for this job, then this commission is just accepted or rejected based on the job status. Otherwise, a new commission for the given change is issued, that is also in force and auto-accept mode. In this case, previous commissions are rejected, since they reflect a previous state of the VM. """ if job_status not in rapi.JOB_STATUS_FINALIZED: return vm # Check successful completion of a job will trigger any quotable change in # the VM state. action = utils.get_action_from_opcode(job_opcode, job_fields) if action == "BUILD": # Quotas for new VMs are automatically accepted by the API return vm if vm.task_job_id == job_id and vm.serial is not None: # Commission for this change has already been issued. So just # accept/reject it. Special case is OP_INSTANCE_CREATE, which even # if fails, must be accepted, as the user must manually remove the # failed server serial = vm.serial if job_status == rapi.JOB_STATUS_SUCCESS: quotas.accept_resource_serial(vm) elif job_status in [rapi.JOB_STATUS_ERROR, rapi.JOB_STATUS_CANCELED]: log.debug("Job %s failed. Rejecting related serial %s", job_id, serial) quotas.reject_resource_serial(vm) elif job_status == rapi.JOB_STATUS_SUCCESS: commission_info = quotas.get_commission_info(resource=vm, action=action, action_fields=job_fields) if commission_info is not None: # Commission for this change has not been issued, or the issued # commission was unaware of the current change. Reject all previous # commissions and create a new one in forced mode! log.debug( "Expected job was %s. Processing job %s. " "Attached serial %s", vm.task_job_id, job_id, vm.serial) reason = ("client: dispatcher, resource: %s, ganeti_job: %s" % (vm, job_id)) serial = quotas.handle_resource_commission( vm, action, action_fields=job_fields, commission_name=reason, force=True, auto_accept=True) log.debug("Issued new commission: %s", serial) return vm
def mock_handle_resource_commission(*args, **kwargs): handle_resource_commission(*args, **kwargs) raise MurphysLaw