diff options
-rw-r--r-- | custodia/store/etcdstore.py | 94 | ||||
-rw-r--r-- | requirements.txt | 1 |
2 files changed, 95 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 diff --git a/requirements.txt b/requirements.txt index 3687329..3746d7c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ jwcrypto six +python-etcd |