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