Ocata-based version of the source code carding
1) a user input command line cinder service-list, view the status of the service cinder, the cinder entry function cinder / api contrib / services.py /: Service: index method
class ServiceController(wsgi.Controller): def __init__(self, ext_mgr=None): self.ext_mgr = ext_mgr super(ServiceController, self).__init__() self.volume_api = volume.API() def index(self, req): """Return a list of all running services. Filter by host & service name. """ context = req.environ['cinder.context'] authorize(context, action='index') detailed = self.ext_mgr.is_loaded('os-extended-services') now = timeutils.utcnow(with_timezone=True)------------------//获取controller 当前的时间 filters = {} if 'host' in req.GET: filters['host'] = req.GET['host'] IF 'binary' in req.GET: Filters [ 'binary'] = req.GET [ 'binary'] elif '-Service' in req.GET: Filters [ 'binary'] = req.GET [ '-Service'] versionutils. report_deprecated_feature (LOG, _ ( "Query Service by the Parameter IS deprecated." "Please use the Parameter binary INSTEAD.")) Services = objects.ServiceList.get_all (context, Filters) ---------- // from db get a list of all the cinder service svcs = [] for svc in services:----------------------------//循环每个 service updated_at = svc.updated_at delta = now - (svc.updated_at or svc.created_at ) ------------- // get updated_at. Does not exist, obtaining the created_at, and calculate the time difference and the current time delta_sec = delta.total_seconds () IF svc.modified_at: delta_mod = now - svc.modified_at Active = 'Enabled ' IF svc.disabled: Active =' Disabled ' ABS IF (delta_sec)> = ABS (delta_mod.total_seconds ()): for updated_at svc.modified_at = absolute value alive = abs (delta_sec) <= CONF.service_down_time ------ / acquisition time difference, and checks whether less than server_down_time configuration, the configuration item the default is 60 seconds art = (alive and "up" ) or "down" ---------------------- // if difference is less than 60, then the service status is up, otherwise Down IF for updated_at: for updated_at = timeutils.normalize_time (for updated_at) ret_fields = { 'binary': svc.binary, 'Host': svc.host, 'Zone': SVC. availability_zone, 'Status': Active, 'State': Art, 'for updated_at':updated_at} # On V3.7 we added cluster support if req.api_version_request.matches('3.7'): ret_fields['cluster'] = svc.cluster_name if detailed: ret_fields['disabled_reason'] = svc.disabled_reason if svc.binary == "cinder-volume": ret_fields['replication_status'] = svc.replication_status ret_fields['active_backend_id'] = svc.active_backend_id ret_fields['frozen'] = svc.frozen svcs.append(ret_fields) return {'services': svcs}
Thus service of the up / down depending on the state of the range of the time difference value and the current controller node database table corresponding to a service of the service updated_at whether the columns in the row of the configuration, if the difference is within the range set, then that service is up, down is if the difference is not within the scope of the set, then that service, then the value of each service from updated_at how to update?
2, corresponding to each service update database cinder update_at value, the time value of this field, that the acquired service running on which physical nodes, to obtain the current time value of the physical nodes, the database is updated value, the count is incremented
various service cinder, such as cinder-api, cinder-backup, etc., are examples of a cinder / service.py file class Service (service.Service) of
(in this example, using a Manager, enable RPC, by listening on topic of the queue, and he also regularly run a task on manager, reported his condition to the database service table)
Start methods of the class as follows:
Start DEF (Self): the version_string = version.version_string () log.info (_LI ( 'Starting% (Topic) S Node (Version% (the version_string) S)'), { 'Topic': self.topic, 'the version_string' : the version_string}) self.model_disconnected = False IF self.coordination: coordination.COORDINATOR.start () self.manager.init_host (added_to_cluster = self.added_to_cluster, -------- call manager module is init_host method, service_id = Service.service_id) ------------------ implementation of this method in turn invokes driver.do_setup, driver.check_for_setup_error, driver.init_capabilities three functions, which may in init_capabilities there will mobilize driven get_volume_stats function to get the information stored in the state storage backend LOG.debug("Creating RPC server for service %s", self.topic) ctxt = context.get_admin_context() endpoints = [self.manager] endpoints.extend(self.manager.additional_endpoints) obj_version_cap = objects.Service.get_minimum_obj_version(ctxt) LOG.debug("Pinning object versions for RPC server serializer to %s", obj_version_cap) serializer = objects_base.CinderObjectSerializer(obj_version_cap) target = messaging.Target(topic=self.topic, server=self.host) self.rpcserver = rpc.get_server(target, endpoints, serializer) self.rpcserver.start() # NOTE(dulek): Kids, don't do that at home. We're relying here on # oslo.messaging implementation details to keep backward compatibility # with pre-Ocata services. This will not matter once we drop # compatibility with them. if self.topic == constants.VOLUME_TOPIC: target = messaging.Target( topic='%(topic)s.%(host)s' % {'topic': self.topic, 'host': self.host}, server=vol_utils.extract_host(self.host, 'host')) self.backend_rpcserver = rpc.get_server(target, endpoints, serializer) self.backend_rpcserver.start() # TODO(geguileo): In O - Remove the is_svc_upgrading_to_n part if self.cluster and not self.is_svc_upgrading_to_n(self.binary): LOG.info(_LI('Starting %(topic)s cluster %(cluster)s (version ' '%(version)s)'), {'topic': self.topic, 'version': version_string, 'cluster': self.cluster}) = messaging.Target target ( Topic = '% S. S%'% (self.topic, self.cluster), Server = vol_utils.extract_host (self.cluster, 'Host')) Serializer = objects_base.CinderObjectSerializer (obj_version_cap) self.cluster_rpcserver = rpc.get_server(target, endpoints, serializer) self.cluster_rpcserver.start() Self .manager.init_host_with_rpc () IF self.report_interval: ------------------------- // If you set report_interval configuration items, then the service will start report_state infinite loop to perform a method, run interval is report_interval, the default value is 10 seconds, which is the default state of 10 reported a pulse = loopingcall.FixedIntervalLoopingCall (---------- which is a cyclic, self.report_state this task is to be executed in a loop self.report_state) pulse.start (= interval the self.report_interval, ----------- started this run this cycle, s1 initial_delay = self.report_interval) self.timers .append (Pulse) IF self.periodic_interval: IF self.periodic_fuzzy_delay: initial_delay the random.randint = (0, self.periodic_fuzzy_delay) else: initial_delay = None periodic = loopingcall.FixedIntervalLoopingCall( self.periodic_tasks) periodic.start(interval=self.periodic_interval, initial_delay=initial_delay) self.timers.append(periodic)
s1方法的实现 def report_state(self):----更新服务的状态到数据库中 """Update the state of this service in the datastore.""" if not self.manager.is_working(): # NOTE(dulek): If manager reports a problem we're not sending # heartbeats - to indicate that service is actually down. LOG.error(_LE('Manager for service %(binary)s %(host)s is ' 'reporting problems, not sending heartbeat. ' 'Service will appear "down".'), {'binary': self.binary, 'host': self.host}) return ctxt = context.get_admin_context() zone = CONF.storage_availability_zone try: try: service_ref = objects.Service.get_by_id(ctxt,Service.service_id)-----根据service_id从数据库中获取service信息 except exception.NotFound: LOG.debug('The service database object disappeared, ' 'recreating it.') self._create_service_ref(ctxt) service_ref = objects.Service.get_by_id(ctxt,Service.service_id) service_ref.report_count += 1--------------更新报告计数器,加1 if zone != service_ref.availability_zone: service_ref.availability_zone = zone service_ref.save() # TODO(termie): make this pattern be more elegant. if getattr(self, 'model_disconnected', False): self.model_disconnected = False LOG.error(_LE('Recovered model server connection!'))
3, content services table field
mysql> desc services; +------------------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------------------+--------------+------+-----+---------+----------------+ | created_at | datetime | YES | | NULL | | | updated_at | datetime | YES | | NULL | | | deleted_at | datetime | YES | | NULL | | | deleted | tinyint(1) | YES | | NULL | | | id | int(11) | NO | PRI | NULL | auto_increment | | host | varchar(255) | YES | | NULL | | | binary | varchar(255) | YES | | NULL | | | topic | varchar(255) | YES | | NULL | | | report_count | int(11) | NO | | NULL | | | disabled | tinyint(1) | YES | | NULL | | | availability_zone | varchar(255) | YES | | NULL | | | disabled_reason | varchar(255) | YES | | NULL | | | modified_at | datetime | YES | | NULL | | | rpc_current_version | varchar(36) | YES | | NULL | | | object_current_version | varchar(36) | YES | | NULL | | | replication_status | varchar(36) | YES | | NULL | | | frozen | tinyint(1) | YES | | NULL | | | active_backend_id | varchar(255) | YES | | NULL | | | cluster_name | varchar(255) | YES | | NULL | | +------------------------+--------------+------+-----+---------+----------------+ 19 rows in set (0.01 sec)
样例 mysql> select * from services limit 2\G; *************************** 1. row *************************** created_at: 2018-08-16 07:29:20 updated_at: 2019-06-14 09:22:23 deleted_at: NULL deleted: 0 id: 1 host: 10.24.1.9 binary: cinder-scheduler topic: cinder-scheduler report_count: 838433 disabled: 0 availability_zone: nova disabled_reason: NULL modified_at: NULL rpc_current_version: 3.5 object_current_version: 1.21 replication_status: not-capable frozen: 0 active_backend_id: NULL cluster_name: NULL *************************** 2. row ***************************