Hardcoding names is ugly enough. Don't care about case.
[nodemanager.git] / net.py
1 #
2 #
3 """network configuration"""
4
5 import sioc
6 import bwlimit
7 import logger
8 import string
9 import iptables
10
11 def GetSlivers(plc, data):
12     InitNodeLimit(data)
13     InitI2(plc, data)
14     InitNAT(plc, data)
15
16 def InitNodeLimit(data):
17     # query running network interfaces
18     devs = sioc.gifconf()
19     ips = dict(zip(devs.values(), devs.keys()))
20     macs = {}
21     for dev in devs:
22         macs[sioc.gifhwaddr(dev).lower()] = dev
23
24     # XXX Exempt Internet2 destinations from node bwlimits
25     # bwlimit.exempt_init('Internet2', internet2_ips)
26     for network in data['networks']:
27         # Get interface name preferably from MAC address, falling
28         # back on IP address.
29         if macs.has_key(network['mac']):
30             dev = macs[network['mac'].lower()]
31         elif ips.has_key(network['ip']):
32             dev = ips[network['ip']]
33         else:
34             logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
35             continue
36
37         # Get current node cap
38         try:
39             old_bwlimit = bwlimit.get_bwcap(dev)
40         except:
41             old_bwlimit = None
42
43         # Get desired node cap
44         if network['bwlimit'] is None or network['bwlimit'] < 0:
45             new_bwlimit = bwlimit.bwmax
46         else:
47             new_bwlimit = network['bwlimit']
48
49         if old_bwlimit != new_bwlimit:
50             # Reinitialize bandwidth limits
51             bwlimit.init(dev, new_bwlimit)
52
53             # XXX This should trigger an rspec refresh in case
54             # some previously invalid sliver bwlimit is now valid
55             # again, or vice-versa.
56
57 def InitI2(plc, data):
58     if "Internet2" in data['groups']:
59         logger.log("This is an Internet2 node.  Setting rules.")
60         i2nodes = []
61         i2nodeids = plc.GetNodeGroups(["Internet2"])[0]['node_ids']
62         for node in plc.GetNodeNetworks({"node_id": i2nodeids}, ["ip"]):
63             i2nodes.append(node['ip'])
64         bwlimit.exempt_init('Internet2', i2nodes)
65
66 def InitNAT(plc, data):
67     # query running network interfaces
68     devs = sioc.gifconf()
69     ips = dict(zip(devs.values(), devs.keys()))
70     macs = {}
71     for dev in devs:
72         macs[sioc.gifhwaddr(dev).lower()] = dev
73
74     ipt = iptables.IPTables()
75     for network in data['networks']:
76         # Get interface name preferably from MAC address, falling
77         # back on IP address.
78         if macs.has_key(network['mac']):
79             dev = macs[network['mac'].lower()]
80         elif ips.has_key(network['ip']):
81             dev = ips[network['ip']]
82         else:
83             logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
84             continue
85
86         try:
87             settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id': network['nodenetwork_setting_ids']})
88         except:
89             continue
90         # XXX arbitrary names
91         for setting in settings:
92             if setting['category'].upper() != 'FIREWALL':
93                 continue
94             if setting['name'].upper() == 'EXTERNAL':
95                 # Enable NAT for this interface
96                 ipt.add_ext(dev)
97             elif setting['name'].upper() == 'INTERNAL':
98                 ipt.add_int(dev)
99             elif setting['name'].upper() == 'PF': # XXX Uglier code is hard to find...
100                 for pf in setting['value'].split("\n"):
101                     fields = {}
102                     for field in pf.split(","):
103                         (key, val) = field.split("=", 2)
104                         fields[key] = val
105                     if 'new_dport' not in fields:
106                         fields['new_dport'] = fields['dport']
107                     if 'source' not in fields:
108                         fields['source'] = "0.0.0.0/0"
109                     ipt.add_pf(fields)
110     ipt.commit()
111
112 def start(options, config):
113     pass