blob: 21ef5ec98e28940a017612573ece6771f938426e [file] [log] [blame]
# Copyright 2017 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from consul import Consul
class ConsulStore(object):
""" Config kv store for consul with a cache for quicker subsequent reads
TODO: This will block the reactor. Should either change
whole call stack to yield or put the put/delete transactions into a
queue to write later with twisted. Will need a transaction
log to ensure we don't lose anything.
Making the whole callstack yield is troublesome because other tasks can
come in on the side and start modifying things which could be bad.
"""
def __init__(self, host, port, path_prefix):
self._consul = Consul(host=host, port=port)
self._path_prefix = path_prefix
self._cache = {}
def make_path(self, key):
return '{}/{}'.format(self._path_prefix, key)
def __getitem__(self, key):
if key in self._cache:
return self._cache[key]
index, value = self._consul.kv.get(self.make_path(key))
if value is not None:
# consul turns empty strings to None, so we do the reverse here
self._cache[key] = value['Value'] or ''
return value['Value'] or ''
else:
raise KeyError(key)
def __contains__(self, key):
if key in self._cache:
return True
index, value = self._consul.kv.get(self.make_path(key))
if value is not None:
self._cache[key] = value['Value']
return True
else:
return False
def __setitem__(self, key, value):
assert isinstance(value, basestring)
self._cache[key] = value
self._consul.kv.put(self.make_path(key), value)
def __delitem__(self, key):
self._cache.pop(key, None)
self._consul.kv.delete(self.make_path(key))
def load_backend(args):
""" Return the kv store backend based on the command line arguments
"""
# TODO: Make this more dynamic
def load_consul_store():
host, port = args.consul.split(':', 1)
return ConsulStore(host, int(port), 'service/voltha/config_data')
loaders = {
'none': lambda: None,
'consul': load_consul_store
}
return loaders[args.backend]()