PEP8 cleanup in nova/api. There should be no functional changes here, just style changes to get violations down.

This commit is contained in:
Eric Day
2010-10-21 15:26:06 -07:00
parent e012a2b737
commit 777b14c27b
16 changed files with 135 additions and 133 deletions

View File

@@ -31,12 +31,13 @@ from nova.api import openstack
from nova.api.ec2 import metadatarequesthandler from nova.api.ec2 import metadatarequesthandler
flags.DEFINE_string('osapi_subdomain', 'api', flags.DEFINE_string('osapi_subdomain', 'api',
'subdomain running the OpenStack API') 'subdomain running the OpenStack API')
flags.DEFINE_string('ec2api_subdomain', 'ec2', flags.DEFINE_string('ec2api_subdomain', 'ec2',
'subdomain running the EC2 API') 'subdomain running the EC2 API')
flags.DEFINE_string('FAKE_subdomain', None, flags.DEFINE_string('FAKE_subdomain', None,
'set to api or ec2 to fake the subdomain of the host for testing') 'set to api or ec2 to fake the subdomain of the host '
'for testing')
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@@ -44,7 +45,7 @@ class API(wsgi.Router):
"""Routes top-level requests to the appropriate controller.""" """Routes top-level requests to the appropriate controller."""
def __init__(self): def __init__(self):
osapidomain = {'sub_domain': [FLAGS.osapi_subdomain]} osapidomain = {'sub_domain': [FLAGS.osapi_subdomain]}
ec2domain = {'sub_domain': [FLAGS.ec2api_subdomain]} ec2domain = {'sub_domain': [FLAGS.ec2api_subdomain]}
# If someone wants to pretend they're hitting the OSAPI subdomain # If someone wants to pretend they're hitting the OSAPI subdomain
# on their local box, they can set FAKE_subdomain to 'api', which # on their local box, they can set FAKE_subdomain to 'api', which
@@ -55,7 +56,7 @@ class API(wsgi.Router):
ec2domain = {} ec2domain = {}
mapper = routes.Mapper() mapper = routes.Mapper()
mapper.sub_domains = True mapper.sub_domains = True
mapper.connect("/", controller=self.osapi_versions, mapper.connect("/", controller=self.osapi_versions,
conditions=osapidomain) conditions=osapidomain)
mapper.connect("/v1.0/{path_info:.*}", controller=openstack.API(), mapper.connect("/v1.0/{path_info:.*}", controller=openstack.API(),
conditions=osapidomain) conditions=osapidomain)
@@ -107,5 +108,3 @@ class API(wsgi.Router):
'2009-04-04', '2009-04-04',
] ]
return ''.join('%s\n' % v for v in versions) return ''.join('%s\n' % v for v in versions)

View File

@@ -62,7 +62,8 @@ class Authenticate(wsgi.Middleware):
# Make a copy of args for authentication and signature verification. # Make a copy of args for authentication and signature verification.
auth_params = dict(req.params) 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. # Authenticate the request.
try: try:
@@ -109,9 +110,11 @@ class Router(wsgi.Middleware):
'SignatureVersion', 'Version', 'Timestamp'] 'SignatureVersion', 'Version', 'Timestamp']
args = dict(req.params) args = dict(req.params)
try: try:
action = req.params['Action'] # raise KeyError if omitted # Raise KeyError if omitted
action = req.params['Action']
for non_arg in non_args: 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: except:
raise webob.exc.HTTPBadRequest() raise webob.exc.HTTPBadRequest()
@@ -184,7 +187,8 @@ class Authorizer(wsgi.Middleware):
context = req.environ['ec2.context'] context = req.environ['ec2.context']
controller_name = req.environ['ec2.controller'].__class__.__name__ controller_name = req.environ['ec2.controller'].__class__.__name__
action = req.environ['ec2.action'] 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): if self._matches_any_role(context, allowed_roles):
return self.application return self.application
else: else:
@@ -242,4 +246,3 @@ class Executor(wsgi.Application):
'<Message>%s</Message></Error></Errors>' '<Message>%s</Message></Error></Errors>'
'<RequestID>?</RequestID></Response>') % (code, message) '<RequestID>?</RequestID></Response>') % (code, message)
return resp return resp

View File

@@ -73,7 +73,7 @@ class AdminController(object):
def describe_users(self, _context, **_kwargs): def describe_users(self, _context, **_kwargs):
"""Returns all users - should be changed to deal with a list.""" """Returns all users - should be changed to deal with a list."""
return {'userSet': 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): def register_user(self, _context, name, **_kwargs):
"""Creates a new user, and returns generated credentials.""" """Creates a new user, and returns generated credentials."""
@@ -91,7 +91,7 @@ class AdminController(object):
def describe_roles(self, context, project_roles=True, **kwargs): def describe_roles(self, context, project_roles=True, **kwargs):
"""Returns a list of allowed roles.""" """Returns a list of allowed roles."""
roles = manager.AuthManager().get_roles(project_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): def describe_user_roles(self, context, user, project=None, **kwargs):
"""Returns a list of roles for the given user. """Returns a list of roles for the given user.
@@ -99,7 +99,7 @@ class AdminController(object):
Specifying project will return only project specific roles. Specifying project will return only project specific roles.
""" """
roles = manager.AuthManager().get_user_roles(user, project=project) 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, def modify_user_role(self, context, user, role, project=None,
operation='add', **kwargs): operation='add', **kwargs):
@@ -155,9 +155,10 @@ class AdminController(object):
'members': [{'member': m} for m in project.member_ids]} 'members': [{'member': m} for m in project.member_ids]}
return result 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.""" """Add or remove a user from a project."""
if operation =='add': if operation == 'add':
manager.AuthManager().add_to_project(user, project) manager.AuthManager().add_to_project(user, project)
elif operation == 'remove': elif operation == 'remove':
manager.AuthManager().remove_from_project(user, project) manager.AuthManager().remove_from_project(user, project)

View File

@@ -44,6 +44,7 @@ def _underscore_to_xmlcase(str):
res = _underscore_to_camelcase(str) res = _underscore_to_camelcase(str)
return res[:1].lower() + res[1:] return res[:1].lower() + res[1:]
def _try_convert(value): def _try_convert(value):
"""Return a non-string if possible""" """Return a non-string if possible"""
if value == 'None': if value == 'None':
@@ -59,12 +60,12 @@ def _try_convert(value):
return value return value
if valueneg[0] == '0': if valueneg[0] == '0':
if valueneg[1] in 'xX': if valueneg[1] in 'xX':
return int(value,16) return int(value, 16)
elif valueneg[1] in 'bB': elif valueneg[1] in 'bB':
return int(value,2) return int(value, 2)
else: else:
try: try:
return int(value,8) return int(value, 8)
except ValueError: except ValueError:
pass pass
try: try:
@@ -80,6 +81,7 @@ def _try_convert(value):
except ValueError: except ValueError:
return value return value
class APIRequest(object): class APIRequest(object):
def __init__(self, controller, action): def __init__(self, controller, action):
self.controller = controller self.controller = controller

View File

@@ -48,6 +48,7 @@ flags.DECLARE('storage_availability_zone', 'nova.volume.manager')
InvalidInputException = exception.InvalidInputException InvalidInputException = exception.InvalidInputException
class QuotaError(exception.ApiError): class QuotaError(exception.ApiError):
"""Quota Exceeeded""" """Quota Exceeeded"""
pass pass
@@ -137,8 +138,8 @@ class CloudController(object):
for node in nodes: for node in nodes:
rpc.cast(context, rpc.cast(context,
'%s.%s' % (FLAGS.compute_topic, node), '%s.%s' % (FLAGS.compute_topic, node),
{ "method": "refresh_security_group", {"method": "refresh_security_group",
"args": {"security_group_id": security_group.id}}) "args": {"security_group_id": security_group.id}})
def get_metadata(self, address): def get_metadata(self, address):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
@@ -147,48 +148,42 @@ class CloudController(object):
return None return None
mpi = self._get_mpi_data(ctxt, instance_ref['project_id']) mpi = self._get_mpi_data(ctxt, instance_ref['project_id'])
if instance_ref['key_name']: if instance_ref['key_name']:
keys = { keys = {'0': {'_name': instance_ref['key_name'],
'0': { 'openssh-key': instance_ref['key_data']}}
'_name': instance_ref['key_name'],
'openssh-key': instance_ref['key_data']
}
}
else: else:
keys = '' keys = ''
hostname = instance_ref['hostname'] hostname = instance_ref['hostname']
floating_ip = db.instance_get_floating_address(ctxt, floating_ip = db.instance_get_floating_address(ctxt,
instance_ref['id']) instance_ref['id'])
ec2_id = internal_id_to_ec2_id(instance_ref['internal_id'])
data = { data = {
'user-data': base64.b64decode(instance_ref['user_data']), 'user-data': base64.b64decode(instance_ref['user_data']),
'meta-data': { 'meta-data': {
'ami-id': instance_ref['image_id'], 'ami-id': instance_ref['image_id'],
'ami-launch-index': instance_ref['launch_index'], 'ami-launch-index': instance_ref['launch_index'],
'ami-manifest-path': 'FIXME', 'ami-manifest-path': 'FIXME',
'block-device-mapping': { # TODO(vish): replace with real data 'block-device-mapping': {
# TODO(vish): replace with real data
'ami': 'sda1', 'ami': 'sda1',
'ephemeral0': 'sda2', 'ephemeral0': 'sda2',
'root': '/dev/sda1', 'root': '/dev/sda1',
'swap': 'sda3' 'swap': 'sda3'},
},
'hostname': hostname, 'hostname': hostname,
'instance-action': 'none', 'instance-action': 'none',
'instance-id': internal_id_to_ec2_id(instance_ref['internal_id']), 'instance-id': ec2_id,
'instance-type': instance_ref['instance_type'], 'instance-type': instance_ref['instance_type'],
'local-hostname': hostname, 'local-hostname': hostname,
'local-ipv4': address, 'local-ipv4': address,
'kernel-id': instance_ref['kernel_id'], 'kernel-id': instance_ref['kernel_id'],
'placement': { # TODO(vish): real zone
'availability-zone': 'nova' # TODO(vish): real zone 'placement': {'availability-zone': 'nova'},
},
'public-hostname': hostname, 'public-hostname': hostname,
'public-ipv4': floating_ip or '', 'public-ipv4': floating_ip or '',
'public-keys': keys, 'public-keys': keys,
'ramdisk-id': instance_ref['ramdisk_id'], 'ramdisk-id': instance_ref['ramdisk_id'],
'reservation-id': instance_ref['reservation_id'], 'reservation-id': instance_ref['reservation_id'],
'security-groups': '', 'security-groups': '',
'mpi': mpi 'mpi': mpi}}
}
}
if False: # TODO(vish): store ancestor ids if False: # TODO(vish): store ancestor ids
data['ancestor-ami-ids'] = [] data['ancestor-ami-ids'] = []
if False: # TODO(vish): store product codes if False: # TODO(vish): store product codes
@@ -211,7 +206,7 @@ class CloudController(object):
'regionEndpoint': FLAGS.ec2_url}] 'regionEndpoint': FLAGS.ec2_url}]
if region_name: if region_name:
regions = [r for r in regions if r['regionName'] in region_name] regions = [r for r in regions if r['regionName'] in region_name]
return {'regionInfo': regions } return {'regionInfo': regions}
def describe_snapshots(self, def describe_snapshots(self,
context, context,
@@ -237,7 +232,8 @@ class CloudController(object):
for key_pair in key_pairs: for key_pair in key_pairs:
# filter out the vpn keys # filter out the vpn keys
suffix = FLAGS.vpn_key_suffix 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({ result.append({
'keyName': key_pair['name'], 'keyName': key_pair['name'],
'keyFingerprint': key_pair['fingerprint'], 'keyFingerprint': key_pair['fingerprint'],
@@ -271,7 +267,7 @@ class CloudController(object):
if not group_name is None: if not group_name is None:
groups = [g for g in groups if g.name in group_name] 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): def _format_security_group(self, context, group):
g = {} g = {}
@@ -295,13 +291,10 @@ class CloudController(object):
g['ipPermissions'] += [r] g['ipPermissions'] += [r]
return g return g
def _revoke_rule_args_to_dict(self, context, to_port=None, from_port=None,
def _authorize_revoke_rule_args_to_dict(self, context, ip_protocol=None, cidr_ip=None, user_id=None,
to_port=None, from_port=None, source_security_group_name=None,
ip_protocol=None, cidr_ip=None, source_security_group_owner_id=None):
user_id=None,
source_security_group_name=None,
source_security_group_owner_id=None):
values = {} values = {}
@@ -322,16 +315,16 @@ class CloudController(object):
values['cidr'] = '0.0.0.0/0' values['cidr'] = '0.0.0.0/0'
if ip_protocol and from_port and to_port: if ip_protocol and from_port and to_port:
from_port = int(from_port) from_port = int(from_port)
to_port = int(to_port) to_port = int(to_port)
ip_protocol = str(ip_protocol) ip_protocol = str(ip_protocol)
if ip_protocol.upper() not in ['TCP','UDP','ICMP']: if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
raise InvalidInputException('%s is not a valid ipProtocol' % raise InvalidInputException('%s is not a valid ipProtocol' %
(ip_protocol,)) (ip_protocol,))
if ((min(from_port, to_port) < -1) or if ((min(from_port, to_port) < -1) or
(max(from_port, to_port) > 65535)): (max(from_port, to_port) > 65535)):
raise InvalidInputException('Invalid port range') raise InvalidInputException('Invalid port range')
values['protocol'] = ip_protocol values['protocol'] = ip_protocol
values['from_port'] = from_port values['from_port'] = from_port
@@ -343,7 +336,6 @@ class CloudController(object):
return values return values
def _security_group_rule_exists(self, security_group, values): def _security_group_rule_exists(self, security_group, values):
"""Indicates whether the specified rule values are already """Indicates whether the specified rule values are already
defined in the given security group. defined in the given security group.
@@ -362,20 +354,19 @@ class CloudController(object):
return True return True
return False return False
def revoke_security_group_ingress(self, context, group_name, **kwargs): def revoke_security_group_ingress(self, context, group_name, **kwargs):
self._ensure_default_security_group(context) self._ensure_default_security_group(context)
security_group = db.security_group_get_by_name(context, security_group = db.security_group_get_by_name(context,
context.project_id, context.project_id,
group_name) group_name)
criteria = self._authorize_revoke_rule_args_to_dict(context, **kwargs) criteria = self._revoke_rule_args_to_dict(context, **kwargs)
if criteria == None: if criteria == None:
raise exception.ApiError("No rule for the specified parameters.") raise exception.ApiError("No rule for the specified parameters.")
for rule in security_group.rules: for rule in security_group.rules:
match = True match = True
for (k,v) in criteria.iteritems(): for (k, v) in criteria.iteritems():
if getattr(rule, k, False) != v: if getattr(rule, k, False) != v:
match = False match = False
if match: if match:
@@ -394,7 +385,7 @@ class CloudController(object):
context.project_id, context.project_id,
group_name) 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 values['parent_group_id'] = security_group.id
if self._security_group_rule_exists(security_group, values): if self._security_group_rule_exists(security_group, values):
@@ -407,7 +398,6 @@ class CloudController(object):
return True return True
def _get_source_project_id(self, context, source_security_group_owner_id): def _get_source_project_id(self, context, source_security_group_owner_id):
if source_security_group_owner_id: if source_security_group_owner_id:
# Parse user:project for source group. # Parse user:project for source group.
@@ -425,13 +415,12 @@ class CloudController(object):
return source_project_id return source_project_id
def create_security_group(self, context, group_name, group_description): def create_security_group(self, context, group_name, group_description):
self._ensure_default_security_group(context) self._ensure_default_security_group(context)
if db.security_group_exists(context, context.project_id, group_name): if db.security_group_exists(context, context.project_id, group_name):
raise exception.ApiError('group %s already exists' % 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, 'project_id': context.project_id,
'name': group_name, 'name': group_name,
'description': group_description} 'description': group_description}
@@ -440,7 +429,6 @@ class CloudController(object):
return {'securityGroupSet': [self._format_security_group(context, return {'securityGroupSet': [self._format_security_group(context,
group_ref)]} group_ref)]}
def delete_security_group(self, context, group_name, **kwargs): def delete_security_group(self, context, group_name, **kwargs):
security_group = db.security_group_get_by_name(context, security_group = db.security_group_get_by_name(context,
context.project_id, context.project_id,
@@ -448,7 +436,6 @@ class CloudController(object):
db.security_group_destroy(context, security_group.id) db.security_group_destroy(context, security_group.id)
return True return True
def get_console_output(self, context, instance_id, **kwargs): def get_console_output(self, context, instance_id, **kwargs):
# instance_id is passed in as a list of instances # instance_id is passed in as a list of instances
ec2_id = instance_id[0] ec2_id = instance_id[0]
@@ -457,13 +444,13 @@ class CloudController(object):
output = rpc.call(context, output = rpc.call(context,
'%s.%s' % (FLAGS.compute_topic, '%s.%s' % (FLAGS.compute_topic,
instance_ref['host']), instance_ref['host']),
{"method" : "get_console_output", {"method": "get_console_output",
"args" : {"instance_id": instance_ref['id']}}) "args": {"instance_id": instance_ref['id']}})
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
return { "InstanceId" : ec2_id, return {"InstanceId": ec2_id,
"Timestamp" : now, "Timestamp": now,
"output" : base64.b64encode(output) } "output": base64.b64encode(output)}
def describe_volumes(self, context, **kwargs): def describe_volumes(self, context, **kwargs):
if context.user.is_admin(): if context.user.is_admin():
@@ -530,7 +517,6 @@ class CloudController(object):
return {'volumeSet': [self._format_volume(context, volume_ref)]} return {'volumeSet': [self._format_volume(context, volume_ref)]}
def attach_volume(self, context, volume_id, instance_id, device, **kwargs): def attach_volume(self, context, volume_id, instance_id, device, **kwargs):
volume_ref = db.volume_get_by_ec2_id(context, volume_id) volume_ref = db.volume_get_by_ec2_id(context, volume_id)
# TODO(vish): abstract status checking? # TODO(vish): abstract status checking?
@@ -633,8 +619,7 @@ class CloudController(object):
i['imageId'] = instance['image_id'] i['imageId'] = instance['image_id']
i['instanceState'] = { i['instanceState'] = {
'code': instance['state'], 'code': instance['state'],
'name': instance['state_description'] 'name': instance['state_description']}
}
fixed_addr = None fixed_addr = None
floating_addr = None floating_addr = None
if instance['fixed_ip']: if instance['fixed_ip']:
@@ -656,7 +641,7 @@ class CloudController(object):
i['amiLaunchIndex'] = instance['launch_index'] i['amiLaunchIndex'] = instance['launch_index']
i['displayName'] = instance['display_name'] i['displayName'] = instance['display_name']
i['displayDescription'] = instance['display_description'] i['displayDescription'] = instance['display_description']
if not reservations.has_key(instance['reservation_id']): if instance['reservation_id'] not in reservations:
r = {} r = {}
r['reservationId'] = instance['reservation_id'] r['reservationId'] = instance['reservation_id']
r['ownerId'] = instance['project_id'] r['ownerId'] = instance['project_id']
@@ -757,10 +742,10 @@ class CloudController(object):
context.project_id, context.project_id,
'default') 'default')
except exception.NotFound: except exception.NotFound:
values = { 'name' : 'default', values = {'name': 'default',
'description' : 'default', 'description': 'default',
'user_id' : context.user.id, 'user_id': context.user.id,
'project_id' : context.project_id } 'project_id': context.project_id}
group = db.security_group_create(context, values) group = db.security_group_create(context, values)
def run_instances(self, context, **kwargs): def run_instances(self, context, **kwargs):
@@ -804,7 +789,7 @@ class CloudController(object):
logging.debug("Going to run %s instances...", num_instances) logging.debug("Going to run %s instances...", num_instances)
launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) launch_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
key_data = None key_data = None
if kwargs.has_key('key_name'): if 'key_name' in kwargs:
key_pair_ref = db.key_pair_get(context, key_pair_ref = db.key_pair_get(context,
context.user.id, context.user.id,
kwargs['key_name']) kwargs['key_name'])
@@ -883,7 +868,6 @@ class CloudController(object):
(context.project.name, context.user.name, inst_id)) (context.project.name, context.user.name, inst_id))
return self._format_run_instances(context, reservation_id) return self._format_run_instances(context, reservation_id)
def terminate_instances(self, context, instance_id, **kwargs): def terminate_instances(self, context, instance_id, **kwargs):
"""Terminate each instance in instance_id, which is a list of ec2 ids. """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): def register_image(self, context, image_location=None, **kwargs):
# FIXME: should the objectstore be doing these authorization checks? # 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_location = kwargs['name']
image_id = images.register(context, image_location) image_id = images.register(context, image_location)
logging.debug("Registered %s as %s" % (image_location, image_id)) logging.debug("Registered %s as %s" % (image_location, image_id))
@@ -1009,7 +993,8 @@ class CloudController(object):
result['launchPermission'].append({'group': 'all'}) result['launchPermission'].append({'group': 'all'})
return result 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'. # TODO(devcamcar): Support users and groups other than 'all'.
if attribute != 'launchPermission': if attribute != 'launchPermission':
raise exception.ApiError('attribute not supported: %s' % attribute) raise exception.ApiError('attribute not supported: %s' % attribute)

View File

@@ -43,6 +43,7 @@ def modify(context, image_id, operation):
return True return True
def update(context, image_id, attributes): def update(context, image_id, attributes):
"""update an image's attributes / info.json""" """update an image's attributes / info.json"""
attributes.update({"image_id": image_id}) attributes.update({"image_id": image_id})
@@ -52,6 +53,7 @@ def update(context, image_id, attributes):
query_args=qs(attributes)) query_args=qs(attributes))
return True return True
def register(context, image_location): def register(context, image_location):
""" rpc call to register a new image based from a manifest """ """ rpc call to register a new image based from a manifest """
@@ -64,13 +66,14 @@ def register(context, image_location):
return image_id return image_id
def list(context, filter_list=[]): def list(context, filter_list=[]):
""" return a list of all images that a user can see """ return a list of all images that a user can see
optionally filtered by a list of image_id """ optionally filtered by a list of image_id """
if FLAGS.connection_type == 'fake': if FLAGS.connection_type == 'fake':
return [{ 'imageId' : 'bar'}] return [{'imageId': 'bar'}]
# FIXME: send along the list of only_images to check for # FIXME: send along the list of only_images to check for
response = conn(context).make_request( 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 [i for i in result if i['imageId'] in filter_list]
return result return result
def get(context, image_id): def get(context, image_id):
"""return a image object if the context has permissions""" """return a image object if the context has permissions"""
result = list(context, [image_id]) result = list(context, [image_id])

View File

@@ -27,7 +27,6 @@ from nova.api.ec2 import cloud
class MetadataRequestHandler(object): class MetadataRequestHandler(object):
"""Serve metadata from the EC2 API.""" """Serve metadata from the EC2 API."""
def print_data(self, data): def print_data(self, data):
@@ -43,7 +42,8 @@ class MetadataRequestHandler(object):
else: else:
output += '/' output += '/'
output += '\n' output += '\n'
return output[:-1] # cut off last \n # Cut off last \n
return output[:-1]
elif isinstance(data, list): elif isinstance(data, list):
return '\n'.join(data) return '\n'.join(data)
else: else:
@@ -65,7 +65,8 @@ class MetadataRequestHandler(object):
cc = cloud.CloudController() cc = cloud.CloudController()
meta_data = cc.get_metadata(req.remote_addr) meta_data = cc.get_metadata(req.remote_addr)
if meta_data is None: 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() raise webob.exc.HTTPNotFound()
data = self.lookup(req.path_info, meta_data) data = self.lookup(req.path_info, meta_data)
if data is None: if data is None:

View File

@@ -43,9 +43,10 @@ from nova.auth import manager
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
flags.DEFINE_string('nova_api_auth', 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') 'The auth mechanism to use for the OpenStack API implemenation')
class API(wsgi.Middleware): class API(wsgi.Middleware):
"""WSGI entry point for all OpenStack API requests.""" """WSGI entry point for all OpenStack API requests."""
@@ -53,6 +54,7 @@ class API(wsgi.Middleware):
app = AuthMiddleware(RateLimitingMiddleware(APIRouter())) app = AuthMiddleware(RateLimitingMiddleware(APIRouter()))
super(API, self).__init__(app) super(API, self).__init__(app)
class AuthMiddleware(wsgi.Middleware): class AuthMiddleware(wsgi.Middleware):
"""Authorize the openstack API request or return an HTTP Forbidden.""" """Authorize the openstack API request or return an HTTP Forbidden."""
@@ -62,7 +64,7 @@ class AuthMiddleware(wsgi.Middleware):
@webob.dec.wsgify @webob.dec.wsgify
def __call__(self, req): 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) return self.auth_driver.authenticate(req)
user = self.auth_driver.authorize_token(req.headers["X-Auth-Token"]) user = self.auth_driver.authorize_token(req.headers["X-Auth-Token"])
@@ -70,11 +72,12 @@ class AuthMiddleware(wsgi.Middleware):
if not user: if not user:
return faults.Fault(webob.exc.HTTPUnauthorized()) 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'] = {}
req.environ['nova.context']['user'] = user req.environ['nova.context']['user'] = user
return self.application return self.application
class RateLimitingMiddleware(wsgi.Middleware): class RateLimitingMiddleware(wsgi.Middleware):
"""Rate limit incoming requests according to the OpenStack rate limits.""" """Rate limit incoming requests according to the OpenStack rate limits."""
@@ -87,7 +90,7 @@ class RateLimitingMiddleware(wsgi.Middleware):
""" """
super(RateLimitingMiddleware, self).__init__(application) super(RateLimitingMiddleware, self).__init__(application)
if not service_host: 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. #Servers. We should revisit them in Nova.
self.limiter = ratelimiting.Limiter(limits={ self.limiter = ratelimiting.Limiter(limits={
'DELETE': (100, ratelimiting.PER_MINUTE), 'DELETE': (100, ratelimiting.PER_MINUTE),
@@ -102,13 +105,14 @@ class RateLimitingMiddleware(wsgi.Middleware):
@webob.dec.wsgify @webob.dec.wsgify
def __call__(self, req): def __call__(self, req):
"""Rate limit the request. """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. Retry-After header giving the time when the request would succeed.
""" """
user_id = req.environ['nova.context']['user']['id'] user_id = req.environ['nova.context']['user']['id']
action_name = self.get_action_name(req) action_name = self.get_action_name(req)
if not action_name: # not rate limited if not action_name:
# Not rate limited
return self.application return self.application
delay = self.get_delay(action_name, user_id) delay = self.get_delay(action_name, user_id)
if delay: if delay:
@@ -152,13 +156,13 @@ class APIRouter(wsgi.Router):
def __init__(self): def __init__(self):
mapper = routes.Mapper() mapper = routes.Mapper()
mapper.resource("server", "servers", controller=servers.Controller(), mapper.resource("server", "servers", controller=servers.Controller(),
collection={ 'detail': 'GET'}, collection={'detail': 'GET'},
member={'action':'POST'}) member={'action': 'POST'})
mapper.resource("backup_schedule", "backup_schedules", mapper.resource("backup_schedule", "backup_schedules",
controller=backup_schedules.Controller(), controller=backup_schedules.Controller(),
parent_resource=dict(member_name='server', parent_resource=dict(member_name='server',
collection_name = 'servers')) collection_name='servers'))
mapper.resource("image", "images", controller=images.Controller(), mapper.resource("image", "images", controller=images.Controller(),
collection={'detail': 'GET'}) collection={'detail': 'GET'})
@@ -172,7 +176,7 @@ class APIRouter(wsgi.Router):
def limited(items, req): def limited(items, req):
"""Return a slice of items according to requested offset and limit. """Return a slice of items according to requested offset and limit.
items - a sliceable items - a sliceable
req - wobob.Request possibly containing offset and limit GET variables. req - wobob.Request possibly containing offset and limit GET variables.
offset is where to start in the list, and limit is the maximum number 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) limit = min(1000, limit)
range_end = offset + limit range_end = offset + limit
return items[offset:range_end] return items[offset:range_end]

View File

@@ -15,9 +15,11 @@ from nova.api.openstack import faults
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
class Context(object): class Context(object):
pass pass
class BasicApiAuthManager(object): class BasicApiAuthManager(object):
""" Implements a somewhat rudimentary version of OpenStack Auth""" """ Implements a somewhat rudimentary version of OpenStack Auth"""
@@ -61,7 +63,7 @@ class BasicApiAuthManager(object):
def authorize_token(self, token_hash): def authorize_token(self, token_hash):
""" retrieves user information from the datastore given a token """ retrieves user information from the datastore given a token
If the token has expired, returns None If the token has expired, returns None
If the token is not found, returns None If the token is not found, returns None
Otherwise returns dict(id=(the authorized user's id)) 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 This method will also remove the token if the timestamp is older than
2 days ago. 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: if token:
delta = datetime.datetime.now() - token.created_at delta = datetime.datetime.now() - token.created_at
if delta.days >= 2: if delta.days >= 2:
@@ -94,8 +96,7 @@ class BasicApiAuthManager(object):
token_dict['user_id'] = user.id token_dict['user_id'] = user.id
token = self.db.auth_create_token(self.context, token_dict) token = self.db.auth_create_token(self.context, token_dict)
return token, user return token, user
return None, None return None, None
def _get_server_mgmt_url(self): def _get_server_mgmt_url(self):
return 'https://%s/v1.0/' % self.host return 'https://%s/v1.0/' % self.host

View File

@@ -22,6 +22,7 @@ from nova import wsgi
from nova.api.openstack import faults from nova.api.openstack import faults
import nova.image.service import nova.image.service
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
def __init__(self): def __init__(self):
pass pass

View File

@@ -55,7 +55,7 @@ class Fault(webob.exc.HTTPException):
if code == 413: if code == 413:
retry = self.wrapped_exc.headers['Retry-After'] retry = self.wrapped_exc.headers['Retry-After']
fault_data[fault_name]['retryAfter'] = retry 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'}}} metadata = {'application/xml': {'attributes': {fault_name: 'code'}}}
serializer = wsgi.Serializer(req.environ, metadata) serializer = wsgi.Serializer(req.environ, metadata)
self.wrapped_exc.body = serializer.to_content_type(fault_data) self.wrapped_exc.body = serializer.to_content_type(fault_data)

View File

@@ -22,16 +22,14 @@ from nova.compute import instance_types
from nova import wsgi from nova import wsgi
import nova.api.openstack import nova.api.openstack
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
"""Flavor controller for the OpenStack API.""" """Flavor controller for the OpenStack API."""
_serialization_metadata = { _serialization_metadata = {
'application/xml': { 'application/xml': {
"attributes": { "attributes": {
"flavor": [ "id", "name", "ram", "disk" ] "flavor": ["id", "name", "ram", "disk"]}}}
}
}
}
def index(self, req): def index(self, req):
"""Return all flavors in brief.""" """Return all flavors in brief."""

View File

@@ -27,16 +27,14 @@ from nova.api.openstack import faults
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
_serialization_metadata = { _serialization_metadata = {
'application/xml': { 'application/xml': {
"attributes": { "attributes": {
"image": [ "id", "name", "updated", "created", "status", "image": ["id", "name", "updated", "created", "status",
"serverId", "progress" ] "serverId", "progress"]}}}
}
}
}
def __init__(self): def __init__(self):
self._service = utils.import_object(FLAGS.image_service) self._service = utils.import_object(FLAGS.image_service)
@@ -72,6 +70,6 @@ class Controller(wsgi.Controller):
raise faults.Fault(exc.HTTPNotFound()) raise faults.Fault(exc.HTTPNotFound())
def update(self, req, id): 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. # we support for now.
raise faults.Fault(exc.HTTPNotFound()) raise faults.Fault(exc.HTTPNotFound())

View File

@@ -13,6 +13,7 @@ PER_MINUTE = 60
PER_HOUR = 60 * 60 PER_HOUR = 60 * 60
PER_DAY = 60 * 60 * 24 PER_DAY = 60 * 60 * 24
class Limiter(object): class Limiter(object):
"""Class providing rate limiting of arbitrary actions.""" """Class providing rate limiting of arbitrary actions."""
@@ -101,7 +102,8 @@ class WSGIApp(object):
return webob.exc.HTTPForbidden( return webob.exc.HTTPForbidden(
headers={'X-Wait-Seconds': "%.2f" % delay}) headers={'X-Wait-Seconds': "%.2f" % delay})
else: else:
return '' # 200 OK # 200 OK
return ''
class WSGIAppProxy(object): class WSGIAppProxy(object):
@@ -109,7 +111,7 @@ class WSGIAppProxy(object):
"""Limiter lookalike that proxies to a ratelimiting.WSGIApp.""" """Limiter lookalike that proxies to a ratelimiting.WSGIApp."""
def __init__(self, service_host): 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.""" host."""
self.service_host = service_host self.service_host = service_host
@@ -118,5 +120,6 @@ class WSGIAppProxy(object):
conn.request('POST', '/limiter/%s/%s' % (username, action)) conn.request('POST', '/limiter/%s/%s' % (username, action))
resp = conn.getresponse() resp = conn.getresponse()
if resp.status == 200: if resp.status == 200:
return None # no delay # No delay
return None
return float(resp.getheader('X-Wait-Seconds')) return float(resp.getheader('X-Wait-Seconds'))

View File

@@ -34,30 +34,32 @@ import nova.image.service
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
def _filter_params(inst_dict): def _filter_params(inst_dict):
""" Extracts all updatable parameters for a server update request """ """ Extracts all updatable parameters for a server update request """
keys = dict(name='name', admin_pass='adminPass') keys = dict(name='name', admin_pass='adminPass')
new_attrs = {} new_attrs = {}
for k, v in keys.items(): for k, v in keys.items():
if inst_dict.has_key(v): if v in inst_dict:
new_attrs[k] = inst_dict[v] new_attrs[k] = inst_dict[v]
return new_attrs return new_attrs
def _entity_list(entities): def _entity_list(entities):
""" Coerces a list of servers into proper dictionary format """ """ Coerces a list of servers into proper dictionary format """
return dict(servers=entities) return dict(servers=entities)
def _entity_detail(inst): def _entity_detail(inst):
""" Maps everything to Rackspace-like attributes for return""" """ Maps everything to Rackspace-like attributes for return"""
power_mapping = { power_mapping = {
power_state.NOSTATE: 'build', power_state.NOSTATE: 'build',
power_state.RUNNING: 'active', power_state.RUNNING: 'active',
power_state.BLOCKED: 'active', power_state.BLOCKED: 'active',
power_state.PAUSED: 'suspended', power_state.PAUSED: 'suspended',
power_state.SHUTDOWN: 'active', power_state.SHUTDOWN: 'active',
power_state.SHUTOFF: 'active', power_state.SHUTOFF: 'active',
power_state.CRASHED: 'error' power_state.CRASHED: 'error'}
}
inst_dict = {} inst_dict = {}
mapped_keys = dict(status='state', imageId='image_id', mapped_keys = dict(status='state', imageId='image_id',
@@ -73,21 +75,20 @@ def _entity_detail(inst):
return dict(server=inst_dict) return dict(server=inst_dict)
def _entity_inst(inst): def _entity_inst(inst):
""" Filters all model attributes save for id and name """ """ Filters all model attributes save for id and name """
return dict(server=dict(id=inst['id'], name=inst['server_name'])) return dict(server=dict(id=inst['id'], name=inst['server_name']))
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
""" The Server API controller for the OpenStack API """ """ The Server API controller for the OpenStack API """
_serialization_metadata = { _serialization_metadata = {
'application/xml': { 'application/xml': {
"attributes": { "attributes": {
"server": [ "id", "imageId", "name", "flavorId", "hostId", "server": ["id", "imageId", "name", "flavorId", "hostId",
"status", "progress", "progress" ] "status", "progress", "progress"]}}}
}
}
}
def __init__(self, db_driver=None): def __init__(self, db_driver=None):
if not db_driver: if not db_driver:
@@ -209,7 +210,7 @@ class Controller(wsgi.Controller):
image = img_service.show(image_id) image = img_service.show(image_id)
if not image: if not image:
raise Exception, "Image not found" raise Exception("Image not found")
inst['server_name'] = env['server']['name'] inst['server_name'] = env['server']['name']
inst['image_id'] = image_id inst['image_id'] = image_id

View File

@@ -17,4 +17,6 @@
from nova import wsgi from nova import wsgi
class Controller(wsgi.Controller): pass
class Controller(wsgi.Controller):
pass