fix calls to AddSlices that took advantage of unchecked columns in previous version
[myplc.git] / db-config
1 #!/usr/bin/env /usr/bin/plcsh
2 #
3 # Bootstraps the PLC database with a default administrator account and
4 # a default site, defines default slice attribute types, and
5 # creates/updates default system slices.
6 #
7 # Mark Huang <mlhuang@cs.princeton.edu>
8 # Copyright (C) 2006 The Trustees of Princeton University
9 #
10 # $Id$
11 # $HeadURL$
12
13 from plc_config import PLCConfiguration
14 import sys
15 import resource
16
17 def main():
18     cfg = PLCConfiguration()
19     cfg.load()
20     variables = cfg.variables()
21
22     # Load variables into dictionaries
23     for category_id, (category, variablelist) in variables.iteritems():
24         globals()[category_id] = dict(zip(variablelist.keys(),
25                                        [variable['value'] for variable in variablelist.values()]))
26
27     # Create/update the default administrator account (should be
28     # person_id 2).
29     admin = { 'person_id': 2,
30               'first_name': "Default",
31               'last_name': "Administrator",
32               'email': plc['root_user'],
33               'password': plc['root_password'] }
34     persons = GetPersons([admin['person_id']])
35     if not persons:
36         person_id = AddPerson(admin)
37         if person_id != admin['person_id']:
38             # Huh? Someone deleted the account manually from the database.
39             DeletePerson(person_id)
40             raise Exception, "Someone deleted the \"%s %s\" account from the database!" % \
41                   (admin['first_name'], admin['last_name'])
42         UpdatePerson(person_id, { 'enabled': True })
43     else:
44         person_id = persons[0]['person_id']
45         UpdatePerson(person_id, admin)
46
47     # Create/update the default site (should be site_id 1)
48     if plc_www['port'] == '80':
49         url = "http://" + plc_www['host'] + "/"
50     elif plc_www['port'] == '443':
51         url = "https://" + plc_www['host'] + "/"
52     else:
53         url = "http://" + plc_www['host'] + ":" + plc_www['port'] + "/"
54     site = { 'site_id': 1,
55              'name': plc['name'] + " Central",
56              'abbreviated_name': plc['name'],
57              'login_base': plc['slice_prefix'],
58              'is_public': False,
59              'url': url,
60              'max_slices': 100 }
61
62     sites = GetSites([site['site_id']])
63     if not sites:
64         site_id = AddSite(site['name'], site['abbreviated_name'], site['login_base'], site)
65         if site_id != site['site_id']:
66             DeleteSite(site_id)
67             raise Exception, "Someone deleted the \"%s\" site from the database!" % \
68                   site['name']
69         sites = [site]
70
71     # Must call UpdateSite() even after AddSite() to update max_slices
72     site_id = sites[0]['site_id']
73     UpdateSite(site_id, site)
74
75     # The default administrator account must be associated with a site
76     # in order to login.
77     AddPersonToSite(admin['person_id'], site['site_id'])
78     SetPersonPrimarySite(admin['person_id'], site['site_id'])
79
80     # Grant admin and PI roles to the default administrator account
81     AddRoleToPerson(10, admin['person_id'])
82     AddRoleToPerson(20, admin['person_id'])
83
84     #################### node tags
85     default_node_types = [
86         { 'tagname' : 'arch',
87           'description' : 'architecture name',
88           'category' : 'node/config', 
89           'min_role_id' : 40} ,
90         { 'tagname' : 'pldistro',
91           'description' : 'PlanetLab distribution',
92           'category' : 'node/config', 
93           'min_role_id' : 10} ,
94         { 'tagname' : 'deployment',
95           'description' : 'typically "alpha", "beta", or "production"',
96           'category' : 'node/operation', 
97           'min_role_id' : 10} ,
98         ]
99
100     #################### interface settings
101     # xxx this should move to PLC/Accessors
102
103     # Setup default slice attribute types
104     default_setting_types = [
105         {'category' : "interface/general",
106          'tagname' : "ifname",
107          'description': "Set interface name, instead of eth0 or the like",
108          'min_role_id' : 40},
109         {'category' : "interface/multihome",
110          'tagname' : "alias",
111          'description': "Specifies that the network is used for multihoming",
112          'min_role_id' : 40},
113
114         {'category' : "interface/hidden",
115          'tagname' : "backdoor",
116          'description': "For testing new settings",
117          'min_role_id' : 10},
118         ] + [
119         { 'category' : "interface/wifi",
120           'tagname' : x,
121           'description' : "802.11 %s -- see %s"%(y,z),
122           'min_role_id' : 40 } for (x,y,z) in [
123             ("mode","Mode","iwconfig"),
124             ("essid","ESSID","iwconfig"),
125             ("nw","Network Id","iwconfig"),
126             ("freq","Frequency","iwconfig"),
127             ("channel","Channel","iwconfig"),
128             ("sens","sensitivity threshold","iwconfig"),
129             ("rate","Rate","iwconfig"),
130             ("key","key","iwconfig key"),
131             ("key1","key1","iwconfig key [1]"),
132             ("key2","key2","iwconfig key [2]"),
133             ("key3","key3","iwconfig key [3]"),
134             ("key4","key4","iwconfig key [4]"),
135             ("securitymode","Security mode","iwconfig enc"),
136             ("iwconfig","Additional parameters to iwconfig","ifup-wireless"),
137             ("iwpriv","Additional parameters to iwpriv","ifup-wireless"),
138             ]
139         ]
140
141     #################### slice attributes
142     # xxx this should move to PLC/Accessors
143
144     # Setup default slice attribute types
145     default_attribute_types = [
146         # Slice type (only vserver is supported)
147         {'tagname': "type",
148          'description': "Type of slice (e.g. vserver)",
149          'category' : 'slice/general',
150          'min_role_id': 20},
151
152         # System slice
153         {'tagname': "system",
154          'description': "Is a default system slice (1) or not (0 or unset)",
155          'category' : 'slice/general',
156          'min_role_id': 10},
157
158         # Slice enabled (1) or suspended (0)
159         {'tagname': "enabled",
160          'description': "Slice enabled (1 or unset) or suspended (0)",
161          'category' : 'slice/general',
162          'min_role_id': 10},
163
164         # Slice reference image
165         {'tagname': "vref",
166          'description': "Reference image",
167          'category' : 'slice/config',
168          'min_role_id': 30},
169
170         # Slice initialization script
171         {'tagname': "initscript",
172          'description': "Slice initialization script",
173          'category' : 'slice/config',
174          'min_role_id': 10},
175
176         # CPU share
177         {'tagname': "cpu_pct",
178          'description': "Reserved CPU percent",
179          'category' : 'slice/rspec',
180          'min_role_id': 10},
181         {'tagname': "cpu_share",
182          'description': "Number of CPU shares",
183          'category' : 'slice/rspec',
184          'min_role_id': 10},
185
186         # Bandwidth limits
187         {'tagname': "net_min_rate",
188          'description': "Minimum bandwidth (kbps)",
189          'category' : 'slice/rspec',
190          'min_role_id': 10},
191         {'tagname': "net_max_rate",
192          'description': "Maximum bandwidth (kbps)",
193          'category' : 'slice/rspec',
194          'min_role_id': 10},
195         {'tagname': "net_i2_min_rate",
196          'description': "Minimum bandwidth over I2 routes (kbps)",
197          'category' : 'slice/rspec',
198          'min_role_id': 10},
199         {'tagname': "net_i2_max_rate",
200          'description': "Maximum bandwidth over I2 routes (kbps)",
201          'category' : 'slice/rspec',
202          'min_role_id': 10},
203         {'tagname': "net_max_kbyte",
204          'description': "Maximum daily network Tx KByte limit.",
205          'category' : 'slice/rspec',
206          'min_role_id': 10},
207         {'tagname': "net_thresh_kbyte",
208          'description': "KByte limit before warning and throttling.",
209          'category' : 'slice/rspec',
210          'min_role_id': 10},
211         {'tagname': "net_i2_max_kbyte",
212          'description': "Maximum daily network Tx KByte limit to I2 hosts.",
213          'category' : 'slice/rspec',
214          'min_role_id': 10},
215         {'tagname': "net_i2_thresh_kbyte",
216          'description': "KByte limit to I2 hosts before warning and throttling.",
217          'category' : 'slice/rspec',
218          'min_role_id': 10},
219         {'tagname': "net_share",
220          'description': "Number of bandwidth shares",
221          'category' : 'slice/rspec',
222          'min_role_id': 10},
223         {'tagname': "net_i2_share",
224          'description': "Number of bandwidth shares over I2 routes",
225          'category' : 'slice/rspec',
226          'min_role_id': 10},
227  
228         # Disk quota
229         {'tagname': "disk_max",
230          'description': "Disk quota (1k disk blocks)",
231          'category' : 'slice/rspec',
232          'min_role_id': 10},
233
234         # Proper operations
235         {'tagname': "proper_op",
236          'description': "Proper operation (e.g. bind_socket)",
237          'category' : 'slice/rspec',
238          'min_role_id': 10},
239
240         # VServer capabilities 
241         {'tagname': "capabilities",
242          'description': "VServer bcapabilities (separate by commas)",
243          'category' : 'slice/rspec',
244          'min_role_id': 10},
245
246         # Vsys
247         {'tagname': "vsys",
248          'description': "Bind vsys script fd's to a slice's vsys directory.",
249          'category' : 'slice/rspec',
250          'min_role_id': 10},
251
252         # CoDemux
253         {'tagname': "codemux",
254          'description': "Demux HTTP between slices using localhost ports. Value in the form 'host, localhost port'.",
255          'category' : 'slice/rspec',
256          'min_role_id': 10},
257
258         # Delegation
259         {'tagname': "delegations",
260          'description': "Coma seperated list of slices to give delegation authority to.",
261          'category' : 'slice/rspec',
262          'min_role_id': 10}
263
264         ]
265
266     # add in the platform supported rlimits to the default_attribute_types
267     for entry in resource.__dict__.keys() + ["VLIMIT_OPENFD"]:
268         if entry.find("LIMIT_")==1:
269             rlim = entry[len("RLIMIT_"):]
270             rlim = rlim.lower()
271             for ty in ("min","soft","hard"):
272                 attribute = {
273                     'tagname': "%s_%s"%(rlim,ty),
274                     'description': "Per sliver RLIMIT %s_%s."%(rlim,ty),
275                     'category': 'slice/limit',
276                     'min_role_id': 10 #admin
277                     }
278                 default_attribute_types.append(attribute)
279
280     # Get list of existing tag types
281     known_tag_types = [tag_type['tagname'] for tag_type in GetTagTypes()]
282
283     all_default_types = default_node_types + default_setting_types + default_attribute_types
284     # Create/update default slice tag types
285     for default_tag_type in all_default_types:
286         if default_tag_type['tagname'] not in known_tag_types:
287             AddTagType(default_tag_type)
288         else:
289             UpdateTagType(default_tag_type['tagname'], default_tag_type)
290
291     #################### conf files
292
293     # Setup default PlanetLabConf entries
294     default_conf_files = [
295         # NTP configuration
296         {'enabled': True,
297          'source': 'PlanetLabConf/ntp.conf.php',
298          'dest': '/etc/ntp.conf',
299          'file_permissions': '644',
300          'file_owner': 'root',
301          'file_group': 'root',
302          'preinstall_cmd': '',
303          'postinstall_cmd': '/etc/rc.d/init.d/ntpd restart',
304          'error_cmd': '',
305          'ignore_cmd_errors': False,
306          'always_update': False},
307         {'enabled': True,
308          'source': 'PlanetLabConf/ntp/step-tickers.php',
309          'dest': '/etc/ntp/step-tickers',
310          'file_permissions': '644',
311          'file_owner': 'root',
312          'file_group': 'root',
313          'preinstall_cmd': '',
314          'postinstall_cmd': '/etc/rc.d/init.d/ntpd restart',
315          'error_cmd': '',
316          'ignore_cmd_errors': False,
317          'always_update': False},
318
319         # SSH server configuration
320         {'enabled': True,
321          'source': 'PlanetLabConf/sshd_config',
322          'dest': '/etc/ssh/sshd_config',
323          'file_permissions': '600',
324          'file_owner': 'root',
325          'file_group': 'root',
326          'preinstall_cmd': '',
327          'postinstall_cmd': '/etc/init.d/sshd restart',
328          'error_cmd': '',
329          'ignore_cmd_errors': False,
330          'always_update': False},
331
332         # Administrative SSH keys
333         {'enabled': True,
334          'source': 'PlanetLabConf/keys.php?root',
335          'dest': '/root/.ssh/authorized_keys',
336          'file_permissions': '644',
337          'file_owner': 'root',
338          'file_group': 'root',
339          'preinstall_cmd': '',
340          'postinstall_cmd': '/bin/chmod 700 /root/.ssh',
341          'error_cmd': '',
342          'ignore_cmd_errors': False,
343          'always_update': False},
344         {'enabled': True,
345          'source': 'PlanetLabConf/keys.php?site_admin',
346          'dest': '/home/site_admin/.ssh/authorized_keys',
347          'file_permissions': '644',
348          'file_owner': 'site_admin',
349          'file_group': 'site_admin',
350          'preinstall_cmd': 'grep -q site_admin /etc/passwd',
351          'postinstall_cmd': '/bin/chmod 700 /home/site_admin/.ssh',
352          'error_cmd': '',
353          'ignore_cmd_errors': False,
354          'always_update': False},
355         # Log rotation configuration
356         {'enabled': True,
357          'source': 'PlanetLabConf/logrotate.conf',
358          'dest': '/etc/logrotate.conf',
359          'file_permissions': '644',
360          'file_owner': 'root',
361          'file_group': 'root',
362          'preinstall_cmd': '',
363          'postinstall_cmd': '',
364          'error_cmd': '',
365          'ignore_cmd_errors': False,
366          'always_update': False},
367
368         # updatedb/locate nightly cron job
369         {'enabled': True,
370          'source': 'PlanetLabConf/slocate.cron',
371          'dest': '/etc/cron.daily/slocate.cron',
372          'file_permissions': '755',
373          'file_owner': 'root',
374          'file_group': 'root',
375          'preinstall_cmd': '',
376          'postinstall_cmd': '',
377          'error_cmd': '',
378          'ignore_cmd_errors': False,
379          'always_update': False},
380
381         # YUM configuration
382         {'enabled': True,
383          'source': 'yum/myplc.repo.php?gpgcheck=1',
384          'dest': '/etc/yum.myplc.d/myplc.repo',
385          'file_permissions': '644', 'file_owner': 'root', 'file_group': 'root',
386          'preinstall_cmd': '', 'postinstall_cmd': '', 'error_cmd': '',
387          'ignore_cmd_errors': False,
388          'always_update': False},
389         {'enabled': True,
390          'source': 'yum/yum.conf',
391          'dest': '/etc/yum.conf',
392          'file_permissions': '644', 'file_owner': 'root', 'file_group': 'root',
393          'preinstall_cmd': '', 'postinstall_cmd': '', 'error_cmd': '',
394          'ignore_cmd_errors': False,
395          'always_update': False},
396         {'enabled': True,
397          'source': 'yum/stock.repo',
398          'dest': '/etc/yum.myplc.d/stock.repo',
399          'file_permissions': '644', 'file_owner': 'root', 'file_group': 'root',
400          'preinstall_cmd': '', 'postinstall_cmd': '', 'error_cmd': '',
401          'ignore_cmd_errors': False,
402          'always_update': False},
403
404         {'enabled': True,
405          'source': 'PlanetLabConf/delete-rpm-list-production',
406          'dest': '/etc/planetlab/delete-rpm-list',
407          'file_permissions': '644',
408          'file_owner': 'root',
409          'file_group': 'root',
410          'preinstall_cmd': '',
411          'postinstall_cmd': '',
412          'error_cmd': '',
413          'ignore_cmd_errors': False,
414          'always_update': False},
415
416         # PLC configuration
417         {'enabled': True,
418          'source': 'PlanetLabConf/get_plc_config.php',
419          'dest': '/etc/planetlab/plc_config',
420          'file_permissions': '644',
421          'file_owner': 'root',
422          'file_group': 'root',
423          'preinstall_cmd': '',
424          'postinstall_cmd': '',
425          'error_cmd': '',
426          'ignore_cmd_errors': False,
427          'always_update': False},
428         {'enabled': True,
429          'source': 'PlanetLabConf/get_plc_config.php?python',
430          'dest': '/etc/planetlab/plc_config.py',
431          'file_permissions': '644',
432          'file_owner': 'root',
433          'file_group': 'root',
434          'preinstall_cmd': '',
435          'postinstall_cmd': '',
436          'error_cmd': '',
437          'ignore_cmd_errors': False,
438          'always_update': False},
439         {'enabled': True,
440          'source': 'PlanetLabConf/get_plc_config.php?perl',
441          'dest': '/etc/planetlab/plc_config.pl',
442          'file_permissions': '644',
443          'file_owner': 'root',
444          'file_group': 'root',
445          'preinstall_cmd': '',
446          'postinstall_cmd': '',
447          'error_cmd': '',
448          'ignore_cmd_errors': False,
449          'always_update': False},
450         {'enabled': True,
451          'source': 'PlanetLabConf/get_plc_config.php?php',
452          'dest': '/etc/planetlab/php/plc_config.php',
453          'file_permissions': '644',
454          'file_owner': 'root',
455          'file_group': 'root',
456          'preinstall_cmd': '',
457          'postinstall_cmd': '',
458          'error_cmd': '',
459          'ignore_cmd_errors': False,
460          'always_update': False},
461
462         # XXX Required for old Node Manager
463         # Proper configuration
464         {'enabled': True,
465          'source': 'PlanetLabConf/propd.conf',
466          'dest': '/etc/proper/propd.conf',
467          'file_permissions': '644',
468          'file_owner': 'root',
469          'file_group': 'root',
470          'preinstall_cmd': '',
471          'postinstall_cmd': '/etc/init.d/proper restart',
472          'error_cmd': '',
473          'ignore_cmd_errors': True,
474          'always_update': False},
475
476         # XXX Required for old Node Manager
477         # Bandwidth cap
478         {'enabled': True,
479          'source': 'PlanetLabConf/bwlimit.php',
480          'dest': '/etc/planetlab/bwcap',
481          'file_permissions': '644',
482          'file_owner': 'root',
483          'file_group': 'root',
484          'preinstall_cmd': '',
485          'postinstall_cmd': '',
486          'error_cmd': '',
487          'ignore_cmd_errors': True,
488          'always_update': False},
489
490         # Proxy ARP setup
491         {'enabled': True,
492          'source': 'PlanetLabConf/proxies.php',
493          'dest': '/etc/planetlab/proxies',
494          'file_permissions': '644',
495          'file_owner': 'root',
496          'file_group': 'root',
497          'preinstall_cmd': '',
498          'postinstall_cmd': '',
499          'error_cmd': '',
500          'ignore_cmd_errors': False,
501          'always_update': False},
502
503         # Firewall configuration
504         {'enabled': True,
505          'source': 'PlanetLabConf/blacklist.php',
506          'dest': '/etc/planetlab/blacklist',
507          'file_permissions': '600',
508          'file_owner': 'root',
509          'file_group': 'root',
510          'preinstall_cmd': '',
511          'postinstall_cmd': '/sbin/iptables-restore --noflush < /etc/planetlab/blacklist',
512          'error_cmd': '',
513          'ignore_cmd_errors': True,
514          'always_update': False},
515
516         # /etc/issue
517         {'enabled': True,
518          'source': 'PlanetLabConf/issue.php',
519          'dest': '/etc/issue',
520          'file_permissions': '644',
521          'file_owner': 'root',
522          'file_group': 'root',
523          'preinstall_cmd': '',
524          'postinstall_cmd': '',
525          'error_cmd': '',
526          'ignore_cmd_errors': False,
527          'always_update': False},
528
529         # Kernel parameters
530         {'enabled': True,
531          'source': 'PlanetLabConf/sysctl.php',
532          'dest': '/etc/sysctl.conf',
533          'file_permissions': '644',
534          'file_owner': 'root',
535          'file_group': 'root',
536          'preinstall_cmd': '',
537          'postinstall_cmd': '/sbin/sysctl -e -p /etc/sysctl.conf',
538          'error_cmd': '',
539          'ignore_cmd_errors': False,
540          'always_update': False},
541
542         # Sendmail configuration
543         {'enabled': True,
544          'source': 'PlanetLabConf/sendmail.mc',
545          'dest': '/etc/mail/sendmail.mc',
546          'file_permissions': '644',
547          'file_owner': 'root',
548          'file_group': 'root',
549          'preinstall_cmd': '',
550          'postinstall_cmd': '',
551          'error_cmd': '',
552          'ignore_cmd_errors': False,
553          'always_update': False},
554         {'enabled': True,
555          'source': 'PlanetLabConf/sendmail.cf',
556          'dest': '/etc/mail/sendmail.cf',
557          'file_permissions': '644',
558          'file_owner': 'root',
559          'file_group': 'root',
560          'preinstall_cmd': '',
561          'postinstall_cmd': 'service sendmail restart',
562          'error_cmd': '',
563          'ignore_cmd_errors': False,
564          'always_update': False},
565
566         # GPG signing keys
567         {'enabled': True,
568          'source': 'PlanetLabConf/RPM-GPG-KEY-fedora',
569          'dest': '/etc/pki/rpm-gpg/RPM-GPG-KEY-fedora',
570          'file_permissions': '644',
571          'file_owner': 'root',
572          'file_group': 'root',
573          'preinstall_cmd': '',
574          'postinstall_cmd': 'rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora',
575          'error_cmd': '',
576          'ignore_cmd_errors': False,
577          'always_update': False},
578         {'enabled': True,
579          'source': 'PlanetLabConf/get_gpg_key.php',
580          'dest': '/etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab',
581          'file_permissions': '644',
582          'file_owner': 'root',
583          'file_group': 'root',
584          'preinstall_cmd': '',
585          'postinstall_cmd': 'rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab',
586          'error_cmd': '',
587          'ignore_cmd_errors': False,
588          'always_update': False},
589
590         # Ping of death configuration
591         # the 'restart' postcommand doesn't work, b/c the pod script doesn't support it.
592         {'enabled': True,
593          'source': 'PlanetLabConf/ipod.conf.php',
594          'dest': '/etc/ipod.conf',
595          'file_permissions': '644',
596          'file_owner': 'root',
597          'file_group': 'root',
598          'preinstall_cmd': '',
599          'postinstall_cmd': '/etc/init.d/pod start',
600          'error_cmd': '',
601          'ignore_cmd_errors': False,
602          'always_update': False},
603
604         # sudo configuration
605         {'enabled': True,
606          'source': 'PlanetLabConf/sudoers.php',
607          'dest': '/etc/sudoers',
608          'file_permissions': '440',
609          'file_owner': 'root',
610          'file_group': 'root',
611          'preinstall_cmd': '',
612          'postinstall_cmd': '/usr/sbin/visudo -c',
613          'error_cmd': '',
614          'ignore_cmd_errors': False,
615          'always_update': False}
616         ]
617
618     # Get list of existing (enabled, global) files
619     conf_files = GetConfFiles()
620     conf_files = filter(lambda conf_file: conf_file['enabled'] and \
621                                           not conf_file['node_ids'] and \
622                                           not conf_file['nodegroup_ids'],
623                         conf_files)
624     dests = [conf_file['dest'] for conf_file in conf_files]
625     conf_files = dict(zip(dests, conf_files))
626
627     # Create/update default PlanetLabConf entries
628     for default_conf_file in default_conf_files:
629         if default_conf_file['dest'] not in dests:
630             AddConfFile(default_conf_file)
631         else:
632             conf_file = conf_files[default_conf_file['dest']]
633             UpdateConfFile(conf_file['conf_file_id'], default_conf_file)
634
635
636     #################### initscripts
637
638     # Default Initscripts
639     default_initscripts = []
640
641     # Find initscripts and add them to the db
642     for (root, dirs, files) in os.walk("/etc/plc_sliceinitscripts"):
643         for f in files:
644             # Read the file
645             file = open(root + "/" + f, "ro")
646             default_initscripts.append({"name": plc['slice_prefix'] + "_" + f,
647                                         "enabled": True,
648                                         "script": file.read().replace("@SITE@", url).replace("@PREFIX@", plc['slice_prefix'])})
649             file.close()
650
651     # Get list of existing initscripts
652     oldinitscripts = GetInitScripts()
653     oldinitscripts = [script['name'] for script in oldinitscripts]
654
655     for initscript in default_initscripts:
656         if initscript['name'] not in oldinitscripts:  AddInitScript(initscript)
657
658     # Create/update system slices
659     default_slices = [
660          # PlanetFlow
661         {'name': plc['slice_prefix'] + "_netflow",
662          'description': "PlanetFlow Traffic Auditing Service.  Logs, captured in the root context using fprobe-ulogd, are stored in a directory in the root context which is bind mounted to the planetflow slice.  The Planetflow Central service then periodically rsyncs these logs from the planetflow slice for aggregation.",
663          'url': url,
664          'instantiation': "plc-instantiated",
665          # Renew forever (minus one day, work around date conversion weirdness)
666          'expires': 0x7fffffff - (60 * 60 * 24),
667          'attributes': [('system', "1"),
668                         ('vref', "planetflow"),
669                         ('vsys', "pfmount")]},
670           # Sirius
671         {'name': plc['slice_prefix'] + "_sirius",
672          'description': 'The Sirius Calendar Service.\n\nSirius provides system-wide reservations of 25% CPU and 2Mb/s outgoing\nbandwidth.  Sign up for hour-long slots using the Web GUI at the\nPlanetLab website.\n\nThis slice should not generate traffic external to PlanetLab.\n',
673          'url': url + "db/sirius/index.php",
674          'instantiation': "plc-instantiated",
675          # Renew forever (minus one day, work around date conversion weirdness)
676          'expires': 0x7fffffff - (60 * 60 * 24),
677          'attributes': [('system', "1"),
678                         ('net_min_rate', "2000"),
679                         ('cpu_pct', "25"),
680                         ('initscript', plc['slice_prefix'] + "_sirius")]}
681         ]
682     
683     for default_slice in default_slices:
684         attributes=default_slice.pop('attributes')
685         slices = GetSlices([default_slice['name']])
686         if slices:
687             slice = slices[0]
688             UpdateSlice(slice['slice_id'], default_slice)
689         else:
690             AddSlice(default_slice)
691             slice = GetSlices([default_slice['name']])[0]
692
693         # Create/update all attributes
694         slice_tags = []
695         if slice['slice_tag_ids']:
696             # Delete unknown attributes
697             for slice_tag in GetSliceTags(slice['slice_tag_ids']):
698                 if (slice_tag['tagname'], slice_tag['value']) \
699                    not in attributes:
700                     DeleteSliceTag(slice_tag['slice_tag_id'])
701                 else:
702                     slice_tags.append((slice_tag['tagname'], slice_tag['value']))
703
704         for (name, value) in attributes:
705             if (name, value) not in slice_tags:
706                 AddSliceTag(slice['name'], name, value)
707
708     
709     #################### body for messages
710
711     installfailed = """
712 Once the node meets these requirements, please reinitiate the install
713 by visiting:
714
715 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
716
717 Update the BootState to 'Reinstall', then reboot the node.
718
719 If you have already performed this step and are still receiving this
720 message, please reply so that we may investigate the problem.
721 """
722
723     # Load default message templates
724     message_templates = [
725         {'message_id': 'Verify account',
726          'subject': "Verify account registration",
727          'template': """
728 Please verify that you registered for a %(PLC_NAME)s account with the
729 username %(email)s by visiting:
730
731 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/register.php?id=%(person_id)d&key=%(verification_key)s
732
733 You must wait for this account to be approved before you can begin using it, please be patient.
734
735 If you did not register for a %(PLC_NAME)s account, please ignore this
736 message, or contact %(PLC_NAME)s Support <%(PLC_MAIL_SUPPORT_ADDRESS)s>.
737 """
738          },
739
740         {'message_id': 'New PI account',
741          'subject': "New PI account registration from %(first_name)s %(last_name)s <%(email)s> at %(site_name)s",
742          'template': """
743 %(first_name)s %(last_name)s <%(email)s> has signed up for a new
744 %(PLC_NAME)s account at %(site_name)s and has requested a PI role. PIs
745 are responsible for enabling user accounts, creating slices, and
746 ensuring that all users abide by the %(PLC_NAME)s Acceptable Use
747 Policy.
748
749 Only %(PLC_NAME)s administrators may enable new PI accounts. If you
750 are a PI at %(site_name)s, please respond and indicate whether this
751 registration is acceptable.
752
753 To view the request, visit:
754
755 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/index.php?id=%(person_id)d
756 """
757          },
758
759         {'message_id': 'New account',
760          'subject': "New account registration from %(first_name)s %(last_name)s <%(email)s> at %(site_name)s",
761          'template': """
762 %(first_name)s %(last_name)s <%(email)s> has signed up for a new
763 %(PLC_NAME)s account at %(site_name)s and has requested the following
764 roles: %(roles)s.
765
766 To deny the request or enable the account, visit:
767
768 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/index.php?id=%(person_id)d
769 """
770          },
771
772         {'message_id': 'Password reset requested',
773          'subject': "Password reset requested",
774          'template': """
775 Someone has requested that the password of your %(PLC_NAME)s account
776 %(email)s be reset. If this person was you, you may continue with the
777 reset by visiting:
778
779 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/reset_password.php?id=%(person_id)d&key=%(verification_key)s
780
781 If you did not request that your password be reset, please contact
782 %(PLC_NAME)s Support <%(PLC_MAIL_SUPPORT_ADDRESS)s>. Do not quote or
783 otherwise include any of this text in any correspondence.
784 """
785          },
786
787         {'message_id': 'Password reset',
788          'subject': "Password reset",
789          'template': """
790 The password of your %(PLC_NAME)s account %(email)s has been
791 temporarily reset to:
792
793 %(password)s
794
795 Please change it at as soon as possible by visiting:
796
797 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/index.php?id=%(person_id)d
798
799 If you did not request that your password be reset, please contact
800 %(PLC_NAME)s Support <%(PLC_MAIL_SUPPORT_ADDRESS)s>. Do not quote or
801 otherwise include any of this text in any correspondence.
802 """
803          },
804
805         # Boot Manager messages
806         {'message_id': "installfinished",
807          'subject': "%(hostname)s completed installation",
808          'template': """
809 %(hostname)s just completed installation.
810
811 The node should be usable in a couple of minutes if installation was
812 successful.
813 """
814          },
815
816         {'message_id': "insufficientdisk",
817          'subject': "%(hostname)s does not have sufficient disk space",
818          'template': """
819 %(hostname)s failed to boot because it does not have sufficent disk
820 space, or because its disk controller was not recognized.
821
822 Please replace the current disk or disk controller or install
823 additional disks to meet the current hardware requirements.
824 """ + installfailed
825          },
826
827         {'message_id': "insufficientmemory",
828          'subject': "%(hostname)s does not have sufficient memory",
829          'template': """
830 %(hostname)s failed to boot because it does not have sufficent
831 memory.
832
833 Please install additional memory to meet the current hardware
834 requirements.
835 """ + installfailed
836          },
837
838         {'message_id': "authfail",
839          'subject': "%(hostname)s failed to authenticate",
840          'template':
841 """
842 %(hostname)s failed to authenticate for the following reason:
843
844 %(fault)s
845
846 The most common reason for authentication failure is that the
847 authentication key stored in the node configuration file, does not
848 match the key on record. 
849
850 There are two possible steps to resolve the problem.
851
852 1. If you have used an All-in-one BootCD that includes the plnode.txt file,
853     then please check your machine for any old boot media, either in the
854     floppy drive, or on a USB stick.  It is likely that an old configuration
855     is being used instead of the new configuration stored on the BootCD.
856 Or, 
857 2. If you are using Generic BootCD image, then regenerate the node 
858     configuration file by visiting:
859
860     https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
861
862     Under 'Download', follow the 'Download plnode.txt file for %(hostname)s'
863     option, and save the downloaded file as plnode.txt on either a floppy 
864     disk or a USB flash drive.  Be sure the 'Boot State' is set to 'Boot', 
865     and, then reboot the node.
866
867 If you have already performed this step and are still receiving this
868 message, please reply so that we can help investigate the problem.
869 """
870          },
871
872         {'message_id': "notinstalled",
873          'subject': "%(hostname)s is not installed",
874          'template':
875 """
876 %(hostname)s failed to boot because it has either never been
877 installed, or the installation is corrupt.
878
879 Please check if the hard drive has failed, and replace it if so. After
880 doing so, visit:
881
882 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
883
884 Change the 'Boot State' to 'Reinstall', and then reboot the node.
885
886 If you have already performed this step and are still receiving this
887 message, please reply so that we may investigate the problem.
888 """
889          },
890
891         {'message_id': "hostnamenotresolve",
892          'subject': "%(hostname)s does not resolve",
893          'template':
894 """
895 %(hostname)s failed to boot because its hostname does not resolve, or
896 does resolve but does not match its configured IP address.
897
898 Please check the network settings for the node, especially its
899 hostname, IP address, and DNS servers, by visiting:
900
901 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
902
903 Correct any errors, and change the 'Boot State' to 'Reinstall', and then
904 reboot the node.
905
906 If you have already performed this step and are still receiving this
907 message, please reply so that we may investigate the problem.
908 """
909          },
910
911         # XXX N.B. I don't think these are necessary, since there's no
912         # way that the Boot Manager would even be able to contact the
913         # API to send these messages.
914
915         {'message_id': "noconfig",
916          'subject': "%(hostname)s does not have a configuration file",
917          'template': """
918 %(hostname)s failed to boot because it could not find a PlanetLab
919 configuration file. To create this file, visit:
920
921 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
922
923 Click the Configuration File link, and save the downloaded file as
924 plnode.txt on either a floppy disk or a USB flash drive.  Change the 
925 'Boot State' to 'Reinstall', and then reboot the node.
926
927 If you have already performed this step and are still receiving this
928 message, please reply so that we may investigate the problem.
929 """
930          },
931
932         {'message_id': "nodetectednetwork",
933          'subject': "%(hostname)s has unsupported network hardware",
934          'template':
935 """
936
937 %(hostname)s failed to boot because it has network hardware that is
938 unsupported by the current production kernel. If it has booted
939 successfully in the past, please try re-installing it by visiting:
940
941 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
942
943 Change the 'Boot State' to 'Reinstall', and then reboot the node.
944
945 If you have already performed this step and are still receiving this
946 message, please reply so that we may investigate the problem.
947 """
948          },
949         ]
950
951     for template in message_templates:
952         messages = GetMessages([template['message_id']])
953         if not messages:
954             AddMessage(template)
955
956     #################### PCUs
957     
958     ### Setup Initial PCU information
959     pcu_types = [{'model': 'AP79xx',
960           'name': 'APC AP79xx',
961           'pcu_protocol_types': [{ 'port': 80,
962                                   'protocol': 'APC79xxHttp',
963                                   'supported': False},
964                                  { 'port': 23,
965                                   'protocol': 'APC79xx',
966                                   'supported': True},
967                                  { 'port': 22,
968                                   'protocol': 'APC79xx',
969                                   'supported': True}],
970           },
971          {'model': 'Masterswitch',
972           'name': 'APC Masterswitch',
973           'pcu_protocol_types': [{ 'port': 80,
974                                   'protocol': 'APCMasterHttp',
975                                   'supported': False},
976                                  { 'port': 23,
977                                   'protocol': 'APCMaster',
978                                   'supported': True},
979                                  { 'port': 22,
980                                   'protocol': 'APCMaster',
981                                   'supported': True}],
982           },
983          {'model': 'DS4-RPC',
984           'name': 'BayTech DS4-RPC',
985           'pcu_protocol_types': [{ 'port': 80,
986                                   'protocol': 'BayTechHttp',
987                                   'supported': False},
988                                  { 'port': 23,
989                                   'protocol': 'BayTech',
990                                   'supported': True},
991                                  { 'port': 22,
992                                   'protocol': 'BayTech',
993                                   'supported': True}],
994           },
995          {'model': 'IP-41x_IP-81x',
996           'name': 'Dataprobe IP-41x & IP-81x',
997           'pcu_protocol_types': [ { 'port': 23,
998                                   'protocol': 'IPALTelnet',
999                                   'supported': True},
1000                                   { 'port': 80,
1001                                   'protocol': 'IPALHttp',
1002                                   'supported': False}],
1003           },
1004          {'model': 'DRAC3',
1005           'name': 'Dell RAC Version 3',
1006           'pcu_protocol_types': [],
1007           },
1008          {'model': 'DRAC4',
1009           'name': 'Dell RAC Version 4',
1010           'pcu_protocol_types': [{ 'port': 443,
1011                                   'protocol': 'DRACRacAdm',
1012                                   'supported': True},
1013                                  { 'port': 80,
1014                                   'protocol': 'DRACRacAdm',
1015                                   'supported': False},
1016                                  { 'port': 22,
1017                                   'protocol': 'DRAC',
1018                                   'supported': True}],
1019           },
1020          {'model': 'ePowerSwitch',
1021           'name': 'ePowerSwitch 1/4/8x',
1022           'pcu_protocol_types': [{ 'port': 80,
1023                                   'protocol': 'ePowerSwitch',
1024                                   'supported': True}],
1025           },
1026          {'model': 'ilo2',
1027           'name': 'HP iLO2 (Integrated Lights-Out)',
1028           'pcu_protocol_types': [{ 'port': 443,
1029                                   'protocol': 'HPiLOHttps',
1030                                   'supported': True},
1031                                  { 'port': 22,
1032                                   'protocol': 'HPiLO',
1033                                   'supported': True}],
1034           },
1035          {'model': 'ilo1',
1036           'name': 'HP iLO version 1',
1037           'pcu_protocol_types': [],
1038           },
1039          {'model': 'PM211-MIP',
1040           'name': 'Infratec PM221-MIP',
1041           'pcu_protocol_types': [],
1042           },
1043          {'model': 'AMT2.5',
1044           'name': 'Intel AMT v2.5 (Active Management Technology)',
1045           'pcu_protocol_types': [],
1046           },
1047          {'model': 'AMT3.0',
1048           'name': 'Intel AMT v3.0 (Active Management Technology)',
1049           'pcu_protocol_types': [],
1050           },
1051          {'model': 'WTI_IPS-4',
1052           'name': 'Western Telematic (WTI IPS-4)',
1053           'pcu_protocol_types': [],
1054           },
1055          {'model': 'unknown',
1056           'name': 'Unknown Vendor or Model',
1057           'pcu_protocol_types': [{ 'port': 443,
1058                                   'protocol': 'UnknownPCU',
1059                                   'supported': False},
1060                                  { 'port': 80,
1061                                   'protocol': 'UnknownPCU',
1062                                   'supported': False},
1063                                  { 'port': 23,
1064                                   'protocol': 'UnknownPCU',
1065                                   'supported': False},
1066                                  { 'port': 22,
1067                                   'protocol': 'UnknownPCU',
1068                                   'supported': False}],
1069           }]
1070
1071     # Get all model names
1072     pcu_models = [type['model'] for type in GetPCUTypes()]
1073     for type in pcu_types:
1074         protocol_types = type['pcu_protocol_types']
1075         # Take this value out of the struct.
1076         del type['pcu_protocol_types']
1077         if type['model'] not in pcu_models:
1078             # Add the name/model info into DB
1079             id = AddPCUType(type)
1080             # for each protocol, also add this.
1081             for ptype in protocol_types:
1082                 AddPCUProtocolType(id, ptype)
1083
1084     default_boot_states = [
1085         'boot',
1086         'failboot',
1087         'safeboot',
1088         'install',
1089         'reinstall',
1090         'disabled',
1091     ]
1092     current_boot_states = GetBootStates()
1093     for state in default_boot_states:
1094         if state not in current_boot_states:
1095             AddBootState(state)
1096
1097     # TODO: Delete old boot states. 
1098     # NOTE: Only do this if all federating peers have the new default boot states above.
1099     #for state in current_boot_states:
1100     #    if state not in default_boot_states:
1101     #        DeleteBootState(state)
1102
1103     # Run local db-config snippets
1104     files = []
1105     dir = "/etc/planetlab/db-config.d"
1106     try:
1107         files = os.listdir(dir)
1108     except:
1109         pass
1110
1111     for file in files:
1112         if (file.endswith(".bak") or file.endswith("~") or
1113             file.endswith(".rpmsave") or file.endswith(".rpmnew") or
1114             file.endswith(".orig")):
1115             continue
1116         execfile(os.path.join(dir, file))
1117
1118
1119 if __name__ == '__main__':
1120     main()
1121
1122 # Local variables:
1123 # tab-width: 4
1124 # mode: python
1125 # End: