Skip to content

Commit

Permalink
[service_discovery] Add a Zookeeper service discovery implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
manolama committed Dec 13, 2016
1 parent d342110 commit db9d707
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 2 deletions.
6 changes: 4 additions & 2 deletions utils/service_discovery/config_stores.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

from utils.service_discovery.etcd_config_store import EtcdStore
from utils.service_discovery.consul_config_store import ConsulStore
from utils.service_discovery.zookeeper_config_store import ZookeeperStore


SD_CONFIG_BACKENDS = ['etcd', 'consul'] # noqa: used somewhere else
SD_CONFIG_BACKENDS = ['etcd', 'consul', 'zk'] # noqa: used somewhere else
SD_TEMPLATE_DIR = '/datadog/check_configs'


Expand All @@ -19,6 +19,8 @@ def get_config_store(agentConfig):
return EtcdStore(agentConfig)
elif agentConfig.get('sd_config_backend') == 'consul':
return ConsulStore(agentConfig)
elif agentConfig.get('sd_config_backend') == 'zk':
return ZookeeperStore(agentConfig)
else:
return StubStore(agentConfig)

Expand Down
99 changes: 99 additions & 0 deletions utils/service_discovery/zookeeper_config_store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# (C) Datadog, Inc. 2016
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)

# std
import logging

from kazoo.client import KazooClient, NoNodeError
from utils.service_discovery.abstract_config_store import AbstractConfigStore, KeyNotFound

DEFAULT_ZK_HOST = '127.0.0.1'
DEFAULT_ZK_PORT = 2181
DEFAULT_TIMEOUT = 5
log = logging.getLogger(__name__)

class ZookeeperStore(AbstractConfigStore):
"""Implementation of a config store client for Zookeeper"""

def _extract_settings(self, config):
"""Extract settings from a config object"""
settings = {
'host': config.get('sd_backend_host', DEFAULT_ZK_HOST),
'port': int(config.get('sd_backend_port', DEFAULT_ZK_PORT)),
}
return settings

def get_client(self, reset=False):
if self.client is None or reset is True:
self.client = KazooClient(
hosts=self.settings.get('host') + ":" + str(self.settings.get('port')),
read_only=True,
)
self.client.start()
return self.client

def client_read(self, path, **kwargs):
"""Retrieve a value from a Zookeeper key."""
try:
if kwargs.get('watch', False):
return self.recursive_mtime(path)
elif kwargs.get('all', False):
# we use it in _populate_identifier_to_checks
results = []
self.recursive_list(path, results)
return results
else:
res, stats = self.client.get(path)
return res.decode("utf-8")
except NoNodeError:
raise KeyNotFound("The key %s was not found in Zookeeper" % path)

def recursive_list(self, path, results):
"""Recursively walks the children from the given path and build a list of key/value tuples"""
try:
data, stat = self.client.get(path)

if data:
node_as_string = data.decode("utf-8")
if not node_as_string:
results.append((path.decode("utf-8"), node_as_string))

children = self.client.get_children(path)
if children is not None:
for child in children:
new_path = '/'.join([path.rstrip('/'), child])
self.recursive_list(new_path, results)
except NoNodeError:
raise KeyNotFound("The key %s was not found in Zookeeper" % path)

def recursive_mtime(self, path):
"""Recursively walks the children from the given path to find the maximum modification time"""
try:
data, stat = self.client.get(path)
children = self.client.get_children(path)
if children is not None and len(children) > 0:
for child in children:
new_path = '/'.join([path.rstrip('/'), child])
return max(stat.mtime, self.recursive_mtime(new_path))
else:
return stat.mtime
except NoNodeError:
raise KeyNotFound("The key %s was not found in Zookeeper" % path)

def dump_directory(self, path, **kwargs):
"""Return a dict made of all image names and their corresponding check info"""
templates = {}
paths = []
self.recursive_list(path, paths)

for pair in paths:
splits = pair[0].split('/')
image = splits[-2]
param = splits[-1]
value = pair[1]
if image not in templates:
templates[image] = {}
templates[image][param] = value

return templates

0 comments on commit db9d707

Please sign in to comment.