def setUpClass(cls, application_name=None, model_alias=None): """Run class setup for running Designate charm operation tests.""" application_name = application_name or "designate" model_alias = model_alias or "" super(BaseDesignateTest, cls).setUpClass(application_name, model_alias) os_release = openstack_utils.get_os_release if os_release() >= os_release('bionic_rocky'): cls.designate_svcs = [ 'designate-agent', 'designate-api', 'designate-central', 'designate-mdns', 'designate-worker', 'designate-sink', 'designate-producer', ] else: cls.designate_svcs = [ 'designate-agent', 'designate-api', 'designate-central', 'designate-mdns', 'designate-pool-manager', 'designate-sink', 'designate-zone-manager', ] # Get keystone session cls.post_xenial_queens = os_release() >= os_release('xenial_queens') overcloud_auth = openstack_utils.get_overcloud_auth() keystone = openstack_utils.get_keystone_client(overcloud_auth) keystone_session = openstack_utils.get_overcloud_keystone_session() if cls.post_xenial_queens: cls.designate = openstack_utils.get_designate_session_client( session=keystone_session) cls.domain_list = cls.designate.zones.list cls.domain_delete = cls.designate.zones.delete cls.domain_create = cls.designate.zones.create else: # Authenticate admin with designate endpoint designate_ep = keystone.service_catalog.url_for( service_type='dns', interface='publicURL') keystone_ep = keystone.service_catalog.url_for( service_type='identity', interface='publicURL') cls.designate = openstack_utils.get_designate_session_client( version=1, auth_url=keystone_ep, token=keystone_session.get_token(), tenant_name="admin", endpoint=designate_ep) cls.domain_list = cls.designate.domains.list cls.domain_delete = cls.designate.domains.delete cls.domain_create = cls.designate.domains.create cls.server_list = cls.designate.servers.list cls.server_create = cls.designate.servers.create cls.server_delete = cls.designate.servers.delete
def setUpClass(cls): """Run class setup for running glance simple streams sync tests.""" super(GlanceSimpleStreamsSyncTest, cls).setUpClass() # dict of OS_* env vars overcloud_auth = openstack_utils.get_overcloud_auth() cls.keystone_client = openstack_utils.get_keystone_client( overcloud_auth) cls.glance_client = openstack_utils.get_glance_session_client( cls.keystone_session)
def test_110_catalog_endpoints(self): """Verify that the endpoints are present in the catalog.""" overcloud_auth = openstack_utils.get_overcloud_auth() keystone_client = openstack_utils.get_keystone_client( overcloud_auth) actual_endpoints = keystone_client.service_catalog.get_endpoints() actual_interfaces = [endpoint['interface'] for endpoint in actual_endpoints["baremetal"]] for expected_interface in ('internal', 'admin', 'public'): assert(expected_interface in actual_interfaces)
def configure_external_s3_backend(): """Set up Ceph-radosgw as an external S3 backend for Glance.""" logging.info("Creating a test S3 user and credentials for Glance") username, displayname = "zaza-glance-test", "Zaza Glance Test User" cmd = "radosgw-admin user create --uid='{}' --display-name='{}'".format( username, displayname) results = model.run_on_leader("ceph-mon", cmd) stdout = json.loads(results["stdout"]) keys = stdout["keys"][0] access_key, secret_key = keys["access_key"], keys["secret_key"] logging.info("Getting S3 endpoint URL of Radosgw from Keystone") keystone_auth = openstack_utils.get_overcloud_auth() keystone_client = openstack_utils.get_keystone_client(keystone_auth) endpoint_url = keystone_client.session.get_endpoint( service_type="s3", interface="public", region="RegionOne", ) logging.info("Creating a test S3 bucket for Glance") bucket_name = "zaza-glance-s3-test" s3_client = boto3.client( "s3", endpoint_url=endpoint_url, aws_access_key_id=access_key, aws_secret_access_key=secret_key, ) s3_client.create_bucket(Bucket=bucket_name) logging.info("Updating Glance configs with S3 endpoint information") model.set_application_config( "glance", { "s3-store-host": endpoint_url, "s3-store-access-key": access_key, "s3-store-secret-key": secret_key, "s3-store-bucket": bucket_name, }, ) model.wait_for_agent_status() logging.info("Waiting for units to reach target states") model.wait_for_application_states( states={ "glance": { "workload-status": "active", "workload-status-message": "Unit is ready", } }) model.block_until_all_units_idle()
def test_200_api_connection(self): """Simple api calls to check service is up and responding.""" logging.info('Instantiating gnocchi client...') overcloud_auth = openstack_utils.get_overcloud_auth() keystone = openstack_utils.get_keystone_client(overcloud_auth) gnocchi_ep = keystone.service_catalog.url_for(service_type='metric', interface='publicURL') gnocchi = gnocchi_client.Client( session=openstack_utils.get_overcloud_keystone_session(), adapter_options={ 'endpoint_override': gnocchi_ep, }) logging.info('Checking api functionality...') assert (gnocchi.status.get() != [])
def test_106_compute_catalog_endpoints(self): """Verify that the compute endpoints are present in the catalog.""" overcloud_auth = openstack_utils.get_overcloud_auth() keystone_client = openstack_utils.get_keystone_client( overcloud_auth) actual_endpoints = keystone_client.service_catalog.get_endpoints() logging.info('Checking compute endpoints...') if self.current_release < self.XENIAL_QUEENS: actual_compute_endpoints = actual_endpoints['compute'][0] for expected_url in ('internalURL', 'adminURL', 'publicURL'): assert(expected_url in actual_compute_endpoints) else: actual_compute_interfaces = [endpoint['interface'] for endpoint in actual_endpoints['compute']] for expected_interface in ('internal', 'admin', 'public'): assert(expected_interface in actual_compute_interfaces)
def test_400_api_connection(self): """Simple api calls to check service is up and responding.""" logging.info('Authenticating with the barbican endpoint') overcloud_auth = openstack_utils.get_overcloud_auth() keystone_client = openstack_utils.get_keystone_client( overcloud_auth) keystone_session = openstack_utils.get_overcloud_keystone_session() barbican_endpoint = keystone_client.service_catalog.url_for( service_type='key-manager', interface='publicURL') barbican = barbican_client.Client(session=keystone_session, endpoint=barbican_endpoint) logging.info('Creating a secret') my_secret = barbican.secrets.create() my_secret.name = u'Random plain text password' my_secret.payload = u'password' logging.info('Storing the secret') my_secret_ref = my_secret.store() assert(my_secret_ref is not None) logging.info('Deleting the secret') my_secret.delete()
def test_400_gnocchi_metrics(self): """Verify that ceilometer-agent publishes metrics to gnocchi.""" current_os_release = openstack_utils.get_os_release() openstack_pike_or_older = ( current_os_release <= openstack_utils.get_os_release('xenial_pike')) if openstack_pike_or_older: # Both the charm and Ceilometer itself had different behaviors in # terms of which metrics were published and how fast, which would # lead to a combinatorial explosion if we had to maintain test # expectations for these old releases. logging.info('OpenStack Pike or older, skipping') return # ceilometer-agent-compute reports metrics for each existing VM, so at # least one VM is needed: self.RESOURCE_PREFIX = 'zaza-ceilometer-agent' self.launch_guest('ubuntu', instance_key=glance_setup.LTS_IMAGE_NAME) logging.info('Instantiating gnocchi client...') overcloud_auth = openstack_utils.get_overcloud_auth() keystone = openstack_utils.get_keystone_client(overcloud_auth) gnocchi_ep = keystone.service_catalog.url_for(service_type='metric', interface='publicURL') gnocchi = gnocchi_client.Client( session=openstack_utils.get_overcloud_keystone_session(), adapter_options={ 'endpoint_override': gnocchi_ep, }) expected_metric_names = self.__get_expected_metric_names( current_os_release) min_timeout_seconds = 500 polling_interval_seconds = ( openstack_utils.get_application_config_option( self.application_name, 'polling-interval')) timeout_seconds = max(10 * polling_interval_seconds, min_timeout_seconds) logging.info('Giving ceilometer-agent {}s to publish all metrics to ' 'gnocchi...'.format(timeout_seconds)) max_time = time.time() + timeout_seconds while time.time() < max_time: found_metric_names = { metric['name'] for metric in gnocchi.metric.list() } missing_metric_names = expected_metric_names - found_metric_names if len(missing_metric_names) == 0: logging.info('All expected metrics found.') break time.sleep(polling_interval_seconds) unexpected_found_metric_names = (found_metric_names - expected_metric_names) if len(unexpected_found_metric_names) > 0: logging.info('Unexpected metrics ' 'published: ' + ', '.join(unexpected_found_metric_names)) if len(missing_metric_names) > 0: self.fail('These metrics should have been published but ' "weren't: " + ', '.join(missing_metric_names))
def _login(dashboard_url, domain, username, password, cafile=None): """Login to the website to get a session. :param dashboard_url: The URL of the dashboard to log in to. :type dashboard_url: str :param domain: the domain to login into :type domain: str :param username: the username to login as :type username: str :param password: the password to use to login :type password: str :returns: tuple of (client, response) where response is the page after logging in. :rtype: (requests.sessions.Session, requests.models.Response) :raises: FailedAuth if the authorisation doesn't work """ auth_url = '{}/auth/login/'.format(dashboard_url) # start session, get csrftoken client = requests.session() client.get(auth_url, verify=cafile) if 'csrftoken' in client.cookies: csrftoken = client.cookies['csrftoken'] else: raise Exception("Missing csrftoken") # build and send post request overcloud_auth = openstack_utils.get_overcloud_auth() if overcloud_auth['OS_AUTH_URL'].endswith("v2.0"): api_version = 2 else: api_version = 3 keystone_client = openstack_utils.get_keystone_client(overcloud_auth) catalog = keystone_client.service_catalog.get_endpoints() logging.info(catalog) if api_version == 2: region = catalog['identity'][0]['publicURL'] else: region = [ i['url'] for i in catalog['identity'] if i['interface'] == 'public' ][0] auth = { 'domain': domain, 'username': username, 'password': password, 'csrfmiddlewaretoken': csrftoken, 'next': '/horizon/', 'region': region, } # In the minimal test deployment /horizon/project/ is unauthorized, # this does not occur in a full deployment and is probably due to # services/information missing that horizon wants to display data # for. # Redirect to /horizon/identity/ instead. if (openstack_utils.get_os_release() >= openstack_utils.get_os_release('xenial_queens')): auth['next'] = '/horizon/identity/' if (openstack_utils.get_os_release() >= openstack_utils.get_os_release('bionic_stein')): auth['region'] = 'default' if api_version == 2: del auth['domain'] logging.info('POST data: "{}"'.format(auth)) response = client.post(auth_url, data=auth, headers={'Referer': auth_url}, verify=cafile) # NOTE(ajkavanagh) there used to be a trusty/icehouse test in the # amulet test, but as the zaza tests only test from trusty/mitaka # onwards, the test has been dropped if (openstack_utils.get_os_release() >= openstack_utils.get_os_release('bionic_stein')): expect = "Sign Out" # update the in dashboard seems to require region to be default in # this test configuration region = 'default' else: expect = 'Projects - OpenStack Dashboard' if expect not in response.text: msg = 'FAILURE code={} text="{}"'.format(response, response.text) logging.info("Yeah, wen't wrong: {}".format(msg)) raise FailedAuth(msg) logging.info("Logged into okay") return client, response
def test_401_authenticate(self): """Validate that authentication succeeds for client log in. Ported from amulet tests. """ logging.info('Checking authentication through dashboard...') unit_name = zaza_model.get_lead_unit_name('openstack-dashboard') keystone_unit = zaza_model.get_lead_unit_name('keystone') dashboard_relation = openstack_juju.get_relation_from_unit( keystone_unit, unit_name, 'identity-service') dashboard_ip = dashboard_relation['private-address'] logging.debug("... dashboard_ip is:{}".format(dashboard_ip)) url = 'http://{}/horizon/auth/login/'.format(dashboard_ip) overcloud_auth = openstack_utils.get_overcloud_auth() if overcloud_auth['OS_AUTH_URL'].endswith("v2.0"): api_version = 2 else: api_version = 3 keystone_client = openstack_utils.get_keystone_client(overcloud_auth) catalog = keystone_client.service_catalog.get_endpoints() logging.info(catalog) if api_version == 2: region = catalog['identity'][0]['publicURL'] else: region = [ i['url'] for i in catalog['identity'] if i['interface'] == 'public' ][0] # NOTE(ajkavanagh) there used to be a trusty/icehouse test in the # amulet test, but as the zaza tests only test from trusty/mitaka # onwards, the test has been dropped if (openstack_utils.get_os_release() >= openstack_utils.get_os_release('bionic_stein')): expect = "Sign Out" # update the in dashboard seems to require region to be default in # this test configuration region = 'default' else: expect = 'Projects - OpenStack Dashboard' # NOTE(thedac) Similar to the connection test above we get occasional # intermittent authentication fails. Wrap in a retry loop. @tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, min=5, max=10), retry=tenacity.retry_unless_exception_type( self.AuthExceptions), reraise=True) def _do_auth_check(expect): # start session, get csrftoken client = requests.session() client.get(url) if 'csrftoken' in client.cookies: csrftoken = client.cookies['csrftoken'] else: raise Exception("Missing csrftoken") # build and send post request auth = { 'domain': 'admin_domain', 'username': '******', 'password': overcloud_auth['OS_PASSWORD'], 'csrfmiddlewaretoken': csrftoken, 'next': '/horizon/', 'region': region, } # In the minimal test deployment /horizon/project/ is unauthorized, # this does not occur in a full deployment and is probably due to # services/information missing that horizon wants to display data # for. # Redirect to /horizon/identity/ instead. if (openstack_utils.get_os_release() >= openstack_utils.get_os_release('xenial_queens')): auth['next'] = '/horizon/identity/' if (openstack_utils.get_os_release() >= openstack_utils.get_os_release('bionic_stein')): auth['region'] = 'default' if api_version == 2: del auth['domain'] logging.info('POST data: "{}"'.format(auth)) response = client.post(url, data=auth, headers={'Referer': url}) if expect not in response.text: msg = 'FAILURE code={} text="{}"'.format( response, response.text) # NOTE(thedac) amulet.raise_status exits on exception. # Raise a custom exception. logging.info("Yeah, wen't wrong: {}".format(msg)) raise self.FailedAuth(msg) raise self.PassedAuth() try: _do_auth_check(expect) except self.FailedAuth as e: assert False, str(e) except self.PassedAuth: pass