def serial_action(request, serial): input_data = utils.get_json_body(request) check_is_dict(input_data) try: serial = int(serial) except ValueError: raise BadRequest("Serial should be an integer.") client_key = unicode(request.component_instance) accept = 'accept' in input_data reject = 'reject' in input_data if accept == reject: raise BadRequest('Specify either accept or reject action.') result = qh.resolve_pending_commission(clientkey=client_key, serial=serial, accept=accept) response = HttpResponse() if not result: response.status_code = 404 return response
def update_metadata(request, image_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) log.info('update_image_metadata %s %s', image_id, req) with backend.PlanktonBackend(request.credentials.userid) as b: image = b.get_image(image_id) try: metadata = req['metadata'] assert isinstance(metadata, dict) except (KeyError, AssertionError): raise faults.BadRequest('Malformed request.') properties = image['properties'] properties.update(metadata) b.update_metadata(image_id, dict(properties=properties)) return util.render_metadata(request, properties, status=201)
def update_volume(request, volume_id): req = utils.get_json_body(request) log.debug('update_volume volume_id: %s, request: %s', volume_id, req) volume = util.get_volume(request.user_uniq, volume_id, for_update=True, non_deleted=True) vol_req = utils.get_attribute(req, "volume", attr_type=dict, required=True) name = utils.get_attribute(vol_req, "display_name", required=False) description = utils.get_attribute(vol_req, "display_description", required=False) delete_on_termination = utils.get_attribute(vol_req, "delete_on_termination", attr_type=bool, required=False) if name is None and description is None and\ delete_on_termination is None: raise faults.BadRequest("Nothing to update.") else: volume = volumes.update(volume, name, description, delete_on_termination) data = json.dumps({'volume': volume_to_dict(volume, detail=True)}) return HttpResponse(data, content_type="application/json", status=200)
def reassign_volume(request, volume_id, args): req = utils.get_json_body(request) log.debug("User: %s, Volume: %s Action: reassign_volume, Request: %s", request.user_uniq, volume_id, args) shared_to_project = args.get("shared_to_project", False) if shared_to_project and not settings.CYCLADES_SHARED_RESOURCES_ENABLED: raise faults.Forbidden("Sharing resource to the members of the project" " is not permitted") project = args.get("project") if project is None: raise faults.BadRequest("Missing 'project' attribute.") volume = util.get_volume(request.user_uniq, request.user_projects, volume_id, for_update=True, non_deleted=True) if request.user_uniq != volume.userid: raise faults.Forbidden("Action 'reassign' is allowed only to the owner" " of the volume.") volumes.reassign_volume(volume, project, shared_to_project) log.info("User %s reassigned volume %s to project %s, shared: %s", request.user_uniq, volume.id, project, shared_to_project) return HttpResponse(status=200)
def membership_action(request, memb_id): user = request.user input_data = utils.get_json_body(request) func, action_data = get_action(MEMBERSHIP_ACTION, input_data) with ExceptionHandler(): func(memb_id, user, reason=action_data) return HttpResponse()
def update_server_name(request, server_id): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # badMediaType(415), # itemNotFound (404), # buildInProgress (409), # overLimit (413) credentials = request.credentials req = utils.get_json_body(request) log.debug("User: %s, VM: %s, Action: rename, Request: %s", credentials.userid, server_id, req) req = utils.get_attribute(req, "server", attr_type=dict, required=True) name = utils.get_attribute(req, "name", attr_type=basestring, required=True) servers.rename(server_id, new_name=name, credentials=credentials) log.info("User %s renamed server %s", credentials.userid, server_id) return HttpResponse(status=204)
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)
def update_snapshot(request, snapshot_id): util.assert_snapshots_enabled(request) req = utils.get_json_body(request) log.debug("User: %s, Snapshot: %s Action: update", request.user_uniq, snapshot_id) snapshot = util.get_snapshot(request.user_uniq, snapshot_id) snap_dict = utils.get_attribute(req, "snapshot", attr_type=dict, required=True) new_name = utils.get_attribute(snap_dict, "display_name", required=False, attr_type=basestring) new_description = utils.get_attribute(snap_dict, "display_description", required=False, attr_type=basestring) if new_name is None and new_description is None: raise faults.BadRequest("Nothing to update.") snapshot = snapshots.update(snapshot, name=new_name, description=new_description) log.info("User %s updated snapshot %s", request.user_uniq, snapshot["id"]) data = json.dumps({'snapshot': snapshot_to_dict(snapshot, detail=True)}) return HttpResponse(data, content_type="application/json", status=200)
def update_server_name(request, server_id): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # badMediaType(415), # itemNotFound (404), # buildInProgress (409), # overLimit (413) req = utils.get_json_body(request) log.info('update_server_name %s %s', server_id, req) req = utils.get_attribute(req, "server", attr_type=dict, required=True) name = utils.get_attribute(req, "name", attr_type=basestring, required=True) vm = util.get_vm(server_id, request.user_uniq, for_update=True, non_suspended=True, non_deleted=True) servers.rename(vm, new_name=name) return HttpResponse(status=204)
def allocate_floating_ip(request): """Allocate a floating IP.""" req = utils.get_json_body(request) floating_ip_dict = api.utils.get_attribute(req, "floatingip", required=True, attr_type=dict) userid = request.user_uniq project = floating_ip_dict.get("project", None) log.info('allocate_floating_ip user: %s request: %s', userid, req) # the network_pool is a mandatory field network_id = api.utils.get_attribute(floating_ip_dict, "floating_network_id", required=False, attr_type=(basestring, int)) if network_id is None: floating_ip = ips.create_floating_ip(userid, project=project) else: try: network_id = int(network_id) except ValueError: raise faults.BadRequest("Invalid networkd ID.") network = util.get_network(network_id, userid, for_update=True, non_deleted=True) address = api.utils.get_attribute(floating_ip_dict, "floating_ip_address", required=False, attr_type=basestring) floating_ip = ips.create_floating_ip(userid, network, address, project=project) log.info("User '%s' allocated floating IP '%s'", userid, floating_ip) request.serialization = "json" data = json.dumps({"floatingip": ip_to_dict(floating_ip)}) return HttpResponse(data, status=200)
def resolve_pending_commissions(request): input_data = utils.get_json_body(request) check_is_dict(input_data) client_key = unicode(request.component_instance) accept = input_data.get('accept', []) reject = input_data.get('reject', []) if not isinstance(accept, list) or not isinstance(reject, list): m = '"accept" and "reject" should reference lists of serials.' raise BadRequest(m) if not are_integer(accept) or not are_integer(reject): raise BadRequest("Serials should be integer.") result = qh.resolve_pending_commissions(clientkey=client_key, accept_set=accept, reject_set=reject) accepted, rejected, notFound, conflicting = result notFound = [(serial, notFoundCF(serial)) for serial in notFound] conflicting = [(serial, conflictingCF(serial)) for serial in conflicting] cloudfaults = notFound + conflicting data = {'accepted': accepted, 'rejected': rejected, 'failed': cloudfaults} return json_response(data)
def update_volume(request, volume_id): credentials = request.credentials req = utils.get_json_body(request) log.debug("User: %s, Volume: %s Action: update_volume, Request: %s", credentials.userid, volume_id, req) vol_req = utils.get_attribute(req, "volume", attr_type=dict, required=True) name = utils.get_attribute(vol_req, "display_name", required=False) description = utils.get_attribute(vol_req, "display_description", required=False) delete_on_termination = utils.get_attribute(vol_req, "delete_on_termination", attr_type=bool, required=False) if name is None and description is None and\ delete_on_termination is None: raise faults.BadRequest("Nothing to update.") volume = volumes.update(volume_id, name, description, delete_on_termination, credentials=credentials) log.info("User %s updated volume %s", credentials.userid, volume_id) data = json.dumps({'volume': volume_to_dict(volume, detail=True)}) return HttpResponse(data, content_type="application/json", status=200)
def update_server_name(request, server_id): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # badMediaType(415), # itemNotFound (404), # buildInProgress (409), # overLimit (413) req = utils.get_json_body(request) log.debug("User: %s, VM: %s, Action: rename, Request: %s", request.user_uniq, server_id, req) req = utils.get_attribute(req, "server", attr_type=dict, required=True) name = utils.get_attribute(req, "name", attr_type=basestring, required=True) vm = util.get_vm(server_id, request.user_uniq, request.user_projects, for_update=True, non_suspended=True, non_deleted=True) servers.rename(vm, new_name=name) log.info("User %s renamed server %s", request.user_uniq, vm.id) return HttpResponse(status=204)
def demux_server_action(request, server_id): req = utils.get_json_body(request) 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, request.user_projects, for_update=True, non_deleted=True, non_suspended=True) try: action = req.keys()[0] except IndexError: raise faults.BadRequest("Malformed Request.") log.debug("User: %s, VM: %s, Action: %s Request: %s", request.user_uniq, 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=True, attr_type=dict) return server_actions[action](request, vm, action_args)
def create_metadata_item(request, image_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) log.info('create_image_metadata_item %s %s %s', image_id, key, req) try: metadict = req['meta'] assert isinstance(metadict, dict) assert len(metadict) == 1 assert key in metadict except (KeyError, AssertionError): raise faults.BadRequest('Malformed request.') val = metadict[key] with backend.PlanktonBackend(request.user_uniq) as b: image = b.get_image(image_id) properties = image['properties'] properties[key] = val b.update_metadata(image_id, dict(properties=properties)) return util.render_meta(request, {key: val}, status=201)
def create_metadata_item(request, image_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) log.info('create_image_metadata_item %s %s %s', image_id, key, req) try: metadict = req['meta'] assert isinstance(metadict, dict) assert len(metadict) == 1 assert key in metadict except (KeyError, AssertionError): raise faults.BadRequest('Malformed request.') val = metadict[key] with backend.PlanktonBackend(request.credentials.userid) as b: image = b.get_image(image_id) properties = image['properties'] properties[key] = val b.update_metadata(image_id, dict(properties=properties)) return util.render_meta(request, {key: val}, status=201)
def create_snapshot(request): """Create a new Snapshot.""" req = utils.get_json_body(request) log.debug("create_snapshot %s", req) user_id = request.user_uniq snap_dict = utils.get_attribute(req, "snapshot", required=True, attr_type=dict) volume_id = utils.get_attribute(snap_dict, "volume_id", required=True) volume = util.get_volume(user_id, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) metadata = utils.get_attribute(snap_dict, "metadata", required=False, attr_type=dict, default={}) name = utils.get_attribute(snap_dict, "display_name", required=False, attr_type=basestring, default="Snapshot of volume '%s'" % volume_id) description = utils.get_attribute(snap_dict, "display_description", required=False, attr_type=basestring, default="") # TODO: What to do with force ? force = utils.get_attribute(req, "force", required=False, attr_type=bool, default=False) snapshot = snapshots.create(user_id=user_id, volume=volume, name=name, description=description, metadata=metadata, force=force) # Render response data = json.dumps(dict(snapshot=snapshot_to_dict(snapshot, detail=False))) return HttpResponse(data, status=202)
def update_snapshot(request, snapshot_id): credentials = request.credentials util.assert_snapshots_enabled(request) req = utils.get_json_body(request) log.debug("User: %s, Snapshot: %s Action: update", credentials.userid, snapshot_id) snapshot = util.get_snapshot(credentials.userid, snapshot_id) snap_dict = utils.get_attribute(req, "snapshot", attr_type=dict, required=True) new_name = utils.get_attribute(snap_dict, "display_name", required=False, attr_type=basestring) new_description = utils.get_attribute(snap_dict, "display_description", required=False, attr_type=basestring) if new_name is None and new_description is None: raise faults.BadRequest("Nothing to update.") snapshot = snapshots.update(snapshot, name=new_name, description=new_description) log.info("User %s updated snapshot %s", credentials.userid, snapshot["id"]) data = json.dumps({'snapshot': snapshot_to_dict(snapshot, detail=True)}) return HttpResponse(data, content_type="application/json", status=200)
def update_volume(request, volume_id): req = utils.get_json_body(request) log.debug("User: %s, Volume: %s Action: update_volume, Request: %s", request.user_uniq, volume_id, req) volume = util.get_volume(request.user_uniq, request.user_projects, volume_id, for_update=True, non_deleted=True) vol_req = utils.get_attribute(req, "volume", attr_type=dict, required=True) name = utils.get_attribute(vol_req, "display_name", required=False) description = utils.get_attribute(vol_req, "display_description", required=False) delete_on_termination = utils.get_attribute(vol_req, "delete_on_termination", attr_type=bool, required=False) if name is None and description is None and\ delete_on_termination is None: raise faults.BadRequest("Nothing to update.") else: volume = volumes.update(volume, name, description, delete_on_termination) log.info("User %s updated volume %s", request.user_uniq, volume.id) data = json.dumps({'volume': volume_to_dict(volume, detail=True)}) return HttpResponse(data, content_type="application/json", status=200)
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)
def resolve_pending_commissions(request): input_data = utils.get_json_body(request) check_is_dict(input_data) client_key = unicode(request.component_instance) accept = input_data.get('accept', []) reject = input_data.get('reject', []) if not isinstance(accept, list) or not isinstance(reject, list): m = '"accept" and "reject" should reference lists of serials.' raise BadRequest(m) if not are_integer(accept) or not are_integer(reject): raise BadRequest("Serials should be integer.") result = qh.resolve_pending_commissions(clientkey=client_key, accept_set=accept, reject_set=reject) accepted, rejected, notFound, conflicting = result notFound = [(serial, notFoundCF(serial)) for serial in notFound] conflicting = [(serial, conflictingCF(serial)) for serial in conflicting] cloudfaults = notFound + conflicting data = {'accepted': accepted, 'rejected': rejected, 'failed': cloudfaults } return json_response(data)
def update_metadata(request, image_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) log.info('update_image_metadata %s %s', image_id, req) with backend.PlanktonBackend(request.user_uniq) as b: image = b.get_image(image_id) try: metadata = req['metadata'] assert isinstance(metadata, dict) except (KeyError, AssertionError): raise faults.BadRequest('Malformed request.') properties = image['properties'] properties.update(metadata) b.update_metadata(image_id, dict(properties=properties)) return util.render_metadata(request, properties, status=201)
def authenticate(request): try: content_length = get_content_length(request) except faults.LengthRequired: content_length = None public_mode = True if not content_length else False d = defaultdict(dict) if not public_mode: req = utils.get_json_body(request) uuid = None try: token_id = req['auth']['token']['id'] except KeyError: try: token_id = req['auth']['passwordCredentials']['password'] uuid = req['auth']['passwordCredentials']['username'] except KeyError: raise faults.BadRequest( 'Malformed request: missing credentials') tenant = req['auth'].get('tenantName') if token_id is None: raise faults.BadRequest('Malformed request: missing token') try: user = AstakosUser.objects.get(auth_token=token_id) except AstakosUser.DoesNotExist: raise faults.Unauthorized('Invalid token') validate_user(user) if uuid is not None: if user.uuid != uuid: raise faults.Unauthorized('Invalid credentials') if tenant: if user.uuid != tenant: raise faults.BadRequest('Not conforming tenantName') d["access"]["token"] = { "id": user.auth_token, "expires": utils.isoformat(user.auth_token_expires), "tenant": {"id": user.uuid, "name": user.realname}} d["access"]["user"] = { "id": user.uuid, 'name': user.realname, "roles": [dict(id=str(g['id']), name=g['name']) for g in user.groups.values('id', 'name')], "roles_links": []} d["access"]["serviceCatalog"] = get_endpoints() if request.serialization == 'xml': return xml_response({'d': d}, 'api/access.xml') else: return json_response(d)
def create_server(request): # Normal Response Code: 202 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badMediaType(415), # itemNotFound (404), # badRequest (400), # serverCapacityUnavailable (503), # overLimit (413) req = utils.get_json_body(request) user_id = request.user_uniq log.info('create_server user: %s request: %s', user_id, req) try: server = req['server'] name = server['name'] metadata = server.get('metadata', {}) assert isinstance(metadata, dict) image_id = server['imageRef'] flavor_id = server['flavorRef'] personality = server.get('personality', []) assert isinstance(personality, list) networks = server.get("networks") if networks is not None: assert isinstance(networks, list) project = server.get("project") except (KeyError, AssertionError): raise faults.BadRequest("Malformed request") volumes = None dev_map = server.get("block_device_mapping_v2") if dev_map is not None: volumes = parse_block_device_mapping(dev_map) # Verify that personalities are well-formed util.verify_personality(personality) # Get flavor (ensure it is active) flavor = util.get_flavor(flavor_id, include_deleted=False) if not flavor.allow_create: msg = ("It is not allowed to create a server from flavor with id '%d'," " see 'allow_create' flavor attribute") raise faults.Forbidden(msg % flavor.id) # Generate password password = util.random_password() vm = servers.create(user_id, name, password, flavor, image_id, metadata=metadata, personality=personality, project=project, networks=networks, volumes=volumes) server = vm_to_dict(vm, detail=True) server['status'] = 'BUILD' server['adminPass'] = password response = render_server(request, server, status=202) return response
def issue_commission(request): input_data = utils.get_json_body(request) check_is_dict(input_data) client_key = unicode(request.component_instance) provisions = input_data.get('provisions') if provisions is None: raise BadRequest("Provisions are missing.") if not isinstance(provisions, list): raise BadRequest("Provisions should be a list.") provisions = _provisions_to_list(provisions) force = input_data.get('force', False) if not isinstance(force, bool): raise BadRequest('"force" option should be a boolean.') auto_accept = input_data.get('auto_accept', False) if not isinstance(auto_accept, bool): raise BadRequest('"auto_accept" option should be a boolean.') name = input_data.get('name', "") if not isinstance(name, basestring): raise BadRequest("Commission name should be a string.") try: result = _issue_commission(clientkey=client_key, provisions=provisions, name=name, force=force, accept=auto_accept) data = {"serial": result} status_code = 201 except (qh_exception.NoCapacityError, qh_exception.NoQuantityError) as e: status_code = 413 body = { "message": e.message, "code": status_code, "data": e.data, } data = {"overLimit": body} except qh_exception.NoHoldingError as e: status_code = 404 body = { "message": e.message, "code": status_code, "data": e.data, } data = {"itemNotFound": body} except qh_exception.InvalidDataError as e: status_code = 400 body = { "message": e.message, "code": status_code, } data = {"badRequest": body} return json_response(data, status_code=status_code)
def reassign_volume(request, volume_id, args): req = utils.get_json_body(request) log.debug('reassign_volume volume_id: %s, request: %s', volume_id, req) project = args.get("project") if project is None: raise faults.BadRequest("Missing 'project' attribute.") volume = util.get_volume(request.user_uniq, volume_id, for_update=True, non_deleted=True) volumes.reassign_volume(volume, project) return HttpResponse(status=200)
def create_snapshot(request): """Create a new Snapshot.""" util.assert_snapshots_enabled(request) req = utils.get_json_body(request) user_id = request.user_uniq log.debug("User: %s, Action: create_snapshot, Request: %s", user_id, req) snap_dict = utils.get_attribute(req, "snapshot", required=True, attr_type=dict) volume_id = utils.get_attribute(snap_dict, "volume_id", required=True) volume = util.get_volume(user_id, request.user_projects, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) metadata = utils.get_attribute(snap_dict, "metadata", required=False, attr_type=dict, default={}) name = utils.get_attribute(snap_dict, "display_name", required=False, attr_type=basestring, default="Snapshot of volume '%s'" % volume_id) description = utils.get_attribute(snap_dict, "display_description", required=False, attr_type=basestring, default="") # TODO: What to do with force ? force = utils.get_attribute(req, "force", required=False, attr_type=bool, default=False) snapshot = snapshots.create(user_id=user_id, volume=volume, name=name, description=description, metadata=metadata, force=force) log.info("User %s created snapshot %s", user_id, snapshot["id"]) # Render response data = json.dumps(dict(snapshot=snapshot_to_dict(snapshot, detail=False))) return HttpResponse(data, status=202)
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)
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)
def issue_commission(request): input_data = utils.get_json_body(request) check_is_dict(input_data) client_key = unicode(request.component_instance) provisions = input_data.get('provisions') if provisions is None: raise BadRequest("Provisions are missing.") if not isinstance(provisions, list): raise BadRequest("Provisions should be a list.") provisions = _provisions_to_list(provisions) force = input_data.get('force', False) if not isinstance(force, bool): raise BadRequest('"force" option should be a boolean.') auto_accept = input_data.get('auto_accept', False) if not isinstance(auto_accept, bool): raise BadRequest('"auto_accept" option should be a boolean.') name = input_data.get('name', "") if not isinstance(name, basestring): raise BadRequest("Commission name should be a string.") try: result = _issue_commission(clientkey=client_key, provisions=provisions, name=name, force=force, accept=auto_accept) data = {"serial": result} status_code = 201 except (qh_exception.NoCapacityError, qh_exception.NoQuantityError) as e: status_code = 413 body = {"message": e.message, "code": status_code, "data": e.data, } data = {"overLimit": body} except qh_exception.NoHoldingError as e: status_code = 404 body = {"message": e.message, "code": status_code, "data": e.data, } data = {"itemNotFound": body} except qh_exception.InvalidDataError as e: status_code = 400 body = {"message": e.message, "code": status_code, } data = {"badRequest": body} return json_response(data, status_code=status_code)
def project_action(request, project_id): user = request.user input_data = utils.get_json_body(request) func, action_data = get_action(PROJECT_ACTION, input_data) with ExceptionHandler(): kwargs = {"request_user": user, "reason": action_data.get("reason", "")} if func in APP_ACTION_FUNCS: kwargs["application_id"] = action_data["app_id"] func(project_id=project_id, **kwargs) return HttpResponse()
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)
def network_action_demux(request, network_id): req = utils.get_json_body(request) action = req.keys()[0] try: f = NETWORK_ACTIONS[action] except KeyError: raise api.faults.BadRequest("Action %s not supported." % action) action_args = req[action] if not isinstance(action_args, dict): raise api.faults.BadRequest("Invalid argument.") return f(request, network_id, action_args)
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)
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)
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)
def update_snapshot_metadata(request, snapshot_id, reset=False): req = utils.get_json_body(request) log.debug('update_snapshot_meta snapshot_id: %s, reset: %s request: %s', snapshot_id, reset, req) snapshot = util.get_snapshot(request.user_uniq, snapshot_id) meta_dict = utils.get_attribute(req, "metadata", required=True, attr_type=dict) with backend.PlanktonBackend(request.user_uniq) as b: b.update_properties(snapshot_id, meta_dict, replace=reset) snapshot = util.get_snapshot(request.user_uniq, snapshot_id) metadata = snapshot["properties"] data = json.dumps({"metadata": dict(metadata)}) return HttpResponse(data, content_type="application/json", status=200)
def project_action(request, project_id): user = request.user input_data = utils.get_json_body(request) func, action_data = get_action(PROJECT_ACTION, input_data) with ExceptionHandler(): kwargs = {"request_user": user, "reason": action_data.get("reason", ""), } if func in APP_ACTION_FUNCS: kwargs["application_id"] = action_data["app_id"] func(project_id=project_id, **kwargs) return HttpResponse()
def allocate_floating_ip(request): """Allocate a floating IP.""" req = utils.get_json_body(request) log.debug("User: %s, Action: create_floating_ip, Request: %s", request.user_uniq, req) floating_ip_dict = api.utils.get_attribute(req, "floatingip", required=True, attr_type=dict) userid = request.user_uniq project = floating_ip_dict.get("project", None) shared_to_project = floating_ip_dict.get("shared_to_project", False) # the network_pool is a mandatory field network_id = api.utils.get_attribute(floating_ip_dict, "floating_network_id", required=False, attr_type=(basestring, int)) if network_id is None: floating_ip = \ ips.create_floating_ip(userid, project=project, shared_to_project=shared_to_project) else: try: network_id = int(network_id) except ValueError: raise faults.BadRequest("Invalid networkd ID.") network = util.get_network(network_id, userid, request.user_projects, for_update=True, non_deleted=True) address = api.utils.get_attribute(floating_ip_dict, "floating_ip_address", required=False, attr_type=basestring) floating_ip = \ ips.create_floating_ip(userid, network, address, project=project, shared_to_project=shared_to_project) log.info("User %s created floating IP %s, network %s, address %s", userid, floating_ip.id, floating_ip.network_id, floating_ip.address) request.serialization = "json" data = json.dumps({"floatingip": ip_to_dict(floating_ip)}) return HttpResponse(data, status=200)
def update_snapshot_metadata(request, snapshot_id, reset=False): credentials = request.credentials util.assert_snapshots_enabled(request) req = utils.get_json_body(request) log.debug("User: %s, Snapshot: %s Action: update_metadata", credentials.userid, snapshot_id) snapshot = util.get_snapshot(credentials.userid, snapshot_id) meta_dict = utils.get_attribute(req, "metadata", required=True, attr_type=dict) with backend.PlanktonBackend(credentials.userid) as b: b.update_properties(snapshot_id, meta_dict, replace=reset) snapshot = util.get_snapshot(credentials.userid, snapshot_id) metadata = snapshot["properties"] data = json.dumps({"metadata": dict(metadata)}) return HttpResponse(data, content_type="application/json", status=200)
def project_action(request, project_id): user = request.user input_data = utils.get_json_body(request) if not isinstance(input_data, dict): raise faults.BadRequest("Invalid input data") func, action_data = get_action(PROJECT_ACTION, input_data) with ExceptionHandler(): kwargs = {"request_user": user, "reason": action_data.get("reason", ""), } if func in APP_ACTION_FUNCS: kwargs["application_id"] = action_data["app_id"] func(project_id=project_id, **kwargs) return HttpResponse()
def update_volume_metadata(request, volume_id, reset=False): credentials = request.credentials req = utils.get_json_body(request) log.debug("User: %s, Volume: %s Action: update_metadata, Request: %s", credentials.userid, 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.credentials, 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", credentials.userid, volume.id) metadata = volume.metadata.values_list('key', 'value') data = json.dumps({"metadata": dict(metadata)}) return HttpResponse(data, content_type="application/json", status=200)
def network_action_demux(request, network_id): req = utils.get_json_body(request) network = util.get_network(network_id, request.user_uniq, request.user_projects, for_update=True, non_deleted=True) action = req.keys()[0] try: f = NETWORK_ACTIONS[action] except KeyError: raise api.faults.BadRequest("Action %s not supported." % action) action_args = req[action] if not isinstance(action_args, dict): raise api.faults.BadRequest("Invalid argument.") return f(request, network, action_args)
def attach_volume(request, server_id): req = utils.get_json_body(request) log.debug("attach_volume server_id %s request", server_id, req) user_id = request.user_uniq vm = util.get_vm(server_id, user_id, for_update=True, non_deleted=True) attachment_dict = api.utils.get_attribute(req, "volumeAttachment", required=True) # Get volume volume_id = api.utils.get_attribute(attachment_dict, "volumeId") volume = get_volume(user_id, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) vm = server_attachments.attach_volume(vm, volume) attachment = volume_to_attachment(volume) data = json.dumps({'volumeAttachment': attachment}) return HttpResponse(data, status=202)
def allocate_floating_ip(request): """Allocate a floating IP.""" req = utils.get_json_body(request) credentials = request.credentials log.debug("User: %s, Action: create_floating_ip, Request: %s", credentials.userid, req) floating_ip_dict = api.utils.get_attribute(req, "floatingip", required=True, attr_type=dict) userid = credentials.userid project = floating_ip_dict.get("project", None) shared_to_project = floating_ip_dict.get("shared_to_project", False) # the network_pool is a mandatory field network_id = api.utils.get_attribute(floating_ip_dict, "floating_network_id", required=False, attr_type=(basestring, int)) if network_id is None: floating_ip = \ ips.create_floating_ip(credentials, project=project, shared_to_project=shared_to_project) else: try: network_id = int(network_id) except ValueError: raise faults.BadRequest("Invalid networkd ID.") address = api.utils.get_attribute(floating_ip_dict, "floating_ip_address", required=False, attr_type=basestring) floating_ip = \ ips.create_floating_ip(credentials, network_id, address, project=project, shared_to_project=shared_to_project) log.info("User %s created floating IP %s, network %s, address %s", userid, floating_ip.id, floating_ip.network_id, floating_ip.address) return HttpResponse(_floatingip_details_view(floating_ip), status=200)
def attach_volume(request, server_id): req = utils.get_json_body(request) credentials = request.credentials user_id = credentials.userid log.debug("User %s, VM: %s, Action: attach_volume, Request: %s", user_id, server_id, req) attachment_dict = api.utils.get_attribute(req, "volumeAttachment", required=True) # Get volume volume_id = api.utils.get_attribute(attachment_dict, "volumeId") volume = servers.attach_volume(server_id, volume_id, credentials) attachment = volume_to_attachment(volume) data = json.dumps({'volumeAttachment': attachment}) return HttpResponse(data, status=202)
def volume_action_demux(request, volume_id): req = utils.get_json_body(request) if not isinstance(req, dict) and len(req) != 1: raise faults.BadRequest("Malformed request") action = req.keys()[0] if not isinstance(action, basestring): raise faults.BadRequest("Malformed Request. Invalid action.") try: action_func = VOLUME_ACTIONS[action] except KeyError: raise faults.BadRequest("Action %s not supported" % action) action_args = utils.get_attribute(req, action, required=True, attr_type=dict) return action_func(request, volume_id, action_args)
def floating_ip_action_demux(request, floating_ip_id): userid = request.user_uniq req = utils.get_json_body(request) log.debug('floating_ip_action %s %s', floating_ip_id, req) if len(req) != 1: raise faults.BadRequest('Malformed request.') floating_ip = util.get_floating_ip_by_id(userid, floating_ip_id, for_update=True) action = req.keys()[0] try: f = FLOATING_IP_ACTIONS[action] except KeyError: raise faults.BadRequest("Action %s not supported." % action) action_args = req[action] if not isinstance(action_args, dict): raise faults.BadRequest("Invalid argument.") return f(request, floating_ip, action_args)