def rename_machine(machine, name): # noqa: E501 """Rename machine Rename target machine # noqa: E501 :param machine: :type machine: str :param name: New machine name :type name: str :rtype: None """ from mist.api.methods import list_resources try: auth_context = connexion.context['token_info']['auth_context'] except KeyError: return 'Authentication failed', 401 from mist.api.logs.methods import log_event try: [machine], total = list_resources(auth_context, 'machine', search=machine, limit=1) except ValueError: return 'Machine does not exist', 404 if not methods.run_pre_action_hooks(machine, 'rename', auth_context.user): return 'OK', 200 # webhook requires stopping action propagation log_event( auth_context.owner.id, 'request', 'rename_machine', machine_id=machine.id, user_id=auth_context.user.id, ) try: auth_context.check_perm('machine', 'rename', machine.id) except PolicyUnauthorizedError: return 'You are not authorized to perform this action', 403 try: result = machine.ctl.rename(name) except ForbiddenError: return 'Action not supported on target machine', 422 methods.run_post_action_hooks(machine, 'rename', auth_context.user, result) return 'Machine renamed successfully'
def machine_actions(request): """ Tags: machines --- Calls a machine action on cloud that supports it. READ permission required on cloud. ACTION permission required on machine(ACTION can be START, STOP, DESTROY, REBOOT or RESIZE, RENAME for some providers). --- machine_uuid: in: path required: true type: string action: enum: - start - stop - reboot - destroy - resize - rename - create_snapshot - remove_snapshot - revert_to_snapshot required: true type: string name: description: The new name of the renamed machine type: string size: description: The size id of the plan to resize type: string snapshot_name: description: The name of the snapshot to create/remove/revert_to snapshot_description: description: The description of the snapshot to create snapshot_dump_memory: description: Dump the machine's memory in the snapshot default: false snapshot_quiesce: description: Enable guest file system quiescing default: false """ cloud_id = request.matchdict.get('cloud') params = params_from_request(request) action = params.get('action', '') name = params.get('name', '') size_id = params.get('size', '') memory = params.get('memory', '') cpus = params.get('cpus', '') cpu_shares = params.get('cpu_shares', '') cpu_units = params.get('cpu_units', '') snapshot_name = params.get('snapshot_name') snapshot_description = params.get('snapshot_description') snapshot_dump_memory = params.get('snapshot_dump_memory') snapshot_quiesce = params.get('snapshot_quiesce') auth_context = auth_context_from_request(request) if cloud_id: machine_id = request.matchdict['machine'] auth_context.check_perm("cloud", "read", cloud_id) try: machine = Machine.objects.get(cloud=cloud_id, machine_id=machine_id, state__ne='terminated') # used by logging_view_decorator request.environ['machine_uuid'] = machine.id except Machine.DoesNotExist: raise NotFoundError("Machine %s doesn't exist" % machine_id) else: machine_uuid = request.matchdict['machine_uuid'] try: machine = Machine.objects.get(id=machine_uuid) # VMs in libvirt can be started no matter if they are terminated if machine.state == 'terminated' and not isinstance( machine.cloud, LibvirtCloud): raise NotFoundError("Machine %s has been terminated" % machine_uuid) # used by logging_view_decorator request.environ['machine_id'] = machine.machine_id request.environ['cloud_id'] = machine.cloud.id except Machine.DoesNotExist: raise NotFoundError("Machine %s doesn't exist" % machine_uuid) cloud_id = machine.cloud.id auth_context.check_perm("cloud", "read", cloud_id) if machine.cloud.owner != auth_context.owner: raise NotFoundError("Machine %s doesn't exist" % machine.id) auth_context.check_perm("machine", action, machine.id) actions = ('start', 'stop', 'reboot', 'destroy', 'resize', 'rename', 'undefine', 'suspend', 'resume', 'remove', 'list_snapshots', 'create_snapshot', 'remove_snapshot', 'revert_to_snapshot', 'clone') if action not in actions: raise BadRequestError("Action '%s' should be " "one of %s" % (action, actions)) if not methods.run_pre_action_hooks(machine, action, auth_context.user): return OK # webhook requires stopping action propagation if action == 'destroy': result = methods.destroy_machine(auth_context.owner, cloud_id, machine.machine_id) elif action == 'remove': log.info('Removing machine %s in cloud %s' % (machine.machine_id, cloud_id)) # if machine has monitoring, disable it if machine.monitoring.hasmonitoring: try: disable_monitoring(auth_context.owner, cloud_id, machine_id, no_ssh=True) except Exception as exc: log.warning("Didn't manage to disable monitoring, maybe the " "machine never had monitoring enabled. Error: %r" % exc) result = machine.ctl.remove() # Schedule a UI update trigger_session_update(auth_context.owner, ['clouds']) elif action in ('start', 'stop', 'reboot', 'clone', 'undefine', 'suspend', 'resume'): result = getattr(machine.ctl, action)() elif action == 'rename': if not name: raise BadRequestError("You must give a name!") result = getattr(machine.ctl, action)(name) elif action == 'resize': _, constraints = auth_context.check_perm("machine", "resize", machine.id) # check cost constraint cost_constraint = constraints.get('cost', {}) if cost_constraint: try: from mist.rbac.methods import check_cost check_cost(auth_context.org, cost_constraint) except ImportError: pass kwargs = {} if memory: kwargs['memory'] = memory if cpus: kwargs['cpus'] = cpus if cpu_shares: kwargs['cpu_shares'] = cpu_shares if cpu_units: kwargs['cpu_units'] = cpu_units result = getattr(machine.ctl, action)(size_id, kwargs) elif action == 'list_snapshots': return machine.ctl.list_snapshots() elif action in ('create_snapshot', 'remove_snapshot', 'revert_to_snapshot'): kwargs = {} if snapshot_description: kwargs['description'] = snapshot_description if snapshot_dump_memory: kwargs['dump_memory'] = bool(snapshot_dump_memory) if snapshot_quiesce: kwargs['quiesce'] = bool(snapshot_quiesce) result = getattr(machine.ctl, action)(snapshot_name, **kwargs) methods.run_post_action_hooks(machine, action, auth_context.user, result) # TODO: We shouldn't return list_machines, just OK. Save the API! return methods.filter_list_machines(auth_context, cloud_id)
def resize_machine(machine, size): # noqa: E501 """Resize machine Resize target machine # noqa: E501 :param machine: :type machine: str :param size: :type size: str :rtype: None """ from mist.api.methods import list_resources try: auth_context = connexion.context['token_info']['auth_context'] except KeyError: return 'Authentication failed', 401 from mist.api.logs.methods import log_event try: [machine], total = list_resources(auth_context, 'machine', search=machine, limit=1) except ValueError: return 'Machine does not exist', 404 if not methods.run_pre_action_hooks(machine, 'resize', auth_context.user): return 'OK', 200 # webhook requires stopping action propagation try: [size], total = list_resources(auth_context, 'size', cloud=machine.cloud.id, search=size, limit=1) except ValueError: return 'Size does not exist', 404 try: _, constraints = auth_context.check_perm( 'machine', 'resize', machine.id) except PolicyUnauthorizedError: return 'You are not authorized to perform this action', 403 # check cost constraint cost_constraint = constraints.get('cost', {}) if cost_constraint: try: from mist.rbac.methods import check_cost check_cost(auth_context.org, cost_constraint) except ImportError: pass # check size constraint size_constraint = constraints.get('size', {}) if size_constraint: try: from mist.rbac.methods import check_size check_size(machine.cloud.id, size_constraint, size) except ImportError: pass log_event( auth_context.owner.id, 'request', 'resize_machine', machine_id=machine.id, user_id=auth_context.user.id, ) try: result = machine.ctl.resize(size.id, {}) except ForbiddenError: return 'Action not supported on target machine', 422 except BadRequestError as e: return str(e), 400 methods.run_post_action_hooks(machine, 'resize', auth_context.user, result) return 'Machine resize issued successfully'