gce-api/gceapi/tests/functional/base.py

289 lines
9.9 KiB
Python

# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import subprocess
import unittest
import urlparse
from oslo_log import log as logging
from tempest_lib.common import rest_client
import testtools
from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import exceptions
from tempest import manager
import tempest.test
CONF = config.CONF
LOG = logging.getLogger("tempest.thirdparty.gce")
class GCEConnection(rest_client.RestClient):
def __init__(self, auth_provider):
super(GCEConnection, self).__init__(auth_provider,
"gceapi", "RegionOne")
self.service = CONF.gceapi.catalog_type
def set_zone(self, zone):
self.zone = zone
def set_region(self, region):
self.region = region
def auth_request(self, uri, **kwargs):
if 'headers' not in kwargs:
kwargs['headers'] = {}
kwargs['headers']['AUTHORIZATION'] = "a " + self.token
return self.http_obj.request(uri, **kwargs)
def _combine_uri(self, *path):
if not len(path):
return None
parts = []
gce_cfg = CONF.gceapi
if not urlparse.urlsplit(path[0]).netloc:
parts = [self.base_url, gce_cfg.api_path, self.tenant_name]
parts.extend(path)
uri = "/".join(x.strip("/") for x in parts if x)
return uri
def _add_params(self, uri, params):
if not params:
return uri
param_list = ["%s=%s" % (param, value)
for (param, value) in params.iteritems()]
return "%s?%s" % (uri, ";".join(param_list))
def _convert_response(self, response):
header = response[0]
body = (json.loads(response[1])
if header.get("content-type") == "application/json"
else None)
return (header.status, body)
def request(self, *path, **kwargs):
if (self.token is None) or (self.base_url is None):
self._set_auth()
uri = self._combine_uri(*path)
params = kwargs.pop("params", None)
uri = self._add_params(uri, params)
response = self.auth_request(uri, **kwargs)
return self._convert_response(response)
def _add_zone_path(self, *path):
return ('zones', self.zone) + path
def _add_region_path(self, *path):
return ('regions', self.region) + path
def get(self, *path):
return self.request(*path)
def zone_get(self, *path):
return self.get(*self._add_zone_path(*path))
def region_get(self, *path):
return self.get(*self._add_region_path(*path))
def post(self, *path, **kwargs):
req_args = {"method": "POST"}
if "body" in kwargs:
req_args["body"] = json.dumps(kwargs["body"])
req_args["headers"] = {"Content-Type": "application/json"}
if "params" in kwargs:
req_args["params"] = kwargs["params"]
return self.request(*path, **req_args)
def zone_post(self, *path, **kwargs):
return self.post(*self._add_zone_path(*path), **kwargs)
def region_post(self, *path, **kwargs):
return self.post(*self._add_region_path(*path), **kwargs)
def delete(self, *path):
return self.request(*path, method="DELETE")
def zone_delete(self, *path):
return self.delete(*self._add_zone_path(*path))
class GCESmokeTestCase(testtools.TestCase):
failed = False
@classmethod
def setUpClass(cls):
super(GCESmokeTestCase, cls).setUpClass()
cls.gce = GCEConnection(manager.Manager().auth_provider)
cls._trash_bin = []
@classmethod
def tearDownClass(cls):
targetLink = None
opLink = None
def check():
(status, body) = cls.gce.get(opLink)
if status == 200 and body.get("progress") == 100:
return True
return False
timeout = CONF.gceapi.operation_timeout
idle = CONF.gceapi.operation_interval
while cls._trash_bin:
targetLink = cls._trash_bin.pop()
(status, body) = cls.gce.delete(targetLink)
if status != 200:
msg = ("Delete operation fails for resource %s"
% targetLink)
LOG.error(msg)
continue
try:
opLink = body["selfLink"]
result = tempest.test.call_until_true(check, timeout, idle)
if not result:
msg = ("Timed out waiting for deletion resource %s"
% targetLink)
LOG.error(msg)
except Exception as exc:
LOG.exception(exc)
@classmethod
def add_resource_cleanup(cls, resource_link):
if resource_link not in cls._trash_bin:
cls._trash_bin.append(resource_link)
@classmethod
def cancel_resource_cleanup(cls, resource_link):
if resource_link in cls._trash_bin:
cls._trash_bin.remove(resource_link)
@staticmethod
def incremental(meth):
def decorator(*args, **kwargs):
try:
meth(*args, **kwargs)
except unittest.SkipTest:
raise
except Exception:
GCESmokeTestCase.failed = True
raise
decorator.__test__ = True
return decorator
def setUp(self):
if GCESmokeTestCase.failed:
raise unittest.SkipTest("Skipped by previous exception")
super(GCESmokeTestCase, self).setUp()
self.skipTest('Not to run in gating. It is just an old example and '
'will be remove removed in future')
def wait_for_operation(self, body, operation, status):
self.assertEqual("compute#operation", body["kind"])
self.assertEqual(operation, body["operationType"])
targetLink = body["targetLink"]
opLink = body["selfLink"]
def check():
(http_status, op_body) = self.gce.get(opLink)
self.assertEqual(http_status, 200)
self.assertEqual(targetLink, op_body["targetLink"])
self.assertEqual(opLink, op_body["selfLink"])
error = op_body.get("error")
if error:
msg = "Operation(resource %s) error %s (%s)" % (targetLink,
error["errors"], op_body.get("httpErrorMessage"))
self.fail(msg)
if op_body["progress"] != 100:
return False
self.assertEqual("DONE", op_body["status"])
return True
timeout = CONF.gceapi.operation_timeout
idle = CONF.gceapi.operation_interval
result = tempest.test.call_until_true(check, timeout, idle)
if not result:
message = "Timed out waiting for uri %s" % targetLink
raise exceptions.TimeoutException(message)
(http_status, body) = self.gce.get(targetLink)
# NOTE(apavlov): only for delete* we wait 404. for other 200
target_status = 404 if "delete" in operation else 200
self.assertEqual(http_status, target_status)
if status:
self.assertEqual(status, body["status"])
def verify_resource_uri(self, uri, resource_path=None, resource_name=None):
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(str(uri))
self.assertEqual(self.gce.base_url.strip("/"),
scheme + "://" + netloc)
resource_parts = [CONF.gceapi.api_path.strip("/"),
self.gce.tenant_name]
if resource_path is not None:
resource_parts.append(resource_path.strip("/"))
if resource_name is not None:
resource_parts.append(resource_name)
self.assertEqual("/" + "/".join(resource_parts), path)
self.assertFalse(query)
self.assertFalse(fragment)
def verify_region_resource_uri(self, uri, resource_path, resource_name):
resource_path = "/".join(["regions", self.ctx.region["name"],
resource_path.strip("/")])
self.verify_resource_uri(uri, resource_path, resource_name)
def verify_zone_resource_uri(self, uri, resource_path, resource_name):
resource_path = "/".join(["zones", self.ctx.zone["name"],
resource_path.strip("/")])
self.verify_resource_uri(uri, resource_path, resource_name)
def _get_ip_address(self, network_interface):
if CONF.gceapi.use_floatingip:
ipaddr = network_interface["accessConfigs"][0]["natIP"]
else:
ipaddr = network_interface["networkIP"]
return ipaddr
def _ping_ip_address(self, ip_address):
cmd = ['ping', '-c1', '-w1', ip_address]
def ping():
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.wait()
return True if proc.returncode == 0 else False
result = tempest.test.call_until_true(
ping, CONF.compute.ping_timeout, 1)
if result:
return
message = "Timed out waiting for ping %s" % (ip_address)
raise exceptions.TimeoutException(message)
def _check_ssh_connectivity(self, ip_address, username, pkey):
ssh = remote_client.RemoteClient(ip_address, username, pkey=pkey)
ssh.validate_authentication()