예제 #1
0
    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
예제 #2
0
 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)
예제 #3
0
 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)
예제 #4
0
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()
예제 #5
0
    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() != [])
예제 #6
0
    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)
예제 #7
0
    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()
예제 #8
0
    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))
예제 #9
0
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
예제 #10
0
    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