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