Fail when Nova API, Nova network and Swift hosts are not set as IP addresses

- Refactor value validator system - cleanup, pep8, documentation, tests and allow multiple validators for each parameter

Fixes: rhbz#886603

Change-Id: I1bb3486ed7168bda2855ee877e32423033620ecc
This commit is contained in:
Martin Magr 2013-02-05 16:03:13 +01:00
parent f6a0b0781b
commit a3d2a6d616
26 changed files with 523 additions and 691 deletions

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
*.pyc *.py[co]
*.swp *.swp
*.log *.log
.tox
packstack.egg-info

View File

@ -1,411 +1,207 @@
# -*- coding: utf-8 -*-
""" """
contains all available validation functions Contains all core validation functions.
""" """
import common_utils as utils
import re
import logging
import output_messages
import basedefs
import socket
import types
import traceback
import os import os
import os.path import re
import socket
import logging
import tempfile import tempfile
from setup_controller import Controller import traceback
import basedefs
import common_utils as utils
from .setup_controller import Controller
from .exceptions import ParamValidationError
__all__ = ('ParamValidationError', 'validate_integer',
'validate_regexp', 'validate_port', 'validate_not_empty',
'validate_options', 'validate_ip', 'validate_multi_ip',
'validate_file', 'validate_ping', 'validate_ssh',
'validate_multi_ssh')
# XXX: Validators should probably only validate (pass on success,
# raise appropriate exception on failure). We should move logging
# and printing probably to run_setup (preferably to single place)
def validateDirSize(path, size): def validate_integer(param, options=None):
availableSpace = utils.getAvailableSpace(_getBasePath(path)) """
if availableSpace < size: Raises ParamValidationError if given param is not integer.
print output_messages.INFO_VAL_PATH_SPACE % (path, """
utils.transformUnits(availableSpace), options = options or []
utils.transformUnits(size))
return False
return True
def validateInteger(param, options=[]):
try: try:
int(param) int(param)
return True except ValueError:
except: logging.debug('validate_integer(%s, options=%s) failed.' %
logging.warn("validateInteger('%s') - failed" %(param)) (param, options))
print output_messages.INFO_VAL_NOT_INTEGER msg = 'Given value is not an integer: %s'
return False raise ParamValidationError(msg % param)
def validateRe(param, options=[]):
def validate_regexp(param, options=None):
"""
Raises ParamValidationError if given param doesn't match at least
one of regular expressions given in options.
"""
options = options or []
for regex in options: for regex in options:
if re.search(regex, param): if re.search(regex, param):
return True break
logging.warn("validateRe('%s') - failed" %(param)) else:
return False logging.debug('validate_regexp(%s, options=%s) failed.' %
(param, options))
msg = 'Given value does not match required regular expresion: %s'
raise ParamValidationError(msg % param)
def validatePort(param, options = []):
#TODO: add actual port check with socket open def validate_port(param, options=None):
logging.debug("Validating %s as a valid TCP Port" % (param)) """
minVal = 0 Raises ParamValidationError if given param is not a decimal number
controller = Controller() in range (0, 65535).
isProxyEnabled = utils.compareStrIgnoreCase(controller.CONF["OVERRIDE_HTTPD_CONFIG"], "yes") """
if not isProxyEnabled: options = options or []
minVal = 1024 validate_integer(param, options)
if not validateInteger(param, options):
return False
port = int(param) port = int(param)
if not (port > minVal and port < 65535) : if not (port >= 0 and port < 65535):
logging.warn(output_messages.INFO_VAL_PORT_NOT_RANGE %(minVal)) logging.debug('validate_port(%s, options=%s) failed.' %
print output_messages.INFO_VAL_PORT_NOT_RANGE %(minVal) (param, options))
return False msg = 'Given value is outside the range of (0, 65535): %s'
(portOpen, process, pid) = utils.isTcpPortOpen(param) raise ParamValidationError(msg % param)
if portOpen:
logging.warn(output_messages.INFO_VAL_PORT_OCCUPIED % (param, process, pid))
print output_messages.INFO_VAL_PORT_OCCUPIED % (param, process, pid)
return False
if isProxyEnabled and not checkAndSetHttpdPortPolicy(param):
logging.warn(output_messages.INFO_VAL_FAILED_ADD_PORT_TO_HTTP_POLICY, port)
print output_messages.INFO_VAL_FAILED_ADD_PORT_TO_HTTP_POLICY % port
return False
return True
def checkAndSetHttpdPortPolicy(port):
def parsePorts(portsStr):
ports = []
for part in portsStr.split(","):
part = part.strip().split("-")
if len(part) > 1:
for port in range(int(part[0]),int(part[1])):
ports.append(port)
else:
ports.append(int(part[0]))
return ports
newPort = int(port) def validate_not_empty(param, options=None):
cmd = [ """
basedefs.EXEC_SEMANAGE, "port", "-l", Raises ParamValidationError if given param is empty.
] """
out, rc = utils.execCmd(cmdList=cmd) #, "-t", "http_port_t"]) options = options or []
if rc: if not param and param is not False:
return False logging.debug('validate_not_empty(%s, options=%s) failed.' %
httpPortsList = [] (param, options))
pattern = re.compile("^http_port_t\s*tcp\s*([0-9, \-]*)$") msg = 'Given value is not allowed: %s'
for line in out.splitlines(): raise ParamValidationError(msg % param)
httpPortPolicy = re.match(pattern, line)
if httpPortPolicy:
httpPortsList = parsePorts(httpPortPolicy.groups()[0]) def validate_options(param, options=None):
logging.debug("http_port_t = %s"%(httpPortsList)) """
if newPort in httpPortsList: Raises ParamValidationError if given param is not member of options.
return True """
options = options or []
validate_not_empty(param, options)
if param not in options:
logging.debug('validate_options(%s, options=%s) failed.' %
(param, options))
msg = 'Given value is not is allowed values %s: %s'
raise ParamValidationError(msg % (options, param))
def validate_ip(param, options=None):
"""
Raises ParamValidationError if given parameter value is not in IPv4
or IPv6 address.
"""
for family in (socket.AF_INET, socket.AF_INET6):
try:
socket.inet_pton(family, param)
break
except socket.error:
continue
else: else:
cmd = [ logging.debug('validate_ip(%s, options=%s) failed.' %
basedefs.EXEC_SEMANAGE, (param, options))
"port", msg = 'Given host is not in IP address format: %s'
"-a", raise ParamValidationError(msg % param)
"-t", "http_port_t",
"-p", "tcp",
"%d"%(newPort),
]
out, rc = utils.execCmd(cmdList=cmd, failOnError=False, usePipeFiles=True)
if rc:
logging.error(out)
return False
return True
def validate_multi_ip(param, options=None):
def validateRemotePort(param, options = []):
#Validate that the port is an integer betweeen 1024 and 65535
logging.debug("Validating %s as a valid TCP Port" % (param))
if validateInteger(param, options):
port = int(param)
if (port > 0 and port < 65535):
return True
else:
logging.warn("validatePort('%s') - failed" %(param))
print output_messages.INFO_VAL_PORT_NOT_RANGE
return False
def validateStringNotEmpty(param, options=[]):
if type(param) != types.StringType or len(param) == 0:
logging.warn("validateStringNotEmpty('%s') - failed" %(param))
print output_messages.INFO_VAL_STRING_EMPTY %(param)
return False
else:
return True
def validateOptions(param, options=[]):
logging.info("Validating %s as part of %s"%(param, options))
if not validateStringNotEmpty(param, options):
return False
if "yes" in options and param.lower() == "y":
return True
if "no" in options and param.lower() == "n":
return True
if param.lower() in [option.lower() for option in options]:
return True
print output_messages.INFO_VAL_NOT_IN_OPTIONS % (", ".join(options))
return False
def validateDomain(param, options=[]):
""" """
Validate domain name Raises ParamValidationError if comma separated IP addresses given
parameter value are in IPv4 or IPv6 aformat.
""" """
logging.info("validating %s as a valid domain string" % (param)) for host in param.split(','):
(errMsg, rc) = _validateString(param, 1, 1024, "^[\w\-\_]+\.[\w\.\-\_]+\w+$") host, device = host.split('/', 1)
validate_ip(host.strip(), options)
# Right now we print a generic error, might want to change it in the future
if rc != 0:
print output_messages.INFO_VAL_NOT_DOMAIN
return False
else:
return True
def validateUser(param, options=[]): def validate_file(param, options=None):
""" """
Validate Auth Username Raises ParamValidationError if provided file in param does not exist.
Setting a logical max value of 256
""" """
logging.info("validating %s as a valid user name" % (param)) options = options or []
(errMsg, rc) = _validateString(param, 1, 256, "^\w[\w\.\-\_\%\@]{2,}$") validate_not_empty(param)
# Right now we print a generic error, might want to change it in the future
if rc != 0:
print output_messages.INFO_VAL_NOT_USER
return False
else:
return True
def validateRemoteHost(param, options=[]):
""" Validate that the we are working with remote DB host
"""
# If we received localhost, use default flow.
# If not local, REMOTE_DB group is run.
# It means returning True if remote, and False if local
if "DB_REMOTE_INSTALL" in param.keys() and param["DB_REMOTE_INSTALL"] == "remote":
return True
else:
return False
def validateFQDN(param, options=[]):
logging.info("Validating %s as a FQDN"%(param))
if not validateDomain(param,options):
return False
try:
#get set of IPs
ipAddresses = utils.getConfiguredIps()
if len(ipAddresses) < 1:
logging.error("Could not find any configured IP address on the host")
raise Exception(output_messages.ERR_EXP_CANT_FIND_IP)
#resolve fqdn
pattern = 'Address: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
resolvedAddresses = _getPatternFromNslookup(param, pattern)
if len(resolvedAddresses) < 1:
logging.error("Failed to resolve %s"%(param))
print output_messages.ERR_DIDNT_RESOLVED_IP%(param)
return False
#string is generated here since we use it in all latter error messages
prettyString = " ".join(["%s"%string for string in resolvedAddresses])
#compare found IP with list of local IPs and match.
if not resolvedAddresses.issubset(ipAddresses):
logging.error("the following address(es): %s are not configured on this host"%(prettyString))
#different grammar for plural and single
if len(resolvedAddresses) > 1:
print output_messages.ERR_IPS_NOT_CONFIGED%(prettyString, param)
else:
print output_messages.ERR_IPS_NOT_CONFIGED_ON_INT%(prettyString, param)
return False
#reverse resolved IP and compare with given fqdn
counter = 0
pattern = '[\w\.-]+\s+name\s\=\s([\w\.\-]+)\.'
for address in resolvedAddresses:
addressSet = _getPatternFromNslookup(address, pattern)
reResolvedAddress = None
if len(addressSet) > 0:
reResolvedAddress = addressSet.pop()
if reResolvedAddress == param:
counter += 1
else:
logging.warn("%s did not reverse-resolve into %s"%(address,param))
if counter < 1:
logging.error("The following addresses: %s did not reverse resolve into %s"%(prettyString, param))
#different grammar for plural and single
if len(resolvedAddresses) > 1:
print output_messages.ERR_IPS_HAS_NO_PTR%(prettyString, param)
else:
print output_messages.ERR_IP_HAS_NO_PTR%(prettyString, param)
return False
#conditions passed
return True
except:
logging.error(traceback.format_exc())
raise
def validateFile(param, options=[]):
"""
Check that provided param is a file
"""
if not validateStringNotEmpty(param):
return False
if not os.path.isfile(param): if not os.path.isfile(param):
print "\n" + output_messages.ERR_FILE + ".\n" logging.debug('validate_file(%s, options=%s) failed.' %
return False (param, options))
msg = 'Given file does not exist: %s'
raise ParamValidationError(msg % param)
return True
def validatePing(param, options=[]): def validate_ping(param, options=None):
""" """
Check that provided host answers to ping Raises ParamValidationError if provided host does not answer to ICMP
echo request.
""" """
if validateStringNotEmpty(param): options = options or []
cmd = [ validate_not_empty(param)
"/bin/ping",
"-c", "1",
"%s" % param,
]
out, rc = utils.execCmd(cmdList=cmd)
if rc == 0:
return True
print "\n" + output_messages.ERR_PING + " %s .\n"%param cmd = ["/bin/ping", "-c", "1", str(param)]
return False out, rc = utils.execCmd(cmdList=cmd)
if rc != 0:
logging.debug('validate_ping(%s, options=%s) failed.' %
(param, options))
msg = 'Given host is unreachable: %s'
raise ParamValidationError(msg % param)
def validateMultiPing(param, options=[]):
if validateStringNotEmpty(param):
hosts = param.split(",")
for host in hosts:
if validatePing(host.strip()) == False:
return False
return True
print "\n" + output_messages.ERR_PING + ".\n"
return False
_testedPorts = [] def validate_multi_ping(param, options=None):
def validatePort(host, port):
""" """
Check that provided host is listening on provided port Raises ParamValidationError if comma separated host given in param
do not answer to ICMP echo request.
""" """
key = "%s:%d"%(host, port) options = options or []
# No need to keep checking the same port multiple times validate_not_empty(param)
if key in _testedPorts: for host in param.split(","):
return True validate_ping(host.strip())
_tested_ports = []
def touch_port(host, port):
"""
Check that provided host is listening on provided port.
"""
key = "%s:%d" % (host, port)
if key in _tested_ports:
return
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.shutdown(socket.SHUT_RDWR)
s.close()
_tested_ports.append(key)
def validate_ssh(param, options=None):
"""
Raises ParamValidationError if provided host does not listen
on port 22.
"""
options = options or []
try: try:
s.connect((host, port)) touch_port(param.strip(), 22)
s.shutdown(socket.SHUT_RDWR) except socket.error:
s.close() logging.debug('validate_ssh(%s, options=%s) failed.' %
except socket.error as msg: (param, options))
return False msg = 'Given host does not listen on port 22: %s'
_testedPorts.append(key) raise ParamValidationError(msg % param)
return True
def validateSSH(param, options=[]):
def validate_multi_ssh(param, options=None):
""" """
Check that provided host is listening on port 22 Raises ParamValidationError if comma separated host provided
in param do not listen on port 22.
""" """
if validatePort(param.strip(), 22): options = options or []
return True validate_not_empty(param)
print "\n" + output_messages.ERR_SSH%param for host in param.split(","):
return False validate_ssh(host)
def validateMultiSSH(param, options=[]):
if validateStringNotEmpty(param):
hosts = param.split(",")
for host in hosts:
if validateSSH(host) == False:
return False
return True
print "\n" + output_messages.ERR_SSH%param + ".\n"
return False
def _validateString(string, minLen, maxLen, regex=".*"):
"""
Generic func to verify a string
match its min/max length
and doesn't contain illegal chars
The func returns various return codes according to the error
plus a default error message
the calling func can decide if to use to default error msg
or to use a more specific one according the RC.
Return codes:
1 - string length is less than min
2 - string length is more tham max
3 - string contain illegal chars
0 - success
"""
# String length is less than minimum allowed
if len(string) < minLen:
msg = output_messages.INFO_STRING_LEN_LESS_THAN_MIN % (minLen)
return(msg, 1)
# String length is more than max allowed
elif len(string) > maxLen:
msg = output_messages.INFO_STRING_EXCEEDS_MAX_LENGTH % (maxLen)
return(msg, 2)
# String contains illegal chars
elif not utils.verifyStringFormat(string, regex):
return(output_messages.INFO_STRING_CONTAINS_ILLEGAL_CHARS, 3)
else:
# Success
return (None, 0)
def _getPatternFromNslookup(address, pattern):
rePattern = re.compile(pattern)
addresses = set()
output = utils.nslookup(address)
list = output.splitlines()
#do not go over the first 2 lines in nslookup output
for line in list[2:]:
found = rePattern.search(line)
if found:
foundAddress = found.group(1)
logging.debug("%s resolved into %s"%(address, foundAddress))
addresses.add(foundAddress)
return addresses
def _getBasePath(path):
if os.path.exists(path):
return path
# Iterate up in the tree structure until we get an
# existing path
return _getBasePath(os.path.dirname(path.rstrip("/")))
def _isPathWriteable(path):
try:
logging.debug("attempting to write temp file to %s" % (path))
tempfile.TemporaryFile(dir=path)
return True
except:
logging.warning(traceback.format_exc())
logging.warning("%s is not writeable" % path)
return False
def r_validateIF(server, device):
""" Validate that a network interface exists on a remote host """
server.append("ifconfig %s || ( echo Device %s does not exist && exit 1 )"%(device, device))
def r_validateDevice(server, device=None):
if device:
# the device MUST exist
server.append('ls -l /dev/%s'%device)
# if it is not mounted then we can use it
server.append('grep "/dev/%s " /proc/self/mounts || exit 0'%device)
# if it is mounted then the mount point has to be in /srv/node
server.append('grep "/dev/%s /srv/node" /proc/self/mounts && exit 0'%device)
# if we got here without exiting then we can't use this device
server.append('exit 1')
return False

View File

@ -20,22 +20,25 @@ class PackStackError(Exception):
class MissingRequirements(PackStackError): class MissingRequirements(PackStackError):
"""Raised when minimum install requirements are not met""" """Raised when minimum install requirements are not met."""
pass pass
class InstallError(PackStackError): class InstallError(PackStackError):
pass pass
class FlagValidationError(InstallError): class FlagValidationError(InstallError):
"""Raised when single flag validation fails."""
pass
class ParamValidationError(InstallError):
"""Raised when parameter value validation fails."""
pass pass
class PluginError(PackStackError): class PluginError(PackStackError):
pass pass
class ParamProcessingError(PluginError): class ParamProcessingError(PluginError):
pass pass

View File

@ -40,8 +40,8 @@ INFO_VAL_PORT_OCCUPIED="Error: TCP Port %s is already open by %s (pid: %s)"
INFO_VAL_PORT_OCCUPIED_BY_JBOSS="Error: TCP Port %s is used by JBoss" INFO_VAL_PORT_OCCUPIED_BY_JBOSS="Error: TCP Port %s is used by JBoss"
INFO_VAL_PASSWORD_DONT_MATCH="Error: passwords don't match" INFO_VAL_PASSWORD_DONT_MATCH="Error: passwords don't match"
INFO_VAL_IS_HOSTNAME = ("Packstack changed given hostname %s to IP " INFO_CHANGED_VALUE = ("Packstack changed given value %s to required "
"address %s.") "value %s")
WARN_VAL_IS_HOSTNAME = ("Warning: Packstack failed to change given " WARN_VAL_IS_HOSTNAME = ("Warning: Packstack failed to change given "
"hostname %s to IP address. Note that some " "hostname %s to IP address. Note that some "
"services might not run correctly when hostname" "services might not run correctly when hostname"

View File

@ -17,7 +17,7 @@ import common_utils as utils
import engine_processors as process import engine_processors as process
import engine_validators as validate import engine_validators as validate
import output_messages import output_messages
from .exceptions import FlagValidationError from .exceptions import FlagValidationError, ParamValidationError
from setup_controller import Controller from setup_controller import Controller
@ -77,8 +77,9 @@ def _getInputFromUser(param):
message = StringIO() message = StringIO()
message.write(param.getKey("PROMPT")) message.write(param.getKey("PROMPT"))
if not param.getKey("VALIDATION_FUNC") == validate.validateRe \ validators = param.getKey("VALIDATORS") or []
and param.getKey("OPTION_LIST"): if validate.validate_regexp not in validators \
and param.getKey("OPTION_LIST"):
message.write(" [%s]" % "|".join(param.getKey("OPTION_LIST"))) message.write(" [%s]" % "|".join(param.getKey("OPTION_LIST")))
if param.getKey("DEFAULT_VALUE"): if param.getKey("DEFAULT_VALUE"):
@ -99,62 +100,33 @@ def _getInputFromUser(param):
userInput = param.getKey("DEFAULT_VALUE") userInput = param.getKey("DEFAULT_VALUE")
# Param processing # Param processing
try: userInput = process_param_value(param, userInput)
logging.debug("Processing value of parameter "
"%s." % param.getKey("CONF_NAME"))
processFunc = param.getKey("PROCESSOR_FUNC")
try:
processArgs = param.getKey("PROCESSOR_ARGS")
except KeyError:
processArgs = None
try:
_userInput = processFunc(userInput, processArgs)
if userInput != _userInput:
msg = output_messages.INFO_VAL_IS_HOSTNAME
print msg % (userInput, _userInput)
userInput = _userInput
else:
logging.debug("Processor returned the original "
"value: %s" % _userInput)
except process.ParamProcessingError, ex:
try:
cn = param.getKey("CONF_NAME")
msg = param.getKey("PROCESSOR_MSG")
print getattr(output_messages, msg) % cn
except KeyError:
logging.debug("Value processing of parameter "
"%s failed." % param.getKey("CONF_NAME"))
except KeyError:
logging.debug("Parameter %s doesn't have value "
"processor." % param.getKey("CONF_NAME"))
# If param requires validation # If param requires validation
if param.getKey("VALIDATION_FUNC")(userInput, param.getKey("OPTION_LIST")): try:
if "yes" in param.getKey("OPTION_LIST") and userInput.lower() == "y": validate_param_value(param, userInput)
userInput = "yes"
if "no" in param.getKey("OPTION_LIST") and userInput.lower() == "n":
userInput = "no"
controller.CONF[param.getKey("CONF_NAME")] = userInput controller.CONF[param.getKey("CONF_NAME")] = userInput
loop = False loop = False
# If validation failed but LOOSE_VALIDATION is true, ask user except ParamValidationError:
elif param.getKey("LOOSE_VALIDATION"): if param.getKey("LOOSE_VALIDATION"):
answer = _askYesNo("User input failed validation, do you still wish to use it") # If validation failed but LOOSE_VALIDATION is true, ask user
if answer: answer = _askYesNo("User input failed validation, "
loop = False "do you still wish to use it")
controller.CONF[param.getKey("CONF_NAME")] = userInput loop = not answer
if answer:
controller.CONF[param.getKey("CONF_NAME")] = userInput
continue
else:
if commandLineValues.has_key(param.getKey("CONF_NAME")):
del commandLineValues[param.getKey("CONF_NAME")]
else: else:
# Delete value from commandLineValues so that we will prompt the user for input
if commandLineValues.has_key(param.getKey("CONF_NAME")): if commandLineValues.has_key(param.getKey("CONF_NAME")):
del commandLineValues[param.getKey("CONF_NAME")] del commandLineValues[param.getKey("CONF_NAME")]
loop = True loop = True
else:
# Delete value from commandLineValues so that we will prompt the user for input
if commandLineValues.has_key(param.getKey("CONF_NAME")):
del commandLineValues[param.getKey("CONF_NAME")]
loop = True
except KeyboardInterrupt: except KeyboardInterrupt:
print "" # add the new line so messages wont be displayed in the same line as the question print "" # add the new line so messages wont be displayed in the same line as the question
raise KeyboardInterrupt raise
except: except:
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
raise Exception(output_messages.ERR_EXP_READ_INPUT_PARAM % (param.getKey("CONF_NAME"))) raise Exception(output_messages.ERR_EXP_READ_INPUT_PARAM % (param.getKey("CONF_NAME")))
@ -172,7 +144,7 @@ def input_param(param):
confirmedParamName = param.getKey("CONF_NAME") + "_CONFIRMED" confirmedParamName = param.getKey("CONF_NAME") + "_CONFIRMED"
confirmedParam.setKey("CONF_NAME", confirmedParamName) confirmedParam.setKey("CONF_NAME", confirmedParamName)
confirmedParam.setKey("PROMPT", output_messages.INFO_CONF_PARAMS_PASSWD_CONFIRM_PROMPT) confirmedParam.setKey("PROMPT", output_messages.INFO_CONF_PARAMS_PASSWD_CONFIRM_PROMPT)
confirmedParam.setKey("VALIDATION_FUNC", validate.validateStringNotEmpty) confirmedParam.setKey("VALIDATORS", [validate.validate_not_empty])
# Now get both values from user (with existing validations # Now get both values from user (with existing validations
while True: while True:
_getInputFromUser(param) _getInputFromUser(param)
@ -285,35 +257,39 @@ def maskString(str):
str = str.replace(password, '*'*8) str = str.replace(password, '*'*8)
return str return str
def _validateParamValue(param, paramValue): def validate_param_value(param, value):
validateFunc = param.getKey("VALIDATION_FUNC") cname = param.getKey("CONF_NAME")
optionsList = param.getKey("OPTION_LIST") logging.debug("Validating parameter %s." % cname)
logging.debug("validating param %s in answer file." % param.getKey("CONF_NAME"))
if not validateFunc(paramValue, optionsList):
raise Exception(output_messages.ERR_EXP_VALIDATE_PARAM % param.getKey("CONF_NAME"))
def _processParamValue(param, paramValue): validators = param.getKey("VALIDATORS") or []
try: opt_list = param.getKey("OPTION_LIST")
processFunc = param.getKey("PROCESSOR_FUNC") for val_func in validators:
except KeyError:
return paramValue
try:
processArgs = param.getKey("PROCESSOR_ARGS")
except KeyError:
processArgs = None
logging.debug("processing param %s in answer file." % param.getKey("CONF_NAME"))
try:
return processFunc(paramValue, processArgs)
except process.ParamProcessingError, ex:
cn = param.getKey("CONF_NAME")
logging.debug("processing param %s failed, falling back to "
"original, reason: %s" % (cn, ex))
try: try:
msg = param.getKey("PROCESSOR_MSG") val_func(value, opt_list)
print getattr(output_messages, msg) % cn except ParamValidationError as ex:
except KeyError: print 'Parameter %s failed validation: %s' % (cname, ex)
pass raise
return paramValue
def process_param_value(param, value):
_value = value
processors = param.getKey("PROCESSORS") or []
for proc_func in processors:
logging.debug("Processing value of parameter "
"%s." % param.getKey("CONF_NAME"))
try:
new_value = proc_func(_value, controller.CONF)
if new_value != _value:
msg = output_messages.INFO_CHANGED_VALUE
print msg % (_value, new_value)
_value = new_value
else:
logging.debug("Processor returned the original "
"value: %s" % _value)
except process.ParamProcessingError, ex:
print ("Value processing of parameter %s "
"failed.\n%s" % (param.getKey("CONF_NAME"), ex))
raise
return _value
def _handleGroupCondition(config, conditionName, conditionValue): def _handleGroupCondition(config, conditionName, conditionValue):
""" """
@ -349,8 +325,8 @@ def _loadParamFromFile(config, section, paramName):
# Validate param value using its validation func # Validate param value using its validation func
param = controller.getParamByName(paramName) param = controller.getParamByName(paramName)
value = _processParamValue(param, value) value = process_param_value(param, value)
_validateParamValue(param, value) validate_param_value(param, value)
# Keep param value in our never ending global conf # Keep param value in our never ending global conf
controller.CONF[param.getKey("CONF_NAME")] = value controller.CONF[param.getKey("CONF_NAME")] = value

View File

@ -1,62 +0,0 @@
"""
Creates a Sample File
"""
import logging
import os
import engine_validators as validate
import basedefs
import common_utils as utils
# Controller object will be initialized from main flow
controller = None
logging.debug("plugin %s loaded", __name__)
def initConfig(controllerObject):
global controller
controller = controllerObject
logging.debug("Initialising Plugine")
conf_params = {"SAMPLE": [
{"CMD_OPTION" : "filename",
"USAGE" : "File to create",
"PROMPT" : "File to create",
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
"DEFAULT_VALUE" : "/tmp/samplefile.txt",
"MASK_INPUT" : False,
"LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_FILENAME",
"USE_DEFAULT" : False,
"NEED_CONFIRM" : False,
"CONDITION" : False },
]
}
conf_groups = [
{ "GROUP_NAME" : "SAMPLE",
"DESCRIPTION" : "Sample config group",
"PRE_CONDITION" : utils.returnYes,
"PRE_CONDITION_MATCH" : "yes",
"POST_CONDITION" : False,
"POST_CONDITION_MATCH" : True},
]
for group in conf_groups:
paramList = conf_params[group["GROUP_NAME"]]
controller.addGroup(group, paramList)
def initSequences(controller):
preparesteps = [
{'title': 'Create File', 'functions':[createfile]}
]
controller.addSequence("Creating File", [], [], preparesteps)
def createfile():
with open(controller.CONF["CONFIG_FILENAME"], "a") as fp:
fp.write("HELLO WORLD")

View File

@ -3,9 +3,9 @@ Container set for groups and parameters
""" """
class Param(object): class Param(object):
allowed_keys = ('CMD_OPTION','USAGE','PROMPT','OPTION_LIST', allowed_keys = ('CMD_OPTION','USAGE','PROMPT','OPTION_LIST',
'PROCESSOR_ARGS', 'PROCESSOR_FUNC', 'PROCESSOR_MSG', 'PROCESSORS', 'VALIDATORS','DEFAULT_VALUE',
'VALIDATION_FUNC','DEFAULT_VALUE','MASK_INPUT','LOOSE_VALIDATION', 'MASK_INPUT', 'LOOSE_VALIDATION', 'CONF_NAME',
'CONF_NAME','USE_DEFAULT','NEED_CONFIRM','CONDITION') 'USE_DEFAULT','NEED_CONFIRM','CONDITION')
def __init__(self, attributes=None): def __init__(self, attributes=None):
if not attributes: if not attributes:
@ -25,10 +25,10 @@ class Param(object):
def getKey(self, key): def getKey(self, key):
self.validateKey(key) self.validateKey(key)
return self.__ATTRIBUTES[key] return self.__ATTRIBUTES.get(key)
def validateKey(self, key): def validateKey(self, key):
if not self.__ATTRIBUTES.has_key(key): if key not in self.allowed_keys:
raise KeyError("%s is not a valid key" % key) raise KeyError("%s is not a valid key" % key)
class Group(Param): class Group(Param):

View File

@ -5,6 +5,7 @@ import re
from packstack.installer import basedefs from packstack.installer import basedefs
from packstack.installer.setup_controller import Controller from packstack.installer.setup_controller import Controller
from packstack.installer.exceptions import PackStackError
controller = Controller() controller = Controller()
@ -12,10 +13,6 @@ PUPPET_DIR = os.path.join(basedefs.DIR_PROJECT_DIR, "puppet")
PUPPET_TEMPLATE_DIR = os.path.join(PUPPET_DIR, "templates") PUPPET_TEMPLATE_DIR = os.path.join(PUPPET_DIR, "templates")
class PackStackError(Exception):
pass
class NovaConfig(object): class NovaConfig(object):
""" """
Helper class to create puppet manifest entries for nova_config Helper class to create puppet manifest entries for nova_config

View File

@ -34,11 +34,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install Cinder", "USAGE" : "The IP address of the server on which to install Cinder",
"PROMPT" : "Enter the IP address of the Cinder server", "PROMPT" : "Enter the IP address of the Cinder server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_CINDER_HOST", "CONF_NAME" : "CONFIG_CINDER_HOST",
@ -49,7 +46,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Cinder to access DB", "USAGE" : "The password to use for the Cinder to access DB",
"PROMPT" : "Enter the password for the Cinder DB access", "PROMPT" : "Enter the password for the Cinder DB access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -61,7 +58,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Cinder to authenticate with Keystone", "USAGE" : "The password to use for the Cinder to authenticate with Keystone",
"PROMPT" : "Enter the password for the Cinder Keystone access", "PROMPT" : "Enter the password for the Cinder Keystone access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -73,7 +70,7 @@ def initConfig(controllerObject):
"USAGE" : "Cinder's volumes group size", "USAGE" : "Cinder's volumes group size",
"PROMPT" : "Enter Cinder's volumes group size", "PROMPT" : "Enter Cinder's volumes group size",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "2G", "DEFAULT_VALUE" : "2G",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -85,7 +82,7 @@ def initConfig(controllerObject):
"USAGE" : "Cinder's volumes group path", "USAGE" : "Cinder's volumes group path",
"PROMPT" : "Enter Cinder's volumes group path", "PROMPT" : "Enter Cinder's volumes group path",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "/var/lib/cinder", "DEFAULT_VALUE" : "/var/lib/cinder",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -97,7 +94,7 @@ def initConfig(controllerObject):
"USAGE" : "Cinder's volumes group name", "USAGE" : "Cinder's volumes group name",
"PROMPT" : "Enter Cinder's volumes group name", "PROMPT" : "Enter Cinder's volumes group name",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "cinder-volumes", "DEFAULT_VALUE" : "cinder-volumes",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -109,7 +106,7 @@ def initConfig(controllerObject):
"USAGE" : "Create Cinder's volumes group", "USAGE" : "Create Cinder's volumes group",
"PROMPT" : "Should Cinder's volumes group be created?", "PROMPT" : "Should Cinder's volumes group be created?",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : createVolume, "VALIDATORS" : [validate.validate_options, createVolume],
"DEFAULT_VALUE" : "y", "DEFAULT_VALUE" : "y",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -141,18 +138,19 @@ def initSequences(controller):
controller.addSequence("Installing OpenStack Cinder", [], [], cindersteps) controller.addSequence("Installing OpenStack Cinder", [], [], cindersteps)
def createVolume(param, options=[]): def createVolume(param, options=None):
""" """
Check that provided host is listening on port 22 Check that provided host is listening on port 22
""" """
options = options or []
if param == "n": if param == "n":
return True return
# XXX: For this case it probably is better (cleaner) to use processor instead of validator
for option in ['CONFIG_CINDER_VOLUMES_SIZE', 'CONFIG_CINDER_VOLUMES_PATH']: for option in ['CONFIG_CINDER_VOLUMES_SIZE', 'CONFIG_CINDER_VOLUMES_PATH']:
param = controller.getParamByName(option) param = controller.getParamByName(option)
param.setKey('USE_DEFAULT', False) param.setKey('USE_DEFAULT', False)
setup.input_param(param) setup.input_param(param)
return True
def checkcindervg(): def checkcindervg():

View File

@ -30,11 +30,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install Horizon", "USAGE" : "The IP address of the server on which to install Horizon",
"PROMPT" : "Enter the IP address of the Horizon server", "PROMPT" : "Enter the IP address of the Horizon server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_HORIZON_HOST", "CONF_NAME" : "CONFIG_HORIZON_HOST",

View File

@ -30,11 +30,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install Glance", "USAGE" : "The IP address of the server on which to install Glance",
"PROMPT" : "Enter the IP address of the Glance server", "PROMPT" : "Enter the IP address of the Glance server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_GLANCE_HOST", "CONF_NAME" : "CONFIG_GLANCE_HOST",
@ -45,7 +42,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Glance to access DB", "USAGE" : "The password to use for the Glance to access DB",
"PROMPT" : "Enter the password for the Glance DB access", "PROMPT" : "Enter the password for the Glance DB access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -57,7 +54,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Glance to authenticate with Keystone", "USAGE" : "The password to use for the Glance to authenticate with Keystone",
"PROMPT" : "Enter the password for the Glance Keystone access", "PROMPT" : "Enter the password for the Glance Keystone access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,

View File

@ -31,11 +31,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install Keystone", "USAGE" : "The IP address of the server on which to install Keystone",
"PROMPT" : "Enter the IP address of the Keystone server", "PROMPT" : "Enter the IP address of the Keystone server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_KEYSTONE_HOST", "CONF_NAME" : "CONFIG_KEYSTONE_HOST",
@ -46,7 +43,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Keystone to access DB", "USAGE" : "The password to use for the Keystone to access DB",
"PROMPT" : "Enter the password for the Keystone DB access", "PROMPT" : "Enter the password for the Keystone DB access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -58,7 +55,7 @@ def initConfig(controllerObject):
"USAGE" : "The token to use for the Keystone service api", "USAGE" : "The token to use for the Keystone service api",
"PROMPT" : "The token to use for the Keystone service api", "PROMPT" : "The token to use for the Keystone service api",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex, "DEFAULT_VALUE" : uuid.uuid4().hex,
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -70,7 +67,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Keystone admin user", "USAGE" : "The password to use for the Keystone admin user",
"PROMPT" : "Enter the password for the Keystone admin user", "PROMPT" : "Enter the password for the Keystone admin user",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,

View File

@ -30,11 +30,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install MySQL", "USAGE" : "The IP address of the server on which to install MySQL",
"PROMPT" : "Enter the IP address of the MySQL server", "PROMPT" : "Enter the IP address of the MySQL server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_MYSQL_HOST", "CONF_NAME" : "CONFIG_MYSQL_HOST",
@ -45,7 +42,7 @@ def initConfig(controllerObject):
"USAGE" : "Username for the MySQL admin user", "USAGE" : "Username for the MySQL admin user",
"PROMPT" : "Enter the username for the MySQL admin user", "PROMPT" : "Enter the username for the MySQL admin user",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "root", "DEFAULT_VALUE" : "root",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -57,7 +54,7 @@ def initConfig(controllerObject):
"USAGE" : "Password for the MySQL admin user", "USAGE" : "Password for the MySQL admin user",
"PROMPT" : "Enter the password for the MySQL admin user", "PROMPT" : "Enter the password for the MySQL admin user",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,

View File

@ -28,11 +28,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the Nova API service", "USAGE" : "The IP address of the server on which to install the Nova API service",
"PROMPT" : "Enter the IP address of the Nova API service", "PROMPT" : "Enter the IP address of the Nova API service",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ip, validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_API_HOST", "CONF_NAME" : "CONFIG_NOVA_API_HOST",
@ -43,11 +40,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the Nova Cert service", "USAGE" : "The IP address of the server on which to install the Nova Cert service",
"PROMPT" : "Enter the IP address of the Nova Cert service", "PROMPT" : "Enter the IP address of the Nova Cert service",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_CERT_HOST", "CONF_NAME" : "CONFIG_NOVA_CERT_HOST",
@ -58,11 +52,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the Nova VNC proxy", "USAGE" : "The IP address of the server on which to install the Nova VNC proxy",
"PROMPT" : "Enter the IP address of the Nova VNC proxy", "PROMPT" : "Enter the IP address of the Nova VNC proxy",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_VNCPROXY_HOST", "CONF_NAME" : "CONFIG_NOVA_VNCPROXY_HOST",
@ -73,11 +64,11 @@ def initConfig(controllerObject):
"USAGE" : "A comma separated list of IP addresses on which to install the Nova Compute services", "USAGE" : "A comma separated list of IP addresses on which to install the Nova Compute services",
"PROMPT" : "Enter a comma separated list of IP addresses on which to install the Nova Compute services", "PROMPT" : "Enter a comma separated list of IP addresses on which to install the Nova Compute services",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateMultiSSH, "VALIDATORS" : [validate.validate_multi_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_COMPUTE_HOSTS", # TO-DO: Create processor for CSV "CONF_NAME" : "CONFIG_NOVA_COMPUTE_HOSTS",
"USE_DEFAULT" : False, "USE_DEFAULT" : False,
"NEED_CONFIRM" : False, "NEED_CONFIRM" : False,
"CONDITION" : False }, "CONDITION" : False },
@ -85,7 +76,7 @@ def initConfig(controllerObject):
"USAGE" : "Private interface for Flat DHCP on the Nova compute servers", "USAGE" : "Private interface for Flat DHCP on the Nova compute servers",
"PROMPT" : "Enter the Private interface for Flat DHCP on the Nova compute servers", "PROMPT" : "Enter the Private interface for Flat DHCP on the Nova compute servers",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "eth1", "DEFAULT_VALUE" : "eth1",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -97,11 +88,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the Nova Network service", "USAGE" : "The IP address of the server on which to install the Nova Network service",
"PROMPT" : "Enter the IP address of the Nova Network service", "PROMPT" : "Enter the IP address of the Nova Network service",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ip, validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_NETWORK_HOST", "CONF_NAME" : "CONFIG_NOVA_NETWORK_HOST",
@ -112,7 +100,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Nova to access DB", "USAGE" : "The password to use for the Nova to access DB",
"PROMPT" : "Enter the password for the Nova DB access", "PROMPT" : "Enter the password for the Nova DB access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -124,7 +112,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Nova to authenticate with Keystone", "USAGE" : "The password to use for the Nova to authenticate with Keystone",
"PROMPT" : "Enter the password for the Nova Keystone access", "PROMPT" : "Enter the password for the Nova Keystone access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -136,7 +124,7 @@ def initConfig(controllerObject):
"USAGE" : "Public interface on the Nova network server", "USAGE" : "Public interface on the Nova network server",
"PROMPT" : "Enter the Public interface on the Nova network server", "PROMPT" : "Enter the Public interface on the Nova network server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "eth0", "DEFAULT_VALUE" : "eth0",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -148,7 +136,7 @@ def initConfig(controllerObject):
"USAGE" : "Private interface for Flat DHCP on the Nova network server", "USAGE" : "Private interface for Flat DHCP on the Nova network server",
"PROMPT" : "Enter the Private interface for Flat DHCP on the Nova network server", "PROMPT" : "Enter the Private interface for Flat DHCP on the Nova network server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : "eth1", "DEFAULT_VALUE" : "eth1",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -160,7 +148,7 @@ def initConfig(controllerObject):
"USAGE" : "IP Range for Flat DHCP", "USAGE" : "IP Range for Flat DHCP",
"PROMPT" : "Enter the IP Range for Flat DHCP", "PROMPT" : "Enter the IP Range for Flat DHCP",
"OPTION_LIST" : ["^([\d]{1,3}\.){3}[\d]{1,3}/\d\d?$"], "OPTION_LIST" : ["^([\d]{1,3}\.){3}[\d]{1,3}/\d\d?$"],
"VALIDATION_FUNC" : validate.validateRe, "VALIDATORS" : [validate.validate_regexp],
"DEFAULT_VALUE" : "192.168.32.0/22", "DEFAULT_VALUE" : "192.168.32.0/22",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -172,7 +160,7 @@ def initConfig(controllerObject):
"USAGE" : "IP Range for Floating IP's", "USAGE" : "IP Range for Floating IP's",
"PROMPT" : "Enter the IP Range for Floating IP's", "PROMPT" : "Enter the IP Range for Floating IP's",
"OPTION_LIST" : ["^([\d]{1,3}\.){3}[\d]{1,3}/\d\d?$"], "OPTION_LIST" : ["^([\d]{1,3}\.){3}[\d]{1,3}/\d\d?$"],
"VALIDATION_FUNC" : validate.validateRe, "VALIDATORS" : [validate.validate_regexp],
"DEFAULT_VALUE" : "10.3.4.0/22", "DEFAULT_VALUE" : "10.3.4.0/22",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -184,11 +172,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the Nova Scheduler service", "USAGE" : "The IP address of the server on which to install the Nova Scheduler service",
"PROMPT" : "Enter the IP address of the Nova Scheduler service", "PROMPT" : "Enter the IP address of the Nova Scheduler service",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_SCHED_HOST", "CONF_NAME" : "CONFIG_NOVA_SCHED_HOST",
@ -204,6 +189,7 @@ def initConfig(controllerObject):
"POST_CONDITION_MATCH" : True} "POST_CONDITION_MATCH" : True}
controller.addGroup(groupDict, paramsList) controller.addGroup(groupDict, paramsList)
def initSequences(controller): def initSequences(controller):
if controller.CONF['CONFIG_NOVA_INSTALL'] != 'y': if controller.CONF['CONFIG_NOVA_INSTALL'] != 'y':
return return
@ -220,59 +206,71 @@ def initSequences(controller):
] ]
controller.addSequence("Installing OpenStack Nova API", [], [], novaapisteps) controller.addSequence("Installing OpenStack Nova API", [], [], novaapisteps)
def createapimanifest(): def createapimanifest():
manifestfile = "%s_api_nova.pp"%controller.CONF['CONFIG_NOVA_API_HOST'] manifestfile = "%s_api_nova.pp"%controller.CONF['CONFIG_NOVA_API_HOST']
manifestdata = getManifestTemplate("nova_api.pp") manifestdata = getManifestTemplate("nova_api.pp")
appendManifestFile(manifestfile, manifestdata, 'novaapi') appendManifestFile(manifestfile, manifestdata, 'novaapi')
def createkeystonemanifest(): def createkeystonemanifest():
manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST'] manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
manifestdata = getManifestTemplate("keystone_nova.pp") manifestdata = getManifestTemplate("keystone_nova.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def createcertmanifest(): def createcertmanifest():
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_CERT_HOST'] manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_CERT_HOST']
manifestdata = getManifestTemplate("nova_cert.pp") manifestdata = getManifestTemplate("nova_cert.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def check_ifcfg(host, device):
"""
Raises ScriptRuntimeError if given host does not have give device.
"""
server = utils.ScriptRunner(host)
cmd = "ifconfig %s || ( echo Device %s does not exist && exit 1 )"
server.append(cmd % (device, device))
server.execute()
def createcomputemanifest(): def createcomputemanifest():
for host in controller.CONF["CONFIG_NOVA_COMPUTE_HOSTS"].split(","): for host in controller.CONF["CONFIG_NOVA_COMPUTE_HOSTS"].split(","):
controller.CONF["CONFIG_NOVA_COMPUTE_HOST"] = host controller.CONF["CONFIG_NOVA_COMPUTE_HOST"] = host
manifestdata = getManifestTemplate("nova_compute.pp") manifestdata = getManifestTemplate("nova_compute.pp")
manifestfile = "%s_nova.pp"%host manifestfile = "%s_nova.pp"%host
server = utils.ScriptRunner(host)
nova_config_options = NovaConfig() nova_config_options = NovaConfig()
if host != controller.CONF["CONFIG_NOVA_NETWORK_HOST"]: if host != controller.CONF["CONFIG_NOVA_NETWORK_HOST"]:
nova_config_options.addOption("flat_interface", controller.CONF['CONFIG_NOVA_COMPUTE_PRIVIF']) nova_config_options.addOption("flat_interface", controller.CONF['CONFIG_NOVA_COMPUTE_PRIVIF'])
validate.r_validateIF(server, controller.CONF['CONFIG_NOVA_COMPUTE_PRIVIF']) check_ifcfg(host, controller.CONF['CONFIG_NOVA_COMPUTE_PRIVIF'])
server.execute()
appendManifestFile(manifestfile, manifestdata + "\n" + nova_config_options.getManifestEntry()) appendManifestFile(manifestfile, manifestdata + "\n" + nova_config_options.getManifestEntry())
def createnetworkmanifest(): def createnetworkmanifest():
hostname = controller.CONF['CONFIG_NOVA_NETWORK_HOST'] host = controller.CONF['CONFIG_NOVA_NETWORK_HOST']
check_ifcfg(host, controller.CONF['CONFIG_NOVA_NETWORK_PRIVIF'])
check_ifcfg(host, controller.CONF['CONFIG_NOVA_NETWORK_PUBIF'])
server = utils.ScriptRunner(hostname) manifestfile = "%s_nova.pp" % host
validate.r_validateIF(server, controller.CONF['CONFIG_NOVA_NETWORK_PRIVIF'])
validate.r_validateIF(server, controller.CONF['CONFIG_NOVA_NETWORK_PUBIF'])
server.execute()
manifestfile = "%s_nova.pp"%hostname
manifestdata = getManifestTemplate("nova_network.pp") manifestdata = getManifestTemplate("nova_network.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def createschedmanifest(): def createschedmanifest():
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_SCHED_HOST'] manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_SCHED_HOST']
manifestdata = getManifestTemplate("nova_sched.pp") manifestdata = getManifestTemplate("nova_sched.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def createvncproxymanifest(): def createvncproxymanifest():
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_VNCPROXY_HOST'] manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_VNCPROXY_HOST']
manifestdata = getManifestTemplate("nova_vncproxy.pp") manifestdata = getManifestTemplate("nova_vncproxy.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def createcommonmanifest(): def createcommonmanifest():
for manifestfile, marker in manifestfiles.getFiles(): for manifestfile, marker in manifestfiles.getFiles():
if manifestfile.endswith("_nova.pp"): if manifestfile.endswith("_nova.pp"):

View File

@ -29,11 +29,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the OpenStack client packages. An admin \"rc\" file will also be installed", "USAGE" : "The IP address of the server on which to install the OpenStack client packages. An admin \"rc\" file will also be installed",
"PROMPT" : "Enter the IP address of the client server", "PROMPT" : "Enter the IP address of the client server",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_OSCLIENT_HOST", "CONF_NAME" : "CONFIG_OSCLIENT_HOST",

View File

@ -29,7 +29,7 @@ def initConfig(controllerObject):
"USAGE" : "Set to 'y' if you would like Packstack to install Glance", "USAGE" : "Set to 'y' if you would like Packstack to install Glance",
"PROMPT" : "Should Packstack install Glance image service", "PROMPT" : "Should Packstack install Glance image service",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "y", "DEFAULT_VALUE" : "y",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -41,7 +41,7 @@ def initConfig(controllerObject):
"USAGE" : "Set to 'y' if you would like Packstack to install Cinder", "USAGE" : "Set to 'y' if you would like Packstack to install Cinder",
"PROMPT" : "Should Packstack install Cinder volume service", "PROMPT" : "Should Packstack install Cinder volume service",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "y", "DEFAULT_VALUE" : "y",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -53,7 +53,7 @@ def initConfig(controllerObject):
"USAGE" : "Set to 'y' if you would like Packstack to install Nova", "USAGE" : "Set to 'y' if you would like Packstack to install Nova",
"PROMPT" : "Should Packstack install Nova compute service", "PROMPT" : "Should Packstack install Nova compute service",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "y", "DEFAULT_VALUE" : "y",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -65,7 +65,7 @@ def initConfig(controllerObject):
"USAGE" : "Set to 'y' if you would like Packstack to install Horizon", "USAGE" : "Set to 'y' if you would like Packstack to install Horizon",
"PROMPT" : "Should Packstack install Horizon dashboard", "PROMPT" : "Should Packstack install Horizon dashboard",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "y", "DEFAULT_VALUE" : "y",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -77,7 +77,7 @@ def initConfig(controllerObject):
"USAGE" : "Set to 'y' if you would like Packstack to install Swift", "USAGE" : "Set to 'y' if you would like Packstack to install Swift",
"PROMPT" : "Should Packstack install Swift object storage", "PROMPT" : "Should Packstack install Swift object storage",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "n", "DEFAULT_VALUE" : "n",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -89,7 +89,7 @@ def initConfig(controllerObject):
"USAGE" : "Set to 'y' if you would like Packstack to install the OpenStack Client packages. An admin \"rc\" file will also be installed", "USAGE" : "Set to 'y' if you would like Packstack to install the OpenStack Client packages. An admin \"rc\" file will also be installed",
"PROMPT" : "Should Packstack install OpenStack client tools", "PROMPT" : "Should Packstack install OpenStack client tools",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "y", "DEFAULT_VALUE" : "y",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -101,7 +101,6 @@ def initConfig(controllerObject):
"USAGE" : "Comma separated list of NTP servers. Leave plain if Packstack should not install ntpd on instances.", "USAGE" : "Comma separated list of NTP servers. Leave plain if Packstack should not install ntpd on instances.",
"PROMPT" : "Enter list of NTP server(s). Leave plain if Packstack should not install ntpd on instances.", "PROMPT" : "Enter list of NTP server(s). Leave plain if Packstack should not install ntpd on instances.",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : lambda param, options: True,
"DEFAULT_VALUE" : '', "DEFAULT_VALUE" : '',
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,

View File

@ -29,11 +29,8 @@ def initConfig(controllerObject):
"USAGE" : "The IP address of the server on which to install the QPID service", "USAGE" : "The IP address of the server on which to install the QPID service",
"PROMPT" : "Enter the IP address of the QPID service", "PROMPT" : "Enter the IP address of the QPID service",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"PROCESSOR_ARGS" : {"allow_localhost": True},
"PROCESSOR_FUNC" : process.processHost,
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_QPID_HOST", "CONF_NAME" : "CONFIG_QPID_HOST",

View File

@ -28,7 +28,7 @@ def initConfig(controllerObject):
"USAGE" : "Install OpenStack from EPEL. If set to \"y\" EPEL will be installed on each server", "USAGE" : "Install OpenStack from EPEL. If set to \"y\" EPEL will be installed on each server",
"PROMPT" : "Should Packstack install EPEL on each server", "PROMPT" : "Should Packstack install EPEL on each server",
"OPTION_LIST" : ["y", "n"], "OPTION_LIST" : ["y", "n"],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "n", "DEFAULT_VALUE" : "n",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -40,7 +40,6 @@ def initConfig(controllerObject):
"USAGE" : "A comma separated list of URLs to any additional yum repositories to install", "USAGE" : "A comma separated list of URLs to any additional yum repositories to install",
"PROMPT" : "Enter a comma separated list of URLs to any additional yum repositories to install", "PROMPT" : "Enter a comma separated list of URLs to any additional yum repositories to install",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : lambda a,b: True,
"DEFAULT_VALUE" : "", "DEFAULT_VALUE" : "",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -52,7 +51,6 @@ def initConfig(controllerObject):
"USAGE" : "To subscribe each server with Red Hat subscription manager, include this with CONFIG_RH_PASSWORD", "USAGE" : "To subscribe each server with Red Hat subscription manager, include this with CONFIG_RH_PASSWORD",
"PROMPT" : "To subscribe each server to Red Hat enter a username here", "PROMPT" : "To subscribe each server to Red Hat enter a username here",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : lambda a,b: True,
"DEFAULT_VALUE" : "", "DEFAULT_VALUE" : "",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -64,7 +62,6 @@ def initConfig(controllerObject):
"USAGE" : "To subscribe each server with Red Hat subscription manager, include this with CONFIG_RH_USERNAME", "USAGE" : "To subscribe each server with Red Hat subscription manager, include this with CONFIG_RH_USERNAME",
"PROMPT" : "To subscribe each server to Red Hat enter your password here", "PROMPT" : "To subscribe each server to Red Hat enter your password here",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : lambda a,b: True,
"DEFAULT_VALUE" : "", "DEFAULT_VALUE" : "",
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,

View File

@ -32,8 +32,8 @@ def initConfig(controllerObject):
"USAGE" : "Path to a Public key to install on servers. If a usable key has not been installed on the remote servers the user will be prompted for a password and this key will be installed so the password will not be required again", "USAGE" : "Path to a Public key to install on servers. If a usable key has not been installed on the remote servers the user will be prompted for a password and this key will be installed so the password will not be required again",
"PROMPT" : "Enter the path to your ssh Public key to install on servers", "PROMPT" : "Enter the path to your ssh Public key to install on servers",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateFile, "VALIDATORS" : [validate.validate_file],
"PROCESSOR_FUNC" : process.processSSHKey, "PROCESSORS" : [process.processSSHKey],
"DEFAULT_VALUE" : (glob.glob(os.path.join(os.environ["HOME"], ".ssh/*.pub"))+[""])[0], "DEFAULT_VALUE" : (glob.glob(os.path.join(os.environ["HOME"], ".ssh/*.pub"))+[""])[0],
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,

View File

@ -31,11 +31,11 @@ def initConfig(controllerObject):
"USAGE" : "The IP address on which to install the Swift proxy service", "USAGE" : "The IP address on which to install the Swift proxy service",
"PROMPT" : "Enter the IP address of the Swift proxy service", "PROMPT" : "Enter the IP address of the Swift proxy service",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateSSH, "VALIDATORS" : [validate.validate_ip, validate.validate_ssh],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_SWIFT_PROXY_HOSTS", # TO-DO: Create processor for CSV "CONF_NAME" : "CONFIG_SWIFT_PROXY_HOSTS", #XXX: Shouldn't be here CONFIG_SWIFT_PROXY_HOST?
"USE_DEFAULT" : False, "USE_DEFAULT" : False,
"NEED_CONFIRM" : False, "NEED_CONFIRM" : False,
"CONDITION" : False }, "CONDITION" : False },
@ -43,7 +43,7 @@ def initConfig(controllerObject):
"USAGE" : "The password to use for the Swift to authenticate with Keystone", "USAGE" : "The password to use for the Swift to authenticate with Keystone",
"PROMPT" : "Enter the password for the Swift Keystone access", "PROMPT" : "Enter the password for the Swift Keystone access",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty],
"DEFAULT_VALUE" : uuid.uuid4().hex[:16], "DEFAULT_VALUE" : uuid.uuid4().hex[:16],
"MASK_INPUT" : True, "MASK_INPUT" : True,
"LOOSE_VALIDATION": False, "LOOSE_VALIDATION": False,
@ -55,11 +55,11 @@ def initConfig(controllerObject):
"USAGE" : "A comma separated list of IP addresses on which to install the Swift Storage services, each entry should take the format <ipaddress>[/dev], for example 127.0.0.1/vdb will install /dev/vdb on 127.0.0.1 as a swift storage device, if /dev is omitted Packstack will create a loopback device for a test setup", "USAGE" : "A comma separated list of IP addresses on which to install the Swift Storage services, each entry should take the format <ipaddress>[/dev], for example 127.0.0.1/vdb will install /dev/vdb on 127.0.0.1 as a swift storage device, if /dev is omitted Packstack will create a loopback device for a test setup",
"PROMPT" : "Enter the Swift Storage servers e.g. host/dev,host/dev", "PROMPT" : "Enter the Swift Storage servers e.g. host/dev,host/dev",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateStringNotEmpty, "VALIDATORS" : [validate.validate_not_empty, validate_storage],
"DEFAULT_VALUE" : utils.getLocalhostIP(), "DEFAULT_VALUE" : utils.getLocalhostIP(),
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_SWIFT_STORAGE_HOSTS", # TO-DO: Create processor for CSV "CONF_NAME" : "CONFIG_SWIFT_STORAGE_HOSTS",
"USE_DEFAULT" : False, "USE_DEFAULT" : False,
"NEED_CONFIRM" : False, "NEED_CONFIRM" : False,
"CONDITION" : False }, "CONDITION" : False },
@ -67,7 +67,7 @@ def initConfig(controllerObject):
"USAGE" : "Number of swift storage zones, this number MUST be no bigger than the number of storage devices configured", "USAGE" : "Number of swift storage zones, this number MUST be no bigger than the number of storage devices configured",
"PROMPT" : "Enter the number of swift storage zones, MUST be no bigger than the number of storage devices configured", "PROMPT" : "Enter the number of swift storage zones, MUST be no bigger than the number of storage devices configured",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateInteger, "VALIDATORS" : [validate.validate_integer],
"DEFAULT_VALUE" : "1", "DEFAULT_VALUE" : "1",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -79,7 +79,7 @@ def initConfig(controllerObject):
"USAGE" : "Number of swift storage replicas, this number MUST be no bigger than the number of storage zones configured", "USAGE" : "Number of swift storage replicas, this number MUST be no bigger than the number of storage zones configured",
"PROMPT" : "Enter the number of swift storage replicas, MUST be no bigger than the number of storage zones configured", "PROMPT" : "Enter the number of swift storage replicas, MUST be no bigger than the number of storage zones configured",
"OPTION_LIST" : [], "OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateInteger, "VALIDATORS" : [validate.validate_integer],
"DEFAULT_VALUE" : "1", "DEFAULT_VALUE" : "1",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -91,7 +91,7 @@ def initConfig(controllerObject):
"USAGE" : "FileSystem type for storage nodes", "USAGE" : "FileSystem type for storage nodes",
"PROMPT" : "Enter FileSystem type for storage nodes", "PROMPT" : "Enter FileSystem type for storage nodes",
"OPTION_LIST" : ['xfs','ext4'], "OPTION_LIST" : ['xfs','ext4'],
"VALIDATION_FUNC" : validate.validateOptions, "VALIDATORS" : [validate.validate_options],
"DEFAULT_VALUE" : "ext4", "DEFAULT_VALUE" : "ext4",
"MASK_INPUT" : False, "MASK_INPUT" : False,
"LOOSE_VALIDATION": True, "LOOSE_VALIDATION": True,
@ -111,6 +111,12 @@ def initConfig(controllerObject):
controller.addGroup(groupDict, paramsList) controller.addGroup(groupDict, paramsList)
def validate_storage(param, options=None):
for host in param.split(','):
host = host.split('/', 1)[0]
validate.validate_ip(host.strip(), options)
def initSequences(controller): def initSequences(controller):
if controller.CONF['CONFIG_SWIFT_INSTALL'] != 'y': if controller.CONF['CONFIG_SWIFT_INSTALL'] != 'y':
return return
@ -124,12 +130,14 @@ def initSequences(controller):
] ]
controller.addSequence("Installing OpenStack Swift", [], [], steps) controller.addSequence("Installing OpenStack Swift", [], [], steps)
def createkeystonemanifest(): def createkeystonemanifest():
manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST'] manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
controller.CONF['CONFIG_SWIFT_PROXY'] = controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'].split(',')[0] controller.CONF['CONFIG_SWIFT_PROXY'] = controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'].split(',')[0]
manifestdata = getManifestTemplate("keystone_swift.pp") manifestdata = getManifestTemplate("keystone_swift.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
devices = [] devices = []
def parseDevices(config_swift_storage_hosts): def parseDevices(config_swift_storage_hosts):
device_number = 0 device_number = 0
@ -142,6 +150,7 @@ def parseDevices(config_swift_storage_hosts):
devices.append({'host':host, 'device':device, 'device_name':'device%s'%device_number, 'zone':str(zone)}) devices.append({'host':host, 'device':device, 'device_name':'device%s'%device_number, 'zone':str(zone)})
return devices return devices
# The ring file should be built and distributed befor the storage services # The ring file should be built and distributed befor the storage services
# come up. Specifically the replicator crashes if the ring isn't present # come up. Specifically the replicator crashes if the ring isn't present
def createbuildermanifest(): def createbuildermanifest():
@ -163,6 +172,7 @@ def createbuildermanifest():
appendManifestFile(manifestfile, manifestdata, 'swiftbuilder') appendManifestFile(manifestfile, manifestdata, 'swiftbuilder')
def createproxymanifest(): def createproxymanifest():
manifestfile = "%s_swift.pp"%controller.CONF['CONFIG_SWIFT_PROXY_HOSTS'] manifestfile = "%s_swift.pp"%controller.CONF['CONFIG_SWIFT_PROXY_HOSTS']
manifestdata = getManifestTemplate("swift_proxy.pp") manifestdata = getManifestTemplate("swift_proxy.pp")
@ -171,6 +181,32 @@ def createproxymanifest():
manifestdata += 'swift::ringsync{["account","container","object"]:\n ring_server => "%s"\n}'%controller.CONF['CONFIG_SWIFT_BUILDER_HOST'] manifestdata += 'swift::ringsync{["account","container","object"]:\n ring_server => "%s"\n}'%controller.CONF['CONFIG_SWIFT_BUILDER_HOST']
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def check_device(host, device):
"""
Raises ScriptRuntimeError if given device is not mounted on given
host.
"""
server = utils.ScriptRunner()
# the device MUST exist
cmd = 'ls -l /dev/%s'
server.append(cmd % device)
# if it is not mounted then we can use it
cmd = 'grep "/dev/%s " /proc/self/mounts || exit 0'
server.append(cmd % device)
# if it is mounted then the mount point has to be in /srv/node
cmd = 'grep "/dev/%s /srv/node" /proc/self/mounts && exit 0'
server.append(cmd % device)
# if we got here without exiting then we can't use this device
server.append('exit 1')
server.execute()
return False
def createstoragemanifest(): def createstoragemanifest():
# this need to happen once per storage host # this need to happen once per storage host
@ -185,10 +221,8 @@ def createstoragemanifest():
host = device['host'] host = device['host']
devicename = device['device_name'] devicename = device['device_name']
device = device['device'] device = device['device']
if device:
server = utils.ScriptRunner(host) check_device(host, device)
validate.r_validateDevice(server, device)
server.execute()
manifestfile = "%s_swift.pp"%host manifestfile = "%s_swift.pp"%host
if device: if device:
@ -198,6 +232,7 @@ def createstoragemanifest():
manifestdata = "\n" + getManifestTemplate("swift_loopback.pp") manifestdata = "\n" + getManifestTemplate("swift_loopback.pp")
appendManifestFile(manifestfile, manifestdata) appendManifestFile(manifestfile, manifestdata)
def createcommonmanifest(): def createcommonmanifest():
for manifestfile, marker in manifestfiles.getFiles(): for manifestfile, marker in manifestfiles.getFiles():
if manifestfile.endswith("_swift.pp"): if manifestfile.endswith("_swift.pp"):

2
run_tests.sh Executable file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
tox -epy26,py27,pep8

View File

@ -1,52 +0,0 @@
# 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 shutil
import tempfile
import subprocess
from unittest import TestCase
class fakePopen(object):
def __init__(self, returncode=0):
self.returncode = returncode
self.stdout = self.stderr = self.data = ""
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
return self
def communicate(self, data):
self.data += data
return self.stdout, self.stderr
class TestCase(TestCase):
def setUp(self):
# Creating a temp directory that can be used by tests
self.tempdir = tempfile.mkdtemp()
# some plugins call popen, we're replacing it for tests
self._Popen = subprocess.Popen
self.fakePopen = subprocess.Popen = fakePopen()
def tearDown(self):
# remove the temp directory
shutil.rmtree(self.tempdir)
subprocess.Popen = self._Popen

76
tests/test_base.py Normal file
View File

@ -0,0 +1,76 @@
# -*- 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 shutil
import tempfile
import subprocess
class FakePopen(object):
def __init__(self, returncode=0):
self.returncode = returncode
self.stdout = self.stderr = self.data = ""
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
return self
def communicate(self, data=None):
self.data += data or ''
return self.stdout, self.stderr
class PackstackTestCaseMixin(object):
"""
Implementation of some assertion methods available by default
in Python2.7+ only
"""
def setUp(self):
# Creating a temp directory that can be used by tests
self.tempdir = tempfile.mkdtemp()
# some plugins call popen, we're replacing it for tests
self._Popen = subprocess.Popen
self.fake_popen = subprocess.Popen = FakePopen()
def tearDown(self):
# remove the temp directory
shutil.rmtree(self.tempdir)
subprocess.Popen = self._Popen
def assertItemsEqual(self, list1, list2, msg=None):
f, s = len(list1), len(list2)
self.assertEqual(f, s, msg=('Element counts were not equal. '
'First has %s, Second has %s' % (f, s)))
for i in list1:
if i not in list2:
raise AssertionError('Given lists differ:'
'\n%(list1)s\n%(list2)s' % locals())
def assertListEqual(self, list1, list2, msg=None):
f, s = len(list1), len(list2)
self.assertEqual(f, s, msg=('Element counts were not equal. '
'First has %s, Second has %s' % (f, s)))
for index, item in enumerate(list1):
if item != list2[index]:
raise AssertionError('Given lists differ:'
'\n%(list1)s\n%(list2)s' % locals())
def assertIsInstance(self, obj, cls, msg=None):
if not isinstance(obj, cls):
raise AssertionError('%s is not an instance of %s' % (obj, cls))

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4 # vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013, Red Hat, Inc. # Copyright 2013, Red Hat, Inc.
@ -15,14 +16,15 @@
# under the License. # under the License.
import os import os
from test import TestCase from unittest import TestCase
from test_base import PackstackTestCaseMixin
from packstack.modules.ospluginutils import gethostlist, \ from packstack.modules.ospluginutils import gethostlist, \
validate_puppet_logfile, \ validate_puppet_logfile, \
PackStackError PackStackError
class OSPluginUtilsTestCase(TestCase): class OSPluginUtilsTestCase(PackstackTestCaseMixin, TestCase):
def test_gethostlist(self): def test_gethostlist(self):
conf = {"A_HOST": "1.1.1.1", "B_HOSTS": "2.2.2.2,1.1.1.1", conf = {"A_HOST": "1.1.1.1", "B_HOSTS": "2.2.2.2,1.1.1.1",
"C_HOSTS": "3.3.3.3/vdc"} "C_HOSTS": "3.3.3.3/vdc"}

View File

@ -15,15 +15,16 @@
# under the License. # under the License.
import os import os
from test import TestCase from unittest import TestCase
from test_base import PackstackTestCaseMixin
from packstack.plugins import serverprep_901 from packstack.plugins import serverprep_901
from packstack.installer.setup_controller import Controller from packstack.installer.setup_controller import Controller
serverprep_901.controller = Controller() serverprep_901.controller = Controller()
class OSPluginUtilsTestCase(TestCase): class OSPluginUtilsTestCase(PackstackTestCaseMixin, TestCase):
def test_rhn_creds_quoted(self): def test_rhn_creds_quoted(self):
"""Make sure RHN password is quoted""" """Make sure RHN password is quoted"""
@ -37,5 +38,5 @@ class OSPluginUtilsTestCase(TestCase):
serverprep_901.serverprep() serverprep_901.serverprep()
self.assertNotEqual( self.assertNotEqual(
self.fakePopen.data.find('--password="%s"' % password), -1 self.fake_popen.data.find('--password="%s"' % password), -1
) )

82
tests/test_validators.py Normal file
View File

@ -0,0 +1,82 @@
# -*- 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 os
import shutil
import tempfile
from unittest import TestCase
from test_base import PackstackTestCaseMixin
from packstack.installer.engine_validators import *
class ValidatorsTestCase(PackstackTestCaseMixin, TestCase):
def setUp(self):
# Creating a temp directory that can be used by tests
self.tempdir = tempfile.mkdtemp()
def tearDown(self):
# remove the temp directory
shutil.rmtree(self.tempdir)
def test_validate_integer(self):
validate_integer('1')
self.assertRaises(ParamValidationError, validate_integer, 'test')
def test_validate_regexp(self):
validate_regexp('Test_123', options=['\w'])
self.assertRaises(ParamValidationError, validate_regexp,
'!#$%', options=['\w'])
def test_validate_port(self):
validate_port('666')
self.assertRaises(ParamValidationError, validate_port, 'test')
self.assertRaises(ParamValidationError, validate_port, '-3')
def test_validate_not_empty(self):
validate_not_empty('test')
validate_not_empty(False)
self.assertRaises(ParamValidationError, validate_not_empty, '')
self.assertRaises(ParamValidationError, validate_not_empty, [])
self.assertRaises(ParamValidationError, validate_not_empty, {})
def test_validate_options(self):
validate_options('a', options=['a', 'b'])
validate_options('b', options=['a', 'b'])
self.assertRaises(ParamValidationError, validate_options,
'c', options=['a', 'b'])
def test_validate_ip(self):
validate_ip('127.0.0.1')
validate_ip('::1')
self.assertRaises(ParamValidationError, validate_ip, 'test')
def test_validate_file(self):
fname = os.path.join(self.tempdir, '.test_validate_file')
bad_name = os.path.join(self.tempdir, '.me_no_exists')
with open(fname, 'w') as f:
f.write('test')
validate_file(fname)
self.assertRaises(ParamValidationError, validate_file, bad_name)
def test_validate_ping(self):
# ping to broadcast fails
self.assertRaises(ParamValidationError, validate_ping, '192.168.122.0')
def test_validate_ssh(self):
# ssh to broadcast fails
self.assertRaises(ParamValidationError, validate_ssh, '192.168.122.0')