3 """ Representation for connd state as returned by tell-connd --status
5 Christian Herdtweck, Intra2net, January 2015
10 # 16/01/15 Christian Herdtweck: started creation
13 from re import match as regexp
17 default_tell_connd_binary = '/usr/intranator/bin/tell-connd'
20 ONLINE_STATE_ALWAYS_ONLINE = 'always online'
21 ONLINE_STATE_ALWAYS_OFFLINE = 'always offline'
22 ONLINE_STATE_DIAL_ON_COMMAND = 'dial on command'
23 ONLINE_STATE_DIAL_ON_DEMAND = 'dial on demand'
26 SUBSYS_DYNDNS = 'dyndns'
29 SUBSYS_SOCKS = 'socks'
31 SUBSYS_WEBPROXY = 'webproxy'
32 SUBSYS_PINGCHECK = 'pingcheck'
33 ALL_SUBSYS = (SUBSYS_DNS, SUBSYS_DYNDNS, SUBSYS_MAIL, SUBSYS_NTP, \
34 SUBSYS_SOCKS, SUBSYS_VPN, SUBSYS_WEBPROXY, SUBSYS_PINGCHECK)
37 """ representation of connd's status as returned by tell-connd --status """
40 default_provider = None
43 subsys_disabled = None
50 return '[ConndState: {0} (default {1}), {2} conn\'s, {3} ips, {4} vpns ]'.format(\
51 self.online_mode, self.default_provider, len(self.connections), \
52 len(self.online_ips), len(self.connected_vpns))
54 def complete_str(self):
56 parts = ['ConndState: online mode = "{0}" (default provider: {1})\n'.format(\
57 self.online_mode, self.default_provider), ]
61 parts.append(' subsys: online: ')
62 if self.subsys_online:
63 for subsys in self.subsys_online:
64 parts.append(subsys + ' ')
67 parts.append('; offline: ')
68 if self.subsys_offline:
69 for subsys in self.subsys_offline:
70 parts.append(subsys + ' ')
73 parts.append('; disabled: ')
74 if self.subsys_disabled:
75 for subsys in self.subsys_disabled:
76 parts.append(subsys + ' ')
82 parts.append(' conns: ')
84 name, info, actions = self.connections[0]
85 parts.append('{0}: {1}, {2}\n'.format(name, info, actions))
87 parts.append('None\n')
88 for name, info, actions in self.connections[1:]:
90 parts.append(' {0}: {1}, {2}\n'.format(name, info, actions))
94 parts.append(' actions: ')
96 parts.append(self.actions[0] + '\n')
98 parts.append('None\n')
99 for action in self.actions[1:]:
101 parts.append(' {0}\n'.format(action))
105 parts.append(' IPs: ')
107 parts.append(self.online_ips[0])
108 for ip in self.online_ips[1:]:
109 parts.append(', {0}'.format(ip))
116 parts.append(' VPNs: ')
117 if self.connected_vpns:
118 parts.append(self.connected_vpns[0])
119 for vpn in self.connected_vpns[1:]:
120 parts.append(', {0}'.format(vpn))
126 return ''.join(parts)
127 #end: ConndState.complete_str
131 def run_tell_connd(tell_connd_binary=default_tell_connd_binary):
132 """ run tell-connd --status, return output iterator and return code
134 catches all it can, so should usually return (output, return_code)
135 where output = [line1, line2, ...]
136 if return_code != 0, output's first line(s) is error message
139 output = subprocess.check_output([tell_connd_binary, '--status'], \
140 stderr=subprocess.STDOUT, universal_newlines=True, shell=False, timeout=timeout)
141 return EX_OK, output.splitlines()
142 except subprocess.CalledProcessError as cpe: # non-zero return status
143 output = ['tell-connd exited with status {0}'.format(cpe.returncode), ]
144 output.extend( cpe.output.splitlines() )
145 return cpe.returncode, output
146 except subprocess.TimeoutExpired as te:
147 output = ['tell-connd timed out after {0}s. Returning -1'.format(te.timeout), ]
148 output.extend( te.output.splitlines() )
150 except Exception as e:
153 #end: ConndState.run_tell_connd
157 def get_state(tell_connd_binary=default_tell_connd_binary):
158 """ get actual state from tell-connd --status
160 returns (err_code, output_lines) if something goes wrong running binary;
161 raises assertion if output from tell-connd does not match expected format
166 err_code, all_lines = ConndState.run_tell_connd(tell_connd_binary)
167 if err_code != EX_OK:
168 return err_code, all_lines
170 output = iter(all_lines)
173 line = next(output).strip()
174 state.online_mode = regexp('online mode\s*:\s*(.+)$', line).groups()[0]
175 assert( state.online_mode in (ONLINE_STATE_DIAL_ON_DEMAND, ONLINE_STATE_DIAL_ON_COMMAND, \
176 ONLINE_STATE_ALWAYS_OFFLINE, ONLINE_STATE_ALWAYS_ONLINE) )
177 line = next(output).strip()
178 state.default_provider = regexp('default provider\s*:\s*(.*)$', \
180 if len(state.default_provider) == 0:
181 state.default_provider = None
182 line = next(output).strip()
183 assert( len(line) == 0 )
186 line = next(output).strip()
187 assert( line == 'subsys' )
188 line = next(output).strip()
189 state.subsys_online = regexp( 'online\s*:\s*(.*)$', line).groups()[0].split()
190 for subsys in state.subsys_online:
191 assert(subsys in ALL_SUBSYS)
192 line = next(output).strip()
193 state.subsys_offline = regexp( 'offline\s*:\s*(.*)$', line).groups()[0].split()
194 for subsys in state.subsys_offline:
195 assert(subsys in ALL_SUBSYS)
196 line = next(output).strip()
197 state.subsys_disabled = regexp('disabled\s*:\s*(.*)$', line).groups()[0].split()
198 for subsys in state.subsys_disabled:
199 assert(subsys in ALL_SUBSYS)
200 line = next(output).strip()
201 assert( len(line) == 0 )
204 state.connections = []
205 line = next(output).strip()
206 assert( line == 'connection map:' )
213 if line == 'end of connection map':
215 conn_name, conn_info = regexp('\[\s*(.+)\s*\]\s*:\s*\(\s*(.*)\s*\)', line).groups()
218 conn_actions = regexp('actions\s*:\s*\[\s*(.+)\s*\]', line).groups()
219 state.connections.append( (conn_name, conn_info, conn_actions) )
223 line = next(output).strip()
224 assert( len(line) == 0 )
227 line = next(output).strip()
228 state.actions = regexp('actions\s*:\s*(.*)', line).groups()[0].split()
229 if len(state.actions) == 1 and state.actions[0].strip() == '-':
231 line = next(output).strip()
232 assert( len(line) == 0 )
235 line = next(output).strip()
236 state.online_ips = regexp('list of online ips\s*:\s*(.*)', \
237 line).groups()[0].split()
238 if len(state.online_ips) == 1 and state.online_ips[0].strip() == 'NONE':
239 state.online_ips = []
240 line = next(output).strip()
241 assert( len(line) == 0 )
244 state.connected_vpns = []
245 line = next(output).strip()
246 assert( line == 'vpns connected:' )
251 elif line == 'end of list of connected vpns':
254 state.connected_vpns.append(line)
258 line = next(output).strip()
259 assert( len(line) == 0 )
260 line = next(output).strip()
261 assert( line == 'Done.' )
264 #end: ConndState.get_state
266 #end: class ConndState
270 state = ConndState.get_state()
272 print(state.complete_str())
275 """ Main function, called when running file as script; runs test()
281 if __name__ == '__main__':
284 # (created using vim -- the world's best text editor)