]>
Commit | Line | Data |
---|---|---|
064af421 BP |
1 | #!/usr/bin/python |
2 | # | |
c4b1912e | 3 | # Copyright (c) 2008,2009 Citrix Systems, Inc. |
064af421 | 4 | # |
c4b1912e IC |
5 | # This program is free software; you can redistribute it and/or modify |
6 | # it under the terms of the GNU Lesser General Public License as published | |
7 | # by the Free Software Foundation; version 2.1 only. with the special | |
8 | # exception on linking described in file LICENSE. | |
9 | # | |
10 | # This program is distributed in the hope that it will be useful, | |
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | # GNU Lesser General Public License for more details. | |
14 | # | |
064af421 BP |
15 | """Usage: |
16 | ||
057fed2b BP |
17 | %(command-name)s <PIF> up |
18 | %(command-name)s <PIF> down | |
b3080599 | 19 | %(command-name)s rewrite |
057fed2b BP |
20 | %(command-name)s --force <BRIDGE> up |
21 | %(command-name)s --force <BRIDGE> down | |
b3080599 | 22 | %(command-name)s --force <BRIDGE> rewrite --device=<INTERFACE> --mac=<MAC-ADDRESS> <CONFIG> |
064af421 | 23 | |
057fed2b BP |
24 | where <PIF> is one of: |
25 | --session <SESSION-REF> --pif <PIF-REF> | |
26 | --pif-uuid <PIF-UUID> | |
27 | and <CONFIG> is one of: | |
28 | --mode=dhcp | |
29 | --mode=static --ip=<IPADDR> --netmask=<NM> [--gateway=<GW>] | |
064af421 BP |
30 | |
31 | Options: | |
b3080599 | 32 | --session A session reference to use to access the xapi DB |
057fed2b BP |
33 | --pif A PIF reference within the session. |
34 | --pif-uuid The UUID of a PIF. | |
35 | --force An interface name. | |
64ddb6fe | 36 | --root-prefix=DIR Use DIR as alternate root directory (for testing). |
b63fadcf | 37 | --no-syslog Write log messages to stderr instead of system log. |
064af421 BP |
38 | """ |
39 | ||
064af421 BP |
40 | # Notes: |
41 | # 1. Every pif belongs to exactly one network | |
42 | # 2. Every network has zero or one pifs | |
43 | # 3. A network may have an associated bridge, allowing vifs to be attached | |
44 | # 4. A network may be bridgeless (there's no point having a bridge over a storage pif) | |
45 | ||
b3080599 IC |
46 | from InterfaceReconfigure import * |
47 | ||
48 | import os, sys, getopt | |
064af421 BP |
49 | import syslog |
50 | import traceback | |
064af421 | 51 | import re |
2bb451b6 | 52 | import random |
064af421 | 53 | |
064af421 BP |
54 | management_pif = None |
55 | ||
1fa5a105 | 56 | dbcache_file = "/var/xapi/network.dbcache" |
064af421 | 57 | |
0b8870d4 | 58 | # |
b3080599 | 59 | # Logging. |
0b8870d4 IC |
60 | # |
61 | ||
0b8870d4 | 62 | def log_pif_action(action, pif): |
b3080599 | 63 | pifrec = db().get_pif_record(pif) |
0b8870d4 IC |
64 | rec = {} |
65 | rec['uuid'] = pifrec['uuid'] | |
66 | rec['ip_configuration_mode'] = pifrec['ip_configuration_mode'] | |
67 | rec['action'] = action | |
68 | rec['pif_netdev_name'] = pif_netdev_name(pif) | |
69 | rec['message'] = "Bring %(action)s PIF %(uuid)s" % rec | |
70 | log("%(message)s: %(pif_netdev_name)s configured as %(ip_configuration_mode)s" % rec) | |
71 | ||
0b8870d4 IC |
72 | # |
73 | # Exceptions. | |
74 | # | |
75 | ||
064af421 BP |
76 | class Usage(Exception): |
77 | def __init__(self, msg): | |
78 | Exception.__init__(self) | |
79 | self.msg = msg | |
80 | ||
0b8870d4 IC |
81 | # |
82 | # Boot from Network filesystem or device. | |
83 | # | |
064af421 | 84 | |
0b8870d4 IC |
85 | def check_allowed(pif): |
86 | """Determine whether interface-reconfigure should be manipulating this PIF. | |
064af421 | 87 | |
0b8870d4 IC |
88 | Used to prevent system PIFs (such as network root disk) from being interfered with. |
89 | """ | |
6dd3fad4 | 90 | |
b3080599 | 91 | pifrec = db().get_pif_record(pif) |
0b8870d4 | 92 | try: |
64ddb6fe | 93 | f = open(root_prefix() + "/proc/ardence") |
0b8870d4 IC |
94 | macline = filter(lambda x: x.startswith("HWaddr:"), f.readlines()) |
95 | f.close() | |
96 | if len(macline) == 1: | |
97 | p = re.compile(".*\s%(MAC)s\s.*" % pifrec, re.IGNORECASE) | |
98 | if p.match(macline[0]): | |
99 | log("Skipping PVS device %(device)s (%(MAC)s)" % pifrec) | |
100 | return False | |
101 | except IOError: | |
102 | pass | |
103 | return True | |
064af421 | 104 | |
0b8870d4 IC |
105 | # |
106 | # Bare Network Devices -- network devices without IP configuration | |
107 | # | |
064af421 | 108 | |
0b8870d4 IC |
109 | def netdev_remap_name(pif, already_renamed=[]): |
110 | """Check whether 'pif' exists and has the correct MAC. | |
111 | If not, try to find a device with the correct MAC and rename it. | |
112 | 'already_renamed' is used to avoid infinite recursion. | |
113 | """ | |
b3080599 | 114 | |
0b8870d4 IC |
115 | def read1(name): |
116 | file = None | |
117 | try: | |
118 | file = open(name, 'r') | |
119 | return file.readline().rstrip('\n') | |
120 | finally: | |
121 | if file != None: | |
122 | file.close() | |
064af421 | 123 | |
0b8870d4 IC |
124 | def get_netdev_mac(device): |
125 | try: | |
64ddb6fe | 126 | return read1("%s/sys/class/net/%s/address" % (root_prefix(), device)) |
0b8870d4 IC |
127 | except: |
128 | # Probably no such device. | |
129 | return None | |
064af421 | 130 | |
0b8870d4 IC |
131 | def get_netdev_tx_queue_len(device): |
132 | try: | |
64ddb6fe | 133 | return int(read1("%s/sys/class/net/%s/tx_queue_len" % (root_prefix(), device))) |
0b8870d4 IC |
134 | except: |
135 | # Probably no such device. | |
136 | return None | |
064af421 | 137 | |
0b8870d4 | 138 | def get_netdev_by_mac(mac): |
64ddb6fe | 139 | for device in os.listdir(root_prefix() + "/sys/class/net"): |
0b8870d4 IC |
140 | dev_mac = get_netdev_mac(device) |
141 | if (dev_mac and mac.lower() == dev_mac.lower() and | |
142 | get_netdev_tx_queue_len(device)): | |
143 | return device | |
144 | return None | |
064af421 | 145 | |
0b8870d4 IC |
146 | def rename_netdev(old_name, new_name): |
147 | log("Changing the name of %s to %s" % (old_name, new_name)) | |
148 | run_command(['/sbin/ifconfig', old_name, 'down']) | |
149 | if not run_command(['/sbin/ip', 'link', 'set', old_name, 'name', new_name]): | |
150 | raise Error("Could not rename %s to %s" % (old_name, new_name)) | |
064af421 | 151 | |
b3080599 | 152 | pifrec = db().get_pif_record(pif) |
2bb451b6 BP |
153 | device = pifrec['device'] |
154 | mac = pifrec['MAC'] | |
155 | ||
156 | # Is there a network device named 'device' at all? | |
0b8870d4 | 157 | device_exists = netdev_exists(device) |
2bb451b6 BP |
158 | if device_exists: |
159 | # Yes. Does it have MAC 'mac'? | |
160 | found_mac = get_netdev_mac(device) | |
161 | if found_mac and mac.lower() == found_mac.lower(): | |
162 | # Yes, everything checks out the way we want. Nothing to do. | |
163 | return | |
164 | else: | |
165 | log("No network device %s" % device) | |
166 | ||
167 | # What device has MAC 'mac'? | |
168 | cur_device = get_netdev_by_mac(mac) | |
169 | if not cur_device: | |
170 | log("No network device has MAC %s" % mac) | |
171 | return | |
172 | ||
173 | # First rename 'device', if it exists, to get it out of the way | |
174 | # for 'cur_device' to replace it. | |
175 | if device_exists: | |
176 | rename_netdev(device, "dev%d" % random.getrandbits(24)) | |
177 | ||
178 | # Rename 'cur_device' to 'device'. | |
179 | rename_netdev(cur_device, device) | |
180 | ||
0b8870d4 IC |
181 | # |
182 | # IP Network Devices -- network devices with IP configuration | |
183 | # | |
064af421 | 184 | |
0b8870d4 IC |
185 | def ifdown(netdev): |
186 | """Bring down a network interface""" | |
0b8870d4 IC |
187 | if not netdev_exists(netdev): |
188 | log("ifdown: device %s does not exist, ignoring" % netdev) | |
189 | return | |
64ddb6fe | 190 | if not os.path.exists("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), netdev)): |
b3080599 IC |
191 | log("ifdown: device %s exists but ifcfg-%s does not" % (netdev,netdev)) |
192 | run_command(["/sbin/ifconfig", netdev, 'down']) | |
193 | return | |
0b8870d4 | 194 | run_command(["/sbin/ifdown", netdev]) |
064af421 | 195 | |
0b8870d4 IC |
196 | def ifup(netdev): |
197 | """Bring up a network interface""" | |
64ddb6fe | 198 | if not os.path.exists(root_prefix() + "/etc/sysconfig/network-scripts/ifcfg-%s" % netdev): |
0b8870d4 IC |
199 | raise Error("ifup: device %s exists but ifcfg-%s does not" % (netdev,netdev)) |
200 | run_command(["/sbin/ifup", netdev]) | |
201 | ||
202 | # | |
b3080599 | 203 | # |
0b8870d4 | 204 | # |
064af421 | 205 | |
b3080599 | 206 | def pif_rename_physical_devices(pif): |
064af421 | 207 | |
0b8870d4 | 208 | if pif_is_vlan(pif): |
b3080599 | 209 | pif = pif_get_vlan_slave(pif) |
064af421 | 210 | |
b3080599 IC |
211 | if pif_is_bond(pif): |
212 | pifs = pif_get_bond_slaves(pif) | |
0b8870d4 | 213 | else: |
b3080599 | 214 | pifs = [pif] |
0b8870d4 | 215 | |
b3080599 IC |
216 | for pif in pifs: |
217 | netdev_remap_name(pif) | |
0b8870d4 IC |
218 | |
219 | # | |
220 | # IP device configuration | |
221 | # | |
064af421 | 222 | |
0b8870d4 IC |
223 | def ipdev_configure_static_routes(interface, oc, f): |
224 | """Open a route-<interface> file for static routes. | |
225 | ||
226 | Opens the static routes configuration file for interface and writes one | |
227 | line for each route specified in the network's other config "static-routes" value. | |
228 | E.g. if | |
229 | interface ( RO): xenbr1 | |
230 | other-config (MRW): static-routes: 172.16.0.0/15/192.168.0.3,172.18.0.0/16/192.168.0.4;... | |
231 | ||
232 | Then route-xenbr1 should be | |
233 | 172.16.0.0/15 via 192.168.0.3 dev xenbr1 | |
234 | 172.18.0.0/16 via 192.168.0.4 dev xenbr1 | |
235 | """ | |
0b8870d4 IC |
236 | if oc.has_key('static-routes'): |
237 | # The key is present - extract comma seperates entries | |
238 | lines = oc['static-routes'].split(',') | |
239 | else: | |
240 | # The key is not present, i.e. there are no static routes | |
241 | lines = [] | |
242 | ||
64ddb6fe | 243 | child = ConfigurationFile("%s/etc/sysconfig/network-scripts/route-%s" % (root_prefix(), interface)) |
0b8870d4 IC |
244 | child.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \ |
245 | (os.path.basename(child.path()), os.path.basename(sys.argv[0]))) | |
246 | ||
247 | try: | |
248 | for l in lines: | |
249 | network, masklen, gateway = l.split('/') | |
250 | child.write("%s/%s via %s dev %s\n" % (network, masklen, gateway, interface)) | |
251 | ||
252 | f.attach_child(child) | |
253 | child.close() | |
254 | ||
255 | except ValueError, e: | |
256 | log("Error in other-config['static-routes'] format for network %s: %s" % (interface, e)) | |
064af421 | 257 | |
0b8870d4 IC |
258 | def ipdev_open_ifcfg(pif): |
259 | ipdev = pif_ipdev_name(pif) | |
c87d1024 | 260 | |
0b8870d4 IC |
261 | log("Writing network configuration for %s" % ipdev) |
262 | ||
64ddb6fe | 263 | f = ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), ipdev)) |
0b8870d4 IC |
264 | |
265 | f.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \ | |
266 | (os.path.basename(f.path()), os.path.basename(sys.argv[0]))) | |
267 | f.write("XEMANAGED=yes\n") | |
268 | f.write("DEVICE=%s\n" % ipdev) | |
269 | f.write("ONBOOT=no\n") | |
270 | ||
271 | return f | |
272 | ||
b3080599 | 273 | def ipdev_configure_network(pif, dp): |
0b8870d4 IC |
274 | """Write the configuration file for a network. |
275 | ||
276 | Writes configuration derived from the network object into the relevant | |
277 | ifcfg file. The configuration file is passed in, but if the network is | |
278 | bridgeless it will be ifcfg-<interface>, otherwise it will be ifcfg-<bridge>. | |
279 | ||
280 | This routine may also write ifcfg files of the networks corresponding to other PIFs | |
281 | in order to maintain consistency. | |
282 | ||
283 | params: | |
284 | pif: Opaque_ref of pif | |
b3080599 | 285 | dp: Datapath object |
0b8870d4 IC |
286 | """ |
287 | ||
b3080599 | 288 | pifrec = db().get_pif_record(pif) |
9a2b1175 IC |
289 | nw = pifrec['network'] |
290 | nwrec = db().get_network_record(nw) | |
0b8870d4 IC |
291 | |
292 | ipdev = pif_ipdev_name(pif) | |
293 | ||
294 | f = ipdev_open_ifcfg(pif) | |
295 | ||
296 | mode = pifrec['ip_configuration_mode'] | |
297 | log("Configuring %s using %s configuration" % (ipdev, mode)) | |
298 | ||
299 | oc = None | |
300 | if pifrec.has_key('other_config'): | |
301 | oc = pifrec['other_config'] | |
302 | ||
b3080599 IC |
303 | dp.configure_ipdev(f) |
304 | ||
064af421 | 305 | if pifrec['ip_configuration_mode'] == "DHCP": |
0b8870d4 IC |
306 | f.write("BOOTPROTO=dhcp\n") |
307 | f.write("PERSISTENT_DHCLIENT=yes\n") | |
064af421 | 308 | elif pifrec['ip_configuration_mode'] == "Static": |
0b8870d4 IC |
309 | f.write("BOOTPROTO=none\n") |
310 | f.write("NETMASK=%(netmask)s\n" % pifrec) | |
311 | f.write("IPADDR=%(IP)s\n" % pifrec) | |
312 | f.write("GATEWAY=%(gateway)s\n" % pifrec) | |
064af421 | 313 | elif pifrec['ip_configuration_mode'] == "None": |
0b8870d4 | 314 | f.write("BOOTPROTO=none\n") |
064af421 | 315 | else: |
0b8870d4 IC |
316 | raise Error("Unknown ip-configuration-mode %s" % pifrec['ip_configuration_mode']) |
317 | ||
318 | if nwrec.has_key('other_config'): | |
319 | settings,offload = ethtool_settings(nwrec['other_config']) | |
320 | if len(settings): | |
321 | f.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings)) | |
322 | if len(offload): | |
323 | f.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload)) | |
324 | ||
0b8870d4 IC |
325 | ipdev_configure_static_routes(ipdev, nwrec['other_config'], f) |
326 | ||
9a2b1175 IC |
327 | mtu = mtu_setting(nw, "Network", nwrec['other_config']) |
328 | if mtu: | |
329 | f.write("MTU=%s\n" % mtu) | |
330 | ||
331 | ||
0b8870d4 IC |
332 | if pifrec.has_key('DNS') and pifrec['DNS'] != "": |
333 | ServerList = pifrec['DNS'].split(",") | |
334 | for i in range(len(ServerList)): f.write("DNS%d=%s\n" % (i+1, ServerList[i])) | |
335 | if oc and oc.has_key('domain'): | |
336 | f.write("DOMAIN='%s'\n" % oc['domain'].replace(',', ' ')) | |
337 | ||
b3080599 | 338 | # There can be only one DNSDEV and one GATEWAYDEV in /etc/sysconfig/network. |
0b8870d4 IC |
339 | # |
340 | # The peerdns pif will be the one with | |
341 | # pif::other-config:peerdns=true, or the mgmt pif if none have | |
342 | # this set. | |
343 | # | |
344 | # The gateway pif will be the one with | |
345 | # pif::other-config:defaultroute=true, or the mgmt pif if none | |
346 | # have this set. | |
347 | ||
b3080599 IC |
348 | # Work out which pif on this host should be the DNSDEV and which |
349 | # should be the GATEWAYDEV | |
0b8870d4 | 350 | # |
b3080599 | 351 | # Note: we prune out the bond master pif (if it exists). This is |
0b8870d4 IC |
352 | # because when we are called to bring up an interface with a bond |
353 | # master, it is implicit that we should bring down that master. | |
0b8870d4 | 354 | |
b3080599 | 355 | pifs_on_host = [p for p in db().get_all_pifs() if not p in pif_get_bond_masters(pif)] |
0b8870d4 IC |
356 | |
357 | # loop through all the pifs on this host looking for one with | |
358 | # other-config:peerdns = true, and one with | |
359 | # other-config:default-route=true | |
b3080599 IC |
360 | peerdns_pif = None |
361 | defaultroute_pif = None | |
0b8870d4 | 362 | for __pif in pifs_on_host: |
b3080599 | 363 | __pifrec = db().get_pif_record(__pif) |
0b8870d4 IC |
364 | __oc = __pifrec['other_config'] |
365 | if __oc.has_key('peerdns') and __oc['peerdns'] == 'true': | |
366 | if peerdns_pif == None: | |
367 | peerdns_pif = __pif | |
368 | else: | |
369 | log('Warning: multiple pifs with "peerdns=true" - choosing %s and ignoring %s' % \ | |
b3080599 | 370 | (db().get_pif_record(peerdns_pif)['device'], __pifrec['device'])) |
0b8870d4 IC |
371 | if __oc.has_key('defaultroute') and __oc['defaultroute'] == 'true': |
372 | if defaultroute_pif == None: | |
373 | defaultroute_pif = __pif | |
374 | else: | |
375 | log('Warning: multiple pifs with "defaultroute=true" - choosing %s and ignoring %s' % \ | |
b3080599 | 376 | (db().get_pif_record(defaultroute_pif)['device'], __pifrec['device'])) |
0b8870d4 IC |
377 | |
378 | # If no pif is explicitly specified then use the mgmt pif for | |
379 | # peerdns/defaultroute. | |
380 | if peerdns_pif == None: | |
381 | peerdns_pif = management_pif | |
382 | if defaultroute_pif == None: | |
383 | defaultroute_pif = management_pif | |
384 | ||
b3080599 IC |
385 | is_dnsdev = peerdns_pif == pif |
386 | is_gatewaydev = defaultroute_pif == pif | |
387 | ||
388 | if is_dnsdev or is_gatewaydev: | |
64ddb6fe | 389 | fnetwork = ConfigurationFile(root_prefix() + "/etc/sysconfig/network") |
b3080599 IC |
390 | for line in fnetwork.readlines(): |
391 | if is_dnsdev and line.lstrip().startswith('DNSDEV='): | |
392 | fnetwork.write('DNSDEV=%s\n' % ipdev) | |
393 | is_dnsdev = False | |
394 | elif is_gatewaydev and line.lstrip().startswith('GATEWAYDEV='): | |
395 | fnetwork.write('GATEWAYDEV=%s\n' % ipdev) | |
396 | is_gatewaydev = False | |
397 | else: | |
398 | fnetwork.write(line) | |
064af421 | 399 | |
b3080599 IC |
400 | if is_dnsdev: |
401 | fnetwork.write('DNSDEV=%s\n' % ipdev) | |
402 | if is_gatewaydev: | |
403 | fnetwork.write('GATEWAYDEV=%s\n' % ipdev) | |
0b8870d4 | 404 | |
b3080599 IC |
405 | fnetwork.close() |
406 | f.attach_child(fnetwork) | |
064af421 | 407 | |
b3080599 | 408 | return f |
064af421 | 409 | |
0b8870d4 | 410 | # |
b3080599 | 411 | # Toplevel actions |
0b8870d4 | 412 | # |
064af421 | 413 | |
b3080599 IC |
414 | def action_up(pif, force): |
415 | pifrec = db().get_pif_record(pif) | |
0b8870d4 | 416 | |
b3080599 | 417 | ipdev = pif_ipdev_name(pif) |
823c5699 | 418 | dp = DatapathFactory()(pif) |
0b8870d4 | 419 | |
b3080599 | 420 | log("action_up: %s" % ipdev) |
0b8870d4 | 421 | |
b3080599 | 422 | f = ipdev_configure_network(pif, dp) |
0b8870d4 | 423 | |
b3080599 | 424 | dp.preconfigure(f) |
0b8870d4 | 425 | |
b3080599 | 426 | f.close() |
0b8870d4 | 427 | |
b3080599 | 428 | pif_rename_physical_devices(pif) |
0b8870d4 | 429 | |
b3080599 IC |
430 | # if we are not forcing the interface up then attempt to tear down |
431 | # any existing devices which might interfere with brinign this one | |
432 | # up. | |
433 | if not force: | |
434 | ifdown(ipdev) | |
0b8870d4 | 435 | |
b3080599 | 436 | dp.bring_down_existing() |
0b8870d4 | 437 | |
064af421 BP |
438 | try: |
439 | f.apply() | |
0b8870d4 | 440 | |
b3080599 | 441 | dp.configure() |
0b8870d4 IC |
442 | |
443 | ifup(ipdev) | |
444 | ||
b3080599 | 445 | dp.post() |
0b8870d4 IC |
446 | |
447 | # Update /etc/issue (which contains the IP address of the management interface) | |
64ddb6fe | 448 | os.system(root_prefix() + "/sbin/update-issue") |
0b8870d4 | 449 | |
064af421 BP |
450 | f.commit() |
451 | except Error, e: | |
0b8870d4 | 452 | log("failed to apply changes: %s" % e.msg) |
064af421 BP |
453 | f.revert() |
454 | raise | |
455 | ||
0b8870d4 | 456 | def action_down(pif): |
0b8870d4 | 457 | ipdev = pif_ipdev_name(pif) |
823c5699 | 458 | dp = DatapathFactory()(pif) |
0b8870d4 | 459 | |
b3080599 | 460 | log("action_down: %s" % ipdev) |
0b8870d4 | 461 | |
b3080599 | 462 | ifdown(ipdev) |
0b8870d4 | 463 | |
b3080599 | 464 | dp.bring_down() |
064af421 | 465 | |
823c5699 IC |
466 | def action_rewrite(): |
467 | DatapathFactory().rewrite() | |
468 | ||
b3080599 IC |
469 | # This is useful for reconfiguring the mgmt interface after having lost connectivity to the pool master |
470 | def action_force_rewrite(bridge, config): | |
471 | def getUUID(): | |
472 | import subprocess | |
473 | uuid,_ = subprocess.Popen(['uuidgen'], stdout = subprocess.PIPE).communicate() | |
474 | return uuid.strip() | |
064af421 | 475 | |
b3080599 IC |
476 | # Notes: |
477 | # 1. that this assumes the interface is bridged | |
478 | # 2. If --gateway is given it will make that the default gateway for the host | |
064af421 | 479 | |
b3080599 | 480 | # extract the configuration |
0b8870d4 | 481 | try: |
b3080599 IC |
482 | mode = config['mode'] |
483 | mac = config['mac'] | |
484 | interface = config['device'] | |
485 | except: | |
486 | raise Usage("Please supply --mode, --mac and --device") | |
064af421 | 487 | |
b3080599 IC |
488 | if mode == 'static': |
489 | try: | |
490 | netmask = config['netmask'] | |
491 | ip = config['ip'] | |
492 | except: | |
493 | raise Usage("Please supply --netmask and --ip") | |
494 | try: | |
495 | gateway = config['gateway'] | |
496 | except: | |
497 | gateway = None | |
498 | elif mode != 'dhcp': | |
499 | raise Usage("--mode must be either static or dhcp") | |
064af421 | 500 | |
b3080599 IC |
501 | if config.has_key('vlan'): |
502 | is_vlan = True | |
503 | vlan_slave, vlan_vid = config['vlan'].split('.') | |
504 | else: | |
505 | is_vlan = False | |
506 | ||
507 | if is_vlan: | |
508 | raise Error("Force rewrite of VLAN not implemented") | |
509 | ||
510 | log("Configuring %s using %s configuration" % (bridge, mode)) | |
511 | ||
64ddb6fe | 512 | f = ConfigurationFile(root_prefix() + dbcache_file) |
b3080599 IC |
513 | |
514 | pif_uuid = getUUID() | |
515 | network_uuid = getUUID() | |
516 | ||
517 | f.write('<?xml version="1.0" ?>\n') | |
518 | f.write('<xenserver-network-configuration>\n') | |
519 | f.write('\t<pif ref="OpaqueRef:%s">\n' % pif_uuid) | |
520 | f.write('\t\t<network>OpaqueRef:%s</network>\n' % network_uuid) | |
521 | f.write('\t\t<management>True</management>\n') | |
522 | f.write('\t\t<uuid>%sPif</uuid>\n' % interface) | |
523 | f.write('\t\t<bond_slave_of>OpaqueRef:NULL</bond_slave_of>\n') | |
524 | f.write('\t\t<bond_master_of/>\n') | |
525 | f.write('\t\t<VLAN_slave_of/>\n') | |
526 | f.write('\t\t<VLAN_master_of>OpaqueRef:NULL</VLAN_master_of>\n') | |
527 | f.write('\t\t<VLAN>-1</VLAN>\n') | |
528 | f.write('\t\t<device>%s</device>\n' % interface) | |
529 | f.write('\t\t<MAC>%s</MAC>\n' % mac) | |
530 | f.write('\t\t<other_config/>\n') | |
531 | if mode == 'dhcp': | |
532 | f.write('\t\t<ip_configuration_mode>DHCP</ip_configuration_mode>\n') | |
533 | f.write('\t\t<IP></IP>\n') | |
534 | f.write('\t\t<netmask></netmask>\n') | |
535 | f.write('\t\t<gateway></gateway>\n') | |
536 | f.write('\t\t<DNS></DNS>\n') | |
537 | elif mode == 'static': | |
538 | f.write('\t\t<ip_configuration_mode>Static</ip_configuration_mode>\n') | |
539 | f.write('\t\t<IP>%s</IP>\n' % ip) | |
540 | f.write('\t\t<netmask>%s</netmask>\n' % netmask) | |
541 | if gateway is not None: | |
542 | f.write('\t\t<gateway>%s</gateway>\n' % gateway) | |
543 | f.write('\t\t<DNS></DNS>\n') | |
544 | else: | |
545 | raise Error("Unknown mode %s" % mode) | |
546 | f.write('\t</pif>\n') | |
547 | ||
548 | f.write('\t<network ref="OpaqueRef:%s">\n' % network_uuid) | |
549 | f.write('\t\t<uuid>InitialManagementNetwork</uuid>\n') | |
550 | f.write('\t\t<PIFs>\n') | |
551 | f.write('\t\t\t<PIF>OpaqueRef:%s</PIF>\n' % pif_uuid) | |
552 | f.write('\t\t</PIFs>\n') | |
553 | f.write('\t\t<bridge>%s</bridge>\n' % bridge) | |
554 | f.write('\t\t<other_config/>\n') | |
555 | f.write('\t</network>\n') | |
556 | f.write('</xenserver-network-configuration>\n') | |
064af421 | 557 | |
064af421 | 558 | f.close() |
b3080599 | 559 | |
064af421 BP |
560 | try: |
561 | f.apply() | |
562 | f.commit() | |
563 | except Error, e: | |
564 | log("failed to apply changes: %s" % e.msg) | |
565 | f.revert() | |
566 | raise | |
567 | ||
064af421 | 568 | def main(argv=None): |
b3080599 | 569 | global management_pif |
0b8870d4 | 570 | |
064af421 BP |
571 | session = None |
572 | pif_uuid = None | |
573 | pif = None | |
574 | ||
575 | force_interface = None | |
576 | force_management = False | |
0b8870d4 | 577 | |
064af421 BP |
578 | if argv is None: |
579 | argv = sys.argv | |
580 | ||
581 | try: | |
582 | try: | |
583 | shortops = "h" | |
b3080599 | 584 | longops = [ "pif=", "pif-uuid=", |
064af421 BP |
585 | "session=", |
586 | "force=", | |
587 | "force-interface=", | |
588 | "management", | |
b3080599 | 589 | "mac=", "device=", "mode=", "ip=", "netmask=", "gateway=", |
64ddb6fe | 590 | "root-prefix=", |
b63fadcf | 591 | "no-syslog", |
064af421 BP |
592 | "help" ] |
593 | arglist, args = getopt.gnu_getopt(argv[1:], shortops, longops) | |
594 | except getopt.GetoptError, msg: | |
595 | raise Usage(msg) | |
596 | ||
597 | force_rewrite_config = {} | |
0b8870d4 | 598 | |
064af421 | 599 | for o,a in arglist: |
b3080599 | 600 | if o == "--pif": |
064af421 BP |
601 | pif = a |
602 | elif o == "--pif-uuid": | |
603 | pif_uuid = a | |
604 | elif o == "--session": | |
605 | session = a | |
606 | elif o == "--force-interface" or o == "--force": | |
607 | force_interface = a | |
608 | elif o == "--management": | |
609 | force_management = True | |
b3080599 | 610 | elif o in ["--mac", "--device", "--mode", "--ip", "--netmask", "--gateway"]: |
064af421 | 611 | force_rewrite_config[o[2:]] = a |
64ddb6fe BP |
612 | elif o == "--root-prefix": |
613 | set_root_prefix(a) | |
b63fadcf BP |
614 | elif o == "--no-syslog": |
615 | set_log_destination("stderr") | |
064af421 BP |
616 | elif o == "-h" or o == "--help": |
617 | print __doc__ % {'command-name': os.path.basename(argv[0])} | |
618 | return 0 | |
619 | ||
b63fadcf BP |
620 | if get_log_destination() == "syslog": |
621 | syslog.openlog(os.path.basename(argv[0])) | |
622 | log("Called as " + str.join(" ", argv)) | |
b3080599 | 623 | |
064af421 BP |
624 | if len(args) < 1: |
625 | raise Usage("Required option <action> not present") | |
626 | if len(args) > 1: | |
627 | raise Usage("Too many arguments") | |
628 | ||
629 | action = args[0] | |
fa2bec94 IC |
630 | |
631 | if not action in ["up", "down", "rewrite", "rewrite-configuration"]: | |
632 | raise Usage("Unknown action \"%s\"" % action) | |
633 | ||
064af421 BP |
634 | # backwards compatibility |
635 | if action == "rewrite-configuration": action = "rewrite" | |
0b8870d4 | 636 | |
064af421 BP |
637 | if ( session or pif ) and pif_uuid: |
638 | raise Usage("--session/--pif and --pif-uuid are mutually exclusive.") | |
639 | if ( session and not pif ) or ( not session and pif ): | |
640 | raise Usage("--session and --pif must be used together.") | |
641 | if force_interface and ( session or pif or pif_uuid ): | |
642 | raise Usage("--force is mutually exclusive with --session, --pif and --pif-uuid") | |
643 | if len(force_rewrite_config) and not (force_interface and action == "rewrite"): | |
644 | raise Usage("\"--force rewrite\" needed for --device, --mode, --ip, --netmask, and --gateway") | |
b3080599 IC |
645 | if (action == "rewrite") and (pif or pif_uuid ): |
646 | raise Usage("rewrite action does not take --pif or --pif-uuid") | |
647 | ||
064af421 BP |
648 | global db |
649 | if force_interface: | |
650 | log("Force interface %s %s" % (force_interface, action)) | |
651 | ||
652 | if action == "rewrite": | |
653 | action_force_rewrite(force_interface, force_rewrite_config) | |
fa2bec94 | 654 | elif action in ["up", "down"]: |
b3080599 IC |
655 | db_init_from_cache(dbcache_file) |
656 | pif = db().get_pif_by_bridge(force_interface) | |
657 | management_pif = db().get_management_pif() | |
064af421 BP |
658 | |
659 | if action == "up": | |
b3080599 | 660 | action_up(pif, True) |
064af421 BP |
661 | elif action == "down": |
662 | action_down(pif) | |
fa2bec94 IC |
663 | else: |
664 | raise Error("Unknown action %s" % action) | |
064af421 | 665 | else: |
b3080599 | 666 | db_init_from_xenapi(session) |
064af421 BP |
667 | |
668 | if pif_uuid: | |
b3080599 | 669 | pif = db().get_pif_by_uuid(pif_uuid) |
064af421 | 670 | |
b3080599 | 671 | if action == "rewrite": |
823c5699 | 672 | action_rewrite() |
064af421 | 673 | else: |
057fed2b BP |
674 | if not pif: |
675 | raise Usage("No PIF given") | |
064af421 | 676 | |
057fed2b | 677 | if force_management: |
0b8870d4 | 678 | # pif is going to be the management pif |
057fed2b BP |
679 | management_pif = pif |
680 | else: | |
681 | # pif is not going to be the management pif. | |
682 | # Search DB cache for pif on same host with management=true | |
b3080599 IC |
683 | pifrec = db().get_pif_record(pif) |
684 | management_pif = db().get_management_pif() | |
064af421 | 685 | |
057fed2b | 686 | log_pif_action(action, pif) |
064af421 | 687 | |
057fed2b BP |
688 | if not check_allowed(pif): |
689 | return 0 | |
690 | ||
691 | if action == "up": | |
b3080599 | 692 | action_up(pif, False) |
057fed2b BP |
693 | elif action == "down": |
694 | action_down(pif) | |
057fed2b | 695 | else: |
fa2bec94 | 696 | raise Error("Unknown action %s" % action) |
064af421 BP |
697 | |
698 | # Save cache. | |
b3080599 | 699 | db().save(dbcache_file) |
0b8870d4 | 700 | |
064af421 BP |
701 | except Usage, err: |
702 | print >>sys.stderr, err.msg | |
703 | print >>sys.stderr, "For help use --help." | |
704 | return 2 | |
705 | except Error, err: | |
706 | log(err.msg) | |
707 | return 1 | |
064af421 | 708 | |
0b8870d4 | 709 | return 0 |
064af421 | 710 | |
064af421 BP |
711 | if __name__ == "__main__": |
712 | rc = 1 | |
713 | try: | |
714 | rc = main() | |
715 | except: | |
716 | ex = sys.exc_info() | |
717 | err = traceback.format_exception(*ex) | |
718 | for exline in err: | |
719 | log(exline) | |
720 | ||
b3080599 | 721 | syslog.closelog() |
0b8870d4 | 722 | |
064af421 | 723 | sys.exit(rc) |