Add novajoin server test
This commit is contained in:
parent
d3ea01cc31
commit
20e73d9285
|
@ -190,7 +190,7 @@ class IPAClient(IPABase):
|
|||
|
||||
def service_managed_by_host(self, service_principal, host):
|
||||
"""Return True if service is managed by specified host"""
|
||||
params = [service_principal]
|
||||
params = [unicode(service_principal)]
|
||||
service_args = {}
|
||||
try:
|
||||
result = self._call_ipa('service_show', *params, **service_args)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
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
|
||||
|
@ -35,51 +34,51 @@ LOG = log.getLogger(__name__)
|
|||
class ScenarioTest(tempest.test.BaseTestCase):
|
||||
"""Base class for scenario tests. Uses tempest own clients. """
|
||||
|
||||
credentials = ['primary']
|
||||
credentials = ['primary', 'admin']
|
||||
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(ScenarioTest, cls).setup_clients()
|
||||
# Clients (in alphabetical order)
|
||||
cls.flavors_client = cls.os_primary.flavors_client
|
||||
cls.flavors_client = cls.os_admin.flavors_client
|
||||
cls.compute_floating_ips_client = (
|
||||
cls.os_primary.compute_floating_ips_client)
|
||||
cls.os_admin.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
|
||||
cls.image_client = cls.os_admin.image_client
|
||||
elif CONF.image_feature_enabled.api_v2:
|
||||
cls.image_client = cls.os_primary.image_client_v2
|
||||
cls.image_client = cls.os_admin.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
|
||||
cls.compute_images_client = cls.os_admin.compute_images_client
|
||||
cls.keypairs_client = cls.os_admin.keypairs_client
|
||||
# Nova security groups client
|
||||
cls.compute_security_groups_client = (
|
||||
cls.os_primary.compute_security_groups_client)
|
||||
cls.os_admin.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
|
||||
cls.os_admin.compute_security_group_rules_client)
|
||||
cls.servers_client = cls.os_admin.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.networks_client = cls.os_admin.networks_client
|
||||
cls.ports_client = cls.os_admin.ports_client
|
||||
cls.routers_client = cls.os_admin.routers_client
|
||||
cls.subnets_client = cls.os_admin.subnets_client
|
||||
cls.floating_ips_client = cls.os_admin.floating_ips_client
|
||||
cls.security_groups_client = cls.os_admin.security_groups_client
|
||||
cls.security_group_rules_client = (
|
||||
cls.os_primary.security_group_rules_client)
|
||||
cls.os_admin.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
|
||||
cls.volumes_client = cls.os_admin.volumes_v2_client
|
||||
cls.snapshots_client = cls.os_admin.snapshots_v2_client
|
||||
|
||||
if CONF.volume_feature_enabled.api_v1:
|
||||
cls.volumes_client = cls.os_primary.volumes_client
|
||||
cls.snapshots_client = cls.os_primary.snapshots_client
|
||||
cls.volumes_client = cls.os_admin.volumes_client
|
||||
cls.snapshots_client = cls.os_admin.snapshots_client
|
||||
|
||||
# ## Test functions library
|
||||
#
|
||||
|
@ -107,105 +106,23 @@ class ScenarioTest(tempest.test.BaseTestCase):
|
|||
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']
|
||||
net_id=None, key=None, wait_until='ACTIVE',
|
||||
sec_grps=[], metadata={}, **kwargs):
|
||||
networks = [{'uuid': net_id}]
|
||||
server = self.servers_client.create_server(name=name,
|
||||
imageRef=image_id,
|
||||
flavorRef=flavor,
|
||||
key_name=key,
|
||||
security_groups=sec_grps,
|
||||
networks=networks,
|
||||
metadata=metadata,
|
||||
**kwargs)['server']
|
||||
server_id = server['id']
|
||||
waiters.wait_for_server_status(self.servers_client, server_id,
|
||||
'ACTIVE')
|
||||
return server
|
||||
|
||||
def create_volume(self, size=None, name=None, snapshot_id=None,
|
||||
|
@ -263,8 +180,8 @@ class ScenarioTest(tempest.test.BaseTestCase):
|
|||
self.addCleanup(client.delete_volume_type, volume_type['id'])
|
||||
return volume_type
|
||||
|
||||
def _image_create(self, name, fmt, path,
|
||||
disk_format=None, properties=None):
|
||||
def image_create(self, name, fmt,
|
||||
disk_format=None, properties=None):
|
||||
if properties is None:
|
||||
properties = {}
|
||||
name = data_utils.rand_name('%s-' % name)
|
||||
|
@ -283,9 +200,10 @@ class ScenarioTest(tempest.test.BaseTestCase):
|
|||
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.addCleanup(self.image_client.delete_image, image['id'])
|
||||
self.assertEqual("queued", image['status'])
|
||||
with open(path, 'rb') as image_file:
|
||||
img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
|
||||
with open(img_path, 'rb') as image_file:
|
||||
if CONF.image_feature_enabled.api_v1:
|
||||
self.image_client.update_image(image['id'], data=image_file)
|
||||
else:
|
||||
|
|
|
@ -58,6 +58,13 @@ class NovajoinScenarioTest(manager.ScenarioTest):
|
|||
if add_domain:
|
||||
host = self.add_domain_to_host(host)
|
||||
result = self.ipa_client.find_host(host)
|
||||
start = int(time.time())
|
||||
host_count = result['count']
|
||||
timeout = 300
|
||||
while (host_count > 0) and (int(time.time()) - start < timeout):
|
||||
time.sleep(30)
|
||||
result = self.ipa_client.find_host(host)
|
||||
host_count = result['count']
|
||||
self.assertFalse(result['count'] > 0)
|
||||
|
||||
def add_domain_to_host(self, host):
|
||||
|
@ -85,14 +92,34 @@ class NovajoinScenarioTest(manager.ScenarioTest):
|
|||
self.assertTrue(result['count'] > 0)
|
||||
|
||||
def verify_service_managed_by_host(self, service, host):
|
||||
# TODO(alee) Implement this using service-show
|
||||
pass
|
||||
service_principal = self.get_service_principal(host, service)
|
||||
result = self.ipa_client.service_managed_by_host(service_principal,
|
||||
host)
|
||||
self.assertTrue(result)
|
||||
|
||||
def verify_service_deleted(self, service, host):
|
||||
service_principal = self.get_service_principal(host, service)
|
||||
result = self.ipa_client.find_service(service_principal)
|
||||
self.assertFalse(result['count'] > 0)
|
||||
|
||||
def verify_compact_services_deleted(self, services, host):
|
||||
for (service, networks) in services.items():
|
||||
for network in networks:
|
||||
subhost = '{host}.{network}.{domain}'.format(
|
||||
host=host, network=network, domain=self.ipa_client.domain
|
||||
)
|
||||
service_principal = self.get_service_principal(subhost, service)
|
||||
result = self.ipa_client.find_service(service_principal)
|
||||
self.assertFalse(result['count'] > 0)
|
||||
|
||||
def verify_managed_services_deleted(self, services):
|
||||
for principal in services:
|
||||
service = principal.split('/', 1)[0]
|
||||
host = principal.split('/', 1)[1]
|
||||
service_principal = self.get_service_principal(host, service)
|
||||
result = self.ipa_client.find_service(service_principal)
|
||||
self.assertFalse(result['count'] > 0)
|
||||
|
||||
def get_service_cert(self, service, host):
|
||||
service_principal = self.get_service_principal(host, service)
|
||||
return self.ipa_client.get_service_cert(service_principal)
|
||||
|
@ -103,7 +130,7 @@ class NovajoinScenarioTest(manager.ScenarioTest):
|
|||
)
|
||||
|
||||
def verify_host_is_ipaclient(self, hostip, user, keypair):
|
||||
cmd = 'id admin'
|
||||
cmd = "id admin"
|
||||
private_key = keypair['private_key']
|
||||
ssh_client = self.get_remote_client(hostip, user, private_key)
|
||||
result = ssh_client.exec_command(cmd)
|
||||
|
|
|
@ -13,104 +13,157 @@
|
|||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
from tempest import test
|
||||
from tempest.lib.common.utils import data_utils
|
||||
|
||||
from novajoin_tempest_plugin.tests.scenario import novajoin_manager
|
||||
|
||||
import ast
|
||||
|
||||
CONF = config.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
USER = 'cloud-user'
|
||||
NETWORK = 'ctlplane'
|
||||
|
||||
|
||||
class EnrollmentTest(novajoin_manager.NovajoinScenarioTest):
|
||||
class ServerTest(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 are removed when the
|
||||
instance is deleted.
|
||||
* Validate that the certs issued have been revoked.
|
||||
"""
|
||||
credentials = ['primary', 'admin']
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(EnrollmentTest, cls).skip_checks()
|
||||
pass
|
||||
def setup_credentials(cls):
|
||||
cls.set_network_resources()
|
||||
super(ServerTest, cls).setup_credentials()
|
||||
|
||||
@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
|
||||
@classmethod
|
||||
def setup_clients(cls):
|
||||
super(ServerTest, cls).setup_clients()
|
||||
|
||||
service = "random service to be added"
|
||||
cn = "cn of random service certificate"
|
||||
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'
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ServerTest, cls).resource_setup()
|
||||
|
||||
def _create_flavor(self, flavor_name):
|
||||
specs = {"capabilities:boot_option": "local",
|
||||
"capabilities:profile": "compute"}
|
||||
flvid = data_utils.rand_int_id(start=1000)
|
||||
ram = 4096
|
||||
vcpus = 1
|
||||
disk = 40
|
||||
self.flavors_client.create_flavor(name=flavor_name,
|
||||
ram=ram,
|
||||
vcpus=vcpus,
|
||||
disk=disk,
|
||||
id=flvid)['flavor']
|
||||
self.flavors_client.set_flavor_extra_spec(flvid,
|
||||
**specs)
|
||||
return flvid
|
||||
|
||||
def _create_image(self, name, properties={}):
|
||||
container_format = 'bare'
|
||||
disk_format = 'qcow2'
|
||||
image_id = self.image_create(name=name,
|
||||
fmt=container_format,
|
||||
disk_format=disk_format,
|
||||
properties=properties)
|
||||
return image_id
|
||||
|
||||
def _verify_host_and_services_are_enrolled(self, server_name,
|
||||
server_id, keypair):
|
||||
|
||||
self.verify_host_registered_with_ipa(server_name)
|
||||
self.verify_host_has_keytab(server_name)
|
||||
|
||||
# Verify compact services are created
|
||||
|
||||
metadata = self.servers_client.list_server_metadata(server_id
|
||||
)['metadata']
|
||||
services = metadata['compact_services']
|
||||
self.compact_services = ast.literal_eval(services)
|
||||
self.verify_compact_services(
|
||||
services=self.compact_services,
|
||||
host=server_name,
|
||||
)
|
||||
self.verify_registered_host(server, keypair, service, cn)
|
||||
self.delete_server(server)
|
||||
|
||||
serial = "serial number of random service certificate"
|
||||
self.verify_unregistered_host(server, service, serial)
|
||||
# Verify managed services are created
|
||||
metadata = self.servers_client.list_server_metadata(server_id
|
||||
)['metadata']
|
||||
self.managed_services = [metadata[key] for key in metadata.keys()
|
||||
if key.startswith('managed_service_')]
|
||||
self.verify_managed_services(self.managed_services)
|
||||
|
||||
@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")
|
||||
# Verify instance created above is ipaclient
|
||||
server_details = self.servers_client.show_server(server_id
|
||||
)['server']
|
||||
ip = self.get_server_ip(server_details)
|
||||
self.verify_host_is_ipaclient(ip, USER, keypair)
|
||||
|
||||
def _verify_host_and_services_are_not_enrolled(self,
|
||||
server_name,
|
||||
server_id):
|
||||
|
||||
# Verify host and associated compact and managed services
|
||||
# are no longer registered with ipa
|
||||
self.verify_host_not_registered_with_ipa(server_name)
|
||||
self.verify_compact_services_deleted(services=self.compact_services,
|
||||
host=server_name)
|
||||
self.verify_managed_services_deleted(self.managed_services)
|
||||
|
||||
def test_enrollment_metadata_in_instance(self):
|
||||
|
||||
networks = self.networks_client.list_networks(name=NETWORK)
|
||||
net_id = networks['networks'][0]['id']
|
||||
flavor_name = data_utils.rand_name('flv_metadata_in_instance')
|
||||
flavor_id = self._create_flavor(flavor_name)
|
||||
image_name = data_utils.rand_name('img_metadata_in_instance')
|
||||
image_id = self._create_image(image_name)
|
||||
keypair = self.create_keypair()
|
||||
security_group = self._create_security_group()
|
||||
instance_name = data_utils.rand_name("instance")
|
||||
metadata = {"ipa_enroll": "True",
|
||||
"compact_services":
|
||||
"{\"HTTP\": [\"ctlplane\", \"internalapi\"]}",
|
||||
"managed_service_test": "novajoin/test.example.com"}
|
||||
server = self.create_server(name=instance_name,
|
||||
image_id=image_id,
|
||||
flavor=flavor_id,
|
||||
net_id=net_id,
|
||||
key=keypair['name'],
|
||||
metadata=metadata,
|
||||
wait_until='ACTIVE')
|
||||
self._verify_host_and_services_are_enrolled(instance_name,
|
||||
server['id'],
|
||||
keypair)
|
||||
self.servers_client.delete_server(server['id'])
|
||||
self._verify_host_and_services_are_not_enrolled(instance_name,
|
||||
server['id'])
|
||||
|
||||
# TODO(alee) Add metadata for service to be created/joined
|
||||
service = "random service to be added"
|
||||
cn = "cn of random service certificate"
|
||||
def test_enrollment_metadata_in_image(self):
|
||||
|
||||
server = self.create_server(
|
||||
name='img_with_metadata_server',
|
||||
image_id=self.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)
|
||||
|
||||
serial = "serial number of cert for random service"
|
||||
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, keypair)
|
||||
self.verify_service_created(service, server)
|
||||
self.verify_cert_tracked(server, 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)
|
||||
networks = self.networks_client.list_networks(name=NETWORK)
|
||||
net_id = networks['networks'][0]['id']
|
||||
flavor_name = data_utils.rand_name('flv_metadata_in_image')
|
||||
flavor_id = self._create_flavor(flavor_name)
|
||||
image_name = data_utils.rand_name('metadata_in_image')
|
||||
properties = {"ipa_enroll": "True"}
|
||||
image_id = self._create_image(image_name, properties)
|
||||
keypair = self.create_keypair()
|
||||
f = open('/tmp/priv.key', 'w')
|
||||
f.write(keypair['private_key'])
|
||||
f.close()
|
||||
instance_name = data_utils.rand_name("novajoin")
|
||||
metadata = {"compact_services":
|
||||
"{\"HTTP\": [\"ctlplane\", \"internalapi\"]}",
|
||||
"managed_service_test": "novajoin/test.example.com"}
|
||||
server = self.create_server(name=instance_name,
|
||||
image_id=image_id,
|
||||
flavor=flavor_id,
|
||||
net_id=net_id,
|
||||
key=keypair['name'],
|
||||
metadata=metadata,
|
||||
wait_until='ACTIVE')
|
||||
self._verify_host_and_services_are_enrolled(instance_name,
|
||||
server['id'], keypair)
|
||||
self.servers_client.delete_server(server['id'])
|
||||
self._verify_host_and_services_are_not_enrolled(instance_name,
|
||||
server['id'])
|
||||
|
|
Loading…
Reference in New Issue