Skip to content

Commit

Permalink
mongod flags for replica set, more python scaffolding from mysql
Browse files Browse the repository at this point in the history
  • Loading branch information
yosifkit committed May 28, 2016
1 parent 3ec7d2e commit 48e94cc
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 5 deletions.
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ ENTRYPOINT []

CMD [ \
"containerpilot", \
"mongod" \
"mongod", \
"--replSet=joyent" \
]

153 changes: 150 additions & 3 deletions bin/manage.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import logging
import os
import sys
import inspect
import json
import logging
import socket

from functools import wraps

import consul as pyconsul
import manta
#import manta
from pymongo import MongoClient

consul = pyconsul.Consul(host=os.environ.get('CONSUL', 'consul'))
local_mongo = MongoClient()

log = logging.getLogger('manage.py')

# consts for node state
PRIMARY = 'mongodb-primary'
SECONDARY = 'mongodb-secondary'

This comment has been minimized.

Copy link
@leoj3n

leoj3n Apr 25, 2019

@yosifkit What is the idea behind the "secondary" mongodb replicaset? Does this imply there could be a second replicaset, also managed by this script? Or does this refer to something else?

This comment has been minimized.

Copy link
@tianon

tianon Apr 25, 2019

Contributor

A MongoDB replica set has two types of nodes:

  • PRIMARY (there's only one of these, and only after a proper election between all the nodes)
  • SECONDARY (all other nodes, and all nodes during an election)

If you want to write to the database, you have to do so on the PRIMARY.

This comment has been minimized.

Copy link
@leoj3n

leoj3n Apr 26, 2019

@tianon Thanks, I get the original intention of these "consts" now. I was confused because they seem to have been repurposed in more recent code, and now the const PRIMARY is used for a different purpose (specifically, to identify the consul service and mongo hostname) as seen here, here, here, and here. Perhaps a better name for this constant in the more recent code would be SERVICE_NAME, which would be less confusing than PRIMARY, and more in-line with SESSION_NAME.

REPLICA = 'mongodb'

def debug(fn):
"""
Function/method decorator to trace calls via debug logging.
Expand Down Expand Up @@ -46,9 +57,145 @@ def get_environ(key, default):

# ---------------------------------------------------------

class MongoDBNode(object):
""" MongoDBNode represents this instance of a MongoDB container. """

def __init__(self, name='', ip=''):
self.hostname = socket.gethostname()
self.name = name if name else get_name()
self.ip = ip if ip else get_ip()
self.state = PRIMARY
self.conn = None

def get_state(self):
# TODO check mongo if I am primary
return self.state

# ---------------------------------------------------------

class ContainerPilot(object):
"""
ContainerPilot config is where we rewrite ContainerPilot's own config
so that we can dynamically alter what service we advertise
"""

def __init__(self, node):
# TODO: we should make sure we can support JSON-in-env-var
# the same as ContainerPilot itself
self.node = node
self.path = get_environ('CONTAINERPILOT', None).replace('file://', '')
with open(self.path, 'r') as f:
self.config = json.loads(f.read())

@debug
def update(self):
state = self.node.get_state()
if state and self.config['services'][0]['name'] != state:
self.config['services'][0]['name'] = state
self.render()
return True

@debug
def render(self):
new_config = json.dumps(self.config)
with open(self.path, 'w') as f:
f.write(new_config)

def reload(self):
""" force ContainerPilot to reload its configuration """
log.info('Reloading ContainerPilot configuration.')
os.kill(1, signal.SIGHUP)

# ---------------------------------------------------------
# Top-level functions called by ContainerPilot or forked by this program

@debug
def pre_start():
"""
MongoDB must be running in order to execute most of our setup behavior
so we're just going to make sure the directory structures are in
place and then let the first health check handler take it from there
"""
#if not os.path.isdir(os.path.join('/data')):
# last_backup = has_snapshot()
# if last_backup:
# get_snapshot(last_backup)
# restore_from_snapshot(last_backup)
# else:
# if not initialize_db():
# log.info('Skipping database setup.')
sys.exit(0)

@debug
def health():
"""
Run a simple health check. Also acts as a check for whether the
ContainerPilot configuration needs to be reloaded (if it's been
changed externally).
"""

# TODO
# - check for primary or replset in consul
# - no others, try setting self as primary and rs.init()
# - otherwise join the replset
# - just leave it alone if I am already in rs.status()
# - if I am primary in rs.status(), tell consul
# - periodic mongodumps to Manta

try:
node = MongoDBNode()
cp = ContainerPilot(node)
if cp.update():
cp.reload()
return

except Exception as ex:
log.exception(ex)
sys.exit(1)

@debug
def on_change():
# TODO when is this called?
time.sleep(1) # avoid hammering Consul

# ---------------------------------------------------------



def get_from_consul(key):
"""
Return the Value field for a given Consul key.
Handles None results safely but lets all other exceptions
just bubble up.
"""
result = consul.kv.get(key)
if result[1]:
return result[1]['Value']
return None

# ---------------------------------------------------------
# utility functions

def get_ip(iface='eth0'):
"""
Use Linux SIOCGIFADDR ioctl to get the IP for the interface.
ref http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/
"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return socket.inet_ntoa(fcntl.ioctl(
sock.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', iface[:15])
)[20:24])

def get_name():
return 'mysql-{}'.format(socket.gethostname())

# ---------------------------------------------------------

if __name__ == '__main__':

manta_config = Manta()
# manta_config = Manta()

if len(sys.argv) > 1:
try:
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mongodb:

consul:
image: consul:v0.6.4
# command: -bootstrap -ui-dir /ui
command: agent -dev -ui -client=0.0.0.0
restart: always
mem_limit: 128m
ports:
Expand Down

0 comments on commit 48e94cc

Please sign in to comment.