174 lines
6.6 KiB
Python
174 lines
6.6 KiB
Python
# Copyright 2012 IBM Corp.
|
|
# Copyright (c) AT&T Labs Inc. 2012 Yun Mao <yunmao@gmail.com>
|
|
#
|
|
# 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.
|
|
|
|
"""Define APIs for the servicegroup access."""
|
|
|
|
import random
|
|
|
|
from oslo.config import cfg
|
|
from oslo.utils import importutils
|
|
|
|
from nova.i18n import _
|
|
from nova.openstack.common import log as logging
|
|
from nova import utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
_default_driver = 'db'
|
|
servicegroup_driver_opt = cfg.StrOpt('servicegroup_driver',
|
|
default=_default_driver,
|
|
help='The driver for servicegroup '
|
|
'service (valid options are: '
|
|
'db, zk, mc)')
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_opt(servicegroup_driver_opt)
|
|
|
|
# NOTE(geekinutah): By default drivers wait 5 seconds before reporting
|
|
INITIAL_REPORTING_DELAY = 5
|
|
|
|
|
|
class API(object):
|
|
|
|
_driver = None
|
|
_driver_name_class_mapping = {
|
|
'db': 'nova.servicegroup.drivers.db.DbDriver',
|
|
'zk': 'nova.servicegroup.drivers.zk.ZooKeeperDriver',
|
|
'mc': 'nova.servicegroup.drivers.mc.MemcachedDriver'
|
|
}
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
'''Create an instance of the servicegroup API.
|
|
|
|
args and kwargs are passed down to the servicegroup driver when it gets
|
|
created. No args currently exist, though. Valid kwargs are:
|
|
|
|
db_allowed - Boolean. False if direct db access is not allowed and
|
|
alternative data access (conductor) should be used
|
|
instead.
|
|
'''
|
|
|
|
if not cls._driver:
|
|
LOG.debug('ServiceGroup driver defined as an instance of %s',
|
|
str(CONF.servicegroup_driver))
|
|
driver_name = CONF.servicegroup_driver
|
|
try:
|
|
driver_class = cls._driver_name_class_mapping[driver_name]
|
|
except KeyError:
|
|
raise TypeError(_("unknown ServiceGroup driver name: %s")
|
|
% driver_name)
|
|
cls._driver = importutils.import_object(driver_class,
|
|
*args, **kwargs)
|
|
utils.check_isinstance(cls._driver, ServiceGroupDriver)
|
|
# we don't have to check that cls._driver is not NONE,
|
|
# check_isinstance does it
|
|
return super(API, cls).__new__(cls)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.basic_config_check()
|
|
|
|
def basic_config_check(self):
|
|
"""Perform basic config check."""
|
|
# Make sure report interval is less than service down time
|
|
report_interval = CONF.report_interval
|
|
if CONF.service_down_time <= report_interval:
|
|
new_service_down_time = int(report_interval * 2.5)
|
|
LOG.warn(_("Report interval must be less than service down "
|
|
"time. Current config: <service_down_time: "
|
|
"%(service_down_time)s, report_interval: "
|
|
"%(report_interval)s>. Setting service_down_time to: "
|
|
"%(new_service_down_time)s"),
|
|
{'service_down_time': CONF.service_down_time,
|
|
'report_interval': report_interval,
|
|
'new_service_down_time': new_service_down_time})
|
|
CONF.set_override('service_down_time', new_service_down_time)
|
|
|
|
def join(self, member_id, group_id, service=None):
|
|
"""Add a new member to the ServiceGroup
|
|
|
|
@param member_id: the joined member ID
|
|
@param group_id: the group name, of the joined member
|
|
@param service: the parameter can be used for notifications about
|
|
disconnect mode and update some internals
|
|
"""
|
|
|
|
LOG.debug('Join new ServiceGroup member %(member_id)s to the '
|
|
'%(group_id)s group, service = %(service)s',
|
|
{'member_id': member_id,
|
|
'group_id': group_id,
|
|
'service': service})
|
|
return self._driver.join(member_id, group_id, service)
|
|
|
|
def service_is_up(self, member):
|
|
"""Check if the given member is up."""
|
|
# NOTE(johngarbutt) no logging in this method,
|
|
# so this doesn't slow down the scheduler
|
|
return self._driver.is_up(member)
|
|
|
|
def leave(self, member_id, group_id):
|
|
"""Explicitly remove the given member from the ServiceGroup
|
|
monitoring.
|
|
"""
|
|
LOG.debug('Explicitly remove the given member %(member_id)s from the'
|
|
'%(group_id)s group monitoring',
|
|
{'member_id': member_id, 'group_id': group_id})
|
|
return self._driver.leave(member_id, group_id)
|
|
|
|
def get_all(self, group_id):
|
|
"""Returns ALL members of the given group."""
|
|
LOG.debug('Returns ALL members of the [%s] '
|
|
'ServiceGroup', group_id)
|
|
return self._driver.get_all(group_id)
|
|
|
|
def get_one(self, group_id):
|
|
"""Returns one member of the given group. The strategy to select
|
|
the member is decided by the driver (e.g. random or round-robin).
|
|
"""
|
|
LOG.debug('Returns one member of the [%s] group', group_id)
|
|
return self._driver.get_one(group_id)
|
|
|
|
|
|
class ServiceGroupDriver(object):
|
|
"""Base class for ServiceGroup drivers."""
|
|
|
|
def join(self, member_id, group_id, service=None):
|
|
"""Join the given service with its group."""
|
|
raise NotImplementedError()
|
|
|
|
def is_up(self, member):
|
|
"""Check whether the given member is up."""
|
|
raise NotImplementedError()
|
|
|
|
def leave(self, member_id, group_id):
|
|
"""Remove the given member from the ServiceGroup monitoring."""
|
|
raise NotImplementedError()
|
|
|
|
def get_all(self, group_id):
|
|
"""Returns ALL members of the given group."""
|
|
raise NotImplementedError()
|
|
|
|
def get_one(self, group_id):
|
|
"""The default behavior of get_one is to randomly pick one from
|
|
the result of get_all(). This is likely to be overridden in the
|
|
actual driver implementation.
|
|
"""
|
|
members = self.get_all(group_id)
|
|
if members is None:
|
|
return None
|
|
length = len(members)
|
|
if length == 0:
|
|
return None
|
|
return random.choice(members)
|