1,nova中的兩條命令執行過程分析:
nova service-list
+------------------+--------------+----------+---------+-------+----------------------------+-----------------+
| Binary | Host | Zone | Status | State | Updated_at | Disabled Reason |
+------------------+--------------+----------+---------+-------+----------------------------+-----------------+
| nova-scheduler | openstack2 | internal | enabled | up | 2014-02-12T02:17:31.000000 | None |
| nova-conductor | openstack2 | internal | enabled | up | 2014-02-12T02:17:32.000000 | None |
| nova-cert | openstack2 | internal | enabled | up | 2014-02-12T02:17:31.000000 | None |
| nova-consoleauth | openstack2 | internal | enabled | up | 2014-02-12T02:17:31.000000 | None |
| nova-compute | openstack2 | nova | enabled | up | 2014-02-12T02:17:33.000000 | None |
| nova-network | openstack2 | internal | enabled | up | 2014-02-12T02:17:29.000000 | None |
| nova-compute | openstack-1 | nova | enabled | up | 2014-02-12T02:17:27.000000 | None |
| nova-network | openstack-1 | internal | enabled | up | 2014-02-12T02:17:32.000000 | None |
+------------------+--------------+----------+---------+-------+----------------------------+-----------------+
nova host-list
+--------------+-------------+----------+
| host_name | service | zone |
+--------------+-------------+----------+
| openstack2 | scheduler | internal |
| openstack2 | conductor | internal |
| openstack2 | cert | internal |
| openstack2 | consoleauth | internal |
| openstack2 | compute | nova |
| openstack2 | network | internal |
| openstack-1 | compute | nova |
| openstack-1 | network | internal |
+--------------+-------------+----------+
那麼controller節點怎麼知道各個node的狀態呢?Controller怎麼知道各個node中運行的服務呢?
在nova-api服務中有以下介個REST-API:
Host-controller中提供了一下幾種方法:
class HostController(object):
def __init__(self):
self.api = compute.HostAPI()
super(HostController, self).__init__()
@wsgi.serializers(xml=HostIndexTemplate)
def index(self, req):
services = self.api.service_get_all(context, filters=filters,
set_zones=True)
for service in services:
hosts.append({'host_name': service['host'],
'service': service['topic'],
'zone': service['availability_zone']})
return {'hosts': hosts}
@wsgi.serializers(xml=HostShowTemplate)
def show(self, req, id):
context = req.environ['nova.context']
host_name = id
try:
service = self.api.service_get_by_compute_host(context, host_name)
def update(self, req, id, body):
return result
service-controller中提供了一下幾種方法
class ServiceController(object):
def __init__(self, ext_mgr=None, *args, **kwargs):
self.host_api = compute.HostAPI()
self.servicegroup_api = servicegroup.API()
self.ext_mgr = ext_mgr
def _get_services(self, req):
services = self.host_api.service_get_all(
context, set_zones=True)
def index(self, req):
detailed = self.ext_mgr.is_loaded('os-extended-services')
services = self._get_services_list(req, detailed)
return {'services': services}
@wsgi.deserializers(xml=ServiceUpdateDeserializer)
@wsgi.serializers(xml=ServiceUpdateTemplate)
def update(self, req, id, body):
try:
self.host_api.service_update(context, host, binary, status_detail)
return ret_value
#從這裏可以看出,對於host和service的查詢和更新操作調用了hostAPI中的一些方法
#查看service_get_all和compute_node_get
def service_get_all(self, context, filters=None, set_zones=False):
services = service_obj.ServiceList.get_all(context, disabled,
set_zones=set_zones)
return ret_services
def compute_node_get(self, context, compute_id):
return self.db.compute_node_get(context, int(compute_id))
可以看出,都是通過調用數據庫實現的;
注,service數據表中包含了主機host的信息
那麼service和host的數據是何時創建的呢?
首先看各個服務service啓動的時候,都做了什麼?
def main():
config.parse_args(sys.argv)
logging.setup("nova")
utils.monkey_patch()
server = service.Service.create(binary='nova-scheduler',
topic=CONF.scheduler_topic)
service.serve(server)
service.wait()
class Service(service.Service):
def __init__(self, host, binary, topic, manager, report_interval=None,
periodic_enable=None, periodic_fuzzy_delay=None,
periodic_interval_max=None, db_allowed=True,
*args, **kwargs):
super(Service, self).__init__()
self.host = host
self.binary = binary
self.topic = topic
self.manager_class_name = manager
self.servicegroup_api = servicegroup.API(db_allowed=db_allowed)
manager_class = importutils.import_class(self.manager_class_name)
self.manager = manager_class(host=self.host, *args, **kwargs)
self.report_interval = report_interval
self.periodic_enable = periodic_enable
self.periodic_fuzzy_delay = periodic_fuzzy_delay
self.periodic_interval_max = periodic_interval_max
self.saved_args, self.saved_kwargs = args, kwargs
self.backdoor_port = None
self.conductor_api = conductor.API(use_local=db_allowed)
self.conductor_api.wait_until_ready(context.get_admin_context())
def start(self):
verstr = version.version_string_with_package()
LOG.audit(_('Starting %(topic)s node (version %(version)s)'),
{'topic': self.topic, 'version': verstr})
self.basic_config_check()
self.manager.init_host()
self.model_disconnected = False
ctxt = context.get_admin_context()
try:
self.service_ref = self.conductor_api.service_get_by_args(ctxt,
self.host, self.binary)
self.service_id = self.service_ref['id']
except exception.NotFound:
self.service_ref = self._create_service_ref(ctxt)
self.manager.pre_start_hook()
if self.backdoor_port is not None:
self.manager.backdoor_port = self.backdoor_port
self.conn = rpc.create_connection(new=True)
LOG.debug(_("Creating Consumer connection for Service %s") %
self.topic)
rpc_dispatcher = self.manager.create_rpc_dispatcher(self.backdoor_port)
# Share this same connection for these Consumers
self.conn.create_consumer(self.topic, rpc_dispatcher, fanout=False)
node_topic = '%s.%s' % (self.topic, self.host)
self.conn.create_consumer(node_topic, rpc_dispatcher, fanout=False)
self.conn.create_consumer(self.topic, rpc_dispatcher, fanout=True)
# Consume from all consumers in a thread
self.conn.consume_in_thread()
self.manager.post_start_hook()
LOG.debug(_("Join ServiceGroup membership for this service %s")
% self.topic)
# Add service to the ServiceGroup membership group.
self.servicegroup_api.join(self.host, self.topic, self)
if self.periodic_enable:
if self.periodic_fuzzy_delay:
initial_delay = random.randint(0, self.periodic_fuzzy_delay)
else:
initial_delay = None
self.tg.add_dynamic_timer(self.periodic_tasks,
initial_delay=initial_delay,
periodic_interval_max=
self.periodic_interval_max)
def _create_service_ref(self, context):
svc_values = {
'host': self.host,
'binary': self.binary,
'topic': self.topic,
'report_count': 0
}
service = self.conductor_api.service_create(context, svc_values)
self.service_id = service['id']
return service
def __getattr__(self, key):
manager = self.__dict__.get('manager', None)
return getattr(manager, key)
@classmethod
def create(cls, host=None, binary=None, topic=None, manager=None,
report_interval=None, periodic_enable=None,
periodic_fuzzy_delay=None, periodic_interval_max=None,
db_allowed=True):
if not host:
host = CONF.host
if not binary:
binary = os.path.basename(sys.argv[0])
if not topic:
topic = binary.rpartition('nova-')[2]
if not manager:
manager_cls = ('%s_manager' %
binary.rpartition('nova-')[2])
manager = CONF.get(manager_cls, None)
if report_interval is None:
report_interval = CONF.report_interval
if periodic_enable is None:
periodic_enable = CONF.periodic_enable
if periodic_fuzzy_delay is None:
periodic_fuzzy_delay = CONF.periodic_fuzzy_delay
service_obj = cls(host, binary, topic, manager,
report_interval=report_interval,
periodic_enable=periodic_enable,
periodic_fuzzy_delay=periodic_fuzzy_delay,
periodic_interval_max=periodic_interval_max,
db_allowed=db_allowed)
return service_obj
def kill(self):
"""Destroy the service object in the datastore."""
self.stop()
try:
self.conductor_api.service_destroy(context.get_admin_context(),
self.service_id)
except exception.NotFound:
LOG.warn(_('Service killed that has no database entry'))
啓動服務時,判斷數據庫中是否已經存在某個服務記錄,如果不存在則創建一條記錄!
services表的結構:2 scheduler中的hostmanager是如何管理和調度計算節點的?
直接查詢數據庫中的compute_node來實現;
3 compute_node表中的數據何時CRUD?
nova-compute服務會通過一個定時任務period_task.perisod_task定期更新compute_node表中的數據,這些數據主要是關於compute節點目前的使用情況!
compute_node表的結構: