 13a2f677ed
			
		
	
	13a2f677ed
	
	
	
		
			
			This is a comma separated list of servers to be excluded from installation in case you are running Packstack the second time with the same answer file and don't want Packstack to touch these servers. For example, suppose that you've already installed the following hosts: - Controller node : 10.0.0.99 - Compute nodes : 10.0.0.100 - 10.0.0.110 and you want add one more compute node 10.0.0.111. Then you can reuse the previous answer file with the following modification: - Add 10.0.0.111 to NOVACOMPUTE_HOSTS - Add existing hosts (10.0.0.99 - 10.0.0.110) to EXCLUDE_SERVERS This avoids applying puppet modules to existing hosts again. (In theory, because of idempotentness of puppet manifests, applying the same modules does no harm. But it is a waste of time and has a potential risk of breaking manual configurations which has been done after the packstack installation.) Change-Id: Ib3dcd94a25a286f82cc0fcedebd1824b1d27d864
		
			
				
	
	
		
			224 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Installs and configures puppet
 | |
| """
 | |
| import sys
 | |
| import logging
 | |
| import os
 | |
| import platform
 | |
| import time
 | |
| 
 | |
| from packstack.installer import utils
 | |
| from packstack.installer import basedefs, output_messages
 | |
| from packstack.installer.exceptions import ScriptRuntimeError
 | |
| 
 | |
| from packstack.modules.ospluginutils import (gethostlist,
 | |
|                                              manifestfiles,
 | |
|                                              scan_puppet_logfile,
 | |
|                                              validate_puppet_logfile)
 | |
| 
 | |
| # Controller object will be initialized from main flow
 | |
| controller = None
 | |
| 
 | |
| # Plugin name
 | |
| PLUGIN_NAME = "OSPUPPET"
 | |
| PLUGIN_NAME_COLORED = utils.color_text(PLUGIN_NAME, 'blue')
 | |
| 
 | |
| logging.debug("plugin %s loaded", __name__)
 | |
| 
 | |
| PUPPETDIR = os.path.abspath(os.path.join(basedefs.DIR_PROJECT_DIR, 'puppet'))
 | |
| MODULEDIR = os.path.join(PUPPETDIR, "modules")
 | |
| 
 | |
| 
 | |
| def initConfig(controllerObject):
 | |
|     global controller
 | |
|     controller = controllerObject
 | |
|     logging.debug("Adding OpenStack Puppet configuration")
 | |
|     paramsList = [
 | |
|                  ]
 | |
| 
 | |
|     groupDict = {"GROUP_NAME"            : "PUPPET",
 | |
|                  "DESCRIPTION"           : "Puppet Config parameters",
 | |
|                  "PRE_CONDITION"         : lambda x: 'yes',
 | |
|                  "PRE_CONDITION_MATCH"   : "yes",
 | |
|                  "POST_CONDITION"        : False,
 | |
|                  "POST_CONDITION_MATCH"  : True}
 | |
| 
 | |
|     controller.addGroup(groupDict, paramsList)
 | |
| 
 | |
| 
 | |
| def getinstallhostlist(conf):
 | |
|     list = []
 | |
|     exclude_list = map(str.strip, conf['EXCLUDE_SERVERS'].split(','))
 | |
|     for host in gethostlist(conf):
 | |
|         if host not in exclude_list:
 | |
|             list.append(host)
 | |
|     return list
 | |
| 
 | |
| 
 | |
| def initSequences(controller):
 | |
|     puppetpresteps = [
 | |
|              {'title': 'Clean Up', 'functions':[runCleanup]},
 | |
|     ]
 | |
|     controller.insertSequence("Clean Up", [], [], puppetpresteps, index=0)
 | |
| 
 | |
|     puppetsteps = [
 | |
|              {'title': 'Installing Dependencies', 'functions':[installdeps]},
 | |
|              {'title': 'Copying Puppet modules and manifests', 'functions':[copyPuppetModules]},
 | |
|              {'title': 'Applying Puppet manifests', 'functions':[applyPuppetManifest]},
 | |
|     ]
 | |
|     controller.addSequence("Puppet", [], [], puppetsteps)
 | |
| 
 | |
| 
 | |
| def runCleanup(config):
 | |
|     localserver = utils.ScriptRunner()
 | |
|     localserver.append("rm -rf %s/*pp" % basedefs.PUPPET_MANIFEST_DIR)
 | |
|     localserver.execute()
 | |
| 
 | |
| 
 | |
| def installdeps(config):
 | |
|     for hostname in getinstallhostlist(controller.CONF):
 | |
|         server = utils.ScriptRunner(hostname)
 | |
|         for package in ("puppet", "openssh-clients", "tar", "nc"):
 | |
|             server.append("rpm -q %s || yum install -y %s" % (package, package))
 | |
|         server.execute()
 | |
| 
 | |
| 
 | |
| def copyPuppetModules(config):
 | |
|     os_modules = ' '.join(('apache', 'cinder', 'concat',
 | |
|                            'create_resources', 'firewall',
 | |
|                            'glance', 'horizon', 'inifile',
 | |
|                            'keystone', 'memcached', 'mysql',
 | |
|                            'nova', 'openstack', 'packstack',
 | |
|                            'qpid', 'quantum', 'rsync', 'ssh', 'stdlib',
 | |
|                            'swift', 'sysctl', 'vlan', 'vswitch', 'xinetd'))
 | |
| 
 | |
|     # write puppet manifest to disk
 | |
|     manifestfiles.writeManifests()
 | |
| 
 | |
|     server = utils.ScriptRunner()
 | |
|     tar_opts = ""
 | |
|     if platform.linux_distribution()[0] == "Fedora":
 | |
|         tar_opts += "--exclude create_resources "
 | |
|     for hostname in getinstallhostlist(controller.CONF):
 | |
|         host_dir = controller.temp_map[hostname]
 | |
|         puppet_dir = os.path.join(host_dir, basedefs.PUPPET_MANIFEST_RELATIVE)
 | |
|         server.append("cd %s/puppet" % basedefs.DIR_PROJECT_DIR)
 | |
|         # copy Packstack facts
 | |
|         server.append("tar %s --dereference -cpzf - facts | "
 | |
|                       "ssh -o StrictHostKeyChecking=no "
 | |
|                           "-o UserKnownHostsFile=/dev/null "
 | |
|                           "root@%s tar -C %s -xpzf -" % (tar_opts, hostname, host_dir))
 | |
|         # copy Packstack manifests
 | |
|         server.append("cd %s" % basedefs.PUPPET_MANIFEST_DIR)
 | |
|         server.append("tar %s --dereference -cpzf - ../manifests | "
 | |
|                       "ssh -o StrictHostKeyChecking=no "
 | |
|                           "-o UserKnownHostsFile=/dev/null "
 | |
|                           "root@%s tar -C %s -xpzf -" % (tar_opts, hostname, host_dir))
 | |
| 
 | |
|         # copy resources
 | |
|         for path, localname in controller.resources.get(hostname, []):
 | |
|             server.append("scp -o StrictHostKeyChecking=no "
 | |
|                 "-o UserKnownHostsFile=/dev/null %s root@%s:%s/resources/%s" %
 | |
|                 (path, hostname, host_dir, localname))
 | |
| 
 | |
|         # copy Puppet modules required by Packstack
 | |
|         server.append("cd %s/puppet/modules" % basedefs.DIR_PROJECT_DIR)
 | |
|         server.append("tar %s --dereference -cpzf - %s | "
 | |
|                       "ssh -o StrictHostKeyChecking=no "
 | |
|                           "-o UserKnownHostsFile=/dev/null "
 | |
|                           "root@%s tar -C %s -xpzf -" %
 | |
|                                 (tar_opts, os_modules, hostname,
 | |
|                                  os.path.join(host_dir, 'modules')))
 | |
|     server.execute()
 | |
| 
 | |
| 
 | |
| def waitforpuppet(currently_running):
 | |
|     global controller
 | |
|     log_len = 0
 | |
|     twirl = ["-","\\","|","/"]
 | |
|     while currently_running:
 | |
|         for hostname, finished_logfile in currently_running:
 | |
|             log_file = os.path.splitext(os.path.basename(finished_logfile))[0]
 | |
|             space_len = basedefs.SPACE_LEN - len(log_file)
 | |
|             if len(log_file) > log_len:
 | |
|                 log_len = len(log_file)
 | |
|             if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
 | |
|                 twirl = twirl[-1:] + twirl[:-1]
 | |
|                 sys.stdout.write(("\rTesting if puppet apply is finished : %s" % log_file).ljust(40 + log_len))
 | |
|                 sys.stdout.write("[ %s ]" % twirl[0])
 | |
|                 sys.stdout.flush()
 | |
|             try:
 | |
|                 # Once a remote puppet run has finished, we retrieve the log
 | |
|                 # file and check it for errors
 | |
|                 local_server = utils.ScriptRunner()
 | |
|                 log = os.path.join(basedefs.PUPPET_MANIFEST_DIR,
 | |
|                                    os.path.basename(finished_logfile).replace(".finished", ".log"))
 | |
|                 local_server.append('scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@%s:%s %s' % (hostname, finished_logfile, log))
 | |
|                 # Errors are expected here if the puppet run isn't finished so we suppress logging them
 | |
|                 local_server.execute(logerrors=False)
 | |
| 
 | |
|                 # If we got to this point the puppet apply has finished
 | |
|                 currently_running.remove((hostname, finished_logfile))
 | |
| 
 | |
|                 # clean off the last "testing apply" msg
 | |
|                 if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
 | |
|                     sys.stdout.write(("\r").ljust(45 + log_len))
 | |
| 
 | |
|             except ScriptRuntimeError, e:
 | |
|                 # the test raises an exception if the file doesn't exist yet
 | |
|                 # TO-DO: We need to start testing 'e' for unexpected exceptions
 | |
|                 time.sleep(3)
 | |
|                 continue
 | |
| 
 | |
|             # check log file for relevant notices
 | |
|             controller.MESSAGES.extend(scan_puppet_logfile(log))
 | |
| 
 | |
|             # check the log file for errors
 | |
|             validate_puppet_logfile(log)
 | |
|             sys.stdout.write(("\r%s : " % log_file).ljust(basedefs.SPACE_LEN))
 | |
|             print ("[ " + utils.color_text(output_messages.INFO_DONE, 'green') + " ]")
 | |
| 
 | |
| 
 | |
| def applyPuppetManifest(config):
 | |
|     print
 | |
|     currently_running = []
 | |
|     lastmarker = None
 | |
|     for manifest, marker in manifestfiles.getFiles():
 | |
|         # if the marker has changed then we don't want to proceed until
 | |
|         # all of the previous puppet runs have finished
 | |
|         if lastmarker != None and lastmarker != marker:
 | |
|             waitforpuppet(currently_running)
 | |
|         lastmarker = marker
 | |
| 
 | |
|         for hostname in getinstallhostlist(controller.CONF):
 | |
|             if "%s_" % hostname not in manifest:
 | |
|                 continue
 | |
| 
 | |
|             host_dir = controller.temp_map[hostname]
 | |
|             print "Applying " + manifest
 | |
|             server = utils.ScriptRunner(hostname)
 | |
| 
 | |
|             man_path = os.path.join(controller.temp_map[hostname],
 | |
|                                     basedefs.PUPPET_MANIFEST_RELATIVE,
 | |
|                                     manifest)
 | |
| 
 | |
|             running_logfile = "%s.running" % man_path
 | |
|             finished_logfile = "%s.finished" % man_path
 | |
|             currently_running.append((hostname, finished_logfile))
 | |
|             # The apache puppet module doesn't work if we set FACTERLIB
 | |
|             # https://github.com/puppetlabs/puppetlabs-apache/pull/138
 | |
|             if not (manifest.endswith('_horizon.pp') or manifest.endswith('_nagios.pp')):
 | |
|                 server.append("export FACTERLIB=$FACTERLIB:%s/facts" % host_dir)
 | |
|             server.append("touch %s" % running_logfile)
 | |
|             server.append("chmod 600 %s" % running_logfile)
 | |
|             server.append("export PACKSTACK_VAR_DIR=%s" % host_dir)
 | |
|             loglevel = ''
 | |
|             if logging.root.level <= logging.DEBUG:
 | |
|                 loglevel = '--debug'
 | |
|             command = "( flock %s/ps.lock puppet apply %s --modulepath %s/modules %s > %s 2>&1 < /dev/null ; mv %s %s ) > /dev/null 2>&1 < /dev/null &" % (host_dir, loglevel, host_dir, man_path, running_logfile, running_logfile, finished_logfile)
 | |
|             server.append(command)
 | |
|             server.execute()
 | |
| 
 | |
|     # wait for outstanding puppet runs befor exiting
 | |
|     waitforpuppet(currently_running)
 |