Esempio n. 1
0
 def test_get_relation_from_unit_fails(self):
     self.patch_object(juju_utils, '_get_unit_names')
     self.patch_object(juju_utils, 'yaml')
     self.patch_object(juju_utils, 'model')
     self._get_unit_names.return_value = ['aunit/0', 'otherunit/0']
     self.model.get_relation_id.return_value = 42
     self.model.run_on_unit.return_value = {'Code': 1, 'Stderr': 'ERROR'}
     with self.assertRaises(Exception):
         juju_utils.get_relation_from_unit('aunit/0', 'otherunit/0',
                                           'arelation')
     self.model.run_on_unit.assert_called_with(
         'aunit/0', 'relation-get --format=yaml -r "42" - "otherunit/0"')
     self.assertFalse(self.yaml.safe_load.called)
Esempio n. 2
0
 def test_get_relation_from_unit(self):
     self.patch_object(juju_utils, '_get_unit_names')
     self.patch_object(juju_utils, 'yaml')
     self.patch_object(juju_utils, 'model')
     self._get_unit_names.return_value = ['aunit/0', 'otherunit/0']
     data = {'foo': 'bar'}
     self.model.get_relation_id.return_value = 42
     self.model.run_on_unit.return_value = {'Code': 0, 'Stdout': str(data)}
     juju_utils.get_relation_from_unit('aunit/0', 'otherunit/0',
                                       'arelation')
     self.model.run_on_unit.assert_called_with(
         'aunit/0', 'relation-get --format=yaml -r "42" - "otherunit/0"')
     self.yaml.safe_load.assert_called_with(str(data))
Esempio n. 3
0
def get_pools_from_broker_req(application_or_unit, model_name=None):
    """Get pools requested by application or unit.

    By retrieving and parsing broker request from relation data we can get a
    list of pools a unit has requested.

    :param application_or_unit: Name of application or unit that is at the
                                other end of a ceph-mon relation.
    :type application_or_unit: str
    :param model_name: Name of Juju model to operate on
    :type model_name: Optional[str]
    :returns: List of pools requested.
    :rtype: List[str]
    :raises: KeyError
    """
    # NOTE: we do not pass on a name for the remote_interface_name as that
    # varies between the Ceph consuming applications.
    relation_data = juju_utils.get_relation_from_unit(
        'ceph-mon', application_or_unit, None, model_name=model_name)

    # NOTE: we probably should consume the Ceph broker code from c-h but c-h is
    # such a beast of a dependency so let's defer adding it to Zaza if we can.
    broker_req = json.loads(relation_data['broker_req'])

    # A charm may request modifications to an existing pool by adding multiple
    # 'create-pool' broker requests so we need to deduplicate the list before
    # returning it.
    return list(set([
        op['name']
        for op in broker_req['ops']
        if op['op'] == 'create-pool'
    ]))
Esempio n. 4
0
    def test_configure_compression(self):
        """Enable compression and validate properties flush through to pool."""
        if not self.mimic_or_newer:
            logging.info('Skipping test, Mimic or newer required.')
            return
        if self.application_name == 'ceph-osd':
            # The ceph-osd charm itself does not request pools, neither does
            # the BlueStore Compression configuration options it have affect
            # pool properties.
            logging.info('test does not apply to ceph-osd charm.')
            return
        elif self.application_name == 'ceph-radosgw':
            # The Ceph RadosGW creates many light weight pools to keep track of
            # metadata, we only compress the pool containing actual data.
            app_pools = ['.rgw.buckets.data']
        else:
            # Retrieve which pools the charm under test has requested skipping
            # metadata pools as they are deliberately not compressed.
            app_pools = [
                pool
                for pool in zaza_ceph.get_pools_from_broker_req(
                    self.application_name, model_name=self.model_name)
                if 'metadata' not in pool
            ]

        ceph_pools_detail = zaza_ceph.get_ceph_pool_details(
            model_name=self.model_name)

        logging.debug('BEFORE: {}'.format(ceph_pools_detail))
        try:
            logging.info('Checking Ceph pool compression_mode prior to change')
            self._assert_pools_properties(
                app_pools, ceph_pools_detail,
                {'options': {'compression_mode': 'none'}})
        except KeyError:
            logging.info('property does not exist on pool, which is OK.')
        logging.info('Changing "bluestore-compression-mode" to "force" on {}'
                     .format(self.application_name))
        with self.config_change(
                {'bluestore-compression-mode': 'none'},
                {'bluestore-compression-mode': 'force'}):
            # Retrieve pool details from Ceph after changing configuration
            ceph_pools_detail = zaza_ceph.get_ceph_pool_details(
                model_name=self.model_name)
            logging.debug('CONFIG_CHANGE: {}'.format(ceph_pools_detail))
            logging.info('Checking Ceph pool compression_mode after to change')
            self._assert_pools_properties(
                app_pools, ceph_pools_detail,
                {'options': {'compression_mode': 'force'}})
        ceph_pools_detail = zaza_ceph.get_ceph_pool_details(
            model_name=self.model_name)
        logging.debug('AFTER: {}'.format(ceph_pools_detail))
        logging.debug(juju_utils.get_relation_from_unit(
            'ceph-mon', self.application_name, None,
            model_name=self.model_name))
        logging.info('Checking Ceph pool compression_mode after restoring '
                     'config to previous value')
        self._assert_pools_properties(
            app_pools, ceph_pools_detail,
            {'options': {'compression_mode': 'none'}})
Esempio n. 5
0
    def _ceph_to_ceph_osd_relation(self, remote_unit_name):
        """Verify the cephX to ceph-osd relation data.

        Helper function to test the relation.
        """
        logging.info('Checking {}:ceph-osd mon relation data...'.
                     format(remote_unit_name))
        unit_name = 'ceph-osd/0'
        relation_name = 'osd'
        remote_unit = zaza_model.get_unit_from_name(remote_unit_name)
        remote_ip = remote_unit.public_address
        cmd = 'leader-get fsid'
        result = zaza_model.run_on_unit(remote_unit_name, cmd)
        fsid = result.get('Stdout').strip()
        expected = {
            'private-address': remote_ip,
            'ceph-public-address': remote_ip,
            'fsid': fsid,
        }
        relation = juju_utils.get_relation_from_unit(
            unit_name,
            remote_unit_name,
            relation_name
        )
        for e_key, e_value in expected.items():
            a_value = relation[e_key]
            self.assertEqual(e_value, a_value)
        self.assertTrue(relation['osd_bootstrap_key'] is not None)
Esempio n. 6
0
    def _wait_to_resolve_test_record(self):
        dns_ip = juju_utils.get_relation_from_unit(
            'designate/0', 'designate-bind/0',
            'dns-backend').get('private-address')

        logging.info('Waiting for dns record to propagate @ {}'.format(dns_ip))
        lookup_cmd = [
            'dig', '+short', '@{}'.format(dns_ip), self.TEST_WWW_RECORD
        ]
        cmd_out = subprocess.check_output(lookup_cmd,
                                          universal_newlines=True).rstrip()
        if not self.TEST_RECORD[self.TEST_WWW_RECORD] == cmd_out:
            raise Exception("Record Doesn't Exist")
Esempio n. 7
0
 def test_ceph_osd_ceph_relation_address(self):
     """Verify the ceph-osd to ceph relation data."""
     logging.info('Checking ceph-osd:ceph-mon relation data...')
     unit_name = 'ceph-osd/0'
     remote_unit_name = 'ceph-mon/0'
     relation_name = 'osd'
     remote_unit = zaza_model.get_unit_from_name(remote_unit_name)
     remote_ip = remote_unit.public_address
     relation = zaza_juju.get_relation_from_unit(unit_name,
                                                 remote_unit_name,
                                                 relation_name)
     # Get private-address in relation
     rel_private_ip = relation.get('private-address')
     # The private address in relation should match ceph-mon/0 address
     self.assertEqual(rel_private_ip, remote_ip)
Esempio n. 8
0
def setup_bgp_speaker(peer_application_name, keystone_session=None):
    """Perform BGP Speaker setup.

    :param peer_application_name: String name of BGP peer application
    :type peer_application_name: string
    :param keystone_session: Keystone session object for overcloud
    :type keystone_session: keystoneauth1.session.Session object
    :returns: None
    :rtype: None
    """
    # Get ASNs from deployment
    dr_relation = juju_utils.get_relation_from_unit(
        'neutron-dynamic-routing',
        peer_application_name,
        'bgpclient')
    peer_asn = dr_relation.get('asn')
    logging.debug('peer ASn: "{}"'.format(peer_asn))
    peer_relation = juju_utils.get_relation_from_unit(
        peer_application_name,
        'neutron-dynamic-routing',
        'bgp-speaker')
    dr_asn = peer_relation.get('asn')
    logging.debug('our ASn: "{}"'.format(dr_asn))

    # If a session has not been provided, acquire one
    if not keystone_session:
        keystone_session = openstack_utils.get_overcloud_keystone_session()

    # Get authenticated clients
    neutron_client = openstack_utils.get_neutron_session_client(
        keystone_session)

    # Create BGP speaker
    logging.info("Setting up BGP speaker")
    bgp_speaker = openstack_utils.create_bgp_speaker(
        neutron_client, local_as=dr_asn)

    # Add networks to bgp speaker
    logging.info("Advertising BGP routes")
    openstack_utils.add_network_to_bgp_speaker(
        neutron_client, bgp_speaker, EXT_NET)
    openstack_utils.add_network_to_bgp_speaker(
        neutron_client, bgp_speaker, PRIVATE_NET)
    logging.debug("Advertised routes: {}"
                  .format(
                      neutron_client.list_route_advertised_from_bgp_speaker(
                          bgp_speaker["id"])))

    # Create peer
    logging.info("Setting up BGP peer")
    bgp_peer = openstack_utils.create_bgp_peer(neutron_client,
                                               peer_application_name,
                                               remote_as=peer_asn)
    # Add peer to bgp speaker
    logging.info("Adding BGP peer to BGP speaker")
    openstack_utils.add_peer_to_bgp_speaker(
        neutron_client, bgp_speaker, bgp_peer)

    # Create Floating IP to advertise
    logging.info("Creating floating IP to advertise")
    port = openstack_utils.create_port(neutron_client, FIP_TEST, PRIVATE_NET)
    floating_ip = openstack_utils.create_floating_ip(neutron_client, EXT_NET,
                                                     port=port)
    logging.info(
        "Advertised floating IP: {}".format(
            floating_ip["floating_ip_address"]))

    # NOTE(fnordahl): As a workaround for LP: #1784083 remove BGP speaker from
    # dragent and add it back.
    logging.info(
        "Waiting for Neutron agent 'neutron-bgp-dragent' to appear...")
    keystone_session = openstack_utils.get_overcloud_keystone_session()
    neutron_client = openstack_utils.get_neutron_session_client(
        keystone_session)
    agents = openstack_utils.neutron_agent_appears(neutron_client,
                                                   'neutron-bgp-dragent')
    agent_id = None
    for agent in agents.get('agents', []):
        agent_id = agent.get('id', None)
        if agent_id is not None:
            break
    logging.info(
        'Waiting for BGP speaker to appear on agent "{}"...'.format(agent_id))
    bgp_speakers = openstack_utils.neutron_bgp_speaker_appears_on_agent(
        neutron_client, agent_id)
    logging.info(
        "Removing and adding back bgp-speakers to agent (LP: #1784083)...")
    while True:
        try:
            for bgp_speaker in bgp_speakers.get('bgp_speakers', []):
                bgp_speaker_id = bgp_speaker.get('id', None)
                logging.info('removing "{}" from "{}"'
                             ''.format(bgp_speaker_id, agent_id))
                neutron_client.remove_bgp_speaker_from_dragent(
                    agent_id, bgp_speaker_id)
        except neutronclient.common.exceptions.NotFound as e:
            logging.info('Exception: "{}"'.format(e))
            break
    neutron_client.add_bgp_speaker_to_dragent(
        agent_id, {'bgp_speaker_id': bgp_speaker_id})