PEP8 cleanup in nova/api. There should be no functional changes here, just style changes to get violations down.
This commit is contained in:
@@ -31,12 +31,13 @@ from nova.api import openstack
|
||||
from nova.api.ec2 import metadatarequesthandler
|
||||
|
||||
|
||||
flags.DEFINE_string('osapi_subdomain', 'api',
|
||||
flags.DEFINE_string('osapi_subdomain', 'api',
|
||||
'subdomain running the OpenStack API')
|
||||
flags.DEFINE_string('ec2api_subdomain', 'ec2',
|
||||
flags.DEFINE_string('ec2api_subdomain', 'ec2',
|
||||
'subdomain running the EC2 API')
|
||||
flags.DEFINE_string('FAKE_subdomain', None,
|
||||
'set to api or ec2 to fake the subdomain of the host for testing')
|
||||
flags.DEFINE_string('FAKE_subdomain', None,
|
||||
'set to api or ec2 to fake the subdomain of the host '
|
||||
'for testing')
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
@@ -44,7 +45,7 @@ class API(wsgi.Router):
|
||||
"""Routes top-level requests to the appropriate controller."""
|
||||
|
||||
def __init__(self):
|
||||
osapidomain = {'sub_domain': [FLAGS.osapi_subdomain]}
|
||||
osapidomain = {'sub_domain': [FLAGS.osapi_subdomain]}
|
||||
ec2domain = {'sub_domain': [FLAGS.ec2api_subdomain]}
|
||||
# If someone wants to pretend they're hitting the OSAPI subdomain
|
||||
# on their local box, they can set FAKE_subdomain to 'api', which
|
||||
@@ -55,7 +56,7 @@ class API(wsgi.Router):
|
||||
ec2domain = {}
|
||||
mapper = routes.Mapper()
|
||||
mapper.sub_domains = True
|
||||
mapper.connect("/", controller=self.osapi_versions,
|
||||
mapper.connect("/", controller=self.osapi_versions,
|
||||
conditions=osapidomain)
|
||||
mapper.connect("/v1.0/{path_info:.*}", controller=openstack.API(),
|
||||
conditions=osapidomain)
|
||||
@@ -107,5 +108,3 @@ class API(wsgi.Router):
|
||||
'2009-04-04',
|
||||
]
|
||||
return ''.join('%s\n' % v for v in versions)
|
||||
|
||||
|
||||
|
@@ -62,7 +62,8 @@ class Authenticate(wsgi.Middleware):
|
||||
|
||||
# Make a copy of args for authentication and signature verification.
|
||||
auth_params = dict(req.params)
|
||||
auth_params.pop('Signature') # not part of authentication args
|
||||
# Not part of authentication args
|
||||
auth_params.pop('Signature')
|
||||
|
||||
# Authenticate the request.
|
||||
try:
|
||||
@@ -109,9 +110,11 @@ class Router(wsgi.Middleware):
|
||||
'SignatureVersion', 'Version', 'Timestamp']
|
||||
args = dict(req.params)
|
||||
try:
|
||||
action = req.params['Action'] # raise KeyError if omitted
|
||||
# Raise KeyError if omitted
|
||||
action = req.params['Action']
|
||||
for non_arg in non_args:
|
||||
args.pop(non_arg) # remove, but raise KeyError if omitted
|
||||
# Remove, but raise KeyError if omitted
|
||||
args.pop(non_arg)
|
||||
except:
|
||||
raise webob.exc.HTTPBadRequest()
|
||||
|
||||
@@ -184,7 +187,8 @@ class Authorizer(wsgi.Middleware):
|
||||
context = req.environ['ec2.context']
|
||||
controller_name = req.environ['ec2.controller'].__class__.__name__
|
||||
action = req.environ['ec2.action']
|
||||
allowed_roles = self.action_roles[controller_name].get(action, ['none'])
|
||||
allowed_roles = self.action_roles[controller_name].get(action,
|
||||
['none'])
|
||||
if self._matches_any_role(context, allowed_roles):
|
||||
return self.application
|
||||
else:
|
||||
@@ -242,4 +246,3 @@ class Executor(wsgi.Application):
|
||||
'<Message>%s</Message></Error></Errors>'
|
||||
'<RequestID>?</RequestID></Response>') % (code, message)
|
||||
return resp
|
||||
|
||||
|
@@ -73,7 +73,7 @@ class AdminController(object):
|
||||
def describe_users(self, _context, **_kwargs):
|
||||
"""Returns all users - should be changed to deal with a list."""
|
||||
return {'userSet':
|
||||
[user_dict(u) for u in manager.AuthManager().get_users()] }
|
||||
[user_dict(u) for u in manager.AuthManager().get_users()]}
|
||||
|
||||
def register_user(self, _context, name, **_kwargs):
|
||||
"""Creates a new user, and returns generated credentials."""
|
||||
@@ -91,7 +91,7 @@ class AdminController(object):
|
||||
def describe_roles(self, context, project_roles=True, **kwargs):
|
||||
"""Returns a list of allowed roles."""
|
||||
roles = manager.AuthManager().get_roles(project_roles)
|
||||
return { 'roles': [{'role': r} for r in roles]}
|
||||
return {'roles': [{'role': r} for r in roles]}
|
||||
|
||||
def describe_user_roles(self, context, user, project=None, **kwargs):
|
||||
"""Returns a list of roles for the given user.
|
||||
@@ -99,7 +99,7 @@ class AdminController(object):
|
||||
Specifying project will return only project specific roles.
|
||||
"""
|
||||
roles = manager.AuthManager().get_user_roles(user, project=project)
|
||||
return { 'roles': [{'role': r} for r in roles]}
|
||||
return {'roles': [{'role': r} for r in roles]}
|
||||
|
||||
def modify_user_role(self, context, user, role, project=None,
|
||||
operation='add', **kwargs):
|
||||
@@ -155,9 +155,10 @@ class AdminController(object):
|
||||
'members': [{'member': m} for m in project.member_ids]}
|
||||
return result
|
||||
|
||||
def modify_project_member(self, context, user, project, operation, **kwargs):
|
||||
def modify_project_member(self, context, user, project, operation,
|
||||
**kwargs):
|
||||
"""Add or remove a user from a project."""
|
||||
if operation =='add':
|
||||
if operation == 'add':
|
||||
manager.AuthManager().add_to_project(user, project)
|
||||
elif operation == 'remove':
|
||||
manager.AuthManager().remove_from_project(user, project)
|
||||
|
@@ -44,6 +44,7 @@ def _underscore_to_xmlcase(str):
|
||||
res = _underscore_to_camelcase(str)
|
||||
return res[:1].lower() + res[1:]
|
||||
|
||||
|
||||
def _try_convert(value):
|
||||
"""Return a non-string if possible"""
|
||||
if value == 'None':
|
||||
@@ -59,12 +60,12 @@ def _try_convert(value):
|
||||
return value
|
||||
if valueneg[0] == '0':
|
||||
if valueneg[1] in 'xX':
|
||||
return int(value,16)
|
||||
return int(value, 16)
|
||||
elif valueneg[1] in 'bB':
|
||||
return int(value,2)
|
||||
return int(value, 2)
|
||||
else:
|
||||
try:
|
||||
return int(value,8)
|
||||
return int(value, 8)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
@@ -80,6 +81,7 @@ def _try_convert(value):
|
||||
except ValueError:
|
||||
return value
|
||||
|
||||
|
||||
class APIRequest(object):
|
||||
def __init__(self, controller, action):
|
||||
self.controller = controller
|
||||
|
@@ -48,6 +48,7 @@ flags.DECLARE('storage_availability_zone', 'nova.volume.manager')
|
||||
|
||||
InvalidInputException = exception.InvalidInputException
|
||||
|
||||
|
||||
class QuotaError(exception.ApiError):
|
||||
"""Quota Exceeeded"""
|
||||
pass
|
||||
@@ -137,8 +138,8 @@ class CloudController(object):
|
||||
for node in nodes:
|
||||
rpc.cast(context,
|
||||
'%s.%s' % (FLAGS.compute_topic, node),
|
||||
{ "method": "refresh_security_group",
|
||||
"args": {"security_group_id": security_group.id}})
|
||||
{"method": "refresh_security_group",
|
||||
"args": {"security_group_id": security_group.id}})
|
||||
|
||||
def get_metadata(self, address):
|
||||
ctxt = context.get_admin_context()
|
||||
@@ -147,48 +148,42 @@ class CloudController(object):
|
||||
return None
|
||||
mpi = self._get_mpi_data(ctxt, instance_ref['project_id'])
|
||||
if instance_ref['key_name']:
|
||||
keys = {
|
||||
'0': {
|
||||
'_name': instance_ref['key_name'],
|
||||
'openssh-key': instance_ref['key_data']
|
||||
}
|
||||
}
|
||||
keys = {'0': {'_name': instance_ref['key_name'],
|
||||
'openssh-key': instance_ref['key_data']}}
|
||||
else:
|
||||
keys = ''
|
||||
hostname = instance_ref['hostname']
|
||||
floating_ip = db.instance_get_floating_address(ctxt,
|
||||
instance_ref['id'])
|
||||
ec2_id = internal_id_to_ec2_id(instance_ref['internal_id'])
|
||||
data = {
|
||||
'user-data': base64.b64decode(instance_ref['user_data']),
|
||||
'meta-data': {
|
||||
'ami-id': instance_ref['image_id'],
|
||||
'ami-launch-index': instance_ref['launch_index'],
|
||||
'ami-manifest-path': 'FIXME',
|
||||
'block-device-mapping': { # TODO(vish): replace with real data
|
||||
'block-device-mapping': {
|
||||
# TODO(vish): replace with real data
|
||||
'ami': 'sda1',
|
||||
'ephemeral0': 'sda2',
|
||||
'root': '/dev/sda1',
|
||||
'swap': 'sda3'
|
||||
},
|
||||
'swap': 'sda3'},
|
||||
'hostname': hostname,
|
||||
'instance-action': 'none',
|
||||
'instance-id': internal_id_to_ec2_id(instance_ref['internal_id']),
|
||||
'instance-id': ec2_id,
|
||||
'instance-type': instance_ref['instance_type'],
|
||||
'local-hostname': hostname,
|
||||
'local-ipv4': address,
|
||||
'kernel-id': instance_ref['kernel_id'],
|
||||
'placement': {
|
||||
'availability-zone': 'nova' # TODO(vish): real zone
|
||||
},
|
||||
# TODO(vish): real zone
|
||||
'placement': {'availability-zone': 'nova'},
|
||||
'public-hostname': hostname,
|
||||
'public-ipv4': floating_ip or '',
|
||||
'public-keys': keys,
|
||||
'ramdisk-id': instance_ref['ramdisk_id'],
|
||||
'reservation-id': instance_ref['reservation_id'],
|
||||
'security-groups': '',
|
||||
'mpi': mpi
|
||||
}
|
||||
}
|
||||
'mpi': mpi}}
|
||||
if False: # TODO(vish): store ancestor ids
|
||||
data['ancestor-ami-ids'] = []
|
||||
if False: # TODO(vish): store product codes
|
||||
@@ -211,7 +206,7 @@ class CloudController(object):
|
||||
'regionEndpoint': FLAGS.ec2_url}]
|
||||
if region_name:
|
||||
regions = [r for r in regions if r['regionName'] in region_name]
|
||||
return {'regionInfo': regions }
|
||||
return {'regionInfo': regions}
|
||||
|
||||
def describe_snapshots(self,
|
||||
context,
|
||||
@@ -237,7 +232,8 @@ class CloudController(object):
|
||||
for key_pair in key_pairs:
|
||||
# filter out the vpn keys
|
||||
suffix = FLAGS.vpn_key_suffix
|
||||
if context.user.is_admin() or not key_pair['name'].endswith(suffix):
|
||||
if context.user.is_admin() or \
|
||||
not key_pair['name'].endswith(suffix):
|
||||
result.append({
|
||||
'keyName': key_pair['name'],
|
||||
'keyFingerprint': key_pair['fingerprint'],
|
||||
@@ -271,7 +267,7 @@ class CloudController(object):
|
||||
if not group_name is None:
|
||||
groups = [g for g in groups if g.name in group_name]
|
||||
|
||||
return {'securityGroupInfo': groups }
|
||||
return {'securityGroupInfo': groups}
|
||||
|
||||
def _format_security_group(self, context, group):
|
||||
g = {}
|
||||
@@ -295,13 +291,10 @@ class CloudController(object):
|
||||
g['ipPermissions'] += [r]
|
||||
return g
|
||||
|
||||
|
||||
def _authorize_revoke_rule_args_to_dict(self, context,
|
||||
to_port=None, from_port=None,
|
||||
ip_protocol=None, cidr_ip=None,
|
||||
user_id=None,
|
||||
source_security_group_name=None,
|
||||
source_security_group_owner_id=None):
|
||||
def _revoke_rule_args_to_dict(self, context, to_port=None, from_port=None,
|
||||
ip_protocol=None, cidr_ip=None, user_id=None,
|
||||
source_security_group_name=None,
|
||||
source_security_group_owner_id=None):
|
||||
|
||||
values = {}
|
||||
|
||||
@@ -322,16 +315,16 @@ class CloudController(object):
|
||||
values['cidr'] = '0.0.0.0/0'
|
||||
|
||||
if ip_protocol and from_port and to_port:
|
||||
from_port = int(from_port)
|
||||
to_port = int(to_port)
|
||||
from_port = int(from_port)
|
||||
to_port = int(to_port)
|
||||
ip_protocol = str(ip_protocol)
|
||||
|
||||
if ip_protocol.upper() not in ['TCP','UDP','ICMP']:
|
||||
raise InvalidInputException('%s is not a valid ipProtocol' %
|
||||
(ip_protocol,))
|
||||
if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
|
||||
raise InvalidInputException('%s is not a valid ipProtocol' %
|
||||
(ip_protocol,))
|
||||
if ((min(from_port, to_port) < -1) or
|
||||
(max(from_port, to_port) > 65535)):
|
||||
raise InvalidInputException('Invalid port range')
|
||||
raise InvalidInputException('Invalid port range')
|
||||
|
||||
values['protocol'] = ip_protocol
|
||||
values['from_port'] = from_port
|
||||
@@ -343,7 +336,6 @@ class CloudController(object):
|
||||
|
||||
return values
|
||||
|
||||
|
||||
def _security_group_rule_exists(self, security_group, values):
|
||||
"""Indicates whether the specified rule values are already
|
||||
defined in the given security group.
|
||||
@@ -362,20 +354,19 @@ class CloudController(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def revoke_security_group_ingress(self, context, group_name, **kwargs):
|
||||
self._ensure_default_security_group(context)
|
||||
security_group = db.security_group_get_by_name(context,
|
||||
context.project_id,
|
||||
group_name)
|
||||
|
||||
criteria = self._authorize_revoke_rule_args_to_dict(context, **kwargs)
|
||||
criteria = self._revoke_rule_args_to_dict(context, **kwargs)
|
||||
if criteria == None:
|
||||
raise exception.ApiError("No rule for the specified parameters.")
|
||||
|
||||
for rule in security_group.rules:
|
||||
match = True
|
||||
for (k,v) in criteria.iteritems():
|
||||
for (k, v) in criteria.iteritems():
|
||||
if getattr(rule, k, False) != v:
|
||||
match = False
|
||||
if match:
|
||||
@@ -394,7 +385,7 @@ class CloudController(object):
|
||||
context.project_id,
|
||||
group_name)
|
||||
|
||||
values = self._authorize_revoke_rule_args_to_dict(context, **kwargs)
|
||||
values = self._revoke_rule_args_to_dict(context, **kwargs)
|
||||
values['parent_group_id'] = security_group.id
|
||||
|
||||
if self._security_group_rule_exists(security_group, values):
|
||||
@@ -407,7 +398,6 @@ class CloudController(object):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _get_source_project_id(self, context, source_security_group_owner_id):
|
||||
if source_security_group_owner_id:
|
||||
# Parse user:project for source group.
|
||||
@@ -425,13 +415,12 @@ class CloudController(object):
|
||||
|
||||
return source_project_id
|
||||
|
||||
|
||||
def create_security_group(self, context, group_name, group_description):
|
||||
self._ensure_default_security_group(context)
|
||||
if db.security_group_exists(context, context.project_id, group_name):
|
||||
raise exception.ApiError('group %s already exists' % group_name)
|
||||
|
||||
group = {'user_id' : context.user.id,
|
||||
group = {'user_id': context.user.id,
|
||||
'project_id': context.project_id,
|
||||
'name': group_name,
|
||||
'description': group_description}
|
||||
@@ -440,7 +429,6 @@ class CloudController(object):
|
||||
return {'securityGroupSet': [self._format_security_group(context,
|
||||
group_ref)]}
|
||||
|
||||
|
||||
def delete_security_group(self, context, group_name, **kwargs):
|
||||
security_group = db.security_group_get_by_name(context,
|
||||
context.project_id,
|
||||
@@ -448,7 +436,6 @@ class CloudController(object):
|
||||
db.security_group_destroy(context, security_group.id)
|
||||
return True
|
||||
|
||||
|
||||
def get_console_output(self, context, instance_id, **kwargs):
|
||||
# instance_id is passed in as a list of instances
|
||||
ec2_id = instance_id[0]
|
||||
@@ -457,13 +444,13 @@ class CloudController(object):
|
||||
output = rpc.call(context,
|
||||
'%s.%s' % (FLAGS.compute_topic,
|
||||
instance_ref['host']),
|
||||
{"method" : "get_console_output",
|
||||
"args" : {"instance_id": instance_ref['id']}})
|
||||
{"method": "get_console_output",
|
||||
"args": {"instance_id": instance_ref['id']}})
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
return { "InstanceId" : ec2_id,
|
||||
"Timestamp" : now,
|
||||
"output" : base64.b64encode(output) }
|
||||
return {"InstanceId": ec2_id,
|
||||
"Timestamp": now,
|
||||
"output": base64.b64encode(output)}
|
||||
|
||||
def describe_volumes(self, context, **kwargs):
|
||||
if context.user.is_admin():
|
||||
@@ -530,7 +517,6 @@ class CloudController(object):
|
||||
|
||||
return {'volumeSet': [self._format_volume(context, volume_ref)]}
|
||||
|
||||
|
||||
def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
|
||||
volume_ref = db.volume_get_by_ec2_id(context, volume_id)
|
||||
# TODO(vish): abstract status checking?
|
||||
@@ -633,8 +619,7 @@ class CloudController(object):
|
||||
i['imageId'] = instance['image_id']
|
||||
i['instanceState'] = {
|
||||
'code': instance['state'],
|
||||
'name': instance['state_description']
|
||||
}
|
||||
'name': instance['state_description']}
|
||||
fixed_addr = None
|
||||
floating_addr = None
|
||||
if instance['fixed_ip']:
|
||||
@@ -656,7 +641,7 @@ class CloudController(object):
|
||||
i['amiLaunchIndex'] = instance['launch_index']
|
||||
i['displayName'] = instance['display_name']
|
||||
i['displayDescription'] = instance['display_description']
|
||||
if not reservations.has_key(instance['reservation_id']):
|
||||
if instance['reservation_id'] not in reservations:
|
||||
r = {}
|
||||
r['reservationId'] = instance['reservation_id']
|
||||
r['ownerId'] = instance['project_id']
|
||||
@@ -757,10 +742,10 @@ class CloudController(object):
|
||||
context.project_id,
|
||||
'default')
|
||||
except exception.NotFound:
|
||||
values = { 'name' : 'default',
|
||||
'description' : 'default',
|
||||
'user_id' : context.user.id,
|
||||
'project_id' : context.project_id }
|
||||
values = {'name': 'default',
|
||||
'description': 'default',
|
||||
'user_id': context.user.id,
|
||||
'project_id': context.project_id}
|
||||
group = db.security_group_create(context, values)
|
||||
|
||||
def run_instances(self, context, **kwargs):
|
||||
@@ -804,7 +789,7 @@ class CloudController(object):
|
||||
logging.debug("Going to run %s instances...", num_instances)
|
||||
launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
|
||||
key_data = None
|
||||
if kwargs.has_key('key_name'):
|
||||
if 'key_name' in kwargs:
|
||||
key_pair_ref = db.key_pair_get(context,
|
||||
context.user.id,
|
||||
kwargs['key_name'])
|
||||
@@ -883,7 +868,6 @@ class CloudController(object):
|
||||
(context.project.name, context.user.name, inst_id))
|
||||
return self._format_run_instances(context, reservation_id)
|
||||
|
||||
|
||||
def terminate_instances(self, context, instance_id, **kwargs):
|
||||
"""Terminate each instance in instance_id, which is a list of ec2 ids.
|
||||
|
||||
@@ -991,7 +975,7 @@ class CloudController(object):
|
||||
|
||||
def register_image(self, context, image_location=None, **kwargs):
|
||||
# FIXME: should the objectstore be doing these authorization checks?
|
||||
if image_location is None and kwargs.has_key('name'):
|
||||
if image_location is None and 'name' in kwargs:
|
||||
image_location = kwargs['name']
|
||||
image_id = images.register(context, image_location)
|
||||
logging.debug("Registered %s as %s" % (image_location, image_id))
|
||||
@@ -1009,7 +993,8 @@ class CloudController(object):
|
||||
result['launchPermission'].append({'group': 'all'})
|
||||
return result
|
||||
|
||||
def modify_image_attribute(self, context, image_id, attribute, operation_type, **kwargs):
|
||||
def modify_image_attribute(self, context, image_id, attribute,
|
||||
operation_type, **kwargs):
|
||||
# TODO(devcamcar): Support users and groups other than 'all'.
|
||||
if attribute != 'launchPermission':
|
||||
raise exception.ApiError('attribute not supported: %s' % attribute)
|
||||
|
@@ -43,6 +43,7 @@ def modify(context, image_id, operation):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def update(context, image_id, attributes):
|
||||
"""update an image's attributes / info.json"""
|
||||
attributes.update({"image_id": image_id})
|
||||
@@ -52,6 +53,7 @@ def update(context, image_id, attributes):
|
||||
query_args=qs(attributes))
|
||||
return True
|
||||
|
||||
|
||||
def register(context, image_location):
|
||||
""" rpc call to register a new image based from a manifest """
|
||||
|
||||
@@ -64,13 +66,14 @@ def register(context, image_location):
|
||||
|
||||
return image_id
|
||||
|
||||
|
||||
def list(context, filter_list=[]):
|
||||
""" return a list of all images that a user can see
|
||||
|
||||
optionally filtered by a list of image_id """
|
||||
|
||||
if FLAGS.connection_type == 'fake':
|
||||
return [{ 'imageId' : 'bar'}]
|
||||
return [{'imageId': 'bar'}]
|
||||
|
||||
# FIXME: send along the list of only_images to check for
|
||||
response = conn(context).make_request(
|
||||
@@ -82,6 +85,7 @@ def list(context, filter_list=[]):
|
||||
return [i for i in result if i['imageId'] in filter_list]
|
||||
return result
|
||||
|
||||
|
||||
def get(context, image_id):
|
||||
"""return a image object if the context has permissions"""
|
||||
result = list(context, [image_id])
|
||||
|
@@ -27,7 +27,6 @@ from nova.api.ec2 import cloud
|
||||
|
||||
|
||||
class MetadataRequestHandler(object):
|
||||
|
||||
"""Serve metadata from the EC2 API."""
|
||||
|
||||
def print_data(self, data):
|
||||
@@ -43,7 +42,8 @@ class MetadataRequestHandler(object):
|
||||
else:
|
||||
output += '/'
|
||||
output += '\n'
|
||||
return output[:-1] # cut off last \n
|
||||
# Cut off last \n
|
||||
return output[:-1]
|
||||
elif isinstance(data, list):
|
||||
return '\n'.join(data)
|
||||
else:
|
||||
@@ -65,7 +65,8 @@ class MetadataRequestHandler(object):
|
||||
cc = cloud.CloudController()
|
||||
meta_data = cc.get_metadata(req.remote_addr)
|
||||
if meta_data is None:
|
||||
logging.error('Failed to get metadata for ip: %s' % req.remote_addr)
|
||||
logging.error('Failed to get metadata for ip: %s' %
|
||||
req.remote_addr)
|
||||
raise webob.exc.HTTPNotFound()
|
||||
data = self.lookup(req.path_info, meta_data)
|
||||
if data is None:
|
||||
|
@@ -43,9 +43,10 @@ from nova.auth import manager
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DEFINE_string('nova_api_auth',
|
||||
'nova.api.openstack.auth.BasicApiAuthManager',
|
||||
'nova.api.openstack.auth.BasicApiAuthManager',
|
||||
'The auth mechanism to use for the OpenStack API implemenation')
|
||||
|
||||
|
||||
class API(wsgi.Middleware):
|
||||
"""WSGI entry point for all OpenStack API requests."""
|
||||
|
||||
@@ -53,6 +54,7 @@ class API(wsgi.Middleware):
|
||||
app = AuthMiddleware(RateLimitingMiddleware(APIRouter()))
|
||||
super(API, self).__init__(app)
|
||||
|
||||
|
||||
class AuthMiddleware(wsgi.Middleware):
|
||||
"""Authorize the openstack API request or return an HTTP Forbidden."""
|
||||
|
||||
@@ -62,7 +64,7 @@ class AuthMiddleware(wsgi.Middleware):
|
||||
|
||||
@webob.dec.wsgify
|
||||
def __call__(self, req):
|
||||
if not req.headers.has_key("X-Auth-Token"):
|
||||
if 'X-Auth-Token' not in req.headers:
|
||||
return self.auth_driver.authenticate(req)
|
||||
|
||||
user = self.auth_driver.authorize_token(req.headers["X-Auth-Token"])
|
||||
@@ -70,11 +72,12 @@ class AuthMiddleware(wsgi.Middleware):
|
||||
if not user:
|
||||
return faults.Fault(webob.exc.HTTPUnauthorized())
|
||||
|
||||
if not req.environ.has_key('nova.context'):
|
||||
if 'nova.context' not in req.environ:
|
||||
req.environ['nova.context'] = {}
|
||||
req.environ['nova.context']['user'] = user
|
||||
return self.application
|
||||
|
||||
|
||||
class RateLimitingMiddleware(wsgi.Middleware):
|
||||
"""Rate limit incoming requests according to the OpenStack rate limits."""
|
||||
|
||||
@@ -87,7 +90,7 @@ class RateLimitingMiddleware(wsgi.Middleware):
|
||||
"""
|
||||
super(RateLimitingMiddleware, self).__init__(application)
|
||||
if not service_host:
|
||||
#TODO(gundlach): These limits were based on limitations of Cloud
|
||||
#TODO(gundlach): These limits were based on limitations of Cloud
|
||||
#Servers. We should revisit them in Nova.
|
||||
self.limiter = ratelimiting.Limiter(limits={
|
||||
'DELETE': (100, ratelimiting.PER_MINUTE),
|
||||
@@ -102,13 +105,14 @@ class RateLimitingMiddleware(wsgi.Middleware):
|
||||
@webob.dec.wsgify
|
||||
def __call__(self, req):
|
||||
"""Rate limit the request.
|
||||
|
||||
If the request should be rate limited, return a 413 status with a
|
||||
|
||||
If the request should be rate limited, return a 413 status with a
|
||||
Retry-After header giving the time when the request would succeed.
|
||||
"""
|
||||
user_id = req.environ['nova.context']['user']['id']
|
||||
action_name = self.get_action_name(req)
|
||||
if not action_name: # not rate limited
|
||||
if not action_name:
|
||||
# Not rate limited
|
||||
return self.application
|
||||
delay = self.get_delay(action_name, user_id)
|
||||
if delay:
|
||||
@@ -152,13 +156,13 @@ class APIRouter(wsgi.Router):
|
||||
def __init__(self):
|
||||
mapper = routes.Mapper()
|
||||
mapper.resource("server", "servers", controller=servers.Controller(),
|
||||
collection={ 'detail': 'GET'},
|
||||
member={'action':'POST'})
|
||||
collection={'detail': 'GET'},
|
||||
member={'action': 'POST'})
|
||||
|
||||
mapper.resource("backup_schedule", "backup_schedules",
|
||||
mapper.resource("backup_schedule", "backup_schedules",
|
||||
controller=backup_schedules.Controller(),
|
||||
parent_resource=dict(member_name='server',
|
||||
collection_name = 'servers'))
|
||||
parent_resource=dict(member_name='server',
|
||||
collection_name='servers'))
|
||||
|
||||
mapper.resource("image", "images", controller=images.Controller(),
|
||||
collection={'detail': 'GET'})
|
||||
@@ -172,7 +176,7 @@ class APIRouter(wsgi.Router):
|
||||
|
||||
def limited(items, req):
|
||||
"""Return a slice of items according to requested offset and limit.
|
||||
|
||||
|
||||
items - a sliceable
|
||||
req - wobob.Request possibly containing offset and limit GET variables.
|
||||
offset is where to start in the list, and limit is the maximum number
|
||||
@@ -187,4 +191,3 @@ def limited(items, req):
|
||||
limit = min(1000, limit)
|
||||
range_end = offset + limit
|
||||
return items[offset:range_end]
|
||||
|
||||
|
@@ -15,9 +15,11 @@ from nova.api.openstack import faults
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
class Context(object):
|
||||
pass
|
||||
|
||||
|
||||
class BasicApiAuthManager(object):
|
||||
""" Implements a somewhat rudimentary version of OpenStack Auth"""
|
||||
|
||||
@@ -61,7 +63,7 @@ class BasicApiAuthManager(object):
|
||||
|
||||
def authorize_token(self, token_hash):
|
||||
""" retrieves user information from the datastore given a token
|
||||
|
||||
|
||||
If the token has expired, returns None
|
||||
If the token is not found, returns None
|
||||
Otherwise returns dict(id=(the authorized user's id))
|
||||
@@ -69,7 +71,7 @@ class BasicApiAuthManager(object):
|
||||
This method will also remove the token if the timestamp is older than
|
||||
2 days ago.
|
||||
"""
|
||||
token = self.db.auth_get_token(self.context, token_hash)
|
||||
token = self.db.auth_get_token(self.context, token_hash)
|
||||
if token:
|
||||
delta = datetime.datetime.now() - token.created_at
|
||||
if delta.days >= 2:
|
||||
@@ -94,8 +96,7 @@ class BasicApiAuthManager(object):
|
||||
token_dict['user_id'] = user.id
|
||||
token = self.db.auth_create_token(self.context, token_dict)
|
||||
return token, user
|
||||
return None, None
|
||||
return None, None
|
||||
|
||||
def _get_server_mgmt_url(self):
|
||||
return 'https://%s/v1.0/' % self.host
|
||||
|
||||
|
@@ -22,6 +22,7 @@ from nova import wsgi
|
||||
from nova.api.openstack import faults
|
||||
import nova.image.service
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
@@ -55,7 +55,7 @@ class Fault(webob.exc.HTTPException):
|
||||
if code == 413:
|
||||
retry = self.wrapped_exc.headers['Retry-After']
|
||||
fault_data[fault_name]['retryAfter'] = retry
|
||||
# 'code' is an attribute on the fault tag itself
|
||||
# 'code' is an attribute on the fault tag itself
|
||||
metadata = {'application/xml': {'attributes': {fault_name: 'code'}}}
|
||||
serializer = wsgi.Serializer(req.environ, metadata)
|
||||
self.wrapped_exc.body = serializer.to_content_type(fault_data)
|
||||
|
@@ -22,16 +22,14 @@ from nova.compute import instance_types
|
||||
from nova import wsgi
|
||||
import nova.api.openstack
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
"""Flavor controller for the OpenStack API."""
|
||||
|
||||
_serialization_metadata = {
|
||||
'application/xml': {
|
||||
"attributes": {
|
||||
"flavor": [ "id", "name", "ram", "disk" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
"flavor": ["id", "name", "ram", "disk"]}}}
|
||||
|
||||
def index(self, req):
|
||||
"""Return all flavors in brief."""
|
||||
|
@@ -27,16 +27,14 @@ from nova.api.openstack import faults
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
|
||||
_serialization_metadata = {
|
||||
'application/xml': {
|
||||
"attributes": {
|
||||
"image": [ "id", "name", "updated", "created", "status",
|
||||
"serverId", "progress" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
"image": ["id", "name", "updated", "created", "status",
|
||||
"serverId", "progress"]}}}
|
||||
|
||||
def __init__(self):
|
||||
self._service = utils.import_object(FLAGS.image_service)
|
||||
@@ -72,6 +70,6 @@ class Controller(wsgi.Controller):
|
||||
raise faults.Fault(exc.HTTPNotFound())
|
||||
|
||||
def update(self, req, id):
|
||||
# Users may not modify public images, and that's all that
|
||||
# Users may not modify public images, and that's all that
|
||||
# we support for now.
|
||||
raise faults.Fault(exc.HTTPNotFound())
|
||||
|
@@ -13,6 +13,7 @@ PER_MINUTE = 60
|
||||
PER_HOUR = 60 * 60
|
||||
PER_DAY = 60 * 60 * 24
|
||||
|
||||
|
||||
class Limiter(object):
|
||||
|
||||
"""Class providing rate limiting of arbitrary actions."""
|
||||
@@ -101,7 +102,8 @@ class WSGIApp(object):
|
||||
return webob.exc.HTTPForbidden(
|
||||
headers={'X-Wait-Seconds': "%.2f" % delay})
|
||||
else:
|
||||
return '' # 200 OK
|
||||
# 200 OK
|
||||
return ''
|
||||
|
||||
|
||||
class WSGIAppProxy(object):
|
||||
@@ -109,7 +111,7 @@ class WSGIAppProxy(object):
|
||||
"""Limiter lookalike that proxies to a ratelimiting.WSGIApp."""
|
||||
|
||||
def __init__(self, service_host):
|
||||
"""Creates a proxy pointing to a ratelimiting.WSGIApp at the given
|
||||
"""Creates a proxy pointing to a ratelimiting.WSGIApp at the given
|
||||
host."""
|
||||
self.service_host = service_host
|
||||
|
||||
@@ -118,5 +120,6 @@ class WSGIAppProxy(object):
|
||||
conn.request('POST', '/limiter/%s/%s' % (username, action))
|
||||
resp = conn.getresponse()
|
||||
if resp.status == 200:
|
||||
return None # no delay
|
||||
# No delay
|
||||
return None
|
||||
return float(resp.getheader('X-Wait-Seconds'))
|
||||
|
@@ -34,30 +34,32 @@ import nova.image.service
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
|
||||
def _filter_params(inst_dict):
|
||||
""" Extracts all updatable parameters for a server update request """
|
||||
keys = dict(name='name', admin_pass='adminPass')
|
||||
new_attrs = {}
|
||||
for k, v in keys.items():
|
||||
if inst_dict.has_key(v):
|
||||
if v in inst_dict:
|
||||
new_attrs[k] = inst_dict[v]
|
||||
return new_attrs
|
||||
|
||||
|
||||
def _entity_list(entities):
|
||||
""" Coerces a list of servers into proper dictionary format """
|
||||
return dict(servers=entities)
|
||||
|
||||
|
||||
def _entity_detail(inst):
|
||||
""" Maps everything to Rackspace-like attributes for return"""
|
||||
power_mapping = {
|
||||
power_state.NOSTATE: 'build',
|
||||
power_state.RUNNING: 'active',
|
||||
power_state.BLOCKED: 'active',
|
||||
power_state.PAUSED: 'suspended',
|
||||
power_state.NOSTATE: 'build',
|
||||
power_state.RUNNING: 'active',
|
||||
power_state.BLOCKED: 'active',
|
||||
power_state.PAUSED: 'suspended',
|
||||
power_state.SHUTDOWN: 'active',
|
||||
power_state.SHUTOFF: 'active',
|
||||
power_state.CRASHED: 'error'
|
||||
}
|
||||
power_state.SHUTOFF: 'active',
|
||||
power_state.CRASHED: 'error'}
|
||||
inst_dict = {}
|
||||
|
||||
mapped_keys = dict(status='state', imageId='image_id',
|
||||
@@ -73,21 +75,20 @@ def _entity_detail(inst):
|
||||
|
||||
return dict(server=inst_dict)
|
||||
|
||||
|
||||
def _entity_inst(inst):
|
||||
""" Filters all model attributes save for id and name """
|
||||
return dict(server=dict(id=inst['id'], name=inst['server_name']))
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
""" The Server API controller for the OpenStack API """
|
||||
|
||||
_serialization_metadata = {
|
||||
'application/xml': {
|
||||
"attributes": {
|
||||
"server": [ "id", "imageId", "name", "flavorId", "hostId",
|
||||
"status", "progress", "progress" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
"server": ["id", "imageId", "name", "flavorId", "hostId",
|
||||
"status", "progress", "progress"]}}}
|
||||
|
||||
def __init__(self, db_driver=None):
|
||||
if not db_driver:
|
||||
@@ -209,7 +210,7 @@ class Controller(wsgi.Controller):
|
||||
image = img_service.show(image_id)
|
||||
|
||||
if not image:
|
||||
raise Exception, "Image not found"
|
||||
raise Exception("Image not found")
|
||||
|
||||
inst['server_name'] = env['server']['name']
|
||||
inst['image_id'] = image_id
|
||||
|
@@ -17,4 +17,6 @@
|
||||
|
||||
from nova import wsgi
|
||||
|
||||
class Controller(wsgi.Controller): pass
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
pass
|
||||
|
Reference in New Issue
Block a user