Skip to content

Instantly share code, notes, and snippets.

@ryancurrah
Created February 10, 2015 23:39
Show Gist options
  • Save ryancurrah/88a4a7c42cb96d054dc3 to your computer and use it in GitHub Desktop.
Save ryancurrah/88a4a7c42cb96d054dc3 to your computer and use it in GitHub Desktop.
Start cloudify celeryd services on cloudify clients
#!/usr/bin/python
"""
This script will start services found in the INIT_DIR for Ubuntu or Redhat.
The services found can be filtered by using the SERVICE_STARTS_WITH parameter.
Required services will be started before the services found using the list parameter REQUIRED_SERVICES.
"""
from subprocess import Popen, PIPE
import time
import sys
import threading
import signal
import os
import datetime
import multiprocessing as mp
# Public vars
INIT_DIR = '/etc/init.d' # String - No trailing slashes please
SERVICE_STARTS_WITH = 'celeryd-' # String
REQUIRED_SERVICES = [] # List of Strings
# Private vars
_REQUIRED_PYTHON_VERSION = (2, 6)
_OS_FLAVOR = 'redhat' if os.path.isfile('/etc/redhat-release') else \
'ubuntu' if os.path.isfile('/etc/lsb-release') else \
'ubuntu'
_STARTED_MESSAGE = "datetime: {0}, service name: {1}, started: {2}"
_FOUND_SERVICES = []
def main():
# Exit script with error if Python is not correct version
_check_version()
# Get list of services
if SERVICE_STARTS_WITH:
print "\nfinding services that start with '{0}'...".format(SERVICE_STARTS_WITH)
else:
print "\nfinding services..."
_FOUND_SERVICES.extend(_get_files(INIT_DIR, SERVICE_STARTS_WITH))
# If no services found exit and let user know
if not _FOUND_SERVICES and SERVICE_STARTS_WITH:
print "...done no services found starting with '{0}' exiting.\n".format(SERVICE_STARTS_WITH)
sys.exit(0)
elif not _FOUND_SERVICES:
print "...done no services found exiting.\n"
sys.exit(0)
print "...done found {0} services\n".format(len(_FOUND_SERVICES))
# Start required services
print "starting required services..."
start_required_services()
print "...done\n"
# Start found services
print "starting found services..."
async_start_found_services()
print "...done\n"
return
def worker(service):
"""
Async worker/task that starts specified service name
"""
if is_service_running(service):
print _STARTED_MESSAGE.format(get_datetime(), service, "already started")
else:
print _STARTED_MESSAGE.format(get_datetime(), service, start_service(service))
return
def async_start_found_services():
"""
Start found services asynchronously, up to 5 workers maximum
"""
pool = mp.Pool(processes=10)
for service in _FOUND_SERVICES:
pool.apply_async(worker, args=(service,))
pool.close()
pool.join()
return
def start_required_services():
for required_service in REQUIRED_SERVICES:
if os.path.isfile("{0}/{1}".format(INIT_DIR.rstrip('/'), required_service)):
if not is_service_running(required_service):
print _STARTED_MESSAGE.format(get_datetime(), required_service, start_service(required_service))
else:
print _STARTED_MESSAGE.format(get_datetime(), required_service, "already started")
else:
print _STARTED_MESSAGE.format(get_datetime(), required_service, "service not found")
sys.exit(1)
def get_datetime():
"""
Returns a datetime object
"""
return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def is_service_running(service_name):
"""
Checks if service is active returns True for running or False for stopped
"""
# Choose which command to use based on OS FLAVOR, defaults to Ubuntu
if _OS_FLAVOR == 'ubuntu':
command = ['service', service_name, 'status']
elif _OS_FLAVOR == 'redhat':
command = ['service', service_name, 'status']
else:
command = ['service', service_name, 'status']
# Execute!
stdout, stderr, returncode = _execute_command(command, retry_count=2, command_sleep=1, command_timeout=20)
if returncode == 0:
running = True
else:
running = False
return running
def start_service(service_name):
"""
Starts service returns True for started or False for stopped
"""
# Choose which command to use based on OS FLAVOR, defaults to Ubuntu
if _OS_FLAVOR == 'ubuntu':
command = ['service', service_name, 'start']
elif _OS_FLAVOR == 'redhat':
command = ['service', service_name, 'start']
else:
command = ['service', service_name, 'start']
# Execute!
stdout, stderr, returncode = _execute_command(command, retry_count=2, command_sleep=1, command_timeout=20)
if returncode == 0:
started = True
else:
started = False
return started
def _get_files(directory='/etc/init.d', starts_with=''):
"""
Returns filenames as a list
"""
directory = directory.rstrip('/')
filenames = []
for filename in os.listdir(directory):
if os.path.isfile("{0}/{1}".format(directory, filename)):
if starts_with:
if filename.startswith(starts_with):
filenames.append(filename)
else:
filenames.append(filename)
return filenames
def _execute_command(command,
environment=None,
retry_count=0,
command_sleep=0,
command_timeout=0):
"""
:param command: Command and it's parameters as a List of Strings
:param environment: Key value list of environment variables to set
:param retry_count: Integer number of retries that will execute run() again on failure
:param command_sleep: Integer number of seconds to sleep for after executing command
:param command_timeout: Integer number of seconds to wait before killing the run() function
:return: results as Tuple stdout, stderr, returncode
"""
def run():
if command_timeout:
kill_check = threading.Event()
def _kill_process_after_a_timeout(process_id):
os.kill(process_id, signal.SIGTERM)
kill_check.set() # tell the main routine that we had to kill
# use SIGKILL if hard to kill...
return
process = Popen(command, stdout=PIPE, stderr=PIPE, env=environment)
pid = process.pid
watchdog = threading.Timer(command_timeout, _kill_process_after_a_timeout, args=(pid, ))
watchdog.start()
stdout, stderr = process.communicate()
watchdog.cancel() # if it's still waiting to run
returncode = process.returncode
if kill_check.isSet():
returncode = 1
stdout = "executing {0} took to long and timedout. " \
"the timeout limit is {1} seconds".format(' '.join(command), command_timeout)
stderr = stdout
else:
process = Popen(command, stdout=PIPE, stderr=PIPE, env=environment)
stdout, stderr = process.communicate()
returncode = process.returncode
return stdout, stderr, returncode
retry_count += 1 # number of retries plus the initial execution
stdout = None
stderr = None
returncode = None
for retry in range(retry_count):
stdout, stderr, returncode = run()
time.sleep(command_sleep)
if returncode == 0:
break
return stdout, stderr, returncode
def _check_version():
"""
Exits out of program if running python version out of date
"""
req_version = _REQUIRED_PYTHON_VERSION
cur_version = sys.version_info
if not cur_version >= req_version:
print "your Python interpreter is too old. Please consider upgrading. " \
"this script requires {0} or higher.".format(req_version)
sys.exit(1)
return
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment