Skip to content

Commit 86f30e2

Browse files
committed
First working version
This commit adds a simple Python script and a Dockerfile to create a minimal container image around it. The script expects to run as part of a Pod in Kubernetes with the stock CouchDB container. When it runs it will query DNS looking for the SRV record associated with a headless service called "couchdb". It will then iterate over the targets of that SRV record and create well-formed membership documents for each one in the local nodes DB. The end result should be that all the Pods backing a StatefulSet associated with the headless Service will be automatically joined up into a cluster on startup.
1 parent 5a7c7f1 commit 86f30e2

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM python:alpine
2+
3+
MAINTAINER Adam Kocoloski [email protected]
4+
5+
RUN pip install requests dnspython
6+
7+
COPY mem3_helper.py /opt/mem3_helper/
8+
9+
WORKDIR /opt/mem3_helper
10+
11+
CMD ["mem3_helper.py"]
12+
ENTRYPOINT ["python"]

mem3_helper.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# This file grabs the list of pod names behind the headless service
2+
# called "couchdb" and feeds those as `couchdb@HOSTNAME` nodes to mem3.
3+
4+
import json
5+
import os
6+
import requests
7+
import time
8+
import dns.resolver
9+
10+
def discover_peers_dns(retries=5):
11+
# Assumes svc.cluster.local is in the DNS search space ...
12+
resource = '_couchdb._tcp.{0}.{1}'.format(
13+
os.environ.get("COUCHDB_SERVICE", "couchdb"),
14+
os.environ.get("POD_NAMESPACE", "default")
15+
)
16+
if retries > 0:
17+
try:
18+
answers = dns.resolver.query(resource, 'SRV')
19+
except dns.resolver.NXDOMAIN:
20+
print('DNS query for SRV records failed with NXDOMAIN error')
21+
time.sleep(5)
22+
discover_peers_dns(retries - 1)
23+
# Erlang requires that we drop the trailing period from the absolute DNS
24+
# name to form the hostname used for the Erlang node. This feels hacky
25+
# but not sure of a more official answer
26+
hostnames = [rdata.target.to_text()[:-1] for rdata in answers]
27+
print(hostnames)
28+
connect_the_dots(hostnames)
29+
else:
30+
print('Could not resolve resource ', resource)
31+
32+
def connect_the_dots(names, retries=5):
33+
if retries > 0:
34+
for name in names:
35+
uri = "http://127.0.0.1:5986/_nodes/couchdb@{0}".format(name)
36+
doc = {}
37+
try:
38+
r = requests.put(uri, data = json.dumps(doc))
39+
print(name, r.status_code)
40+
except requests.exceptions.ConnectionError:
41+
print('CouchDB admin port not up yet')
42+
time.sleep(5)
43+
connect_the_dots(names, retries - 1)
44+
sleep_forever()
45+
else:
46+
print('Could not connect to local admin port to supply node names')
47+
48+
def sleep_forever():
49+
while True:
50+
time.sleep(5)
51+
52+
if __name__ == '__main__':
53+
print(os.environ)
54+
discover_peers_dns()

0 commit comments

Comments
 (0)