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)
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))
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' ]))
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'}})
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)
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")
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)
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})