51f8e30641d7ab10ae30952d2ec748db3338c865
[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.1.1.1 2006/03/27 17:36:46 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     else:
82         site_id = sites[0]['site_id']
83         # XXX login_base cannot be updated
84         del site['login_base']
85         AdmUpdateSite(site_id, site)
86
87     # The default administrator account must be associated with a site
88     # in order to login.
89     AdmAddPersonToSite(admin['person_id'], site['site_id'])
90     AdmSetPersonPrimarySite(admin['person_id'], site['site_id'])
91
92     # Grant admin and PI roles to the default administrator account
93     AdmGrantRoleToPerson(admin['person_id'], 10)
94     AdmGrantRoleToPerson(admin['person_id'], 20)
95
96     # Further bootstrap the database. A few PlanetLabConf entries are
97     # absolutely required, and NM requires the slice tables to be
98     # populated.
99     #
100     # XXX This data should really become part of the DB schema so that
101     # we don't have to copy it from PLC. For now, this code is only
102     # intended to be called at build time, when we know that we have
103     # access to PLC. Once the tables have been populated, this code
104     # should never be called again and PLC access is not required,
105     # i.e., end users of MyPLC should never see this code be executed.
106
107     # Use xmlrpclib to connect to PLC temporarily. plcapilib cannot
108     # connect to multiple servers at once.
109     auth = {'AuthMethod': 'anonymous'}
110     PLC = None
111
112     conf_files = AdmGetConfFile()
113     if not conf_files:
114         if PLC is None:
115             PLC = xmlrpclib.Server("https://www.planet-lab.org/PLCAPI/")
116         for conf_file in PLC.AnonAdmGetConfFile(auth):
117             if conf_file['enabled'] and \
118                not conf_file['node_id'] and \
119                not conf_file['nodegroup_id']:
120                 AdmCreateConfFile(conf_file['enabled'],
121                                   conf_file['source'],
122                                   conf_file['dest'],
123                                   conf_file['file_permissions'],
124                                   conf_file['file_owner'],
125                                   conf_file['file_group'],
126                                   conf_file['preinstall_cmd'],
127                                   conf_file['postinstall_cmd'],
128                                   conf_file['error_cmd'],
129                                   conf_file['ignore_cmd_errors'],
130                                   conf_file['always_update'])
131         
132     # Setup default slice attribute types, slices, and
133     # attributes. These are hard-coded here because we cannot safely
134     # support an anonymous interface to the SliceAttribute functions,
135     # yet we also do not want to require API authentication for
136     # bootstrapping.
137     
138     if not SliceAttributeTypeList():
139         # Create system attribute types
140         attribute_types = [{'name': "general_prop_share",
141                             'description': "general share",
142                             'is_exclusive': False, 'min_role_id': 10, 'max_per_slice': 1,
143                             'value_fields': [{'description': "",
144                                               'name': "general_prop_share",
145                                               'type': "integer"}]},
146                            {'name': "initscript",
147                             'description': "slice initialization script",
148                             'is_exclusive': False, 'min_role_id': 10, 'max_per_slice': 1,
149                             'value_fields': [{'description': "",
150                                               'name': "initscript_id",
151                                               'type': "integer"}]},
152                            {'name': "plc_slice_type",
153                             'description': "Type of slice rspec to be created",
154                             'is_exclusive': True, 'min_role_id': 20, 'max_per_slice': 1,
155                             'value_fields': [{'description': "rspec class",
156                                               'name': "type",
157                                               'type': "string"}]},
158                            {'name': "nm_cpu_share",
159                             'description': "Number of CPU shares to be allocated to slice",
160                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
161                             'value_fields': [{'description': "number of shares",
162                                               'name': "cpu_share",
163                                               'type': "integer"}]},
164                            {'name': "plc_agent_version",
165                             'description': "Version of PLC agent (slice creation service) software to be deployed",
166                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
167                             'value_fields': [{'description': "current version of PLC agent (SCS)",
168                                               'name': "version",
169                                               'type': "string"}]},
170                            {'name': "plc_ticket_pubkey",
171                             'description': "Public key used to verify PLC-signed tickets",
172                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
173                             'value_fields': [{'description': "PEM-encoded public key",
174                                               'name': "key",
175                                               'type': "string"}]},
176                            {'name': "nm_disk_quota",
177                             'description': "Disk quota",
178                             'is_exclusive': True, 'min_role_id': 10, 'max_per_slice': 1,
179                             'value_fields': [{'description': "Number of 1k disk blocks",
180                                               'name': "quota",
181                                               'type': "integer"}]}]
182         for attribute_type in attribute_types:
183             SliceAttributeTypeCreate(attribute_type['name'], attribute_type['description'],
184                                      attribute_type['min_role_id'], attribute_type['max_per_slice'],
185                                      attribute_type['is_exclusive'], attribute_type['value_fields'])
186
187     if not SliceListNames():
188         # Get contents of SSL public certificate used for signing tickets
189         try:
190             plc_ticket_pubkey = ""
191             for line in file(plc_api['ssl_key_pub']):
192                 # Skip comments
193                 if line[0:5] != "-----":
194                     # XXX The embedded newlines matter, do not strip()!
195                     plc_ticket_pubkey += line
196         except:
197             plc_ticket_pubkey = '%KEY%'
198
199         # Create system slices
200         slices = [{'name': "pl_conf",
201                    'description': "PlanetLab Slice Creation Service (SCS)",
202                    'url': url,
203                    'attributes': {'plc_slice_type': {'type': "VServerSlice"},
204                                   'plc_agent_version': {'version': "1.0"},
205                                   'plc_ticket_pubkey': {'key': plc_ticket_pubkey}}},
206                   {'name': "pl_conf_vserverslice",
207                    'description': "Default attributes for vserver slices",
208                    'url': url,
209                    'attributes': {'nm_cpu_share': {'cpu_share': 32},
210                                   'plc_slice_type': {'type': "VServerSlice"},
211                                   'nm_disk_quota': {'quota': 5000000}}}]
212         for slice in slices:
213             SliceCreate(slice['name'])
214             SliceUpdate(slice['name'], slice['url'], slice['description'])
215             SliceSetInstantiationMethod(slice['name'], 'plc-instantiated')
216             # Renew forever
217             SliceRenew(slice['name'], sys.maxint)
218             for attribute, values in slice['attributes'].iteritems():
219                 SliceAttributeAdd(slice['name'], attribute, values)
220
221
222 if __name__ == '__main__':
223     main()