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