DTD for configuration file
[myplc.git] / api-config
1 #!/usr/bin/python
2 #
3 # Bootstraps the PLC database with a default administrator account and
4 # a default site.
5 #
6 # Mark Huang <mlhuang@cs.princeton.edu>
7 # Copyright (C) 2006 The Trustees of Princeton University
8 #
9 # $Id: api-config,v 1.4 2006/03/28 22:35:42 mlhuang Exp $
10 #
11
12 import plcapilib
13 (plcapi, moreopts, argv) = plcapilib.plcapi(globals())
14 from plc_config import PLCConfiguration
15 import xmlrpclib
16 import sys
17
18
19 def main():
20     cfg = PLCConfiguration()
21     cfg.load()
22     variables = cfg.variables()
23
24     # Load variables into dictionaries
25     (category, variablelist) = variables['plc']
26     plc = dict(zip(variablelist.keys(),
27                    [variable['value'] for variable in variablelist.values()]))
28
29     (category, variablelist) = variables['plc_www']
30     plc_www = dict(zip(variablelist.keys(),
31                        [variable['value'] for variable in variablelist.values()]))
32
33     (category, variablelist) = variables['plc_api']
34     plc_api = dict(zip(variablelist.keys(),
35                        [variable['value'] for variable in variablelist.values()]))
36
37     # Create/update the default administrator account (should be
38     # person_id 2).
39     admin = { 'person_id': 2,
40               'first_name': "Default",
41               'last_name': "Administrator",
42               'email': plc['root_user'],
43               'password': plc['root_password'] }
44     persons = AdmGetPersons([admin['person_id']])
45     if not persons:
46         person_id = AdmAddPerson(admin['first_name'], admin['last_name'], admin)
47         if person_id != admin['person_id']:
48             # Huh? Someone deleted the account manually from the database.
49             AdmDeletePerson(person_id)
50             raise Exception, "Someone deleted the \"%s %s\" account from the database!" % \
51                   (admin['first_name'], admin['last_name'])
52         AdmSetPersonEnabled(person_id, True)
53     else:
54         person_id = persons[0]['person_id']
55         AdmUpdatePerson(person_id, admin)
56
57     # Create/update the default site (should be site_id 0)
58     if plc_www['port'] == '80':
59         url = "http://" + plc_www['host'] + "/"
60     elif plc_www['port'] == '443':
61         url = "https://" + plc_www['host'] + "/"
62     else:
63         url = "http://" + plc_www['host'] + ":" + plc_www['port'] + "/"
64     site = { 'site_id': 1,
65              'name': plc['name'] + " Central",
66              'abbreviated_name': plc['name'],
67              # XXX Default site slice_prefix/login_base must be "pl_"
68              # 'login_base': plc['slice_prefix'],
69              'login_base': "pl",
70              'is_public': False,
71              'url': url,
72              'max_slices': 100 }
73
74     sites = AdmGetSites([site['site_id']])
75     if not sites:
76         site_id = AdmAddSite(site['name'], site['abbreviated_name'], site['login_base'], site)
77         if site_id != site['site_id']:
78             AdmDeleteSite(site_id)
79             raise Exception, "Someone deleted the \"%s\" site from the database!" % \
80                   site['name']
81         sites = [site]
82
83     # Must call AdmUpdateSite() even after AdmAddSite() to update max_slices
84     site_id = sites[0]['site_id']
85     # XXX login_base cannot be updated
86     del site['login_base']
87     AdmUpdateSite(site_id, site)
88
89     # The default administrator account must be associated with a site
90     # in order to login.
91     AdmAddPersonToSite(admin['person_id'], site['site_id'])
92     AdmSetPersonPrimarySite(admin['person_id'], site['site_id'])
93
94     # Grant admin and PI roles to the default administrator account
95     AdmGrantRoleToPerson(admin['person_id'], 10)
96     AdmGrantRoleToPerson(admin['person_id'], 20)
97
98     # Further bootstrap the database. A few PlanetLabConf entries are
99     # absolutely required, and NM requires the slice tables to be
100     # populated.
101     #
102     # XXX This data should really become part of the DB schema so that
103     # we don't have to copy it from PLC. For now, this code is only
104     # intended to be called at build time, when we know that we have
105     # access to PLC. Once the tables have been populated, this code
106     # should never be called again and PLC access is not required,
107     # i.e., end users of MyPLC should never see this code be executed.
108
109     # Use xmlrpclib to connect to PLC temporarily. plcapilib cannot
110     # connect to multiple servers at once.
111     auth = {'AuthMethod': 'anonymous'}
112     PLC = None
113
114     conf_files = AdmGetConfFile()
115     if not conf_files:
116         if PLC is None:
117             PLC = xmlrpclib.Server("https://www.planet-lab.org/PLCAPI/")
118         for conf_file in PLC.AnonAdmGetConfFile(auth):
119             if conf_file['enabled'] and \
120                not conf_file['node_id'] and \
121                not conf_file['nodegroup_id']:
122                 AdmCreateConfFile(conf_file['enabled'],
123                                   conf_file['source'],
124                                   conf_file['dest'],
125                                   conf_file['file_permissions'],
126                                   conf_file['file_owner'],
127                                   conf_file['file_group'],
128                                   conf_file['preinstall_cmd'],
129                                   conf_file['postinstall_cmd'],
130                                   conf_file['error_cmd'],
131                                   conf_file['ignore_cmd_errors'],
132                                   conf_file['always_update'])
133         
134     # Setup default slice attribute types, slices, and
135     # attributes. These are hard-coded here because we cannot safely
136     # support an anonymous interface to the SliceAttribute functions,
137     # yet we also do not want to require API authentication for
138     # bootstrapping.
139     
140     if not SliceAttributeTypeList():
141         # Create system attribute types
142         attribute_types = [{'name': "general_prop_share",
143                             'description': "general share",
144                             'is_exclusive': False, 'min_role_id': 10, 'max_per_slice': 1,
145                             'value_fields': [{'description': "",
146                                               'name': "general_prop_share",
147                                               'type': "integer"}]},
148                            {'name': "initscript",
149                             'description': "slice initialization script",
150                             'is_exclusive': False, 'min_role_id': 10, 'max_per_slice': 1,
151                             'value_fields': [{'description': "",
152                                               'name': "initscript_id",
153                                               'type': "integer"}]},
154                            {'name': "plc_slice_type",
155                             'description': "Type of slice rspec to be created",
156                             'is_exclusive': True, 'min_role_id': 20, 'max_per_slice': 1,
157                             'value_fields': [{'description': "rspec class",
158                                               'name': "type",
159                                               'type': "string"}]},
160                            {'name': "nm_cpu_share",
161                             'description': "Number of CPU shares to be allocated to slice",
162                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
163                             'value_fields': [{'description': "number of shares",
164                                               'name': "cpu_share",
165                                               'type': "integer"}]},
166                            {'name': "plc_agent_version",
167                             'description': "Version of PLC agent (slice creation service) software to be deployed",
168                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
169                             'value_fields': [{'description': "current version of PLC agent (SCS)",
170                                               'name': "version",
171                                               'type': "string"}]},
172                            {'name': "plc_ticket_pubkey",
173                             'description': "Public key used to verify PLC-signed tickets",
174                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
175                             'value_fields': [{'description': "PEM-encoded public key",
176                                               'name': "key",
177                                               'type': "string"}]},
178                            {'name': "nm_disk_quota",
179                             'description': "Disk quota",
180                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
181                             'value_fields': [{'description': "Number of 1k disk blocks",
182                                               'name': "quota",
183                                               'type': "integer"}]}]
184         for attribute_type in attribute_types:
185             SliceAttributeTypeCreate(attribute_type['name'], attribute_type['description'],
186                                      attribute_type['min_role_id'], attribute_type['max_per_slice'],
187                                      attribute_type['is_exclusive'], attribute_type['value_fields'])
188
189     # Get contents of SSL public certificate used for signing tickets
190     try:
191         plc_ticket_pubkey = ""
192         for line in file(plc_api['ssl_key_pub']):
193             # Skip comments
194             if line[0:5] != "-----":
195                 # XXX The embedded newlines matter, do not strip()!
196                 plc_ticket_pubkey += line
197     except:
198         plc_ticket_pubkey = '%KEY%'
199
200     # Create/update system slices
201     slices = [{'name': "pl_conf",
202                'description': "PlanetLab Slice Creation Service (SCS)",
203                'url': url,
204                'attributes': {'plc_slice_type': {'type': "VServerSlice"},
205                               'plc_agent_version': {'version': "1.0"},
206                               'plc_ticket_pubkey': {'key': plc_ticket_pubkey}}},
207               {'name': "pl_conf_vserverslice",
208                'description': "Default attributes for vserver slices",
209                'url': url,
210                'attributes': {'nm_cpu_share': {'cpu_share': 32},
211                               'plc_slice_type': {'type': "VServerSlice"},
212                               'nm_disk_quota': {'quota': 5000000}}}]
213     for slice in slices:
214         try:
215             SliceInfo([slice['name']])
216         except:
217             SliceCreate(slice['name'])
218             SliceSetInstantiationMethod(slice['name'], 'plc-instantiated')
219         SliceUpdate(slice['name'], slice['url'], slice['description'])
220         # Renew forever
221         SliceRenew(slice['name'], sys.maxint)
222         # Create/update all attributes
223         for attribute, values in slice['attributes'].iteritems():
224             SliceAttributeSet(slice['name'], attribute, values)
225
226
227 if __name__ == '__main__':
228     main()