Coverage for nova/servicegroup/drivers/mc.py: 80%
46 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-17 15:08 +0000
1# Service heartbeat driver using Memcached
2# Copyright (c) 2013 Akira Yoshiyama <akirayoshiyama at gmail dot com>
3#
4# This is derived from nova/servicegroup/drivers/db.py.
5# Copyright 2012 IBM Corp.
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16# implied.
17# See the License for the specific language governing permissions and
18# limitations under the License.
20import iso8601
21from oslo_log import log as logging
22from oslo_utils import timeutils
24from nova import cache_utils
25import nova.conf
26from nova.i18n import _
27from nova.servicegroup import api
28from nova.servicegroup.drivers import base
31CONF = nova.conf.CONF
34LOG = logging.getLogger(__name__)
37class MemcachedDriver(base.Driver):
39 def __init__(self, *args, **kwargs):
40 self.mc = cache_utils.get_memcached_client(
41 expiration_time=CONF.service_down_time)
43 def join(self, member_id, group_id, service=None):
44 """Join the given service with its group."""
46 LOG.debug('Memcached_Driver: join new ServiceGroup member '
47 '%(member_id)s to the %(group_id)s group, '
48 'service = %(service)s',
49 {'member_id': member_id,
50 'group_id': group_id,
51 'service': service})
52 if service is None: 52 ↛ 53line 52 didn't jump to line 53 because the condition on line 52 was never true
53 raise RuntimeError(_('service is a mandatory argument for '
54 'Memcached based ServiceGroup driver'))
55 report_interval = service.report_interval
56 if report_interval: 56 ↛ exitline 56 didn't return from function 'join' because the condition on line 56 was always true
57 service.tg.add_timer_args(
58 report_interval, self._report_state, args=[service],
59 initial_delay=api.INITIAL_REPORTING_DELAY)
61 def is_up(self, service_ref):
62 """Moved from nova.utils
63 Check whether a service is up based on last heartbeat.
64 """
65 key = "%(topic)s:%(host)s" % service_ref
66 is_up = self.mc.get(str(key)) is not None
67 if not is_up:
68 LOG.debug('Seems service %s is down', key)
70 return is_up
72 def updated_time(self, service_ref):
73 """Get the updated time from memcache"""
74 key = "%(topic)s:%(host)s" % service_ref
75 updated_time_in_mc = self.mc.get(str(key))
76 updated_time_in_db = service_ref['updated_at']
78 if updated_time_in_mc:
79 # Change mc time to offset-aware time
80 updated_time_in_mc = updated_time_in_mc.replace(tzinfo=iso8601.UTC)
81 # If [DEFAULT]/enable_new_services is set to be false, the
82 # ``updated_time_in_db`` will be None, in this case, use
83 # ``updated_time_in_mc`` instead.
84 if (not updated_time_in_db or
85 updated_time_in_db <= updated_time_in_mc):
86 return updated_time_in_mc
88 return updated_time_in_db
90 def _report_state(self, service):
91 """Update the state of this service in the datastore."""
92 try:
93 key = "%(topic)s:%(host)s" % service.service_ref
94 # memcached has data expiration time capability.
95 # set(..., time=CONF.service_down_time) uses it and
96 # reduces key-deleting code.
97 self.mc.set(str(key),
98 timeutils.utcnow())
100 # TODO(termie): make this pattern be more elegant.
101 if getattr(service, 'model_disconnected', False): 101 ↛ 102line 101 didn't jump to line 102 because the condition on line 101 was never true
102 service.model_disconnected = False
103 LOG.info(
104 'Recovered connection to memcache server for reporting '
105 'service status.'
106 )
108 # TODO(vish): this should probably only catch connection errors
109 except Exception:
110 if not getattr(service, 'model_disconnected', False):
111 service.model_disconnected = True
112 LOG.warning(
113 'Lost connection to memcache server for reporting service '
114 'status.'
115 )