Exemple #1
0
def resize(server_id, flavor_id, credentials=None, atomic_context=None):
    vm = util.get_vm(server_id,
                     credentials,
                     for_update=True,
                     non_deleted=True,
                     non_suspended=True)
    flavor = util.get_flavor(flavor_id,
                             credentials,
                             include_deleted=False,
                             for_project=vm.project)
    action_fields = {"beparams": {"vcpus": flavor.cpu, "maxmem": flavor.ram}}
    with commands.ServerCommand("RESIZE",
                                server_id,
                                credentials,
                                atomic_context,
                                action_fields=action_fields) as vm:
        old_flavor = vm.flavor
        # User requested the same flavor
        if old_flavor.id == flavor.id:
            raise faults.BadRequest("Server '%s' flavor is already '%s'." %
                                    (vm, flavor))
        # Check that resize can be performed
        if old_flavor.disk != flavor.disk:
            raise faults.BadRequest("Cannot change instance's disk size.")
        if old_flavor.volume_type_id != flavor.volume_type_id:
            raise faults.BadRequest("Cannot change instance's volume type.")

        log.info("Resizing VM from flavor '%s' to '%s", old_flavor, flavor)
        job_id = backend.resize_instance(vm,
                                         vcpus=flavor.cpu,
                                         memory=flavor.ram)
        vm.record_job(job_id)
        return vm
Exemple #2
0
def set_firewall_profile(request, server_id, args):
    # Normal Response Code: 200
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       overLimit (413)
    credentials = request.credentials
    profile = args.get("profile")
    if profile is None:
        raise faults.BadRequest("Missing 'profile' attribute")

    nic_id = args.get("nic")
    if nic_id is None:
        raise faults.BadRequest("Missing 'nic' attribute")

    servers.set_firewall_profile(server_id,
                                 profile=profile,
                                 nic_id=nic_id,
                                 credentials=credentials)

    log.info("User %s set firewall profile of VM %s, port %s",
             credentials.userid, server_id, nic_id)

    return HttpResponse(status=202)
Exemple #3
0
def attach_volume(vm, volume):
    """Attach a volume to a server.

    The volume must be in 'AVAILABLE' status in order to be attached. Also,
    number of the volumes that are attached to the server must remain less
    than 'GANETI_MAX_DISKS_PER_INSTANCE' setting. This function will send
    the corresponding job to Ganeti backend and update the status of the
    volume to 'ATTACHING'.

    """
    # Check volume state
    if volume.status not in ["AVAILABLE", "CREATING"]:
        raise faults.BadRequest("Cannot attach volume while volume is in"
                                " '%s' status." % volume.status)

    # Check that disk templates are the same
    if volume.volume_type_id != vm.flavor.volume_type_id:
        msg = ("Volume and server must have the same volume type. Volume has"
               " volume type '%s' while server has '%s'" %
               (volume.volume_type_id, vm.flavor.volume_type_id))
        raise faults.BadRequest(msg)

    # Check maximum disk per instance hard limit
    vm_volumes_num = vm.volumes.filter(deleted=False).count()
    if vm_volumes_num == settings.GANETI_MAX_DISKS_PER_INSTANCE:
        raise faults.BadRequest("Maximum volumes per server limit reached")

    if volume.status == "CREATING":
        action_fields = {"disks": [("add", volume, {})]}
    else:
        action_fields = {}
    comm = commands.server_command("ATTACH_VOLUME",
                                   action_fields=action_fields)
    return comm(_attach_volume)(vm, volume)
Exemple #4
0
def remove(request, net, args):
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       overLimit (413)

    attachment = args.get("attachment")
    if attachment is None:
        raise faults.BadRequest("Missing 'attachment' attribute.")
    try:
        nic_id = int(attachment)
    except (ValueError, TypeError):
        raise faults.BadRequest("Invalid 'attachment' attribute.")

    nic = util.get_nic(nic_id=nic_id)
    server_id = nic.machine_id
    vm = util.get_vm(server_id,
                     request.user_uniq,
                     non_suspended=True,
                     for_update=True,
                     non_deleted=True)

    servers.disconnect(vm, nic)

    return HttpResponse(status=202)
Exemple #5
0
def get_uuid_displayname_catalogs(request, user_call=True):
    # Normal Response Codes: 200
    # Error Response Codes: BadRequest (400)

    try:
        input_data = json.loads(request.body)
    except:
        raise faults.BadRequest('Request body should be json formatted.')
    else:
        if not isinstance(input_data, dict):
            raise faults.BadRequest(
                'Request body should be a json formatted dictionary')
        uuids = input_data.get('uuids', [])
        if uuids is None and user_call:
            uuids = []
        displaynames = input_data.get('displaynames', [])
        if displaynames is None and user_call:
            displaynames = []
        user_obj = AstakosUser.objects
        d = {
            'uuid_catalog': user_obj.uuid_catalog(uuids),
            'displayname_catalog': user_obj.displayname_catalog(displaynames)
        }

        response = HttpResponse()
        response.content = json.dumps(d)
        response['Content-Type'] = 'application/json; charset=UTF-8'
        response['Content-Length'] = len(response.content)
        return response
Exemple #6
0
def detach_volume(vm, volume):
    """Detach a Volume from a VM

    The volume must be in 'IN_USE' status in order to be detached. Also,
    the root volume of the instance (index=0) can not be detached. This
    function will send the corresponding job to Ganeti backend and update the
    status of the volume to 'DETACHING'.

    """
    util.assert_detachable_volume_type(volume.volume_type)
    _check_attachment(vm, volume)
    if volume.status not in ["IN_USE", "ERROR"]:
        raise faults.BadRequest("Cannot detach volume while volume is in"
                                " '%s' status." % volume.status)
    if volume.index == 0:
        raise faults.BadRequest("Cannot detach the root volume of server %s." %
                                vm)

    with commands.ServerCommand("DETACH_VOLUME", vm):
        jobid = backend.detach_volume(vm, volume)
        vm.record_job(jobid)
        log.info("Detached volume '%s' from server '%s'. JobID: '%s'",
                 volume.id, volume.machine_id, jobid)
        volume.backendjobid = jobid
        volume.status = "DETACHING"
        volume.save()
Exemple #7
0
def server_action(request, server_id):
    req = utils.get_request_dict(request)
    log.debug('server_action %s %s', server_id, req)

    if len(req) != 1:
        raise faults.BadRequest("Malformed request")

    # Do not allow any action on deleted or suspended VMs
    vm = util.get_vm(server_id,
                     request.user_uniq,
                     for_update=True,
                     non_deleted=True,
                     non_suspended=True)

    try:
        key = req.keys()[0]
        if key not in ARBITRARY_ACTIONS:
            start_action(vm, key_to_action(key))
        val = req[key]
        assert isinstance(val, dict)
        return server_actions[key](request, vm, val)
    except KeyError:
        raise faults.BadRequest("Unknown action")
    except AssertionError:
        raise faults.BadRequest("Invalid argument")
Exemple #8
0
def validate_server_action(vm, action):
    if vm.deleted:
        raise faults.BadRequest("Server '%s' has been deleted." % vm.id)

    # Destroyin a server should always be permitted
    if action == "DESTROY":
        return

    # Check that there is no pending action
    pending_action = vm.task
    if pending_action:
        if pending_action == "BUILD":
            raise faults.BuildInProgress("Server '%s' is being build." % vm.id)
        raise faults.BadRequest("Cannot perform '%s' action while there is a"
                                " pending '%s'." % (action, pending_action))

    # Check if action can be performed to VM's operstate
    operstate = vm.operstate
    if operstate == "ERROR":
        raise faults.BadRequest("Cannot perform '%s' action while server is"
                                " in 'ERROR' state." % action)
    elif operstate == "BUILD" and action != "BUILD":
        raise faults.BuildInProgress("Server '%s' is being build." % vm.id)
    elif (action == "START" and operstate != "STOPPED") or\
         (action == "STOP" and operstate != "STARTED") or\
         (action == "RESIZE" and operstate != "STOPPED") or\
         (action in ["CONNECT", "DISCONNECT"] and operstate != "STOPPED"
          and not settings.GANETI_USE_HOTPLUG):
        raise faults.BadRequest("Cannot perform '%s' action while server is"
                                " in '%s' state." % (action, operstate))
    return
Exemple #9
0
def delete_volume(vm, volume, atomic_context):
    """Delete attached volume and update its status

    The volume must be in 'IN_USE' status in order to be deleted. This
    function will send the corresponding job to Ganeti backend and update the
    status of the volume to 'DELETING'.
    """
    _check_attachment(vm, volume)
    if volume.status not in ["IN_USE", "ERROR"]:
        raise faults.BadRequest("Cannot delete volume while volume is in"
                                " '%s' status." % volume.status)
    if volume.index == 0:
        raise faults.BadRequest("Cannot delete the root volume of server %s." %
                                vm)

    action_fields = {"disks": [("remove", volume, {})]}
    with commands.ServerCommand("DELETE_VOLUME",
                                vm,
                                atomic_context=atomic_context,
                                action_fields=action_fields,
                                for_user=volume.userid):
        jobid = backend.delete_volume(vm, volume)
        vm.record_job(jobid)
        log.info("Deleted volume '%s' from server '%s'. JobID: '%s'",
                 volume.id, volume.machine_id, jobid)
        volume.backendjobid = jobid
        util.mark_volume_as_deleted(volume)
Exemple #10
0
def get_console(request, vm, args):
    # Normal Response Code: 200
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       overLimit (413)

    log.info("Get console  VM %s: %s", vm, args)

    console_type = args.get("type")
    if console_type is None:
        raise faults.BadRequest("No console 'type' specified.")

    supported_types = ['vnc', 'vnc-ws', 'vnc-wss']
    if console_type not in supported_types:
        raise faults.BadRequest('Supported types: %s' %
                                ', '.join(supported_types))

    console_info = servers.console(vm, console_type)

    if request.serialization == 'xml':
        mimetype = 'application/xml'
        data = render_to_string('console.xml', {'console': console_info})
    else:
        mimetype = 'application/json'
        data = json.dumps({'console': console_info})

    return HttpResponse(data, mimetype=mimetype, status=200)
Exemple #11
0
def _port_for_request(user_id, network_dict):
    if not isinstance(network_dict, dict):
        raise faults.BadRequest("Malformed request. Invalid 'networks' field")
    port_id = network_dict.get("port")
    network_id = network_dict.get("uuid")
    if port_id is not None:
        return util.get_port(port_id, user_id, for_update=True)
    elif network_id is not None:
        address = network_dict.get("fixed_ip")
        network = util.get_network(network_id, user_id, non_deleted=True)
        if network.public:
            if network.subnet4 is not None:
                if not "fixed_ip" in network_dict:
                    return create_public_ipv4_port(user_id, network)
                elif address is None:
                    msg = "Cannot connect to public network"
                    raise faults.BadRequest(msg % network.id)
                else:
                    return create_public_ipv4_port(user_id, network, address)
            else:
                raise faults.Forbidden("Cannot connect to IPv6 only public"
                                       " network %" % network.id)
        else:
            return _create_port(user_id, network, address=address)
    else:
        raise faults.BadRequest("Network 'uuid' or 'port' attribute"
                                " is required.")
Exemple #12
0
def update_network_name(request, network_id):
    # Normal Response Code: 204
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       forbidden (403)
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       overLimit (413)

    req = utils.get_request_dict(request)
    log.info('update_network_name %s', network_id)

    try:
        name = req['network']['name']
    except (TypeError, KeyError):
        raise faults.BadRequest('Malformed request.')

    net = util.get_network(network_id, request.user_uniq)
    if net.public:
        raise faults.Forbidden('Can not rename the public network.')
    if net.deleted:
        raise faults.BadRequest("Network has been deleted.")
    net.name = name
    net.save()
    return HttpResponse(status=204)
Exemple #13
0
def get_vm(server_id, user_id, projects, for_update=False,
           non_deleted=False, non_suspended=False, prefetch_related=None):
    """Find a VirtualMachine instance based on ID and owner."""

    try:
        server_id = int(server_id)

        servers = VirtualMachine.objects.for_user(userid=user_id,
                                                  projects=projects)

        if for_update:
            servers = servers.select_for_update()
        if prefetch_related is not None:
            if isinstance(prefetch_related, list):
                servers = servers.prefetch_related(*prefetch_related)
            else:
                servers = servers.prefetch_related(prefetch_related)

        vm = servers.get(id=server_id)

        if non_deleted and vm.deleted:
            raise faults.BadRequest("Server has been deleted.")
        if non_suspended and vm.suspended:
            raise faults.Forbidden("Administratively Suspended VM")
        return vm
    except (ValueError, TypeError):
        raise faults.BadRequest('Invalid server ID.')
    except VirtualMachine.DoesNotExist:
        raise faults.ItemNotFound('Server not found.')
Exemple #14
0
def remove(request, net, args):
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       overLimit (413)

    try:  # attachment string: nic-<vm-id>-<nic-index>
        server_id = args.get('attachment', None).split('-')[1]
        nic_index = args.get('attachment', None).split('-')[2]
    except AttributeError:
        raise faults.BadRequest("Malformed Request")
    except IndexError:
        raise faults.BadRequest('Malformed Network Interface Id')

    if not server_id or not nic_index:
        raise faults.BadRequest('Malformed Request.')

    vm = get_vm(server_id, request.user_uniq, non_suspended=True)
    nic = get_nic_from_index(vm, nic_index)

    log.info("Removing NIC %s from VM %s", str(nic.index), vm)

    if nic.dirty:
        raise faults.BuildInProgress('Machine is busy.')
    else:
        vm.nics.all().update(dirty=True)

    backend.disconnect_from_network(vm, nic)
    return HttpResponse(status=202)
Exemple #15
0
def demux_server_action(request, server_id):
    req = utils.get_json_body(request)
    log.debug('server_action %s %s', server_id, req)

    if not isinstance(req, dict) and len(req) != 1:
        raise faults.BadRequest("Malformed request")

    # Do not allow any action on deleted or suspended VMs
    vm = util.get_vm(server_id,
                     request.user_uniq,
                     for_update=True,
                     non_deleted=True,
                     non_suspended=True)

    try:
        action = req.keys()[0]
    except IndexError:
        raise faults.BadRequest("Malformed Request.")

    if not isinstance(action, basestring):
        raise faults.BadRequest("Malformed Request. Invalid action.")

    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
        if action not in ARBITRARY_ACTIONS:
            raise faults.BadRequest("Action %s not supported" % action)
    action_args = utils.get_attribute(req,
                                      action,
                                      required=True,
                                      attr_type=dict)

    return server_actions[action](request, vm, action_args)
Exemple #16
0
        def wrapper(request, *args, **kwargs):
            # The args variable may contain up to (account, container, object).
            if len(args) > 1 and len(args[1]) > 256:
                raise faults.BadRequest("Container name too large")
            if len(args) > 2 and len(args[2]) > 1024:
                raise faults.BadRequest('Object name too large.')

            success_status = False
            try:
                # Add a PithosBackend as attribute of the request object
                request.backend = get_backend()
                request.backend.pre_exec(lock_container_path)

                # Many API method expect thet X-Auth-Token in request,token
                request.token = request.x_auth_token
                update_request_headers(request)
                response = func(request, *args, **kwargs)
                update_response_headers(request, response)

                success_status = True
                return response
            finally:
                # Always close PithosBackend connection
                if getattr(request, "backend", None) is not None:
                    request.backend.post_exec(success_status)
                    request.backend.close()
Exemple #17
0
def demux_server_action(request, server_id):
    credentials = request.credentials
    req = utils.get_json_body(request)

    if not isinstance(req, dict) and len(req) != 1:
        raise faults.BadRequest("Malformed request")

    try:
        action = req.keys()[0]
    except IndexError:
        raise faults.BadRequest("Malformed Request.")

    log.debug("User: %s, VM: %s, Action: %s Request: %s", credentials.userid,
              server_id, action, req)

    if not isinstance(action, basestring):
        raise faults.BadRequest("Malformed Request. Invalid action.")

    if key_to_action(action) not in [x[0] for x in VirtualMachine.ACTIONS]:
        if action not in ARBITRARY_ACTIONS:
            raise faults.BadRequest("Action %s not supported" % action)
    action_args = utils.get_attribute(req,
                                      action,
                                      required=False,
                                      attr_type=dict)
    return server_actions[action](request, server_id, action_args)
Exemple #18
0
def submit_modification(app_data, user, project_id):
    owner = app_data.get("owner")
    if owner is not None:
        try:
            owner = AstakosUser.objects.accepted().get(uuid=owner)
        except AstakosUser.DoesNotExist:
            raise faults.BadRequest("User does not exist.")

    name = app_data.get("name")

    join_policy = app_data.get("join_policy")
    if join_policy is not None:
        try:
            join_policy = MEMBERSHIP_POLICY[join_policy]
        except KeyError:
            raise faults.BadRequest("Invalid join policy")

    leave_policy = app_data.get("leave_policy")
    if leave_policy is not None:
        try:
            leave_policy = MEMBERSHIP_POLICY[leave_policy]
        except KeyError:
            raise faults.BadRequest("Invalid leave policy")

    start_date = app_data.get("start_date")
    end_date = app_data.get("end_date")

    max_members = app_data.get("max_members")
    if max_members is not None:
        max_members = _parse_max_members(max_members)

    private = _get_maybe_boolean(app_data, "private")
    homepage = _get_maybe_string(app_data, "homepage")
    description = _get_maybe_string(app_data, "description")
    comments = _get_maybe_string(app_data, "comments")
    resources = app_data.get("resources", {})

    submit = functions.submit_application
    with ExceptionHandler():
        application = submit(
            owner=owner,
            name=name,
            project_id=project_id,
            homepage=homepage,
            description=description,
            start_date=start_date,
            end_date=end_date,
            member_join_policy=join_policy,
            member_leave_policy=leave_policy,
            limit_on_members_number=max_members,
            private=private,
            comments=comments,
            resources=resources,
            request_user=user)

    result = {"application": application.id,
              "id": application.chain.uuid,
              }
    return json_response(result, status_code=201)
Exemple #19
0
def check_meta_headers(meta):
    if len(meta) > 90:
        raise faults.BadRequest('Too many headers.')
    for k, v in meta.iteritems():
        if len(k) > 128:
            raise faults.BadRequest('Header name too large.')
        if len(v) > 256:
            raise faults.BadRequest('Header value too large.')
Exemple #20
0
def get_sharing(request):
    """Parse an X-Object-Sharing header from the request.

    Raises BadRequest on error.
    """

    permissions = request.META.get('HTTP_X_OBJECT_SHARING')
    if permissions is None:
        return None

    # TODO: Document or remove '~' replacing.
    permissions = permissions.replace('~', '')

    ret = {}
    permissions = permissions.replace(' ', '')
    if permissions == '':
        return ret
    for perm in (x for x in permissions.split(';')):
        if perm.startswith('read='):
            ret['read'] = list(
                set([v.replace(' ', '').lower() for v in perm[5:].split(',')]))
            if '' in ret['read']:
                ret['read'].remove('')
            if '*' in ret['read']:
                ret['read'] = ['*']
            if len(ret['read']) == 0:
                raise faults.BadRequest(
                    'Bad X-Object-Sharing header value: invalid length')
        elif perm.startswith('write='):
            ret['write'] = list(
                set([v.replace(' ', '').lower() for v in perm[6:].split(',')]))
            if '' in ret['write']:
                ret['write'].remove('')
            if '*' in ret['write']:
                ret['write'] = ['*']
            if len(ret['write']) == 0:
                raise faults.BadRequest(
                    'Bad X-Object-Sharing header value: invalid length')
        else:
            raise faults.BadRequest(
                'Bad X-Object-Sharing header value: missing prefix')

    # replace displayname with uuid
    if TRANSLATE_UUIDS:
        try:
            ret['read'] = [
                replace_permissions_displayname(
                    getattr(request, 'token', None), x)
                for x in ret.get('read', [])
            ]
            ret['write'] = [
                replace_permissions_displayname(
                    getattr(request, 'token', None), x)
                for x in ret.get('write', [])
            ]
        except ItemNotExists, e:
            raise faults.BadRequest(
                'Bad X-Object-Sharing header value: unknown account: %s' % e)
Exemple #21
0
def validate_network_action(network, action):
    if network.deleted:
        raise faults.BadRequest("Network has been deleted.")
    if action in ["DRAIN", "UNDRAIN"]:
        if not network.public:
            raise faults.BadRequest("Network is not public.")
        if action == "DRAIN" and network.drained:
            raise faults.BadRequest("Network is drained.")
        if action == "UNDRAIN" and not network.drained:
            raise faults.BadRequest("Network is not drained.")
Exemple #22
0
def get_attribute(request, attribute, attr_type=None, required=True):
    value = request.get(attribute, None)
    if required and value is None:
        raise faults.BadRequest("Malformed request. Missing attribute '%s'." %
                                attribute)
    if attr_type is not None and value is not None\
       and not isinstance(value, attr_type):
        raise faults.BadRequest("Malformed request. Invalid '%s' field"
                                % attribute)
    return value
Exemple #23
0
def create_new_keypair(request):
    """Generates or imports a keypair.

    Normal response code: 201

    Error response codes: badRequest(400), unauthorized(401), forbidden(403),
                          conflict(409)
    """

    userid = request.credentials.userid
    if PublicKeyPair.user_limit_exceeded(userid):
        return HttpResponseServerError("SSH keys limit exceeded")

    req = utils.get_json_body(request)
    try:
        keypair = req['keypair']
        assert (isinstance(req, dict))
        name = keypair['name']
    except (KeyError, AssertionError):
        raise faults.BadRequest('Malformed request.')

    if re.match(key_name_regex, name) is None:
        raise faults.BadRequest('Invalid name format')

    try:
        # If the key with the same name exists in the database
        # a conflict error will be raised

        util.get_keypair(name, userid)
        # If we get past this point then the key is already present
        # in the database
        raise faults.Conflict('A keypair with that name already exists')
    except faults.ItemNotFound:
        new_keypair = PublicKeyPair(name=name, user=userid)

    gen_keypair = None
    try:
        new_keypair.content = keypair['public_key']
    except KeyError:
        # If the public_key field is omitted, generate a new
        # keypair and return both the private and the public key
        if not SUPPORT_GENERATE_KEYS:
            raise faults.Forbidden(
                "Application does not support ssh keys generation")

        gen_keypair = generate_keypair()
        new_keypair.content = gen_keypair['public']

    new_keypair.save()

    data = keypair_to_dict(new_keypair)
    if gen_keypair is not None:
        data['keypair']['private_key'] = gen_keypair['private']

    return HttpResponse(json.dumps(data), status=201)
Exemple #24
0
def os_get_vnc_console(request, server_id, args):
    # Normal Response Code: 200
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       badMediaType(415),
    #                       itemNotFound (404),
    #                       buildInProgress (409),
    #                       overLimit (413)

    credentials = request.credentials
    log.debug("User: %s, VM: %s, Action: get_osVNC console, Request: %s",
              credentials.userid, server_id, args)

    console_type = args.get('type')
    if console_type is None:
        raise faults.BadRequest("No console 'type' specified.")

    supported_types = {'novnc': 'vnc-wss', 'xvpvnc': 'vnc'}
    if console_type not in supported_types:
        raise faults.BadRequest('Supported types: %s' %
                                ', '.join(supported_types.keys()))

    console_info = servers.console(server_id,
                                   supported_types[console_type],
                                   credentials=credentials)

    global machines_console_url
    if machines_console_url is None:
        machines_console_url = reverse('synnefo.ui.views.machines_console')

    if console_type == 'novnc':
        # Return the URL of the WebSocket noVNC client
        url = settings.CYCLADES_BASE_URL + machines_console_url
        url += '?host=%(host)s&port=%(port)s&password=%(password)s'
    else:
        # Return a URL to paste into a Java VNC client
        # FIXME: VNC clients (and the TigerVNC Java applet) can't handle the
        # password.
        url = '%(host)s:%(port)s?password=%(password)s'

    resp = {'type': console_type, 'url': url % console_info}

    if request.serialization == 'xml':
        mimetype = 'application/xml'
        data = render_to_string('os-console.xml', {'console': resp})
    else:
        mimetype = 'application/json'
        data = json.dumps({'console': resp})

    log.info("User %s got VNC console for VM %s", credentials.userid,
             server_id)

    return HttpResponse(data, content_type=mimetype, status=200)
Exemple #25
0
def update_metadata(request, server_id):
    # Normal Response Code: 201
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badRequest (400),
    #                       buildInProgress (409),
    #                       badMediaType(415),
    #                       overLimit (413)

    req = utils.get_json_body(request)
    credentials = request.credentials
    userid = credentials.userid

    log.debug("User: %s, VM: %s, Action: update_metadata, Request: %s", userid,
              server_id, req)

    vm = util.get_vm(server_id,
                     credentials,
                     non_suspended=True,
                     non_deleted=True)
    metadata = utils.get_attribute(req,
                                   "metadata",
                                   required=True,
                                   attr_type=dict)

    if len(metadata) + len(vm.metadata.all()) - \
       len(vm.metadata.all().filter(meta_key__in=metadata.keys())) > \
       settings.CYCLADES_VM_MAX_METADATA:
        raise faults.BadRequest("Virtual Machines cannot have more than %s "
                                "metadata items" %
                                settings.CYCLADES_VM_MAX_METADATA)

    for key, val in metadata.items():
        if len(key) > VirtualMachineMetadata.KEY_LENGTH:
            raise faults.BadRequest("Malformed Request. Metadata key is too"
                                    " long")
        if len(val) > VirtualMachineMetadata.VALUE_LENGTH:
            raise faults.BadRequest("Malformed Request. Metadata value is too"
                                    " long")

        if not isinstance(key, (basestring, int)) or\
           not isinstance(val, (basestring, int)):
            raise faults.BadRequest("Malformed Request. Invalid metadata.")
        meta, created = vm.metadata.get_or_create(meta_key=key)
        meta.meta_value = val
        meta.save()

    vm.save()

    log.info("User %s updated metadata of VM %s", userid, vm.id)

    vm_meta = dict((m.meta_key, m.meta_value) for m in vm.metadata.all())
    return util.render_metadata(request, vm_meta, status=201)
Exemple #26
0
def remove_floating_ip(request, vm, args):
    address = args.get("address")
    if address is None:
        raise faults.BadRequest("Missing 'address' attribute")
    floating_ip = util.get_floating_ip_by_address(vm.userid, address,
                                                  for_update=True)
    if floating_ip.nic is None:
        raise faults.BadRequest("Floating IP %s not attached to instance"
                                % address)
    servers.delete_port(floating_ip.nic)
    return HttpResponse(status=202)
Exemple #27
0
def create_common(user_id, size, name=None, description=None,
                  source_volume_id=None, source_snapshot_id=None,
                  source_image_id=None, volume_type=None, metadata=None,
                  project_id=None, shared_to_project=False):
    """Common tasks and checks for the creation of a new volume.

    This function processes the necessary arguments in order to call the
    `_create_volume` function, which creates the volume in the DB.

    The main duty of `create_common` is to handle the metadata creation of the
    volume and to update the quota of the user.
    """
    # Assert that not more than one source are used
    sources = filter(lambda x: x is not None,
                     [source_volume_id, source_snapshot_id, source_image_id])
    if len(sources) > 1:
        raise faults.BadRequest("Volume can not have more than one source!")

    if source_volume_id is not None:
        source_type = "volume"
        source_uuid = source_volume_id
    elif source_snapshot_id is not None:
        source_type = "snapshot"
        source_uuid = source_snapshot_id
    elif source_image_id is not None:
        source_type = "image"
        source_uuid = source_image_id
    else:
        source_type = "blank"
        source_uuid = None

    if project_id is None:
        project_id = user_id

    if metadata is not None and \
       len(metadata) > settings.CYCLADES_VOLUME_MAX_METADATA:
        raise faults.BadRequest("Volumes cannot have more than %s metadata "
                                "items" %
                                settings.CYCLADES_VOLUME_MAX_METADATA)

    volume = _create_volume(user_id, project_id, size, source_type,
                            source_uuid, volume_type=volume_type,
                            name=name, description=description, index=None,
                            shared_to_project=shared_to_project)

    if metadata is not None:
        for meta_key, meta_val in metadata.items():
            utils.check_name_length(meta_key, VolumeMetadata.KEY_LENGTH,
                                    "Metadata key is too long")
            utils.check_name_length(meta_val, VolumeMetadata.VALUE_LENGTH,
                                    "Metadata value is too long")
            volume.metadata.create(key=meta_key, value=meta_val)

    return volume
Exemple #28
0
def create_metadata_item(request, server_id, key):
    # Normal Response Code: 201
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       itemNotFound (404),
    #                       badRequest (400),
    #                       buildInProgress (409),
    #                       badMediaType(415),
    #                       overLimit (413)

    req = utils.get_json_body(request)
    credentials = request.credentials
    userid = credentials.userid
    log.debug("User: %s, VM: %s, Action: create_metadata, Request: %s", userid,
              server_id, req)

    vm = util.get_vm(server_id,
                     credentials,
                     non_suspended=True,
                     non_deleted=True)
    try:
        metadict = req['meta']
        assert isinstance(metadict, dict)
        assert len(metadict) == 1
        assert key in metadict
    except (KeyError, AssertionError):
        raise faults.BadRequest("Malformed request")

    value = metadict[key]

    # Check key, value length
    if len(key) > VirtualMachineMetadata.KEY_LENGTH:
        raise faults.BadRequest("Malformed Request. Metadata key is too long")
    if len(value) > VirtualMachineMetadata.VALUE_LENGTH:
        raise faults.BadRequest("Malformed Request. Metadata value is too"
                                " long")

    # Check number of metadata items
    if vm.metadata.exclude(meta_key=key).count() == \
       settings.CYCLADES_VM_MAX_METADATA:
        raise faults.BadRequest("Virtual Machines cannot have more than %s"
                                " metadata items" %
                                settings.CYCLADES_VM_MAX_METADATA)

    meta, created = VirtualMachineMetadata.objects.get_or_create(meta_key=key,
                                                                 vm=vm)

    meta.meta_value = value
    meta.save()
    vm.save()
    d = {meta.meta_key: meta.meta_value}
    return util.render_meta(request, d, status=201)
Exemple #29
0
def update_volume_metadata(request, volume_id, reset=False):
    req = utils.get_json_body(request)
    log.debug("User: %s, Volume: %s Action: update_metadata, Request: %s",
              request.user_uniq, volume_id, req)

    meta_dict = utils.get_attribute(req,
                                    "metadata",
                                    required=True,
                                    attr_type=dict)
    for key, value in meta_dict.items():
        check_name_length(key, VolumeMetadata.KEY_LENGTH,
                          "Metadata key is too long.")
        check_name_length(value, VolumeMetadata.VALUE_LENGTH,
                          "Metadata value is too long.")
    volume = util.get_volume(request.user_uniq,
                             request.user_projects,
                             volume_id,
                             for_update=True,
                             non_deleted=True)
    if reset:
        if len(meta_dict) > settings.CYCLADES_VOLUME_MAX_METADATA:
            raise faults.BadRequest("Volumes cannot have more than %s metadata"
                                    " items" %
                                    settings.CYCLADES_VOLUME_MAX_METADATA)

        volume.metadata.all().delete()
        for key, value in meta_dict.items():
            volume.metadata.create(key=key, value=value)
    else:
        if len(meta_dict) + len(volume.metadata.all()) - \
           len(volume.metadata.all().filter(key__in=meta_dict.keys())) > \
           settings.CYCLADES_VOLUME_MAX_METADATA:
            raise faults.BadRequest("Volumes cannot have more than %s metadata"
                                    " items" %
                                    settings.CYCLADES_VOLUME_MAX_METADATA)

        for key, value in meta_dict.items():
            try:
                # Update existing metadata
                meta = volume.metadata.get(key=key)
                meta.value = value
                meta.save()
            except VolumeMetadata.DoesNotExist:
                # Or create a new one
                volume.metadata.create(key=key, value=value)

    log.info("User %s updated metadata for volume %s", request.user_uniq,
             volume.id)

    metadata = volume.metadata.values_list('key', 'value')
    data = json.dumps({"metadata": dict(metadata)})
    return HttpResponse(data, content_type="application/json", status=200)
Exemple #30
0
def list_images(request, detail=False):
    """Return a list of available images.

    This includes images owned by the user, images shared with the user and
    public images.

    """
    def get_request_params(keys):
        params = {}
        for key in keys:
            val = request.GET.get(key, None)
            if val is not None:
                params[key] = val
        return params

    log.debug('list_public_images detail=%s', detail)

    filters = get_request_params(FILTERS)
    params = get_request_params(PARAMS)

    params.setdefault('sort_key', 'created_at')
    params.setdefault('sort_dir', 'desc')

    if not params['sort_key'] in SORT_KEY_OPTIONS:
        raise faults.BadRequest("Invalid 'sort_key'")
    if not params['sort_dir'] in SORT_DIR_OPTIONS:
        raise faults.BadRequest("Invalid 'sort_dir'")

    if 'size_max' in filters:
        try:
            filters['size_max'] = int(filters['size_max'])
        except ValueError:
            raise faults.BadRequest("Malformed request.")

    if 'size_min' in filters:
        try:
            filters['size_min'] = int(filters['size_min'])
        except ValueError:
            raise faults.BadRequest("Malformed request.")

    with PlanktonBackend(request.user_uniq) as backend:
        images = backend.list_images(filters, params)

    # Remove keys that should not be returned
    fields = DETAIL_FIELDS if detail else LIST_FIELDS
    for image in images:
        for key in image.keys():
            if key not in fields:
                del image[key]

    data = json.dumps(images, indent=settings.DEBUG)
    return HttpResponse(data)