1 |
douglas |
1411 |
#!/usr/bin/env python |
2 |
|
|
# DHCP Client Exit Hooks Installer |
3 |
|
|
# |
4 |
|
|
# Douglas Thrift |
5 |
|
|
# |
6 |
|
|
# $Id$ |
7 |
|
|
|
8 |
|
|
import optparse |
9 |
|
|
import os |
10 |
|
|
import re |
11 |
|
|
import sys |
12 |
|
|
import tempfile |
13 |
|
|
|
14 |
|
|
HOOKS = 'dhclient-exit-hooks' |
15 |
|
|
VARIABLES = { |
16 |
|
|
'tunnelbroker': { |
17 |
|
|
'pass': None, |
18 |
|
|
'user_id': None, |
19 |
|
|
'tunnel_id': None, |
20 |
|
|
}, |
21 |
|
|
'dns': { |
22 |
|
|
'key': None, |
23 |
|
|
'secret': None, |
24 |
|
|
}, |
25 |
|
|
} |
26 |
|
|
|
27 |
|
|
def parse(hooks, callback): |
28 |
|
|
functions = re.compile(r'^(%s)\(\)$' % '|'.join(VARIABLES.iterkeys())) |
29 |
|
|
function = None |
30 |
|
|
|
31 |
|
|
with open(hooks, 'rb') as hooks: |
32 |
|
|
for line in hooks: |
33 |
|
|
if line == '}\n': |
34 |
|
|
function = None |
35 |
|
|
else: |
36 |
|
|
match = functions.match(line) |
37 |
|
|
|
38 |
|
|
if match is not None: |
39 |
|
|
function = match.group(1) |
40 |
|
|
|
41 |
|
|
callback(line, function, VARIABLES.get(function)) |
42 |
|
|
|
43 |
|
|
if __name__ == '__main__': |
44 |
|
|
import readline |
45 |
|
|
|
46 |
|
|
parser = optparse.OptionParser(usage = '%prog [options] [DIRECTORY]') |
47 |
|
|
|
48 |
|
|
def variables(option, opt, value, parser, *args, **kwargs): |
49 |
|
|
variables = VARIABLES.get(value[0]) |
50 |
|
|
|
51 |
|
|
if variables is None: |
52 |
|
|
raise optparse.OptionValueError, '%s unknown function "%s"' % (opt, value[0]) |
53 |
|
|
|
54 |
|
|
if value[1] not in variables: |
55 |
|
|
raise optparse.OptionValueError, '%s unknown variable "%s"' % (opt, value[1]) |
56 |
|
|
|
57 |
|
|
parser.values.ensure_value(option.dest, set()).add(value) |
58 |
|
|
|
59 |
|
|
parser.add_option('-f', '--force', action = 'callback', type = 'string', dest = 'force', default = set(), nargs = 2, callback = variables, metavar = 'FUNCTION VARIABLE') |
60 |
|
|
|
61 |
|
|
options, args = parser.parse_args() |
62 |
|
|
|
63 |
|
|
if len(args) != 1: |
64 |
|
|
parser.error('no directory specified') |
65 |
|
|
|
66 |
|
|
os.umask(077) |
67 |
|
|
|
68 |
|
|
hooks = os.path.join(args[0], HOOKS) |
69 |
|
|
|
70 |
|
|
if os.path.exists(hooks): |
71 |
|
|
def read(line, function, variables): |
72 |
|
|
if function is not None: |
73 |
|
|
match = re.match(r"^\tlocal (%s)='(.*)'$" % '|'.join(variables.iterkeys()), line) |
74 |
|
|
|
75 |
|
|
if match is not None: |
76 |
|
|
variable, value = match.group(1, 2) |
77 |
|
|
|
78 |
|
|
if (function, variable) not in options.force: |
79 |
|
|
variables[variable] = value |
80 |
|
|
|
81 |
|
|
parse(hooks, read) |
82 |
|
|
|
83 |
|
|
with tempfile.NamedTemporaryFile('wb', prefix = HOOKS + '.', dir = args[0]) as temp: |
84 |
|
|
def write(line, function, variables): |
85 |
|
|
if function is not None: |
86 |
|
|
match = re.match(r'''^\t(?:read -p '{0} ({1}): ' -r \1|local ({1})=`python -c "(import .+); print (.*'{0} \2: '.*)"`)$'''.format(function, '|'.join(variables.iterkeys())), line) |
87 |
|
|
|
88 |
|
|
if match is not None: |
89 |
|
|
variable = match.group(1) |
90 |
|
|
|
91 |
|
|
if variable is None: |
92 |
|
|
variable, imports, python = match.group(2, 3, 4) |
93 |
|
|
else: |
94 |
|
|
imports, python = None, None |
95 |
|
|
|
96 |
|
|
value = variables[variable] |
97 |
|
|
|
98 |
|
|
if value is None: |
99 |
|
|
if python is not None: |
100 |
|
|
exec imports |
101 |
|
|
|
102 |
|
|
value = eval(python) |
103 |
|
|
else: |
104 |
|
|
value = raw_input('%s %s: ' % (function, variable)) |
105 |
|
|
|
106 |
|
|
line = "\tlocal %s='%s'\n" % (variable, value) |
107 |
|
|
|
108 |
|
|
temp.write(line) |
109 |
|
|
|
110 |
|
|
parse(HOOKS, write) |
111 |
|
|
|
112 |
|
|
temp.delete = False |
113 |
|
|
|
114 |
|
|
os.rename(temp.name, hooks) |