remove proxy to ec2

Change-Id: I7c20d19ba1d608c84fbcf9602fcd4be61e9f64ea
This commit is contained in:
Andrey Pavlov 2014-12-25 21:48:42 +03:00
parent a53c96d231
commit 28756f3ad6
21 changed files with 67 additions and 851 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
.pydevproject .pydevproject
ec2_api.egg-info ec2_api.egg-info
.tox .tox
.testrepository

View File

@ -421,7 +421,7 @@ def ec2_error_ex(ex, req, code=None, message=None, unexpected=False):
log_msg = _("%(ex_name)s raised: %(ex_str)s") log_msg = _("%(ex_name)s raised: %(ex_str)s")
# NOTE(jruzicka): For compatibility with EC2 API, treat expected # NOTE(jruzicka): For compatibility with EC2 API, treat expected
# exceptions as client (4xx) errors. The exception error code is 500 # exceptions as client (4xx) errors. The exception error code is 500
# by default and most exceptions inherit this from NovaException even # by default and most exceptions inherit this from EC2Exception even
# though they are actually client errors in most cases. # though they are actually client errors in most cases.
if status >= 500: if status >= 500:
status = 400 status = 400
@ -468,34 +468,9 @@ class Executor(wsgi.Application):
ec2_id = ec2utils.id_to_ec2_inst_id(ex.kwargs['instance_id']) ec2_id = ec2utils.id_to_ec2_inst_id(ex.kwargs['instance_id'])
message = ex.msg_fmt % {'instance_id': ec2_id} message = ex.msg_fmt % {'instance_id': ec2_id}
return ec2_error_ex(ex, req, message=message) return ec2_error_ex(ex, req, message=message)
except exception.NovaDbVolumeNotFound as ex:
ec2_id = ec2utils.id_to_ec2_vol_id(ex.kwargs['volume_id'])
message = ex.msg_fmt % {'volume_id': ec2_id}
return ec2_error_ex(ex, req, message=message)
except exception.NovaDbSnapshotNotFound as ex:
ec2_id = ec2utils.id_to_ec2_snap_id(ex.kwargs['snapshot_id'])
message = ex.msg_fmt % {'snapshot_id': ec2_id}
return ec2_error_ex(ex, req, message=message)
except exception.MethodNotFound:
try:
http, response = api_request.proxy(req)
resp = webob.Response()
resp.status = http["status"]
resp.headers["content-type"] = http["content-type"]
resp.body = str(response)
return resp
except Exception as ex:
return ec2_error_ex(ex, req, unexpected=True)
except exception.EC2ServerError as ex:
resp = webob.Response()
resp.status = ex.response['status']
resp.headers['Content-Type'] = ex.response['content-type']
resp.body = ex.content
return resp
except Exception as ex: except Exception as ex:
return ec2_error_ex(ex, req, return ec2_error_ex(
unexpected=not isinstance( ex, req, unexpected=not isinstance(ex, exception.EC2Exception))
ex, exception.EC2Exception))
else: else:
resp = webob.Response() resp = webob.Response()
resp.status = 200 resp.status = 200

View File

@ -22,7 +22,6 @@ from oslo.config import cfg
from ec2api.api import clients from ec2api.api import clients
from ec2api.api import common from ec2api.api import common
from ec2api.api import ec2client
from ec2api.api import ec2utils from ec2api.api import ec2utils
from ec2api.api import utils from ec2api.api import utils
from ec2api.db import api as db_api from ec2api.db import api as db_api
@ -275,7 +274,6 @@ class AddressEngineNeutron(object):
msg = _("The address '%(public_ip)s' does not belong to you.") msg = _("The address '%(public_ip)s' does not belong to you.")
raise exception.AuthFailure(msg % {'public_ip': public_ip}) raise exception.AuthFailure(msg % {'public_ip': public_ip})
ec2 = ec2client.ec2client(context)
# NOTE(ft): in fact only the first two parameters are used to # NOTE(ft): in fact only the first two parameters are used to
# associate an address in EC2 Classic mode. Other parameters are # associate an address in EC2 Classic mode. Other parameters are
# sent to validate them for EC2 Classic mode and raise an error. # sent to validate them for EC2 Classic mode and raise an error.

View File

@ -25,11 +25,10 @@ from oslo.config import cfg
from ec2api.api import cloud from ec2api.api import cloud
from ec2api.api import ec2utils from ec2api.api import ec2utils
from ec2api.api import proxy
from ec2api import exception from ec2api import exception
from ec2api.openstack.common.gettextutils import _
from ec2api.openstack.common import log as logging from ec2api.openstack.common import log as logging
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -58,14 +57,15 @@ class APIRequest(object):
self.controller = cloud.VpcCloudController() self.controller = cloud.VpcCloudController()
else: else:
self.controller = cloud.CloudController() self.controller = cloud.CloudController()
self.proxyController = proxy.ProxyController()
def invoke(self, context): def invoke(self, context):
try: try:
method = getattr(self.controller, method = getattr(self.controller,
ec2utils.camelcase_to_underscore(self.action)) ec2utils.camelcase_to_underscore(self.action))
except AttributeError: except AttributeError:
raise exception.MethodNotFound(name=self.action) LOG.exception(_('Unsupported API request: action = %(action)s'),
{'action': self.action})
raise exception.InvalidRequest()
args = ec2utils.dict_from_dotted_str(self.args.items()) args = ec2utils.dict_from_dotted_str(self.args.items())
@ -91,9 +91,6 @@ class APIRequest(object):
result = method(context, **args) result = method(context, **args)
return self._render_response(result, context.request_id) return self._render_response(result, context.request_id)
def proxy(self, req):
return self.proxyController.proxy(req, self.args)
def _render_response(self, response_data, request_id): def _render_response(self, response_data, request_id):
xml = minidom.Document() xml = minidom.Document()

View File

@ -1,222 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# 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.
import base64
import hashlib
import hmac
import re
import time
import types
import urllib
import urlparse
import httplib2
from lxml import etree
from oslo.config import cfg
from ec2api.api import ec2utils
from ec2api import exception
from ec2api.openstack.common import log as logging
ec2_opts = [
cfg.StrOpt('base_ec2_host',
default="localhost",
help='The IP address of the EC2 API server'),
cfg.IntOpt('base_ec2_port',
default=8773,
help='The port of the EC2 API server'),
cfg.StrOpt('base_ec2_scheme',
default='http',
help='The protocol to use when connecting to the EC2 API '
'server (http, https)'),
cfg.StrOpt('base_ec2_path',
default='/services/Cloud',
help='The path prefix used to call the ec2 API server'),
]
CONF = cfg.CONF
CONF.register_opts(ec2_opts)
LOG = logging.getLogger(__name__)
ISO8601 = '%Y-%m-%dT%H:%M:%SZ'
def ec2client(context):
return EC2Client(context)
class EC2Requester(object):
def __init__(self, version, http_method):
self.http_obj = httplib2.Http(
disable_ssl_certificate_validation=True)
self.version = version
self.method = http_method
def request(self, context, action, args):
headers = {
'content-type': 'application/x-www-form-urlencoded',
'connection': 'close',
}
params = args
params['Action'] = action
params['Version'] = self.version
self._add_auth(context, params)
params = self._get_query_string(params)
if self.method == 'POST':
url = self._ec2_url
body = params
else:
url = '?'.join((self._ec2_url, params,))
body = None
response, content = self.http_obj.request(url, self.method,
body=body, headers=headers)
return response, content
_ec2_url = '%s://%s:%s%s' % (CONF.base_ec2_scheme,
CONF.base_ec2_host,
CONF.base_ec2_port,
CONF.base_ec2_path)
@staticmethod
def _get_query_string(params):
pairs = []
for key in sorted(params):
value = params[key]
pairs.append(urllib.quote(key.encode('utf-8'), safe='') + '=' +
urllib.quote(value.encode('utf-8'), safe='-_~'))
return '&'.join(pairs)
def _calc_signature(self, context, params):
LOG.debug('Calculating signature using v2 auth.')
split = urlparse.urlsplit(self._ec2_url)
path = split.path
if len(path) == 0:
path = '/'
string_to_sign = '%s\n%s\n%s\n' % (self.method,
split.netloc,
path)
secret = context.secret_key
lhmac = hmac.new(secret.encode('utf-8'), digestmod=hashlib.sha256)
string_to_sign += self._get_query_string(params)
LOG.debug('String to sign: %s', string_to_sign)
lhmac.update(string_to_sign.encode('utf-8'))
b64 = base64.b64encode(lhmac.digest()).strip().decode('utf-8')
return b64
def _add_auth(self, context, params):
params['AWSAccessKeyId'] = context.access_key
params['SignatureVersion'] = '2'
params['SignatureMethod'] = 'HmacSHA256'
params['Timestamp'] = time.strftime(ISO8601, time.gmtime())
signature = self._calc_signature(context, params)
params['Signature'] = signature
class EC2Client(object):
def __init__(self, context):
self.context = context
self.requester = EC2Requester(context.api_version, 'POST')
def __getattr__(self, name):
ec2_name = self._underscore_to_camelcase(name)
def func(self, **kwargs):
params = self._build_params(**kwargs)
response, content = self.requester.request(self.context, ec2_name,
params)
return self._process_response(response, content)
func.__name__ = name
setattr(self, name, types.MethodType(func, self, self.__class__))
setattr(self.__class__, name,
types.MethodType(func, None, self.__class__))
return getattr(self, name)
@staticmethod
def _process_response(response, content):
if response.status > 200:
raise exception.EC2ServerError(response, content)
res = EC2Client._parse_xml(content)
res = next(res.itervalues())
if 'return' in res:
return res['return']
else:
res.pop('requestId')
return res
@staticmethod
def _build_params(**kwargs):
def add_list_param(params, items, label):
for i in range(1, len(items) + 1):
item = items[i - 1]
item_label = '%s.%d' % (label, i)
if isinstance(item, dict):
add_dict_param(params, item, item_label)
else:
params[item_label] = str(item)
def add_dict_param(params, items, label=None):
for key, value in items.iteritems():
ec2_key = EC2Client._underscore_to_camelcase(key)
item_label = '%s.%s' % (label, ec2_key) if label else ec2_key
if isinstance(value, dict):
add_dict_param(params, value, item_label)
elif isinstance(value, list):
add_list_param(params, value, item_label)
else:
params[item_label] = str(value)
params = {}
add_dict_param(params, kwargs)
return params
_xml_scheme = re.compile('\sxmlns=".*"')
@staticmethod
# NOTE(ft): this function is used in unit tests until it be moved to one
# of utils module
def _parse_xml(xml_string):
xml_string = EC2Client._xml_scheme.sub('', xml_string)
xml = etree.fromstring(xml_string)
def convert_node(node):
children = list(node)
if len(children):
if children[0].tag == 'item':
val = list(convert_node(child)[1] for child in children)
else:
val = dict(convert_node(child) for child in children)
elif node.tag.endswith('Set'):
val = []
else:
# TODO(ft): do not use private function
val = (ec2utils._try_convert(node.text)
if node.text
else node.text)
return node.tag, val
return dict([convert_node(xml)])
@staticmethod
# NOTE(ft): this function is copied from apirequest to avoid circular
# module reference. It should be moved to one of utils module
def _underscore_to_camelcase(st):
return ''.join([x[:1].upper() + x[1:] for x in st.split('_')])

View File

@ -152,29 +152,9 @@ def is_ec2_timestamp_expired(request, expires=None):
return True return True
def id_to_glance_id(context, image_id):
"""Convert an internal (db) id to a glance id."""
return novadb.s3_image_get(context, image_id)['uuid']
def glance_id_to_id(context, glance_id):
"""Convert a glance id to an internal (db) id."""
if glance_id is None:
return
try:
return novadb.s3_image_get_by_uuid(context, glance_id)['id']
except exception.NotFound:
return novadb.s3_image_create(context, glance_id)['id']
def ec2_id_to_glance_id(context, ec2_id): def ec2_id_to_glance_id(context, ec2_id):
image_id = ec2_id_to_id(ec2_id) image_id = ec2_id_to_id(ec2_id)
return id_to_glance_id(context, image_id) return novadb.s3_image_get(context, image_id)['uuid']
def glance_id_to_ec2_id(context, glance_id, image_type='ami'):
image_id = glance_id_to_id(context, glance_id)
return image_ec2_id(image_id, image_type=image_type)
# TODO(Alex) This function is copied as is from original cloud.py. It doesn't # TODO(Alex) This function is copied as is from original cloud.py. It doesn't
@ -187,12 +167,6 @@ def ec2_id_to_id(ec2_id):
raise exception.InvalidId(id=ec2_id) raise exception.InvalidId(id=ec2_id)
def image_ec2_id(image_id, image_type='ami'):
"""Returns image ec2_id using id and three letter type."""
template = image_type + '-%08x'
return id_to_ec2_id(image_id, template=template)
def id_to_ec2_id(instance_id, template='i-%08x'): def id_to_ec2_id(instance_id, template='i-%08x'):
"""Convert an instance ID (int) to an ec2 ID (i-[base 16 number]).""" """Convert an instance ID (int) to an ec2 ID (i-[base 16 number])."""
return template % int(instance_id) return template % int(instance_id)
@ -204,7 +178,7 @@ def id_to_ec2_inst_id(instance_id):
return None return None
elif uuidutils.is_uuid_like(instance_id): elif uuidutils.is_uuid_like(instance_id):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
int_id = get_int_id_from_instance_uuid(ctxt, instance_id) int_id = _get_int_id_from_instance_uuid(ctxt, instance_id)
return id_to_ec2_id(int_id) return id_to_ec2_id(int_id)
else: else:
return id_to_ec2_id(instance_id) return id_to_ec2_id(instance_id)
@ -213,14 +187,14 @@ def id_to_ec2_inst_id(instance_id):
def ec2_inst_id_to_uuid(context, ec2_id): def ec2_inst_id_to_uuid(context, ec2_id):
""""Convert an instance id to uuid.""" """"Convert an instance id to uuid."""
int_id = ec2_id_to_id(ec2_id) int_id = ec2_id_to_id(ec2_id)
return get_instance_uuid_from_int_id(context, int_id) return _get_instance_uuid_from_int_id(context, int_id)
def get_instance_uuid_from_int_id(context, int_id): def _get_instance_uuid_from_int_id(context, int_id):
return novadb.get_instance_uuid_by_ec2_id(context, int_id) return novadb.get_instance_uuid_by_ec2_id(context, int_id)
def get_int_id_from_instance_uuid(context, instance_uuid): def _get_int_id_from_instance_uuid(context, instance_uuid):
if instance_uuid is None: if instance_uuid is None:
return return
try: try:
@ -229,69 +203,6 @@ def get_int_id_from_instance_uuid(context, instance_uuid):
return novadb.ec2_instance_create(context, instance_uuid)['id'] return novadb.ec2_instance_create(context, instance_uuid)['id']
def get_volume_uuid_from_int_id(context, int_id):
return novadb.get_volume_uuid_by_ec2_id(context, int_id)
def id_to_ec2_snap_id(snapshot_id):
"""Get or create an ec2 volume ID (vol-[base 16 number]) from uuid."""
if uuidutils.is_uuid_like(snapshot_id):
ctxt = context.get_admin_context()
int_id = get_int_id_from_snapshot_uuid(ctxt, snapshot_id)
return id_to_ec2_id(int_id, 'snap-%08x')
else:
return id_to_ec2_id(snapshot_id, 'snap-%08x')
def id_to_ec2_vol_id(volume_id):
"""Get or create an ec2 volume ID (vol-[base 16 number]) from uuid."""
if uuidutils.is_uuid_like(volume_id):
ctxt = context.get_admin_context()
int_id = get_int_id_from_volume_uuid(ctxt, volume_id)
return id_to_ec2_id(int_id, 'vol-%08x')
else:
return id_to_ec2_id(volume_id, 'vol-%08x')
def get_int_id_from_volume_uuid(context, volume_uuid):
if volume_uuid is None:
return
try:
return novadb.get_ec2_volume_id_by_uuid(context, volume_uuid)
except exception.NotFound:
return novadb.ec2_volume_create(context, volume_uuid)['id']
def ec2_vol_id_to_uuid(ec2_id):
"""Get the corresponding UUID for the given ec2-id."""
ctxt = context.get_admin_context()
# NOTE(jgriffith) first strip prefix to get just the numeric
int_id = ec2_id_to_id(ec2_id)
return get_volume_uuid_from_int_id(ctxt, int_id)
def get_snapshot_uuid_from_int_id(context, int_id):
return novadb.get_snapshot_uuid_by_ec2_id(context, int_id)
def ec2_snap_id_to_uuid(ec2_id):
"""Get the corresponding UUID for the given ec2-id."""
ctxt = context.get_admin_context()
# NOTE(jgriffith) first strip prefix to get just the numeric
int_id = ec2_id_to_id(ec2_id)
return get_snapshot_uuid_from_int_id(ctxt, int_id)
def get_int_id_from_snapshot_uuid(context, snapshot_uuid):
if snapshot_uuid is None:
return
try:
return novadb.get_ec2_snapshot_id_by_uuid(context, snapshot_uuid)
except exception.NotFound:
return novadb.ec2_snapshot_create(context, snapshot_uuid)['id']
# NOTE(ft): extra functions to use in vpc specific code or instead of # NOTE(ft): extra functions to use in vpc specific code or instead of
# malformed existed functions # malformed existed functions

View File

@ -1,27 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# 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.
from ec2api.api import ec2client
class ProxyController(object):
def __str__(self):
return 'ProxyController'
def proxy(self, req, args):
requester = ec2client.EC2Requester(req.params["Version"],
req.environ["REQUEST_METHOD"])
return requester.request(req.environ['ec2api.context'],
req.params["Action"], args)

View File

@ -28,7 +28,8 @@ def create_volume(context, availability_zone=None, size=None,
description=None, metadata=None, iops=None, encrypted=None, description=None, metadata=None, iops=None, encrypted=None,
kms_key_id=None): kms_key_id=None):
if snapshot_id is not None: if snapshot_id is not None:
os_snapshot_id = ec2utils.ec2_snap_id_to_uuid(snapshot_id) snapshot = ec2utils.get_db_item(context, 'snap', snapshot_id)
os_snapshot_id = snapshot['os_id']
else: else:
os_snapshot_id = None os_snapshot_id = None

View File

@ -18,12 +18,12 @@ from ec2api.openstack.common.db import options
from ec2api import paths from ec2api import paths
from ec2api import version from ec2api import version
_DEFAULT_SQL_CONNECTION = 'sqlite:///' + paths.state_path_def('nova.sqlite') _DEFAULT_SQL_CONNECTION = 'sqlite:///' + paths.state_path_def('ec2api.sqlite')
def parse_args(argv, default_config_files=None): def parse_args(argv, default_config_files=None):
options.set_defaults(sql_connection=_DEFAULT_SQL_CONNECTION, options.set_defaults(sql_connection=_DEFAULT_SQL_CONNECTION,
sqlite_db='nova.sqlite') sqlite_db='ec2api.sqlite')
cfg.CONF(argv[1:], cfg.CONF(argv[1:],
project='ec2api', project='ec2api',
version=version.version_info.version_string(), version=version.version_info.version_string(),

View File

@ -25,7 +25,6 @@ from sqlalchemy import and_
from sqlalchemy import or_ from sqlalchemy import or_
from sqlalchemy.sql import bindparam from sqlalchemy.sql import bindparam
from ec2api.api import ec2utils
import ec2api.context import ec2api.context
from ec2api.db.sqlalchemy import models from ec2api.db.sqlalchemy import models
from ec2api.openstack.common.db import exception as db_exception from ec2api.openstack.common.db import exception as db_exception
@ -91,20 +90,8 @@ def model_query(context, model, *args, **kwargs):
def _new_id(kind, os_id): def _new_id(kind, os_id):
# NOTE(ft): obtaining new id from Nova DB is temporary solution obj_id = "%(kind)s-%(id)08x" % {"kind": kind,
# while we don't implmenet all Nova EC2 methods "id": random.randint(1, 0xffffffff)}
if kind == 'i':
obj_id = ec2utils.id_to_ec2_inst_id(os_id)
elif kind == 'vol':
obj_id = ec2utils.id_to_ec2_vol_id(os_id)
elif kind == 'snap':
obj_id = ec2utils.id_to_ec2_snap_id(os_id)
elif kind in ('ami', 'ari', 'aki'):
obj_id = ec2utils.glance_id_to_ec2_id(
ec2api.context.get_admin_context(), os_id, kind)
else:
obj_id = "%(kind)s-%(id)08x" % {"kind": kind,
"id": random.randint(1, 0xffffffff)}
return obj_id return obj_id

View File

@ -133,10 +133,6 @@ class PasteAppNotFound(EC2Exception):
msg_fmt = _("Could not load paste app '%(name)s' from %(path)s") msg_fmt = _("Could not load paste app '%(name)s' from %(path)s")
class MethodNotFound(EC2Exception):
msg_fmt = _("Could not find method '%(name)s'")
class Forbidden(EC2Exception): class Forbidden(EC2Exception):
ec2_code = 'AuthFailure' ec2_code = 'AuthFailure'
msg_fmt = _("Not authorized.") msg_fmt = _("Not authorized.")
@ -166,16 +162,6 @@ class NovaDbImageNotFound(EC2NotFound):
msg_fmt = _("The image id '[%(image_id)s]' does not exist") msg_fmt = _("The image id '[%(image_id)s]' does not exist")
class NovaDbVolumeNotFound(EC2NotFound):
ec2_code = 'InvalidVolume.NotFound'
msg_fmt = _("Volume %(volume_id)s could not be found.")
class NovaDbSnapshotNotFound(EC2NotFound):
ec2_code = 'InvalidSnapshot.NotFound'
msg_fmt = _("Snapshot %(snapshot_id)s could not be found.")
class NovaDbInstanceNotFound(EC2NotFound): class NovaDbInstanceNotFound(EC2NotFound):
ec2_code = 'InvalidInstanceID.NotFound' ec2_code = 'InvalidInstanceID.NotFound'
msg_fmt = _("Instance %(instance_id)s could not be found.") msg_fmt = _("Instance %(instance_id)s could not be found.")

View File

@ -85,43 +85,6 @@ def s3_image_get(context, image_id):
return IMPL.s3_image_get(context, image_id) return IMPL.s3_image_get(context, image_id)
def s3_image_get_by_uuid(context, image_uuid):
"""Find local s3 image represented by the provided uuid."""
return IMPL.s3_image_get_by_uuid(context, image_uuid)
def s3_image_create(context, image_uuid):
"""Create local s3 image represented by provided uuid."""
return IMPL.s3_image_create(context, image_uuid)
###################
def get_ec2_volume_id_by_uuid(context, volume_id):
return IMPL.get_ec2_volume_id_by_uuid(context, volume_id)
def get_volume_uuid_by_ec2_id(context, ec2_id):
return IMPL.get_volume_uuid_by_ec2_id(context, ec2_id)
def ec2_volume_create(context, volume_id, forced_id=None):
return IMPL.ec2_volume_create(context, volume_id, forced_id)
def get_snapshot_uuid_by_ec2_id(context, ec2_id):
return IMPL.get_snapshot_uuid_by_ec2_id(context, ec2_id)
def get_ec2_snapshot_id_by_uuid(context, snapshot_id):
return IMPL.get_ec2_snapshot_id_by_uuid(context, snapshot_id)
def ec2_snapshot_create(context, snapshot_id, forced_id=None):
return IMPL.ec2_snapshot_create(context, snapshot_id, forced_id)
################### ###################
@ -140,14 +103,6 @@ def ec2_instance_create(context, instance_uuid, id=None):
return IMPL.ec2_instance_create(context, instance_uuid, id) return IMPL.ec2_instance_create(context, instance_uuid, id)
def ec2_instance_get_by_uuid(context, instance_uuid):
return IMPL.ec2_instance_get_by_uuid(context, instance_uuid)
def ec2_instance_get_by_id(context, instance_id):
return IMPL.ec2_instance_get_by_id(context, instance_id)
def instance_get_by_uuid(context, uuid, columns_to_join=None, use_slave=False): def instance_get_by_uuid(context, uuid, columns_to_join=None, use_slave=False):
"""Get an instance or raise if it does not exist.""" """Get an instance or raise if it does not exist."""
return IMPL.instance_get_by_uuid(context, uuid, return IMPL.instance_get_by_uuid(context, uuid,

View File

@ -26,7 +26,6 @@ from sqlalchemy import or_
import ec2api.context import ec2api.context
from ec2api import exception from ec2api import exception
from ec2api.novadb.sqlalchemy import models from ec2api.novadb.sqlalchemy import models
from ec2api.openstack.common.db import exception as db_exc
from ec2api.openstack.common.db.sqlalchemy import session as db_session from ec2api.openstack.common.db.sqlalchemy import session as db_session
from ec2api.openstack.common.gettextutils import _ from ec2api.openstack.common.gettextutils import _
from ec2api.openstack.common import log as logging from ec2api.openstack.common import log as logging
@ -179,118 +178,6 @@ def s3_image_get(context, image_id):
return result return result
def s3_image_get_by_uuid(context, image_uuid):
"""Find local s3 image represented by the provided uuid."""
result = (model_query(context, models.S3Image, read_deleted="yes").
filter_by(uuid=image_uuid).
first())
if not result:
raise exception.NovaDbImageNotFound(image_id=image_uuid)
return result
def s3_image_create(context, image_uuid):
"""Create local s3 image represented by provided uuid."""
try:
s3_image_ref = models.S3Image()
s3_image_ref.update({'uuid': image_uuid})
s3_image_ref.save()
except Exception as e:
raise db_exc.DBError(e)
return s3_image_ref
##################
def _ec2_volume_get_query(context, session=None):
return model_query(context, models.VolumeIdMapping,
session=session, read_deleted='yes')
def _ec2_snapshot_get_query(context, session=None):
return model_query(context, models.SnapshotIdMapping,
session=session, read_deleted='yes')
@require_context
def ec2_volume_create(context, volume_uuid, id=None):
"""Create ec2 compatible volume by provided uuid."""
ec2_volume_ref = models.VolumeIdMapping()
ec2_volume_ref.update({'uuid': volume_uuid})
if id is not None:
ec2_volume_ref.update({'id': id})
ec2_volume_ref.save()
return ec2_volume_ref
@require_context
def get_ec2_volume_id_by_uuid(context, volume_id):
result = (_ec2_volume_get_query(context).
filter_by(uuid=volume_id).
first())
if not result:
raise exception.NovaDbVolumeNotFound(volume_id=volume_id)
return result['id']
@require_context
def get_volume_uuid_by_ec2_id(context, ec2_id):
result = (model_query(context, models.VolumeIdMapping, read_deleted='yes').
filter_by(id=ec2_id).
first())
if not result:
raise exception.NovaDbVolumeNotFound(volume_id=ec2_id)
return result['uuid']
@require_context
def ec2_snapshot_create(context, snapshot_uuid, id=None):
"""Create ec2 compatible snapshot by provided uuid."""
ec2_snapshot_ref = models.SnapshotIdMapping()
ec2_snapshot_ref.update({'uuid': snapshot_uuid})
if id is not None:
ec2_snapshot_ref.update({'id': id})
ec2_snapshot_ref.save()
return ec2_snapshot_ref
@require_context
def get_ec2_snapshot_id_by_uuid(context, snapshot_id):
result = (_ec2_snapshot_get_query(context).
filter_by(uuid=snapshot_id).
first())
if not result:
raise exception.NovaDbSnapshotNotFound(snapshot_id=snapshot_id)
return result['id']
@require_context
def get_snapshot_uuid_by_ec2_id(context, ec2_id):
result = (model_query(context, models.SnapshotIdMapping,
read_deleted='yes').
filter_by(id=ec2_id).
first())
if not result:
raise exception.NovaDbSnapshotNotFound(snapshot_id=ec2_id)
return result['uuid']
################### ###################
@ -308,7 +195,7 @@ def ec2_instance_create(context, instance_uuid, id=None):
@require_context @require_context
def ec2_instance_get_by_uuid(context, instance_uuid): def _ec2_instance_get_by_uuid(context, instance_uuid):
result = (_ec2_instance_get_query(context). result = (_ec2_instance_get_query(context).
filter_by(uuid=instance_uuid). filter_by(uuid=instance_uuid).
first()) first())
@ -321,12 +208,12 @@ def ec2_instance_get_by_uuid(context, instance_uuid):
@require_context @require_context
def get_ec2_instance_id_by_uuid(context, instance_id): def get_ec2_instance_id_by_uuid(context, instance_id):
result = ec2_instance_get_by_uuid(context, instance_id) result = _ec2_instance_get_by_uuid(context, instance_id)
return result['id'] return result['id']
@require_context @require_context
def ec2_instance_get_by_id(context, instance_id): def _ec2_instance_get_by_id(context, instance_id):
result = (_ec2_instance_get_query(context). result = (_ec2_instance_get_query(context).
filter_by(id=instance_id). filter_by(id=instance_id).
first()) first())
@ -339,7 +226,7 @@ def ec2_instance_get_by_id(context, instance_id):
@require_context @require_context
def get_instance_uuid_by_ec2_id(context, ec2_id): def get_instance_uuid_by_ec2_id(context, ec2_id):
result = ec2_instance_get_by_id(context, ec2_id) result = _ec2_instance_get_by_id(context, ec2_id)
return result['uuid'] return result['uuid']

View File

@ -59,22 +59,6 @@ class S3Image(BASE, NovaBase):
uuid = Column(String(36), nullable=False) uuid = Column(String(36), nullable=False)
class VolumeIdMapping(BASE, NovaBase):
"""Compatibility layer for the EC2 volume service."""
__tablename__ = 'volume_id_mappings'
__table_args__ = ()
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
uuid = Column(String(36), nullable=False)
class SnapshotIdMapping(BASE, NovaBase):
"""Compatibility layer for the EC2 snapshot service."""
__tablename__ = 'snapshot_id_mappings'
__table_args__ = ()
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
uuid = Column(String(36), nullable=False)
class InstanceIdMapping(BASE, NovaBase): class InstanceIdMapping(BASE, NovaBase):
"""Compatibility layer for the EC2 instance service.""" """Compatibility layer for the EC2 instance service."""
__tablename__ = 'instance_id_mappings' __tablename__ = 'instance_id_mappings'

View File

@ -17,9 +17,9 @@ import mock
from oslotest import base as test_base from oslotest import base as test_base
import ec2api.api.apirequest import ec2api.api.apirequest
from ec2api.api import ec2client
from ec2api.tests import fakes from ec2api.tests import fakes
from ec2api.tests import matchers from ec2api.tests import matchers
from ec2api.tests import tools
import ec2api.wsgi import ec2api.wsgi
@ -58,14 +58,6 @@ class ApiTestCase(test_base.BaseTestCase):
mock.patch('ec2api.api.ec2utils.ec2_inst_id_to_uuid')) mock.patch('ec2api.api.ec2utils.ec2_inst_id_to_uuid'))
self.ec2_inst_id_to_uuid = ec2_inst_id_to_uuid_patcher.start() self.ec2_inst_id_to_uuid = ec2_inst_id_to_uuid_patcher.start()
self.addCleanup(ec2_inst_id_to_uuid_patcher.stop) self.addCleanup(ec2_inst_id_to_uuid_patcher.stop)
# TODO(ft): patch EC2Client object instead of ec2client function
# to make this similar to other patchers (neutron)
# Now it's impossible since tests use EC2Client._parse_xml
# Or patch neutron client function too, and make tests on client
# functions
ec2_patcher = mock.patch('ec2api.api.ec2client.ec2client')
self.ec2 = ec2_patcher.start().return_value
self.addCleanup(ec2_patcher.stop)
isotime_patcher = mock.patch('ec2api.openstack.common.timeutils.' isotime_patcher = mock.patch('ec2api.openstack.common.timeutils.'
'isotime') 'isotime')
self.isotime = isotime_patcher.start() self.isotime = isotime_patcher.start()
@ -90,7 +82,7 @@ class ApiTestCase(test_base.BaseTestCase):
'endpoints': [{'publicUrl': 'fake_url'}]}]) 'endpoints': [{'publicUrl': 'fake_url'}]}])
def _check_and_transform_response(self, response, action): def _check_and_transform_response(self, response, action):
body = ec2client.EC2Client._parse_xml(response.body) body = tools.parse_xml(response.body)
if response.status_code == 200: if response.status_code == 200:
action_tag = '%sResponse' % action action_tag = '%sResponse' % action
self.assertIn(action_tag, body) self.assertIn(action_tag, body)

View File

@ -20,7 +20,6 @@ from oslotest import base as test_base
from ec2api import api from ec2api import api
from ec2api.api import apirequest from ec2api.api import apirequest
from ec2api.api import cloud
from ec2api import exception from ec2api import exception
from ec2api.tests import fakes_request_response as fakes from ec2api.tests import fakes_request_response as fakes
from ec2api.tests import matchers from ec2api.tests import matchers
@ -35,10 +34,6 @@ class ApiInitTestCase(test_base.BaseTestCase):
def setUp(self): def setUp(self):
super(ApiInitTestCase, self).setUp() super(ApiInitTestCase, self).setUp()
requester_patcher = mock.patch('ec2api.api.ec2client.EC2Requester')
self.requester_class = requester_patcher.start()
self.requester = self.requester_class.return_value
self.addCleanup(requester_patcher.stop)
controller_patcher = mock.patch('ec2api.api.cloud.VpcCloudController') controller_patcher = mock.patch('ec2api.api.cloud.VpcCloudController')
self.controller_class = controller_patcher.start() self.controller_class = controller_patcher.start()
@ -94,36 +89,3 @@ class ApiInitTestCase(test_base.BaseTestCase):
'KeyError', 'Unknown error occurred.') 'KeyError', 'Unknown error occurred.')
do_check(exception.InvalidVpcIDNotFound('fake_msg'), 400, do_check(exception.InvalidVpcIDNotFound('fake_msg'), 400,
'InvalidVpcID.NotFound', 'fake_msg') 'InvalidVpcID.NotFound', 'fake_msg')
def test_execute_proxy(self):
self.controller_class.return_value = mock.create_autospec(
cloud.CloudController, instance=True)
# NOTE(ft): recreate APIRequest to use mock with autospec
ec2_request = apirequest.APIRequest('FakeAction', 'fake_v1',
{'Param': 'fake_param'})
self.environ['ec2.request'] = ec2_request
self.environ['QUERY_STRING'] = 'Version=fake_v1&Action=FakeAction'
self.requester.request.return_value = ({'status': 200,
'content-type': 'fake_type'},
'fake_data')
res = self.request.send(self.application)
self.requester_class.assert_called_once_with('fake_v1', 'FAKE')
self.requester.request.assert_called_once_with(self.fake_context,
'FakeAction',
{'Param': 'fake_param'})
self.assertEqual(200, res.status_code)
self.assertEqual('fake_type', res.content_type)
self.assertEqual('fake_data', res.body)
def test_execute_proxy_error(self):
self.controller.fake_action.side_effect = exception.EC2ServerError(
{'status': 400, 'content-type': 'fake_type'},
'fake_content')
res = self.request.send(self.application)
self.assertEqual(400, res.status_code)
self.assertEqual('fake_type', res.content_type)
self.assertEqual('fake_content', res.body)

View File

@ -20,7 +20,6 @@ import mock
from oslotest import base as test_base from oslotest import base as test_base
from ec2api.api import apirequest from ec2api.api import apirequest
from ec2api.api import ec2client
from ec2api.tests import fakes_request_response as fakes from ec2api.tests import fakes_request_response as fakes
from ec2api.tests import matchers from ec2api.tests import matchers
from ec2api.tests import tools from ec2api.tests import tools
@ -35,9 +34,6 @@ class EC2RequesterTestCase(test_base.BaseTestCase):
def setUp(self): def setUp(self):
super(EC2RequesterTestCase, self).setUp() super(EC2RequesterTestCase, self).setUp()
requester_patcher = mock.patch('ec2api.api.ec2client.EC2Requester')
self.requester = requester_patcher.start().return_value
self.addCleanup(requester_patcher.stop)
controller_patcher = mock.patch('ec2api.api.cloud.VpcCloudController') controller_patcher = mock.patch('ec2api.api.cloud.VpcCloudController')
self.controller = controller_patcher.start().return_value self.controller = controller_patcher.start().return_value
@ -89,7 +85,7 @@ class EC2RequesterTestCase(test_base.BaseTestCase):
# based on the order of tags # based on the order of tags
xml = etree.fromstring(observed) xml = etree.fromstring(observed)
self.assertEqual(xmlns, xml.nsmap.get(None)) self.assertEqual(xmlns, xml.nsmap.get(None))
observed_data = ec2client.EC2Client._parse_xml(observed) observed_data = tools.parse_xml(observed)
expected = {root_tag: tools.update_dict(dict_data, expected = {root_tag: tools.update_dict(dict_data,
{'requestId': request_id})} {'requestId': request_id})}
self.assertThat(observed_data, matchers.DictMatches(expected)) self.assertThat(observed_data, matchers.DictMatches(expected))

View File

@ -1,172 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# 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.
import collections
import time
import mock
from oslotest import base as test_base
from ec2api.api import ec2client
from ec2api import exception
from ec2api.tests import fakes_request_response as fakes
from ec2api.tests import matchers
class EC2RequesterTestCase(test_base.BaseTestCase):
fake_context_class = collections.namedtuple('FakeContext', ['access_key',
'secret_key'])
def setUp(self):
super(EC2RequesterTestCase, self).setUp()
httplib2_patcher = mock.patch('ec2api.api.ec2client.httplib2')
self.httplib2 = httplib2_patcher.start()
self.addCleanup(httplib2_patcher.stop)
gmtime_patcher = mock.patch('ec2api.api.ec2client.time.gmtime')
self.gmtime = gmtime_patcher.start()
self.addCleanup(gmtime_patcher.stop)
def test_post_request(self):
http_obj = self.httplib2.Http.return_value
http_obj.request.return_value = ('fake_response', 'fake_context',)
self.gmtime.return_value = time.struct_time((2014, 6, 13,
7, 43, 54, 4, 164, 0,))
requester = ec2client.EC2Requester('fake_v1', 'POST')
requester._ec2_url = 'http://fake.host.com:1234/fake_Service'
context = self.fake_context_class('caeafa52dda845d78a54786aa2ad355b',
'f889ec080e094a92badb6f6ba0253393')
result = requester.request(context, 'FakeAction',
{'Arg1': 'Val1', 'Arg2': 'Val2'})
http_obj.request.assert_called_once_with(
'http://fake.host.com:1234/fake_Service',
'POST',
body='AWSAccessKeyId=caeafa52dda845d78a54786aa2ad355b&'
'Action=FakeAction&Arg1=Val1&Arg2=Val2&Signature='
'uBRxsBHetogWlgv%2FHJnJLK0vBMEChm1LFX%2BH9U1kjHo%3D&'
'SignatureMethod=HmacSHA256&SignatureVersion=2&'
'Timestamp=2014-06-13T07%3A43%3A54Z&Version=fake_v1',
headers={'content-type': 'application/x-www-form-urlencoded',
'connection': 'close'})
self.assertEqual(('fake_response', 'fake_context',), result)
def test_get_request(self):
http_obj = self.httplib2.Http.return_value
http_obj.request.return_value = ('fake_response', 'fake_context',)
self.gmtime.return_value = time.struct_time((2014, 6, 14,
10, 6, 16, 5, 165, 0,))
requester = ec2client.EC2Requester('fake_v1', 'GET')
requester._ec2_url = 'http://fake.host.com'
context = self.fake_context_class('c1ba55bbcaeb4b41bc9a6d5344392825',
'24aaf70906fe4d799f6360d7cd6320ba')
result = requester.request(context, 'FakeAction',
{'Arg1': 'Val1', 'Arg2': 'Val2'})
http_obj.request.assert_called_once_with(
'http://fake.host.com?'
'AWSAccessKeyId=c1ba55bbcaeb4b41bc9a6d5344392825&'
'Action=FakeAction&Arg1=Val1&Arg2=Val2&Signature='
'puCc5v7kjOLibLTaT5bDp%2FPcgtbWMGt3kvh54z%2BpedE%3D&'
'SignatureMethod=HmacSHA256&SignatureVersion=2&'
'Timestamp=2014-06-14T10%3A06%3A16Z&Version=fake_v1',
'GET',
body=None,
headers={'content-type': 'application/x-www-form-urlencoded',
'connection': 'close'})
self.assertEqual(('fake_response', 'fake_context',), result)
class EC2ClientTestCase(test_base.BaseTestCase):
fake_response_class = collections.namedtuple('response', ['status'])
def test_ec2_xml_to_json_on_fake_result(self):
json = ec2client.EC2Client._parse_xml(fakes.XML_FAKE_RESULT)
self.assertIsInstance(json, dict)
self.assertThat(fakes.DICT_FAKE_RESULT, matchers.DictMatches(json))
def test_ec2_xml_to_json_on_single_result(self):
json = ec2client.EC2Client._parse_xml(fakes.XML_SINGLE_RESULT)
self.assertIsInstance(json, dict)
self.assertThat(fakes.DICT_SINGLE_RESULT, matchers.DictMatches(json))
def test_ec2_xml_to_json_on_result_set(self):
json = ec2client.EC2Client._parse_xml(fakes.XML_RESULT_SET)
self.assertIsInstance(json, dict)
self.assertThat(fakes.DICT_RESULT_SET, matchers.DictMatches(json))
def test_ec2_xml_to_json_on_empty_result_set(self):
json = ec2client.EC2Client._parse_xml(fakes.XML_EMPTY_RESULT_SET)
self.assertIsInstance(json, dict)
self.assertThat(fakes.DICT_EMPTY_RESULT_SET,
matchers.DictMatches(json))
def test_ec2_xml_to_json_on_error(self):
json = ec2client.EC2Client._parse_xml(fakes.XML_ERROR)
self.assertIsInstance(json, dict)
self.assertThat(fakes.DICT_ERROR, matchers.DictMatches(json))
def test_process_response_on_data_result(self):
response = self.fake_response_class(200)
json = ec2client.EC2Client._process_response(response,
fakes.XML_FAKE_RESULT)
self.assertThat(json,
matchers.DictMatches(fakes.DICT_FAKE_RESULT_DATA))
def test_process_response_on_ok_result(self):
response = self.fake_response_class(200)
result = ec2client.EC2Client._process_response(
response, fakes.XML_SILENT_OPERATIN_RESULT)
self.assertEqual(True, result)
def test_process_response_on_error(self):
response = self.fake_response_class(400)
try:
ec2client.EC2Client._process_response(response, fakes.XML_ERROR)
except exception.EC2ServerError as ex:
self.assertEqual(response, ex.response)
self.assertEqual(fakes.XML_ERROR, ex.content)
except Exception as ex:
self.fail('%s was raised instead of '
'ec2api.exception.EC2ServerError' % str(ex))
else:
self.fail('No ec2api.exception.EC2ServerError was raised')
def test_build_params(self):
ec2_params = ec2client.EC2Client._build_params(
**fakes.DICT_FAKE_PARAMS)
self.assertThat(ec2_params,
matchers.DictMatches(fakes.DOTTED_FAKE_PARAMS))
@mock.patch('ec2api.api.ec2client.EC2Requester')
def test_call_action(self, requester_class):
requester = requester_class.return_value
fake_response = self.fake_response_class(200)
requester.request.return_value = (fake_response,
fakes.XML_FAKE_RESULT,)
fake_context_class = collections.namedtuple('FakeContext',
['api_version'])
fake_context = fake_context_class('fake_v1')
ec2 = ec2client.ec2client(fake_context)
json = ec2.fake_action(fake_int=1234, fake_str='fake')
self.assertThat(json,
matchers.DictMatches(fakes.DICT_FAKE_RESULT_DATA))
requester_class.assert_called_once_with('fake_v1', 'POST')
requester.request.assert_called_once_with(
fake_context, 'FakeAction',
{'FakeInt': '1234', 'FakeStr': 'fake'})

View File

@ -52,10 +52,6 @@ class InstanceTestCase(base.ApiTestCase):
novadb_patcher = (mock.patch('ec2api.api.instance.novadb')) novadb_patcher = (mock.patch('ec2api.api.instance.novadb'))
self.novadb = novadb_patcher.start() self.novadb = novadb_patcher.start()
self.addCleanup(novadb_patcher.stop) self.addCleanup(novadb_patcher.stop)
glance_id_to_ec2_id_patcher = (
mock.patch('ec2api.api.instance.ec2utils.glance_id_to_ec2_id'))
self.glance_id_to_ec2_id = glance_id_to_ec2_id_patcher.start()
self.addCleanup(glance_id_to_ec2_id_patcher.stop)
self.fake_image_class = collections.namedtuple( self.fake_image_class = collections.namedtuple(
'FakeImage', ['id', 'status', 'properties']) 'FakeImage', ['id', 'status', 'properties'])
@ -83,8 +79,6 @@ class InstanceTestCase(base.ApiTestCase):
self.utils_generate_uid.return_value = fakes.ID_EC2_RESERVATION_1 self.utils_generate_uid.return_value = fakes.ID_EC2_RESERVATION_1
self.glance.images.get.return_value = fakes.OSImage(fakes.OS_IMAGE_1) self.glance.images.get.return_value = fakes.OSImage(fakes.OS_IMAGE_1)
# self.ec2_id_to_glance_id.return_value = 'fake_image_id'
# self.glance_id_to_ec2_id.return_value = None
fake_flavor = self.fake_flavor_class('fake_flavor') fake_flavor = self.fake_flavor_class('fake_flavor')
self.nova_flavors.list.return_value = [fake_flavor] self.nova_flavors.list.return_value = [fake_flavor]
self.nova_servers.create.return_value = ( self.nova_servers.create.return_value = (
@ -156,7 +150,6 @@ class InstanceTestCase(base.ApiTestCase):
self.create_network_interface.reset_mock() self.create_network_interface.reset_mock()
self.nova_servers.reset_mock() self.nova_servers.reset_mock()
self.ec2.reset_mock()
self.db_api.reset_mock() self.db_api.reset_mock()
self.isotime.reset_mock() self.isotime.reset_mock()
@ -217,13 +210,6 @@ class InstanceTestCase(base.ApiTestCase):
self.create_network_interface.side_effect = ( self.create_network_interface.side_effect = (
[{'networkInterface': eni} [{'networkInterface': eni}
for eni in self.EC2_DETACHED_ENIS]) for eni in self.EC2_DETACHED_ENIS])
self.ec2.describe_instances.return_value = {
'reservationSet': [
fakes.gen_ec2_reservation(
fakes.ID_EC2_RESERVATION_1,
[fakes.gen_ec2_instance(ec2_instance_id,
private_ip_address=None)
for ec2_instance_id in self.IDS_EC2_INSTANCE])]}
self.nova_servers.create.side_effect = [ self.nova_servers.create.side_effect = [
self.fake_instance_class(os_instance_id) self.fake_instance_class(os_instance_id)
for os_instance_id in self.IDS_OS_INSTANCE] for os_instance_id in self.IDS_OS_INSTANCE]
@ -422,8 +408,6 @@ class InstanceTestCase(base.ApiTestCase):
fakes.ID_EC2_INSTANCE_2: fakes.ID_OS_INSTANCE_2} fakes.ID_EC2_INSTANCE_2: fakes.ID_OS_INSTANCE_2}
self.ec2_inst_id_to_uuid.side_effect = ( self.ec2_inst_id_to_uuid.side_effect = (
lambda _, inst_id: os_instance_ids_dict[inst_id]) lambda _, inst_id: os_instance_ids_dict[inst_id])
self.ec2.terminate_instances.return_value = (
ec2_terminate_instances_result)
def do_check(mock_port_list=[], mock_eni_list=[], def do_check(mock_port_list=[], mock_eni_list=[],
updated_ports=[], deleted_ports=[]): updated_ports=[], deleted_ports=[]):
@ -443,8 +427,6 @@ class InstanceTestCase(base.ApiTestCase):
self.ec2_inst_id_to_uuid.assert_any_call( self.ec2_inst_id_to_uuid.assert_any_call(
mock.ANY, inst_id) mock.ANY, inst_id)
self._assert_list_ports_is_called_with_filter(self.IDS_OS_INSTANCE) self._assert_list_ports_is_called_with_filter(self.IDS_OS_INSTANCE)
self.ec2.terminate_instances.assert_called_once_with(
instance_id=self.IDS_EC2_INSTANCE)
self.assertEqual(len(updated_ports), self.assertEqual(len(updated_ports),
self.neutron.update_port.call_count) self.neutron.update_port.call_count)
self.assertEqual(len(updated_ports), self.assertEqual(len(updated_ports),
@ -469,7 +451,6 @@ class InstanceTestCase(base.ApiTestCase):
self.ec2_inst_id_to_uuid.reset_mock() self.ec2_inst_id_to_uuid.reset_mock()
self.neutron.list_ports.reset_mock() self.neutron.list_ports.reset_mock()
self.neutron.update_port.reset_mock() self.neutron.update_port.reset_mock()
self.ec2.terminate_instances.reset_mock()
self.db_api.delete_item.reset_mock() self.db_api.delete_item.reset_mock()
self.db_api.update_item.reset_mock() self.db_api.update_item.reset_mock()
@ -566,9 +547,6 @@ class InstanceTestCase(base.ApiTestCase):
self.IDS_EC2_INSTANCE, ips_instance)] self.IDS_EC2_INSTANCE, ips_instance)]
reservation_set = gen_reservation_set([instances[0], instances[1]]) reservation_set = gen_reservation_set([instances[0], instances[1]])
self.ec2.describe_instances.return_value = (
{'reservationSet': reservation_set,
'fakeKey': 'fakeValue'})
self.ec2_inst_id_to_uuid.side_effect = self.IDS_OS_INSTANCE self.ec2_inst_id_to_uuid.side_effect = self.IDS_OS_INSTANCE
self.neutron.list_ports.return_value = {'ports': mock_port_list} self.neutron.list_ports.return_value = {'ports': mock_port_list}
self.db_api.get_items.return_value = ( self.db_api.get_items.return_value = (
@ -591,14 +569,11 @@ class InstanceTestCase(base.ApiTestCase):
self.assertThat({'reservationSet': reservation_set, self.assertThat({'reservationSet': reservation_set,
'fakeKey': 'fakeValue'}, 'fakeKey': 'fakeValue'},
matchers.DictMatches(resp), verbose=True) matchers.DictMatches(resp), verbose=True)
self.ec2.describe_instances.assert_called_once_with(
instance_id=None, filter=None)
for inst_id in self.IDS_EC2_INSTANCE: for inst_id in self.IDS_EC2_INSTANCE:
self.ec2_inst_id_to_uuid.assert_any_call( self.ec2_inst_id_to_uuid.assert_any_call(
mock.ANY, inst_id) mock.ANY, inst_id)
self._assert_list_ports_is_called_with_filter(self.IDS_OS_INSTANCE) self._assert_list_ports_is_called_with_filter(self.IDS_OS_INSTANCE)
self.ec2.describe_instances.reset_mock()
self.neutron.list_ports.reset_mock() self.neutron.list_ports.reset_mock()
# NOTE(ft): 2 instances; the first has 2 correct ports; # NOTE(ft): 2 instances; the first has 2 correct ports;

View File

@ -14,9 +14,13 @@
import copy import copy
import re
from lxml import etree
import mock import mock
from ec2api.api import ec2utils
def update_dict(dict1, dict2): def update_dict(dict1, dict2):
"""Get a copy of union of two dicts.""" """Get a copy of union of two dicts."""
@ -51,3 +55,29 @@ class CopyingMock(mock.MagicMock):
args = copy.deepcopy(args) args = copy.deepcopy(args)
kwargs = copy.deepcopy(kwargs) kwargs = copy.deepcopy(kwargs)
return super(CopyingMock, self).__call__(*args, **kwargs) return super(CopyingMock, self).__call__(*args, **kwargs)
_xml_scheme = re.compile('\sxmlns=".*"')
def parse_xml(xml_string):
xml_string = _xml_scheme.sub('', xml_string)
xml = etree.fromstring(xml_string)
def convert_node(node):
children = list(node)
if len(children):
if children[0].tag == 'item':
val = list(convert_node(child)[1] for child in children)
else:
val = dict(convert_node(child) for child in children)
elif node.tag.endswith('Set'):
val = []
else:
# TODO(ft): do not use private function
val = (ec2utils._try_convert(node.text)
if node.text
else node.text)
return node.tag, val
return dict([convert_node(xml)])

View File

@ -16,8 +16,8 @@
''' '''
find_unused_options.py find_unused_options.py
Compare the nova.conf file with the nova.conf.sample file to find any unused Compare the ec2api.conf file with the ec2api.conf.sample file to find any
options or default values in nova.conf unused options or default values in ec2api.conf
''' '''
from __future__ import print_function from __future__ import print_function
@ -56,17 +56,17 @@ class PropertyCollecter(iniparser.BaseParser):
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(description='''Compare the nova.conf parser = argparse.ArgumentParser(description='''Compare the ec2api.conf
file with the nova.conf.sample file to find any unused options or file with the ec2api.conf.sample file to find any unused options or
default values in nova.conf''') default values in ec2api.conf''')
parser.add_argument('-c', action='store', parser.add_argument('-c', action='store',
default='/etc/nova/nova.conf', default='/etc/ec2api/ec2api.conf',
help='path to nova.conf\ help='path to ec2api.conf\
(defaults to /etc/nova/nova.conf)') (defaults to /etc/ec2api/ec2api.conf)')
parser.add_argument('-s', default='./etc/nova/nova.conf.sample', parser.add_argument('-s', default='./etc/ec2api/ec2api.conf.sample',
help='path to nova.conf.sample\ help='path to ec2api.conf.sample\
(defaults to ./etc/nova/nova.conf.sample') (defaults to ./etc/ec2api/ec2api.conf.sample')
options = parser.parse_args() options = parser.parse_args()
conf_file_options = PropertyCollecter.collect_properties(open(options.c)) conf_file_options = PropertyCollecter.collect_properties(open(options.c))