-
Notifications
You must be signed in to change notification settings - Fork 1
/
kea-agent-daemon
executable file
·130 lines (102 loc) · 4.23 KB
/
kea-agent-daemon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/python3 -tt
# Twisted hosts our website and helps with async tasks.
# The application threads are structured in the following way:
#
# reactor
# `-- agent (1 thread)
# `-- workers (2 threads)
#
from twisted.internet import reactor
from twisted.web.wsgi import WSGIResource
from twisted.web.server import Site
from twisted.python.threadpool import ThreadPool
from twisted.python import log
# For database async notifications.
from txpostgres import txpostgres
# Data are accessed through SQLSoup, using SQLAlchemy.
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy import create_engine
# Command line arguments follow the GNU conventions.
from getopt import gnu_getopt
from sys import argv, stderr, exit
# Configuration is stored in a simple ini file.
from configparser import ConfigParser
# Import all the application handles.
from adminator import KeaAgent
from sqlmodel import Session
if __name__ == '__main__':
def do_start(config):
# Start Twisted logging to console.
log.startLogging(stderr)
# Read database configuration options.
db_url = config.get('database', 'url')
# Default to much saner database query defaults and always
# commit and/or flush statements explicitly.
factory = sessionmaker(autocommit=False, autoflush=False)
# Prepare database connection
engine = create_engine(db_url, echo=False)
# factory to create scoped_session of type Session (from sqlmodel, not sqlalchemy)
# to avoid multi-threading problems in new versions of things
def sqlmodel_factory():
return Session(engine, autoflush=False)
db = scoped_session(sqlmodel_factory)
# Extract agent options, sans the pool_size we handle here.
agent_opts = dict(config.items('kea'))
agent_pool = int(agent_opts.pop('pool_size', 2))
# Set the correct thread pool size for the agent.
reactor.suggestThreadPoolSize(agent_pool)
# Prepare the agent that runs in an exclusive thread.
agent = KeaAgent(db, **agent_opts)
# Prepare async notification listener.
txpg = txpostgres.Connection()
db = txpg.connect(db_url)
txpg.addNotifyObserver(agent.notify)
db.addCallback(lambda _: txpg.runOperation('listen dhcp'))
db.addCallback(lambda _: log.msg('Listening For dhcp Notifications'))
def error(failure, call):
log.err(failure, "DB connection error")
exit(1)
db.addErrback(error)
# Run the startup code as the first thing.
reactor.callLater(0, agent.start)
# Run the Twisted reactor until the user terminates us.
reactor.run()
def do_help(*args, **kwargs):
print('Usage: kea-agent-daemon [--config=/etc/adminator.ini]')
print('Runs the database->kea configuration agent.')
print('')
print('The agent listens to database notifications and constructs a')
print('configuration file on every change. It then instructs the')
print('kea service to pick up this configuration file.')
print('')
print('OPTIONS:')
print(' --help, -h Display this help.')
print(' --version, -V Display version info.')
print('')
print(' --config, -c file Load alternative configuration file.')
print('')
print('Report bugs at <http://github.com/techlib/adminator>.')
def do_version(*args, **kwargs):
print('kea-agent-daemon (NTK) 1')
# Parse command line arguments.
opts, args = gnu_getopt(argv, 'hVc:', ['help', 'version', 'config='])
action = do_start
config_path = '/etc/adminator.ini'
for k, v in opts:
if k in ('--help', '-h'):
action = do_help
elif k in ('--version', '-V'):
action = do_version
elif k in ('--config', '-c'):
config_path = v
# Load the configuration from file.
if action not in (do_help, do_version):
config = ConfigParser()
config.read(config_path)
# Load the configuration from file.
config = ConfigParser()
config.read(config_path)
# Perform the selected action.
action(config=config)
# vim:set sw=4 ts=4 et:
# -*- coding: utf-8 -*-