Initial commit
This commit is contained in:
commit
b48503b71f
4
HACKING.rst
Normal file
4
HACKING.rst
Normal file
@ -0,0 +1,4 @@
|
||||
barbican_tempest_plugin Style Commandments
|
||||
===============================================
|
||||
|
||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
176
LICENSE
Normal file
176
LICENSE
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
24
README.rst
Normal file
24
README.rst
Normal file
@ -0,0 +1,24 @@
|
||||
===============================
|
||||
Tempest Integration of Novajoin
|
||||
===============================
|
||||
|
||||
This project defines a tempest plugin containing tests used to verify the
|
||||
functionality of a novajoin installation. The plugin will automatically load
|
||||
these tests into tempest.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
The novajoin_tempest_plugin tests the novajoin API, which requires the
|
||||
existence of an IPA server.
|
||||
|
||||
Developers
|
||||
----------
|
||||
For more information on novajoin, refer to:
|
||||
http://docs.openstack.org/developer/novajoin/
|
||||
|
||||
For more information on tempest plugins, refer to:
|
||||
http://docs.openstack.org/developer/tempest/plugin.html#using-plugins
|
||||
|
||||
Bugs
|
||||
----
|
||||
Please report bugs to: http://bugs.launchpad.net/novajoin
|
6
novajoin_tempest_plugin/README.rst
Normal file
6
novajoin_tempest_plugin/README.rst
Normal file
@ -0,0 +1,6 @@
|
||||
===============================================
|
||||
Tempest Integration of Novajoin
|
||||
===============================================
|
||||
|
||||
This directory contains Tempest tests to cover the Novajoin project.
|
||||
|
18
novajoin_tempest_plugin/__init__.py
Normal file
18
novajoin_tempest_plugin/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# 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 pbr.version
|
||||
|
||||
|
||||
__version__ = pbr.version.VersionInfo(
|
||||
'novajoin_tempest_plugin').version_string()
|
||||
|
40
novajoin_tempest_plugin/clients.py
Normal file
40
novajoin_tempest_plugin/clients.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright (c) 2016 SAP SE
|
||||
#
|
||||
# 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 tempest import clients
|
||||
from tempest.common import credentials_factory as common_creds
|
||||
from tempest import config
|
||||
from tempest.lib.services import clients as cli
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
ADMIN_CREDS = common_creds.get_configured_admin_credentials()
|
||||
|
||||
|
||||
class Manager(clients.Manager):
|
||||
def __init__(self, credentials=ADMIN_CREDS):
|
||||
super(Manager, self).__init__(credentials)
|
||||
|
||||
|
||||
class Clients(cli.ServiceClients):
|
||||
"""Tempest stable service clients and loaded plugins service clients"""
|
||||
|
||||
def __init__(self, credentials, service=None):
|
||||
"""Emulate the interface of Tempest's clients.Manager"""
|
||||
# Identity settings
|
||||
if CONF.identity.auth_version == 'v2':
|
||||
identity_uri = CONF.identity.uri
|
||||
else:
|
||||
identity_uri = CONF.identity.uri_v3
|
||||
super(Clients, self).__init__(credentials, identity_uri)
|
15
novajoin_tempest_plugin/config.py
Normal file
15
novajoin_tempest_plugin/config.py
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2015
|
||||
# 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.
|
||||
|
37
novajoin_tempest_plugin/plugin.py
Normal file
37
novajoin_tempest_plugin/plugin.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright 2015 Red Hat Inc.
|
||||
# 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 novajoin_tempest_plugin import config as project_config
|
||||
|
||||
|
||||
class NovajoinTempestPlugin(plugins.TempestPlugin):
|
||||
def load_tests(self):
|
||||
base_path = os.path.split(os.path.dirname(
|
||||
os.path.abspath(__file__)))[0]
|
||||
test_dir = "novajoin_tempest_plugin/tests"
|
||||
full_test_dir = os.path.join(base_path, test_dir)
|
||||
return full_test_dir, base_path
|
||||
|
||||
def register_opts(self, conf):
|
||||
pass
|
||||
|
||||
def get_opt_lists(self):
|
||||
pass
|
0
novajoin_tempest_plugin/services/__init__.py
Normal file
0
novajoin_tempest_plugin/services/__init__.py
Normal file
0
novajoin_tempest_plugin/tests/__init__.py
Normal file
0
novajoin_tempest_plugin/tests/__init__.py
Normal file
0
novajoin_tempest_plugin/tests/api/__init__.py
Normal file
0
novajoin_tempest_plugin/tests/api/__init__.py
Normal file
20
novajoin_tempest_plugin/tests/base.py
Normal file
20
novajoin_tempest_plugin/tests/base.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Copyright 2016 SAP SE
|
||||
#
|
||||
# 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 tempest.lib import base
|
||||
|
||||
|
||||
class TestCase(base.BaseTestCase):
|
||||
|
||||
"""Test case base class for all unit tests."""
|
0
novajoin_tempest_plugin/tests/scenario/__init__.py
Normal file
0
novajoin_tempest_plugin/tests/scenario/__init__.py
Normal file
555
novajoin_tempest_plugin/tests/scenario/manager.py
Normal file
555
novajoin_tempest_plugin/tests/scenario/manager.py
Normal file
@ -0,0 +1,555 @@
|
||||
# Copyright 2012 OpenStack Foundation
|
||||
# Copyright 2013 IBM Corp.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from tempest.common import compute
|
||||
from tempest.common import image as common_image
|
||||
from tempest.common.utils.linux import remote_client
|
||||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import tempest.test
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ScenarioTest(tempest.test.BaseTestCase):
|
||||
"""Base class for scenario tests. Uses tempest own clients. """
|
||||
|
||||
credentials = ['primary']
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(ScenarioTest, cls).setup_clients()
|
||||
# Clients (in alphabetical order)
|
||||
cls.flavors_client = cls.os_primary.flavors_client
|
||||
cls.compute_floating_ips_client = (
|
||||
cls.os_primary.compute_floating_ips_client)
|
||||
if CONF.service_available.glance:
|
||||
# Check if glance v1 is available to determine which client to use.
|
||||
if CONF.image_feature_enabled.api_v1:
|
||||
cls.image_client = cls.os_primary.image_client
|
||||
elif CONF.image_feature_enabled.api_v2:
|
||||
cls.image_client = cls.os_primary.image_client_v2
|
||||
else:
|
||||
raise lib_exc.InvalidConfiguration(
|
||||
'Either api_v1 or api_v2 must be True in '
|
||||
'[image-feature-enabled].')
|
||||
# Compute image client
|
||||
cls.compute_images_client = cls.os_primary.compute_images_client
|
||||
cls.keypairs_client = cls.os_primary.keypairs_client
|
||||
# Nova security groups client
|
||||
cls.compute_security_groups_client = (
|
||||
cls.os_primary.compute_security_groups_client)
|
||||
cls.compute_security_group_rules_client = (
|
||||
cls.os_primary.compute_security_group_rules_client)
|
||||
cls.servers_client = cls.os_primary.servers_client
|
||||
# Neutron network client
|
||||
cls.networks_client = cls.os_primary.networks_client
|
||||
cls.ports_client = cls.os_primary.ports_client
|
||||
cls.routers_client = cls.os_primary.routers_client
|
||||
cls.subnets_client = cls.os_primary.subnets_client
|
||||
cls.floating_ips_client = cls.os_primary.floating_ips_client
|
||||
cls.security_groups_client = cls.os_primary.security_groups_client
|
||||
cls.security_group_rules_client = (
|
||||
cls.os_primary.security_group_rules_client)
|
||||
|
||||
if CONF.volume_feature_enabled.api_v2:
|
||||
cls.volumes_client = cls.os_primary.volumes_v2_client
|
||||
cls.snapshots_client = cls.os_primary.snapshots_v2_client
|
||||
else:
|
||||
cls.volumes_client = cls.os_primary.volumes_client
|
||||
cls.snapshots_client = cls.os_primary.snapshots_client
|
||||
|
||||
# ## Test functions library
|
||||
#
|
||||
# The create_[resource] functions only return body and discard the
|
||||
# resp part which is not used in scenario tests
|
||||
|
||||
def _create_port(self, network_id, client=None, namestart='port-quotatest',
|
||||
**kwargs):
|
||||
if not client:
|
||||
client = self.ports_client
|
||||
name = data_utils.rand_name(namestart)
|
||||
result = client.create_port(
|
||||
name=name,
|
||||
network_id=network_id,
|
||||
**kwargs)
|
||||
self.assertIsNotNone(result, 'Unable to allocate port')
|
||||
port = result['port']
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
client.delete_port, port['id'])
|
||||
return port
|
||||
|
||||
def create_keypair(self, client=None):
|
||||
if not client:
|
||||
client = self.keypairs_client
|
||||
name = data_utils.rand_name(self.__class__.__name__)
|
||||
# We don't need to create a keypair by pubkey in scenario
|
||||
body = client.create_keypair(name=name)
|
||||
self.addCleanup(client.delete_keypair, name)
|
||||
return body['keypair']
|
||||
|
||||
def create_server(self, name=None, image_id=None, flavor=None,
|
||||
validatable=False, wait_until='ACTIVE',
|
||||
clients=None, **kwargs):
|
||||
"""Wrapper utility that returns a test server.
|
||||
|
||||
This wrapper utility calls the common create test server and
|
||||
returns a test server. The purpose of this wrapper is to minimize
|
||||
the impact on the code of the tests already using this
|
||||
function.
|
||||
"""
|
||||
|
||||
# NOTE(jlanoux): As a first step, ssh checks in the scenario
|
||||
# tests need to be run regardless of the run_validation and
|
||||
# validatable parameters and thus until the ssh validation job
|
||||
# becomes voting in CI. The test resources management and IP
|
||||
# association are taken care of in the scenario tests.
|
||||
# Therefore, the validatable parameter is set to false in all
|
||||
# those tests. In this way create_server just return a standard
|
||||
# server and the scenario tests always perform ssh checks.
|
||||
|
||||
# Needed for the cross_tenant_traffic test:
|
||||
if clients is None:
|
||||
clients = self.os_primary
|
||||
|
||||
if name is None:
|
||||
name = data_utils.rand_name(self.__class__.__name__ + "-server")
|
||||
|
||||
vnic_type = CONF.network.port_vnic_type
|
||||
|
||||
# If vnic_type is configured create port for
|
||||
# every network
|
||||
if vnic_type:
|
||||
ports = []
|
||||
|
||||
create_port_body = {'binding:vnic_type': vnic_type,
|
||||
'namestart': 'port-smoke'}
|
||||
if kwargs:
|
||||
# Convert security group names to security group ids
|
||||
# to pass to create_port
|
||||
if 'security_groups' in kwargs:
|
||||
security_groups = \
|
||||
clients.security_groups_client.list_security_groups(
|
||||
).get('security_groups')
|
||||
sec_dict = dict([(s['name'], s['id'])
|
||||
for s in security_groups])
|
||||
|
||||
sec_groups_names = [s['name'] for s in kwargs.pop(
|
||||
'security_groups')]
|
||||
security_groups_ids = [sec_dict[s]
|
||||
for s in sec_groups_names]
|
||||
|
||||
if security_groups_ids:
|
||||
create_port_body[
|
||||
'security_groups'] = security_groups_ids
|
||||
networks = kwargs.pop('networks', [])
|
||||
else:
|
||||
networks = []
|
||||
|
||||
# If there are no networks passed to us we look up
|
||||
# for the project's private networks and create a port.
|
||||
# The same behaviour as we would expect when passing
|
||||
# the call to the clients with no networks
|
||||
if not networks:
|
||||
networks = clients.networks_client.list_networks(
|
||||
**{'router:external': False, 'fields': 'id'})['networks']
|
||||
|
||||
# It's net['uuid'] if networks come from kwargs
|
||||
# and net['id'] if they come from
|
||||
# clients.networks_client.list_networks
|
||||
for net in networks:
|
||||
net_id = net.get('uuid', net.get('id'))
|
||||
if 'port' not in net:
|
||||
port = self._create_port(network_id=net_id,
|
||||
client=clients.ports_client,
|
||||
**create_port_body)
|
||||
ports.append({'port': port['id']})
|
||||
else:
|
||||
ports.append({'port': net['port']})
|
||||
if ports:
|
||||
kwargs['networks'] = ports
|
||||
self.ports = ports
|
||||
|
||||
tenant_network = self.get_tenant_network()
|
||||
|
||||
body, servers = compute.create_test_server(
|
||||
clients,
|
||||
tenant_network=tenant_network,
|
||||
wait_until=wait_until,
|
||||
name=name, flavor=flavor,
|
||||
image_id=image_id, **kwargs)
|
||||
|
||||
self.addCleanup(waiters.wait_for_server_termination,
|
||||
clients.servers_client, body['id'])
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
clients.servers_client.delete_server, body['id'])
|
||||
server = clients.servers_client.show_server(body['id'])['server']
|
||||
return server
|
||||
|
||||
def create_volume(self, size=None, name=None, snapshot_id=None,
|
||||
imageRef=None, volume_type=None):
|
||||
if size is None:
|
||||
size = CONF.volume.volume_size
|
||||
if imageRef:
|
||||
image = self.compute_images_client.show_image(imageRef)['image']
|
||||
min_disk = image.get('minDisk')
|
||||
size = max(size, min_disk)
|
||||
if name is None:
|
||||
name = data_utils.rand_name(self.__class__.__name__ + "-volume")
|
||||
kwargs = {'display_name': name,
|
||||
'snapshot_id': snapshot_id,
|
||||
'imageRef': imageRef,
|
||||
'volume_type': volume_type,
|
||||
'size': size}
|
||||
volume = self.volumes_client.create_volume(**kwargs)['volume']
|
||||
|
||||
self.addCleanup(self.volumes_client.wait_for_resource_deletion,
|
||||
volume['id'])
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.volumes_client.delete_volume, volume['id'])
|
||||
|
||||
# NOTE(e0ne): Cinder API v2 uses name instead of display_name
|
||||
if 'display_name' in volume:
|
||||
self.assertEqual(name, volume['display_name'])
|
||||
else:
|
||||
self.assertEqual(name, volume['name'])
|
||||
waiters.wait_for_volume_resource_status(self.volumes_client,
|
||||
volume['id'], 'available')
|
||||
# The volume retrieved on creation has a non-up-to-date status.
|
||||
# Retrieval after it becomes active ensures correct details.
|
||||
volume = self.volumes_client.show_volume(volume['id'])['volume']
|
||||
return volume
|
||||
|
||||
def create_volume_type(self, client=None, name=None, backend_name=None):
|
||||
if not client:
|
||||
client = self.admin_volume_types_client
|
||||
if not name:
|
||||
class_name = self.__class__.__name__
|
||||
name = data_utils.rand_name(class_name + '-volume-type')
|
||||
randomized_name = data_utils.rand_name('scenario-type-' + name)
|
||||
|
||||
LOG.debug("Creating a volume type: %s on backend %s",
|
||||
randomized_name, backend_name)
|
||||
extra_specs = {}
|
||||
if backend_name:
|
||||
extra_specs = {"volume_backend_name": backend_name}
|
||||
|
||||
body = client.create_volume_type(name=randomized_name,
|
||||
extra_specs=extra_specs)
|
||||
volume_type = body['volume_type']
|
||||
self.assertIn('id', volume_type)
|
||||
self.addCleanup(client.delete_volume_type, volume_type['id'])
|
||||
return volume_type
|
||||
|
||||
def _image_create(self, name, fmt, path,
|
||||
disk_format=None, properties=None):
|
||||
if properties is None:
|
||||
properties = {}
|
||||
name = data_utils.rand_name('%s-' % name)
|
||||
params = {
|
||||
'name': name,
|
||||
'container_format': fmt,
|
||||
'disk_format': disk_format or fmt,
|
||||
}
|
||||
if CONF.image_feature_enabled.api_v1:
|
||||
params['is_public'] = 'False'
|
||||
params['properties'] = properties
|
||||
params = {'headers': common_image.image_meta_to_headers(**params)}
|
||||
else:
|
||||
params['visibility'] = 'private'
|
||||
# Additional properties are flattened out in the v2 API.
|
||||
params.update(properties)
|
||||
body = self.image_client.create_image(**params)
|
||||
image = body['image'] if 'image' in body else body
|
||||
self.addCleanup(self.image_client.delete_image, image['id'])
|
||||
self.assertEqual("queued", image['status'])
|
||||
with open(path, 'rb') as image_file:
|
||||
if CONF.image_feature_enabled.api_v1:
|
||||
self.image_client.update_image(image['id'], data=image_file)
|
||||
else:
|
||||
self.image_client.store_image_file(image['id'], image_file)
|
||||
return image['id']
|
||||
|
||||
def rebuild_server(self, server_id, image=None,
|
||||
preserve_ephemeral=False, wait=True,
|
||||
rebuild_kwargs=None):
|
||||
if image is None:
|
||||
image = CONF.compute.image_ref
|
||||
|
||||
rebuild_kwargs = rebuild_kwargs or {}
|
||||
|
||||
LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
|
||||
server_id, image, preserve_ephemeral)
|
||||
self.servers_client.rebuild_server(
|
||||
server_id=server_id, image_ref=image,
|
||||
preserve_ephemeral=preserve_ephemeral,
|
||||
**rebuild_kwargs)
|
||||
if wait:
|
||||
waiters.wait_for_server_status(self.servers_client,
|
||||
server_id, 'ACTIVE')
|
||||
|
||||
def create_floating_ip(self, thing, pool_name=None):
|
||||
"""Create a floating IP and associates to a server on Nova"""
|
||||
|
||||
if not pool_name:
|
||||
pool_name = CONF.network.floating_network_name
|
||||
floating_ip = (self.compute_floating_ips_client.
|
||||
create_floating_ip(pool=pool_name)['floating_ip'])
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.compute_floating_ips_client.delete_floating_ip,
|
||||
floating_ip['id'])
|
||||
self.compute_floating_ips_client.associate_floating_ip_to_server(
|
||||
floating_ip['ip'], thing['id'])
|
||||
return floating_ip
|
||||
|
||||
def nova_volume_attach(self, server, volume_to_attach):
|
||||
volume = self.servers_client.attach_volume(
|
||||
server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
|
||||
% CONF.compute.volume_device_name)['volumeAttachment']
|
||||
self.assertEqual(volume_to_attach['id'], volume['id'])
|
||||
waiters.wait_for_volume_resource_status(self.volumes_client,
|
||||
volume['id'], 'in-use')
|
||||
|
||||
# Return the updated volume after the attachment
|
||||
return self.volumes_client.show_volume(volume['id'])['volume']
|
||||
|
||||
def nova_volume_detach(self, server, volume):
|
||||
self.servers_client.detach_volume(server['id'], volume['id'])
|
||||
waiters.wait_for_volume_resource_status(self.volumes_client,
|
||||
volume['id'], 'available')
|
||||
|
||||
volume = self.volumes_client.show_volume(volume['id'])['volume']
|
||||
self.assertEqual('available', volume['status'])
|
||||
|
||||
def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
|
||||
private_key=None):
|
||||
ssh_client = self.get_remote_client(ip_address,
|
||||
private_key=private_key)
|
||||
if dev_name is not None:
|
||||
ssh_client.make_fs(dev_name)
|
||||
ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
|
||||
mount_path))
|
||||
cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
|
||||
ssh_client.exec_command(cmd_timestamp)
|
||||
timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
|
||||
% mount_path)
|
||||
if dev_name is not None:
|
||||
ssh_client.exec_command('sudo umount %s' % mount_path)
|
||||
return timestamp
|
||||
|
||||
def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
|
||||
private_key=None):
|
||||
ssh_client = self.get_remote_client(ip_address,
|
||||
private_key=private_key)
|
||||
if dev_name is not None:
|
||||
ssh_client.mount(dev_name, mount_path)
|
||||
timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
|
||||
% mount_path)
|
||||
if dev_name is not None:
|
||||
ssh_client.exec_command('sudo umount %s' % mount_path)
|
||||
return timestamp
|
||||
|
||||
def get_server_ip(self, server):
|
||||
"""Get the server fixed or floating IP.
|
||||
|
||||
Based on the configuration we're in, return a correct ip
|
||||
address for validating that a guest is up.
|
||||
"""
|
||||
if CONF.validation.connect_method == 'floating':
|
||||
# The tests calling this method don't have a floating IP
|
||||
# and can't make use of the validation resources. So the
|
||||
# method is creating the floating IP there.
|
||||
return self.create_floating_ip(server)['ip']
|
||||
elif CONF.validation.connect_method == 'fixed':
|
||||
# Determine the network name to look for based on config or creds
|
||||
# provider network resources.
|
||||
if CONF.validation.network_for_ssh:
|
||||
addresses = server['addresses'][
|
||||
CONF.validation.network_for_ssh]
|
||||
else:
|
||||
creds_provider = self._get_credentials_provider()
|
||||
net_creds = creds_provider.get_primary_creds()
|
||||
network = getattr(net_creds, 'network', None)
|
||||
addresses = (server['addresses'][network['name']]
|
||||
if network else [])
|
||||
for address in addresses:
|
||||
if (address['version'] == CONF.validation.ip_version_for_ssh
|
||||
and address['OS-EXT-IPS:type'] == 'fixed'):
|
||||
return address['addr']
|
||||
raise exceptions.ServerUnreachable(server_id=server['id'])
|
||||
else:
|
||||
raise lib_exc.InvalidConfiguration()
|
||||
|
||||
def get_remote_client(self, ip_address, username=None, private_key=None):
|
||||
"""Get a SSH client to a remote server
|
||||
|
||||
@param ip_address the server floating or fixed IP address to use
|
||||
for ssh validation
|
||||
@param username name of the Linux account on the remote server
|
||||
@param private_key the SSH private key to use
|
||||
@return a RemoteClient object
|
||||
"""
|
||||
|
||||
if username is None:
|
||||
username = CONF.validation.image_ssh_user
|
||||
# Set this with 'keypair' or others to log in with keypair or
|
||||
# username/password.
|
||||
if CONF.validation.auth_method == 'keypair':
|
||||
password = None
|
||||
if private_key is None:
|
||||
private_key = self.keypair['private_key']
|
||||
else:
|
||||
password = CONF.validation.image_ssh_password
|
||||
private_key = None
|
||||
linux_client = remote_client.RemoteClient(ip_address, username,
|
||||
pkey=private_key,
|
||||
password=password)
|
||||
try:
|
||||
linux_client.validate_authentication()
|
||||
except Exception as e:
|
||||
message = ('Initializing SSH connection to %(ip)s failed. '
|
||||
'Error: %(error)s' % {'ip': ip_address,
|
||||
'error': e})
|
||||
caller = test_utils.find_test_caller()
|
||||
if caller:
|
||||
message = '(%s) %s' % (caller, message)
|
||||
LOG.exception(message)
|
||||
self._log_console_output()
|
||||
raise
|
||||
|
||||
return linux_client
|
||||
|
||||
def _default_security_group(self, client=None, tenant_id=None):
|
||||
"""Get default secgroup for given tenant_id.
|
||||
|
||||
:returns: default secgroup for given tenant
|
||||
"""
|
||||
if client is None:
|
||||
client = self.security_groups_client
|
||||
if not tenant_id:
|
||||
tenant_id = client.tenant_id
|
||||
sgs = [
|
||||
sg for sg in list(client.list_security_groups().values())[0]
|
||||
if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
|
||||
]
|
||||
msg = "No default security group for tenant %s." % (tenant_id)
|
||||
self.assertGreater(len(sgs), 0, msg)
|
||||
return sgs[0]
|
||||
|
||||
def _create_security_group(self):
|
||||
# Create security group
|
||||
sg_name = data_utils.rand_name(self.__class__.__name__)
|
||||
sg_desc = sg_name + " description"
|
||||
secgroup = self.compute_security_groups_client.create_security_group(
|
||||
name=sg_name, description=sg_desc)['security_group']
|
||||
self.assertEqual(secgroup['name'], sg_name)
|
||||
self.assertEqual(secgroup['description'], sg_desc)
|
||||
self.addCleanup(
|
||||
test_utils.call_and_ignore_notfound_exc,
|
||||
self.compute_security_groups_client.delete_security_group,
|
||||
secgroup['id'])
|
||||
|
||||
# Add rules to the security group
|
||||
self._create_loginable_secgroup_rule(secgroup['id'])
|
||||
|
||||
return secgroup
|
||||
|
||||
def _create_loginable_secgroup_rule(self, secgroup_id=None):
|
||||
_client = self.compute_security_groups_client
|
||||
_client_rules = self.compute_security_group_rules_client
|
||||
if secgroup_id is None:
|
||||
sgs = _client.list_security_groups()['security_groups']
|
||||
for sg in sgs:
|
||||
if sg['name'] == 'default':
|
||||
secgroup_id = sg['id']
|
||||
|
||||
# These rules are intended to permit inbound ssh and icmp
|
||||
# traffic from all sources, so no group_id is provided.
|
||||
# Setting a group_id would only permit traffic from ports
|
||||
# belonging to the same security group.
|
||||
rulesets = [
|
||||
{
|
||||
# ssh
|
||||
'ip_protocol': 'tcp',
|
||||
'from_port': 22,
|
||||
'to_port': 22,
|
||||
'cidr': '0.0.0.0/0',
|
||||
},
|
||||
{
|
||||
# ping
|
||||
'ip_protocol': 'icmp',
|
||||
'from_port': -1,
|
||||
'to_port': -1,
|
||||
'cidr': '0.0.0.0/0',
|
||||
}
|
||||
]
|
||||
rules = list()
|
||||
for ruleset in rulesets:
|
||||
sg_rule = _client_rules.create_security_group_rule(
|
||||
parent_group_id=secgroup_id, **ruleset)['security_group_rule']
|
||||
rules.append(sg_rule)
|
||||
return rules
|
||||
|
||||
def _create_security_group_rule(self, secgroup=None,
|
||||
sec_group_rules_client=None,
|
||||
tenant_id=None,
|
||||
security_groups_client=None, **kwargs):
|
||||
"""Create a rule from a dictionary of rule parameters.
|
||||
|
||||
Create a rule in a secgroup. if secgroup not defined will search for
|
||||
default secgroup in tenant_id.
|
||||
|
||||
:param secgroup: the security group.
|
||||
:param tenant_id: if secgroup not passed -- the tenant in which to
|
||||
search for default secgroup
|
||||
:param kwargs: a dictionary containing rule parameters:
|
||||
for example, to allow incoming ssh:
|
||||
rule = {
|
||||
direction: 'ingress'
|
||||
protocol:'tcp',
|
||||
port_range_min: 22,
|
||||
port_range_max: 22
|
||||
}
|
||||
"""
|
||||
if sec_group_rules_client is None:
|
||||
sec_group_rules_client = self.security_group_rules_client
|
||||
if security_groups_client is None:
|
||||
security_groups_client = self.security_groups_client
|
||||
if not tenant_id:
|
||||
tenant_id = security_groups_client.tenant_id
|
||||
if secgroup is None:
|
||||
secgroup = self._default_security_group(
|
||||
client=security_groups_client, tenant_id=tenant_id)
|
||||
|
||||
ruleset = dict(security_group_id=secgroup['id'],
|
||||
tenant_id=secgroup['tenant_id'])
|
||||
ruleset.update(kwargs)
|
||||
|
||||
sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
|
||||
sg_rule = sg_rule['security_group_rule']
|
||||
|
||||
self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
|
||||
self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
|
||||
|
||||
return sg_rule
|
87
novajoin_tempest_plugin/tests/scenario/novajoin_manager.py
Normal file
87
novajoin_tempest_plugin/tests/scenario/novajoin_manager.py
Normal file
@ -0,0 +1,87 @@
|
||||
# Copyright 2017 Red Hat
|
||||
# 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 base64
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
import os
|
||||
|
||||
from oslo_log import log as logging
|
||||
from tempest import config
|
||||
|
||||
from novajoin_tempest_plugin import clients
|
||||
from novajoin_tempest_plugin.tests.scenario import manager as mgr
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NovajoinScenarioTest(mgr.ScenarioTest):
|
||||
|
||||
credentials = ('primary', 'admin')
|
||||
manager = clients.Manager()
|
||||
|
||||
def setUp(self):
|
||||
super(NovajoinScenarioTest, self).setUp()
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
# check if novajoin is enabled?
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(NovajoinScenarioTest, cls).setup_clients()
|
||||
|
||||
os = getattr(cls, 'os_%s' % cls.credentials[0])
|
||||
os_adm = getattr(cls, 'os_%s' % cls.credentials[1])
|
||||
# set up ipa client
|
||||
|
||||
def verify_host_registered_with_ipa(self, host):
|
||||
# check if specified host is registered with ipa
|
||||
# basically doing a host-show
|
||||
pass
|
||||
|
||||
def verify_host_not_registered_with_ipa(self, host):
|
||||
# check if specified host is not registered with ipa
|
||||
pass
|
||||
|
||||
def verify_host_has_keytab(self, host):
|
||||
# check if specified host entry has a keytab
|
||||
pass
|
||||
|
||||
def verify_host_is_ipaclient(self, host, keypair):
|
||||
# ssh into the host
|
||||
# do test like "getent passwd admin" or similar
|
||||
pass
|
||||
|
||||
def verify_service_created(self, service, host):
|
||||
# verify service exists for host on ipa server
|
||||
# needed for the triple-O tests
|
||||
pass
|
||||
|
||||
def verify_service_deleted(self, servicei, host):
|
||||
# verify service entry does not exist
|
||||
pass
|
||||
|
||||
def verify_cert_tracked(self, host, keypair, cn):
|
||||
# ssh into the host with the provided keypair
|
||||
# run certmonger command to ensure cert is
|
||||
# being tracked
|
||||
pass
|
||||
|
||||
def verify_cert_revoked(self, serial):
|
||||
# verify that the given certificate has been revoked
|
||||
pass
|
@ -0,0 +1,106 @@
|
||||
# Copyright (c) 2017 Red Hat
|
||||
#
|
||||
# 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 import config
|
||||
from tempest.lib import decorators
|
||||
from tempest import test
|
||||
|
||||
from novajoin_tempest_plugin.tests.scenario import novajoin_manager
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EnrollmentTest(novajoin_manager.NovajoinScenarioTest):
|
||||
|
||||
"""The test suite for server enrollment
|
||||
|
||||
This test is to verify the enrollment and removal of
|
||||
servers with a nova service that has been configured to register
|
||||
and de-register clients with an IPA server.
|
||||
|
||||
We create servers using ipa_enroll=True as metadata, and also
|
||||
by using an image that contains ipa_enroll=True as metadata.
|
||||
|
||||
The tests do the following:
|
||||
* Create a server using either metadata method
|
||||
* Validate that the server is registered in the IPA server
|
||||
* Validate the the ipaclient is working on the server
|
||||
* Delete the newly created server
|
||||
* Validate that the server is no longer registered with IPA
|
||||
|
||||
TODO: We can also add the following tests:
|
||||
* Add metadata to register and create some cert entries
|
||||
* Validate that the certs for those entries are issued and
|
||||
tracked
|
||||
* Validate that the service entries arer removed when the
|
||||
instance is deleted.
|
||||
* Validate that the certs issued have been revoked.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(EnrollmentTest, cls).skip_checks()
|
||||
pass
|
||||
|
||||
@decorators.idempotent_id('89165fb4-5534-4b9d-8429-97ccffb8f86f')
|
||||
@test.services('compute')
|
||||
def test_enrollment_using_metadata(self):
|
||||
LOG.info("Creating keypair and security group")
|
||||
keypair = self.create_keypair()
|
||||
security_group = self._create_security_group()
|
||||
# TODO(alee) Add metadata for ipa_enroll=True
|
||||
# TODO(alee) Add metadata for service to be created/joined
|
||||
server = self.create_server(
|
||||
name='passed_metadata_server',
|
||||
image_id=self.no_metadata_img_uuid,
|
||||
key_name=keypair['name'],
|
||||
security_groups=[{'name': security_group['name']}],
|
||||
wait_until='ACTIVE'
|
||||
)
|
||||
self.verify_registered_host(server, keypair, service, cn)
|
||||
self.delete_server(server)
|
||||
self.verify_unregistered_host(server, service, serial)
|
||||
|
||||
@decorators.idempotent_id('cbc752ed-b716-4727-910f-956ccf965723')
|
||||
@test.services('compute')
|
||||
def test_enrollment_using_image_metadata(self):
|
||||
LOG.info("Creating keypair and security group")
|
||||
keypair = self.create_keypair()
|
||||
security_group = self._create_security_group()
|
||||
# TODO(alee) Add metadata for service to be created/joined
|
||||
server = self.create_server(
|
||||
name='signed_img_server',
|
||||
image_id=metadata_img_uuid,
|
||||
key_name=keypair['name'],
|
||||
security_groups=[{'name': security_group['name']}],
|
||||
wait_until='ACTIVE'
|
||||
)
|
||||
self.verify_registered_host(server, keypair, service, cn)
|
||||
self.delete_server(server)
|
||||
self.verify_unregistered_host(server, service, serial)
|
||||
|
||||
def verify_registered_host(self, server, keypair, service, cn):
|
||||
self.verify_host_registered_with_ipa(server)
|
||||
self.verify_host_has_keytab(server)
|
||||
self.verify_host_is_ipaclient(server)
|
||||
self.verify_service_created(service, server)
|
||||
self.verify_cert_tracked(self, host, keypair, cn)
|
||||
|
||||
def verify_unregistered_host(self, server, service, serial):
|
||||
self.verify_host_not_registered_with_ipa(server)
|
||||
self.verify_service_deleted(service, server)
|
||||
self.verify_cert_revoked(serial)
|
||||
|
@ -0,0 +1,49 @@
|
||||
# Copyright (c) 2017 Red Hat
|
||||
#
|
||||
# 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 import config
|
||||
from tempest.lib import decorators
|
||||
from tempest import test
|
||||
|
||||
from novajoin_tempest_plugin.tests.scenario import novajoin_manager
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TripleOTest(novajoin_manager.NovajoinScenarioTest):
|
||||
|
||||
"""The test suite for tripleO configuration
|
||||
|
||||
Novajoin is currently deployed in tripleO as part of the
|
||||
undercloud as part of a tripleO deployment.
|
||||
|
||||
This test is to validate that all the nodes and services
|
||||
for an HA deployment have been correctly created.
|
||||
|
||||
This means:
|
||||
* Validating that the undercloud is enrolled in IPA
|
||||
* Validating that the controller is enrolled in IPA
|
||||
* Validating that the compute node is enrolled
|
||||
* Validating that HA services have been created in IPA
|
||||
* Validating that certs are being tracked.
|
||||
* Validate that TLS connections are being established for
|
||||
all internal services
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(TripleOTest, cls).skip_checks()
|
||||
pass
|
@ -0,0 +1,29 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
test_novajoin_tempest_plugin
|
||||
----------------------------------
|
||||
|
||||
Tests for `novajoin_tempest_plugin` module.
|
||||
"""
|
||||
|
||||
from tempest.lib import decorators
|
||||
|
||||
from novajoin_tempest_plugin.tests import base
|
||||
|
||||
|
||||
class TestNovajoin_tempest_plugin(base.TestCase):
|
||||
|
||||
@decorators.idempotent_id('8abf6dec-37b9-43ca-95cf-b8ebecda3c8d')
|
||||
def test_something(self):
|
||||
pass
|
10
requirements.txt
Normal file
10
requirements.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=1.8 # Apache-2.0
|
||||
|
||||
tempest>=12.1.0 # Apache-2.0
|
||||
cryptography!=1.3.0,>=1.0 # BSD/Apache-2.0
|
||||
|
||||
oslo.config>=3.22.0 # Apache-2.0
|
28
setup.cfg
Normal file
28
setup.cfg
Normal file
@ -0,0 +1,28 @@
|
||||
[metadata]
|
||||
name = novajoin_tempest_plugin
|
||||
summary = OpenStack Novajoin tempest tests.
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://www.openstack.org/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: Python :: 3.5
|
||||
|
||||
[files]
|
||||
packages =
|
||||
novajoin_tempest_plugin
|
||||
|
||||
[entry_points]
|
||||
tempest.test_plugins =
|
||||
novajoin_tests = novajoin_tempest_plugin.plugin:NovajoinTempestPlugin
|
29
setup.py
Normal file
29
setup.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright 2016 SAP SE
|
||||
#
|
||||
# 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.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||
# setuptools if some other modules registered functions in `atexit`.
|
||||
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||
try:
|
||||
import multiprocessing # noqa
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr>=1.8'],
|
||||
pbr=True)
|
15
test-requirements.txt
Normal file
15
test-requirements.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking>=0.12.0,<0.13 # Apache-2.0
|
||||
|
||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||
sphinx>=1.2.1,!=1.3b1,<1.4 # BSD
|
||||
oslosphinx>=4.7.0 # Apache-2.0
|
||||
oslotest>=1.10.0 # Apache-2.0
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
|
||||
oslo.log>=3.22.0 # Apache-2.0
|
31
tox.ini
Normal file
31
tox.ini
Normal file
@ -0,0 +1,31 @@
|
||||
[tox]
|
||||
minversion = 2.0
|
||||
envlist = py35,py27,pypy,pep8
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
PYTHONWARNINGS=default::DeprecationWarning
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:pep8]
|
||||
commands =
|
||||
flake8 {posargs}
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
show-source = True
|
||||
ignore = E123,E125
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
Loading…
x
Reference in New Issue
Block a user