From 62d5fae8d11b6403f9a63a709270ffafebb7ef09 Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Tue, 31 Jan 2012 16:29:28 -0600 Subject: remove unsupported ec2 extensions implements blueprint remove-ec2-extensions * remove deprecated unofficial ec2 admin api * remove admin api from wsgi/paste * remove unofficial ec2 call for ajaxterm / update calls * remove displayName/displayDescription from volumes/instances Change-Id: If5a5ae26ebb9456a3c7376ff4ff0aa9589be1f5b --- nova/api/ec2/admin.py | 418 --------------------------------------------- nova/api/ec2/apirequest.py | 9 - nova/api/ec2/cloud.py | 72 +------- 3 files changed, 4 insertions(+), 495 deletions(-) delete mode 100644 nova/api/ec2/admin.py (limited to 'nova/api') diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py deleted file mode 100644 index 4e81debe4..000000000 --- a/nova/api/ec2/admin.py +++ /dev/null @@ -1,418 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# 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. - -""" -Admin API controller, exposed through http via the api worker. -""" - -import base64 -import urllib - -import netaddr - -from nova.api.ec2 import ec2utils -from nova.auth import manager -from nova import compute -from nova.compute import instance_types -from nova.compute import vm_states -from nova import db -from nova import exception -from nova import flags -from nova import log as logging -from nova import utils - - -FLAGS = flags.FLAGS -LOG = logging.getLogger('nova.api.ec2.admin') - - -def user_dict(user, base64_file=None): - """Convert the user object to a result dict""" - if user: - return { - 'username': user.id, - 'accesskey': user.access, - 'secretkey': user.secret, - 'file': base64_file} - else: - return {} - - -def project_dict(project): - """Convert the project object to a result dict""" - if project: - return { - 'projectname': project.id, - 'project_manager_id': project.project_manager_id, - 'description': project.description} - else: - return {} - - -def host_dict(host, compute_service, instances, volume_service, volumes, now): - """Convert a host model object to a result dict""" - rv = {'hostname': host, 'instance_count': len(instances), - 'volume_count': len(volumes)} - if compute_service: - latest = compute_service['updated_at'] or compute_service['created_at'] - delta = now - latest - if delta.seconds <= FLAGS.service_down_time: - rv['compute'] = 'up' - else: - rv['compute'] = 'down' - if volume_service: - latest = volume_service['updated_at'] or volume_service['created_at'] - delta = now - latest - if delta.seconds <= FLAGS.service_down_time: - rv['volume'] = 'up' - else: - rv['volume'] = 'down' - return rv - - -def instance_dict(inst): - return {'name': inst['name'], - 'memory_mb': inst['memory_mb'], - 'vcpus': inst['vcpus'], - 'disk_gb': inst['root_gb'], - 'flavor_id': inst['flavorid']} - - -def vpn_dict(project, vpn_instance): - rv = {'project_id': project.id, - 'public_ip': project.vpn_ip, - 'public_port': project.vpn_port} - if vpn_instance: - rv['instance_id'] = ec2utils.id_to_ec2_id(vpn_instance['id']) - rv['created_at'] = utils.isotime(vpn_instance['created_at']) - address = vpn_instance.get('fixed_ip', None) - if address: - rv['internal_ip'] = address['address'] - if project.vpn_ip and project.vpn_port: - if utils.vpn_ping(project.vpn_ip, project.vpn_port): - rv['state'] = 'running' - else: - rv['state'] = 'down' - else: - rv['state'] = 'down - invalid project vpn config' - else: - rv['state'] = 'pending' - return rv - - -class AdminController(object): - """ - API Controller for users, hosts, nodes, and workers. - """ - - def __str__(self): - return 'AdminController' - - def __init__(self): - self.compute_api = compute.API() - - def describe_instance_types(self, context, **_kwargs): - """Returns all active instance types data (vcpus, memory, etc.)""" - inst_types = instance_types.get_all_types() - inst_type_dicts = [instance_dict(i) for i in inst_types.values()] - return {'instanceTypeSet': inst_type_dicts} - - def describe_user(self, _context, name, **_kwargs): - """Returns user data, including access and secret keys.""" - return user_dict(manager.AuthManager().get_user(name)) - - 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()]} - - def register_user(self, context, name, **_kwargs): - """Creates a new user, and returns generated credentials.""" - LOG.audit(_("Creating new user: %s"), name, context=context) - return user_dict(manager.AuthManager().create_user(name)) - - def deregister_user(self, context, name, **_kwargs): - """Deletes a single user (NOT undoable.) - Should throw an exception if the user has instances, - volumes, or buckets remaining. - """ - LOG.audit(_("Deleting user: %s"), name, context=context) - manager.AuthManager().delete_user(name) - return True - - 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]} - - def describe_user_roles(self, context, user, project=None, **kwargs): - """Returns a list of roles for the given user. - Omitting project will return any global roles that the user has. - 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]} - - def modify_user_role(self, context, user, role, project=None, - operation='add', **kwargs): - """Add or remove a role for a user and project.""" - if operation == 'add': - if project: - msg = _("Adding role %(role)s to user %(user)s" - " for project %(project)s") % locals() - LOG.audit(msg, context=context) - else: - msg = _("Adding sitewide role %(role)s to" - " user %(user)s") % locals() - LOG.audit(msg, context=context) - manager.AuthManager().add_role(user, role, project) - elif operation == 'remove': - if project: - msg = _("Removing role %(role)s from user %(user)s" - " for project %(project)s") % locals() - LOG.audit(msg, context=context) - else: - msg = _("Removing sitewide role %(role)s" - " from user %(user)s") % locals() - LOG.audit(msg, context=context) - manager.AuthManager().remove_role(user, role, project) - else: - raise exception.ApiError(_('operation must be add or remove')) - - return True - - def generate_x509_for_user(self, context, name, project=None, **kwargs): - """Generates and returns an x509 certificate for a single user. - Is usually called from a client that will wrap this with - access and secret key info, and return a zip file. - """ - if project is None: - project = name - project = manager.AuthManager().get_project(project) - user = manager.AuthManager().get_user(name) - msg = _("Getting x509 for user: %(name)s" - " on project: %(project)s") % locals() - LOG.audit(msg, context=context) - return user_dict(user, base64.b64encode(project.get_credentials(user))) - - def describe_project(self, context, name, **kwargs): - """Returns project data, including member ids.""" - return project_dict(manager.AuthManager().get_project(name)) - - def describe_projects(self, context, user=None, **kwargs): - """Returns all projects - should be changed to deal with a list.""" - return {'projectSet': - [project_dict(u) for u in - manager.AuthManager().get_projects(user=user)]} - - def register_project(self, context, name, manager_user, description=None, - member_users=None, **kwargs): - """Creates a new project""" - msg = _("Create project %(name)s managed by" - " %(manager_user)s") % locals() - LOG.audit(msg, context=context) - return project_dict( - manager.AuthManager().create_project( - name, - manager_user, - description=None, - member_users=None)) - - def modify_project(self, context, name, manager_user, description=None, - **kwargs): - """Modifies a project""" - msg = _("Modify project: %(name)s managed by" - " %(manager_user)s") % locals() - LOG.audit(msg, context=context) - manager.AuthManager().modify_project(name, - manager_user=manager_user, - description=description) - return True - - def deregister_project(self, context, name): - """Permanently deletes a project.""" - LOG.audit(_("Delete project: %s"), name, context=context) - manager.AuthManager().delete_project(name) - return True - - def describe_project_members(self, context, name, **kwargs): - project = manager.AuthManager().get_project(name) - result = { - 'members': [{'member': m} for m in project.member_ids]} - return result - - def modify_project_member(self, context, user, project, operation, - **kwargs): - """Add or remove a user from a project.""" - if operation == 'add': - msg = _("Adding user %(user)s to project %(project)s") % locals() - LOG.audit(msg, context=context) - manager.AuthManager().add_to_project(user, project) - elif operation == 'remove': - msg = _("Removing user %(user)s from" - " project %(project)s") % locals() - LOG.audit(msg, context=context) - manager.AuthManager().remove_from_project(user, project) - else: - raise exception.ApiError(_('operation must be add or remove')) - return True - - def _vpn_for(self, context, project_id): - """Get the VPN instance for a project ID.""" - for instance in db.instance_get_all_by_project(context, project_id): - if (instance['image_id'] == str(FLAGS.vpn_image_id) - and not instance['vm_state'] in [vm_states.DELETED]): - return instance - - def start_vpn(self, context, project): - instance = self._vpn_for(context, project) - if not instance: - # NOTE(vish) import delayed because of __init__.py - from nova.cloudpipe import pipelib - pipe = pipelib.CloudPipe() - proj = manager.AuthManager().get_project(project) - user_id = proj.project_manager_id - try: - pipe.launch_vpn_instance(project, user_id) - except db.NoMoreNetworks: - raise exception.ApiError("Unable to claim IP for VPN instance" - ", ensure it isn't running, and try " - "again in a few minutes") - instance = self._vpn_for(context, project) - return {'instance_id': ec2utils.id_to_ec2_id(instance['id'])} - - def describe_vpns(self, context): - vpns = [] - for project in manager.AuthManager().get_projects(): - instance = self._vpn_for(context, project.id) - vpns.append(vpn_dict(project, instance)) - return {'items': vpns} - - # FIXME(vish): these host commands don't work yet, perhaps some of the - # required data can be retrieved from service objects? - - def describe_hosts(self, context, **_kwargs): - """Returns status info for all nodes. Includes: - * Hostname - * Compute (up, down, None) - * Instance count - * Volume (up, down, None) - * Volume Count - """ - services = db.service_get_all(context, False) - now = utils.utcnow() - hosts = [] - rv = [] - for host in [service['host'] for service in services]: - if not host in hosts: - hosts.append(host) - for host in hosts: - compute = [s for s in services if s['host'] == host \ - and s['binary'] == 'nova-compute'] - if compute: - compute = compute[0] - instances = db.instance_get_all_by_host(context, host) - volume = [s for s in services if s['host'] == host \ - and s['binary'] == 'nova-volume'] - if volume: - volume = volume[0] - volumes = db.volume_get_all_by_host(context, host) - rv.append(host_dict(host, compute, instances, volume, volumes, - now)) - return {'hosts': rv} - - def _provider_fw_rule_exists(self, context, rule): - # TODO(todd): we call this repeatedly, can we filter by protocol? - for old_rule in db.provider_fw_rule_get_all(context): - if all([rule[k] == old_rule[k] for k in ('cidr', 'from_port', - 'to_port', 'protocol')]): - return True - return False - - def block_external_addresses(self, context, cidr): - """Add provider-level firewall rules to block incoming traffic.""" - LOG.audit(_('Blocking traffic to all projects incoming from %s'), - cidr, context=context) - cidr = urllib.unquote(cidr).decode() - failed = {'status': 'Failed', 'message': ' 0 rules added'} - if not utils.is_valid_cidr(cidr): - msg = 'Improper input. Please provide a valid cidr: ' \ - 'e.g. 121.12.10.11/24.' - failed['message'] = msg + failed['message'] - return failed - #Normalizing cidr. e.g. '20.20.20.11/24' -> '20.20.20.0/24', so that - #db values stay in sync with filters' values (e.g. in iptables) - cidr = str(netaddr.IPNetwork(cidr).cidr) - rule = {'cidr': cidr} - tcp_rule = rule.copy() - tcp_rule.update({'protocol': 'tcp', 'from_port': 1, 'to_port': 65535}) - udp_rule = rule.copy() - udp_rule.update({'protocol': 'udp', 'from_port': 1, 'to_port': 65535}) - icmp_rule = rule.copy() - icmp_rule.update({'protocol': 'icmp', 'from_port': -1, - 'to_port': None}) - rules_added = 0 - if not self._provider_fw_rule_exists(context, tcp_rule): - db.provider_fw_rule_create(context, tcp_rule) - rules_added += 1 - if not self._provider_fw_rule_exists(context, udp_rule): - db.provider_fw_rule_create(context, udp_rule) - rules_added += 1 - if not self._provider_fw_rule_exists(context, icmp_rule): - db.provider_fw_rule_create(context, icmp_rule) - rules_added += 1 - if not rules_added: - msg = 'Duplicate Rule.' - failed['message'] = msg + failed['message'] - return failed - self.compute_api.trigger_provider_fw_rules_refresh(context) - return {'status': 'OK', 'message': 'Added %s rules' % rules_added} - - def describe_external_address_blocks(self, context): - blocks = db.provider_fw_rule_get_all(context) - # NOTE(todd): use a set since we have icmp/udp/tcp rules with same cidr - blocks = set([b.cidr for b in blocks]) - blocks = [{'cidr': b} for b in blocks] - return {'externalIpBlockInfo': - list(sorted(blocks, key=lambda k: k['cidr']))} - - def remove_external_address_block(self, context, cidr): - LOG.audit(_('Removing ip block from %s'), cidr, context=context) - cidr = urllib.unquote(cidr).decode() - # Catch the exception and LOG for improper or malicious inputs. - # Also return a proper status and message in that case - failed = {'status': 'Failed', 'message': ' 0 rules deleted'} - if not utils.is_valid_cidr(cidr): - msg = 'Improper input. Please provide a valid cidr: ' \ - 'e.g. 121.12.10.11/24.' - failed['message'] = msg + failed['message'] - return failed - #Normalizing cidr. e.g. '20.20.20.11/24' -> '20.20.20.0/24', so that - #db values stay in sync with filters' values (e.g. in iptables) - cidr = str(netaddr.IPNetwork(cidr).cidr) - rules = db.provider_fw_rule_get_all_by_cidr(context, cidr) - - if not rules: - msg = 'No such CIDR currently blocked.' - failed['message'] = msg + failed['message'] - return failed - else: - for rule in rules: - db.provider_fw_rule_destroy(context, rule['id']) - self.compute_api.trigger_provider_fw_rules_refresh(context) - return {'status': 'OK', 'message': 'Deleted %s rules' % len(rules)} diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py index ae7204740..01ea19628 100644 --- a/nova/api/ec2/apirequest.py +++ b/nova/api/ec2/apirequest.py @@ -24,7 +24,6 @@ import datetime # TODO(termie): replace minidom with etree from xml.dom import minidom -from nova.api.ec2 import admin from nova.api.ec2 import ec2utils from nova import exception from nova import flags @@ -57,14 +56,6 @@ class APIRequest(object): def invoke(self, context): try: - # Raise NotImplemented exception for Admin specific request if - # admin flag is set to false in nova.conf - if (isinstance(self.controller, admin.AdminController) - and (not FLAGS.allow_ec2_admin_api)): - ## Raise InvalidRequest exception for EC2 Admin interface ## - LOG.exception("Unsupported API request") - raise exception.InvalidRequest() - method = getattr(self.controller, ec2utils.camelcase_to_underscore(self.action)) except AttributeError: diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4c5e07f9f..c21973565 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -23,10 +23,7 @@ datastore. """ import base64 -import os import re -import shutil -import tempfile import time import urllib @@ -253,7 +250,6 @@ class CloudController(object): 'zoneState': 'available'}]} services = db.service_get_all(context, False) - now = utils.utcnow() hosts = [] for host in [service['host'] for service in services]: if not host in hosts: @@ -323,9 +319,6 @@ class CloudController(object): s['ownerId'] = snapshot['project_id'] s['volumeSize'] = snapshot['volume_size'] s['description'] = snapshot['display_description'] - - s['display_name'] = snapshot['display_name'] - s['display_description'] = snapshot['display_description'] return s def create_snapshot(self, context, volume_id, **kwargs): @@ -336,8 +329,8 @@ class CloudController(object): snapshot = self.volume_api.create_snapshot( context, volume, - kwargs.get('display_name'), - kwargs.get('display_description')) + None, + kwargs.get('description')) return self._format_snapshot(context, snapshot) def delete_snapshot(self, context, snapshot_id, **kwargs): @@ -793,15 +786,6 @@ class CloudController(object): "Timestamp": now, "output": base64.b64encode(output)} - def get_ajax_console(self, context, instance_id, **kwargs): - """Web based ajax terminal for vm. - - This is an extension to the normal ec2_api""" - ec2_id = instance_id[0] - instance_id = ec2utils.ec2_id_to_id(ec2_id) - instance = self.compute_api.get(context, instance_id) - return self.compute_api.get_ajax_console(context, instance) - def describe_volumes(self, context, volume_id=None, **kwargs): if volume_id: volumes = [] @@ -849,8 +833,6 @@ class CloudController(object): else: v['snapshotId'] = None - v['display_name'] = volume['display_name'] - v['display_description'] = volume['display_description'] return v def create_volume(self, context, **kwargs): @@ -866,8 +848,8 @@ class CloudController(object): volume = self.volume_api.create(context, size, - kwargs.get('display_name'), - kwargs.get('display_description'), + None, + None, snapshot) # TODO(vish): Instance should be None at db layer instead of # trying to lazy load, but for now we turn it into @@ -880,18 +862,6 @@ class CloudController(object): self.volume_api.delete(context, volume) return True - def update_volume(self, context, volume_id, **kwargs): - volume_id = ec2utils.ec2_id_to_id(volume_id) - updatable_fields = ['display_name', 'display_description'] - changes = {} - for field in updatable_fields: - if field in kwargs: - changes[field] = kwargs[field] - if changes: - volume = self.volume_api.get(context, volume_id) - self.volume_api.update(context, volume, fields=changes) - return True - def attach_volume(self, context, volume_id, instance_id, device, **kwargs): volume_id = ec2utils.ec2_id_to_id(volume_id) instance_id = ec2utils.ec2_id_to_id(instance_id) @@ -1160,8 +1130,6 @@ class CloudController(object): self._format_instance_type(instance, i) i['launchTime'] = instance['created_at'] i['amiLaunchIndex'] = instance['launch_index'] - i['displayName'] = instance['display_name'] - i['displayDescription'] = instance['display_description'] self._format_instance_root_device_name(instance, i) self._format_instance_bdm(context, instance_id, i['rootDeviceName'], i) @@ -1268,8 +1236,6 @@ class CloudController(object): max_count=max_count, kernel_id=kwargs.get('kernel_id'), ramdisk_id=kwargs.get('ramdisk_id'), - display_name=kwargs.get('display_name'), - display_description=kwargs.get('display_description'), key_name=kwargs.get('key_name'), user_data=kwargs.get('user_data'), security_group=kwargs.get('security_group'), @@ -1321,35 +1287,6 @@ class CloudController(object): self.compute_api.start(context, instance) return True - def rescue_instance(self, context, instance_id, **kwargs): - """This is an extension to the normal ec2_api""" - LOG.debug(_("Going to rescue instance %s") % instance_id) - _instance_id = ec2utils.ec2_id_to_id(instance_id) - instance = self.compute_api.get(context, _instance_id) - self.compute_api.rescue(context, instance) - return True - - def unrescue_instance(self, context, instance_id, **kwargs): - """This is an extension to the normal ec2_api""" - LOG.debug(_("Going to unrescue instance %s") % instance_id) - _instance_id = ec2utils.ec2_id_to_id(instance_id) - instance = self.compute_api.get(context, _instance_id) - self.compute_api.unrescue(context, instance) - return True - - def update_instance(self, context, instance_id, **kwargs): - """This is an extension to the normal ec2_api""" - updatable_fields = ['display_name', 'display_description'] - changes = {} - for field in updatable_fields: - if field in kwargs: - changes[field] = kwargs[field] - if changes: - instance_id = ec2utils.ec2_id_to_id(instance_id) - instance = self.compute_api.get(context, instance_id) - self.compute_api.update(context, instance, **changes) - return True - def _get_image(self, context, ec2_id): try: internal_id = ec2utils.ec2_id_to_id(ec2_id) @@ -1394,7 +1331,6 @@ class CloudController(object): i['imageLocation'] = image['properties'].get('image_location') i['imageState'] = self._get_image_state(image) - i['displayName'] = name i['description'] = image.get('description') display_mapping = {'aki': 'kernel', 'ari': 'ramdisk', -- cgit