[Erp5-report] r36109 luke - /erp5/trunk/utils/erp5.timmy/src/erp5/timmy/timmy.py
nobody at svn.erp5.org
nobody at svn.erp5.org
Tue Jun 8 18:26:25 CEST 2010
Author: luke
Date: Tue Jun 8 18:26:25 2010
New Revision: 36109
URL: http://svn.erp5.org?rev=36109&view=rev
Log:
- start cleanup of timmy
Modified:
erp5/trunk/utils/erp5.timmy/src/erp5/timmy/timmy.py
Modified: erp5/trunk/utils/erp5.timmy/src/erp5/timmy/timmy.py
URL: http://svn.erp5.org/erp5/trunk/utils/erp5.timmy/src/erp5/timmy/timmy.py?rev=36109&r1=36108&r2=36109&view=diff
==============================================================================
--- erp5/trunk/utils/erp5.timmy/src/erp5/timmy/timmy.py [utf8] (original)
+++ erp5/trunk/utils/erp5.timmy/src/erp5/timmy/timmy.py [utf8] Tue Jun 8 18:26:25 2010
@@ -36,187 +36,6 @@
new_uid = generateServerKey()
file(key_file, 'w').write(new_uid)
return new_uid
-
-def parseOptions():
- parser = OptionParser()
- parser.add_option("-k", "--key-file",
- help="File with server key")
-
- parser.add_option("-s", "--server-url",
- help="URL of provisioning server")
-
- parser.add_option("-b", "--base-profile",
- help="Base profile")
-
- parser.add_option("-t", "--template-directory",
- help="Directory with templates")
-
- parser.add_option("-o", "--main-output",
- help="Main profile output, which will be run by buildout")
-
- parser.add_option("-d", "--instances-directory",
- help="Instances profiles output, must be existing directory")
-
- parser.add_option("-r", "--buildout-binary",
- help="Buildout binary to run")
-
- parser.add_option("-p", "--pid-file",
- help="Lock file with the pid file.")
-
- parser.add_option("-l", "--log-file",
- help="Log file.")
-
- parser.set_defaults(buildout_offline=False)
- parser.add_option("-N", "--buildout-offline", action="store_true",
- help="Run buildout in offline mode.")
-
- (options, args) = parser.parse_args()
- required_option_list = [
- 'base_profile',
- 'buildout_binary',
- 'instances_directory',
- 'key_file',
- 'main_output',
- 'server_url',
- 'pid_file'
- ]
- missing_required_option_list = [o for o in required_option_list \
- if not getattr(options, o, None)]
- if len(missing_required_option_list):
- parser.error('Required options are missing: %s' % ', '.join(
- missing_required_option_list))
-
- for filepath in options.base_profile,:
- if not os.path.exists(filepath):
- raise ValueError('Cannot find "%s"' % os.path.abspath(filepath))
- if not os.path.exists(options.instances_directory):
- os.mkdir(options.instances_directory)
- elif not os.path.isdir(options.instances_directory):
- raise ValueError('File %s is not a directory' %
- os.path.abspath(options.instances_directory))
- return options, args
-
-def setRunning(value, pid_file):
- if value:
- if os.path.exists(pid_file):
- # Pid file is present
- logging.warning('Timmy already have the pid file %s' % pid_file)
- pid = open(pid_file, 'r').readline()
- # XXX This could use psutil library.
- if os.path.exists("/proc/%s" % pid):
- # In case process is present, ignore.
- logging.critical('A Timmy process is running with pid %s' % pid)
- sys.exit(1)
- # Start new process
- write_pid(pid_file)
- else:
- os.remove(pid_file)
-
-def write_pid(pid_file):
- pid = os.getpid()
- try:
- f = open(pid_file, 'w')
- f.write('%s' % pid)
- f.close()
- except (IOError, OSError):
- logging.critical('Timmy could not write pidfile %s' % pid_file)
- raise
-
-def findTemplate(template_directory_list, template_name):
- for template_directory in template_directory_list:
- path = os.path.join(template_directory, template_name)
- if os.path.isfile(path):
- logging.debug('Found template %r' % path)
- return path
- return None
-
-def updateBaseProfile(template_directory_list, file_output, base_profile,
- instances_directory, instance_dict_list):
- # TODO:
- # * cleanup in case of problem
- # * use safe update of output file
- template_data = ''.join(file(findTemplate(template_directory_list,
- 'main-template.cfg')).readlines())
- template = PercentTemplate(template_data)
- replacement_dict = {
- 'BASE_PROFILE': base_profile,
- 'INSTANCE_PROFILE_LIST': [],
- 'INSTANCE_PART_LIST': []
- }
- for instance in [q for q in instance_dict_list if q['TYPE'] != 'Zope Instance']:
- profile_path = os.path.join(instances_directory,
- '%s.cfg' % instance['ID'])
- if not os.path.exists(profile_path):
- logging.warning('Profile %r not generated, ignoring' % profile_path)
- continue
- replacement_dict['INSTANCE_PROFILE_LIST'].append('%s/%s.cfg' % (
- instances_directory, instance['ID']))
- replacement_dict['INSTANCE_PART_LIST'].append(instance['ID'])
-
- for instance in [q for q in instance_dict_list if q['TYPE'] == 'Zope Instance']:
- profile_path = os.path.join(instances_directory,
- '%s.cfg' % instance['ID'])
- if not os.path.exists(profile_path):
- logging.warning('Profile %r not generated' % profile_path)
- continue
- replacement_dict['INSTANCE_PROFILE_LIST'].append('%s/%s.cfg' % (
- instances_directory, instance['ID']))
- replacement_dict['INSTANCE_PART_LIST'].append(instance['ID'])
-
- replacement_dict['INSTANCE_PROFILE_LIST'] = '\n '.join(
- replacement_dict['INSTANCE_PROFILE_LIST'])
- replacement_dict['INSTANCE_PART_LIST'] = '\n '.join(
- replacement_dict['INSTANCE_PART_LIST'])
- out = file(file_output, 'w')
- out.write(template.substitute(replacement_dict))
- out.close()
-
-def updateInstanceProfiles(template_directory_list, output_directory,
- instance_dict_list):
- for instance in instance_dict_list:
- template_name = '%s-template.cfg' % instance['TYPE'].lower()\
- .replace(' ','-')
- template_path = findTemplate(template_directory_list, template_name)
- if template_path is None:
- logging.warning('Template %r for %s not found, ignoring' % (template_name,
- instance['TYPE']))
- continue
- template_data = ''.join(file(template_path).readlines())
-
- template = PercentTemplate(template_data)
- if 'BT5_LIST' in instance:
- instance['BT5_LIST'] = '\n '.join(instance['BT5_LIST'])
- if 'IP_ADDRESS_LIST' in instance:
- if instance['IP_ADDRESS_LIST']:
- instance['IP_ADDRESS'] = instance['IP_ADDRESS_LIST'][0]
- out = file(os.path.join(output_directory, '%s.cfg' % instance['ID']), 'w')
- out.write(template.substitute(instance))
- out.close()
-
-def runBuildout(buildout, profile, offline):
- invoke_list = [buildout]
- if offline:
- invoke_list.append('-N')
- invoke_list.extend(['-c', profile, '-t', '5'])
- logging.info('invoking %s' % ' '.join(invoke_list))
- popen = subprocess.Popen([buildout, '-c', profile],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (result_std, result_err) = popen.communicate()
- # TODO: check that site is accesible in Data.fs, we cannot belive in
- # Popen.returncode, as subprocesses of subprocesses are not handled
- # properly
-
- # TODO: parse result_std and result_err
-
- if popen.returncode == 0:
- log_method = logging.info
- else:
- log_method = logging.error
- log_method('Buildout finished with bad status code (%s)' % \
- popen.returncode)
- log_method('Standard output:\n%s' % result_std)
- log_method('Error output:\n%s' % result_err)
- return popen.returncode, result_std, result_err
class Partition(object):
# generic
@@ -580,199 +399,387 @@
print 'Server key located at: %s' % os.path.abspath(options.key_file)
print 'Key: %s' % key
-def getTemplateDirectoryList(user_template_directory):
- """Returns list of directories, in which there might be templates"""
- template_directory_list = []
- if pkg_resources.resource_isdir(__name__, 'template'):
- template_directory = pkg_resources.resource_filename(__name__, "template")
- template_directory_list.append(template_directory)
- logging.info('Using %r as fallback directory with templates' %
- template_directory)
-
- if user_template_directory is not None:
- if os.path.isdir(user_template_directory):
- template_directory = os.path.abspath(user_template_directory)
+class Timmy(object):
+ def __init__(self):
+ socket.setdefaulttimeout(30.0)
+ self.options = self.parseOptions()[0]
+ logging_kw = dict(level=logging.INFO,
+ format='%(asctime)s:%(levelname)s:%(name)s:%(message)s')
+ if self.options.log_file is not None:
+ logging_kw['filename'] = options.log_file
+ logging.basicConfig(**logging_kw)
+ self.time_begin = time.time()
+ logging.info('[%s] Timmy started' % os.getpid())
+ self.options.template_directory_list = self.getTemplateDirectoryList(self.options.template_directory)
+
+ def getTemplateDirectoryList(self, user_template_directory):
+ """Returns list of directories, in which there might be templates"""
+ template_directory_list = []
+ if pkg_resources.resource_isdir(__name__, 'template'):
+ template_directory = pkg_resources.resource_filename(__name__, "template")
template_directory_list.append(template_directory)
- logging.info('Using %r as default directory with templates' %
+ logging.info('Using %r as fallback directory with templates' %
template_directory)
- else:
- logging.warning('User template %r is not a directory' %
- template_directory)
- if len(template_directory_list) == 0:
- logging.warning('No templates were found, some functionality will be not available')
- template_directory_list.reverse()
- return template_directory_list
-
-def run():
- socket.setdefaulttimeout(30.0)
- (options, args) = parseOptions()
- logging_kw = dict(level=logging.INFO,
- format='%(asctime)s:%(levelname)s:%(name)s:%(message)s')
- if options.log_file is not None:
- logging_kw['filename'] = options.log_file
- logging.basicConfig(**logging_kw)
- time_begin = time.time()
- logging.info('[%s] Timmy started' % os.getpid())
- options.template_directory_list = getTemplateDirectoryList(options.template_directory)
- try:
- setRunning(True, options.pid_file)
- except:
- # XXX-Luke: If possible it would be nice to send such issue to
- # master server
- logging.error('Issue during setting pid file %s %s' % sys.exc_info()[:2])
- raise
- try:
+
+ if user_template_directory is not None:
+ if os.path.isdir(user_template_directory):
+ template_directory = os.path.abspath(user_template_directory)
+ template_directory_list.append(template_directory)
+ logging.info('Using %r as default directory with templates' %
+ template_directory)
+ else:
+ logging.warning('User template %r is not a directory' %
+ template_directory)
+ if len(template_directory_list) == 0:
+ logging.warning('No templates were found, some functionality will be not available')
+ template_directory_list.reverse()
+ return template_directory_list
+
+ def run(self):
+ try:
+ self.setRunning(True, self.options.pid_file)
+ except:
+ # XXX-Luke: If possible it would be nice to send such issue to
+ # master server
+ logging.error('Issue during setting pid file %s %s' % sys.exc_info()[:2])
+ raise
try:
try:
- server = XMLRPCServer(options.server_url,
- getServerKey(options.key_file))
- partition_dict_list = server.call('getComputerConfigurationDictList')
- except socket.error, e:
- logging.error('Unable to connect to remote server, verify if the URL is'
- ' accessible.')
- sys.exit(1)
- except xmlrpclib.Fault, e:
- logging.error('Error found on server side, unable to continue, failed:'
- ' %s.' % e.faultString)
- sys.exit(1)
-
- computer_id = getServerKey(options.key_file)
- server.call('updatePartitionState', computer_id, 'reportStarted',
- 'timmy is running on computer')
- supervisor_id = computer_id
- supervisor_list = [q for q in partition_dict_list if q['TYPE'] == \
- 'Supervisor Server']
- if len(supervisor_list) > 0:
- supervisor_id = supervisor_list[0]['PARTITION_ID']
-
- # prepare - run supervisor
- try:
- supervisord_popen = subprocess.Popen([SUPERVISORD],
+ try:
+ server = XMLRPCServer(self.options.server_url,
+ getServerKey(self.options.key_file))
+ partition_dict_list = server.call('getComputerConfigurationDictList')
+ except socket.error, e:
+ logging.error('Unable to connect to remote server, verify if the URL is'
+ ' accessible.')
+ sys.exit(1)
+ except xmlrpclib.Fault, e:
+ logging.error('Error found on server side, unable to continue, failed:'
+ ' %s.' % e.faultString)
+ sys.exit(1)
+
+ computer_id = getServerKey(self.options.key_file)
+ server.call('updatePartitionState', computer_id, 'reportStarted',
+ 'timmy is running on computer')
+ supervisor_id = computer_id
+ supervisor_list = [q for q in partition_dict_list if q['TYPE'] == \
+ 'Supervisor Server']
+ if len(supervisor_list) > 0:
+ supervisor_id = supervisor_list[0]['PARTITION_ID']
+
+ # prepare - run supervisor
+ try:
+ supervisord_popen = subprocess.Popen([SUPERVISORD],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (result_std, result_err) = supervisord_popen.communicate()
+ except:
+ server.call('updatePartitionState', supervisor_id, 'reportError',
+ 'Unsupported issue while trying to start supervisord: %s:%s' % (
+ str(sys.exc_info()[0]), str(sys.exc_info()[1])))
+ raise
+
+ if supervisord_popen.returncode == 0:
+ log_message = 'Supervisord started with: stdout = %r stderr = %r' % (
+ result_std, result_err)
+ server.call('updatePartitionState', supervisor_id, 'reportStarted',
+ log_message)
+ logging.info(log_message)
+ else:
+ if "Another program is already listening" in result_err:
+ logging.info('Supervisord already running: stdout = %r stderr = '
+ '%r' % (result_std, result_err))
+ else:
+ log_message = 'Supervisord unknown problem: stdout = %r stderr = %r' \
+ % (result_std, result_err)
+ server.call('updatePartitionState', supervisor_id, 'reportError',
+ log_message)
+ logging.info(log_message)
+
+ # 1a pass - instance profiles
+ try:
+ self.updateInstanceProfiles(self.options.template_directory_list,
+ self.options.instances_directory, partition_dict_list)
+ except:
+ server.call('updatePartitionState', computer_id, 'reportError',
+ 'Unexpected issue while updating instance profiles: %s:%s' % (
+ str(sys.exc_info()[0]), str(sys.exc_info()[1])))
+ raise
+ # 1b pass - main profile
+ try:
+ self.updateBaseProfile(self.options.template_directory_list, self.options.main_output,
+ self.options.base_profile, self.options.instances_directory,
+ partition_dict_list)
+ except:
+ server.call('updatePartitionState', computer_id, 'reportError',
+ 'Unexpected issue while updating base profile: %s:%s' % (
+ str(sys.exc_info()[0]), str(sys.exc_info()[1])))
+ raise
+ # 2 pass - run buildout
+ try:
+ return_code, result_std, result_err = self.runBuildout(
+ self.options.buildout_binary, self.options.main_output,
+ self.options.buildout_offline)
+ if return_code != 0:
+ server.call('updatePartitionState', computer_id, 'reportError',
+ 'Buildout finished with bad status code (%s). Stdout = "%s", stde'
+ 'rr = "%s"' % (return_code, result_std, result_err))
+ except:
+ server.call('updatePartitionState', computer_id, 'reportError',
+ 'Unexpected issue while running buildout: %s:%s' % (
+ str(sys.exc_info()[0]), str(sys.exc_info()[1])))
+ raise
+
+ # force supervisor to reload its configuration
+ supervisorctl_popen = subprocess.Popen([SUPERVISORCTL, 'update'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (result_std, result_err) = supervisord_popen.communicate()
- except:
- server.call('updatePartitionState', supervisor_id, 'reportError',
- 'Unsupported issue while trying to start supervisord: %s:%s' % (
- str(sys.exc_info()[0]), str(sys.exc_info()[1])))
- raise
-
- if supervisord_popen.returncode == 0:
- log_message = 'Supervisord started with: stdout = %r stderr = %r' % (
- result_std, result_err)
- server.call('updatePartitionState', supervisor_id, 'reportStarted',
- log_message)
- logging.info(log_message)
- else:
- if "Another program is already listening" in result_err:
- logging.info('Supervisord already running: stdout = %r stderr = '
- '%r' % (result_std, result_err))
+ (result_std, result_err) = supervisorctl_popen.communicate()
+ if supervisorctl_popen.returncode == 0:
+ log_message = 'Supervisorctl updated with: stdout = %r stderr = %r' % (
+ result_std, result_err)
+ server.call('updatePartitionState', supervisor_id, 'reportStarted',
+ log_message)
+ logging.info(log_message)
else:
- log_message = 'Supervisord unknown problem: stdout = %r stderr = %r' \
- % (result_std, result_err)
+ log_message = 'Supervisorctl issue during update: stdout = %r stderr ='\
+ ' %r' % (result_std, result_err)
server.call('updatePartitionState', supervisor_id, 'reportError',
log_message)
- logging.info(log_message)
-
- # 1a pass - instance profiles
- try:
- updateInstanceProfiles(options.template_directory_list,
- options.instances_directory, partition_dict_list)
- except:
- server.call('updatePartitionState', computer_id, 'reportError',
- 'Unexpected issue while updating instance profiles: %s:%s' % (
- str(sys.exc_info()[0]), str(sys.exc_info()[1])))
+ logging.error(log_message)
+
+ # do start all of supervisor controlled programs
+ # it is noop in case if all is running
+ # it forces to start problematic services (FATAL state)
+ supervisorctl_popen = subprocess.Popen([SUPERVISORCTL, 'start', 'all'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (result_std, result_err) = supervisorctl_popen.communicate()
+ if supervisorctl_popen.returncode != 0:
+ log_message = 'Supervisorctl issue during start all: stdout = %r std'\
+ 'err = %r' % (result_std, result_err)
+ server.call('updatePartitionState', supervisor_id, 'reportError',
+ log_message)
+ logging.error(log_message)
+ elif len(result_std) > 0 or len(result_err) > 0:
+ # emit log only in case if something important was done by supervisor
+ # no need to pollute master server, as this is only local server hack
+ logging.info('Supervisorctl start all with: stdout = %r stderr = %r' % (
+ result_std, result_err))
+
+
+ # 3 pass - manage instances
+ # XXX-Luke: To be moved to proper recipe
+ updated_partition_list = []
+ helper = Helper()
+ for partition_dict in partition_dict_list:
+ # install
+ # stop
+ # switch to special management
+ # start
+ partition = Partition(partition_dict)
+ switcher_dict = dict(
+ start = 'manageStart',
+ stop = 'manageStop',
+ nothing = 'manageNothing',
+ install = 'manageInstall',
+ )
+ action = getattr(helper, switcher_dict[partition_dict['ACTION']])
+ action(partition, server)
+ except xmlrpclib.Fault, e:
+ logging.error('Unexpected error in xml-rpc communication, unable to co'
+ 'ntinue, failed: %s.' % e.faultString)
raise
- # 1b pass - main profile
- try:
- updateBaseProfile(options.template_directory_list, options.main_output,
- options.base_profile, options.instances_directory,
- partition_dict_list)
- except:
- server.call('updatePartitionState', computer_id, 'reportError',
- 'Unexpected issue while updating base profile: %s:%s' % (
- str(sys.exc_info()[0]), str(sys.exc_info()[1])))
+ except socket.sslerror, e:
+ logging.error('Unexpected error in socket communication, unable to co'
+ 'ntinue, failed: %s.' % e)
raise
- # 2 pass - run buildout
- try:
- return_code, result_std, result_err = runBuildout(
- options.buildout_binary, options.main_output,
- options.buildout_offline)
- if return_code != 0:
- server.call('updatePartitionState', computer_id, 'reportError',
- 'Buildout finished with bad status code (%s). Stdout = "%s", stde'
- 'rr = "%s"' % (return_code, result_std, result_err))
- except:
- server.call('updatePartitionState', computer_id, 'reportError',
- 'Unexpected issue while running buildout: %s:%s' % (
- str(sys.exc_info()[0]), str(sys.exc_info()[1])))
- raise
-
- # force supervisor to reload its configuration
- supervisorctl_popen = subprocess.Popen([SUPERVISORCTL, 'update'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (result_std, result_err) = supervisorctl_popen.communicate()
- if supervisorctl_popen.returncode == 0:
- log_message = 'Supervisorctl updated with: stdout = %r stderr = %r' % (
- result_std, result_err)
- server.call('updatePartitionState', supervisor_id, 'reportStarted',
- log_message)
- logging.info(log_message)
- else:
- log_message = 'Supervisorctl issue during update: stdout = %r stderr ='\
- ' %r' % (result_std, result_err)
- server.call('updatePartitionState', supervisor_id, 'reportError',
- log_message)
- logging.error(log_message)
-
- # do start all of supervisor controlled programs
- # it is noop in case if all is running
- # it forces to start problematic services (FATAL state)
- supervisorctl_popen = subprocess.Popen([SUPERVISORCTL, 'start', 'all'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- (result_std, result_err) = supervisorctl_popen.communicate()
- if supervisorctl_popen.returncode != 0:
- log_message = 'Supervisorctl issue during start all: stdout = %r std'\
- 'err = %r' % (result_std, result_err)
- server.call('updatePartitionState', supervisor_id, 'reportError',
- log_message)
- logging.error(log_message)
- elif len(result_std) > 0 or len(result_err) > 0:
- # emit log only in case if something important was done by supervisor
- # no need to pollute master server, as this is only local server hack
- logging.info('Supervisorctl start all with: stdout = %r stderr = %r' % (
- result_std, result_err))
-
-
- # 3 pass - manage instances
- # XXX-Luke: To be moved to proper recipe
- updated_partition_list = []
- helper = Helper()
- for partition_dict in partition_dict_list:
- # install
- # stop
- # switch to special management
- # start
- partition = Partition(partition_dict)
- switcher_dict = dict(
- start = 'manageStart',
- stop = 'manageStop',
- nothing = 'manageNothing',
- install = 'manageInstall',
- )
- action = getattr(helper, switcher_dict[partition_dict['ACTION']])
- action(partition, server)
- except xmlrpclib.Fault, e:
- logging.error('Unexpected error in xml-rpc communication, unable to co'
- 'ntinue, failed: %s.' % e.faultString)
+ finally:
+ self.setRunning(False, self.options.pid_file)
+ logging.info('[%s] Timmy finished, invocation time: %.3fs' % (os.getpid(),
+ time.time() - self.time_begin))
+
+ def runBuildout(self, buildout, profile, offline):
+ invoke_list = [buildout]
+ if offline:
+ invoke_list.append('-N')
+ invoke_list.extend(['-c', profile, '-t', '5'])
+ logging.info('invoking %s' % ' '.join(invoke_list))
+ popen = subprocess.Popen([buildout, '-c', profile],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (result_std, result_err) = popen.communicate()
+ # TODO: check that site is accesible in Data.fs, we cannot belive in
+ # Popen.returncode, as subprocesses of subprocesses are not handled
+ # properly
+
+ # TODO: parse result_std and result_err
+
+ if popen.returncode == 0:
+ log_method = logging.info
+ else:
+ log_method = logging.error
+ log_method('Buildout finished with bad status code (%s)' % \
+ popen.returncode)
+ log_method('Standard output:\n%s' % result_std)
+ log_method('Error output:\n%s' % result_err)
+ return popen.returncode, result_std, result_err
+
+ def updateInstanceProfiles(self, template_directory_list, output_directory,
+ instance_dict_list):
+ for instance in instance_dict_list:
+ template_name = '%s-template.cfg' % instance['TYPE'].lower()\
+ .replace(' ','-')
+ template_path = self.findTemplate(template_directory_list, template_name)
+ if template_path is None:
+ logging.warning('Template %r for %s not found, ignoring' % (template_name,
+ instance['TYPE']))
+ continue
+ template_data = ''.join(file(template_path).readlines())
+
+ template = PercentTemplate(template_data)
+ if 'BT5_LIST' in instance:
+ instance['BT5_LIST'] = '\n '.join(instance['BT5_LIST'])
+ if 'IP_ADDRESS_LIST' in instance:
+ if instance['IP_ADDRESS_LIST']:
+ instance['IP_ADDRESS'] = instance['IP_ADDRESS_LIST'][0]
+ out = file(os.path.join(output_directory, '%s.cfg' % instance['ID']), 'w')
+ out.write(template.substitute(instance))
+ out.close()
+
+ def findTemplate(self, template_directory_list, template_name):
+ for template_directory in template_directory_list:
+ path = os.path.join(template_directory, template_name)
+ if os.path.isfile(path):
+ logging.debug('Found template %r' % path)
+ return path
+ return None
+
+ def updateBaseProfile(self, template_directory_list, file_output, base_profile,
+ instances_directory, instance_dict_list):
+ # TODO:
+ # * cleanup in case of problem
+ # * use safe update of output file
+ template_data = ''.join(file(self.findTemplate(template_directory_list,
+ 'main-template.cfg')).readlines())
+ template = PercentTemplate(template_data)
+ replacement_dict = {
+ 'BASE_PROFILE': base_profile,
+ 'INSTANCE_PROFILE_LIST': [],
+ 'INSTANCE_PART_LIST': []
+ }
+ for instance in [q for q in instance_dict_list if q['TYPE'] != 'Zope Instance']:
+ profile_path = os.path.join(instances_directory,
+ '%s.cfg' % instance['ID'])
+ if not os.path.exists(profile_path):
+ logging.warning('Profile %r not generated, ignoring' % profile_path)
+ continue
+ replacement_dict['INSTANCE_PROFILE_LIST'].append('%s/%s.cfg' % (
+ instances_directory, instance['ID']))
+ replacement_dict['INSTANCE_PART_LIST'].append(instance['ID'])
+
+ for instance in [q for q in instance_dict_list if q['TYPE'] == 'Zope Instance']:
+ profile_path = os.path.join(instances_directory,
+ '%s.cfg' % instance['ID'])
+ if not os.path.exists(profile_path):
+ logging.warning('Profile %r not generated' % profile_path)
+ continue
+ replacement_dict['INSTANCE_PROFILE_LIST'].append('%s/%s.cfg' % (
+ instances_directory, instance['ID']))
+ replacement_dict['INSTANCE_PART_LIST'].append(instance['ID'])
+
+ replacement_dict['INSTANCE_PROFILE_LIST'] = '\n '.join(
+ replacement_dict['INSTANCE_PROFILE_LIST'])
+ replacement_dict['INSTANCE_PART_LIST'] = '\n '.join(
+ replacement_dict['INSTANCE_PART_LIST'])
+ out = file(file_output, 'w')
+ out.write(template.substitute(replacement_dict))
+ out.close()
+
+ def setRunning(self, value, pid_file):
+ if value:
+ if os.path.exists(pid_file):
+ # Pid file is present
+ logging.warning('Timmy already have the pid file %s' % pid_file)
+ pid = open(pid_file, 'r').readline()
+ # XXX This could use psutil library.
+ if os.path.exists("/proc/%s" % pid):
+ # In case process is present, ignore.
+ logging.critical('A Timmy process is running with pid %s' % pid)
+ sys.exit(1)
+ # Start new process
+ self.write_pid(pid_file)
+ else:
+ os.remove(pid_file)
+
+ def write_pid(self, pid_file):
+ pid = os.getpid()
+ try:
+ f = open(pid_file, 'w')
+ f.write('%s' % pid)
+ f.close()
+ except (IOError, OSError):
+ logging.critical('Timmy could not write pidfile %s' % pid_file)
raise
- except socket.sslerror, e:
- logging.error('Unexpected error in socket communication, unable to co'
- 'ntinue, failed: %s.' % e.faultString)
- raise
- finally:
- setRunning(False, options.pid_file)
- logging.info('[%s] Timmy finished, invocation time: %.3fs' % (os.getpid(),
- time.time() - time_begin))
+
+ def parseOptions(self):
+ parser = OptionParser()
+ parser.add_option("-k", "--key-file",
+ help="File with server key")
+
+ parser.add_option("-s", "--server-url",
+ help="URL of provisioning server")
+
+ parser.add_option("-b", "--base-profile",
+ help="Base profile")
+
+ parser.add_option("-t", "--template-directory",
+ help="Directory with templates")
+
+ parser.add_option("-o", "--main-output",
+ help="Main profile output, which will be run by buildout")
+
+ parser.add_option("-d", "--instances-directory",
+ help="Instances profiles output, must be existing directory")
+
+ parser.add_option("-r", "--buildout-binary",
+ help="Buildout binary to run")
+
+ parser.add_option("-p", "--pid-file",
+ help="Lock file with the pid file.")
+
+ parser.add_option("-l", "--log-file",
+ help="Log file.")
+
+ parser.set_defaults(buildout_offline=False)
+ parser.add_option("-N", "--buildout-offline", action="store_true",
+ help="Run buildout in offline mode.")
+
+ (options, args) = parser.parse_args()
+ required_option_list = [
+ 'base_profile',
+ 'buildout_binary',
+ 'instances_directory',
+ 'key_file',
+ 'main_output',
+ 'server_url',
+ 'pid_file'
+ ]
+ missing_required_option_list = [o for o in required_option_list \
+ if not getattr(options, o, None)]
+ if len(missing_required_option_list):
+ parser.error('Required options are missing: %s' % ', '.join(
+ missing_required_option_list))
+
+ for filepath in options.base_profile,:
+ if not os.path.exists(filepath):
+ raise ValueError('Cannot find "%s"' % os.path.abspath(filepath))
+ if not os.path.exists(options.instances_directory):
+ os.mkdir(options.instances_directory)
+ elif not os.path.isdir(options.instances_directory):
+ raise ValueError('File %s is not a directory' %
+ os.path.abspath(options.instances_directory))
+ return options, args
+
+
+def run():
+ return Timmy().run()
if __name__ == '__main__':
run()
More information about the Erp5-report
mailing list