diff options
author | Simo Sorce <simo@redhat.com> | 2015-09-25 04:26:45 +0200 |
---|---|---|
committer | Simo Sorce <simo@redhat.com> | 2015-10-19 12:17:48 -0400 |
commit | 0ca07419bbc2c4e499b4c37d2183d82b2640e816 (patch) | |
tree | c46bb64f554f7fc26dbcb2f21904a903f669676b /custodia | |
parent | 1d813cc53b9c03636967600f0e31e0cafb14813c (diff) | |
download | custodia-0ca07419bbc2c4e499b4c37d2183d82b2640e816.tar.gz custodia-0ca07419bbc2c4e499b4c37d2183d82b2640e816.tar.xz custodia-0ca07419bbc2c4e499b4c37d2183d82b2640e816.zip |
Implement ETCD based Store
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Christian Heimes <cheimes@redhat.com>
Diffstat (limited to 'custodia')
-rw-r--r-- | custodia/store/etcdstore.py | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/custodia/store/etcdstore.py b/custodia/store/etcdstore.py new file mode 100644 index 0000000..9a9e535 --- /dev/null +++ b/custodia/store/etcdstore.py @@ -0,0 +1,94 @@ +# Copyright (C) 2015 Custodia Project Contributors - see LICENSE file + +from __future__ import print_function + +import os +import sys + +import etcd + +from custodia.store.interface import CSStore, CSStoreError, CSStoreExists + + +def log_error(error): + print(error, file=sys.stderr) + + +class EtcdStore(CSStore): + + def __init__(self, config): + self.server = config.get('etcd_server', '127.0.0.1') + self.port = int(config.get('etcd_port', 4001)) + self.namespace = config.get('namespace', "/custodia") + + # Initialize the DB by trying to create the default table + try: + self.etcd = etcd.Client(self.server, self.port) + self.etcd.write(self.namespace, None, dir=True) + except etcd.EtcdNotFile: + # Already exists + pass + except etcd.EtcdException as err: + log_error("Error creating namespace %s: [%r]" % (self.namespace, + repr(err))) + raise CSStoreError('Error occurred while trying to init db') + + def get(self, key): + try: + result = self.etcd.get(os.path.join(self.namespace, key)) + except etcd.EtcdException as err: + log_error("Error fetching key %s: [%r]" % (key, repr(err))) + raise CSStoreError('Error occurred while trying to get key') + return result.value + + def set(self, key, value, replace=False): + path = os.path.join(self.namespace, key) + try: + self.etcd.write(path, value, prevExist=replace) + except etcd.EtcdAlreadyExist as err: + raise CSStoreExists(str(err)) + except etcd.EtcdException as err: + log_error("Error storing key %s: [%r]" % (key, repr(err))) + raise CSStoreError('Error occurred while trying to store key') + + def span(self, key): + path = os.path.join(self.namespace, key) + try: + self.etcd.write(path, None, dir=True, prevExist=False) + except etcd.EtcdAlreadyExist as err: + raise CSStoreExists(str(err)) + except etcd.EtcdException as err: + log_error("Error storing key %s: [%r]" % (key, repr(err))) + raise CSStoreError('Error occurred while trying to store key') + + def list(self, keyfilter='/'): + path = os.path.join(self.namespace, keyfilter) + if path != '/': + path = path.rstrip('/') + try: + result = self.etcd.read(path, recursive=True) + except etcd.EtcdKeyNotFound: + return None + except etcd.EtcdException as err: + log_error("Error listing %s: [%r]" % (keyfilter, repr(err))) + raise CSStoreError('Error occurred while trying to list keys') + + value = set() + for entry in result.get_subtree(): + if entry.key == path: + continue + name = entry.key[len(path):] + if entry.dir and not name.endswith('/'): + name += '/' + value.add(name.lstrip('/')) + return sorted(value) + + def cut(self, key): + try: + self.etcd.delete(os.path.join(self.namespace, key)) + except etcd.EtcdKeyNotFound: + return False + except etcd.EtcdException as err: + log_error("Error removing key %s: [%r]" % (key, repr(err))) + raise CSStoreError('Error occurred while trying to cut key') + return True |