fuel-upgrade/fuel_upgrade/clients/supervisor_client.py

209 lines
6.6 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2014 Mirantis, 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 httplib
import logging
import os
import socket
import xmlrpclib
from xmlrpclib import Fault
from fuel_upgrade import utils
logger = logging.getLogger(__name__)
class UnixSocketHTTPConnection(httplib.HTTPConnection):
def connect(self):
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(self.host)
class UnixSocketHTTP(httplib.HTTP):
_connection_class = UnixSocketHTTPConnection
class UnixSocketTransport(xmlrpclib.Transport, object):
"""Http transport for UNIX socket
"""
def __init__(self, socket_path):
"""Create object
:params socket_path: path to the socket
"""
self.socket_path = socket_path
super(UnixSocketTransport, self).__init__()
def make_connection(self, host):
return UnixSocketHTTP(self.socket_path)
class SupervisorClient(object):
"""RPC Client for supervisor
"""
templates_dir = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'templates'))
def __init__(self, config, from_version):
"""Create supervisor client
:param config: config object
"""
self.config = config
self.from_version = from_version
self.supervisor_template_path = os.path.join(
self.templates_dir, 'supervisor.conf')
self.supervisor_common_template_path = os.path.join(
self.templates_dir, 'common.conf')
self.supervisor_config_dir = self.get_config_path(
self.config.new_version)
self.previous_supervisor_config_path = self.get_config_path(
self.from_version)
utils.create_dir_if_not_exists(self.supervisor_config_dir)
self.supervisor = self.get_supervisor()
def get_config_path(self, version):
"""Creates path to supervisor config with
specific version
:param version: version of config
:returns: path to supervisor config
"""
return os.path.join(
self.config.supervisor['configs_prefix'], version)
def get_supervisor(self):
"""Returns supervisor rpc object
"""
server = xmlrpclib.Server(
'http://unused_variable',
transport=UnixSocketTransport(
self.config.supervisor['endpoint']))
return server.supervisor
def switch_to_new_configs(self):
"""Switch to new version of configs
for supervisor. Creates symlink on special
directory.
"""
current_cfg_path = self.config.supervisor['current_configs_prefix']
utils.symlink(self.supervisor_config_dir, current_cfg_path)
self.supervisor.reloadConfig()
def switch_to_previous_configs(self):
"""Switch to previous version of fuel
"""
current_cfg_path = self.config.supervisor['current_configs_prefix']
utils.symlink(
self.previous_supervisor_config_path,
current_cfg_path)
self.supervisor.reloadConfig()
def start_all_services(self):
"""Stops all processes
"""
logger.info('Start all services')
self.supervisor.startAllProcesses()
def stop_all_services(self):
"""Stops all processes
"""
logger.info('Stop all services')
self.supervisor.stopAllProcesses()
def restart_and_wait(self):
"""Restart supervisor and wait untill it will be available
"""
logger.info('Restart supervisor')
self.supervisor.restart()
all_processes = utils.wait_for_true(
lambda: self.get_all_processes_safely() is not None,
timeout=self.config.supervisor['restart_timeout'])
logger.debug('List of supervisor processes %s', all_processes)
def start(self, service_name):
"""Start the process under supervisor
:param str service_name: name of supervisor's process
"""
logger.debug('Start supervisor process %s', service_name)
self.supervisor.startProcess(service_name)
def get_all_processes_safely(self):
"""Retrieves list of processes from supervisor,
doesn't raise errors if there is no running
supervisor.
:returns: list of processes in case of success or
None in case of error
"""
try:
return self.supervisor.getAllProcessInfo()
except (IOError, Fault):
return None
def generate_configs(self, services):
"""Generates supervisor configs for services
:param services: list of dicts where
`config_name` - is the name of the config
`service_name` - is the name of the service
`command` - command to run
`autostart` - run the service on supervisor start
"""
logger.info(
'Generate supervisor configs for services %s', services)
for service in services:
self.generate_config(
service['config_name'],
service['service_name'],
service['command'],
autostart=service['autostart'])
def generate_config(self, config_name, service_name,
command, autostart=True):
"""Generates config for each service
:param str config_name: is the name of the config
:param str service_name: is the name of the service
:param str command: command to run
:param bool autostart: run the service on supervisor start
"""
config_path = os.path.join(
self.supervisor_config_dir,
'{0}'.format('{0}.conf'.format(config_name)))
log_path = '/var/log/{0}.log'.format(service_name)
params = {
'service_name': service_name,
'command': command,
'log_path': log_path,
'autostart': 'true' if autostart else 'false'}
utils.render_template_to_file(
self.supervisor_template_path, config_path, params)