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:
parent
f6a0b0781b
commit
a3d2a6d616
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
*.pyc
|
||||
*.py[co]
|
||||
*.swp
|
||||
*.log
|
||||
.tox
|
||||
packstack.egg-info
|
||||
|
@ -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.path
|
||||
import re
|
||||
import socket
|
||||
import logging
|
||||
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):
|
||||
availableSpace = utils.getAvailableSpace(_getBasePath(path))
|
||||
if availableSpace < size:
|
||||
print output_messages.INFO_VAL_PATH_SPACE % (path,
|
||||
utils.transformUnits(availableSpace),
|
||||
utils.transformUnits(size))
|
||||
return False
|
||||
return True
|
||||
|
||||
def validateInteger(param, options=[]):
|
||||
def validate_integer(param, options=None):
|
||||
"""
|
||||
Raises ParamValidationError if given param is not integer.
|
||||
"""
|
||||
options = options or []
|
||||
try:
|
||||
int(param)
|
||||
return True
|
||||
except:
|
||||
logging.warn("validateInteger('%s') - failed" %(param))
|
||||
print output_messages.INFO_VAL_NOT_INTEGER
|
||||
return False
|
||||
except ValueError:
|
||||
logging.debug('validate_integer(%s, options=%s) failed.' %
|
||||
(param, options))
|
||||
msg = 'Given value is not an integer: %s'
|
||||
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:
|
||||
if re.search(regex, param):
|
||||
return True
|
||||
logging.warn("validateRe('%s') - failed" %(param))
|
||||
return False
|
||||
break
|
||||
else:
|
||||
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
|
||||
logging.debug("Validating %s as a valid TCP Port" % (param))
|
||||
minVal = 0
|
||||
controller = Controller()
|
||||
isProxyEnabled = utils.compareStrIgnoreCase(controller.CONF["OVERRIDE_HTTPD_CONFIG"], "yes")
|
||||
if not isProxyEnabled:
|
||||
minVal = 1024
|
||||
if not validateInteger(param, options):
|
||||
return False
|
||||
|
||||
def validate_port(param, options=None):
|
||||
"""
|
||||
Raises ParamValidationError if given param is not a decimal number
|
||||
in range (0, 65535).
|
||||
"""
|
||||
options = options or []
|
||||
validate_integer(param, options)
|
||||
port = int(param)
|
||||
if not (port > minVal and port < 65535) :
|
||||
logging.warn(output_messages.INFO_VAL_PORT_NOT_RANGE %(minVal))
|
||||
print output_messages.INFO_VAL_PORT_NOT_RANGE %(minVal)
|
||||
return False
|
||||
(portOpen, process, pid) = utils.isTcpPortOpen(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
|
||||
if not (port >= 0 and port < 65535):
|
||||
logging.debug('validate_port(%s, options=%s) failed.' %
|
||||
(param, options))
|
||||
msg = 'Given value is outside the range of (0, 65535): %s'
|
||||
raise ParamValidationError(msg % param)
|
||||
|
||||
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)
|
||||
cmd = [
|
||||
basedefs.EXEC_SEMANAGE, "port", "-l",
|
||||
]
|
||||
out, rc = utils.execCmd(cmdList=cmd) #, "-t", "http_port_t"])
|
||||
if rc:
|
||||
return False
|
||||
httpPortsList = []
|
||||
pattern = re.compile("^http_port_t\s*tcp\s*([0-9, \-]*)$")
|
||||
for line in out.splitlines():
|
||||
httpPortPolicy = re.match(pattern, line)
|
||||
if httpPortPolicy:
|
||||
httpPortsList = parsePorts(httpPortPolicy.groups()[0])
|
||||
logging.debug("http_port_t = %s"%(httpPortsList))
|
||||
if newPort in httpPortsList:
|
||||
return True
|
||||
def validate_not_empty(param, options=None):
|
||||
"""
|
||||
Raises ParamValidationError if given param is empty.
|
||||
"""
|
||||
options = options or []
|
||||
if not param and param is not False:
|
||||
logging.debug('validate_not_empty(%s, options=%s) failed.' %
|
||||
(param, options))
|
||||
msg = 'Given value is not allowed: %s'
|
||||
raise ParamValidationError(msg % param)
|
||||
|
||||
|
||||
def validate_options(param, options=None):
|
||||
"""
|
||||
Raises ParamValidationError if given param is not member of options.
|
||||
"""
|
||||
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:
|
||||
cmd = [
|
||||
basedefs.EXEC_SEMANAGE,
|
||||
"port",
|
||||
"-a",
|
||||
"-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
|
||||
logging.debug('validate_ip(%s, options=%s) failed.' %
|
||||
(param, options))
|
||||
msg = 'Given host is not in IP address format: %s'
|
||||
raise ParamValidationError(msg % param)
|
||||
|
||||
|
||||
|
||||
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=[]):
|
||||
def validate_multi_ip(param, options=None):
|
||||
"""
|
||||
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))
|
||||
(errMsg, rc) = _validateString(param, 1, 1024, "^[\w\-\_]+\.[\w\.\-\_]+\w+$")
|
||||
for host in param.split(','):
|
||||
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
|
||||
Setting a logical max value of 256
|
||||
Raises ParamValidationError if provided file in param does not exist.
|
||||
"""
|
||||
logging.info("validating %s as a valid user name" % (param))
|
||||
(errMsg, rc) = _validateString(param, 1, 256, "^\w[\w\.\-\_\%\@]{2,}$")
|
||||
|
||||
# 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
|
||||
options = options or []
|
||||
validate_not_empty(param)
|
||||
|
||||
if not os.path.isfile(param):
|
||||
print "\n" + output_messages.ERR_FILE + ".\n"
|
||||
return False
|
||||
logging.debug('validate_file(%s, options=%s) failed.' %
|
||||
(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):
|
||||
cmd = [
|
||||
"/bin/ping",
|
||||
"-c", "1",
|
||||
"%s" % param,
|
||||
]
|
||||
out, rc = utils.execCmd(cmdList=cmd)
|
||||
if rc == 0:
|
||||
return True
|
||||
options = options or []
|
||||
validate_not_empty(param)
|
||||
|
||||
print "\n" + output_messages.ERR_PING + " %s .\n"%param
|
||||
return False
|
||||
cmd = ["/bin/ping", "-c", "1", str(param)]
|
||||
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 validatePort(host, port):
|
||||
def validate_multi_ping(param, options=None):
|
||||
"""
|
||||
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)
|
||||
# No need to keep checking the same port multiple times
|
||||
if key in _testedPorts:
|
||||
return True
|
||||
options = options or []
|
||||
validate_not_empty(param)
|
||||
for host in param.split(","):
|
||||
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.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:
|
||||
s.connect((host, port))
|
||||
s.shutdown(socket.SHUT_RDWR)
|
||||
s.close()
|
||||
except socket.error as msg:
|
||||
return False
|
||||
_testedPorts.append(key)
|
||||
return True
|
||||
touch_port(param.strip(), 22)
|
||||
except socket.error:
|
||||
logging.debug('validate_ssh(%s, options=%s) failed.' %
|
||||
(param, options))
|
||||
msg = 'Given host does not listen on port 22: %s'
|
||||
raise ParamValidationError(msg % param)
|
||||
|
||||
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):
|
||||
return True
|
||||
print "\n" + output_messages.ERR_SSH%param
|
||||
return False
|
||||
|
||||
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
|
||||
options = options or []
|
||||
validate_not_empty(param)
|
||||
for host in param.split(","):
|
||||
validate_ssh(host)
|
||||
|
@ -20,22 +20,25 @@ class PackStackError(Exception):
|
||||
|
||||
|
||||
class MissingRequirements(PackStackError):
|
||||
"""Raised when minimum install requirements are not met"""
|
||||
"""Raised when minimum install requirements are not met."""
|
||||
pass
|
||||
|
||||
|
||||
class InstallError(PackStackError):
|
||||
pass
|
||||
|
||||
|
||||
class FlagValidationError(InstallError):
|
||||
"""Raised when single flag validation fails."""
|
||||
pass
|
||||
|
||||
class ParamValidationError(InstallError):
|
||||
"""Raised when parameter value validation fails."""
|
||||
pass
|
||||
|
||||
|
||||
class PluginError(PackStackError):
|
||||
pass
|
||||
|
||||
|
||||
class ParamProcessingError(PluginError):
|
||||
pass
|
||||
|
||||
|
@ -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_PASSWORD_DONT_MATCH="Error: passwords don't match"
|
||||
|
||||
INFO_VAL_IS_HOSTNAME = ("Packstack changed given hostname %s to IP "
|
||||
"address %s.")
|
||||
INFO_CHANGED_VALUE = ("Packstack changed given value %s to required "
|
||||
"value %s")
|
||||
WARN_VAL_IS_HOSTNAME = ("Warning: Packstack failed to change given "
|
||||
"hostname %s to IP address. Note that some "
|
||||
"services might not run correctly when hostname"
|
||||
|
@ -17,7 +17,7 @@ import common_utils as utils
|
||||
import engine_processors as process
|
||||
import engine_validators as validate
|
||||
import output_messages
|
||||
from .exceptions import FlagValidationError
|
||||
from .exceptions import FlagValidationError, ParamValidationError
|
||||
|
||||
from setup_controller import Controller
|
||||
|
||||
@ -77,8 +77,9 @@ def _getInputFromUser(param):
|
||||
message = StringIO()
|
||||
message.write(param.getKey("PROMPT"))
|
||||
|
||||
if not param.getKey("VALIDATION_FUNC") == validate.validateRe \
|
||||
and param.getKey("OPTION_LIST"):
|
||||
validators = param.getKey("VALIDATORS") or []
|
||||
if validate.validate_regexp not in validators \
|
||||
and param.getKey("OPTION_LIST"):
|
||||
message.write(" [%s]" % "|".join(param.getKey("OPTION_LIST")))
|
||||
|
||||
if param.getKey("DEFAULT_VALUE"):
|
||||
@ -99,62 +100,33 @@ def _getInputFromUser(param):
|
||||
userInput = param.getKey("DEFAULT_VALUE")
|
||||
|
||||
# Param processing
|
||||
try:
|
||||
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"))
|
||||
userInput = process_param_value(param, userInput)
|
||||
|
||||
# If param requires validation
|
||||
if param.getKey("VALIDATION_FUNC")(userInput, param.getKey("OPTION_LIST")):
|
||||
if "yes" in param.getKey("OPTION_LIST") and userInput.lower() == "y":
|
||||
userInput = "yes"
|
||||
if "no" in param.getKey("OPTION_LIST") and userInput.lower() == "n":
|
||||
userInput = "no"
|
||||
try:
|
||||
validate_param_value(param, userInput)
|
||||
controller.CONF[param.getKey("CONF_NAME")] = userInput
|
||||
loop = False
|
||||
# If validation failed but LOOSE_VALIDATION is true, ask user
|
||||
elif param.getKey("LOOSE_VALIDATION"):
|
||||
answer = _askYesNo("User input failed validation, do you still wish to use it")
|
||||
if answer:
|
||||
loop = False
|
||||
controller.CONF[param.getKey("CONF_NAME")] = userInput
|
||||
except ParamValidationError:
|
||||
if param.getKey("LOOSE_VALIDATION"):
|
||||
# If validation failed but LOOSE_VALIDATION is true, ask user
|
||||
answer = _askYesNo("User input failed validation, "
|
||||
"do you still wish to use it")
|
||||
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:
|
||||
# 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
|
||||
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:
|
||||
print "" # add the new line so messages wont be displayed in the same line as the question
|
||||
raise KeyboardInterrupt
|
||||
raise
|
||||
except:
|
||||
logging.error(traceback.format_exc())
|
||||
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"
|
||||
confirmedParam.setKey("CONF_NAME", confirmedParamName)
|
||||
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
|
||||
while True:
|
||||
_getInputFromUser(param)
|
||||
@ -285,35 +257,39 @@ def maskString(str):
|
||||
str = str.replace(password, '*'*8)
|
||||
return str
|
||||
|
||||
def _validateParamValue(param, paramValue):
|
||||
validateFunc = param.getKey("VALIDATION_FUNC")
|
||||
optionsList = param.getKey("OPTION_LIST")
|
||||
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 validate_param_value(param, value):
|
||||
cname = param.getKey("CONF_NAME")
|
||||
logging.debug("Validating parameter %s." % cname)
|
||||
|
||||
def _processParamValue(param, paramValue):
|
||||
try:
|
||||
processFunc = param.getKey("PROCESSOR_FUNC")
|
||||
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))
|
||||
validators = param.getKey("VALIDATORS") or []
|
||||
opt_list = param.getKey("OPTION_LIST")
|
||||
for val_func in validators:
|
||||
try:
|
||||
msg = param.getKey("PROCESSOR_MSG")
|
||||
print getattr(output_messages, msg) % cn
|
||||
except KeyError:
|
||||
pass
|
||||
return paramValue
|
||||
val_func(value, opt_list)
|
||||
except ParamValidationError as ex:
|
||||
print 'Parameter %s failed validation: %s' % (cname, ex)
|
||||
raise
|
||||
|
||||
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):
|
||||
"""
|
||||
@ -349,8 +325,8 @@ def _loadParamFromFile(config, section, paramName):
|
||||
|
||||
# Validate param value using its validation func
|
||||
param = controller.getParamByName(paramName)
|
||||
value = _processParamValue(param, value)
|
||||
_validateParamValue(param, value)
|
||||
value = process_param_value(param, value)
|
||||
validate_param_value(param, value)
|
||||
|
||||
# Keep param value in our never ending global conf
|
||||
controller.CONF[param.getKey("CONF_NAME")] = value
|
||||
|
@ -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")
|
||||
|
@ -3,9 +3,9 @@ Container set for groups and parameters
|
||||
"""
|
||||
class Param(object):
|
||||
allowed_keys = ('CMD_OPTION','USAGE','PROMPT','OPTION_LIST',
|
||||
'PROCESSOR_ARGS', 'PROCESSOR_FUNC', 'PROCESSOR_MSG',
|
||||
'VALIDATION_FUNC','DEFAULT_VALUE','MASK_INPUT','LOOSE_VALIDATION',
|
||||
'CONF_NAME','USE_DEFAULT','NEED_CONFIRM','CONDITION')
|
||||
'PROCESSORS', 'VALIDATORS','DEFAULT_VALUE',
|
||||
'MASK_INPUT', 'LOOSE_VALIDATION', 'CONF_NAME',
|
||||
'USE_DEFAULT','NEED_CONFIRM','CONDITION')
|
||||
|
||||
def __init__(self, attributes=None):
|
||||
if not attributes:
|
||||
@ -25,10 +25,10 @@ class Param(object):
|
||||
|
||||
def getKey(self, key):
|
||||
self.validateKey(key)
|
||||
return self.__ATTRIBUTES[key]
|
||||
return self.__ATTRIBUTES.get(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)
|
||||
|
||||
class Group(Param):
|
||||
|
@ -5,6 +5,7 @@ import re
|
||||
|
||||
from packstack.installer import basedefs
|
||||
from packstack.installer.setup_controller import Controller
|
||||
from packstack.installer.exceptions import PackStackError
|
||||
|
||||
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")
|
||||
|
||||
|
||||
class PackStackError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NovaConfig(object):
|
||||
"""
|
||||
Helper class to create puppet manifest entries for nova_config
|
||||
|
@ -34,11 +34,8 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address of the server on which to install Cinder",
|
||||
"PROMPT" : "Enter the IP address of the Cinder server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_CINDER_HOST",
|
||||
@ -49,7 +46,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Cinder to access DB",
|
||||
"PROMPT" : "Enter the password for the Cinder DB access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -61,7 +58,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Cinder to authenticate with Keystone",
|
||||
"PROMPT" : "Enter the password for the Cinder Keystone access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -73,7 +70,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Cinder's volumes group size",
|
||||
"PROMPT" : "Enter Cinder's volumes group size",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "2G",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -85,7 +82,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Cinder's volumes group path",
|
||||
"PROMPT" : "Enter Cinder's volumes group path",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "/var/lib/cinder",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -97,7 +94,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Cinder's volumes group name",
|
||||
"PROMPT" : "Enter Cinder's volumes group name",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "cinder-volumes",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -109,7 +106,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Create Cinder's volumes group",
|
||||
"PROMPT" : "Should Cinder's volumes group be created?",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : createVolume,
|
||||
"VALIDATORS" : [validate.validate_options, createVolume],
|
||||
"DEFAULT_VALUE" : "y",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -141,18 +138,19 @@ def initSequences(controller):
|
||||
controller.addSequence("Installing OpenStack Cinder", [], [], cindersteps)
|
||||
|
||||
|
||||
def createVolume(param, options=[]):
|
||||
def createVolume(param, options=None):
|
||||
"""
|
||||
Check that provided host is listening on port 22
|
||||
"""
|
||||
options = options or []
|
||||
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']:
|
||||
param = controller.getParamByName(option)
|
||||
param.setKey('USE_DEFAULT', False)
|
||||
setup.input_param(param)
|
||||
return True
|
||||
|
||||
|
||||
def checkcindervg():
|
||||
|
@ -30,11 +30,8 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address of the server on which to install Horizon",
|
||||
"PROMPT" : "Enter the IP address of the Horizon server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_HORIZON_HOST",
|
||||
|
@ -30,11 +30,8 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address of the server on which to install Glance",
|
||||
"PROMPT" : "Enter the IP address of the Glance server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_GLANCE_HOST",
|
||||
@ -45,7 +42,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Glance to access DB",
|
||||
"PROMPT" : "Enter the password for the Glance DB access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -57,7 +54,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Glance to authenticate with Keystone",
|
||||
"PROMPT" : "Enter the password for the Glance Keystone access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
|
@ -31,11 +31,8 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address of the server on which to install Keystone",
|
||||
"PROMPT" : "Enter the IP address of the Keystone server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_KEYSTONE_HOST",
|
||||
@ -46,7 +43,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Keystone to access DB",
|
||||
"PROMPT" : "Enter the password for the Keystone DB access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -58,7 +55,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The token to use for the Keystone service api",
|
||||
"PROMPT" : "The token to use for the Keystone service api",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex,
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -70,7 +67,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Keystone admin user",
|
||||
"PROMPT" : "Enter the password for the Keystone admin user",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
|
@ -30,11 +30,8 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address of the server on which to install MySQL",
|
||||
"PROMPT" : "Enter the IP address of the MySQL server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_MYSQL_HOST",
|
||||
@ -45,7 +42,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Username for the MySQL admin user",
|
||||
"PROMPT" : "Enter the username for the MySQL admin user",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "root",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -57,7 +54,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Password for the MySQL admin user",
|
||||
"PROMPT" : "Enter the password for the MySQL admin user",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": True,
|
||||
|
@ -28,11 +28,8 @@ def initConfig(controllerObject):
|
||||
"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",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ip, validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"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",
|
||||
"PROMPT" : "Enter the IP address of the Nova Cert service",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"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",
|
||||
"PROMPT" : "Enter the IP address of the Nova VNC proxy",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"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",
|
||||
"PROMPT" : "Enter a comma separated list of IP addresses on which to install the Nova Compute services",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateMultiSSH,
|
||||
"VALIDATORS" : [validate.validate_multi_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_NOVA_COMPUTE_HOSTS", # TO-DO: Create processor for CSV
|
||||
"CONF_NAME" : "CONFIG_NOVA_COMPUTE_HOSTS",
|
||||
"USE_DEFAULT" : False,
|
||||
"NEED_CONFIRM" : False,
|
||||
"CONDITION" : False },
|
||||
@ -85,7 +76,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "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" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "eth1",
|
||||
"MASK_INPUT" : False,
|
||||
"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",
|
||||
"PROMPT" : "Enter the IP address of the Nova Network service",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ip, validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_NOVA_NETWORK_HOST",
|
||||
@ -112,7 +100,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Nova to access DB",
|
||||
"PROMPT" : "Enter the password for the Nova DB access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -124,7 +112,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Nova to authenticate with Keystone",
|
||||
"PROMPT" : "Enter the password for the Nova Keystone access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -136,7 +124,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Public interface on the Nova network server",
|
||||
"PROMPT" : "Enter the Public interface on the Nova network server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "eth0",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
@ -148,7 +136,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "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" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : "eth1",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
@ -160,7 +148,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "IP Range for Flat DHCP",
|
||||
"PROMPT" : "Enter the IP Range for Flat DHCP",
|
||||
"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",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
@ -172,7 +160,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "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?$"],
|
||||
"VALIDATION_FUNC" : validate.validateRe,
|
||||
"VALIDATORS" : [validate.validate_regexp],
|
||||
"DEFAULT_VALUE" : "10.3.4.0/22",
|
||||
"MASK_INPUT" : False,
|
||||
"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",
|
||||
"PROMPT" : "Enter the IP address of the Nova Scheduler service",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_NOVA_SCHED_HOST",
|
||||
@ -204,6 +189,7 @@ def initConfig(controllerObject):
|
||||
"POST_CONDITION_MATCH" : True}
|
||||
controller.addGroup(groupDict, paramsList)
|
||||
|
||||
|
||||
def initSequences(controller):
|
||||
if controller.CONF['CONFIG_NOVA_INSTALL'] != 'y':
|
||||
return
|
||||
@ -220,59 +206,71 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing OpenStack Nova API", [], [], novaapisteps)
|
||||
|
||||
|
||||
def createapimanifest():
|
||||
manifestfile = "%s_api_nova.pp"%controller.CONF['CONFIG_NOVA_API_HOST']
|
||||
manifestdata = getManifestTemplate("nova_api.pp")
|
||||
appendManifestFile(manifestfile, manifestdata, 'novaapi')
|
||||
|
||||
|
||||
def createkeystonemanifest():
|
||||
manifestfile = "%s_keystone.pp"%controller.CONF['CONFIG_KEYSTONE_HOST']
|
||||
manifestdata = getManifestTemplate("keystone_nova.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createcertmanifest():
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_CERT_HOST']
|
||||
manifestdata = getManifestTemplate("nova_cert.pp")
|
||||
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():
|
||||
for host in controller.CONF["CONFIG_NOVA_COMPUTE_HOSTS"].split(","):
|
||||
controller.CONF["CONFIG_NOVA_COMPUTE_HOST"] = host
|
||||
manifestdata = getManifestTemplate("nova_compute.pp")
|
||||
manifestfile = "%s_nova.pp"%host
|
||||
|
||||
server = utils.ScriptRunner(host)
|
||||
nova_config_options = NovaConfig()
|
||||
|
||||
if host != controller.CONF["CONFIG_NOVA_NETWORK_HOST"]:
|
||||
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())
|
||||
|
||||
|
||||
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)
|
||||
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
|
||||
manifestfile = "%s_nova.pp" % host
|
||||
manifestdata = getManifestTemplate("nova_network.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createschedmanifest():
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_SCHED_HOST']
|
||||
manifestdata = getManifestTemplate("nova_sched.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createvncproxymanifest():
|
||||
manifestfile = "%s_nova.pp"%controller.CONF['CONFIG_NOVA_VNCPROXY_HOST']
|
||||
manifestdata = getManifestTemplate("nova_vncproxy.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createcommonmanifest():
|
||||
for manifestfile, marker in manifestfiles.getFiles():
|
||||
if manifestfile.endswith("_nova.pp"):
|
||||
|
@ -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",
|
||||
"PROMPT" : "Enter the IP address of the client server",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_OSCLIENT_HOST",
|
||||
|
@ -29,7 +29,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Set to 'y' if you would like Packstack to install Glance",
|
||||
"PROMPT" : "Should Packstack install Glance image service",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "y",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -41,7 +41,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Set to 'y' if you would like Packstack to install Cinder",
|
||||
"PROMPT" : "Should Packstack install Cinder volume service",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "y",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -53,7 +53,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Set to 'y' if you would like Packstack to install Nova",
|
||||
"PROMPT" : "Should Packstack install Nova compute service",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "y",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -65,7 +65,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Set to 'y' if you would like Packstack to install Horizon",
|
||||
"PROMPT" : "Should Packstack install Horizon dashboard",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "y",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
@ -77,7 +77,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Set to 'y' if you would like Packstack to install Swift",
|
||||
"PROMPT" : "Should Packstack install Swift object storage",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "n",
|
||||
"MASK_INPUT" : 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",
|
||||
"PROMPT" : "Should Packstack install OpenStack client tools",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "y",
|
||||
"MASK_INPUT" : 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.",
|
||||
"PROMPT" : "Enter list of NTP server(s). Leave plain if Packstack should not install ntpd on instances.",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : lambda param, options: True,
|
||||
"DEFAULT_VALUE" : '',
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
|
@ -29,11 +29,8 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address of the server on which to install the QPID service",
|
||||
"PROMPT" : "Enter the IP address of the QPID service",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"PROCESSOR_ARGS" : {"allow_localhost": True},
|
||||
"PROCESSOR_FUNC" : process.processHost,
|
||||
"PROCESSOR_MSG" : "WARN_VAL_IS_HOSTNAME",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_QPID_HOST",
|
||||
|
@ -28,7 +28,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "Install OpenStack from EPEL. If set to \"y\" EPEL will be installed on each server",
|
||||
"PROMPT" : "Should Packstack install EPEL on each server",
|
||||
"OPTION_LIST" : ["y", "n"],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "n",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
@ -40,7 +40,6 @@ def initConfig(controllerObject):
|
||||
"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",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : lambda a,b: True,
|
||||
"DEFAULT_VALUE" : "",
|
||||
"MASK_INPUT" : False,
|
||||
"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",
|
||||
"PROMPT" : "To subscribe each server to Red Hat enter a username here",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : lambda a,b: True,
|
||||
"DEFAULT_VALUE" : "",
|
||||
"MASK_INPUT" : False,
|
||||
"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",
|
||||
"PROMPT" : "To subscribe each server to Red Hat enter your password here",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : lambda a,b: True,
|
||||
"DEFAULT_VALUE" : "",
|
||||
"MASK_INPUT" : True,
|
||||
"LOOSE_VALIDATION": True,
|
||||
|
@ -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",
|
||||
"PROMPT" : "Enter the path to your ssh Public key to install on servers",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateFile,
|
||||
"PROCESSOR_FUNC" : process.processSSHKey,
|
||||
"VALIDATORS" : [validate.validate_file],
|
||||
"PROCESSORS" : [process.processSSHKey],
|
||||
"DEFAULT_VALUE" : (glob.glob(os.path.join(os.environ["HOME"], ".ssh/*.pub"))+[""])[0],
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": False,
|
||||
|
@ -31,11 +31,11 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The IP address on which to install the Swift proxy service",
|
||||
"PROMPT" : "Enter the IP address of the Swift proxy service",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateSSH,
|
||||
"VALIDATORS" : [validate.validate_ip, validate.validate_ssh],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"MASK_INPUT" : False,
|
||||
"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,
|
||||
"NEED_CONFIRM" : False,
|
||||
"CONDITION" : False },
|
||||
@ -43,7 +43,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "The password to use for the Swift to authenticate with Keystone",
|
||||
"PROMPT" : "Enter the password for the Swift Keystone access",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty],
|
||||
"DEFAULT_VALUE" : uuid.uuid4().hex[:16],
|
||||
"MASK_INPUT" : True,
|
||||
"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",
|
||||
"PROMPT" : "Enter the Swift Storage servers e.g. host/dev,host/dev",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
|
||||
"VALIDATORS" : [validate.validate_not_empty, validate_storage],
|
||||
"DEFAULT_VALUE" : utils.getLocalhostIP(),
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
"CONF_NAME" : "CONFIG_SWIFT_STORAGE_HOSTS", # TO-DO: Create processor for CSV
|
||||
"CONF_NAME" : "CONFIG_SWIFT_STORAGE_HOSTS",
|
||||
"USE_DEFAULT" : False,
|
||||
"NEED_CONFIRM" : 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",
|
||||
"PROMPT" : "Enter the number of swift storage zones, MUST be no bigger than the number of storage devices configured",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateInteger,
|
||||
"VALIDATORS" : [validate.validate_integer],
|
||||
"DEFAULT_VALUE" : "1",
|
||||
"MASK_INPUT" : False,
|
||||
"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",
|
||||
"PROMPT" : "Enter the number of swift storage replicas, MUST be no bigger than the number of storage zones configured",
|
||||
"OPTION_LIST" : [],
|
||||
"VALIDATION_FUNC" : validate.validateInteger,
|
||||
"VALIDATORS" : [validate.validate_integer],
|
||||
"DEFAULT_VALUE" : "1",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
@ -91,7 +91,7 @@ def initConfig(controllerObject):
|
||||
"USAGE" : "FileSystem type for storage nodes",
|
||||
"PROMPT" : "Enter FileSystem type for storage nodes",
|
||||
"OPTION_LIST" : ['xfs','ext4'],
|
||||
"VALIDATION_FUNC" : validate.validateOptions,
|
||||
"VALIDATORS" : [validate.validate_options],
|
||||
"DEFAULT_VALUE" : "ext4",
|
||||
"MASK_INPUT" : False,
|
||||
"LOOSE_VALIDATION": True,
|
||||
@ -111,6 +111,12 @@ def initConfig(controllerObject):
|
||||
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):
|
||||
if controller.CONF['CONFIG_SWIFT_INSTALL'] != 'y':
|
||||
return
|
||||
@ -124,12 +130,14 @@ def initSequences(controller):
|
||||
]
|
||||
controller.addSequence("Installing OpenStack Swift", [], [], steps)
|
||||
|
||||
|
||||
def createkeystonemanifest():
|
||||
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")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
devices = []
|
||||
def parseDevices(config_swift_storage_hosts):
|
||||
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)})
|
||||
return devices
|
||||
|
||||
|
||||
# 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():
|
||||
@ -163,6 +172,7 @@ def createbuildermanifest():
|
||||
|
||||
appendManifestFile(manifestfile, manifestdata, 'swiftbuilder')
|
||||
|
||||
|
||||
def createproxymanifest():
|
||||
manifestfile = "%s_swift.pp"%controller.CONF['CONFIG_SWIFT_PROXY_HOSTS']
|
||||
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']
|
||||
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():
|
||||
|
||||
# this need to happen once per storage host
|
||||
@ -185,10 +221,8 @@ def createstoragemanifest():
|
||||
host = device['host']
|
||||
devicename = device['device_name']
|
||||
device = device['device']
|
||||
|
||||
server = utils.ScriptRunner(host)
|
||||
validate.r_validateDevice(server, device)
|
||||
server.execute()
|
||||
if device:
|
||||
check_device(host, device)
|
||||
|
||||
manifestfile = "%s_swift.pp"%host
|
||||
if device:
|
||||
@ -198,6 +232,7 @@ def createstoragemanifest():
|
||||
manifestdata = "\n" + getManifestTemplate("swift_loopback.pp")
|
||||
appendManifestFile(manifestfile, manifestdata)
|
||||
|
||||
|
||||
def createcommonmanifest():
|
||||
for manifestfile, marker in manifestfiles.getFiles():
|
||||
if manifestfile.endswith("_swift.pp"):
|
||||
|
2
run_tests.sh
Executable file
2
run_tests.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
tox -epy26,py27,pep8
|
@ -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
76
tests/test_base.py
Normal 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))
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013, Red Hat, Inc.
|
||||
@ -15,14 +16,15 @@
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
from test import TestCase
|
||||
from unittest import TestCase
|
||||
|
||||
from test_base import PackstackTestCaseMixin
|
||||
from packstack.modules.ospluginutils import gethostlist, \
|
||||
validate_puppet_logfile, \
|
||||
PackStackError
|
||||
|
||||
|
||||
class OSPluginUtilsTestCase(TestCase):
|
||||
class OSPluginUtilsTestCase(PackstackTestCaseMixin, TestCase):
|
||||
def test_gethostlist(self):
|
||||
conf = {"A_HOST": "1.1.1.1", "B_HOSTS": "2.2.2.2,1.1.1.1",
|
||||
"C_HOSTS": "3.3.3.3/vdc"}
|
||||
|
@ -15,15 +15,16 @@
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
from test import TestCase
|
||||
from unittest import TestCase
|
||||
|
||||
from test_base import PackstackTestCaseMixin
|
||||
from packstack.plugins import serverprep_901
|
||||
from packstack.installer.setup_controller import Controller
|
||||
|
||||
serverprep_901.controller = Controller()
|
||||
|
||||
|
||||
class OSPluginUtilsTestCase(TestCase):
|
||||
class OSPluginUtilsTestCase(PackstackTestCaseMixin, TestCase):
|
||||
def test_rhn_creds_quoted(self):
|
||||
"""Make sure RHN password is quoted"""
|
||||
|
||||
@ -37,5 +38,5 @@ class OSPluginUtilsTestCase(TestCase):
|
||||
serverprep_901.serverprep()
|
||||
|
||||
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
82
tests/test_validators.py
Normal 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')
|
Loading…
Reference in New Issue
Block a user