components/openstack/common/openstack_single_host.py
changeset 3998 5bd484384122
equal deleted inserted replaced
3997:0ca3f3d6c919 3998:5bd484384122
       
     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:])