]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/__main__.py
bridge: vlan-aware: add new boolean policy "vlan_aware_bridge_address_support"
[mirror_ifupdown2.git] / ifupdown2 / __main__.py
1 #!/usr/bin/python
2 #
3 # Copyright 2016 Cumulus Networks, Inc. All rights reserved.
4 # Author: Julien Fortin, julien@cumulusnetworks.com
5 #
6 #
7
8 import os
9 import re
10 import sys
11 import json
12 import errno
13 import struct
14 import select
15 import socket
16 import signal
17
18 try:
19 import ifupdown2.ifupdown.config as core_config
20 from ifupdown2.ifupdown.log import log
21 from ifupdown2 import __version__
22
23 core_config.__version__ = __version__
24 except:
25 import ifupdown.config as core_config
26 from ifupdown.log import log
27
28 core_config.__version__ = __import__('__init__').__version__
29
30
31 class Ifupdown2Complete(Exception):
32 def __init__(self, status):
33 self.status = status
34
35
36 class Ifupdown2Client:
37 def __init__(self, argv):
38
39 self.stdin = None
40 self.argv = argv
41 self.data = ''
42 self.HEADER_SIZE = 4
43 self.daemon_pid = -1
44
45 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
46 try:
47 self.socket.connect('/var/run/ifupdown2d/uds')
48
49 signal.signal(signal.SIGINT, self.signal_handler)
50 signal.signal(signal.SIGTERM, self.signal_handler)
51 signal.signal(signal.SIGQUIT, self.signal_handler)
52
53 try:
54 self.SO_PEERCRED = socket.SO_PEERCRED
55 except AttributeError:
56 # powerpc is the only non-generic we care about. alpha, mips,
57 # sparc, and parisc also have non-generic values.
58 machine = os.uname()[4]
59 if re.search(r'^(ppc|powerpc)', machine):
60 self.SO_PASSCRED = 20
61 self.SO_PEERCRED = 21
62 else:
63 self.SO_PASSCRED = 16
64 self.SO_PEERCRED = 17
65 try:
66 self.socket.setsockopt(socket.SOL_SOCKET, self.SO_PASSCRED, 1)
67 except Exception as e:
68 raise Exception('setsockopt: %s' % str(e))
69
70 except socket.error:
71 self.socket.close()
72 self.socket = None
73 sys.stderr.write("""
74 ERROR: %s could not connect to ifupdown2d
75
76 Try starting ifupdown2d with:
77 sudo systemctl start ifupdown2d
78
79 To configure ifupdown2d to start when the box boots:
80 sudo systemctl enable ifupdown2d
81 """ % argv[0])
82
83 def __del__(self):
84 if self.socket:
85 self.socket.close()
86
87 def signal_handler(self, sig, frame):
88 if self.daemon_pid > 0:
89 os.kill(self.daemon_pid, sig)
90
91 def read_data(self):
92 ready = select.select([self.socket], [], [])
93 if ready and ready[0] and ready[0][0] == self.socket:
94 d = self.socket.recv(65536)
95 if self.data:
96 self.data += d
97 else:
98 self.data = d
99 return True
100 return False
101
102 def get_packets(self):
103 """
104 ifupdown2 output is divided into "json packets"
105 the first 4 bytes is the size of the next json
106 object to etract
107
108 """
109 data_size = len(self.data)
110 if not data_size:
111 raise Ifupdown2Complete(status=1)
112
113 packets = []
114 try:
115 while data_size > 0:
116 packet_len = struct.unpack('=I', self.data[:self.HEADER_SIZE])[0]
117 packet_data = self.data[self.HEADER_SIZE:packet_len + self.HEADER_SIZE]
118
119 fmt = "=%ds" % packet_len
120
121 packets.append(json.loads(struct.unpack(fmt, packet_data)[0]))
122
123 self.data = self.data[self.HEADER_SIZE + packet_len:]
124 data_size -= self.HEADER_SIZE + packet_len
125 except:
126 pass
127 return packets
128
129 def process_packets(self, packets):
130 for packet in packets:
131 if 'pid' in packet:
132 self.daemon_pid = packet['pid']
133 if 'stdout' in packet:
134 sys.stdout.write(packet['stdout'])
135 if 'stderr' in packet:
136 sys.stderr.write(packet['stderr'])
137 if 'status' in packet:
138 raise Ifupdown2Complete(packet['status'])
139
140 def run(self):
141 status = 1
142 if self.socket:
143 for arg in ['-i', '--interfaces']:
144 try:
145 if self.argv[self.argv.index(arg) + 1] == '-':
146 self.stdin = sys.stdin.read()
147 continue
148 except (ValueError, IndexError):
149 pass
150
151 self.socket.send(json.dumps({
152 'argv': self.argv,
153 'stdin': self.stdin
154 }))
155
156 try:
157 while True:
158 try:
159 self.read_data()
160 self.process_packets(self.get_packets())
161 except Ifupdown2Complete as e:
162 status = e.status
163 break
164 except Exception as e:
165 if ((isinstance(e.args, tuple) and e[0] == 4)
166 or (hasattr(e, 'errno') and e.errno == errno.EINTR)):
167 pass
168 else:
169 raise
170 except Exception as e:
171 sys.stderr.write(str(e))
172 finally:
173 self.socket.close()
174 return status if status != None else 1
175
176
177 def ifupdown2_standalone():
178 try:
179 import ifupdown2.ifupdown.main as main_ifupdown2
180 except:
181 import ifupdown.main as main_ifupdown2
182 ifupdown2 = main_ifupdown2.Ifupdown2(daemon=False, uid=os.geteuid())
183 ifupdown2.parse_argv(sys.argv)
184 ifupdown2.update_logger()
185 return ifupdown2.main()
186
187
188 def main():
189 try:
190 if 'use_daemon=yes' in open(core_config.IFUPDOWN2_CONF_PATH).read():
191 return Ifupdown2Client(sys.argv).run()
192 else:
193 return ifupdown2_standalone()
194 except KeyboardInterrupt:
195 return 1
196 except Exception as e:
197 log.error(str(e))
198 return 1
199
200
201 if __name__ == '__main__':
202 try:
203 sys.exit(main())
204 except KeyboardInterrupt:
205 sys.exit(1)