Added head url keyword.
[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     # Setup default PlanetLabConf entries
84     default_conf_files = [
85         # NTP configuration
86         {'enabled': True,
87          'source': 'PlanetLabConf/ntp.conf.php',
88          'dest': '/etc/ntp.conf',
89          'file_permissions': '644',
90          'file_owner': 'root',
91          'file_group': 'root',
92          'preinstall_cmd': '',
93          'postinstall_cmd': '/etc/rc.d/init.d/ntpd restart',
94          'error_cmd': '',
95          'ignore_cmd_errors': False,
96          'always_update': False},
97         {'enabled': True,
98          'source': 'PlanetLabConf/ntp/step-tickers.php',
99          'dest': '/etc/ntp/step-tickers',
100          'file_permissions': '644',
101          'file_owner': 'root',
102          'file_group': 'root',
103          'preinstall_cmd': '',
104          'postinstall_cmd': '/etc/rc.d/init.d/ntpd restart',
105          'error_cmd': '',
106          'ignore_cmd_errors': False,
107          'always_update': False},
108
109         # SSH server configuration
110         {'enabled': True,
111          'source': 'PlanetLabConf/sshd_config',
112          'dest': '/etc/ssh/sshd_config',
113          'file_permissions': '600',
114          'file_owner': 'root',
115          'file_group': 'root',
116          'preinstall_cmd': '',
117          'postinstall_cmd': '/etc/init.d/sshd restart',
118          'error_cmd': '',
119          'ignore_cmd_errors': False,
120          'always_update': False},
121
122         # Administrative SSH keys
123         {'enabled': True,
124          'source': 'PlanetLabConf/keys.php?root',
125          'dest': '/root/.ssh/authorized_keys',
126          'file_permissions': '644',
127          'file_owner': 'root',
128          'file_group': 'root',
129          'preinstall_cmd': '',
130          'postinstall_cmd': '/bin/chmod 700 /root/.ssh',
131          'error_cmd': '',
132          'ignore_cmd_errors': False,
133          'always_update': False},
134         {'enabled': True,
135          'source': 'PlanetLabConf/keys.php?site_admin',
136          'dest': '/home/site_admin/.ssh/authorized_keys',
137          'file_permissions': '644',
138          'file_owner': 'site_admin',
139          'file_group': 'site_admin',
140          'preinstall_cmd': 'grep -q site_admin /etc/passwd',
141          'postinstall_cmd': '/bin/chmod 700 /home/site_admin/.ssh',
142          'error_cmd': '',
143          'ignore_cmd_errors': False,
144          'always_update': False},
145         {'enabled': True,
146          'source': 'PlanetLabConf/keys.php?role=admin',
147          'dest': '/home/pl_admin/.ssh/authorized_keys',
148          'file_permissions': '644',
149          'file_owner': 'pl_admin',
150          'file_group': 'pl_admin',
151          'preinstall_cmd': 'grep -q pl_admin /etc/passwd',
152          'postinstall_cmd': '/bin/chmod 700 /home/pl_admin/.ssh',
153          'error_cmd': '',
154          'ignore_cmd_errors': False,
155          'always_update': False},
156
157         # Log rotation configuration
158         {'enabled': True,
159          'source': 'PlanetLabConf/logrotate.conf',
160          'dest': '/etc/logrotate.conf',
161          'file_permissions': '644',
162          'file_owner': 'root',
163          'file_group': 'root',
164          'preinstall_cmd': '',
165          'postinstall_cmd': '',
166          'error_cmd': '',
167          'ignore_cmd_errors': False,
168          'always_update': False},
169
170         # updatedb/locate nightly cron job
171         {'enabled': True,
172          'source': 'PlanetLabConf/slocate.cron',
173          'dest': '/etc/cron.daily/slocate.cron',
174          'file_permissions': '755',
175          'file_owner': 'root',
176          'file_group': 'root',
177          'preinstall_cmd': '',
178          'postinstall_cmd': '',
179          'error_cmd': '',
180          'ignore_cmd_errors': False,
181          'always_update': False},
182
183         # YUM configuration
184         {'enabled': True,
185          'source': 'PlanetLabConf/yum.conf.php?gpgcheck=1',
186          'dest': '/etc/yum.conf',
187          'file_permissions': '644',
188          'file_owner': 'root',
189          'file_group': 'root',
190          'preinstall_cmd': '',
191          'postinstall_cmd': '',
192          'error_cmd': '',
193          'ignore_cmd_errors': False,
194          'always_update': False},
195         {'enabled': True,
196          'source': 'PlanetLabConf/delete-rpm-list-production',
197          'dest': '/etc/planetlab/delete-rpm-list',
198          'file_permissions': '644',
199          'file_owner': 'root',
200          'file_group': 'root',
201          'preinstall_cmd': '',
202          'postinstall_cmd': '',
203          'error_cmd': '',
204          'ignore_cmd_errors': False,
205          'always_update': False},
206
207         # PLC configuration
208         {'enabled': True,
209          'source': 'PlanetLabConf/get_plc_config.php',
210          'dest': '/etc/planetlab/plc_config',
211          'file_permissions': '644',
212          'file_owner': 'root',
213          'file_group': 'root',
214          'preinstall_cmd': '',
215          'postinstall_cmd': '',
216          'error_cmd': '',
217          'ignore_cmd_errors': False,
218          'always_update': False},
219         {'enabled': True,
220          'source': 'PlanetLabConf/get_plc_config.php?python',
221          'dest': '/etc/planetlab/plc_config.py',
222          'file_permissions': '644',
223          'file_owner': 'root',
224          'file_group': 'root',
225          'preinstall_cmd': '',
226          'postinstall_cmd': '',
227          'error_cmd': '',
228          'ignore_cmd_errors': False,
229          'always_update': False},
230         {'enabled': True,
231          'source': 'PlanetLabConf/get_plc_config.php?perl',
232          'dest': '/etc/planetlab/plc_config.pl',
233          'file_permissions': '644',
234          'file_owner': 'root',
235          'file_group': 'root',
236          'preinstall_cmd': '',
237          'postinstall_cmd': '',
238          'error_cmd': '',
239          'ignore_cmd_errors': False,
240          'always_update': False},
241         {'enabled': True,
242          'source': 'PlanetLabConf/get_plc_config.php?php',
243          'dest': '/etc/planetlab/php/plc_config.php',
244          'file_permissions': '644',
245          'file_owner': 'root',
246          'file_group': 'root',
247          'preinstall_cmd': '',
248          'postinstall_cmd': '',
249          'error_cmd': '',
250          'ignore_cmd_errors': False,
251          'always_update': False},
252
253         # XXX Required for old Node Manager
254         # Proper configuration
255         {'enabled': True,
256          'source': 'PlanetLabConf/propd.conf',
257          'dest': '/etc/proper/propd.conf',
258          'file_permissions': '644',
259          'file_owner': 'root',
260          'file_group': 'root',
261          'preinstall_cmd': '',
262          'postinstall_cmd': '/etc/init.d/proper restart',
263          'error_cmd': '',
264          'ignore_cmd_errors': True,
265          'always_update': False},
266
267         # XXX Required for old Node Manager
268         # Bandwidth cap
269         {'enabled': True,
270          'source': 'PlanetLabConf/bwlimit.php',
271          'dest': '/etc/planetlab/bwcap',
272          'file_permissions': '644',
273          'file_owner': 'root',
274          'file_group': 'root',
275          'preinstall_cmd': '',
276          'postinstall_cmd': '',
277          'error_cmd': '',
278          'ignore_cmd_errors': True,
279          'always_update': False},
280
281         # Proxy ARP setup
282         {'enabled': True,
283          'source': 'PlanetLabConf/proxies.php',
284          'dest': '/etc/planetlab/proxies',
285          'file_permissions': '644',
286          'file_owner': 'root',
287          'file_group': 'root',
288          'preinstall_cmd': '',
289          'postinstall_cmd': '',
290          'error_cmd': '',
291          'ignore_cmd_errors': False,
292          'always_update': False},
293
294         # Firewall configuration
295         {'enabled': True,
296          'source': 'PlanetLabConf/iptables',
297          'dest': '/etc/sysconfig/iptables',
298          'file_permissions': '600',
299          'file_owner': 'root',
300          'file_group': 'root',
301          'preinstall_cmd': '',
302          'postinstall_cmd': '',
303          'error_cmd': '',
304          'ignore_cmd_errors': False,
305          'always_update': False},
306         {'enabled': True,
307          'source': 'PlanetLabConf/blacklist.php',
308          'dest': '/etc/planetlab/blacklist',
309          'file_permissions': '600',
310          'file_owner': 'root',
311          'file_group': 'root',
312          'preinstall_cmd': '',
313          'postinstall_cmd': '/sbin/iptables-restore --noflush < /etc/planetlab/blacklist',
314          'error_cmd': '',
315          'ignore_cmd_errors': True,
316          'always_update': False},
317
318         # /etc/issue
319         {'enabled': True,
320          'source': 'PlanetLabConf/issue.php',
321          'dest': '/etc/issue',
322          'file_permissions': '644',
323          'file_owner': 'root',
324          'file_group': 'root',
325          'preinstall_cmd': '',
326          'postinstall_cmd': '',
327          'error_cmd': '',
328          'ignore_cmd_errors': False,
329          'always_update': False},
330
331         # Kernel parameters
332         {'enabled': True,
333          'source': 'PlanetLabConf/sysctl.php',
334          'dest': '/etc/sysctl.conf',
335          'file_permissions': '644',
336          'file_owner': 'root',
337          'file_group': 'root',
338          'preinstall_cmd': '',
339          'postinstall_cmd': '/sbin/sysctl -e -p /etc/sysctl.conf',
340          'error_cmd': '',
341          'ignore_cmd_errors': False,
342          'always_update': False},
343
344         # Sendmail configuration
345         {'enabled': True,
346          'source': 'PlanetLabConf/sendmail.mc',
347          'dest': '/etc/mail/sendmail.mc',
348          'file_permissions': '644',
349          'file_owner': 'root',
350          'file_group': 'root',
351          'preinstall_cmd': '',
352          'postinstall_cmd': '',
353          'error_cmd': '',
354          'ignore_cmd_errors': False,
355          'always_update': False},
356         {'enabled': True,
357          'source': 'PlanetLabConf/sendmail.cf',
358          'dest': '/etc/mail/sendmail.cf',
359          'file_permissions': '644',
360          'file_owner': 'root',
361          'file_group': 'root',
362          'preinstall_cmd': '',
363          'postinstall_cmd': 'service sendmail restart',
364          'error_cmd': '',
365          'ignore_cmd_errors': False,
366          'always_update': False},
367
368         # GPG signing keys
369         {'enabled': True,
370          'source': 'PlanetLabConf/RPM-GPG-KEY-fedora',
371          'dest': '/etc/pki/rpm-gpg/RPM-GPG-KEY-fedora',
372          'file_permissions': '644',
373          'file_owner': 'root',
374          'file_group': 'root',
375          'preinstall_cmd': '',
376          'postinstall_cmd': 'rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora',
377          'error_cmd': '',
378          'ignore_cmd_errors': False,
379          'always_update': False},
380         {'enabled': True,
381          'source': 'PlanetLabConf/get_gpg_key.php',
382          'dest': '/etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab',
383          'file_permissions': '644',
384          'file_owner': 'root',
385          'file_group': 'root',
386          'preinstall_cmd': '',
387          'postinstall_cmd': 'rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-planetlab',
388          'error_cmd': '',
389          'ignore_cmd_errors': False,
390          'always_update': False},
391
392         # Ping of death configuration
393         # the 'restart' postcommand doesn't work, b/c the pod script doesn't support it.
394         {'enabled': True,
395          'source': 'PlanetLabConf/ipod.conf.php',
396          'dest': '/etc/ipod.conf',
397          'file_permissions': '644',
398          'file_owner': 'root',
399          'file_group': 'root',
400          'preinstall_cmd': '',
401          'postinstall_cmd': '/etc/init.d/pod start',
402          'error_cmd': '',
403          'ignore_cmd_errors': False,
404          'always_update': False},
405
406         # sudo configuration
407         {'enabled': True,
408          'source': 'PlanetLabConf/sudoers',
409          'dest': '/etc/sudoers',
410          'file_permissions': '440',
411          'file_owner': 'root',
412          'file_group': 'root',
413          'preinstall_cmd': '',
414          'postinstall_cmd': '/usr/sbin/visudo -c',
415          'error_cmd': '',
416          'ignore_cmd_errors': False,
417          'always_update': False}
418         ]
419
420     # Get list of existing (enabled, global) files
421     conf_files = GetConfFiles()
422     conf_files = filter(lambda conf_file: conf_file['enabled'] and \
423                                           not conf_file['node_ids'] and \
424                                           not conf_file['nodegroup_ids'],
425                         conf_files)
426     dests = [conf_file['dest'] for conf_file in conf_files]
427     conf_files = dict(zip(dests, conf_files))
428
429     # Create/update default PlanetLabConf entries
430     for default_conf_file in default_conf_files:
431         if default_conf_file['dest'] not in dests:
432             AddConfFile(default_conf_file)
433         else:
434             conf_file = conf_files[default_conf_file['dest']]
435             UpdateConfFile(conf_file['conf_file_id'], default_conf_file)
436
437     # Setup default slice attribute types
438     default_attribute_types = [
439         # Slice type (only vserver is supported)
440         {'name': "type",
441          'description': "Type of slice (e.g. vserver)",
442          'min_role_id': 20},
443
444         # System slice
445         {'name': "system",
446          'description': "Is a default system slice (1) or not (0 or unset)",
447          'min_role_id': 10},
448
449         # Slice enabled (1) or suspended (0)
450         {'name': "enabled",
451          'description': "Slice enabled (1 or unset) or suspended (0)",
452          'min_role_id': 10},
453
454         # Slice reference image
455         {'name': "vref",
456          'description': "Reference image",
457          'min_role_id': 30},
458
459         # Slice initialization script
460         {'name': "initscript",
461          'description': "Slice initialization script",
462          'min_role_id': 10},
463
464         # CPU share
465         {'name': "cpu_min",
466          'description': "Minimum CPU share (ms/s)",
467          'min_role_id': 10},
468         {'name': "cpu_share",
469          'description': "Number of CPU shares",
470          'min_role_id': 10},
471
472         # Bandwidth limits
473         {'name': "net_min_rate",
474          'description': "Minimum bandwidth (kbps)",
475          'min_role_id': 10},
476         {'name': "net_max_rate",
477          'description': "Maximum bandwidth (kbps)",
478          'min_role_id': 10},
479         {'name': "net_i2_min_rate",
480          'description': "Minimum bandwidth over I2 routes (kbps)",
481          'min_role_id': 10},
482         {'name': "net_i2_max_rate",
483          'description': "Maximum bandwidth over I2 routes (kbps)",
484          'min_role_id': 10},
485         {'name': "net_max_kbyte",
486          'description': "Maximum daily network Tx KByte limit.",
487          'min_role_id': 10},
488         {'name': "net_thresh_kbyte",
489          'description': "KByte limit before warning and throttling.",
490          'min_role_id': 10},
491         {'name': "net_i2_max_kbyte",
492          'description': "Maximum daily network Tx KByte limit to I2 hosts.",
493          'min_role_id': 10},
494         {'name': "net_i2_thresh_kbyte",
495          'description': "KByte limit to I2 hosts before warning and throttling.",
496          'min_role_id': 10},
497         {'name': "net_share",
498          'description': "Number of bandwidth shares",
499          'min_role_id': 10},
500         {'name': "net_i2_share",
501          'description': "Number of bandwidth shares over I2 routes",
502          'min_role_id': 10},
503  
504         # Disk quota
505         {'name': "disk_max",
506          'description': "Disk quota (1k disk blocks)",
507          'min_role_id': 10},
508
509         # Proper operations
510         {'name': "proper_op",
511          'description': "Proper operation (e.g. bind_socket)",
512          'min_role_id': 10},
513
514         # XXX Required for old Node Manager
515         # Special attributes applicable to Slice Creation Service (pl_conf) slice
516         {'name': "plc_slice_type",
517          'description': "Type of slice rspec to be created",
518          'min_role_id': 20},
519         {'name': "plc_agent_version",
520          'description': "Version of PLC agent (slice creation service) software to be deployed",
521          'min_role_id': 10},
522         {'name': "plc_ticket_pubkey",
523          'description': "Public key used to verify PLC-signed tickets",
524          'min_role_id': 10}
525         ]
526
527     # Get list of existing attribute types
528     attribute_types = GetSliceAttributeTypes()
529     attribute_types = [attribute_type['name'] for attribute_type in attribute_types]
530
531     # Create/update default slice attribute types
532     for default_attribute_type in default_attribute_types:
533         if default_attribute_type['name'] not in attribute_types:
534             AddSliceAttributeType(default_attribute_type)
535         else:
536             UpdateSliceAttributeType(default_attribute_type['name'], default_attribute_type)
537
538     # Create/update system slices
539     legacy_slices = [
540         # XXX Required for old Node Manager
541         {'name': "pl_conf",
542          'description': "PlanetLab Slice Creation Service (SCS)",
543          'url': url,
544          'instantiation': "plc-instantiated",
545          # Renew forever
546          'expires': sys.maxint,
547          'attributes': [('plc_slice_type', "VServerSlice"),
548                         ('plc_agent_version', "1.0"),
549                         ('plc_ticket_pubkey', "")]},
550
551         # XXX Required for old Node Manager
552         {'name': "pl_conf_vserverslice",
553          'description': "Default attributes for vserver slices",
554          'url': url,
555          'instantiation': "plc-instantiated",
556          # Renew forever
557          'expires': sys.maxint,
558          'attributes': [('cpu_share', "32"),
559                         ('plc_slice_type', "VServerSlice"),
560                         ('disk_max', "5000000")]},
561         ]
562     default_slices = [
563          # PlanetFlow
564         {'name': plc['slice_prefix'] + "_netflow",
565          'description': "PlanetFlow Traffic Auditing Service",
566          'url': url,
567          'instantiation': "plc-instantiated",
568          # Renew forever
569          'expires': sys.maxint,
570          'attributes': [('system', "1"),
571                         ('vref', "planetflow"),
572                         ('proper_op', "open file=/etc/passwd, flags=r"),
573                         ('proper_op', "create_socket"),
574                         ('proper_op', "bind_socket")]},
575         ]
576          
577     ### xxx - to review once new node manager rolls out
578     # if PLC_SLICE_PREFIX is left to default - this is meant for the public PL only
579     if plc['slice_prefix'] == 'pl':
580         # create both legacy slices together with netflow through default_slices
581         default_slices += legacy_slices
582     else:
583         # we use another slice prefix : disable legacy slices if already created
584         for legacy_slice in legacy_slices:
585             try:
586                 DeleteSlice(legacy_slice['name'])
587             except:
588                 pass
589     
590     for default_slice in default_slices:
591         slices = GetSlices([default_slice['name']])
592         if slices:
593             slice = slices[0]
594             UpdateSlice(slice['slice_id'], default_slice)
595         else:
596             AddSlice(default_slice)
597             slice = GetSlices([default_slice['name']])[0]
598
599         # Create/update all attributes
600         slice_attributes = []
601         if slice['slice_attribute_ids']:
602             # Delete unknown attributes
603             for slice_attribute in GetSliceAttributes(slice['slice_attribute_ids']):
604                 if (slice_attribute['name'], slice_attribute['value']) \
605                    not in default_slice['attributes']:
606                     DeleteSliceAttribute(slice_attribute['slice_attribute_id'])
607                 else:
608                     slice_attributes.append((slice_attribute['name'], slice_attribute['value']))
609
610         for (name, value) in default_slice['attributes']:
611             if (name, value) not in slice_attributes:
612                 AddSliceAttribute(slice['name'], name, value)
613
614     installfailed = """
615 Once the node meets these requirements, please reinitiate the install
616 by visiting:
617
618 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
619
620 Update the BootState to 'Reinstall', then reboot the node.
621
622 If you have already performed this step and are still receiving this
623 message, please reply so that we may investigate the problem.
624 """
625
626     # Load default message templates
627     message_templates = [
628         {'message_id': 'Verify account',
629          'subject': "Verify account registration",
630          'template': """
631 Please verify that you registered for a %(PLC_NAME)s account with the
632 username %(email)s by visiting:
633
634 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/register.php?id=%(person_id)d&key=%(verification_key)s
635
636 If you did not register for a %(PLC_NAME)s account, please ignore this
637 message, or contact %(PLC_NAME)s Support <%(PLC_MAIL_SUPPORT_ADDRESS)s>.
638 """
639          },
640
641         {'message_id': 'New PI account',
642          'subject': "New PI account registration from %(first_name)s %(last_name)s <%(email)s> at %(site_name)s",
643          'template': """
644 %(first_name)s %(last_name)s <%(email)s> has signed up for a new
645 %(PLC_NAME)s account at %(site_name)s and has requested a PI role. PIs
646 are responsible for enabling user accounts, creating slices, and
647 ensuring that all users abide by the %(PLC_NAME)s Acceptable Use
648 Policy.
649
650 Only %(PLC_NAME)s administrators may enable new PI accounts. If you
651 are a PI at %(site_name)s, please respond and indicate whether this
652 registration is acceptable.
653
654 To view the request, visit:
655
656 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/index.php?id=%(person_id)d
657 """
658          },
659
660         {'message_id': 'New account',
661          'subject': "New account registration from %(first_name)s %(last_name)s <%(email)s> at %(site_name)s",
662          'template': """
663 %(first_name)s %(last_name)s <%(email)s> has signed up for a new
664 %(PLC_NAME)s account at %(site_name)s and has requested the following
665 roles: %(roles)s.
666
667 To deny the request or enable the account, visit:
668
669 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/index.php?id=%(person_id)d
670 """
671          },
672
673         {'message_id': 'Password reset requested',
674          'subject': "Password reset requested",
675          'template': """
676 Someone has requested that the password of your %(PLC_NAME)s account
677 %(email)s be reset. If this person was you, you may continue with the
678 reset by visiting:
679
680 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/reset_password.php?id=%(person_id)d&key=%(verification_key)s
681
682 If you did not request that your password be reset, please contact
683 %(PLC_NAME)s Support <%(PLC_MAIL_SUPPORT_ADDRESS)s>. Do not quote or
684 otherwise include any of this text in any correspondence.
685 """
686          },
687
688         {'message_id': 'Password reset',
689          'subject': "Password reset",
690          'template': """
691 The password of your %(PLC_NAME)s account %(email)s has been
692 temporarily reset to:
693
694 %(password)s
695
696 Please change it at as soon as possible by visiting:
697
698 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/persons/index.php?id=%(person_id)d
699
700 If you did not request that your password be reset, please contact
701 %(PLC_NAME)s Support <%(PLC_MAIL_SUPPORT_ADDRESS)s>. Do not quote or
702 otherwise include any of this text in any correspondence.
703 """
704          },
705
706         # Boot Manager messages
707         {'message_id': "installfinished",
708          'subject': "%(hostname)s completed installation",
709          'template': """
710 %(hostname)s just completed installation.
711
712 The node should be usable in a couple of minutes if installation was
713 successful.
714 """
715          },
716
717         {'message_id': "insufficientdisk",
718          'subject': "%(hostname)s does not have sufficient disk space",
719          'template': """
720 %(hostname)s failed to boot because it does not have sufficent disk
721 space, or because its disk controller was not recognized.
722
723 Please replace the current disk or disk controller or install
724 additional disks to meet the current hardware requirements.
725 """ + installfailed
726          },
727
728         {'message_id': "insufficientmemory",
729          'subject': "%(hostname)s does not have sufficient memory",
730          'template': """
731 %(hostname)s failed to boot because it does not have sufficent
732 memory.
733
734 Please install additional memory to meet the current hardware
735 requirements.
736 """ + installfailed
737          },
738
739         {'message_id': "authfail",
740          'subject': "%(hostname)s failed to authenticate",
741          'template':
742 """
743 %(hostname)s failed to authenticate for the following reason:
744
745 %(fault)s
746
747 The most common reason for authentication failure is that the
748 authentication key stored in the node configuration file, does not
749 match the key on record. 
750
751 There are two possible steps to resolve the problem.
752
753 1. If you have used an All-in-one BootCD that includes the plnode.txt file,
754     then please check your machine for any old boot media, either in the
755     floppy drive, or on a USB stick.  It is likely that an old configuration
756     is being used instead of the new configuration stored on the BootCD.
757 Or, 
758 2. If you are using Generic BootCD image, then regenerate the node 
759     configuration file by visiting:
760
761     https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
762
763     Under 'Download', follow the 'Download plnode.txt file for %(hostname)s'
764     option, and save the downloaded file as plnode.txt on either a floppy 
765     disk or a USB flash drive.  Be sure the 'Boot State' is set to 'Boot', 
766     and, then reboot the node.
767
768 If you have already performed this step and are still receiving this
769 message, please reply so that we can help investigate the problem.
770 """
771          },
772
773         {'message_id': "notinstalled",
774          'subject': "%(hostname)s is not installed",
775          'template':
776 """
777 %(hostname)s failed to boot because it has either never been
778 installed, or the installation is corrupt.
779
780 Please check if the hard drive has failed, and replace it if so. After
781 doing so, visit:
782
783 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
784
785 Change the 'Boot State' to 'Reinstall', and then reboot the node.
786
787 If you have already performed this step and are still receiving this
788 message, please reply so that we may investigate the problem.
789 """
790          },
791
792         {'message_id': "hostnamenotresolve",
793          'subject': "%(hostname)s does not resolve",
794          'template':
795 """
796 %(hostname)s failed to boot because its hostname does not resolve, or
797 does resolve but does not match its configured IP address.
798
799 Please check the network settings for the node, especially its
800 hostname, IP address, and DNS servers, by visiting:
801
802 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
803
804 Correct any errors, and change the 'Boot State' to 'Reinstall', and then
805 reboot the node.
806
807 If you have already performed this step and are still receiving this
808 message, please reply so that we may investigate the problem.
809 """
810          },
811
812         # XXX N.B. I don't think these are necessary, since there's no
813         # way that the Boot Manager would even be able to contact the
814         # API to send these messages.
815
816         {'message_id': "noconfig",
817          'subject': "%(hostname)s does not have a configuration file",
818          'template': """
819 %(hostname)s failed to boot because it could not find a PlanetLab
820 configuration file. To create this file, visit:
821
822 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
823
824 Click the Configuration File link, and save the downloaded file as
825 plnode.txt on either a floppy disk or a USB flash drive.  Change the 
826 'Boot State' to 'Reinstall', and then reboot the node.
827
828 If you have already performed this step and are still receiving this
829 message, please reply so that we may investigate the problem.
830 """
831          },
832
833         {'message_id': "nodetectednetwork",
834          'subject': "%(hostname)s has unsupported network hardware",
835          'template':
836 """
837
838 %(hostname)s failed to boot because it has network hardware that is
839 unsupported by the current production kernel. If it has booted
840 successfully in the past, please try re-installing it by visiting:
841
842 https://%(PLC_WWW_HOST)s:%(PLC_WWW_SSL_PORT)d/db/nodes/?id=%(node_id)d
843
844 Change the 'Boot State' to 'Reinstall', and then reboot the node.
845
846 If you have already performed this step and are still receiving this
847 message, please reply so that we may investigate the problem.
848 """
849          },
850         ]
851
852     for template in message_templates:
853         messages = GetMessages([template['message_id']])
854         if not messages:
855             AddMessage(template)
856
857 if __name__ == '__main__':
858     main()
859
860 # Local variables:
861 # tab-width: 4
862 # mode: python
863 # End: