diff options
6 files changed, 7 insertions, 611 deletions
diff --git a/ceilometer/tests/tempest/api/test_telemetry_notification_api.py b/ceilometer/tests/tempest/api/test_telemetry_notification_api.py index e38702a9..d5a1eb0e 100644 --- a/ceilometer/tests/tempest/api/test_telemetry_notification_api.py +++ b/ceilometer/tests/tempest/api/test_telemetry_notification_api.py @@ -12,9 +12,11 @@ # Change-Id: I14e16a1a7d9813b324ee40545c07f0e88fb637b7 +import six import testtools from ceilometer.tests.tempest.api import base +from tempest.common.utils import data_utils from tempest import config from tempest.lib import decorators from tempest import test @@ -44,7 +46,9 @@ class TelemetryNotificationAPITest(base.BaseTelemetryTest): def test_check_glance_v2_notifications(self): body = self.create_image(self.image_client_v2, visibility='private') - self.image_client_v2.store_image_file(body['id'], "file") + file_content = data_utils.random_bytes() + image_file = six.BytesIO(file_content) + self.image_client_v2.store_image_file(body['id'], image_file) self.image_client_v2.show_image_file(body['id']) query = 'resource', 'eq', body['id'] diff --git a/ceilometer/tests/tempest/service/client.py b/ceilometer/tests/tempest/service/client.py index 6fe637f3..332b4503 100644 --- a/ceilometer/tests/tempest/service/client.py +++ b/ceilometer/tests/tempest/service/client.py @@ -22,13 +22,11 @@ from tempest.lib.services.compute import flavors_client as flavor_cli from tempest.lib.services.compute import floating_ips_client as floatingip_cli from tempest.lib.services.compute import networks_client as network_cli from tempest.lib.services.compute import servers_client as server_cli +from tempest.lib.services.image.v2 import images_client as img_cli_v2 from tempest import manager from tempest.services.object_storage import container_client as container_cli from tempest.services.object_storage import object_client as obj_cli -from ceilometer.tests.tempest.service.images.v2 import images_client as \ - img_cli_v2 - CONF = config.CONF @@ -121,7 +119,7 @@ class Manager(manager.Manager): compute_params.update(default_params) image_params = { - 'catalog_type': CONF.image.catalog_type, + 'service': CONF.image.catalog_type, 'region': CONF.image.region or CONF.identity.region, 'endpoint_type': CONF.image.endpoint_type, 'build_interval': CONF.image.build_interval, diff --git a/ceilometer/tests/tempest/service/images/__init__.py b/ceilometer/tests/tempest/service/images/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/ceilometer/tests/tempest/service/images/__init__.py +++ /dev/null diff --git a/ceilometer/tests/tempest/service/images/glance_http.py b/ceilometer/tests/tempest/service/images/glance_http.py deleted file mode 100644 index 19a9d981..00000000 --- a/ceilometer/tests/tempest/service/images/glance_http.py +++ /dev/null @@ -1,361 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# Originally copied from python-glanceclient - -import copy -import hashlib -import posixpath -import re -import socket -import struct - -import OpenSSL -from oslo_log import log as logging -import six -from six import moves -from six.moves import http_client as httplib -from six.moves.urllib import parse as urlparse - -from ceilometer.tests.tempest import exceptions as exc - -LOG = logging.getLogger(__name__) -USER_AGENT = 'tempest' -CHUNKSIZE = 1024 * 64 # 64kB -TOKEN_CHARS_RE = re.compile('^[-A-Za-z0-9+/=]*$') - - -class HTTPClient(object): - - def __init__(self, auth_provider, filters, **kwargs): - self.auth_provider = auth_provider - self.filters = filters - self.endpoint = auth_provider.base_url(filters) - endpoint_parts = urlparse.urlparse(self.endpoint) - self.endpoint_scheme = endpoint_parts.scheme - self.endpoint_hostname = endpoint_parts.hostname - self.endpoint_port = endpoint_parts.port - - self.connection_class = self._get_connection_class( - self.endpoint_scheme) - self.connection_kwargs = self._get_connection_kwargs( - self.endpoint_scheme, **kwargs) - - @staticmethod - def _get_connection_class(scheme): - if scheme == 'https': - return VerifiedHTTPSConnection - else: - return httplib.HTTPConnection - - @staticmethod - def _get_connection_kwargs(scheme, **kwargs): - _kwargs = {'timeout': float(kwargs.get('timeout', 600))} - - if scheme == 'https': - _kwargs['ca_certs'] = kwargs.get('ca_certs', None) - _kwargs['cert_file'] = kwargs.get('cert_file', None) - _kwargs['key_file'] = kwargs.get('key_file', None) - _kwargs['insecure'] = kwargs.get('insecure', False) - _kwargs['ssl_compression'] = kwargs.get('ssl_compression', True) - - return _kwargs - - def _get_connection(self): - _class = self.connection_class - try: - return _class(self.endpoint_hostname, self.endpoint_port, - **self.connection_kwargs) - except httplib.InvalidURL: - raise exc.EndpointNotFound - - def _http_request(self, url, method, **kwargs): - """Send an http request with the specified characteristics. - - Wrapper around httplib.HTTP(S)Connection.request to handle tasks such - as setting headers and error handling. - """ - # Copy the kwargs so we can reuse the original in case of redirects - kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) - kwargs['headers'].setdefault('User-Agent', USER_AGENT) - - self._log_request(method, url, kwargs['headers']) - - conn = self._get_connection() - - try: - url_parts = urlparse.urlparse(url) - conn_url = posixpath.normpath(url_parts.path) - LOG.debug('Actual Path: {path}'.format(path=conn_url)) - if kwargs['headers'].get('Transfer-Encoding') == 'chunked': - conn.putrequest(method, conn_url) - for header, value in kwargs['headers'].items(): - conn.putheader(header, value) - conn.endheaders() - chunk = kwargs['body'].read(CHUNKSIZE) - # Chunk it, baby... - while chunk: - conn.send('%x\r\n%s\r\n' % (len(chunk), chunk)) - chunk = kwargs['body'].read(CHUNKSIZE) - conn.send('0\r\n\r\n') - else: - conn.request(method, conn_url, **kwargs) - resp = conn.getresponse() - except socket.gaierror as e: - message = ("Error finding address for %(url)s: %(e)s" % - {'url': url, 'e': e}) - raise exc.EndpointNotFound(message) - except (socket.error, socket.timeout) as e: - message = ("Error communicating with %(endpoint)s %(e)s" % - {'endpoint': self.endpoint, 'e': e}) - raise exc.TimeoutException(message) - - body_iter = ResponseBodyIterator(resp) - # Read body into string if it isn't obviously image data - if resp.getheader('content-type', None) != 'application/octet-stream': - body_str = ''.join([body_chunk for body_chunk in body_iter]) - body_iter = six.StringIO(body_str) - self._log_response(resp, None) - else: - self._log_response(resp, body_iter) - - return resp, body_iter - - def _log_request(self, method, url, headers): - LOG.info('Request: ' + method + ' ' + url) - if headers: - headers_out = headers - if 'X-Auth-Token' in headers and headers['X-Auth-Token']: - token = headers['X-Auth-Token'] - if len(token) > 64 and TOKEN_CHARS_RE.match(token): - headers_out = headers.copy() - headers_out['X-Auth-Token'] = "<Token omitted>" - LOG.info('Request Headers: ' + str(headers_out)) - - def _log_response(self, resp, body): - status = str(resp.status) - LOG.info("Response Status: " + status) - if resp.getheaders(): - LOG.info('Response Headers: ' + str(resp.getheaders())) - if body: - str_body = str(body) - length = len(body) - LOG.info('Response Body: ' + str_body[:2048]) - if length >= 2048: - self.LOG.debug("Large body (%d) md5 summary: %s", length, - hashlib.md5(str_body).hexdigest()) - - def raw_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', - 'application/octet-stream') - if 'body' in kwargs: - if (hasattr(kwargs['body'], 'read') - and method.lower() in ('post', 'put')): - # We use 'Transfer-Encoding: chunked' because - # body size may not always be known in advance. - kwargs['headers']['Transfer-Encoding'] = 'chunked' - - # Decorate the request with auth - req_url, kwargs['headers'], kwargs['body'] = \ - self.auth_provider.auth_request( - method=method, url=url, headers=kwargs['headers'], - body=kwargs.get('body', None), filters=self.filters) - return self._http_request(req_url, method, **kwargs) - - -class OpenSSLConnectionDelegator(object): - """An OpenSSL.SSL.Connection delegator. - - Supplies an additional 'makefile' method which httplib requires - and is not present in OpenSSL.SSL.Connection. - - Note: Since it is not possible to inherit from OpenSSL.SSL.Connection - a delegator must be used. - """ - def __init__(self, *args, **kwargs): - self.connection = OpenSSL.SSL.Connection(*args, **kwargs) - - def __getattr__(self, name): - return getattr(self.connection, name) - - def makefile(self, *args, **kwargs): - # Ensure the socket is closed when this file is closed - kwargs['close'] = True - return socket._fileobject(self.connection, *args, **kwargs) - - -class VerifiedHTTPSConnection(httplib.HTTPSConnection): - """Extended HTTPSConnection which uses OpenSSL library for enhanced SSL - - Note: Much of this functionality can eventually be replaced - with native Python 3.3 code. - """ - def __init__(self, host, port=None, key_file=None, cert_file=None, - ca_certs=None, timeout=None, insecure=False, - ssl_compression=True): - httplib.HTTPSConnection.__init__(self, host, port, - key_file=key_file, - cert_file=cert_file) - self.key_file = key_file - self.cert_file = cert_file - self.timeout = timeout - self.insecure = insecure - self.ssl_compression = ssl_compression - self.ca_certs = ca_certs - self.setcontext() - - @staticmethod - def host_matches_cert(host, x509): - """Verify that the x509 certificate we have received from 'host' - - Identifies the server we are connecting to, ie that the certificate's - Common Name or a Subject Alternative Name matches 'host'. - """ - # First see if we can match the CN - if x509.get_subject().commonName == host: - return True - - # Also try Subject Alternative Names for a match - san_list = None - for i in moves.xrange(x509.get_extension_count()): - ext = x509.get_extension(i) - if ext.get_short_name() == 'subjectAltName': - san_list = str(ext) - for san in ''.join(san_list.split()).split(','): - if san == "DNS:%s" % host: - return True - - # Server certificate does not match host - msg = ('Host "%s" does not match x509 certificate contents: ' - 'CommonName "%s"' % (host, x509.get_subject().commonName)) - if san_list is not None: - msg = msg + ', subjectAltName "%s"' % san_list - raise exc.SSLCertificateError(msg) - - def verify_callback(self, connection, x509, errnum, - depth, preverify_ok): - if x509.has_expired(): - msg = "SSL Certificate expired on '%s'" % x509.get_notAfter() - raise exc.SSLCertificateError(msg) - - if depth == 0 and preverify_ok is True: - # We verify that the host matches against the last - # certificate in the chain - return self.host_matches_cert(self.host, x509) - else: - # Pass through OpenSSL's default result - return preverify_ok - - def setcontext(self): - """Set up the OpenSSL context.""" - self.context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) - - if self.ssl_compression is False: - self.context.set_options(0x20000) # SSL_OP_NO_COMPRESSION - - if self.insecure is not True: - self.context.set_verify(OpenSSL.SSL.VERIFY_PEER, - self.verify_callback) - else: - self.context.set_verify(OpenSSL.SSL.VERIFY_NONE, - self.verify_callback) - - if self.cert_file: - try: - self.context.use_certificate_file(self.cert_file) - except Exception as e: - msg = 'Unable to load cert from "%s" %s' % (self.cert_file, e) - raise exc.SSLConfigurationError(msg) - if self.key_file is None: - # We support having key and cert in same file - try: - self.context.use_privatekey_file(self.cert_file) - except Exception as e: - msg = ('No key file specified and unable to load key ' - 'from "%s" %s' % (self.cert_file, e)) - raise exc.SSLConfigurationError(msg) - - if self.key_file: - try: - self.context.use_privatekey_file(self.key_file) - except Exception as e: - msg = 'Unable to load key from "%s" %s' % (self.key_file, e) - raise exc.SSLConfigurationError(msg) - - if self.ca_certs: - try: - self.context.load_verify_locations(self.ca_certs) - except Exception as e: - msg = 'Unable to load CA from "%s" %s' % (self.ca_certs, e) - raise exc.SSLConfigurationError(msg) - else: - self.context.set_default_verify_paths() - - def connect(self): - """Connect to SSL port and apply per-connection parameters.""" - try: - addresses = socket.getaddrinfo(self.host, - self.port, - socket.AF_UNSPEC, - socket.SOCK_STREAM) - except OSError as msg: - raise exc.RestClientException(msg) - for res in addresses: - af, socktype, proto, canonname, sa = res - sock = socket.socket(af, socket.SOCK_STREAM) - - if self.timeout is not None: - # '0' microseconds - sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, - struct.pack('LL', self.timeout, 0)) - self.sock = OpenSSLConnectionDelegator(self.context, sock) - try: - self.sock.connect(sa) - except OSError as msg: - if self.sock: - self.sock = None - continue - break - if self.sock is None: - # Happen only when all results have failed. - raise exc.RestClientException('Cannot connect to %s' % self.host) - - def close(self): - if self.sock: - # Remove the reference to the socket but don't close it yet. - # Response close will close both socket and associated - # file. Closing socket too soon will cause response - # reads to fail with socket IO error 'Bad file descriptor'. - self.sock = None - httplib.HTTPSConnection.close(self) - - -class ResponseBodyIterator(object): - """A class that acts as an iterator over an HTTP response.""" - - def __init__(self, resp): - self.resp = resp - - def __iter__(self): - while True: - yield self.next() - - def next(self): - chunk = self.resp.read(CHUNKSIZE) - if chunk: - return chunk - else: - raise StopIteration() diff --git a/ceilometer/tests/tempest/service/images/v2/__init__.py b/ceilometer/tests/tempest/service/images/v2/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/ceilometer/tests/tempest/service/images/v2/__init__.py +++ /dev/null diff --git a/ceilometer/tests/tempest/service/images/v2/images_client.py b/ceilometer/tests/tempest/service/images/v2/images_client.py deleted file mode 100644 index d0cbadc6..00000000 --- a/ceilometer/tests/tempest/service/images/v2/images_client.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - -from ceilometer.tests.tempest.service.images import glance_http - - -class ImagesClient(rest_client.RestClient): - - def __init__(self, auth_provider, catalog_type, region, **kwargs): - super(ImagesClient, self).__init__( - auth_provider, catalog_type, region, **kwargs) - self._http = None - self.dscv = kwargs.get("disable_ssl_certificate_validation") - self.ca_certs = kwargs.get("ca_certs") - - def _get_http(self): - return glance_http.HTTPClient(auth_provider=self.auth_provider, - filters=self.filters, - insecure=self.dscv, - ca_certs=self.ca_certs) - - @property - def http(self): - if self._http is None: - self._http = self._get_http() - return self._http - - def update_image(self, image_id, patch): - """Update an image. - - Available params: see http://developer.openstack.org/ - api-ref-image-v2.html#updateImage-v2 - """ - data = json.dumps(patch) - headers = {"Content-Type": "application/openstack-images-v2.0" - "-json-patch"} - resp, body = self.patch('v2/images/%s' % image_id, data, headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image(self, **kwargs): - """Create an image. - - Available params: see http://developer.openstack.org/ - api-ref-image-v2.html#createImage-v2 - """ - data = json.dumps(kwargs) - resp, body = self.post('v2/images', data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def deactivate_image(self, image_id): - url = 'v2/images/%s/actions/deactivate' % image_id - resp, body = self.post(url, None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def reactivate_image(self, image_id): - url = 'v2/images/%s/actions/reactivate' % image_id - resp, body = self.post(url, None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - url = 'v2/images/%s' % image_id - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def list_images(self, params=None): - url = 'v2/images' - - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - url = 'v2/images/%s' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_image(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'image' - - def store_image_file(self, image_id, data): - url = 'v2/images/%s/file' % image_id - headers = {'Content-Type': 'application/octet-stream'} - resp, body = self.http.raw_request('PUT', url, headers=headers, - body=data) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_image_file(self, image_id): - url = 'v2/images/%s/file' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def add_image_tag(self, image_id, tag): - url = 'v2/images/%s/tags/%s' % (image_id, tag) - resp, body = self.put(url, body=None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_image_tag(self, image_id, tag): - url = 'v2/images/%s/tags/%s' % (image_id, tag) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def list_image_members(self, image_id): - url = 'v2/images/%s/members' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image_member(self, image_id, **kwargs): - """Create an image member. - - Available params: see http://developer.openstack.org/ - api-ref-image-v2.html#createImageMember-v2 - """ - url = 'v2/images/%s/members' % image_id - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_image_member(self, image_id, member_id, **kwargs): - """Update an image member. - - Available params: see http://developer.openstack.org/ - api-ref-image-v2.html#updateImageMember-v2 - """ - url = 'v2/images/%s/members/%s' % (image_id, member_id) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_image_member(self, image_id, member_id): - url = 'v2/images/%s/members/%s' % (image_id, member_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def delete_image_member(self, image_id, member_id): - url = 'v2/images/%s/members/%s' % (image_id, member_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def show_schema(self, schema): - url = 'v2/schemas/%s' % schema - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_resource_types(self): - url = '/v2/metadefs/resource_types' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_namespace(self, **kwargs): - """Create a namespace. - - Available params: see http://developer.openstack.org/ - api-ref-image-v2.html#createNamespace-v2 - """ - data = json.dumps(kwargs) - resp, body = self.post('/v2/metadefs/namespaces', data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace(self, namespace): - url = '/v2/metadefs/namespaces/%s' % namespace - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace(self, namespace, **kwargs): - """Update a namespace. - - Available params: see http://developer.openstack.org/ - api-ref-image-v2.html#updateNamespace-v2 - """ - # NOTE: On Glance API, we need to pass namespace on both URI - # and a request body. - params = {'namespace': namespace} - params.update(kwargs) - data = json.dumps(params) - url = '/v2/metadefs/namespaces/%s' % namespace - resp, body = self.put(url, body=data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace(self, namespace): - url = '/v2/metadefs/namespaces/%s' % namespace - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) |