Merge pull request #24 from paramite/master

Issue #23
This commit is contained in:
Derek Higgins
2012-12-18 08:40:07 -08:00
17 changed files with 283 additions and 59 deletions

View File

@@ -22,7 +22,7 @@ EXEC_SEMANAGE="semanage"
EXEC_NSLOOKUP = "nslookup"
EXEC_CHKCONFIG = "chkconfig"
EXEC_SERVICE = "service"
EXEC_IP = "ip"
#text colors
RED = "\033[0;31m"

View File

@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
"""
contains all common and re-usable code for rhevm-setup and sub packages
"""
@@ -6,15 +8,25 @@ import pwd
import logging
import subprocess
import re
import output_messages
import traceback
import os
import basedefs
import datetime
import types
import time
import socket
import tempfile
import basedefs
import output_messages
class UtilsError(Exception):
pass
class UtilsNetworkError(UtilsError):
pass
def getColoredText (text, color):
''' gets text string and color
and returns a colored text.
@@ -290,6 +302,71 @@ def installed(rpm):
def returnYes(controller):
return "yes"
def getLocalhostIP():
"""
Returns IP address of localhost.
"""
# TO-DO: Will probably need to find better way to find out localhost
# address.
# find nameservers
ns_regex = re.compile('nameserver\s*(?P<ns_ip>[\d\.\:])')
resolv, rc = execCmd(['cat /etc/resolv.conf | grep nameserver',],
failOnError=False, useShell=True)
nsrvs = []
for line in resolv.split('\n'):
match = ns_regex.match(line.strip())
if match:
nsrvs.append(match.group('ns_ip'))
# try to connect to nameservers and return own IP address
nsrvs.append('8.8.8.8') # default to google dns
for i in nsrvs:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((i, 0))
loc_ip = s.getsockname()[0]
except socket.error:
continue
else:
return loc_ip
def host2ip(hostname, allow_localhost=False):
"""
Converts given hostname to IP address. Raises HostnameConvertError
if conversion failed.
"""
try:
ip_list = socket.gethostbyaddr(hostname)[2]
if allow_localhost:
return ip_list[0]
else:
local_ips = ('127.0.0.1', '::1')
for ip in ip_list:
if ip not in local_ips:
break
else:
raise NameError()
return ip
except NameError:
# given hostname is localhost, return appropriate IP address
ip = getLocalhostIP()
if not ip:
raise UtilsNetworkError('Failed to get local IP address.')
return ip
except socket.error:
raise UtilsNetworkError('Unknown hostname %s.' % hostname)
except Exception, ex:
raise UtilsNetworkError('Unknown error appeared: %s' % repr(ex))
def forceIP(host, allow_localhost=False):
host = host.strip()
ipv4_regex = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
ipv6_regex = re.compile('[abcdef\d\:]+')
if not ipv4_regex.match(host) or not ipv6_regex.match(host):
host = host2ip(host, allow_localhost=allow_localhost)
return host
class ScriptRunner(object):
def __init__(self, ip=None):
self.script = []
@@ -336,5 +413,3 @@ class ScriptRunner(object):
def ifexists(self, fn, s):
self.append("[ -e %s ] && %s"%(fn, s))

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from .common_utils import UtilsNetworkError, forceIP
__all__ = ('ParamProcessingError', 'processHost')
class ParamProcessingError(Exception):
pass
def processHost(param, process_args=None):
"""
Given parameter is a hostname, try to change it to IP address
"""
localhost = process_args and \
process_args.get('allow_localhost', False)
try:
return forceIP(param, allow_localhost=localhost)
except UtilsNetworkError, ex:
raise ParamProcessingError(str(ex))

View File

@@ -13,6 +13,12 @@ import os.path
import tempfile
from setup_controller import Controller
# 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:
@@ -364,4 +370,3 @@ def r_validateDevice(server, device=None):
# if we got here without exiting then we can't use this device
server.append('exit 1')
return False

View File

@@ -40,6 +40,13 @@ 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.")
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"
" is used.")
INFO_STRING_LEN_LESS_THAN_MIN="String length is less than the minimum allowed: %s"
INFO_STRING_EXCEEDS_MAX_LENGTH="String length exceeds the maximum length allowed: %s"
INFO_STRING_CONTAINS_ILLEGAL_CHARS="String contains illegal characters"
@@ -70,7 +77,7 @@ ERR_EXP_FAILED_INIT_LOGGER="Unexpected error: Failed to initiate logger, please
ERR_RC_CODE="Return Code is not zero"
ERR_FAILURE="General failure"
ERR_NO_ANSWER_FILE="Error: Could not find file %s"
ERR_ONLY_1_FLAG="Error: The %s flag is mutually exclusive to all other command line options"
#
INFO_KEYSTONERC="To use the command line tools simply source the keystonerc_* files created here"

View File

@@ -16,6 +16,7 @@ from optparse import OptionParser, OptionGroup
import basedefs
import common_utils as utils
import engine_validators as validate
import engine_processors as process
import output_messages
from setup_controller import Controller
@@ -28,7 +29,15 @@ commandLineValues = {}
#TODO: read default values from conf_param?
masked_value_set = set()
def initLogging():
class InstallError(Exception):
pass
class FlagValidationError(InstallError):
pass
def initLogging(level='INFO'):
global logFile
try:
#in order to use UTC date for the log file, send True to getCurrentDateTime(True)
@@ -36,7 +45,7 @@ def initLogging():
logFile = os.path.join(basedefs.DIR_LOG,logFilename)
if not os.path.isdir(os.path.dirname(logFile)):
os.makedirs(os.path.dirname(logFile))
level = logging.INFO
level = getattr(logging, level)
hdlr = logging.FileHandler(filename = logFile, mode='w')
fmts='%(asctime)s::%(levelname)s::%(module)s::%(lineno)d::%(name)s:: %(message)s'
dfmt='%Y-%m-%d %H:%M:%S'
@@ -63,7 +72,7 @@ def initSequences():
def setDebug():
if controller.CONF['CONFIG_DEBUG'] == 'y':
logging.root.setLevel(logging.DEBUG)
logging.root.setLevel(logging.DEBUG) # XXX: this doesn't work at all, will have to refactor
def initConfig():
"""
@@ -162,6 +171,36 @@ def _getInputFromUser(param):
if userInput == "" and len(param.getKey("DEFAULT_VALUE")) > 0:
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"))
# 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":
@@ -320,6 +359,29 @@ def _validateParamValue(param, paramValue):
if not validateFunc(paramValue, optionsList):
raise Exception(output_messages.ERR_EXP_VALIDATE_PARAM % param.getKey("CONF_NAME"))
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))
try:
msg = param.getKey("PROCESSOR_MSG")
print getattr(output_messages, msg) % cn
except KeyError:
pass
return paramValue
def _handleGroupCondition(config, conditionName, conditionValue):
"""
handle params group pre/post condition
@@ -354,6 +416,7 @@ def _loadParamFromFile(config, section, paramName):
# Validate param value using its validation func
param = controller.getParamByName(paramName)
value = _processParamValue(param, value)
_validateParamValue(param, value)
# Keep param value in our never ending global conf
@@ -736,10 +799,9 @@ def countCmdLineFlags(options, flag):
def validateSingleFlag(options, flag):
counter = countCmdLineFlags(options, flag)
if counter > 0:
optParser.print_help()
print
#replace _ with - for printing's sake
raise Exception(output_messages.ERR_ONLY_1_FLAG % "--%s" % flag.replace("_","-"))
flag = flag.replace("_","-")
msg = output_messages.ERR_ONLY_1_FLAG % ("--%s" % flag)
raise FlagValidationError(msg)
def initPluginsConfig():
@@ -806,12 +868,15 @@ def main():
except SystemExit:
raise
except FlagValidationError, ex:
optParser.print_help()
print
except BaseException as e:
logging.error(traceback.format_exc())
print e
print output_messages.ERR_CHECK_LOG_FILE_FOR_MORE_INFO%(logFile)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -3,16 +3,21 @@ 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')
def __init__(self, attributes={}):
self.__ATTRIBUTES = {}
if attributes:
for key in self.allowed_keys:
self.__ATTRIBUTES[key] = attributes[key]
else:
def __init__(self, attributes=None):
if not attributes:
self.__ATTRIBUTES = {}.fromkeys(self.allowed_keys)
return
self.__ATTRIBUTES = {}
for key, value in attributes.iteritems():
if key not in self.allowed_keys:
raise KeyError('Given attribute %s is '
'not allowed' % key)
self.__ATTRIBUTES[key] = value
def setKey(self, key, value):
self.validateKey(key)

View File

@@ -5,6 +5,7 @@ Installs and configures Cinder
import logging
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -30,6 +31,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -77,4 +81,3 @@ def createmanifest():
manifestfile = "%s_cinder.pp"%controller.CONF['CONFIG_CINDER_HOST']
manifestdata = getManifestTemplate("cinder.pp")
appendManifestFile(manifestfile, manifestdata)

View File

@@ -6,6 +6,7 @@ import logging
import uuid
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -31,6 +32,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",

View File

@@ -5,6 +5,7 @@ Installs and configures Glance
import logging
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -30,6 +31,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -67,4 +71,3 @@ def createmanifest():
manifestfile = "%s_glance.pp"%controller.CONF['CONFIG_GLANCE_HOST']
manifestdata = getManifestTemplate("glance.pp")
appendManifestFile(manifestfile, manifestdata)

View File

@@ -7,6 +7,7 @@ import uuid
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -32,6 +33,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",

View File

@@ -2,9 +2,11 @@
Installs and configures MySQL
"""
import uuid
import logging
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -30,6 +32,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -52,8 +57,8 @@ def initConfig(controllerObject):
"USAGE" : "Password for the MySQL admin user",
"PROMPT" : "Password for the MySQL admin user",
"OPTION_LIST" : [],
"VALIDATION_FUNC" : lambda a,b: True,
"DEFAULT_VALUE" : "",
"VALIDATION_FUNC" : validate.validateStringNotEmpty,
"DEFAULT_VALUE" : uuid.uuid4().hex[:6],
"MASK_INPUT" : True,
"LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_MYSQL_PW",
@@ -83,4 +88,3 @@ def createmanifest():
manifestfile = "%s_mysql.pp"%controller.CONF['CONFIG_MYSQL_HOST']
manifestdata = getManifestTemplate("mysql.pp")
appendManifestFile(manifestfile, manifestdata, 'pre')

View File

@@ -6,6 +6,7 @@ import logging
import os
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
import packstack.installer.common_utils as utils
from packstack.modules.ospluginutils import NovaConfig, getManifestTemplate, appendManifestFile, manifestfiles
@@ -28,6 +29,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -40,6 +44,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -52,6 +59,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validateMultiPing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -66,7 +76,7 @@ def initConfig(controllerObject):
"DEFAULT_VALUE" : "127.0.0.1",
"MASK_INPUT" : False,
"LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_NOVA_COMPUTE_HOSTS",
"CONF_NAME" : "CONFIG_NOVA_COMPUTE_HOSTS", # TO-DO: Create processor for CSV
"USE_DEFAULT" : False,
"NEED_CONFIRM" : False,
"CONDITION" : False },
@@ -100,6 +110,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",
@@ -160,6 +173,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",

View File

@@ -5,6 +5,7 @@ Installs and configures an openstack client
import logging
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -30,6 +31,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",

View File

@@ -5,6 +5,7 @@ Installs and configures qpid
import logging
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -30,6 +31,9 @@ def initConfig(controllerObject):
"OPTION_LIST" : [],
"VALIDATION_FUNC" : validate.validatePing,
"DEFAULT_VALUE" : "127.0.0.1",
"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",

View File

@@ -6,6 +6,7 @@ import logging
import os
import packstack.installer.engine_validators as validate
import packstack.installer.engine_processors as process
from packstack.installer import basedefs
import packstack.installer.common_utils as utils
@@ -33,7 +34,7 @@ def initConfig(controllerObject):
"DEFAULT_VALUE" : "127.0.0.1",
"MASK_INPUT" : False,
"LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_SWIFT_PROXY_HOSTS",
"CONF_NAME" : "CONFIG_SWIFT_PROXY_HOSTS", # TO-DO: Create processor for CSV
"USE_DEFAULT" : False,
"NEED_CONFIRM" : False,
"CONDITION" : False },
@@ -45,7 +46,7 @@ def initConfig(controllerObject):
"DEFAULT_VALUE" : "127.0.0.1",
"MASK_INPUT" : False,
"LOOSE_VALIDATION": True,
"CONF_NAME" : "CONFIG_SWIFT_STORAGE_HOSTS",
"CONF_NAME" : "CONFIG_SWIFT_STORAGE_HOSTS", # TO-DO: Create processor for CSV
"USE_DEFAULT" : False,
"NEED_CONFIRM" : False,
"CONDITION" : False },

View File

@@ -1,6 +1,7 @@
class {"mysql::server":
config_hash => {bind_address => "0.0.0.0"}
config_hash => {bind_address => "0.0.0.0",
root_password => "%(CONFIG_MYSQL_PW)s",}
}
class {"keystone::db::mysql":