def remember_devices(devs): """Add device to local store of ringed devices.""" d = os.path.dirname(KV_DB_PATH) if not os.path.isdir(d): mkdir(d) kvstore = KVStore(KV_DB_PATH) devstore = devstore_safe_load(kvstore.get(key='devices')) or {} env_uuid = os.environ['JUJU_ENV_UUID'] for dev in devs: blk_uuid = get_device_blkid("/dev/%s" % (dev)) key = "%s@%s" % (dev, env_uuid) if key in devstore and devstore[key].get('blkid') == blk_uuid: log("Device '%s' already in devstore (status:%s)" % (dev, devstore[key].get('status')), level=DEBUG) else: existing = [(k, v) for k, v in devstore.iteritems() if v.get('blkid') == blk_uuid and re.match("^(.+)@(.+)$", k).group(1) == dev] if existing: log("Device '%s' already in devstore but has a different " "JUJU_ENV_UUID (%s)" % (dev, re.match(".+@(.+)$", existing[0][0]).group(1)), level=WARNING) else: log("Adding device '%s' with blkid='%s' to devstore" % (blk_uuid, dev), level=DEBUG) devstore[key] = {'blkid': blk_uuid, 'status': 'active'} if devstore: kvstore.set(key='devices', value=json.dumps(devstore)) kvstore.flush() kvstore.close()
def remember_devices(devs): """Add device to local store of ringed devices.""" d = os.path.dirname(KV_DB_PATH) if not os.path.isdir(d): mkdir(d) kvstore = KVStore(KV_DB_PATH) devstore = devstore_safe_load(kvstore.get(key='devices')) or {} env_uuid = os.environ.get('JUJU_ENV_UUID', os.environ.get('JUJU_MODEL_UUID')) for dev in devs: blk_uuid = get_device_blkid("/dev/%s" % (dev)) key = "%s@%s" % (dev, env_uuid) if key in devstore and devstore[key].get('blkid') == blk_uuid: log("Device '%s' already in devstore (status:%s)" % (dev, devstore[key].get('status')), level=DEBUG) else: existing = [(k, v) for k, v in devstore.iteritems() if v.get('blkid') == blk_uuid and re.match("^(.+)@(.+)$", k).group(1) == dev] if existing: log("Device '%s' already in devstore but has a different " "JUJU_[ENV|MODEL]_UUID (%s)" % (dev, re.match(".+@(.+)$", existing[0][0]).group(1)), level=WARNING) else: log("Adding device '%s' with blkid='%s' to devstore" % (dev, blk_uuid), level=DEBUG) devstore[key] = {'blkid': blk_uuid, 'status': 'active'} if devstore: kvstore.set(key='devices', value=json.dumps(devstore)) kvstore.flush() kvstore.close()
def test_configure_amqp(self, mock_grant_permissions, mock_create_vhost, mock_create_user, mock_get_rabbit_password, mock_set_ha_mode, mock_is_leader): mock_is_leader.return_value = True tmpdir = tempfile.mkdtemp() try: db_path = '{}/kv.db'.format(tmpdir) rid = 'amqp:1' store = Storage(db_path) with patch('charmhelpers.core.unitdata._KV', store): # Check .set with patch.object(store, 'set') as mock_set: rabbitmq_server_relations.configure_amqp( 'user_foo', 'vhost_blah', rid) d = { rid: { "username": "******", "vhost": "vhost_blah", "mirroring-queues": True } } mock_set.assert_has_calls( [call(key='amqp_config_tracker', value=d)]) for m in [ mock_grant_permissions, mock_create_vhost, mock_create_user, mock_set_ha_mode ]: self.assertTrue(m.called) m.reset_mock() # Check .get with patch.object(store, 'get') as mock_get: mock_get.return_value = d rabbitmq_server_relations.configure_amqp( 'user_foo', 'vhost_blah', rid) mock_set.assert_has_calls( [call(key='amqp_config_tracker', value=d)]) for m in [ mock_grant_permissions, mock_create_vhost, mock_create_user, mock_set_ha_mode ]: self.assertFalse(m.called) # Check invalid relation id self.assertRaises(Exception, rabbitmq_server_relations.configure_amqp, 'user_foo', 'vhost_blah', None, admin=True) # Test writing data d = {} for rid, user in [('amqp:1', 'userA'), ('amqp:2', 'userB')]: rabbitmq_server_relations.configure_amqp( user, 'vhost_blah', rid) d.update({ rid: { "username": user, "vhost": "vhost_blah", "mirroring-queues": True } }) self.assertEqual(store.get('amqp_config_tracker'), d) @rabbitmq_server_relations.validate_amqp_config_tracker def fake_configure_amqp(*args, **kwargs): return rabbitmq_server_relations.configure_amqp( *args, **kwargs) # Test invalidating data mock_is_leader.return_value = False d['amqp:2']['stale'] = True for rid, user in [('amqp:1', 'userA'), ('amqp:3', 'userC')]: fake_configure_amqp(user, 'vhost_blah', rid) d[rid] = { "username": user, "vhost": "vhost_blah", "mirroring-queues": True, 'stale': True } # Since this is a dummy case we need to toggle the stale # values. del d[rid]['stale'] self.assertEqual(store.get('amqp_config_tracker'), d) d[rid]['stale'] = True finally: if os.path.exists(tmpdir): shutil.rmtree(tmpdir)
def is_device_in_ring(dev, skip_rel_check=False, ignore_deactivated=True): """Check if device has been added to the ring. First check local KV store then check storage rel with proxy. """ d = os.path.dirname(KV_DB_PATH) if not os.path.isdir(d): mkdir(d) log("Device '%s' does not appear to be in use by Swift" % (dev), level=INFO) return False # First check local KV store kvstore = KVStore(KV_DB_PATH) devstore = devstore_safe_load(kvstore.get(key='devices')) kvstore.close() deactivated = [] if devstore: blk_uuid = get_device_blkid("/dev/%s" % (dev)) env_uuid = os.environ.get('JUJU_ENV_UUID', os.environ.get('JUJU_MODEL_UUID')) masterkey = "%s@%s" % (dev, env_uuid) if (masterkey in devstore and devstore[masterkey].get('blkid') == blk_uuid and devstore[masterkey].get('status') == 'active'): log("Device '%s' appears to be in use by Swift (found in local " "devstore)" % (dev), level=INFO) return True for key, val in devstore.iteritems(): if key != masterkey and val.get('blkid') == blk_uuid: log("Device '%s' appears to be in use by Swift (found in " "local devstore) but has a different " "JUJU_[ENV|MODEL]_UUID (current=%s, expected=%s). " "This could indicate that the device was added as part of " "a previous deployment and will require manual removal or " "updating if it needs to be reformatted." % (dev, key, masterkey), level=INFO) return True if ignore_deactivated: deactivated = [ k == masterkey and v.get('blkid') == blk_uuid and v.get('status') != 'active' for k, v in devstore.iteritems() ] if skip_rel_check: log("Device '%s' does not appear to be in use by swift (searched " "local devstore only)" % (dev), level=INFO) return False # Then check swift-storage relation with proxy for rid in relation_ids('swift-storage'): devstore = relation_get(attribute='device', rid=rid, unit=local_unit()) if devstore and dev in devstore.split(':'): if not ignore_deactivated or dev not in deactivated: log("Device '%s' appears to be in use by swift (found on " "proxy relation) but was not found in local devstore so " "will be added to the cache" % (dev), level=INFO) remember_devices([dev]) return True log("Device '%s' does not appear to be in use by swift (searched local " "devstore and proxy relation)" % (dev), level=INFO) return False
def test_configure_amqp(self, mock_config, mock_grant_permissions, mock_create_vhost, mock_create_user, mock_get_rabbit_password, mock_set_ha_mode, mock_is_leader, mock_configure_notification_ttl, mock_configure_ttl): config_data = { 'notification-ttl': 450000, 'mirroring-queues': True, } mock_is_leader.return_value = True mock_config.side_effect = lambda attribute: config_data.get(attribute) tmpdir = tempfile.mkdtemp() try: db_path = '{}/kv.db'.format(tmpdir) rid = 'amqp:1' store = Storage(db_path) with patch('charmhelpers.core.unitdata._KV', store): # Check .set with patch.object(store, 'set') as mock_set: rabbitmq_server_relations.configure_amqp('user_foo', 'vhost_blah', rid) d = {rid: {"username": "******", "vhost": "vhost_blah", "ttl": None, "mirroring-queues": True}} mock_set.assert_has_calls([call(key='amqp_config_tracker', value=d)]) for m in [mock_grant_permissions, mock_create_vhost, mock_create_user, mock_set_ha_mode]: self.assertTrue(m.called) m.reset_mock() # Check .get with patch.object(store, 'get') as mock_get: mock_get.return_value = d rabbitmq_server_relations.configure_amqp('user_foo', 'vhost_blah', rid) mock_set.assert_has_calls([call(key='amqp_config_tracker', value=d)]) for m in [mock_grant_permissions, mock_create_vhost, mock_create_user, mock_set_ha_mode]: self.assertFalse(m.called) # Check invalid relation id self.assertRaises(Exception, rabbitmq_server_relations.configure_amqp, 'user_foo', 'vhost_blah', None, admin=True) # Test writing data d = {} for rid, user in [('amqp:1', 'userA'), ('amqp:2', 'userB')]: rabbitmq_server_relations.configure_amqp(user, 'vhost_blah', rid) d.update({rid: {"username": user, "vhost": "vhost_blah", "ttl": None, "mirroring-queues": True}}) self.assertEqual(store.get('amqp_config_tracker'), d) @rabbitmq_server_relations.validate_amqp_config_tracker def fake_configure_amqp(*args, **kwargs): return rabbitmq_server_relations.configure_amqp(*args, **kwargs) # Test invalidating data mock_is_leader.return_value = False d['amqp:2']['stale'] = True for rid, user in [('amqp:1', 'userA'), ('amqp:3', 'userC')]: fake_configure_amqp(user, 'vhost_blah', rid) d[rid] = {"username": user, "vhost": "vhost_blah", "ttl": None, "mirroring-queues": True, 'stale': True} # Since this is a dummy case we need to toggle the stale # values. del d[rid]['stale'] self.assertEqual(store.get('amqp_config_tracker'), d) d[rid]['stale'] = True mock_configure_notification_ttl.assert_not_called() mock_configure_ttl.assert_not_called() # Test openstack notification workaround d = {} for rid, user in [('amqp:1', 'userA')]: rabbitmq_server_relations.configure_amqp( user, 'openstack', rid, admin=False, ttlname='heat_expiry', ttlreg='heat-engine-listener|engine_worker', ttl=45000) (mock_configure_notification_ttl. assert_called_once_with('openstack', 450000)) (mock_configure_ttl. assert_called_once_with( 'openstack', 'heat_expiry', 'heat-engine-listener|engine_worker', 45000)) finally: if os.path.exists(tmpdir): shutil.rmtree(tmpdir)
def is_device_in_ring(dev, skip_rel_check=False, ignore_deactivated=True): """Check if device has been added to the ring. First check local KV store then check storage rel with proxy. """ d = os.path.dirname(KV_DB_PATH) if not os.path.isdir(d): mkdir(d) log("Device '%s' does not appear to be in use by Swift" % (dev), level=INFO) return False # First check local KV store kvstore = KVStore(KV_DB_PATH) devstore = devstore_safe_load(kvstore.get(key='devices')) kvstore.close() deactivated = [] if devstore: blk_uuid = get_device_blkid("/dev/%s" % (dev)) env_uuid = os.environ['JUJU_ENV_UUID'] masterkey = "%s@%s" % (dev, env_uuid) if (masterkey in devstore and devstore[masterkey].get('blkid') == blk_uuid and devstore[masterkey].get('status') == 'active'): log("Device '%s' appears to be in use by Swift (found in local " "devstore)" % (dev), level=INFO) return True for key, val in devstore.iteritems(): if key != masterkey and val.get('blkid') == blk_uuid: log("Device '%s' appears to be in use by Swift (found in " "local devstore) but has a different JUJU_ENV_UUID " "(current=%s, expected=%s). " "This could indicate that the device was added as part of " "a previous deployment and will require manual removal or " "updating if it needs to be reformatted." % (dev, key, masterkey), level=INFO) return True if ignore_deactivated: deactivated = [k == masterkey and v.get('blkid') == blk_uuid and v.get('status') != 'active' for k, v in devstore.iteritems()] if skip_rel_check: log("Device '%s' does not appear to be in use by swift (searched " "local devstore only)" % (dev), level=INFO) return False # Then check swift-storage relation with proxy for rid in relation_ids('swift-storage'): devstore = relation_get(attribute='device', rid=rid, unit=local_unit()) if devstore and dev in devstore.split(':'): if not ignore_deactivated or dev not in deactivated: log("Device '%s' appears to be in use by swift (found on " "proxy relation) but was not found in local devstore so " "will be added to the cache" % (dev), level=INFO) remember_devices([dev]) return True log("Device '%s' does not appear to be in use by swift (searched local " "devstore and proxy relation)" % (dev), level=INFO) return False
def test_configure_amqp(self, mock_config, mock_grant_permissions, mock_create_vhost, mock_create_user, mock_get_rabbit_password, mock_set_ha_mode, mock_is_leader, mock_configure_notification_ttl): config_data = { 'notification-ttl': 450000, 'mirroring-queues': True, } mock_is_leader.return_value = True mock_config.side_effect = lambda attribute: config_data.get(attribute) tmpdir = tempfile.mkdtemp() try: db_path = '{}/kv.db'.format(tmpdir) rid = 'amqp:1' store = Storage(db_path) with patch('charmhelpers.core.unitdata._KV', store): # Check .set with patch.object(store, 'set') as mock_set: rabbitmq_server_relations.configure_amqp('user_foo', 'vhost_blah', rid) d = {rid: {"username": "******", "vhost": "vhost_blah", "mirroring-queues": True}} mock_set.assert_has_calls([call(key='amqp_config_tracker', value=d)]) for m in [mock_grant_permissions, mock_create_vhost, mock_create_user, mock_set_ha_mode]: self.assertTrue(m.called) m.reset_mock() # Check .get with patch.object(store, 'get') as mock_get: mock_get.return_value = d rabbitmq_server_relations.configure_amqp('user_foo', 'vhost_blah', rid) mock_set.assert_has_calls([call(key='amqp_config_tracker', value=d)]) for m in [mock_grant_permissions, mock_create_vhost, mock_create_user, mock_set_ha_mode]: self.assertFalse(m.called) # Check invalid relation id self.assertRaises(Exception, rabbitmq_server_relations.configure_amqp, 'user_foo', 'vhost_blah', None, admin=True) # Test writing data d = {} for rid, user in [('amqp:1', 'userA'), ('amqp:2', 'userB')]: rabbitmq_server_relations.configure_amqp(user, 'vhost_blah', rid) d.update({rid: {"username": user, "vhost": "vhost_blah", "mirroring-queues": True}}) self.assertEqual(store.get('amqp_config_tracker'), d) @rabbitmq_server_relations.validate_amqp_config_tracker def fake_configure_amqp(*args, **kwargs): return rabbitmq_server_relations.configure_amqp(*args, **kwargs) # Test invalidating data mock_is_leader.return_value = False d['amqp:2']['stale'] = True for rid, user in [('amqp:1', 'userA'), ('amqp:3', 'userC')]: fake_configure_amqp(user, 'vhost_blah', rid) d[rid] = {"username": user, "vhost": "vhost_blah", "mirroring-queues": True, 'stale': True} # Since this is a dummy case we need to toggle the stale # values. del d[rid]['stale'] self.assertEqual(store.get('amqp_config_tracker'), d) d[rid]['stale'] = True mock_configure_notification_ttl.assert_not_called() # Test openstack notification workaround d = {} for rid, user in [('amqp:1', 'userA')]: rabbitmq_server_relations.configure_amqp(user, 'openstack', rid) (mock_configure_notification_ttl. assert_called_once_with('openstack', 450000)) finally: if os.path.exists(tmpdir): shutil.rmtree(tmpdir)