remove proxy to ec2
Change-Id: I7c20d19ba1d608c84fbcf9602fcd4be61e9f64ea
This commit is contained in:
parent
a53c96d231
commit
28756f3ad6
|
@ -4,3 +4,4 @@
|
|||
.pydevproject
|
||||
ec2_api.egg-info
|
||||
.tox
|
||||
.testrepository
|
||||
|
|
|
@ -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")
|
||||
# NOTE(jruzicka): For compatibility with EC2 API, treat expected
|
||||
# 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.
|
||||
if status >= 500:
|
||||
status = 400
|
||||
|
@ -468,34 +468,9 @@ class Executor(wsgi.Application):
|
|||
ec2_id = ec2utils.id_to_ec2_inst_id(ex.kwargs['instance_id'])
|
||||
message = ex.msg_fmt % {'instance_id': ec2_id}
|
||||
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:
|
||||
return ec2_error_ex(ex, req,
|
||||
unexpected=not isinstance(
|
||||
ex, exception.EC2Exception))
|
||||
return ec2_error_ex(
|
||||
ex, req, unexpected=not isinstance(ex, exception.EC2Exception))
|
||||
else:
|
||||
resp = webob.Response()
|
||||
resp.status = 200
|
||||
|
|
|
@ -22,7 +22,6 @@ from oslo.config import cfg
|
|||
|
||||
from ec2api.api import clients
|
||||
from ec2api.api import common
|
||||
from ec2api.api import ec2client
|
||||
from ec2api.api import ec2utils
|
||||
from ec2api.api import utils
|
||||
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.")
|
||||
raise exception.AuthFailure(msg % {'public_ip': public_ip})
|
||||
|
||||
ec2 = ec2client.ec2client(context)
|
||||
# NOTE(ft): in fact only the first two parameters are used to
|
||||
# associate an address in EC2 Classic mode. Other parameters are
|
||||
# sent to validate them for EC2 Classic mode and raise an error.
|
||||
|
|
|
@ -25,11 +25,10 @@ from oslo.config import cfg
|
|||
|
||||
from ec2api.api import cloud
|
||||
from ec2api.api import ec2utils
|
||||
from ec2api.api import proxy
|
||||
from ec2api import exception
|
||||
from ec2api.openstack.common.gettextutils import _
|
||||
from ec2api.openstack.common import log as logging
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -58,14 +57,15 @@ class APIRequest(object):
|
|||
self.controller = cloud.VpcCloudController()
|
||||
else:
|
||||
self.controller = cloud.CloudController()
|
||||
self.proxyController = proxy.ProxyController()
|
||||
|
||||
def invoke(self, context):
|
||||
try:
|
||||
method = getattr(self.controller,
|
||||
ec2utils.camelcase_to_underscore(self.action))
|
||||
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())
|
||||
|
||||
|
@ -91,9 +91,6 @@ class APIRequest(object):
|
|||
result = method(context, **args)
|
||||
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):
|
||||
xml = minidom.Document()
|
||||
|
||||
|
|
|
@ -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('_')])
|
|
@ -152,29 +152,9 @@ def is_ec2_timestamp_expired(request, expires=None):
|
|||
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):
|
||||
image_id = ec2_id_to_id(ec2_id)
|
||||
return id_to_glance_id(context, image_id)
|
||||
|
||||
|
||||
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)
|
||||
return novadb.s3_image_get(context, image_id)['uuid']
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
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'):
|
||||
"""Convert an instance ID (int) to an ec2 ID (i-[base 16 number])."""
|
||||
return template % int(instance_id)
|
||||
|
@ -204,7 +178,7 @@ def id_to_ec2_inst_id(instance_id):
|
|||
return None
|
||||
elif uuidutils.is_uuid_like(instance_id):
|
||||
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)
|
||||
else:
|
||||
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):
|
||||
""""Convert an instance id to uuid."""
|
||||
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)
|
||||
|
||||
|
||||
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:
|
||||
return
|
||||
try:
|
||||
|
@ -229,69 +203,6 @@ def get_int_id_from_instance_uuid(context, instance_uuid):
|
|||
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
|
||||
# malformed existed functions
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -28,7 +28,8 @@ def create_volume(context, availability_zone=None, size=None,
|
|||
description=None, metadata=None, iops=None, encrypted=None,
|
||||
kms_key_id=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:
|
||||
os_snapshot_id = None
|
||||
|
||||
|
|
|
@ -18,12 +18,12 @@ from ec2api.openstack.common.db import options
|
|||
from ec2api import paths
|
||||
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):
|
||||
options.set_defaults(sql_connection=_DEFAULT_SQL_CONNECTION,
|
||||
sqlite_db='nova.sqlite')
|
||||
sqlite_db='ec2api.sqlite')
|
||||
cfg.CONF(argv[1:],
|
||||
project='ec2api',
|
||||
version=version.version_info.version_string(),
|
||||
|
|
|
@ -25,7 +25,6 @@ from sqlalchemy import and_
|
|||
from sqlalchemy import or_
|
||||
from sqlalchemy.sql import bindparam
|
||||
|
||||
from ec2api.api import ec2utils
|
||||
import ec2api.context
|
||||
from ec2api.db.sqlalchemy import models
|
||||
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):
|
||||
# NOTE(ft): obtaining new id from Nova DB is temporary solution
|
||||
# while we don't implmenet all Nova EC2 methods
|
||||
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)}
|
||||
obj_id = "%(kind)s-%(id)08x" % {"kind": kind,
|
||||
"id": random.randint(1, 0xffffffff)}
|
||||
return obj_id
|
||||
|
||||
|
||||
|
|
|
@ -133,10 +133,6 @@ class PasteAppNotFound(EC2Exception):
|
|||
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):
|
||||
ec2_code = 'AuthFailure'
|
||||
msg_fmt = _("Not authorized.")
|
||||
|
@ -166,16 +162,6 @@ class NovaDbImageNotFound(EC2NotFound):
|
|||
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):
|
||||
ec2_code = 'InvalidInstanceID.NotFound'
|
||||
msg_fmt = _("Instance %(instance_id)s could not be found.")
|
||||
|
|
|
@ -85,43 +85,6 @@ def 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)
|
||||
|
||||
|
||||
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):
|
||||
"""Get an instance or raise if it does not exist."""
|
||||
return IMPL.instance_get_by_uuid(context, uuid,
|
||||
|
|
|
@ -26,7 +26,6 @@ from sqlalchemy import or_
|
|||
import ec2api.context
|
||||
from ec2api import exception
|
||||
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.gettextutils import _
|
||||
from ec2api.openstack.common import log as logging
|
||||
|
@ -179,118 +178,6 @@ def s3_image_get(context, image_id):
|
|||
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
|
||||
def ec2_instance_get_by_uuid(context, instance_uuid):
|
||||
def _ec2_instance_get_by_uuid(context, instance_uuid):
|
||||
result = (_ec2_instance_get_query(context).
|
||||
filter_by(uuid=instance_uuid).
|
||||
first())
|
||||
|
@ -321,12 +208,12 @@ def ec2_instance_get_by_uuid(context, instance_uuid):
|
|||
|
||||
@require_context
|
||||
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']
|
||||
|
||||
|
||||
@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).
|
||||
filter_by(id=instance_id).
|
||||
first())
|
||||
|
@ -339,7 +226,7 @@ def ec2_instance_get_by_id(context, instance_id):
|
|||
|
||||
@require_context
|
||||
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']
|
||||
|
||||
|
||||
|
|
|
@ -59,22 +59,6 @@ class S3Image(BASE, NovaBase):
|
|||
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):
|
||||
"""Compatibility layer for the EC2 instance service."""
|
||||
__tablename__ = 'instance_id_mappings'
|
||||
|
|
|
@ -17,9 +17,9 @@ import mock
|
|||
from oslotest import base as test_base
|
||||
|
||||
import ec2api.api.apirequest
|
||||
from ec2api.api import ec2client
|
||||
from ec2api.tests import fakes
|
||||
from ec2api.tests import matchers
|
||||
from ec2api.tests import tools
|
||||
import ec2api.wsgi
|
||||
|
||||
|
||||
|
@ -58,14 +58,6 @@ class ApiTestCase(test_base.BaseTestCase):
|
|||
mock.patch('ec2api.api.ec2utils.ec2_inst_id_to_uuid'))
|
||||
self.ec2_inst_id_to_uuid = ec2_inst_id_to_uuid_patcher.start()
|
||||
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')
|
||||
self.isotime = isotime_patcher.start()
|
||||
|
@ -90,7 +82,7 @@ class ApiTestCase(test_base.BaseTestCase):
|
|||
'endpoints': [{'publicUrl': 'fake_url'}]}])
|
||||
|
||||
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:
|
||||
action_tag = '%sResponse' % action
|
||||
self.assertIn(action_tag, body)
|
||||
|
|
|
@ -20,7 +20,6 @@ from oslotest import base as test_base
|
|||
|
||||
from ec2api import api
|
||||
from ec2api.api import apirequest
|
||||
from ec2api.api import cloud
|
||||
from ec2api import exception
|
||||
from ec2api.tests import fakes_request_response as fakes
|
||||
from ec2api.tests import matchers
|
||||
|
@ -35,10 +34,6 @@ class ApiInitTestCase(test_base.BaseTestCase):
|
|||
|
||||
def setUp(self):
|
||||
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')
|
||||
self.controller_class = controller_patcher.start()
|
||||
|
@ -94,36 +89,3 @@ class ApiInitTestCase(test_base.BaseTestCase):
|
|||
'KeyError', 'Unknown error occurred.')
|
||||
do_check(exception.InvalidVpcIDNotFound('fake_msg'), 400,
|
||||
'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)
|
||||
|
|
|
@ -20,7 +20,6 @@ import mock
|
|||
from oslotest import base as test_base
|
||||
|
||||
from ec2api.api import apirequest
|
||||
from ec2api.api import ec2client
|
||||
from ec2api.tests import fakes_request_response as fakes
|
||||
from ec2api.tests import matchers
|
||||
from ec2api.tests import tools
|
||||
|
@ -35,9 +34,6 @@ class EC2RequesterTestCase(test_base.BaseTestCase):
|
|||
|
||||
def setUp(self):
|
||||
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')
|
||||
self.controller = controller_patcher.start().return_value
|
||||
|
@ -89,7 +85,7 @@ class EC2RequesterTestCase(test_base.BaseTestCase):
|
|||
# based on the order of tags
|
||||
xml = etree.fromstring(observed)
|
||||
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,
|
||||
{'requestId': request_id})}
|
||||
self.assertThat(observed_data, matchers.DictMatches(expected))
|
||||
|
|
|
@ -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'})
|
|
@ -52,10 +52,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
novadb_patcher = (mock.patch('ec2api.api.instance.novadb'))
|
||||
self.novadb = novadb_patcher.start()
|
||||
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(
|
||||
'FakeImage', ['id', 'status', 'properties'])
|
||||
|
@ -83,8 +79,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
self.utils_generate_uid.return_value = fakes.ID_EC2_RESERVATION_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')
|
||||
self.nova_flavors.list.return_value = [fake_flavor]
|
||||
self.nova_servers.create.return_value = (
|
||||
|
@ -156,7 +150,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
|
||||
self.create_network_interface.reset_mock()
|
||||
self.nova_servers.reset_mock()
|
||||
self.ec2.reset_mock()
|
||||
self.db_api.reset_mock()
|
||||
self.isotime.reset_mock()
|
||||
|
||||
|
@ -217,13 +210,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
self.create_network_interface.side_effect = (
|
||||
[{'networkInterface': eni}
|
||||
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.fake_instance_class(os_instance_id)
|
||||
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}
|
||||
self.ec2_inst_id_to_uuid.side_effect = (
|
||||
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=[],
|
||||
updated_ports=[], deleted_ports=[]):
|
||||
|
@ -443,8 +427,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
self.ec2_inst_id_to_uuid.assert_any_call(
|
||||
mock.ANY, inst_id)
|
||||
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.neutron.update_port.call_count)
|
||||
self.assertEqual(len(updated_ports),
|
||||
|
@ -469,7 +451,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
self.ec2_inst_id_to_uuid.reset_mock()
|
||||
self.neutron.list_ports.reset_mock()
|
||||
self.neutron.update_port.reset_mock()
|
||||
self.ec2.terminate_instances.reset_mock()
|
||||
self.db_api.delete_item.reset_mock()
|
||||
self.db_api.update_item.reset_mock()
|
||||
|
||||
|
@ -566,9 +547,6 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
self.IDS_EC2_INSTANCE, ips_instance)]
|
||||
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.neutron.list_ports.return_value = {'ports': mock_port_list}
|
||||
self.db_api.get_items.return_value = (
|
||||
|
@ -591,14 +569,11 @@ class InstanceTestCase(base.ApiTestCase):
|
|||
self.assertThat({'reservationSet': reservation_set,
|
||||
'fakeKey': 'fakeValue'},
|
||||
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:
|
||||
self.ec2_inst_id_to_uuid.assert_any_call(
|
||||
mock.ANY, inst_id)
|
||||
self._assert_list_ports_is_called_with_filter(self.IDS_OS_INSTANCE)
|
||||
|
||||
self.ec2.describe_instances.reset_mock()
|
||||
self.neutron.list_ports.reset_mock()
|
||||
|
||||
# NOTE(ft): 2 instances; the first has 2 correct ports;
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
|
||||
|
||||
import copy
|
||||
import re
|
||||
|
||||
from lxml import etree
|
||||
import mock
|
||||
|
||||
from ec2api.api import ec2utils
|
||||
|
||||
|
||||
def update_dict(dict1, dict2):
|
||||
"""Get a copy of union of two dicts."""
|
||||
|
@ -51,3 +55,29 @@ class CopyingMock(mock.MagicMock):
|
|||
args = copy.deepcopy(args)
|
||||
kwargs = copy.deepcopy(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)])
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
'''
|
||||
find_unused_options.py
|
||||
|
||||
Compare the nova.conf file with the nova.conf.sample file to find any unused
|
||||
options or default values in nova.conf
|
||||
Compare the ec2api.conf file with the ec2api.conf.sample file to find any
|
||||
unused options or default values in ec2api.conf
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
|
@ -56,17 +56,17 @@ class PropertyCollecter(iniparser.BaseParser):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='''Compare the nova.conf
|
||||
file with the nova.conf.sample file to find any unused options or
|
||||
default values in nova.conf''')
|
||||
parser = argparse.ArgumentParser(description='''Compare the ec2api.conf
|
||||
file with the ec2api.conf.sample file to find any unused options or
|
||||
default values in ec2api.conf''')
|
||||
|
||||
parser.add_argument('-c', action='store',
|
||||
default='/etc/nova/nova.conf',
|
||||
help='path to nova.conf\
|
||||
(defaults to /etc/nova/nova.conf)')
|
||||
parser.add_argument('-s', default='./etc/nova/nova.conf.sample',
|
||||
help='path to nova.conf.sample\
|
||||
(defaults to ./etc/nova/nova.conf.sample')
|
||||
default='/etc/ec2api/ec2api.conf',
|
||||
help='path to ec2api.conf\
|
||||
(defaults to /etc/ec2api/ec2api.conf)')
|
||||
parser.add_argument('-s', default='./etc/ec2api/ec2api.conf.sample',
|
||||
help='path to ec2api.conf.sample\
|
||||
(defaults to ./etc/ec2api/ec2api.conf.sample')
|
||||
options = parser.parse_args()
|
||||
|
||||
conf_file_options = PropertyCollecter.collect_properties(open(options.c))
|
||||
|
|
Loading…
Reference in New Issue