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()
Esempio n. 2
0
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()
Esempio n. 3
0
    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)
Esempio n. 4
0
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)