diff options
| author | Devendra Modium <dmodium@isi.edu> | 2011-07-07 16:30:58 -0400 |
|---|---|---|
| committer | Devendra Modium <dmodium@isi.edu> | 2011-07-07 16:30:58 -0400 |
| commit | ebd3b88d8b06e7e7f54671811ccff3bdc1531e08 (patch) | |
| tree | 9d6eaf53272349fd4f3187ff9221795768fb7609 /nova/api | |
| parent | 784c0a76967310843269d7f8be9df6bc292ff3c8 (diff) | |
| parent | bc8f009f8ac6393301dd857339918d40b93be63d (diff) | |
| download | nova-ebd3b88d8b06e7e7f54671811ccff3bdc1531e08.tar.gz nova-ebd3b88d8b06e7e7f54671811ccff3bdc1531e08.tar.xz nova-ebd3b88d8b06e7e7f54671811ccff3bdc1531e08.zip | |
Merging issuse
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/ec2/cloud.py | 116 | ||||
| -rw-r--r-- | nova/api/openstack/common.py | 10 | ||||
| -rw-r--r-- | nova/api/openstack/contrib/floating_ips.py | 3 | ||||
| -rw-r--r-- | nova/api/openstack/contrib/hosts.py | 114 | ||||
| -rw-r--r-- | nova/api/openstack/views/addresses.py | 10 | ||||
| -rw-r--r-- | nova/api/openstack/views/flavors.py | 16 | ||||
| -rw-r--r-- | nova/api/openstack/views/images.py | 16 | ||||
| -rw-r--r-- | nova/api/openstack/views/servers.py | 14 |
8 files changed, 237 insertions, 62 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 5449be403..9be30cf75 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -120,8 +120,8 @@ class CloudController(object): result = {} for instance in self.compute_api.get_all(context, project_id=project_id): - if instance['fixed_ip']: - line = '%s slots=%d' % (instance['fixed_ip']['address'], + if instance['fixed_ips']: + line = '%s slots=%d' % (instance['fixed_ips'][0]['address'], instance['vcpus']) key = str(instance['key_name']) if key in result: @@ -390,15 +390,21 @@ class CloudController(object): pass return True - def describe_security_groups(self, context, group_name=None, **kwargs): + def describe_security_groups(self, context, group_name=None, group_id=None, + **kwargs): self.compute_api.ensure_default_security_group(context) - if group_name: + if group_name or group_id: groups = [] - for name in group_name: - group = db.security_group_get_by_name(context, - context.project_id, - name) - groups.append(group) + if group_name: + for name in group_name: + group = db.security_group_get_by_name(context, + context.project_id, + name) + groups.append(group) + if group_id: + for gid in group_id: + group = db.security_group_get(context, gid) + groups.append(group) elif context.is_admin: groups = db.security_group_get_all(context) else: @@ -496,13 +502,26 @@ class CloudController(object): return True return False - def revoke_security_group_ingress(self, context, group_name, **kwargs): - LOG.audit(_("Revoke security group ingress %s"), group_name, - context=context) + def revoke_security_group_ingress(self, context, group_name=None, + group_id=None, **kwargs): + if not group_name and not group_id: + err = "Not enough parameters, need group_name or group_id" + raise exception.ApiError(_(err)) self.compute_api.ensure_default_security_group(context) - security_group = db.security_group_get_by_name(context, - context.project_id, - group_name) + notfound = exception.SecurityGroupNotFound + if group_name: + security_group = db.security_group_get_by_name(context, + context.project_id, + group_name) + if not security_group: + raise notfound(security_group_id=group_name) + if group_id: + security_group = db.security_group_get(context, group_id) + if not security_group: + raise notfound(security_group_id=group_id) + + msg = "Revoke security group ingress %s" + LOG.audit(_(msg), security_group['name'], context=context) criteria = self._revoke_rule_args_to_dict(context, **kwargs) if criteria is None: @@ -517,7 +536,7 @@ class CloudController(object): if match: db.security_group_rule_destroy(context, rule['id']) self.compute_api.trigger_security_group_rules_refresh(context, - security_group['id']) + security_group_id=security_group['id']) return True raise exception.ApiError(_("No rule for the specified parameters.")) @@ -525,14 +544,26 @@ class CloudController(object): # Unfortunately, it seems Boto is using an old API # for these operations, so support for newer API versions # is sketchy. - def authorize_security_group_ingress(self, context, group_name, **kwargs): - LOG.audit(_("Authorize security group ingress %s"), group_name, - context=context) + def authorize_security_group_ingress(self, context, group_name=None, + group_id=None, **kwargs): + if not group_name and not group_id: + err = "Not enough parameters, need group_name or group_id" + raise exception.ApiError(_(err)) self.compute_api.ensure_default_security_group(context) - security_group = db.security_group_get_by_name(context, - context.project_id, - group_name) - + notfound = exception.SecurityGroupNotFound + if group_name: + security_group = db.security_group_get_by_name(context, + context.project_id, + group_name) + if not security_group: + raise notfound(security_group_id=group_name) + if group_id: + security_group = db.security_group_get(context, group_id) + if not security_group: + raise notfound(security_group_id=group_id) + + msg = "Authorize security group ingress %s" + LOG.audit(_(msg), security_group['name'], context=context) values = self._revoke_rule_args_to_dict(context, **kwargs) if values is None: raise exception.ApiError(_("Not enough parameters to build a " @@ -546,7 +577,7 @@ class CloudController(object): security_group_rule = db.security_group_rule_create(context, values) self.compute_api.trigger_security_group_rules_refresh(context, - security_group['id']) + security_group_id=security_group['id']) return True @@ -582,11 +613,23 @@ class CloudController(object): return {'securityGroupSet': [self._format_security_group(context, group_ref)]} - def delete_security_group(self, context, group_name, **kwargs): + def delete_security_group(self, context, group_name=None, group_id=None, + **kwargs): + if not group_name and not group_id: + err = "Not enough parameters, need group_name or group_id" + raise exception.ApiError(_(err)) + notfound = exception.SecurityGroupNotFound + if group_name: + security_group = db.security_group_get_by_name(context, + context.project_id, + group_name) + if not security_group: + raise notfound(security_group_id=group_name) + elif group_id: + security_group = db.security_group_get(context, group_id) + if not security_group: + raise notfound(security_group_id=group_id) LOG.audit(_("Delete security group %s"), group_name, context=context) - security_group = db.security_group_get_by_name(context, - context.project_id, - group_name) db.security_group_destroy(context, security_group.id) return True @@ -792,15 +835,15 @@ class CloudController(object): 'name': instance['state_description']} fixed_addr = None floating_addr = None - if instance['fixed_ip']: - fixed_addr = instance['fixed_ip']['address'] - if instance['fixed_ip']['floating_ips']: - fixed = instance['fixed_ip'] + if instance['fixed_ips']: + fixed = instance['fixed_ips'][0] + fixed_addr = fixed['address'] + if fixed['floating_ips']: floating_addr = fixed['floating_ips'][0]['address'] - if instance['fixed_ip']['network'] and 'use_v6' in kwargs: + if fixed['network'] and 'use_v6' in kwargs: i['dnsNameV6'] = ipv6.to_global( - instance['fixed_ip']['network']['cidr_v6'], - instance['mac_address'], + fixed['network']['cidr_v6'], + fixed['virtual_interface']['address'], instance['project_id']) i['privateDnsName'] = fixed_addr @@ -876,7 +919,8 @@ class CloudController(object): public_ip = self.network_api.allocate_floating_ip(context) return {'publicIp': public_ip} except rpc.RemoteError as ex: - if ex.exc_type == 'NoMoreAddresses': + # NOTE(tr3buchet) - why does this block exist? + if ex.exc_type == 'NoMoreFloatingIps': raise exception.NoMoreFloatingIps() else: raise diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index aa8911b62..9aa384f33 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -134,3 +134,13 @@ def get_id_from_href(href): except: LOG.debug(_("Error extracting id from href: %s") % href) raise webob.exc.HTTPBadRequest(_('could not parse id from href')) + + +def remove_version_from_href(base_url): + """Removes the api version from the href. + + Given: 'http://www.nova.com/v1.1/123' + Returns: 'http://www.nova.com/123' + + """ + return base_url.rsplit('/', 1).pop(0) diff --git a/nova/api/openstack/contrib/floating_ips.py b/nova/api/openstack/contrib/floating_ips.py index 914ec5bfb..b27336574 100644 --- a/nova/api/openstack/contrib/floating_ips.py +++ b/nova/api/openstack/contrib/floating_ips.py @@ -85,7 +85,8 @@ class FloatingIPController(object): address = self.network_api.allocate_floating_ip(context) ip = self.network_api.get_floating_ip_by_ip(context, address) except rpc.RemoteError as ex: - if ex.exc_type == 'NoMoreAddresses': + # NOTE(tr3buchet) - why does this block exist? + if ex.exc_type == 'NoMoreFloatingIps': raise exception.NoMoreFloatingIps() else: raise diff --git a/nova/api/openstack/contrib/hosts.py b/nova/api/openstack/contrib/hosts.py new file mode 100644 index 000000000..55e57e1a4 --- /dev/null +++ b/nova/api/openstack/contrib/hosts.py @@ -0,0 +1,114 @@ +# Copyright (c) 2011 Openstack, LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""The hosts admin extension.""" + +import webob.exc + +from nova import compute +from nova import exception +from nova import flags +from nova import log as logging +from nova.api.openstack import common +from nova.api.openstack import extensions +from nova.api.openstack import faults +from nova.scheduler import api as scheduler_api + + +LOG = logging.getLogger("nova.api.hosts") +FLAGS = flags.FLAGS + + +def _list_hosts(req, service=None): + """Returns a summary list of hosts, optionally filtering + by service type. + """ + context = req.environ['nova.context'] + hosts = scheduler_api.get_host_list(context) + if service: + hosts = [host for host in hosts + if host["service"] == service] + return hosts + + +def check_host(fn): + """Makes sure that the host exists.""" + def wrapped(self, req, id, service=None, *args, **kwargs): + listed_hosts = _list_hosts(req, service) + hosts = [h["host_name"] for h in listed_hosts] + if id in hosts: + return fn(self, req, id, *args, **kwargs) + else: + raise exception.HostNotFound(host=id) + return wrapped + + +class HostController(object): + """The Hosts API controller for the OpenStack API.""" + def __init__(self): + self.compute_api = compute.API() + super(HostController, self).__init__() + + def index(self, req): + return {'hosts': _list_hosts(req)} + + @check_host + def update(self, req, id, body): + for raw_key, raw_val in body.iteritems(): + key = raw_key.lower().strip() + val = raw_val.lower().strip() + # NOTE: (dabo) Right now only 'status' can be set, but other + # actions may follow. + if key == "status": + if val[:6] in ("enable", "disabl"): + return self._set_enabled_status(req, id, + enabled=(val.startswith("enable"))) + else: + explanation = _("Invalid status: '%s'") % raw_val + raise webob.exc.HTTPBadRequest(explanation=explanation) + else: + explanation = _("Invalid update setting: '%s'") % raw_key + raise webob.exc.HTTPBadRequest(explanation=explanation) + + def _set_enabled_status(self, req, host, enabled): + """Sets the specified host's ability to accept new instances.""" + context = req.environ['nova.context'] + state = "enabled" if enabled else "disabled" + LOG.audit(_("Setting host %(host)s to %(state)s.") % locals()) + result = self.compute_api.set_host_enabled(context, host=host, + enabled=enabled) + return {"host": host, "status": result} + + +class Hosts(extensions.ExtensionDescriptor): + def get_name(self): + return "Hosts" + + def get_alias(self): + return "os-hosts" + + def get_description(self): + return "Host administration" + + def get_namespace(self): + return "http://docs.openstack.org/ext/hosts/api/v1.1" + + def get_updated(self): + return "2011-06-29T00:00:00+00:00" + + def get_resources(self): + resources = [extensions.ResourceExtension('os-hosts', HostController(), + collection_actions={'update': 'PUT'}, member_actions={})] + return resources diff --git a/nova/api/openstack/views/addresses.py b/nova/api/openstack/views/addresses.py index 2810cce39..b59eb4751 100644 --- a/nova/api/openstack/views/addresses.py +++ b/nova/api/openstack/views/addresses.py @@ -33,16 +33,18 @@ class ViewBuilderV10(ViewBuilder): return dict(public=public_ips, private=private_ips) def build_public_parts(self, inst): - return utils.get_from_path(inst, 'fixed_ip/floating_ips/address') + return utils.get_from_path(inst, 'fixed_ips/floating_ips/address') def build_private_parts(self, inst): - return utils.get_from_path(inst, 'fixed_ip/address') + return utils.get_from_path(inst, 'fixed_ips/address') class ViewBuilderV11(ViewBuilder): def build(self, inst): - private_ips = utils.get_from_path(inst, 'fixed_ip/address') + # TODO(tr3buchet) - this shouldn't be hard coded to 4... + private_ips = utils.get_from_path(inst, 'fixed_ips/address') private_ips = [dict(version=4, addr=a) for a in private_ips] - public_ips = utils.get_from_path(inst, 'fixed_ip/floating_ips/address') + public_ips = utils.get_from_path(inst, + 'fixed_ips/floating_ips/address') public_ips = [dict(version=4, addr=a) for a in public_ips] return dict(public=public_ips, private=private_ips) diff --git a/nova/api/openstack/views/flavors.py b/nova/api/openstack/views/flavors.py index 462890ab2..0403ece1b 100644 --- a/nova/api/openstack/views/flavors.py +++ b/nova/api/openstack/views/flavors.py @@ -71,6 +71,7 @@ class ViewBuilderV11(ViewBuilder): def _build_links(self, flavor_obj): """Generate a container of links that refer to the provided flavor.""" href = self.generate_href(flavor_obj["id"]) + bookmark = self.generate_bookmark(flavor_obj["id"]) links = [ { @@ -79,13 +80,7 @@ class ViewBuilderV11(ViewBuilder): }, { "rel": "bookmark", - "type": "application/json", - "href": href, - }, - { - "rel": "bookmark", - "type": "application/xml", - "href": href, + "href": bookmark, }, ] @@ -94,3 +89,10 @@ class ViewBuilderV11(ViewBuilder): def generate_href(self, flavor_id): """Create an url that refers to a specific flavor id.""" return "%s/flavors/%s" % (self.base_url, flavor_id) + + def generate_bookmark(self, flavor_id): + """Create an url that refers to a specific flavor id.""" + return "%s/flavors/%s" % ( + common.remove_version_from_href(self.base_url), + flavor_id, + ) diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 8d2303bcd..005341c62 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -17,6 +17,8 @@ import os.path +from nova.api.openstack import common + class ViewBuilder(object): """Base class for generating responses to OpenStack API image requests.""" @@ -104,6 +106,7 @@ class ViewBuilderV11(ViewBuilder): """Return a standardized image structure for display by the API.""" image = ViewBuilder.build(self, image_obj, detail) href = self.generate_href(image_obj["id"]) + bookmark = self.generate_bookmark(image_obj["id"]) if detail: image["metadata"] = image_obj.get("properties", {}) @@ -114,13 +117,12 @@ class ViewBuilderV11(ViewBuilder): }, { "rel": "bookmark", - "type": "application/json", - "href": href, - }, - { - "rel": "bookmark", - "type": "application/xml", - "href": href, + "href": bookmark, }] return image + + def generate_bookmark(self, image_id): + """Create an url that refers to a specific flavor id.""" + return os.path.join(common.remove_version_from_href(self._url), + "images", str(image_id)) diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index cbfa5aae7..67fb6a84e 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -156,6 +156,7 @@ class ViewBuilderV11(ViewBuilder): def _build_links(self, response, inst): href = self.generate_href(inst["id"]) + bookmark = self.generate_bookmark(inst["id"]) links = [ { @@ -164,13 +165,7 @@ class ViewBuilderV11(ViewBuilder): }, { "rel": "bookmark", - "type": "application/json", - "href": href, - }, - { - "rel": "bookmark", - "type": "application/xml", - "href": href, + "href": bookmark, }, ] @@ -179,3 +174,8 @@ class ViewBuilderV11(ViewBuilder): def generate_href(self, server_id): """Create an url that refers to a specific server id.""" return os.path.join(self.base_url, "servers", str(server_id)) + + def generate_bookmark(self, server_id): + """Create an url that refers to a specific flavor id.""" + return os.path.join(common.remove_version_from_href(self.base_url), + "servers", str(server_id)) |
