Change to use tempest plugin framework
Tempest plugin framework provides more flexibility for projects. With this plugin, it's not requiring the tests live in the tempest tree. Change-Id: I8681140d02926b4b3e6af84b8f03b9385e62cc72
This commit is contained in:
commit
955fa96f1f
|
@ -0,0 +1,30 @@
|
||||||
|
# Copyright 2015 Intel 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_config import cfg
|
||||||
|
|
||||||
|
from tempest import config # noqa
|
||||||
|
|
||||||
|
|
||||||
|
congressha_group = cfg.OptGroup(name="congressha", title="Congress HA Options")
|
||||||
|
|
||||||
|
CongressHAGroup = [
|
||||||
|
cfg.StrOpt("replica_type",
|
||||||
|
default="policyha",
|
||||||
|
help="service type used to create a replica congress server."),
|
||||||
|
cfg.IntOpt("replica_port",
|
||||||
|
default=4001,
|
||||||
|
help="The listening port for a replica congress server. "),
|
||||||
|
]
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Copyright 2015 Intel
|
||||||
|
# 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 os
|
||||||
|
|
||||||
|
from tempest import config
|
||||||
|
from tempest.test_discover import plugins
|
||||||
|
|
||||||
|
from congress_tempest_tests import config as config_congress
|
||||||
|
|
||||||
|
|
||||||
|
class CongressTempestPlugin(plugins.TempestPlugin):
|
||||||
|
def load_tests(self):
|
||||||
|
base_path = os.path.split(os.path.dirname(
|
||||||
|
os.path.abspath(__file__)))[0]
|
||||||
|
test_dir = "congress_tempest_tests/tests"
|
||||||
|
full_test_dir = os.path.join(base_path, test_dir)
|
||||||
|
return full_test_dir, base_path
|
||||||
|
|
||||||
|
def register_opts(self, conf):
|
||||||
|
config.register_opt_group(conf, config_congress.congressha_group,
|
||||||
|
config_congress.CongressHAGroup)
|
||||||
|
|
||||||
|
def get_opt_lists(self):
|
||||||
|
return [(config_congress.congressha_group.name,
|
||||||
|
config_congress.CongressHAGroup)]
|
|
@ -0,0 +1,173 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from tempest.common import service_client
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyClient(service_client.ServiceClient):
|
||||||
|
|
||||||
|
policy = '/v1/policies'
|
||||||
|
policy_path = '/v1/policies/%s'
|
||||||
|
policy_rules = '/v1/policies/%s/rules'
|
||||||
|
policy_rules_path = '/v1/policies/%s/rules/%s'
|
||||||
|
policy_tables = '/v1/policies/%s/tables'
|
||||||
|
policy_table_path = '/v1/policies/%s/tables/%s'
|
||||||
|
policy_rows = '/v1/policies/%s/tables/%s/rows'
|
||||||
|
policy_rows_trace = '/v1/policies/%s/tables/%s/rows?trace=True'
|
||||||
|
policies = '/v1/policies'
|
||||||
|
policy_action = '/v1/policies/%s?%s'
|
||||||
|
datasources = '/v1/data-sources'
|
||||||
|
datasource_path = '/v1/data-sources/%s'
|
||||||
|
datasource_tables = '/v1/data-sources/%s/tables'
|
||||||
|
datasource_table_path = '/v1/data-sources/%s/tables/%s'
|
||||||
|
datasource_status = '/v1/data-sources/%s/status'
|
||||||
|
datasource_schema = '/v1/data-sources/%s/schema'
|
||||||
|
datasource_table_schema = '/v1/data-sources/%s/tables/%s/spec'
|
||||||
|
datasource_rows = '/v1/data-sources/%s/tables/%s/rows'
|
||||||
|
driver = '/v1/system/drivers'
|
||||||
|
driver_path = '/v1/system/drivers/%s'
|
||||||
|
|
||||||
|
def _resp_helper(self, resp, body):
|
||||||
|
body = json.loads(body)
|
||||||
|
return service_client.ResponseBody(resp, body)
|
||||||
|
|
||||||
|
def create_policy(self, body):
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post(
|
||||||
|
self.policy, body=body)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def delete_policy(self, policy):
|
||||||
|
resp, body = self.delete(
|
||||||
|
self.policy_path % policy)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_policy(self, policy):
|
||||||
|
resp, body = self.get(
|
||||||
|
self.policy_path % policy)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def create_policy_rule(self, policy_name, body=None):
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post(
|
||||||
|
self.policy_rules % policy_name, body=body)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def delete_policy_rule(self, policy_name, rule_id):
|
||||||
|
resp, body = self.delete(
|
||||||
|
self.policy_rules_path % (policy_name, rule_id))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_policy_rule(self, policy_name, rule_id):
|
||||||
|
resp, body = self.get(
|
||||||
|
self.policy_rules_path % (policy_name, rule_id))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_policy_rows(self, policy_name, table, trace=None):
|
||||||
|
if trace:
|
||||||
|
query = self.policy_rows_trace
|
||||||
|
else:
|
||||||
|
query = self.policy_rows
|
||||||
|
resp, body = self.get(query % (policy_name, table))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_policy_rules(self, policy_name):
|
||||||
|
resp, body = self.get(self.policy_rules % (policy_name))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_policy(self):
|
||||||
|
resp, body = self.get(self.policies)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_policy_tables(self, policy_name):
|
||||||
|
resp, body = self.get(self.policy_tables % (policy_name))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def execute_policy_action(self, policy_name, action, trace, delta, body):
|
||||||
|
body = json.dumps(body)
|
||||||
|
uri = "?action=%s&trace=%s&delta=%s" % (action, trace, delta)
|
||||||
|
resp, body = self.post(
|
||||||
|
(self.policy_path % policy_name) + str(uri), body=body)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_policy_table(self, policy_name, table_id):
|
||||||
|
resp, body = self.get(self.policy_table_path % (policy_name, table_id))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_datasources(self):
|
||||||
|
resp, body = self.get(self.datasources)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_datasource_tables(self, datasource_name):
|
||||||
|
resp, body = self.get(self.datasource_tables % (datasource_name))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_datasource_rows(self, datasource_name, table_name):
|
||||||
|
resp, body = self.get(self.datasource_rows %
|
||||||
|
(datasource_name, table_name))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_datasource_status(self, datasource_name):
|
||||||
|
resp, body = self.get(self.datasource_status % datasource_name)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_datasource_schema(self, datasource_name):
|
||||||
|
resp, body = self.get(self.datasource_schema % datasource_name)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_datasource_table_schema(self, datasource_name, table_name):
|
||||||
|
resp, body = self.get(self.datasource_table_schema %
|
||||||
|
(datasource_name, table_name))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_datasource_table(self, datasource_name, table_id):
|
||||||
|
resp, body = self.get(self.datasource_table_path %
|
||||||
|
(datasource_name, table_id))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def create_datasource(self, body=None):
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post(
|
||||||
|
self.datasources, body=body)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def delete_datasource(self, datasource):
|
||||||
|
resp, body = self.delete(
|
||||||
|
self.datasource_path % datasource)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def execute_datasource_action(self, service_name, action, body):
|
||||||
|
body = json.dumps(body)
|
||||||
|
uri = "?action=%s" % (action)
|
||||||
|
resp, body = self.post(
|
||||||
|
(self.datasource_path % service_name) + str(uri), body=body)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def list_drivers(self):
|
||||||
|
resp, body = self.get(self.driver)
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def show_driver(self, driver):
|
||||||
|
resp, body = self.get(self.driver_path % (driver))
|
||||||
|
return self._resp_helper(resp, body)
|
||||||
|
|
||||||
|
def request_refresh(self, driver, body=None):
|
||||||
|
body = json.dumps(body)
|
||||||
|
resp, body = self.post(self.datasource_path %
|
||||||
|
(driver) + "?action=request-refresh",
|
||||||
|
body=body)
|
||||||
|
return self._resp_helper(resp, body)
|
|
@ -0,0 +1,17 @@
|
||||||
|
====================
|
||||||
|
Tempest Integration
|
||||||
|
====================
|
||||||
|
|
||||||
|
This directory contains Tempest tests to cover Congress project.
|
||||||
|
|
||||||
|
To list all Congress tempest cases, go to tempest directory, then run::
|
||||||
|
|
||||||
|
$ testr list-tests congress
|
||||||
|
|
||||||
|
To run only these tests in tempest, go to tempest directory, then run::
|
||||||
|
|
||||||
|
$ ./run_tempest -N -- congress
|
||||||
|
|
||||||
|
To run a single test case, go to tempest directory, then run with test case name, e.g.::
|
||||||
|
|
||||||
|
$ ./run_tempest.sh -N -- congress_tempest_tests.tests.scenario.test_congress_basic_ops.TestPolicyBasicOps.test_policy_basic_op
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Copyright 2014 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.
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import clients # noqa
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCeilometerDriver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestCeilometerDriver, cls).check_preconditions()
|
||||||
|
|
||||||
|
def setUp(cls):
|
||||||
|
super(TestCeilometerDriver, cls).setUp()
|
||||||
|
if not CONF.service_available.ceilometer:
|
||||||
|
msg = ("%s skipped as ceilometer is not available" %
|
||||||
|
cls.__class__.__name__)
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
cls.os = clients.Manager(cls.admin_manager.auth_provider.credentials)
|
||||||
|
cls.telemetry_client = cls.os.telemetry_client
|
||||||
|
cls.datasource_id = manager_congress.get_datasource_id(
|
||||||
|
cls.admin_manager.congress_client, 'ceilometer')
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_ceilometer_meters_table(self):
|
||||||
|
meter_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'meters')['columns'])
|
||||||
|
meter_id_col = next(i for i, c in enumerate(meter_schema)
|
||||||
|
if c['name'] == 'meter_id')
|
||||||
|
|
||||||
|
def _check_data_table_ceilometer_meters():
|
||||||
|
# Fetch data from ceilometer each time, because this test may start
|
||||||
|
# before ceilometer has all the users.
|
||||||
|
meters = self.telemetry_client.list_meters()
|
||||||
|
meter_map = {}
|
||||||
|
for meter in meters:
|
||||||
|
meter_map[meter['meter_id']] = meter
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'meters'))
|
||||||
|
for row in results['results']:
|
||||||
|
try:
|
||||||
|
meter_row = meter_map[row['data'][meter_id_col]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(meter_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(meter_row[meter_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_ceilometer_meters,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Copyright 2014 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.
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import clients # noqa
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCinderDriver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestCinderDriver, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable or
|
||||||
|
CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or'
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(cls):
|
||||||
|
super(TestCinderDriver, cls).setUp()
|
||||||
|
cls.os = clients.Manager(cls.admin_manager.auth_provider.credentials)
|
||||||
|
cls.cinder = cls.os.volumes_client
|
||||||
|
cls.datasource_id = manager_congress.get_datasource_id(
|
||||||
|
cls.admin_manager.congress_client, 'cinder')
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_cinder_volumes_table(self):
|
||||||
|
volume_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'volumes')['columns'])
|
||||||
|
volume_id_col = next(i for i, c in enumerate(volume_schema)
|
||||||
|
if c['name'] == 'id')
|
||||||
|
|
||||||
|
def _check_data_table_cinder_volumes():
|
||||||
|
# Fetch data from cinder each time, because this test may start
|
||||||
|
# before cinder has all the users.
|
||||||
|
volumes = self.cinder.list_volumes()
|
||||||
|
volumes_map = {}
|
||||||
|
for volume in volumes:
|
||||||
|
volumes_map[volume['id']] = volume
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'volumes'))
|
||||||
|
for row in results['results']:
|
||||||
|
try:
|
||||||
|
volume_row = volumes_map[row['data'][volume_id_col]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(volume_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(volume_row[volume_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_cinder_volumes,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
|
@ -0,0 +1,127 @@
|
||||||
|
# Copyright 2014 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.
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import clients # noqa
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGlanceV2Driver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestGlanceV2Driver, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable
|
||||||
|
or CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or '
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(cls):
|
||||||
|
super(TestGlanceV2Driver, cls).setUp()
|
||||||
|
if not CONF.service_available.glance:
|
||||||
|
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
|
||||||
|
raise cls.skipException(skip_msg)
|
||||||
|
cls.os = clients.Manager()
|
||||||
|
cls.glancev2 = cls.os.image_client_v2
|
||||||
|
cls.datasource_id = manager_congress.get_datasource_id(
|
||||||
|
cls.admin_manager.congress_client, 'glancev2')
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('image')
|
||||||
|
def test_glancev2_images_table(self):
|
||||||
|
image_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'images')['columns'])
|
||||||
|
image_id_col = next(i for i, c in enumerate(image_schema)
|
||||||
|
if c['name'] == 'id')
|
||||||
|
|
||||||
|
def _check_data_table_glancev2_images():
|
||||||
|
# Fetch data from glance each time, because this test may start
|
||||||
|
# before glance has all the users.
|
||||||
|
images = self.glancev2.list_images()
|
||||||
|
image_map = {}
|
||||||
|
for image in images:
|
||||||
|
image_map[image['id']] = image
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'images'))
|
||||||
|
for row in results['results']:
|
||||||
|
try:
|
||||||
|
image_row = image_map[row['data'][image_id_col]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(image_schema)):
|
||||||
|
# glancev2 doesn't return kernel_id/ramdisk_id if
|
||||||
|
# it isn't present...
|
||||||
|
if ((image_schema[index]['name'] == 'kernel_id' and
|
||||||
|
'kernel_id' not in row['data']) or
|
||||||
|
(image_schema[index]['name'] == 'ramdisk_id' and
|
||||||
|
'ramdisk_id' not in row['data'])):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# FIXME(arosen): congress-server should retain the type
|
||||||
|
# but doesn't today.
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(image_row[image_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_glancev2_images,
|
||||||
|
duration=100, sleep_for=4):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('image')
|
||||||
|
def test_glancev2_tags_table(self):
|
||||||
|
def _check_data_table_glance_images():
|
||||||
|
# Fetch data from glance each time, because this test may start
|
||||||
|
# before glance has all the users.
|
||||||
|
images = self.glancev2.list_images()
|
||||||
|
image_tag_map = {}
|
||||||
|
for image in images:
|
||||||
|
image_tag_map[image['id']] = image['tags']
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'tags'))
|
||||||
|
for row in results['results']:
|
||||||
|
image_id, tag = row['data'][0], row['data'][1]
|
||||||
|
glance_image_tags = image_tag_map.get(image_id)
|
||||||
|
if not glance_image_tags:
|
||||||
|
# congress had image that glance doesn't know about.
|
||||||
|
return False
|
||||||
|
if tag not in glance_image_tags:
|
||||||
|
# congress had a tag that wasn't on the image.
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_glance_images,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
|
@ -0,0 +1,161 @@
|
||||||
|
# Copyright 2014 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.
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import clients # noqa
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestKeystoneV2Driver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestKeystoneV2Driver, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable or
|
||||||
|
CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or'
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(cls):
|
||||||
|
super(TestKeystoneV2Driver, cls).setUp()
|
||||||
|
cls.os = clients.Manager(cls.admin_manager.auth_provider.credentials)
|
||||||
|
cls.keystone = cls.os.identity_client
|
||||||
|
cls.datasource_id = manager_congress.get_datasource_id(
|
||||||
|
cls.admin_manager.congress_client, 'keystone')
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_keystone_users_table(self):
|
||||||
|
user_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'users')['columns'])
|
||||||
|
user_id_col = next(i for i, c in enumerate(user_schema)
|
||||||
|
if c['name'] == 'id')
|
||||||
|
|
||||||
|
def _check_data_table_keystone_users():
|
||||||
|
# Fetch data from keystone each time, because this test may start
|
||||||
|
# before keystone has all the users.
|
||||||
|
users = self.keystone.get_users()
|
||||||
|
user_map = {}
|
||||||
|
for user in users:
|
||||||
|
user_map[user['id']] = user
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'users'))
|
||||||
|
for row in results['results']:
|
||||||
|
try:
|
||||||
|
user_row = user_map[row['data'][user_id_col]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(user_schema)):
|
||||||
|
if ((user_schema[index]['name'] == 'tenantId' and
|
||||||
|
'tenantId' not in user_row) or
|
||||||
|
(user_schema[index]['name'] == 'email' and
|
||||||
|
'email' not in user_row)):
|
||||||
|
# Keystone does not return the tenantId or email column
|
||||||
|
# if not present.
|
||||||
|
pass
|
||||||
|
elif (str(row['data'][index]) !=
|
||||||
|
str(user_row[user_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_keystone_users,
|
||||||
|
duration=100, sleep_for=4):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_keystone_roles_table(self):
|
||||||
|
role_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'roles')['columns'])
|
||||||
|
role_id_col = next(i for i, c in enumerate(role_schema)
|
||||||
|
if c['name'] == 'id')
|
||||||
|
|
||||||
|
def _check_data_table_keystone_roles():
|
||||||
|
# Fetch data from keystone each time, because this test may start
|
||||||
|
# before keystone has all the users.
|
||||||
|
roles = self.keystone.list_roles()
|
||||||
|
roles_map = {}
|
||||||
|
for role in roles:
|
||||||
|
roles_map[role['id']] = role
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'roles'))
|
||||||
|
for row in results['results']:
|
||||||
|
try:
|
||||||
|
role_row = roles_map[row['data'][role_id_col]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(role_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(role_row[role_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_keystone_roles,
|
||||||
|
duration=100, sleep_for=4):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_keystone_tenants_table(self):
|
||||||
|
tenant_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'tenants')['columns'])
|
||||||
|
tenant_id_col = next(i for i, c in enumerate(tenant_schema)
|
||||||
|
if c['name'] == 'id')
|
||||||
|
|
||||||
|
def _check_data_table_keystone_tenants():
|
||||||
|
# Fetch data from keystone each time, because this test may start
|
||||||
|
# before keystone has all the users.
|
||||||
|
tenants = self.keystone.list_tenants()
|
||||||
|
tenants_map = {}
|
||||||
|
for tenant in tenants:
|
||||||
|
tenants_map[tenant['id']] = tenant
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'tenants'))
|
||||||
|
for row in results['results']:
|
||||||
|
try:
|
||||||
|
tenant_row = tenants_map[row['data'][tenant_id_col]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(tenant_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(tenant_row[tenant_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_keystone_tenants,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
|
@ -0,0 +1,189 @@
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard. 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 random
|
||||||
|
import string
|
||||||
|
|
||||||
|
from tempest import config
|
||||||
|
from tempest import test
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class TestMuranoDriver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestMuranoDriver, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable
|
||||||
|
or CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or '
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestMuranoDriver, self).setUp()
|
||||||
|
self.congress_client = (
|
||||||
|
self.admin_manager.congress_client)
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('compute')
|
||||||
|
def test_murano_predeployment(self):
|
||||||
|
|
||||||
|
def _delete_policy_rules(policy_name):
|
||||||
|
result = self.congress_client.list_policy_rules(
|
||||||
|
policy_name)['results']
|
||||||
|
for rule in result:
|
||||||
|
self.congress_client.delete_policy_rule(
|
||||||
|
policy_name,
|
||||||
|
rule['id'])
|
||||||
|
|
||||||
|
def _create_random_policy():
|
||||||
|
policy_name = "murano_%s" % ''.join(random.choice(string.lowercase)
|
||||||
|
for x in range(10))
|
||||||
|
body = {"name": policy_name}
|
||||||
|
resp = self.congress_client.create_policy(body)
|
||||||
|
self.addCleanup(_delete_policy_rules, resp['name'])
|
||||||
|
return resp['name']
|
||||||
|
|
||||||
|
def _create_datasource():
|
||||||
|
body = {"config": {"username": CONF.identity.admin_username,
|
||||||
|
"tenant_name": CONF.identity.admin_tenant_name,
|
||||||
|
"password": CONF.identity.admin_password,
|
||||||
|
"auth_url": CONF.identity.uri},
|
||||||
|
"driver": "murano",
|
||||||
|
"name": "murano"}
|
||||||
|
datasource = self.congress_client.create_datasource(body)['id']
|
||||||
|
self.addCleanup(self.congress_client.delete_datasource, datasource)
|
||||||
|
|
||||||
|
def _create_rule(policy_name, rule):
|
||||||
|
self.congress_client.create_policy_rule(policy_name, rule)
|
||||||
|
|
||||||
|
def _simulate_policy(policy_name, query):
|
||||||
|
resp = self.congress_client.execute_policy_action(
|
||||||
|
policy_name,
|
||||||
|
"simulate",
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
query)
|
||||||
|
return resp['result']
|
||||||
|
|
||||||
|
rule1 = {
|
||||||
|
"rule": "allowed_flavors(flavor) :- nova:flavors(flavor_id,"
|
||||||
|
"flavor, vcpus, ram, disk, ephemeral, rxtx_factor),"
|
||||||
|
"equal(flavor, \"m1.medium\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule2 = {
|
||||||
|
"rule": "allowed_flavors(flavor) :- nova:flavors(flavor_id,"
|
||||||
|
"flavor, vcpus, ram, disk, ephemeral, rxtx_factor),"
|
||||||
|
"equal(flavor, \"m1.small\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule3 = {
|
||||||
|
"rule": "allowed_flavors(flavor) :- nova:flavors(flavor_id,"
|
||||||
|
"flavor, vcpus, ram, disk, ephemeral, rxtx_factor),"
|
||||||
|
"equal(flavor, \"m1.tiny\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule4 = {
|
||||||
|
"rule": "murano_pending_envs(env_id) :- "
|
||||||
|
"murano:objects(env_id, tenant_id, \"io.murano.Environment\"),"
|
||||||
|
"murano:states(env_id, env_state),"
|
||||||
|
"equal(env_state, \"pending\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule5 = {
|
||||||
|
"rule": "murano_instances(env_id, instance_id) :- "
|
||||||
|
"murano:objects(env_id, tenant_id, \"io.murano.Environment\"),"
|
||||||
|
"murano:objects(service_id, env_id, service_type),"
|
||||||
|
"murano:parent_types(service_id, \"io.murano.Object\"),"
|
||||||
|
"murano:parent_types(service_id, \"io.murano.Application\"),"
|
||||||
|
"murano:parent_types(service_id, service_type),"
|
||||||
|
"murano:objects(instance_id, service_id, instance_type),"
|
||||||
|
"murano:parent_types(instance_id,"
|
||||||
|
"\"io.murano.resources.Instance\"),"
|
||||||
|
"murano:parent_types(instance_id, \"io.murano.Object\"),"
|
||||||
|
"murano:parent_types(instance_id, instance_type)"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule6 = {
|
||||||
|
"rule": "murano_instance_flavors(instance_id, flavor) :- "
|
||||||
|
"murano:properties(instance_id, \"flavor\", flavor)"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule7 = {
|
||||||
|
"rule": "predeploy_error(env_id) :- "
|
||||||
|
"murano_pending_envs(env_id),"
|
||||||
|
"murano_instances(env_id, instance_id),"
|
||||||
|
"murano_instance_flavors(instance_id, flavor),"
|
||||||
|
"not allowed_flavors(flavor)"
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_query1 = {
|
||||||
|
"query": "predeploy_error(env_id)",
|
||||||
|
"action_policy": "action",
|
||||||
|
"sequence": "murano:objects+(\"env_uuid\", \"tenant_uuid\","
|
||||||
|
"\"io.murano.Environment\") murano:states+(\"env_uuid\", "
|
||||||
|
"\"pending\") murano:objects+(\"service_uuid\", \"env_uuid\", "
|
||||||
|
"\"service_type\") murano:parent_types+(\"service_uuid\", "
|
||||||
|
"\"io.murano.Object\") murano:parent_types+(\"service_uuid\", "
|
||||||
|
"\"io.murano.Application\") murano:parent_types+(\"service_uuid\","
|
||||||
|
"\"service_type\") murano:objects+(\"instance_uuid\", "
|
||||||
|
"\"service_uuid\", \"service_type\") murano:objects+(\""
|
||||||
|
"instance_uuid\", \"service_uuid\", \"instance_type\") "
|
||||||
|
"murano:parent_types+(\"instance_uuid\", "
|
||||||
|
"\"io.murano.resources.Instance\") murano:parent_types+(\""
|
||||||
|
"instance_uuid\", \"io.murano.Object\") murano:parent_types+(\""
|
||||||
|
"instance_uuid\", \"instance_type\") murano:properties+(\""
|
||||||
|
"instance_uuid\", \"flavor\", \"m1.small\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_query2 = {
|
||||||
|
"query": "predeploy_error(env_id)",
|
||||||
|
"action_policy": "action",
|
||||||
|
"sequence": "murano:objects+(\"env_uuid\", \"tenant_uuid\","
|
||||||
|
"\"io.murano.Environment\") murano:states+(\"env_uuid\", "
|
||||||
|
"\"pending\") murano:objects+(\"service_uuid\", \"env_uuid\", "
|
||||||
|
"\"service_type\") murano:parent_types+(\"service_uuid\", "
|
||||||
|
"\"io.murano.Object\") murano:parent_types+(\"service_uuid\", "
|
||||||
|
"\"io.murano.Application\") murano:parent_types+(\"service_uuid\","
|
||||||
|
"\"service_type\") murano:objects+(\"instance_uuid\", "
|
||||||
|
"\"service_uuid\", \"service_type\") murano:objects+(\""
|
||||||
|
"instance_uuid\", \"service_uuid\", \"instance_type\") "
|
||||||
|
"murano:parent_types+(\"instance_uuid\", "
|
||||||
|
"\"io.murano.resources.Instance\") murano:parent_types+(\""
|
||||||
|
"instance_uuid\", \"io.murano.Object\") murano:parent_types+(\""
|
||||||
|
"instance_uuid\", \"instance_type\") murano:properties+(\""
|
||||||
|
"instance_uuid\", \"flavor\", \"m1.large\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
_create_datasource()
|
||||||
|
policy_name = _create_random_policy()
|
||||||
|
_create_rule(policy_name, rule1)
|
||||||
|
_create_rule(policy_name, rule2)
|
||||||
|
_create_rule(policy_name, rule3)
|
||||||
|
_create_rule(policy_name, rule4)
|
||||||
|
_create_rule(policy_name, rule5)
|
||||||
|
_create_rule(policy_name, rule6)
|
||||||
|
_create_rule(policy_name, rule7)
|
||||||
|
result = _simulate_policy(policy_name, sim_query1)
|
||||||
|
self.assertEqual([], result)
|
||||||
|
result = _simulate_policy(policy_name, sim_query2)
|
||||||
|
self.assertEqual('predeploy_error("env_uuid")', result[0])
|
|
@ -0,0 +1,386 @@
|
||||||
|
# Copyright 2014 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.
|
||||||
|
import time
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import clients # noqa
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNeutronV2Driver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestNeutronV2Driver, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable
|
||||||
|
or CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or '
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(cls):
|
||||||
|
super(TestNeutronV2Driver, cls).setUp()
|
||||||
|
if not CONF.service_available.neutron:
|
||||||
|
skip_msg = ("%s skipped as neutron is not available"
|
||||||
|
% cls.__name__)
|
||||||
|
raise cls.skipException(skip_msg)
|
||||||
|
cls.os = clients.Manager(cls.admin_manager.auth_provider.credentials)
|
||||||
|
cls.neutron_client = cls.os.network_client
|
||||||
|
cls.datasource_id = manager_congress.get_datasource_id(
|
||||||
|
cls.admin_manager.congress_client, 'neutronv2')
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('network')
|
||||||
|
def test_neutronv2_networks_table(self):
|
||||||
|
def _check_data():
|
||||||
|
networks = self.neutron_client.list_networks()
|
||||||
|
network_map = {}
|
||||||
|
for network in networks['networks']:
|
||||||
|
network_map[network['id']] = network
|
||||||
|
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
client.request_refresh(self.datasource_id)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
network_schema = (client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'networks')['columns'])
|
||||||
|
|
||||||
|
results = (client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'networks'))
|
||||||
|
for row in results['results']:
|
||||||
|
network_row = network_map[row['data'][0]]
|
||||||
|
for index in range(len(network_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(network_row[network_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data,
|
||||||
|
duration=200, sleep_for=10):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('network')
|
||||||
|
def test_neutronv2_ports_tables(self):
|
||||||
|
port_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'ports')['columns'])
|
||||||
|
|
||||||
|
port_sec_binding_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'security_group_port_bindings')['columns'])
|
||||||
|
|
||||||
|
fixed_ips_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'fixed_ips')['columns'])
|
||||||
|
|
||||||
|
def _check_data():
|
||||||
|
ports_from_neutron = self.neutron_client.list_ports()
|
||||||
|
port_map = {}
|
||||||
|
for port in ports_from_neutron['ports']:
|
||||||
|
port_map[port['id']] = port
|
||||||
|
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
client.request_refresh(self.datasource_id)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
ports = (client.list_datasource_rows(self.datasource_id, 'ports'))
|
||||||
|
security_group_port_bindings = (
|
||||||
|
client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'security_group_port_bindings'))
|
||||||
|
fixed_ips = (
|
||||||
|
client.list_datasource_rows(self.datasource_id, 'fixed_ips'))
|
||||||
|
|
||||||
|
# Validate ports table
|
||||||
|
for row in ports['results']:
|
||||||
|
port_row = port_map[row['data'][0]]
|
||||||
|
for index in range(len(port_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(port_row[port_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# validate security_group_port_bindings table
|
||||||
|
for row in security_group_port_bindings['results']:
|
||||||
|
port_row = port_map[row['data'][0]]
|
||||||
|
for index in range(len(port_sec_binding_schema)):
|
||||||
|
row_index = port_sec_binding_schema[index]['name']
|
||||||
|
# Translate port_id -> id
|
||||||
|
if row_index == 'port_id':
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(port_row['id'])):
|
||||||
|
return False
|
||||||
|
elif row_index == 'security_group_id':
|
||||||
|
if (str(row['data'][index]) not in
|
||||||
|
port_row['security_groups']):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# validate fixed_ips
|
||||||
|
for row in fixed_ips['results']:
|
||||||
|
port_row = port_map[row['data'][0]]
|
||||||
|
for index in range(len(fixed_ips_schema)):
|
||||||
|
row_index = fixed_ips_schema[index]['name']
|
||||||
|
if row_index in ['subnet_id', 'ip_address']:
|
||||||
|
if not port_row['fixed_ips']:
|
||||||
|
continue
|
||||||
|
for fixed_ip in port_row['fixed_ips']:
|
||||||
|
if row['data'][index] == fixed_ip[row_index]:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# no subnet_id/ip_address match found
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data,
|
||||||
|
duration=200, sleep_for=10):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('network')
|
||||||
|
def test_neutronv2_subnets_tables(self):
|
||||||
|
subnet_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'subnets')['columns'])
|
||||||
|
|
||||||
|
host_routes_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'host_routes')['columns'])
|
||||||
|
|
||||||
|
dns_nameservers_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'dns_nameservers')['columns'])
|
||||||
|
|
||||||
|
allocation_pools_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'allocation_pools')['columns'])
|
||||||
|
|
||||||
|
def _check_data():
|
||||||
|
subnets_from_neutron = self.neutron_client.list_subnets()
|
||||||
|
subnet_map = {}
|
||||||
|
for subnet in subnets_from_neutron['subnets']:
|
||||||
|
subnet_map[subnet['id']] = subnet
|
||||||
|
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
client.request_refresh(self.datasource_id)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
subnets = (
|
||||||
|
client.list_datasource_rows(self.datasource_id, 'subnets'))
|
||||||
|
host_routes = (
|
||||||
|
client.list_datasource_rows(self.datasource_id, 'host_routes'))
|
||||||
|
dns_nameservers = (
|
||||||
|
client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'dns_nameservers'))
|
||||||
|
allocation_pools = (
|
||||||
|
client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'allocation_pools'))
|
||||||
|
|
||||||
|
# Validate subnets table
|
||||||
|
for row in subnets['results']:
|
||||||
|
subnet_row = subnet_map[row['data'][0]]
|
||||||
|
for index in range(len(subnet_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(subnet_row[subnet_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# validate dns_nameservers
|
||||||
|
for row in dns_nameservers['results']:
|
||||||
|
subnet_row = subnet_map[row['data'][0]]
|
||||||
|
for index in range(len(dns_nameservers_schema)):
|
||||||
|
row_index = dns_nameservers_schema[index]['name']
|
||||||
|
if row_index in ['dns_nameserver']:
|
||||||
|
if (row['data'][index]
|
||||||
|
not in subnet_row['dns_nameservers']):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# validate host_routes
|
||||||
|
for row in host_routes['results']:
|
||||||
|
subnet_row = subnet_map[row['data'][0]]
|
||||||
|
for index in range(len(host_routes_schema)):
|
||||||
|
row_index = host_routes_schema[index]['name']
|
||||||
|
if row_index in ['destination', 'nexthop']:
|
||||||
|
if not subnet_row['host_routes']:
|
||||||
|
continue
|
||||||
|
for host_route in subnet_row['host_routes']:
|
||||||
|
if row['data'][index] == host_route[row_index]:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# no destination/nexthop match found
|
||||||
|
return False
|
||||||
|
|
||||||
|
# validate allocation_pools
|
||||||
|
for row in allocation_pools['results']:
|
||||||
|
subnet_row = subnet_map[row['data'][0]]
|
||||||
|
for index in range(len(allocation_pools_schema)):
|
||||||
|
row_index = allocation_pools_schema[index]['name']
|
||||||
|
if row_index in ['start', 'end']:
|
||||||
|
if not subnet_row['allocation_pools']:
|
||||||
|
continue
|
||||||
|
for allocation_pool in subnet_row['allocation_pools']:
|
||||||
|
if (row['data'][index] ==
|
||||||
|
allocation_pool[row_index]):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# no destination/nexthop match found
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data,
|
||||||
|
duration=200, sleep_for=10):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('network')
|
||||||
|
def test_neutronv2_routers_tables(self):
|
||||||
|
router_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'routers')['columns'])
|
||||||
|
|
||||||
|
ext_gw_info_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'external_gateway_infos')['columns'])
|
||||||
|
|
||||||
|
def _check_data():
|
||||||
|
routers_from_neutron = self.neutron_client.list_routers()
|
||||||
|
router_map = {}
|
||||||
|
for router in routers_from_neutron['routers']:
|
||||||
|
router_map[router['id']] = router
|
||||||
|
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
client.request_refresh(self.datasource_id)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
routers = (
|
||||||
|
client.list_datasource_rows(self.datasource_id, 'routers'))
|
||||||
|
|
||||||
|
ext_gw_info = (
|
||||||
|
client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'external_gateway_infos'))
|
||||||
|
|
||||||
|
# Validate routers table
|
||||||
|
for row in routers['results']:
|
||||||
|
router_row = router_map[row['data'][0]]
|
||||||
|
for index in range(len(router_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(router_row[router_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# validate external_gateway_infos
|
||||||
|
for row in ext_gw_info['results']:
|
||||||
|
router_ext_gw_info = (
|
||||||
|
router_map[row['data'][0]]['external_gateway_info'])
|
||||||
|
# populate router_id
|
||||||
|
router_ext_gw_info['router_id'] = row['data'][0]
|
||||||
|
for index in range(len(ext_gw_info_schema)):
|
||||||
|
val = router_ext_gw_info[ext_gw_info_schema[index]['name']]
|
||||||
|
if (str(row['data'][index]) != str(val)):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data,
|
||||||
|
duration=200, sleep_for=10):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('network')
|
||||||
|
def test_neutronv2_security_groups_table(self):
|
||||||
|
sg_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'security_groups')['columns'])
|
||||||
|
|
||||||
|
def _check_data():
|
||||||
|
client = self.neutron_client
|
||||||
|
security_groups_neutron = client.list_security_groups()
|
||||||
|
security_groups_map = {}
|
||||||
|
for security_group in security_groups_neutron['security_groups']:
|
||||||
|
security_groups_map[security_group['id']] = security_group
|
||||||
|
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
client.request_refresh(self.datasource_id)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
security_groups = (
|
||||||
|
client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'security_groups'))
|
||||||
|
|
||||||
|
# Validate security_group table
|
||||||
|
for row in security_groups['results']:
|
||||||
|
sg_row = security_groups_map[row['data'][0]]
|
||||||
|
for index in range(len(sg_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(sg_row[sg_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data,
|
||||||
|
duration=200, sleep_for=10):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('network')
|
||||||
|
def test_neutronv2_security_group_rules_table(self):
|
||||||
|
sgrs_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'security_group_rules')['columns'])
|
||||||
|
|
||||||
|
def _check_data():
|
||||||
|
client = self.neutron_client
|
||||||
|
security_groups_neutron = client.list_security_groups()
|
||||||
|
sgrs_map = {} # security_group_rules
|
||||||
|
for sg in security_groups_neutron['security_groups']:
|
||||||
|
for sgr in sg['security_group_rules']:
|
||||||
|
sgrs_map[sgr['id']] = sgr
|
||||||
|
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
client.request_refresh(self.datasource_id)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
security_group_rules = (
|
||||||
|
client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'security_group_rules'))
|
||||||
|
|
||||||
|
# Validate security_group_rules table
|
||||||
|
for row in security_group_rules['results']:
|
||||||
|
sg_rule_row = sgrs_map[row['data'][1]]
|
||||||
|
for index in range(len(sgrs_schema)):
|
||||||
|
if (str(row['data'][index]) !=
|
||||||
|
str(sg_rule_row[sgrs_schema[index]['name']])):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data,
|
||||||
|
duration=200, sleep_for=10):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
|
@ -0,0 +1,130 @@
|
||||||
|
# Copyright 2014 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.
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestNovaDriver(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestNovaDriver, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable
|
||||||
|
or CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or '
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestNovaDriver, self).setUp()
|
||||||
|
self.keypairs = {}
|
||||||
|
self.servers = []
|
||||||
|
self.datasource_id = manager_congress.get_datasource_id(
|
||||||
|
self.admin_manager.congress_client, 'nova')
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('compute', 'network')
|
||||||
|
def test_nova_datasource_driver_servers(self):
|
||||||
|
self._setup_network_and_servers()
|
||||||
|
|
||||||
|
server_schema = (
|
||||||
|
self.admin_manager.congress_client.show_datasource_table_schema(
|
||||||
|
self.datasource_id, 'servers')['columns'])
|
||||||
|
# Convert some of the column names.
|
||||||
|
|
||||||
|
def convert_col(col):
|
||||||
|
if col == 'host_id':
|
||||||
|
return 'hostId'
|
||||||
|
elif col == 'image_id':
|
||||||
|
return 'image'
|
||||||
|
elif col == 'flavor_id':
|
||||||
|
return 'flavor'
|
||||||
|
else:
|
||||||
|
return col
|
||||||
|
|
||||||
|
keys = [convert_col(c['name']) for c in server_schema]
|
||||||
|
|
||||||
|
def _check_data_table_nova_servers():
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'servers'))
|
||||||
|
for row in results['results']:
|
||||||
|
match = True
|
||||||
|
for index in range(len(keys)):
|
||||||
|
if keys[index] in ['image', 'flavor']:
|
||||||
|
val = self.servers[0][keys[index]]['id']
|
||||||
|
else:
|
||||||
|
val = self.servers[0][keys[index]]
|
||||||
|
|
||||||
|
if row['data'][index] != val:
|
||||||
|
match = False
|
||||||
|
break
|
||||||
|
if match:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_nova_servers,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('compute', 'network')
|
||||||
|
def test_nova_datasource_driver_flavors(self):
|
||||||
|
def _check_data_table_nova_flavors():
|
||||||
|
# Fetch data from nova each time, because this test may start
|
||||||
|
# before nova has all the users.
|
||||||
|
flavors = self.flavors_client.list_flavors(detail=True)
|
||||||
|
flavor_id_map = {}
|
||||||
|
for flavor in flavors:
|
||||||
|
flavor_id_map[flavor['id']] = flavor
|
||||||
|
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_rows(
|
||||||
|
self.datasource_id, 'flavors'))
|
||||||
|
# TODO(alexsyip): Not sure what the following OS-FLV-EXT-DATA:
|
||||||
|
# prefix is for.
|
||||||
|
keys = ['id', 'name', 'vcpus', 'ram', 'disk',
|
||||||
|
'OS-FLV-EXT-DATA:ephemeral', 'rxtx_factor']
|
||||||
|
for row in results['results']:
|
||||||
|
match = True
|
||||||
|
try:
|
||||||
|
flavor_row = flavor_id_map[row['data'][0]]
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
for index in range(len(keys)):
|
||||||
|
if row['data'][index] != flavor_row[keys[index]]:
|
||||||
|
match = False
|
||||||
|
break
|
||||||
|
if match:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not test.call_until_true(func=_check_data_table_nova_flavors,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
|
@ -0,0 +1,299 @@
|
||||||
|
# Copyright 2015 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.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest.common import cred_provider
|
||||||
|
from tempest import config
|
||||||
|
from tempest import exceptions
|
||||||
|
from tempest import manager as tempestmanager
|
||||||
|
from tempest import test
|
||||||
|
from tempest_lib import decorators
|
||||||
|
from tempest_lib import exceptions as restexc
|
||||||
|
|
||||||
|
from congress_tempest_tests.services.policy import policy_client
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestHA(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestHA, self).setUp()
|
||||||
|
self.keypairs = {}
|
||||||
|
self.servers = []
|
||||||
|
self.replicas = {}
|
||||||
|
|
||||||
|
def _prepare_replica(self, port_num):
|
||||||
|
replica_url = "http://127.0.0.1:%d" % port_num
|
||||||
|
ksclient = self.admin_manager.identity_client
|
||||||
|
resp = ksclient.create_service('congressha',
|
||||||
|
CONF.congressha.replica_type,
|
||||||
|
description='policy ha service')
|
||||||
|
self.replica_service_id = resp['id']
|
||||||
|
resp = ksclient.create_endpoint(self.replica_service_id,
|
||||||
|
CONF.identity.region,
|
||||||
|
publicurl=replica_url,
|
||||||
|
adminurl=replica_url,
|
||||||
|
internalurl=replica_url)
|
||||||
|
self.replica_endpoint_id = resp['id']
|
||||||
|
|
||||||
|
def _cleanup_replica(self):
|
||||||
|
ksclient = self.admin_manager.identity_client
|
||||||
|
ksclient.delete_endpoint(self.replica_endpoint_id)
|
||||||
|
ksclient.delete_service(self.replica_service_id)
|
||||||
|
|
||||||
|
def start_replica(self, port_num):
|
||||||
|
self._prepare_replica(port_num)
|
||||||
|
f = tempfile.NamedTemporaryFile(mode='w', suffix='.conf',
|
||||||
|
prefix='congress%d-' % port_num,
|
||||||
|
dir='/tmp', delete=False)
|
||||||
|
conf_file = f.name
|
||||||
|
template = open('/etc/congress/congress.conf')
|
||||||
|
conf = template.read()
|
||||||
|
conf = conf.replace('# bind_port = 1789',
|
||||||
|
'bind_port = %d\n' % port_num)
|
||||||
|
conf = conf.replace('# datasource_sync_period = 60',
|
||||||
|
'datasource_sync_period = 5')
|
||||||
|
f.write(conf)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
args = ['/usr/bin/python',
|
||||||
|
'bin/congress-server',
|
||||||
|
'--config-file',
|
||||||
|
conf_file]
|
||||||
|
|
||||||
|
out = tempfile.NamedTemporaryFile(mode='w', suffix='.out',
|
||||||
|
prefix='congress%d-' % port_num,
|
||||||
|
dir='/tmp', delete=False)
|
||||||
|
err = tempfile.NamedTemporaryFile(mode='w', suffix='.err',
|
||||||
|
prefix='congress%d-' % port_num,
|
||||||
|
dir='/tmp', delete=False)
|
||||||
|
p = subprocess.Popen(args, stdout=out, stderr=err,
|
||||||
|
cwd='/opt/stack/congress')
|
||||||
|
|
||||||
|
assert port_num not in self.replicas
|
||||||
|
self.replicas[port_num] = (p, conf_file)
|
||||||
|
|
||||||
|
def stop_replica(self, port_num):
|
||||||
|
proc, conf_file = self.replicas[port_num]
|
||||||
|
# Using proc.terminate() will block at proc.wait(), no idea why yet
|
||||||
|
proc.kill()
|
||||||
|
proc.wait()
|
||||||
|
os.unlink(conf_file)
|
||||||
|
self.replicas[port_num] = (None, conf_file)
|
||||||
|
self._cleanup_replica()
|
||||||
|
|
||||||
|
def create_client(self, client_type):
|
||||||
|
creds = cred_provider.get_configured_credentials('identity_admin')
|
||||||
|
auth_prov = tempestmanager.get_auth_provider(creds)
|
||||||
|
|
||||||
|
return policy_client.PolicyClient(
|
||||||
|
auth_prov, client_type,
|
||||||
|
CONF.identity.region)
|
||||||
|
|
||||||
|
def datasource_exists(self, client, datasource_id):
|
||||||
|
try:
|
||||||
|
LOG.debug("datasource_exists begin")
|
||||||
|
body = client.list_datasource_status(datasource_id)
|
||||||
|
LOG.debug("list_datasource_status: %s", str(body))
|
||||||
|
except restexc.NotFound as e:
|
||||||
|
LOG.debug("not found")
|
||||||
|
return False
|
||||||
|
except restexc.Unauthorized as e:
|
||||||
|
LOG.debug("connection refused")
|
||||||
|
return False
|
||||||
|
except socket.error as e:
|
||||||
|
LOG.debug("Replica server not ready")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
return True
|
||||||
|
|
||||||
|
def datasource_missing(self, client, datasource_id):
|
||||||
|
try:
|
||||||
|
LOG.debug("datasource_missing begin")
|
||||||
|
body = client.list_datasource_status(datasource_id)
|
||||||
|
LOG.debug("list_datasource_status: %s", str(body))
|
||||||
|
except restexc.NotFound as e:
|
||||||
|
LOG.debug("not found")
|
||||||
|
return True
|
||||||
|
except restexc.Unauthorized as e:
|
||||||
|
LOG.debug("connection refused")
|
||||||
|
return False
|
||||||
|
except socket.error as e:
|
||||||
|
LOG.debug("Replica server not ready")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
return False
|
||||||
|
|
||||||
|
def find_fake(self, client):
|
||||||
|
datasources = client.list_datasources()
|
||||||
|
for r in datasources['results']:
|
||||||
|
if r['name'] == 'fake':
|
||||||
|
LOG.debug('existing fake driver: %s', str(r['id']))
|
||||||
|
return r['id']
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_fake(self, client):
|
||||||
|
# Create fake datasource if it does not exist. Returns the
|
||||||
|
# fake datasource id.
|
||||||
|
fake_id = self.find_fake(client)
|
||||||
|
if fake_id:
|
||||||
|
return fake_id
|
||||||
|
|
||||||
|
item = {'id': None,
|
||||||
|
'name': 'fake',
|
||||||
|
'driver': 'fake_datasource',
|
||||||
|
'config': '{"username":"fakeu", "tenant_name": "faket",' +
|
||||||
|
'"password": "fakep",' +
|
||||||
|
'"auth_url": "http://127.0.0.1:5000/v2"}',
|
||||||
|
'description': 'bar',
|
||||||
|
'enabled': True}
|
||||||
|
ret = client.create_datasource(item)
|
||||||
|
LOG.debug('created fake driver: %s', str(ret['id']))
|
||||||
|
return ret['id']
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_datasource_db_sync_add(self):
|
||||||
|
# Verify that a replica adds a datasource when a datasource
|
||||||
|
# appears in the database.
|
||||||
|
client1 = self.admin_manager.congress_client
|
||||||
|
|
||||||
|
# delete fake if it exists.
|
||||||
|
old_fake_id = self.find_fake(client1)
|
||||||
|
if old_fake_id:
|
||||||
|
client1.delete_datasource(old_fake_id)
|
||||||
|
|
||||||
|
# Verify that primary server has no fake datasource
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_missing(client1, old_fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"primary should not have fake, but does")
|
||||||
|
|
||||||
|
need_to_delete_fake = False
|
||||||
|
try:
|
||||||
|
# Create a new fake datasource
|
||||||
|
fake_id = self.create_fake(client1)
|
||||||
|
need_to_delete_fake = True
|
||||||
|
|
||||||
|
# Verify that primary server has fake datasource
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_exists(client1, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"primary should have fake, but does not")
|
||||||
|
|
||||||
|
# start replica
|
||||||
|
self.start_replica(CONF.congressha.replica_port)
|
||||||
|
|
||||||
|
# Create session for second server.
|
||||||
|
client2 = self.create_client(CONF.congressha.replica_type)
|
||||||
|
|
||||||
|
# Verify that second server has fake datasource
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_exists(client2, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"replica should have fake, but does not")
|
||||||
|
|
||||||
|
# Remove fake from primary server instance.
|
||||||
|
LOG.debug("removing fake datasource %s", str(fake_id))
|
||||||
|
client1.delete_datasource(fake_id)
|
||||||
|
need_to_delete_fake = False
|
||||||
|
|
||||||
|
# Confirm that fake is gone from primary server instance.
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_missing(client1, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
self.stop_replica(CONF.congressha.replica_port)
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"primary instance still has fake")
|
||||||
|
LOG.debug("removed fake datasource from primary instance")
|
||||||
|
|
||||||
|
# Confirm that second service instance removes fake.
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_missing(client2, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"replica should remove fake, but still has it")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.stop_replica(CONF.congressha.replica_port)
|
||||||
|
if need_to_delete_fake:
|
||||||
|
self.admin_manager.congress_client.delete_datasource(fake_id)
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
def test_datasource_db_sync_remove(self):
|
||||||
|
# Verify that a replica removes a datasource when a datasource
|
||||||
|
# disappears from the database.
|
||||||
|
client1 = self.admin_manager.congress_client
|
||||||
|
fake_id = self.create_fake(client1)
|
||||||
|
need_to_delete_fake = True
|
||||||
|
try:
|
||||||
|
self.start_replica(CONF.congressha.replica_port)
|
||||||
|
|
||||||
|
# Verify that primary server has fake datasource
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_exists(client1, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"primary should have fake, but does not")
|
||||||
|
|
||||||
|
# Create session for second server.
|
||||||
|
client2 = self.create_client(CONF.congressha.replica_type)
|
||||||
|
|
||||||
|
# Verify that second server has fake datasource
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_exists(client2, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"replica should have fake, but does not")
|
||||||
|
|
||||||
|
# Remove fake from primary server instance.
|
||||||
|
LOG.debug("removing fake datasource %s", str(fake_id))
|
||||||
|
client1.delete_datasource(fake_id)
|
||||||
|
need_to_delete_fake = False
|
||||||
|
|
||||||
|
# Confirm that fake is gone from primary server instance.
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_missing(client1, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
self.stop_replica(CONF.congressha.replica_port)
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"primary instance still has fake")
|
||||||
|
LOG.debug("removed fake datasource from primary instance")
|
||||||
|
|
||||||
|
# Confirm that second service instance removes fake.
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=lambda: self.datasource_missing(client2, fake_id),
|
||||||
|
duration=60, sleep_for=1):
|
||||||
|
raise exceptions.TimeoutException(
|
||||||
|
"replica should remove fake, but still has it")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
self.stop_replica(CONF.congressha.replica_port)
|
||||||
|
if need_to_delete_fake:
|
||||||
|
self.admin_manager.congress_client.delete_datasource(fake_id)
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Copyright (c) 2015 Hewlett Packard. 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 retrying
|
||||||
|
|
||||||
|
|
||||||
|
@retrying.retry(stop_max_attempt_number=20, wait_fixed=1000)
|
||||||
|
def retry_check_function_return_value(f, expected_value, error_msg=None):
|
||||||
|
"""Check if function f returns expected value."""
|
||||||
|
if not error_msg:
|
||||||
|
error_msg = 'Expected value "%s" not found' % expected_value
|
||||||
|
r = f()
|
||||||
|
if r != expected_value:
|
||||||
|
raise Exception(error_msg)
|
|
@ -0,0 +1,267 @@
|
||||||
|
# Copyright 2012 OpenStack Foundation
|
||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
# 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 collections
|
||||||
|
import re
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from tempest.common import cred_provider
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import manager as tempestmanager
|
||||||
|
from tempest.scenario import manager # noqa
|
||||||
|
from tempest.services.network import resources as net_resources # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
from tempest_lib.common.utils import data_utils
|
||||||
|
|
||||||
|
from congress_tempest_tests.services.policy import policy_client
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple',
|
||||||
|
['floating_ip', 'server'])
|
||||||
|
|
||||||
|
|
||||||
|
def get_datasource_id(client, name):
|
||||||
|
datasources = client.list_datasources()
|
||||||
|
for datasource in datasources['results']:
|
||||||
|
if datasource['name'] == name:
|
||||||
|
return datasource['id']
|
||||||
|
raise Exception("Datasource %s not found." % name)
|
||||||
|
|
||||||
|
|
||||||
|
# Note: these tests all use neutron today so we mix with that.
|
||||||
|
class ScenarioPolicyBase(manager.NetworkScenarioTest):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(ScenarioPolicyBase, cls).setUpClass()
|
||||||
|
# auth provider for admin credentials
|
||||||
|
creds = cred_provider.get_configured_credentials('identity_admin')
|
||||||
|
auth_prov = tempestmanager.get_auth_provider(creds)
|
||||||
|
|
||||||
|
cls.admin_manager.congress_client = policy_client.PolicyClient(
|
||||||
|
auth_prov, "policy", CONF.identity.region)
|
||||||
|
|
||||||
|
def _setup_network_and_servers(self):
|
||||||
|
self.security_group = (self._create_security_group
|
||||||
|
(tenant_id=self.tenant_id))
|
||||||
|
self.network, self.subnet, self.router = self.create_networks()
|
||||||
|
self.check_networks()
|
||||||
|
|
||||||
|
name = data_utils.rand_name('server-smoke')
|
||||||
|
server = self._create_server(name, self.network)
|
||||||
|
self._check_tenant_network_connectivity()
|
||||||
|
|
||||||
|
floating_ip = self.create_floating_ip(server)
|
||||||
|
self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
|
||||||
|
|
||||||
|
def check_networks(self):
|
||||||
|
"""Check for newly created network/subnet/router.
|
||||||
|
|
||||||
|
Checks that we see the newly created network/subnet/router via
|
||||||
|
checking the result of list_[networks,routers,subnets].
|
||||||
|
"""
|
||||||
|
|
||||||
|
seen_nets = self._list_networks()
|
||||||
|
seen_names = [n['name'] for n in seen_nets]
|
||||||
|
seen_ids = [n['id'] for n in seen_nets]
|
||||||
|
self.assertIn(self.network.name, seen_names)
|
||||||
|
self.assertIn(self.network.id, seen_ids)
|
||||||
|
|
||||||
|
if self.subnet:
|
||||||
|
seen_subnets = self._list_subnets()
|
||||||
|
seen_net_ids = [n['network_id'] for n in seen_subnets]
|
||||||
|
seen_subnet_ids = [n['id'] for n in seen_subnets]
|
||||||
|
self.assertIn(self.network.id, seen_net_ids)
|
||||||
|
self.assertIn(self.subnet.id, seen_subnet_ids)
|
||||||
|
|
||||||
|
if self.router:
|
||||||
|
seen_routers = self._list_routers()
|
||||||
|
seen_router_ids = [n['id'] for n in seen_routers]
|
||||||
|
seen_router_names = [n['name'] for n in seen_routers]
|
||||||
|
self.assertIn(self.router.name,
|
||||||
|
seen_router_names)
|
||||||
|
self.assertIn(self.router.id,
|
||||||
|
seen_router_ids)
|
||||||
|
|
||||||
|
def _create_server(self, name, network):
|
||||||
|
keypair = self.create_keypair()
|
||||||
|
self.keypairs[keypair['name']] = keypair
|
||||||
|
security_groups = [self.security_group]
|
||||||
|
create_kwargs = {
|
||||||
|
'networks': [
|
||||||
|
{'uuid': network.id},
|
||||||
|
],
|
||||||
|
'key_name': keypair['name'],
|
||||||
|
'security_groups': security_groups,
|
||||||
|
}
|
||||||
|
server = self.create_server(name=name, create_kwargs=create_kwargs)
|
||||||
|
self.servers.append(server)
|
||||||
|
return server
|
||||||
|
|
||||||
|
def _get_server_key(self, server):
|
||||||
|
return self.keypairs[server['key_name']]['private_key']
|
||||||
|
|
||||||
|
def _check_tenant_network_connectivity(self):
|
||||||
|
ssh_login = CONF.compute.image_ssh_user
|
||||||
|
for server in self.servers:
|
||||||
|
# call the common method in the parent class
|
||||||
|
super(ScenarioPolicyBase, self)._check_tenant_network_connectivity(
|
||||||
|
server, ssh_login, self._get_server_key(server),
|
||||||
|
servers_for_debug=self.servers)
|
||||||
|
|
||||||
|
def _create_and_associate_floating_ips(self, server):
|
||||||
|
public_network_id = CONF.network.public_network_id
|
||||||
|
floating_ip = self._create_floating_ip(server, public_network_id)
|
||||||
|
self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
|
||||||
|
|
||||||
|
def _check_public_network_connectivity(self, should_connect=True,
|
||||||
|
msg=None):
|
||||||
|
ssh_login = CONF.compute.image_ssh_user
|
||||||
|
floating_ip, server = self.floating_ip_tuple
|
||||||
|
ip_address = floating_ip.floating_ip_address
|
||||||
|
private_key = None
|
||||||
|
if should_connect:
|
||||||
|
private_key = self._get_server_key(server)
|
||||||
|
# call the common method in the parent class
|
||||||
|
super(ScenarioPolicyBase, self)._check_public_network_connectivity(
|
||||||
|
ip_address, ssh_login, private_key, should_connect, msg,
|
||||||
|
self.servers)
|
||||||
|
|
||||||
|
def _disassociate_floating_ips(self):
|
||||||
|
floating_ip, server = self.floating_ip_tuple
|
||||||
|
self._disassociate_floating_ip(floating_ip)
|
||||||
|
self.floating_ip_tuple = Floating_IP_tuple(
|
||||||
|
floating_ip, None)
|
||||||
|
|
||||||
|
def _reassociate_floating_ips(self):
|
||||||
|
floating_ip, server = self.floating_ip_tuple
|
||||||
|
name = data_utils.rand_name('new_server-smoke-')
|
||||||
|
# create a new server for the floating ip
|
||||||
|
server = self._create_server(name, self.network)
|
||||||
|
self._associate_floating_ip(floating_ip, server)
|
||||||
|
self.floating_ip_tuple = Floating_IP_tuple(
|
||||||
|
floating_ip, server)
|
||||||
|
|
||||||
|
def _create_new_network(self):
|
||||||
|
self.new_net = self._create_network(tenant_id=self.tenant_id)
|
||||||
|
self.new_subnet = self._create_subnet(
|
||||||
|
network=self.new_net,
|
||||||
|
gateway_ip=None)
|
||||||
|
|
||||||
|
def _hotplug_server(self):
|
||||||
|
old_floating_ip, server = self.floating_ip_tuple
|
||||||
|
ip_address = old_floating_ip.floating_ip_address
|
||||||
|
private_key = self._get_server_key(server)
|
||||||
|
ssh_client = self.get_remote_client(ip_address,
|
||||||
|
private_key=private_key)
|
||||||
|
old_nic_list = self._get_server_nics(ssh_client)
|
||||||
|
# get a port from a list of one item
|
||||||
|
port_list = self._list_ports(device_id=server['id'])
|
||||||
|
self.assertEqual(1, len(port_list))
|
||||||
|
old_port = port_list[0]
|
||||||
|
_, interface = self.interface_client.create_interface(
|
||||||
|
server=server['id'],
|
||||||
|
network_id=self.new_net.id)
|
||||||
|
self.addCleanup(self.network_client.wait_for_resource_deletion,
|
||||||
|
'port',
|
||||||
|
interface['port_id'])
|
||||||
|
self.addCleanup(self.delete_wrapper,
|
||||||
|
self.interface_client.delete_interface,
|
||||||
|
server['id'], interface['port_id'])
|
||||||
|
|
||||||
|
def check_ports():
|
||||||
|
self.new_port_list = [port for port in
|
||||||
|
self._list_ports(device_id=server['id'])
|
||||||
|
if port != old_port]
|
||||||
|
return len(self.new_port_list) == 1
|
||||||
|
|
||||||
|
if not test.call_until_true(check_ports, CONF.network.build_timeout,
|
||||||
|
CONF.network.build_interval):
|
||||||
|
raise exceptions.TimeoutException("No new port attached to the "
|
||||||
|
"server in time (%s sec) !"
|
||||||
|
% CONF.network.build_timeout)
|
||||||
|
new_port = net_resources.DeletablePort(client=self.network_client,
|
||||||
|
**self.new_port_list[0])
|
||||||
|
|
||||||
|
def check_new_nic():
|
||||||
|
new_nic_list = self._get_server_nics(ssh_client)
|
||||||
|
self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
|
||||||
|
return len(self.diff_list) == 1
|
||||||
|
|
||||||
|
if not test.call_until_true(check_new_nic, CONF.network.build_timeout,
|
||||||
|
CONF.network.build_interval):
|
||||||
|
raise exceptions.TimeoutException("Interface not visible on the "
|
||||||
|
"guest after %s sec"
|
||||||
|
% CONF.network.build_timeout)
|
||||||
|
|
||||||
|
num, new_nic = self.diff_list[0]
|
||||||
|
ssh_client.assign_static_ip(nic=new_nic,
|
||||||
|
addr=new_port.fixed_ips[0]['ip_address'])
|
||||||
|
ssh_client.turn_nic_on(nic=new_nic)
|
||||||
|
|
||||||
|
def _get_server_nics(self, ssh_client):
|
||||||
|
reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
|
||||||
|
ipatxt = ssh_client.get_ip_list()
|
||||||
|
return reg.findall(ipatxt)
|
||||||
|
|
||||||
|
def _check_network_internal_connectivity(self, network):
|
||||||
|
"""via ssh check VM internal connectivity:
|
||||||
|
|
||||||
|
- ping internal gateway and DHCP port, implying in-tenant connectivity
|
||||||
|
pinging both, because L3 and DHCP agents might be on different nodes.
|
||||||
|
"""
|
||||||
|
floating_ip, server = self.floating_ip_tuple
|
||||||
|
# get internal ports' ips:
|
||||||
|
# get all network ports in the new network
|
||||||
|
internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
|
||||||
|
self._list_ports(tenant_id=server['tenant_id'],
|
||||||
|
network_id=network.id)
|
||||||
|
if p['device_owner'].startswith('network'))
|
||||||
|
|
||||||
|
self._check_server_connectivity(floating_ip, internal_ips)
|
||||||
|
|
||||||
|
def _check_network_external_connectivity(self):
|
||||||
|
"""ping public network default gateway to imply external conn."""
|
||||||
|
if not CONF.network.public_network_id:
|
||||||
|
msg = 'public network not defined.'
|
||||||
|
LOG.info(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
subnet = self._list_subnets(
|
||||||
|
network_id=CONF.network.public_network_id)
|
||||||
|
self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
|
||||||
|
|
||||||
|
external_ips = [subnet[0]['gateway_ip']]
|
||||||
|
self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
|
||||||
|
external_ips)
|
||||||
|
|
||||||
|
def _check_server_connectivity(self, floating_ip, address_list):
|
||||||
|
ip_address = floating_ip.floating_ip_address
|
||||||
|
private_key = self._get_server_key(self.floating_ip_tuple.server)
|
||||||
|
ssh_source = self._ssh_to_server(ip_address, private_key)
|
||||||
|
|
||||||
|
for remote_ip in address_list:
|
||||||
|
try:
|
||||||
|
self.assertTrue(self._check_remote_connectivity(ssh_source,
|
||||||
|
remote_ip),
|
||||||
|
"Timed out waiting for %s to become "
|
||||||
|
"reachable" % remote_ip)
|
||||||
|
except Exception:
|
||||||
|
LOG.exception("Unable to access {dest} via ssh to "
|
||||||
|
"floating-ip {src}".format(dest=remote_ip,
|
||||||
|
src=floating_ip))
|
||||||
|
raise
|
|
@ -0,0 +1,238 @@
|
||||||
|
# Copyright 2012 OpenStack Foundation
|
||||||
|
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||||
|
# 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_log import log as logging
|
||||||
|
from tempest_lib import decorators
|
||||||
|
|
||||||
|
from tempest import config # noqa
|
||||||
|
from tempest import exceptions # noqa
|
||||||
|
from tempest import test # noqa
|
||||||
|
|
||||||
|
from congress_tempest_tests.tests.scenario import helper # noqa
|
||||||
|
from congress_tempest_tests.tests.scenario import manager_congress # noqa
|
||||||
|
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPolicyBasicOps(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestPolicyBasicOps, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable
|
||||||
|
or CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or '
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestPolicyBasicOps, self).setUp()
|
||||||
|
self.keypairs = {}
|
||||||
|
self.servers = []
|
||||||
|
|
||||||
|
def _create_random_policy(self):
|
||||||
|
policy_name = "nova_%s" % ''.join(random.choice(string.lowercase)
|
||||||
|
for x in range(10))
|
||||||
|
body = {"name": policy_name}
|
||||||
|
resp = self.admin_manager.congress_client.create_policy(body)
|
||||||
|
self.addCleanup(self.admin_manager.congress_client.delete_policy,
|
||||||
|
resp['id'])
|
||||||
|
return resp['name']
|
||||||
|
|
||||||
|
def _create_policy_rule(self, policy_name, rule, rule_name=None,
|
||||||
|
comment=None):
|
||||||
|
body = {'rule': rule}
|
||||||
|
if rule_name:
|
||||||
|
body['name'] = rule_name
|
||||||
|
if comment:
|
||||||
|
body['comment'] = comment
|
||||||
|
client = self.admin_manager.congress_client
|
||||||
|
response = client.create_policy_rule(policy_name, body)
|
||||||
|
if response:
|
||||||
|
self.addCleanup(client.delete_policy_rule, policy_name,
|
||||||
|
response['id'])
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
raise Exception('Failed to create policy rule (%s, %s)'
|
||||||
|
% (policy_name, rule))
|
||||||
|
|
||||||
|
def _create_test_server(self, name=None):
|
||||||
|
image_ref = CONF.compute.image_ref
|
||||||
|
flavor_ref = CONF.compute.flavor_ref
|
||||||
|
keypair = self.create_keypair()
|
||||||
|
security_group = self._create_security_group()
|
||||||
|
security_groups = [{'name': security_group['name']}]
|
||||||
|
create_kwargs = {'key_name': keypair['name'],
|
||||||
|
'security_groups': security_groups}
|
||||||
|
instance = self.create_server(name=name,
|
||||||
|
image=image_ref,
|
||||||
|
flavor=flavor_ref,
|
||||||
|
create_kwargs=create_kwargs)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('compute', 'network')
|
||||||
|
def test_execution_action(self):
|
||||||
|
metadata = {'testkey1': 'value3'}
|
||||||
|
server = self._create_test_server()
|
||||||
|
congress_client = self.admin_manager.congress_client
|
||||||
|
servers_client = self.admin_manager.servers_client
|
||||||
|
policy = self._create_random_policy()
|
||||||
|
service = 'nova'
|
||||||
|
action = 'servers.set_meta'
|
||||||
|
action_args = {'args': {'positional': [],
|
||||||
|
'named': {'server': server['id'],
|
||||||
|
'metadata': metadata}}}
|
||||||
|
body = action_args
|
||||||
|
|
||||||
|
# execute via datasource api
|
||||||
|
body.update({'name': action})
|
||||||
|
congress_client.execute_datasource_action(service, "execute", body)
|
||||||
|
return_meta = servers_client.get_server_metadata_item(server["id"],
|
||||||
|
"testkey1")
|
||||||
|
self.assertEqual(metadata, return_meta,
|
||||||
|
"Failed to execute action via datasource API")
|
||||||
|
|
||||||
|
# execute via policy api
|
||||||
|
body.update({'name': service + ':' + action})
|
||||||
|
congress_client.execute_policy_action(policy, "execute", False,
|
||||||
|
False, body)
|
||||||
|
return_meta = servers_client.get_server_metadata_item(server["id"],
|
||||||
|
"testkey1")
|
||||||
|
self.assertEqual(metadata, return_meta,
|
||||||
|
"Failed to execute action via policy API")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('compute', 'network')
|
||||||
|
def test_policy_basic_op(self):
|
||||||
|
self._setup_network_and_servers()
|
||||||
|
body = {"rule": "port_security_group(id, security_group_name) "
|
||||||
|
":-neutronv2:ports(id, tenant_id, name, network_id,"
|
||||||
|
"mac_address, admin_state_up, status, device_id, "
|
||||||
|
"device_owner),"
|
||||||
|
"neutronv2:security_group_port_bindings(id, "
|
||||||
|
"security_group_id), neutronv2:security_groups("
|
||||||
|
"security_group_id, tenant_id1, security_group_name,"
|
||||||
|
"description)"}
|
||||||
|
results = self.admin_manager.congress_client.create_policy_rule(
|
||||||
|
'classification', body)
|
||||||
|
rule_id = results['id']
|
||||||
|
self.addCleanup(
|
||||||
|
self.admin_manager.congress_client.delete_policy_rule,
|
||||||
|
'classification', rule_id)
|
||||||
|
|
||||||
|
# Find the ports of on this server
|
||||||
|
ports = self._list_ports(device_id=self.servers[0]['id'])
|
||||||
|
|
||||||
|
def check_data():
|
||||||
|
results = self.admin_manager.congress_client.list_policy_rows(
|
||||||
|
'classification', 'port_security_group')
|
||||||
|
for row in results['results']:
|
||||||
|
if (row['data'][0] == ports[0]['id'] and
|
||||||
|
row['data'][1] ==
|
||||||
|
self.servers[0]['security_groups'][0]['name']):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not test.call_until_true(func=check_data,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
@decorators.skip_because(bug='1486246')
|
||||||
|
@test.attr(type='smoke')
|
||||||
|
@test.services('compute', 'network')
|
||||||
|
def test_reactive_enforcement(self):
|
||||||
|
servers_client = self.admin_manager.servers_client
|
||||||
|
server_name = 'server_under_test'
|
||||||
|
server = self._create_test_server(name=server_name)
|
||||||
|
policy_name = self._create_random_policy()
|
||||||
|
meta_key = 'meta_test_key1'
|
||||||
|
meta_val = 'value1'
|
||||||
|
meta_data = {meta_key: meta_val}
|
||||||
|
rules = [
|
||||||
|
'execute[nova:servers_set_meta(id, "%s", "%s")] :- '
|
||||||
|
'test_servers(id)' % (meta_key, meta_val),
|
||||||
|
'test_servers(id) :- '
|
||||||
|
'nova:servers(id, name, host_id, status, '
|
||||||
|
'tenant_id, user_id, image_id, flavor_id),'
|
||||||
|
'equal(name, "%s")' % server_name]
|
||||||
|
|
||||||
|
for rule in rules:
|
||||||
|
self._create_policy_rule(policy_name, rule)
|
||||||
|
|
||||||
|
f = lambda: servers_client.get_server_metadata_item(server['id'],
|
||||||
|
meta_key)
|
||||||
|
helper.retry_check_function_return_value(f, meta_data)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCongressDataSources(manager_congress.ScenarioPolicyBase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_preconditions(cls):
|
||||||
|
super(TestCongressDataSources, cls).check_preconditions()
|
||||||
|
if not (CONF.network.tenant_networks_reachable
|
||||||
|
or CONF.network.public_network_id):
|
||||||
|
msg = ('Either tenant_networks_reachable must be "true", or '
|
||||||
|
'public_network_id must be defined.')
|
||||||
|
cls.enabled = False
|
||||||
|
raise cls.skipException(msg)
|
||||||
|
|
||||||
|
def test_all_loaded_datasources_are_initialized(self):
|
||||||
|
datasources = self.admin_manager.congress_client.list_datasources()
|
||||||
|
|
||||||
|
def _check_all_datasources_are_initialized():
|
||||||
|
for datasource in datasources['results']:
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_status(
|
||||||
|
datasource['id']))
|
||||||
|
if results['initialized'] != 'True':
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(
|
||||||
|
func=_check_all_datasources_are_initialized,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
||||||
|
|
||||||
|
def test_all_datasources_have_tables(self):
|
||||||
|
datasources = self.admin_manager.congress_client.list_datasources()
|
||||||
|
|
||||||
|
def check_data():
|
||||||
|
for datasource in datasources['results']:
|
||||||
|
results = (
|
||||||
|
self.admin_manager.congress_client.list_datasource_tables(
|
||||||
|
datasource['id']))
|
||||||
|
# NOTE(arosen): if there are no results here we return false as
|
||||||
|
# there is something wrong with a driver as it doesn't expose
|
||||||
|
# any tables.
|
||||||
|
if not results['results']:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not test.call_until_true(func=check_data,
|
||||||
|
duration=100, sleep_for=5):
|
||||||
|
raise exceptions.TimeoutException("Data did not converge in time "
|
||||||
|
"or failure in server")
|
Loading…
Reference in New Issue