Merge "Refactored packstack.installer.setup_sequences"
This commit is contained in:
@@ -41,10 +41,5 @@ EXEC_CHKCONFIG = "chkconfig"
|
||||
EXEC_SERVICE = "service"
|
||||
EXEC_IP = "ip"
|
||||
|
||||
# text colors
|
||||
NO_COLOR = "\033[0m"
|
||||
COLORS = {'red': "\033[0;31m", 'green': "\033[92m", 'blue': "\033[94m",
|
||||
'yellow': "\033[93m"}
|
||||
|
||||
# space len size for color print
|
||||
SPACE_LEN = 70
|
||||
|
||||
105
packstack/installer/core/sequences.py
Normal file
105
packstack/installer/core/sequences.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Base class for steps & sequences
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from .. import utils
|
||||
from ..exceptions import SequenceError
|
||||
|
||||
|
||||
class Step(object):
|
||||
"""
|
||||
Wrapper for function representing single setup step.
|
||||
"""
|
||||
def __init__(self, name, function, title=None):
|
||||
self.name = name
|
||||
self.title = title or ('Step: %s' % name)
|
||||
|
||||
# process step function
|
||||
if function and not callable(function):
|
||||
raise SequenceError("Function object have to be callable. "
|
||||
"Object %s is not callable." % function)
|
||||
self.function = function
|
||||
|
||||
def run(self, config=None):
|
||||
config = config or {}
|
||||
# TO-DO: complete logger name when logging will be setup correctly
|
||||
logger = logging.getLogger()
|
||||
logger.debug('Running step %s.' % self.name)
|
||||
sys.stdout.write('%s...' % self.title)
|
||||
sys.stdout.flush()
|
||||
|
||||
# count space needed for title print
|
||||
title = self.title
|
||||
for color in utils.COLORS.itervalues():
|
||||
title = re.sub(re.escape(color), '', title)
|
||||
space = 70 - len(title)
|
||||
|
||||
# execute and report state
|
||||
state_fmt = '[ %s ]\n'
|
||||
try:
|
||||
self.function(config)
|
||||
except Exception, ex:
|
||||
logger.debug(traceback.format_exc())
|
||||
state = state_fmt % utils.color_text('ERROR', 'red')
|
||||
sys.stdout.write(state.rjust(space))
|
||||
sys.stdout.flush()
|
||||
raise SequenceError(str(ex))
|
||||
else:
|
||||
state = state_fmt % utils.color_text('DONE', 'green')
|
||||
sys.stdout.write(state.rjust(space))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
|
||||
class Sequence(object):
|
||||
"""
|
||||
Wrapper for sequence of setup steps.
|
||||
"""
|
||||
def __init__(self, name, steps, title=None, condition=None,
|
||||
cond_match=None):
|
||||
self.name = name
|
||||
self.title = title
|
||||
self.condition = condition
|
||||
self.cond_match = cond_match
|
||||
|
||||
# process sequence steps
|
||||
self.steps = utils.SortedDict()
|
||||
for step in steps:
|
||||
name, func = step['name'], step['function']
|
||||
self.steps[name] = Step(name, func, title=step.get('title'))
|
||||
|
||||
def validate_condition(self, config):
|
||||
"""
|
||||
Returns True if config option condition has value given
|
||||
in cond_match. Otherwise returns False.
|
||||
"""
|
||||
if not self.condition:
|
||||
return True
|
||||
result = config.get(self.condition)
|
||||
return result == self.cond_match
|
||||
|
||||
def run(self, config=None, step=None):
|
||||
"""
|
||||
Runs sequence of steps. Runs only specific step if step's name
|
||||
is given via 'step' parameter.
|
||||
"""
|
||||
config = config or {}
|
||||
if not self.validate_condition(config):
|
||||
return
|
||||
if step:
|
||||
self.steps[step].run(config=config)
|
||||
return
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.debug('Running sequence %s.' % self.name)
|
||||
if self.title:
|
||||
sys.stdout.write('%s\n' % self.title)
|
||||
sys.stdout.flush()
|
||||
for step in self.steps.itervalues():
|
||||
step.run(config=config)
|
||||
@@ -64,5 +64,11 @@ class ScriptRuntimeError(PackStackError):
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class ExecuteRuntimeError(PackStackError):
|
||||
"""Raised when utils.execute does not end successfully."""
|
||||
|
||||
|
||||
class SequenceError(PackStackError):
|
||||
"""Exception for errors during setup sequence run."""
|
||||
pass
|
||||
|
||||
@@ -3,7 +3,15 @@ Controller class is a SINGLETON which handles all groups, params, sequences,
|
||||
steps and replaces the CONF dictionary.
|
||||
"""
|
||||
from setup_params import Group
|
||||
from setup_sequences import Sequence
|
||||
from .core.sequences import Sequence
|
||||
|
||||
|
||||
def steps_new_format(steplist):
|
||||
# we have to duplicate title to name parameter and also only sigle
|
||||
# function is allowed in new step
|
||||
return [{'name': i['title'], 'title': i['title'],
|
||||
'function': i['functions'][0]} for i in steplist]
|
||||
|
||||
|
||||
class Controller(object):
|
||||
|
||||
@@ -64,27 +72,32 @@ class Controller(object):
|
||||
|
||||
# Sequences and steps
|
||||
def addSequence(self, desc, cond, cond_match, steps):
|
||||
self.__SEQUENCES.append(Sequence(desc, cond, cond_match, steps))
|
||||
self.__SEQUENCES.append(Sequence(desc, steps_new_format(steps),
|
||||
condition=cond,
|
||||
cond_match=cond_match))
|
||||
|
||||
def insertSequence(self, desc, cond, cond_match, steps, index=0):
|
||||
self.__SEQUENCES.insert(index, Sequence(desc, cond, cond_match, steps))
|
||||
self.__SEQUENCES.insert(index, Sequence(desc,
|
||||
steps_new_format(steps),
|
||||
condition=cond,
|
||||
cond_match=cond_match))
|
||||
|
||||
def getAllSequences(self):
|
||||
return self.__SEQUENCES
|
||||
|
||||
def runAllSequences(self):
|
||||
for sequence in self.__SEQUENCES:
|
||||
sequence.run()
|
||||
sequence.run(self.CONF)
|
||||
|
||||
def getSequenceByDesc(self, desc):
|
||||
for sequence in self.getAllSequences():
|
||||
if sequence.getDescription() == desc:
|
||||
if sequence.name == desc:
|
||||
return sequence
|
||||
return None
|
||||
|
||||
def __getSequenceIndexByDesc(self, desc):
|
||||
for sequence in self.getAllSequences():
|
||||
if sequence.getDescription() == desc:
|
||||
if sequence.name == desc:
|
||||
return self.__SEQUENCES.index(sequence)
|
||||
return None
|
||||
|
||||
@@ -97,7 +110,10 @@ class Controller(object):
|
||||
index = self.__getSequenceIndexByDesc(sequenceName)
|
||||
if index == None:
|
||||
index = len(self.getAllSequences())
|
||||
self.__SEQUENCES.insert(index, Sequence(desc, cond, cond_match, steps))
|
||||
self.__SEQUENCES.insert(index, Sequence(desc,
|
||||
steps_new_format(steps),
|
||||
condition=cond,
|
||||
cond_match=cond_match))
|
||||
|
||||
# Groups and params
|
||||
def addGroup(self, group, params):
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
"""
|
||||
Base class for steps & sequences
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
import re
|
||||
import string
|
||||
import traceback
|
||||
import basedefs
|
||||
import output_messages
|
||||
from . import utils
|
||||
|
||||
class Step(object):
|
||||
def __init__(self, title=None, functions=[]):
|
||||
self.__TITLE = None
|
||||
self.__FUNCTIONS = []
|
||||
if title:
|
||||
if not isinstance(title, str):
|
||||
raise TypeError("step's title should be of string type instead of %s" % type(title))
|
||||
if not isinstance(functions, list):
|
||||
raise TypeError("step's function should be of list type instead of %s" % type(functions))
|
||||
for function in functions:
|
||||
if not callable(function):
|
||||
raise TypeError("All parameters which pass as functions should be callable. %s is not callable" % function)
|
||||
|
||||
self.setTitle(title)
|
||||
for function in functions:
|
||||
self.addFunction(function)
|
||||
|
||||
def setTitle(self, title):
|
||||
self.__TITLE = title
|
||||
|
||||
def getTitle(self):
|
||||
return self.__TITLE
|
||||
|
||||
def addFunction(self, function):
|
||||
self.__FUNCTIONS.append(function)
|
||||
|
||||
def removeFunction(self, function):
|
||||
self.__FUNCTIONS.remove(function)
|
||||
|
||||
def getFunctions(self):
|
||||
return self.__FUNCTIONS
|
||||
|
||||
def run(self):
|
||||
# keep relative space
|
||||
# allow newline chars in title. This is useful for plugins
|
||||
alignedTitle = self.getTitle()
|
||||
if re.search('\n', alignedTitle):
|
||||
alignedTitle = self.getTitle().split('\n')[-1]
|
||||
for color in basedefs.COLORS:
|
||||
if color in alignedTitle:
|
||||
alignedTitle = string.replace(alignedTitle, color, '')
|
||||
spaceLen = basedefs.SPACE_LEN - len(alignedTitle)
|
||||
print "%s..."%(self.getTitle()),
|
||||
sys.stdout.flush()
|
||||
for function in self.getFunctions():
|
||||
try:
|
||||
logging.debug("running %s"%(function.func_name))
|
||||
function()
|
||||
except:
|
||||
logging.debug(traceback.format_exc())
|
||||
raise
|
||||
print ("[ " + utils.color_text(output_messages.INFO_DONE, 'green') + " ]").rjust(spaceLen)
|
||||
|
||||
class Sequence(object):
|
||||
"""
|
||||
Gets 4 parameters:
|
||||
description, condition's name/function, condition's expected result and steps
|
||||
steps should be a list of dictionaries, example:
|
||||
[ { 'title' : 'step1's title',
|
||||
'functions' : [ func1, func2, func3 ] },
|
||||
{ 'title' : 'step2's tittle',
|
||||
'functions' : [ func4, func6 ] } ]
|
||||
"""
|
||||
def __init__(self, desc=None, cond=[], cond_match=[], steps=[]):
|
||||
self.__DESCRIPTION = None
|
||||
self.__CONDITION = None
|
||||
self.__COND_MATCH = None
|
||||
self.__STEPS = []
|
||||
|
||||
self.setDescription(desc)
|
||||
self.setCondition(cond, cond_match)
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
raise TypeError("step should be of dictionary type instead of %s" % type(step))
|
||||
self.addStep(step['title'], step['functions'])
|
||||
|
||||
def addStep(self, title, functions):
|
||||
self.__STEPS.append(Step(title, functions))
|
||||
|
||||
def setDescription(self, desc):
|
||||
self.__DESCRIPTION = desc
|
||||
|
||||
def getDescription(self):
|
||||
return self.__DESCRIPTION
|
||||
|
||||
def getSteps(self):
|
||||
return self.__STEPS
|
||||
|
||||
def getStepByTitle(self, stepTitle):
|
||||
for step in self.__STEPS:
|
||||
if step.getTitle == stepTitle:
|
||||
return step
|
||||
return None
|
||||
|
||||
def setCondition(self, cond, cond_match):
|
||||
for item in [cond, cond_match]:
|
||||
if not isinstance(item, list):
|
||||
raise TypeError("supplied parameter should be of list type instead of %s" % type(item))
|
||||
|
||||
self.__CONDITION = cond
|
||||
self.__COND_MATCH = cond_match
|
||||
|
||||
def __validateCondition(self):
|
||||
"""
|
||||
Both _CONDITION & _COND_MATCH are lists.
|
||||
if any of them is a function that needs to be run, the first member
|
||||
of the list is the function and the rest of the members in that list
|
||||
are the params for the said function
|
||||
i.e. self._CONDITION = [function, arg1, arg2]
|
||||
will be executed as function(arg1, arg2)
|
||||
if the first member of the list is not a function. we handle it
|
||||
as anything else (i.e. string/bool etc)
|
||||
"""
|
||||
if len(self.__CONDITION) < 1 and len(self.__COND_MATCH) < 1:
|
||||
return True
|
||||
|
||||
condResult = None
|
||||
condMatchResult = None
|
||||
|
||||
if callable(self.__CONDITION[0]):
|
||||
condResult = self.__CONDITION[0](*self.__CONDITION[1:])
|
||||
else:
|
||||
condResult = self.__CONDITION[0]
|
||||
|
||||
if callable(self.__COND_MATCH[0]):
|
||||
condMatchResult = self.__COND_MATCH[0](*self.__COND_MATCH[1:])
|
||||
else:
|
||||
condMatchResult = self.__COND_MATCH[0]
|
||||
|
||||
if condResult == condMatchResult:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def removeStepByTitle(self, stepTitle):
|
||||
self.__STEPS.remove(stepTitle)
|
||||
|
||||
def run(self):
|
||||
if self.__validateCondition():
|
||||
for step in self.__STEPS:
|
||||
step.run()
|
||||
|
||||
def runStepByTitle(self, stepTitle):
|
||||
step = self.getStepByTitle(stepTitle)
|
||||
step.run()
|
||||
|
||||
def listStepsByTitle(self):
|
||||
output = []
|
||||
for step in self.__STEPS:
|
||||
output.append(step.getTitle())
|
||||
return output
|
||||
@@ -4,11 +4,11 @@ from .datastructures import SortedDict
|
||||
from .decorators import retry
|
||||
from .network import get_localhost_ip, host2ip, force_ip, device_from_ip
|
||||
from .shell import ScriptRunner, execute
|
||||
from .strings import color_text, mask_string
|
||||
from .strings import COLORS, color_text, mask_string
|
||||
|
||||
|
||||
__all__ = ('SortedDict',
|
||||
'retry',
|
||||
'ScriptRunner', 'execute',
|
||||
'get_localhost_ip', 'host2ip', 'force_ip', 'device_from_ip',
|
||||
'color_text', 'mask_string')
|
||||
'COLORS', 'color_text', 'mask_string')
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .. import basedefs
|
||||
|
||||
|
||||
STR_MASK = '*' * 8
|
||||
COLORS = {'nocolor': "\033[0m", 'red': "\033[0;31m",
|
||||
'green': "\033[92m", 'blue': "\033[94m",
|
||||
'yellow': "\033[93m"}
|
||||
|
||||
|
||||
def color_text(text, color):
|
||||
@@ -11,7 +12,7 @@ def color_text(text, color):
|
||||
Returns given text string with appropriate color tag. Allowed values
|
||||
for color parameter are 'red', 'blue', 'green' and 'yellow'.
|
||||
"""
|
||||
return '%s%s%s' % (basedefs.COLORS[color], text, basedefs.NO_COLOR)
|
||||
return '%s%s%s' % (COLORS[color], text, COLORS['nocolor'])
|
||||
|
||||
|
||||
def mask_string(unmasked, mask_list=None, replace_list=None):
|
||||
|
||||
@@ -136,12 +136,12 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing OpenStack Cinder", [], [], cinder_steps)
|
||||
|
||||
def install_cinder_deps():
|
||||
def install_cinder_deps(config):
|
||||
server = utils.ScriptRunner(controller.CONF['CONFIG_CINDER_HOST'])
|
||||
server.append("rpm -q %(package)s || yum install -y %(package)s" % {'package': "lvm2"})
|
||||
server.execute()
|
||||
|
||||
def check_cinder_vg():
|
||||
def check_cinder_vg(config):
|
||||
|
||||
cinders_volume = 'cinder-volumes'
|
||||
|
||||
@@ -211,13 +211,13 @@ def check_cinder_vg():
|
||||
raise exceptions.MissingRequirements(err)
|
||||
|
||||
|
||||
def create_keystone_manifest():
|
||||
def create_keystone_manifest(config):
|
||||
manifestfile = "%s_keystone.pp" % controller.CONF['CONFIG_KEYSTONE_HOST']
|
||||
manifestdata = getManifestTemplate("keystone_cinder.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def create_manifest():
|
||||
def create_manifest(config):
|
||||
manifestfile = "%s_cinder.pp" % controller.CONF['CONFIG_CINDER_HOST']
|
||||
manifestdata = getManifestTemplate("cinder.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
@@ -109,7 +109,7 @@ def initSequences(controller):
|
||||
controller.addSequence("Installing OpenStack Horizon", [], [], steps)
|
||||
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
controller.CONF["CONFIG_HORIZON_SECRET_KEY"] = uuid.uuid4().hex
|
||||
horizon_host = controller.CONF['CONFIG_HORIZON_HOST']
|
||||
manifestfile = "%s_horizon.pp" % horizon_host
|
||||
|
||||
@@ -87,12 +87,12 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing OpenStack Glance", [], [], glancesteps)
|
||||
|
||||
def createkeystonemanifest():
|
||||
def createkeystonemanifest(config):
|
||||
manifestfile = "%s_keystone.pp" % controller.CONF['CONFIG_KEYSTONE_HOST']
|
||||
manifestdata = getManifestTemplate("keystone_glance.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
manifestfile = "%s_glance.pp" % controller.CONF['CONFIG_GLANCE_HOST']
|
||||
manifestdata = getManifestTemplate("glance.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
@@ -92,7 +92,7 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing OpenStack Keystone", [], [], keystonesteps)
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
|
||||
manifestdata = getManifestTemplate("keystone.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
@@ -81,7 +81,7 @@ def initSequences(controller):
|
||||
controller.addSequence("Installing MySQL", [], [], mysqlsteps)
|
||||
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
host = controller.CONF['CONFIG_MYSQL_HOST']
|
||||
manifestfile = "%s_mysql.pp" % host
|
||||
manifestdata = [getManifestTemplate("mysql.pp")]
|
||||
|
||||
@@ -99,7 +99,7 @@ def nagios_host(hostname, **kwargs):
|
||||
return "%s}\n" % out
|
||||
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
manifest_entries = ''
|
||||
# I should be adding service entries with nagios_service but it appears to be broken
|
||||
# http://projects.puppetlabs.com/issues/3420
|
||||
@@ -167,7 +167,7 @@ def createmanifest():
|
||||
manifestdata = getManifestTemplate("nagios_server.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
def createnrpemanifests():
|
||||
def createnrpemanifests(config):
|
||||
for hostname in gethostlist(controller.CONF):
|
||||
controller.CONF['CONFIG_NRPE_HOST'] = hostname
|
||||
manifestfile = "%s_nagios_nrpe.pp" % hostname
|
||||
|
||||
@@ -272,25 +272,25 @@ def initSequences(controller):
|
||||
controller.addSequence("Installing OpenStack Nova API", [], [], novaapisteps)
|
||||
|
||||
|
||||
def createapimanifest():
|
||||
def createapimanifest(config):
|
||||
manifestfile = "%s_api_nova.pp"%controller.CONF['CONFIG_NOVA_API_HOST']
|
||||
manifestdata = getManifestTemplate("nova_api.pp")
|
||||
appendManifestFile(manifestfile, manifestdata, 'novaapi')
|
||||
|
||||
|
||||
def createkeystonemanifest():
|
||||
def createkeystonemanifest(config):
|
||||
manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
|
||||
manifestdata = getManifestTemplate("keystone_nova.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createcertmanifest():
|
||||
def createcertmanifest(config):
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_CERT_HOST']
|
||||
manifestdata = getManifestTemplate("nova_cert.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createconductormanifest():
|
||||
def createconductormanifest(config):
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_CONDUCTOR_HOST']
|
||||
manifestdata = getManifestTemplate("nova_conductor.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
@@ -328,7 +328,7 @@ def bring_up_ifcfg(host, device):
|
||||
raise ScriptRuntimeError(msg)
|
||||
|
||||
|
||||
def createcomputemanifest():
|
||||
def createcomputemanifest(config):
|
||||
for host in controller.CONF["CONFIG_NOVA_COMPUTE_HOSTS"].split(","):
|
||||
host = host.strip()
|
||||
controller.CONF["CONFIG_NOVA_COMPUTE_HOST"] = host
|
||||
@@ -348,7 +348,7 @@ def createcomputemanifest():
|
||||
appendManifestFile(manifestfile, manifestdata + "\n" + nova_config_options.getManifestEntry())
|
||||
|
||||
|
||||
def createnetworkmanifest():
|
||||
def createnetworkmanifest(config):
|
||||
host = controller.CONF['CONFIG_NOVA_NETWORK_HOST']
|
||||
for i in ('CONFIG_NOVA_NETWORK_PRIVIF', 'CONFIG_NOVA_NETWORK_PUBIF'):
|
||||
check_ifcfg(host, controller.CONF[i])
|
||||
@@ -373,19 +373,19 @@ def createnetworkmanifest():
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createschedmanifest():
|
||||
def createschedmanifest(config):
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_SCHED_HOST']
|
||||
manifestdata = getManifestTemplate("nova_sched.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createvncproxymanifest():
|
||||
def createvncproxymanifest(config):
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_VNCPROXY_HOST']
|
||||
manifestdata = getManifestTemplate("nova_vncproxy.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createcommonmanifest():
|
||||
def createcommonmanifest(config):
|
||||
for manifestfile, marker in manifestfiles.getFiles():
|
||||
if manifestfile.endswith("_nova.pp"):
|
||||
data = getManifestTemplate("nova_common.pp")
|
||||
|
||||
@@ -57,7 +57,7 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing OpenStack Client", [], [], osclientsteps)
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
client_host = controller.CONF['CONFIG_OSCLIENT_HOST'].strip()
|
||||
manifestfile = "%s_osclient.pp" % client_host
|
||||
manifestdata = getManifestTemplate("openstack_client.pp")
|
||||
|
||||
@@ -42,7 +42,7 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Running post install scripts", [], [], osclientsteps)
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
for hostname in gethostlist(controller.CONF):
|
||||
manifestfile = "%s_postscript.pp" % hostname
|
||||
manifestdata = getManifestTemplate("postscript.pp")
|
||||
|
||||
@@ -146,13 +146,13 @@ def initSequences(controller):
|
||||
'instances might be problem for '
|
||||
'some OpenStack components.')
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
for hostname in gethostlist(controller.CONF):
|
||||
manifestfile = "%s_prescript.pp" % hostname
|
||||
manifestdata = getManifestTemplate("prescript.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
def create_ntp_manifest():
|
||||
def create_ntp_manifest(config):
|
||||
servers = ''
|
||||
for srv in controller.CONF['CONFIG_NTP_SERVERS'].split(','):
|
||||
srv = srv.strip()
|
||||
|
||||
@@ -59,13 +59,13 @@ def initSequences(controller):
|
||||
controller.addSequence("Puppet", [], [], puppetsteps)
|
||||
|
||||
|
||||
def runCleanup():
|
||||
def runCleanup(config):
|
||||
localserver = utils.ScriptRunner()
|
||||
localserver.append("rm -rf %s/*pp" % basedefs.PUPPET_MANIFEST_DIR)
|
||||
localserver.execute()
|
||||
|
||||
|
||||
def installdeps():
|
||||
def installdeps(config):
|
||||
for hostname in gethostlist(controller.CONF):
|
||||
server = utils.ScriptRunner(hostname)
|
||||
for package in ("puppet", "openssh-clients", "tar"):
|
||||
@@ -73,7 +73,7 @@ def installdeps():
|
||||
server.execute()
|
||||
|
||||
|
||||
def copyPuppetModules():
|
||||
def copyPuppetModules(config):
|
||||
os_modules = ' '.join(('apache', 'cinder', 'concat',
|
||||
'create_resources', 'firewall',
|
||||
'glance', 'horizon', 'inifile',
|
||||
@@ -165,7 +165,7 @@ def waitforpuppet(currently_running):
|
||||
print ("[ " + utils.color_text(output_messages.INFO_DONE, 'green') + " ]")
|
||||
|
||||
|
||||
def applyPuppetManifest():
|
||||
def applyPuppetManifest(config):
|
||||
print
|
||||
currently_running = []
|
||||
lastmarker = None
|
||||
|
||||
@@ -57,7 +57,7 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing QPID", [], [], qpidsteps)
|
||||
|
||||
def createmanifest():
|
||||
def createmanifest(config):
|
||||
manifestfile = "%s_qpid.pp"%controller.CONF['CONFIG_QPID_HOST']
|
||||
manifestdata = getManifestTemplate("qpid.pp")
|
||||
appendManifestFile(manifestfile, manifestdata, 'pre')
|
||||
|
||||
@@ -373,7 +373,7 @@ def initSequences(controller):
|
||||
controller.addSequence("Preparing servers", [], [], preparesteps)
|
||||
|
||||
|
||||
def serverprep():
|
||||
def serverprep(config):
|
||||
config = controller.CONF
|
||||
|
||||
rh_username = None
|
||||
|
||||
@@ -61,7 +61,7 @@ def initSequences(controller):
|
||||
controller.addSequence("Setting up ssh keys", [], [], puppetsteps)
|
||||
|
||||
|
||||
def installKeys():
|
||||
def installKeys(config):
|
||||
with open(controller.CONF["CONFIG_SSH_KEY"]) as fp:
|
||||
sshkeydata = fp.read().strip()
|
||||
for hostname in gethostlist(controller.CONF):
|
||||
|
||||
@@ -130,7 +130,7 @@ def initSequences(controller):
|
||||
controller.addSequence("Installing OpenStack Swift", [], [], steps)
|
||||
|
||||
|
||||
def createkeystonemanifest():
|
||||
def createkeystonemanifest(config):
|
||||
manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
|
||||
controller.CONF['CONFIG_SWIFT_PROXY'] = controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'].split(',')[0]
|
||||
manifestdata = getManifestTemplate("keystone_swift.pp")
|
||||
@@ -158,7 +158,7 @@ def parse_devices(config_swift_storage_hosts):
|
||||
|
||||
# The ring file should be built and distributed befor the storage services
|
||||
# come up. Specifically the replicator crashes if the ring isn't present
|
||||
def createbuildermanifest():
|
||||
def createbuildermanifest(config):
|
||||
# TODO : put this on the proxy server, will need to change this later
|
||||
controller.CONF['CONFIG_SWIFT_BUILDER_HOST'] = controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'].split(',')[0]
|
||||
manifestfile = "%s_ring_swift.pp"%controller.CONF['CONFIG_SWIFT_BUILDER_HOST']
|
||||
@@ -178,7 +178,7 @@ def createbuildermanifest():
|
||||
appendManifestFile(manifestfile, manifestdata, 'swiftbuilder')
|
||||
|
||||
|
||||
def createproxymanifest():
|
||||
def createproxymanifest(config):
|
||||
manifestfile = "%s_swift.pp"%controller.CONF['CONFIG_SWIFT_PROXY_HOSTS']
|
||||
manifestdata = getManifestTemplate("swift_proxy.pp")
|
||||
# If the proxy server is also a storage server then swift::ringsync will be included for the storage server
|
||||
@@ -212,7 +212,7 @@ def check_device(host, device):
|
||||
return False
|
||||
|
||||
|
||||
def createstoragemanifest():
|
||||
def createstoragemanifest(config):
|
||||
|
||||
# this need to happen once per storage host
|
||||
for host in set([device['host'] for device in devices]):
|
||||
@@ -238,7 +238,7 @@ def createstoragemanifest():
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createcommonmanifest():
|
||||
def createcommonmanifest(config):
|
||||
for manifestfile, marker in manifestfiles.getFiles():
|
||||
if manifestfile.endswith("_swift.pp"):
|
||||
data = getManifestTemplate("swift_common.pp")
|
||||
|
||||
98
tests/installer/test_sequences.py
Normal file
98
tests/installer/test_sequences.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013, Red Hat, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import sys
|
||||
import StringIO
|
||||
from unittest import TestCase
|
||||
|
||||
from packstack.installer import utils
|
||||
from packstack.installer.core.sequences import *
|
||||
|
||||
from ..test_base import PackstackTestCaseMixin
|
||||
|
||||
|
||||
class StepTestCase(PackstackTestCaseMixin, TestCase):
|
||||
def setUp(self):
|
||||
super(StepTestCase, self).setUp()
|
||||
self._stdout = sys.stdout
|
||||
sys.stdout = StringIO.StringIO()
|
||||
|
||||
def tearDown(self):
|
||||
super(StepTestCase, self).tearDown()
|
||||
sys.stdout = self._stdout
|
||||
|
||||
def test_run(self):
|
||||
"""
|
||||
Test packstack.instaler.core.sequences.Step run.
|
||||
"""
|
||||
def func(config):
|
||||
if 'test' not in config:
|
||||
raise AssertionError('Missing config value.')
|
||||
|
||||
step = Step('test', func, title='Running test')
|
||||
step.run(config={'test': 'test'})
|
||||
contents = sys.stdout.getvalue()
|
||||
|
||||
state = '[ %s ]\n' % utils.color_text('DONE', 'green')
|
||||
if not contents.startswith('Running test') or \
|
||||
not contents.endswith(state):
|
||||
raise AssertionError('Step run test failed: %s' % contents)
|
||||
|
||||
|
||||
class SequenceTestCase(PackstackTestCaseMixin, TestCase):
|
||||
def setUp(self):
|
||||
super(SequenceTestCase, self).setUp()
|
||||
self._stdout = sys.stdout
|
||||
sys.stdout = StringIO.StringIO()
|
||||
|
||||
self.steps = [{'name': '1', 'function': lambda x: True,
|
||||
'title': 'Step 1'},
|
||||
{'name': '2', 'function': lambda x: True,
|
||||
'title': 'Step 2'},
|
||||
{'name': '3', 'function': lambda x: True,
|
||||
'title': 'Step 3'}]
|
||||
|
||||
self.seq = Sequence('test', self.steps, condition='test',
|
||||
cond_match='test')
|
||||
|
||||
def tearDown(self):
|
||||
super(SequenceTestCase, self).tearDown()
|
||||
sys.stdout = self._stdout
|
||||
|
||||
def test_run(self):
|
||||
"""
|
||||
Test packstack.instaler.core.sequences.Sequence run.
|
||||
"""
|
||||
self.seq.run()
|
||||
contents = sys.stdout.getvalue()
|
||||
self.assertEqual(contents, '')
|
||||
|
||||
self.seq.run(config={'test': 'test'}, step='2')
|
||||
contents = sys.stdout.getvalue()
|
||||
assert contents.startswith('Step 2')
|
||||
|
||||
output = []
|
||||
state_fmt = '[ %s ]\n'
|
||||
self.steps.insert(0, {'title': 'Step 2'})
|
||||
for i in self.steps:
|
||||
space = 70 - len(i['title'])
|
||||
title = '[ %s ]\n' % utils.color_text('DONE', 'green')
|
||||
output.append('%s...%s' % (i['title'], title.rjust(space)))
|
||||
|
||||
self.seq.run(config={'test': 'test'})
|
||||
contents = sys.stdout.getvalue()
|
||||
self.assertEqual(contents, ''.join(output))
|
||||
Reference in New Issue
Block a user