|
1 #!/usr/bin/python |
|
2 |
|
3 import ConfigParser |
|
4 import grp |
|
5 import os |
|
6 import pwd |
|
7 import shutil |
|
8 import sys |
|
9 import time |
|
10 import warnings |
|
11 |
|
12 import netifaces |
|
13 |
|
14 from M2Crypto import RSA |
|
15 from optparse import OptionParser |
|
16 from solaris_install import with_spinner |
|
17 from subprocess import CalledProcessError, Popen, PIPE, check_call |
|
18 |
|
19 |
|
20 def get_external_ip(): |
|
21 '''Process all IPv4 network interfaces returning address of first |
|
22 non-localhost(127.0.0.1) address or None of not found. |
|
23 ''' |
|
24 for iface in netifaces.interfaces(): |
|
25 for addr in netifaces.ifaddresses(iface)[netifaces.AF_INET]: |
|
26 if addr['addr'] != "127.0.0.1": |
|
27 return addr['addr'] |
|
28 return None |
|
29 |
|
30 |
|
31 def keystone(sqlite): |
|
32 print "configuring keystone" |
|
33 config = ConfigParser.RawConfigParser() |
|
34 config.readfp(open("/etc/keystone/keystone.conf")) |
|
35 config.set("DEFAULT", "admin_token", "ADMIN") |
|
36 if not sqlite: |
|
37 config.set("database", "connection", |
|
38 "mysql://keystone:keystone@localhost/keystone") |
|
39 with open("/etc/keystone/keystone.conf", "wb") as fh: |
|
40 config.write(fh) |
|
41 |
|
42 print "enabling keystone" |
|
43 check_call(["/usr/sbin/svcadm", "enable", "-rs", "keystone"]) |
|
44 |
|
45 # sleep for a few seconds to let SMF catch up |
|
46 time.sleep(2) |
|
47 |
|
48 print "loading sample data" |
|
49 check_call(["/usr/bin/bash", "sample_data.sh"], |
|
50 cwd="/usr/demo/openstack/keystone") |
|
51 |
|
52 # Create ironic keystone info as not in sample_data.sh |
|
53 check_call(["/usr/bin/bash", "ironic-keystone-setup.sh"], |
|
54 cwd="/usr/demo/openstack/keystone") |
|
55 |
|
56 print "testing keystone" |
|
57 print "keystone user-list:" |
|
58 check_call(["keystone", "user-list"], |
|
59 env={"SERVICE_ENDPOINT": "http://localhost:35357/v2.0", |
|
60 "SERVICE_TOKEN": "ADMIN"}) |
|
61 |
|
62 |
|
63 def glance(sqlite): |
|
64 print "configuring glance" |
|
65 |
|
66 config = ConfigParser.RawConfigParser() |
|
67 config.readfp(open("/etc/glance/glance-api.conf")) |
|
68 config.set("keystone_authtoken", "admin_tenant_name", "service") |
|
69 config.set("keystone_authtoken", "admin_user", "glance") |
|
70 config.set("keystone_authtoken", "admin_password", "glance") |
|
71 if not sqlite: |
|
72 config.set("database", "connection", |
|
73 "mysql://glance:glance@localhost/glance") |
|
74 |
|
75 with open("/etc/glance/glance-api.conf", "wb") as fh: |
|
76 config.write(fh) |
|
77 |
|
78 config = ConfigParser.RawConfigParser() |
|
79 config.readfp(open("/etc/glance/glance-cache.conf")) |
|
80 config.set("DEFAULT", "auth_url", "http://127.0.0.1:5000/v2.0/") |
|
81 config.set("DEFAULT", "admin_tenant_name", "service") |
|
82 config.set("DEFAULT", "admin_user", "glance") |
|
83 config.set("DEFAULT", "admin_password", "glance") |
|
84 with open("/etc/glance/glance-cache.conf", "wb") as fh: |
|
85 config.write(fh) |
|
86 |
|
87 config = ConfigParser.RawConfigParser() |
|
88 config.readfp(open("/etc/glance/glance-registry.conf")) |
|
89 config.set("keystone_authtoken", "admin_tenant_name", "service") |
|
90 config.set("keystone_authtoken", "admin_user", "glance") |
|
91 config.set("keystone_authtoken", "admin_password", "glance") |
|
92 if not sqlite: |
|
93 config.set("database", "connection", |
|
94 "mysql://glance:glance@localhost/glance") |
|
95 with open("/etc/glance/glance-registry.conf", "wb") as fh: |
|
96 config.write(fh) |
|
97 |
|
98 config = ConfigParser.RawConfigParser() |
|
99 config.readfp(open("/etc/glance/glance-api-paste.ini")) |
|
100 config.set("filter:authtoken", "auth_uri", "http://127.0.0.1:5000/v2.0/") |
|
101 config.set("filter:authtoken", "identity_uri", "http://127.0.0.1:35357") |
|
102 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
103 config.set("filter:authtoken", "admin_user", "glance") |
|
104 config.set("filter:authtoken", "admin_password", "glance") |
|
105 with open("/etc/glance/glance-api-paste.ini", "wb") as fh: |
|
106 config.write(fh) |
|
107 |
|
108 config = ConfigParser.RawConfigParser() |
|
109 config.readfp(open("/etc/glance/glance-registry-paste.ini")) |
|
110 config.set("filter:authtoken", "auth_uri", "http://127.0.0.1:5000/v2.0/") |
|
111 config.set("filter:authtoken", "identity_uri", "http://127.0.0.1:35357") |
|
112 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
113 config.set("filter:authtoken", "admin_user", "glance") |
|
114 config.set("filter:authtoken", "admin_password", "glance") |
|
115 with open("/etc/glance/glance-registry-paste.ini", "wb") as fh: |
|
116 config.write(fh) |
|
117 |
|
118 config = ConfigParser.RawConfigParser() |
|
119 config.readfp(open("/etc/glance/glance-scrubber.conf")) |
|
120 config.set("DEFAULT", "filesystem_store_datadir", "/var/lib/glance/images") |
|
121 config.set("DEFAULT", "swift_store_auth_address", "127.0.0.1:5000/v2.0/") |
|
122 config.set("DEFAULT", "swift_store_user", "johndoe:johndoe") |
|
123 config.set("DEFAULT", "swift_store_key", |
|
124 "a86850deb2742ec3cb41518e26aa2d89") |
|
125 config.set("DEFAULT", "s3_store_host", "127.0.0.1:8080/v1.0/") |
|
126 config.set("DEFAULT", "s3_store_access_key", '"<20-char AWS access key>"') |
|
127 config.set("DEFAULT", "s3_store_secret_key", '"<40-char AWS secret key>"') |
|
128 config.set("DEFAULT", "s3_store_bucket", '"<lowercased 20-char aws key>"') |
|
129 config.set("DEFAULT", "s3_store_create_bucket_on_put", "False") |
|
130 config.set("DEFAULT", "auth_url", "http://127.0.0.1:5000/v2.0/") |
|
131 config.set("DEFAULT", "admin_tenant_name", "service") |
|
132 config.set("DEFAULT", "admin_user", "glance") |
|
133 config.set("DEFAULT", "admin_password", "glance") |
|
134 with open("/etc/glance/glance-scrubber.conf", "wb") as fh: |
|
135 config.write(fh) |
|
136 |
|
137 print "enabling glance-api, glance-registry, and glance-scrubber" |
|
138 check_call(["/usr/sbin/svcadm", "enable", "-rs", "glance-api", "glance-db", |
|
139 "glance-registry", "glance-scrubber"]) |
|
140 |
|
141 # sleep for a few seconds to let SMF catch up |
|
142 time.sleep(2) |
|
143 |
|
144 print "testing glance" |
|
145 print "glance image-list:" |
|
146 check_call(["glance", "image-list"], |
|
147 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
148 "OS_PASSWORD": "glance", |
|
149 "OS_USERNAME": "glance", |
|
150 "OS_TENANT_NAME": "service"}) |
|
151 |
|
152 |
|
153 def create_pubkey(user): |
|
154 # look for ssh keys for the user |
|
155 sshdir = os.path.join(user.pw_dir, ".ssh") |
|
156 if not os.path.exists(sshdir): |
|
157 os.mkdir(sshdir) |
|
158 |
|
159 print "setting .ssh/config" |
|
160 ssh_config = "Host *\n\tStrictHostKeyChecking no\n" |
|
161 with open(os.path.join(user.pw_dir, ".ssh", "config"), "w") as fh: |
|
162 fh.write(ssh_config) |
|
163 |
|
164 if not [f for f in os.listdir(sshdir) if f.endswith("rsa.pub")]: |
|
165 key = RSA.gen_key(2048, 65337) |
|
166 key.save_key(os.path.join(sshdir, "id_rsa"), |
|
167 cipher=None) |
|
168 os.chmod(os.path.join(sshdir, "id_rsa"), 0600) |
|
169 p = Popen(["ssh-keygen", "-y", "-f", |
|
170 os.path.join(sshdir, "id_rsa")], stdout=PIPE, stderr=PIPE) |
|
171 pubkey, err = p.communicate() |
|
172 owner = "%s:%s" % (user.pw_name, grp.getgrgid(user.pw_gid).gr_name) |
|
173 check_call(["chown", "-R", owner, sshdir]) |
|
174 else: |
|
175 with open(os.path.join(sshdir, "id_rsa.pub"), "r+") as fh: |
|
176 pubkey = fh.read() |
|
177 return pubkey |
|
178 |
|
179 |
|
180 def neutron_prep(): |
|
181 # look for an 'evsuser' |
|
182 try: |
|
183 evsuser = pwd.getpwnam("evsuser") |
|
184 except KeyError: |
|
185 # no 'evsuser' on system. Go create one |
|
186 print "creating 'evsuser' account" |
|
187 check_call(["useradd", "-d", "/var/lib/evsuser", "-m", "evsuser"]) |
|
188 evsuser = pwd.getpwnam("evsuser") |
|
189 neutronuser = pwd.getpwnam("neutron") |
|
190 root = pwd.getpwnam("root") |
|
191 |
|
192 print "creating ssh keys" |
|
193 evsuser_pubkey = create_pubkey(evsuser) |
|
194 neutron_pubkey = create_pubkey(neutronuser) |
|
195 root_pubkey = create_pubkey(root) |
|
196 |
|
197 print "setting .ssh/config" |
|
198 ssh_config = "Host *\n\tStrictHostKeyChecking no\n" |
|
199 for user in [evsuser, neutronuser, root]: |
|
200 with open(os.path.join(user.pw_dir, ".ssh", "config"), "w") as fh: |
|
201 fh.write(ssh_config) |
|
202 |
|
203 print "populating authorized_keys" |
|
204 path = os.path.join(evsuser.pw_dir, ".ssh", "authorized_keys") |
|
205 with open(path, "w") as fh: |
|
206 fh.write(evsuser_pubkey) |
|
207 fh.write(neutron_pubkey) |
|
208 fh.write(root_pubkey) |
|
209 |
|
210 owner = "%s:%s" % (evsuser.pw_name, grp.getgrgid(evsuser.pw_gid).gr_name) |
|
211 check_call(["chown", "-R", owner, |
|
212 os.path.join(evsuser.pw_dir, ".ssh", "authorized_keys")]) |
|
213 |
|
214 |
|
215 def neutron(sqlite): |
|
216 neutron_prep() |
|
217 |
|
218 print "configuring EVS" |
|
219 check_call(['evsadm', 'set-prop', '-p', |
|
220 'controller=ssh://evsuser@localhost']) |
|
221 |
|
222 try: |
|
223 check_call(["evsadm"]) |
|
224 except CalledProcessError: |
|
225 raise RuntimeError("Unable to call evsadm.") |
|
226 |
|
227 try: |
|
228 check_call(["dladm", "show-etherstub", "l3stub0"], stdout=PIPE, |
|
229 stderr=PIPE) |
|
230 except CalledProcessError: |
|
231 # l3stub0 not found, go create it |
|
232 try: |
|
233 check_call(["dladm", "create-etherstub", "l3stub0"]) |
|
234 except CalledProcessError: |
|
235 raise RuntimeError("Unable to create etherstub") |
|
236 |
|
237 check_call(['evsadm', 'set-controlprop', '-p', 'l2-type=vlan']) |
|
238 check_call(['evsadm', 'set-controlprop', '-p', 'uplink-port=l3stub0']) |
|
239 check_call(['evsadm', 'set-controlprop', '-p', 'vlan-range=200-300']) |
|
240 check_call(['ipadm', 'set-prop', '-p', 'forwarding=on', 'ipv4']) |
|
241 |
|
242 print "configuring neutron" |
|
243 config = ConfigParser.RawConfigParser() |
|
244 config.readfp(open("/etc/neutron/neutron.conf")) |
|
245 config.set("DEFAULT", "allow_overlapping_ips", "False") |
|
246 if not sqlite: |
|
247 config.set("database", "connection", |
|
248 "mysql://neutron:neutron@localhost/neutron") |
|
249 else: |
|
250 config.set("database", "connection", |
|
251 "sqlite:////var/lib/neutron/neutron.sqlite") |
|
252 |
|
253 if not config.has_section("keystone_authtoken"): |
|
254 config.add_section("keystone_authtoken") |
|
255 config.set("keystone_authtoken", "auth_host", "127.0.0.1") |
|
256 config.set("keystone_authtoken", "auth_port", "35357") |
|
257 config.set("keystone_authtoken", "auth_protocol", "http") |
|
258 config.set("keystone_authtoken", "admin_tenant_name", "service") |
|
259 config.set("keystone_authtoken", "admin_user", "neutron") |
|
260 config.set("keystone_authtoken", "admin_password", "neutron") |
|
261 config.set("keystone_authtoken", "signing_dir", |
|
262 "/var/lib/neutron/keystone-signing") |
|
263 with open("/etc/neutron/neutron.conf", "wb") as fh: |
|
264 config.write(fh) |
|
265 |
|
266 config = ConfigParser.RawConfigParser() |
|
267 config.readfp(open("/etc/neutron/api-paste.ini")) |
|
268 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
269 config.set("filter:authtoken", "admin_user", "neutron") |
|
270 config.set("filter:authtoken", "admin_password", "neutron") |
|
271 config.set("filter:authtoken", "auth_uri", "http://127.0.0.1:5000/v2.0/") |
|
272 config.set("filter:authtoken", "identity_uri", "http://127.0.0.1:35357") |
|
273 with open("/etc/neutron/api-paste.ini", "wb") as fh: |
|
274 config.write(fh) |
|
275 |
|
276 config = ConfigParser.RawConfigParser() |
|
277 config.readfp(open("/etc/neutron/l3_agent.ini")) |
|
278 config.set("DEFAULT", "enable_metadata_proxy", "True") |
|
279 with open("/etc/neutron/l3_agent.ini", "wb") as fh: |
|
280 config.write(fh) |
|
281 |
|
282 config = ConfigParser.RawConfigParser() |
|
283 config.readfp(open("/etc/neutron/metadata_agent.ini")) |
|
284 config.set("DEFAULT", "admin_tenant_name", "service") |
|
285 config.set("DEFAULT", "admin_user", "neutron") |
|
286 config.set("DEFAULT", "admin_password", "neutron") |
|
287 config.set("DEFAULT", "auth_url", "http://127.0.0.1:5000/v2.0/") |
|
288 config.set("DEFAULT", "nova_metadata_ip", "127.0.0.1") |
|
289 config.set("DEFAULT", "nova_metadata_port", "8775") |
|
290 config.set("DEFAULT", "metadata_proxy_shared_secret", "seCr3t") |
|
291 with open("/etc/neutron/metadata_agent.ini", "wb") as fh: |
|
292 config.write(fh) |
|
293 |
|
294 print "enabling neutron services" |
|
295 check_call(["/usr/sbin/svcadm", "enable", "-rs", "ipfilter"]) |
|
296 check_call(["/usr/sbin/svcadm", "enable", "-rs", "neutron-server", |
|
297 "neutron-dhcp-agent", "neutron-metadata-agent"]) |
|
298 |
|
299 print "testing neutron" |
|
300 print "neutron networks:" |
|
301 check_call(["neutron", "net-list"], |
|
302 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
303 "OS_PASSWORD": "neutron", |
|
304 "OS_USERNAME": "neutron", |
|
305 "OS_TENANT_NAME": "service"}) |
|
306 |
|
307 |
|
308 def nova(sqlite): |
|
309 print "configuring nova" |
|
310 config = ConfigParser.RawConfigParser() |
|
311 config.readfp(open("/etc/nova/nova.conf")) |
|
312 config.set("DEFAULT", "firewall_driver", |
|
313 "nova.virt.firewall.NoopFirewallDriver") |
|
314 config.set("DEFAULT", "neutron_url", "http://localhost:9696") |
|
315 config.set("DEFAULT", "neutron_admin_username", "neutron") |
|
316 config.set("DEFAULT", "neutron_admin_password", "neutron") |
|
317 config.set("DEFAULT", "neutron_admin_tenant_name", "service") |
|
318 config.set("DEFAULT", "neutron_admin_auth_url", |
|
319 "http://localhost:5000/v2.0") |
|
320 config.set("DEFAULT", "neutron_auth_strategy", "keystone") |
|
321 config.set("DEFAULT", "network_driver", "nova.network.solaris_net") |
|
322 |
|
323 # Set VNC console configuration |
|
324 proxy_port = "6080" |
|
325 ext_ip = get_external_ip() or "127.0.0.1" |
|
326 config.set("DEFAULT", "vnc_enabled", "true") |
|
327 config.set("DEFAULT", "vncserver_listen", "0.0.0.0") |
|
328 config.set("DEFAULT", "novncproxy_port", proxy_port) |
|
329 config.set("DEFAULT", "novncproxy_base_url", |
|
330 "http://" + ext_ip + ":" + proxy_port + "/vnc_auto.html") |
|
331 config.set("DEFAULT", "novncproxy_host", "0.0.0.0") |
|
332 |
|
333 if not sqlite: |
|
334 config.set("database", "connection", |
|
335 "mysql://nova:nova@localhost/nova") |
|
336 |
|
337 # get the number of CPUs so we can throttle down the requests made against |
|
338 # rabbitmq |
|
339 p = Popen(["psrinfo", "-p"], stdout=PIPE, stderr=PIPE) |
|
340 out, err = p.communicate() |
|
341 workers = out.strip() |
|
342 config.set("DEFAULT", "metadata_workers", workers) |
|
343 config.set("DEFAULT", "osapi_compute_workers", workers) |
|
344 config.set("DEFAULT", "ec2_workers", workers) |
|
345 config.set("conductor", "workers", workers) |
|
346 |
|
347 if not config.has_section("neutron"): |
|
348 config.add_section("neutron") |
|
349 config.set("neutron", "service_metadata_proxy", "True") |
|
350 config.set("neutron", "metadata_proxy_shared_secret", "seCr3t") |
|
351 |
|
352 with open("/etc/nova/nova.conf", "wb") as fh: |
|
353 config.write(fh) |
|
354 |
|
355 config = ConfigParser.RawConfigParser() |
|
356 config.readfp(open("/etc/nova/api-paste.ini")) |
|
357 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
358 config.set("filter:authtoken", "admin_user", "nova") |
|
359 config.set("filter:authtoken", "admin_password", "nova") |
|
360 config.set("filter:authtoken", "auth_uri", "http://127.0.0.1:5000/v2.0/") |
|
361 config.set("filter:authtoken", "identity_uri", "http://127.0.0.1:35357") |
|
362 with open("/etc/nova/api-paste.ini", "wb") as fh: |
|
363 config.write(fh) |
|
364 |
|
365 print "enabling nova services" |
|
366 check_call(["/usr/sbin/svcadm", "enable", "-rs", "nova-conductor"]) |
|
367 # sleep for a few seconds to let SMF catch up |
|
368 time.sleep(2) |
|
369 |
|
370 check_call(["/usr/sbin/svcadm", "enable", "-rs", "nova-api-ec2", |
|
371 "nova-api-osapi-compute", "nova-scheduler", |
|
372 "nova-cert", "nova-compute", "nova-api-metadata", |
|
373 "nova-consoleauth", "nova-novncproxy"]) |
|
374 |
|
375 # sleep for a few seconds to let SMF catch up |
|
376 time.sleep(2) |
|
377 |
|
378 print "testing nova" |
|
379 print "nova endpoints:" |
|
380 check_call(["nova", "endpoints"], |
|
381 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
382 "OS_PASSWORD": "nova", |
|
383 "OS_USERNAME": "nova", |
|
384 "OS_TENANT_NAME": "service"}) |
|
385 |
|
386 print "nova list:" |
|
387 check_call(["nova", "list"], |
|
388 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
389 "OS_PASSWORD": "nova", |
|
390 "OS_USERNAME": "nova", |
|
391 "OS_TENANT_NAME": "service"}) |
|
392 |
|
393 |
|
394 def cinder(sqlite): |
|
395 print "configuring cinder" |
|
396 config = ConfigParser.RawConfigParser() |
|
397 config.readfp(open("/etc/cinder/cinder.conf")) |
|
398 config.set("DEFAULT", "my_ip", "localhost") |
|
399 config.set("DEFAULT", "scheduler_driver", |
|
400 "cinder.scheduler.filter_scheduler.FilterScheduler") |
|
401 config.set("DEFAULT", "zfs_volume_base", "rpool/cinder") |
|
402 config.set("DEFAULT", "san_is_local", "true") |
|
403 if not sqlite: |
|
404 config.set("database", "connection", |
|
405 "mysql://cinder:cinder@localhost/cinder") |
|
406 |
|
407 with open("/etc/cinder/cinder.conf", "wb") as fh: |
|
408 config.write(fh) |
|
409 |
|
410 config = ConfigParser.RawConfigParser() |
|
411 config.readfp(open("/etc/cinder/api-paste.ini")) |
|
412 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
413 config.set("filter:authtoken", "admin_user", "cinder") |
|
414 config.set("filter:authtoken", "admin_password", "cinder") |
|
415 config.set("filter:authtoken", "signing_dir", |
|
416 "/var/lib/cinder/keystone-signing") |
|
417 with open("/etc/cinder/api-paste.ini", "wb") as fh: |
|
418 config.write(fh) |
|
419 |
|
420 print "enabling cinder services" |
|
421 check_call(["/usr/sbin/svcadm", "enable", "-rs", "cinder-api", "cinder-db", |
|
422 "cinder-backup", "cinder-scheduler", "cinder-volume:setup", |
|
423 "cinder-volume:default"]) |
|
424 |
|
425 # sleep for a few seconds to let SMF catch up |
|
426 time.sleep(2) |
|
427 |
|
428 print "testing cinder" |
|
429 print "cinder list:" |
|
430 check_call(["cinder", "list"], |
|
431 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
432 "OS_PASSWORD": "cinder", |
|
433 "OS_USERNAME": "cinder", |
|
434 "OS_TENANT_NAME": "service"}) |
|
435 |
|
436 |
|
437 def horizon(): |
|
438 print "configuring horizon" |
|
439 # who loves sed? |
|
440 cmd = ["gsed", '-i', |
|
441 "-e", "s@SECURE_PROXY_SSL_HEADER@#SECURE_PROXY_SSL_HEADER@", |
|
442 "-e", "s@CSRF_COOKIE_SECURE@#CSRF_COOKIE_SECURE@", |
|
443 "-e", "s@SESSION_COOKIE_SECURE@#SESSION_COOKIE_SECURE@", |
|
444 "/etc/openstack_dashboard/local_settings.py"] |
|
445 try: |
|
446 check_call(cmd) |
|
447 except OSError: |
|
448 print "text/gnu-sed not installed: skipping horizon configuration." |
|
449 return |
|
450 |
|
451 shutil.copy("/etc/apache2/2.4/samples-conf.d/openstack-dashboard-http.conf", |
|
452 "/etc/apache2/2.4/conf.d") |
|
453 |
|
454 cmd = ["svcs", "-H", "-o", "state", "apache24"] |
|
455 p = Popen(cmd, stdout=PIPE, stderr=PIPE) |
|
456 out, err = p.communicate() |
|
457 if out.strip() == "disabled": |
|
458 check_call(["/usr/sbin/svcadm", "enable", "apache24"]) |
|
459 else: |
|
460 check_call(["/usr/sbin/svcadm", "restart", "apache24"]) |
|
461 |
|
462 |
|
463 def swift(): |
|
464 print "configuring swift" |
|
465 config = ConfigParser.RawConfigParser() |
|
466 config.readfp(open("/etc/swift/proxy-server.conf")) |
|
467 if not config.has_section("filter:authtoken"): |
|
468 config.add_section("filter:authtoken") |
|
469 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
470 config.set("filter:authtoken", "admin_user", "swift") |
|
471 config.set("filter:authtoken", "admin_password", "swift") |
|
472 config.set("filter:authtoken", "signing_dir", |
|
473 "/var/lib/swift/keystone-signing") |
|
474 # We might be upgrading from an existing swift configuration that doesn't |
|
475 # have the defaults in the new packages ... |
|
476 if "keystoneauth" not in config.get("pipeline:main", "pipeline"): |
|
477 config.set("pipeline:main", "pipeline", "catch_errors healthcheck " |
|
478 "proxy-logging cache slo ratelimit tempauth container-quotas " |
|
479 "account-quotas authtoken keystoneauth proxy-logging proxy-server") |
|
480 config.set("app:proxy-server", "account_autocreate", "true") |
|
481 config.set("filter:authtoken", "paste.filter_factory", |
|
482 "keystoneclient.middleware.auth_token:filter_factory") |
|
483 config.set("filter:authtoken", "auth_host", "127.0.0.1") |
|
484 config.set("filter:authtoken", "auth_port", "35357") |
|
485 config.set("filter:authtoken", "auth_protocol", "http") |
|
486 config.set("filter:authtoken", "auth_uri", "http://127.0.0.1:5000/") |
|
487 config.set("filter:authtoken", "delay_auth_decision", "1") |
|
488 config.set("filter:authtoken", "cache", "swift.cache") |
|
489 config.set("filter:authtoken", "include_service_catalog", "False") |
|
490 if not config.has_section("filter:keystoneauth"): |
|
491 config.add_section("filter:keystoneauth") |
|
492 config.set("filter:keystoneauth", "use", "egg:swift#keystoneauth") |
|
493 with open("/etc/swift/proxy-server.conf", "wb") as fh: |
|
494 config.write(fh) |
|
495 |
|
496 print "building rings" |
|
497 |
|
498 def rb(type, action, *args): |
|
499 check_call(["/usr/bin/swift-ring-builder", |
|
500 "/etc/swift/%s.builder" % type, action] + list(args)) |
|
501 |
|
502 port = {"object": 6000, "container": 6001, "account": 6002} |
|
503 ipv4addr = get_external_ip() or "127.0.0.1" |
|
504 if ipv4addr != "127.0.0.1": |
|
505 print "swift cluster using %s on net0" % ipv4addr |
|
506 else: |
|
507 ipv4addr = "127.0.0.1" |
|
508 print "swift cluster using %s on loopback" % ipv4addr |
|
509 print "You may want to change this with:" |
|
510 print " # swift-ring-builder /etc/swift/<type>.builder set_info 127.0.0.1 <ip>" |
|
511 print " # swift-ring-builder /etc/swift/<type>.builder write_ring" |
|
512 print "where <type> is set to 'object', 'container', and 'account' and" |
|
513 print "<ip> is set to the IP address you want the cluster to use." |
|
514 for t in port.keys(): |
|
515 rb(t, "create", "10", "3", "1") |
|
516 rb(t, "add", "r1z1-%s:%s/disk0" % (ipv4addr, port[t]), "100") |
|
517 rb(t, "rebalance") |
|
518 |
|
519 print "creating ZFS datasets" |
|
520 try: |
|
521 check_call(["/usr/sbin/zfs", "list", "rpool/export/swift"], |
|
522 stdout=PIPE, stderr=PIPE) |
|
523 except: |
|
524 # doesn't exist; create it |
|
525 check_call(["/usr/sbin/zfs", "create", "-o", "mountpoint=none", |
|
526 "rpool/export/swift"]) |
|
527 |
|
528 try: |
|
529 check_call(["/usr/sbin/zfs", "list", "rpool/export/swift/srv"], |
|
530 stdout=PIPE, stderr=PIPE) |
|
531 except: |
|
532 # doesn't exist; create it |
|
533 check_call(["/usr/sbin/zfs", "create", "-o", "mountpoint=/srv", |
|
534 "rpool/export/swift/srv"]) |
|
535 |
|
536 try: |
|
537 check_call(["/usr/sbin/zfs", "list", "rpool/export/swift/srv/node"], |
|
538 stdout=PIPE, stderr=PIPE) |
|
539 except: |
|
540 # doesn't exist; create it |
|
541 check_call(["/usr/sbin/zfs", "create", "rpool/export/swift/srv/node"]) |
|
542 |
|
543 try: |
|
544 check_call(["/usr/sbin/zfs", "list", |
|
545 "rpool/export/swift/srv/node/disk0"], |
|
546 stdout=PIPE, stderr=PIPE) |
|
547 except: |
|
548 # doesn't exist; create it |
|
549 check_call(["/usr/sbin/zfs", "create", |
|
550 "rpool/export/swift/srv/node/disk0"]) |
|
551 |
|
552 check_call(["/usr/bin/chown", "-R", "swift:swift", "/srv"]) |
|
553 check_call(["/usr/bin/chown", "-R", "swift:swift", "/etc/swift"]) |
|
554 |
|
555 print "enabling swift services" |
|
556 check_call(["/usr/sbin/svcadm", "enable", "-rs", |
|
557 "swift-replicator-rsync", "swift-account-replicator", |
|
558 "swift-container-sync", "swift-container-server", "swift-account-auditor", |
|
559 "swift-container-updater", "swift-container-reconciler", |
|
560 "swift-container-replicator", "swift-container-auditor", |
|
561 "swift-account-reaper", "swift-account-server", "swift-object-expirer", |
|
562 "swift-object-auditor", "swift-object-server", "swift-object-replicator", |
|
563 "swift-object-updater", "swift-proxy-server"]) |
|
564 |
|
565 # sleep for a few seconds to let SMF catch up |
|
566 time.sleep(2) |
|
567 |
|
568 print "testing swift" |
|
569 env = { |
|
570 "OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
571 "OS_USERNAME": "admin", |
|
572 "OS_PASSWORD": "secrete", |
|
573 "OS_TENANT_NAME": "demo" |
|
574 } |
|
575 check_call(["swift", "upload", "junk", "/etc/motd"], env=env) |
|
576 check_call(["swift", "stat", "junk", "etc/motd"], env=env) |
|
577 try: |
|
578 os.unlink("/tmp/swifttest") |
|
579 except: |
|
580 pass |
|
581 check_call(["swift", "download", "-o", "/tmp/swifttest", "junk", |
|
582 "etc/motd"], |
|
583 env=env) |
|
584 |
|
585 check_call(["diff", "/tmp/swifttest", "/etc/motd"]) |
|
586 try: |
|
587 os.unlink("/tmp/swifttest") |
|
588 except: |
|
589 pass |
|
590 |
|
591 |
|
592 def heat(sqlite): |
|
593 print "configuring heat" |
|
594 check_call(["/usr/demo/openstack/keystone/heat-keystone-setup"], |
|
595 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
596 "OS_PASSWORD": "secrete", |
|
597 "OS_USERNAME": "admin", |
|
598 "OS_TENANT_NAME": "demo"}) |
|
599 |
|
600 config = ConfigParser.RawConfigParser() |
|
601 config.readfp(open("/etc/heat/heat.conf")) |
|
602 |
|
603 if not sqlite: |
|
604 config.set("database", "connection", |
|
605 "mysql://heat:heat@localhost/heat") |
|
606 |
|
607 config.set("keystone_authtoken", "admin_tenant_name", "service") |
|
608 config.set("keystone_authtoken", "admin_user", "heat") |
|
609 config.set("keystone_authtoken", "admin_password", "heat") |
|
610 with open("/etc/heat/heat.conf", "wb") as fh: |
|
611 config.write(fh) |
|
612 |
|
613 config = ConfigParser.RawConfigParser() |
|
614 config.readfp(open("/etc/heat/api-paste.ini")) |
|
615 config.set("filter:authtoken", "admin_user", "heat") |
|
616 config.set("filter:authtoken", "admin_password", "heat") |
|
617 config.set("filter:authtoken", "admin_tenant_name", "service") |
|
618 config.set("filter:authtoken", "auth_uri", "http://127.0.0.1:5000/v2.0/") |
|
619 config.set("filter:authtoken", "identity_uri", "http://127.0.0.1:35357") |
|
620 with open("/etc/heat/api-paste.ini", "wb") as fh: |
|
621 config.write(fh) |
|
622 |
|
623 print "enabling heat services" |
|
624 check_call(["/usr/sbin/svcadm", "enable", "-rs", "heat-api", "heat-db", |
|
625 "heat-engine", "heat-api-cfn", "heat-api-cloudwatch"]) |
|
626 |
|
627 # sleep for a few seconds to let SMF catch up |
|
628 time.sleep(2) |
|
629 |
|
630 print "testing heat" |
|
631 print "heat stack-list:" |
|
632 check_call(["heat", "stack-list"], |
|
633 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
634 "OS_USERNAME": "admin", |
|
635 "OS_PASSWORD": "secrete", |
|
636 "OS_TENANT_NAME": "demo"}) |
|
637 |
|
638 |
|
639 def ironic_prep(): |
|
640 """Prepare ironic user for SSH authentication""" |
|
641 ironic = pwd.getpwnam("ironic") |
|
642 |
|
643 print "creating ssh keys" |
|
644 ironic_pubkey = create_pubkey(ironic) |
|
645 |
|
646 print "setting .ssh/config" |
|
647 ssh_config = "Host *\n\tStrictHostKeyChecking no\n" |
|
648 with open(os.path.join(ironic.pw_dir, ".ssh", "config"), "w") as fh: |
|
649 fh.write(ssh_config) |
|
650 |
|
651 print "populating authorized_keys" |
|
652 path = os.path.join(ironic.pw_dir, ".ssh", "authorized_keys") |
|
653 with open(path, "w") as fh: |
|
654 fh.write(ironic_pubkey) |
|
655 |
|
656 owner = "%s:%s" % (ironic.pw_name, grp.getgrgid(ironic.pw_gid).gr_name) |
|
657 check_call(["chown", "-R", owner, |
|
658 os.path.join(ironic.pw_dir, ".ssh", "authorized_keys")]) |
|
659 |
|
660 |
|
661 def ironic(sqlite): |
|
662 """Configure Ironic for Single Node""" |
|
663 print "configuring ironic" |
|
664 |
|
665 ironic_prep() |
|
666 |
|
667 # Check if keystone installed, if not use noauth |
|
668 pr = Popen(['pkg', 'info', 'cloud/openstack/keystone'], |
|
669 stdout=PIPE, stderr=PIPE) |
|
670 _out, _err = pr.communicate() |
|
671 keystone = (pr.returncode == 0) |
|
672 |
|
673 print "configuring ironic" |
|
674 config = ConfigParser.RawConfigParser() |
|
675 config.readfp(open("/etc/ironic/ironic.conf")) |
|
676 if not keystone: |
|
677 config.set("DEFAULT", "auth_strategy", "noauth") |
|
678 else: |
|
679 config.set("DEFAULT", "auth_strategy", "keystone") |
|
680 config.set("DEFAULT", "enabled_drivers", "solaris") |
|
681 config.set("ai", "server", "localhost") |
|
682 config.set("ai", "username", "ironic") |
|
683 config.set("ai", "port", "22") |
|
684 config.set("ai", "timeout", "10") |
|
685 config.set("ai", "deploy_interval", "30") |
|
686 config.set("ai", "ssh_key_file", "/var/lib/ironic/.ssh/id_rsa") |
|
687 config.set("conductor", "api_url", "http://localhost:6385/") |
|
688 config.set("conductor", "heartbeat_interval", "60") |
|
689 config.set("conductor", "heartbeat_timeout", "60") |
|
690 config.set("conductor", "check_provision_state_interval", "120") |
|
691 config.set("conductor", "sync_power_state_interval", "300") |
|
692 if not sqlite: |
|
693 config.set("database", "connection", |
|
694 "mysql://ironic:ironic@localhost/ironic") |
|
695 else: |
|
696 config.set("database", "connection", |
|
697 "sqlite:////var/lib/ironic/ironic.sqlite") |
|
698 config.set("neutron", "url", "http://localhost:9696") |
|
699 |
|
700 # Glance host needs to be external IP not 127.0.0.1 |
|
701 # Otherwise AI Client won't be able to find real glance host |
|
702 ext_ip = get_external_ip() or "127.0.0.1" |
|
703 |
|
704 config.set("glance", "glance_host", ext_ip) |
|
705 config.set("glance", "glance_port", "9292") |
|
706 config.set("glance", "glance_protocol", "http") |
|
707 config.set("glance", "glance_api_servers", "%s:9292" % ext_ip) |
|
708 |
|
709 config.set("solaris_ipmi", "imagecache_dirname", "/var/lib/ironic/images") |
|
710 config.set("solaris_ipmi", "imagecache_lock_timeout", "60") |
|
711 |
|
712 if not keystone: |
|
713 config.set("glance", "auth_strategy", "noauth") |
|
714 else: |
|
715 config.set("glance", "auth_strategy", "keystone") |
|
716 config.set("keystone_authtoken", "auth_host", "127.0.0.1") |
|
717 config.set("keystone_authtoken", "auth_url", |
|
718 "http://127.0.0.1:5000/v2.0") |
|
719 config.set("keystone_authtoken", "admin_user", "ironic") |
|
720 config.set("keystone_authtoken", "admin_password", "ironic") |
|
721 config.set("keystone_authtoken", "admin_tenant_name", "service") |
|
722 config.set("keystone_authtoken", "signing_dir", |
|
723 "/var/lib/ironic/keystone-signing") |
|
724 config.set("keystone_authtoken", "identity_uri", |
|
725 "http://127.0.0.1:35357") |
|
726 |
|
727 with open("/etc/ironic/ironic.conf", "wb") as fh: |
|
728 config.write(fh) |
|
729 |
|
730 print "enabling ironic services" |
|
731 check_call(["/usr/sbin/svcadm", "enable", "-rs", "ironic-db"]) |
|
732 |
|
733 check_call(["/usr/sbin/svcadm", "enable", "-rs", "ironic-api", |
|
734 "ironic-conductor"]) |
|
735 |
|
736 # sleep for a few seconds to let SMF catch up |
|
737 time.sleep(2) |
|
738 |
|
739 print "testing ironic" |
|
740 print "ironic driver-list:" |
|
741 if keystone: |
|
742 check_call(["ironic", "driver-list"], |
|
743 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
744 "OS_USERNAME": "admin", |
|
745 "OS_PASSWORD": "secrete", |
|
746 "OS_TENANT_NAME": "demo"}) |
|
747 else: |
|
748 check_call(["ironic", "driver-list"], |
|
749 env={"OS_AUTH_URL": "http://localhost:5000/v2.0", |
|
750 "OS_USERNAME": "admin", |
|
751 "OS_PASSWORD": "secrete", |
|
752 "OS_AUTH_TOKEN": "fake-token", |
|
753 "OS_TENANT_NAME": "demo"}) |
|
754 |
|
755 print "NOTE: Ironic expecting AI Server on localhost" |
|
756 |
|
757 |
|
758 def parse_args(args=sys.argv[1:]): |
|
759 parser = OptionParser() |
|
760 parser.add_option('--sqlite', help='user sqlite instead of mysql', |
|
761 action='store_true', dest='sqlite') |
|
762 options, args = parser.parse_args(args) |
|
763 |
|
764 return options, args |
|
765 |
|
766 |
|
767 @with_spinner |
|
768 def pkg_install(pkg): |
|
769 |
|
770 swrite = lambda x: sys.stdout.write('\r' + x + ' ') |
|
771 |
|
772 todo = [] |
|
773 if isinstance(pkg, str): |
|
774 pkg = [pkg] |
|
775 |
|
776 for p in pkg: |
|
777 cmd = ['pkg', 'list', p] |
|
778 try: |
|
779 check_call(cmd, stdout=PIPE, stderr=PIPE) |
|
780 except CalledProcessError: |
|
781 todo.append(p) |
|
782 |
|
783 if not todo: |
|
784 return |
|
785 |
|
786 swrite('installing %s' % ", ".join(pkg)) |
|
787 cmd = ['pkg', 'install', '--accept'] |
|
788 cmd.extend(pkg) |
|
789 |
|
790 p = Popen(cmd, stdout=PIPE, stderr=PIPE) |
|
791 out, err = p.communicate() |
|
792 if p.returncode not in (0, 4): |
|
793 swrite('Error installing: %s' % pkg) |
|
794 swrite('---') |
|
795 swrite(out) |
|
796 swrite('---') |
|
797 swrite(err) |
|
798 |
|
799 |
|
800 def main(args): |
|
801 options, args = parse_args() |
|
802 |
|
803 if not args: |
|
804 args = ["keystone", "glance", "nova", "cinder", "horizon", "swift", |
|
805 "heat", "neutron", "ironic"] |
|
806 |
|
807 cmd = ["svcadm", "restart", "rad:local"] |
|
808 check_call(cmd) |
|
809 |
|
810 # install rabbit if needed and start it |
|
811 pkg_install('rabbitmq') |
|
812 cmd = ["svcs", "-H", "-o", "state", "rabbitmq"] |
|
813 p = Popen(cmd, stdout=PIPE, stderr=PIPE) |
|
814 out, err = p.communicate() |
|
815 if out.strip() == "disabled": |
|
816 check_call(["/usr/sbin/svcadm", "enable", "-rs", "rabbitmq"]) |
|
817 |
|
818 if not options.sqlite: |
|
819 # install mysql if needed and start it |
|
820 pkg_install(['mysql-55', 'mysql-55/client', 'python-mysql']) |
|
821 cmd = ["svcs", "-H", "-o", "state", "mysql"] |
|
822 p = Popen(cmd, stdout=PIPE, stderr=PIPE) |
|
823 out, err = p.communicate() |
|
824 if out.strip() == "disabled": |
|
825 check_call(["/usr/sbin/svcadm", "enable", "-rs", "mysql"]) |
|
826 |
|
827 # sleep for 2 seconds to allow SMF to catch up |
|
828 time.sleep(2) |
|
829 |
|
830 # ignore the Deprecation warning from importing MySQLdb |
|
831 warnings.filterwarnings("ignore") |
|
832 import MySQLdb |
|
833 # create mysql databases |
|
834 for i in range(5): |
|
835 try: |
|
836 db = MySQLdb.connect('localhost', 'root') |
|
837 cursor = db.cursor() |
|
838 break |
|
839 except Exception as err: |
|
840 # mysql isn't ready. sleep for 2 more seconds |
|
841 time.sleep(2) |
|
842 else: |
|
843 sys.exit('unable to connect to mysql: %s' % err) |
|
844 |
|
845 dbs = ["nova", "cinder", "glance", "keystone", "heat", "neutron", |
|
846 "ironic"] |
|
847 |
|
848 # Get list of already existinng databases: |
|
849 cursor.execute("SHOW DATABASES") |
|
850 databases = cursor.fetchall() |
|
851 existing_dbs = [database[0] for database in databases] |
|
852 |
|
853 for name in (db_name for db_name in dbs if db_name not in existing_dbs): |
|
854 # Check if dbs exists, create/grant of it does not |
|
855 print '\ncreating MySQL database %s' % (name) |
|
856 cursor.execute('CREATE DATABASE %s ' |
|
857 'DEFAULT CHARACTER SET utf8 ' |
|
858 'DEFAULT COLLATE utf8_general_ci;' % name) |
|
859 cursor.execute("GRANT ALL PRIVILEGES ON %s.* TO '%s'@'localhost' IDENTIFIED BY '%s';" % (name, name, name)) |
|
860 cursor.execute("FLUSH PRIVILEGES;") |
|
861 db.commit() |
|
862 db.close() |
|
863 |
|
864 if "keystone" in args: |
|
865 keystone(options.sqlite) |
|
866 |
|
867 if "glance" in args: |
|
868 glance(options.sqlite) |
|
869 |
|
870 if "nova" in args: |
|
871 nova(options.sqlite) |
|
872 |
|
873 if "cinder" in args: |
|
874 cinder(options.sqlite) |
|
875 |
|
876 if "horizon" in args: |
|
877 horizon() |
|
878 |
|
879 if "neutron" in args: |
|
880 neutron(options.sqlite) |
|
881 |
|
882 if "swift" in args: |
|
883 swift() |
|
884 |
|
885 if "heat" in args: |
|
886 heat(options.sqlite) |
|
887 |
|
888 if "ironic" in args: |
|
889 ironic(options.sqlite) |
|
890 |
|
891 if __name__ == "__main__": |
|
892 main(sys.argv[1:]) |