当node节点state为manage时,可执行inspector
ironic node-set-provision-state <node_uuid> manage
ironic node-set-provision-state <node_uuid> inspect

inspect阶段

执行inspect后ironic会发送PUT请求到 /v1/nodes/{node_ident}/provision , ironic-api 收到这个请求后会根据 body 的 target 字段做处理:

class NodeStatesController(rest.RestController):
_custom_actions = {
'power': ['PUT'],
'provision': ['PUT'],
'raid': ['PUT'],
}
def get(self, node_ident):
.......
def raid(self, node_ident, target_raid_config):
......
def power(self, node_ident, target, timeout=None):
......
def provision(self, node_ident, target, configdrive=None,
clean_steps=None, rescue_password=None):
if target in (ir_states.ACTIVE, ir_states.REBUILD):#判断状态
rebuild = (target == ir_states.REBUILD)
pecan.request.rpcapi.do_node_deploy(context=pecan.request.context,
node_id=rpc_node.uuid,
rebuild=rebuild,
configdrive=configdrive,
topic=topic)
elif target == ir_states.VERBS['inspect']:#调用inspect_hardware方法
pecan.request.rpcapi.inspect_hardware(pecan.request.context, rpc_node.uuid, topic=topic)

ironic/api/controllers/v1/node.py

然后通过发送 http 请求 到 ironic-inspector。inspect 的具体实现是跟 driver 有关,在 driver.inspect.inspect_hardware 中

def inspect_hardware(self, task):
#检查硬件以获取硬件属性
eventlet.spawn_n(_start_inspection, task.node.uuid, task.context)
return states.INSPECTING def _start_inspection(node_uuid, context):
try:
_get_client(context).introspect(node_uuid)#调取_get_client函数,该函数调取keystone对inspector进行认证
def _get_client(context):
.......
return client.ClientV1(api_version=INSPECTOR_API_VERSION,
session=session,
inspector_url=inspector_url)#调取inspetor client

ironic/drivers/modules/inspector.py

class ClientV1(http.BaseClient):
#客户端V1版本
.......
#创建一个客户端
def __init__(self, **kwargs):
kwargs.setdefault('api_version', DEFAULT_API_VERSION)
super(ClientV1, self).__init__(**kwargs)
self.rules = RulesAPI(self.request)#获取自省规则 #启动节点自省
def introspect(self, uuid):
if not isinstance(uuid, six.string_types):
raise TypeError(
_("Expected string for uuid argument, got %r") % uuid) self.request('post', '/introspection/%s' % uuid)

ironic_inspector_client/v1.py

inspector处理阶段

@api('/v1/introspection/<node_id>',
rule="introspection:{}",
verb_to_rule_map={'GET': 'status', 'POST': 'start'},
methods=['GET', 'POST'])
def api_introspection(node_id):
if flask.request.method == 'POST':#如果请求是post,验证token,返回202,即接受请求
introspect.introspect(node_id,
token=flask.request.headers.get('X-Auth-Token'))#调取introspect函数,为节点启动硬件属性自省。
return '', 202
else:
node_info = node_cache.get_node(node_id)
return flask.json.jsonify(generate_introspection_status(node_info))

ironic-inspector/ironic_inspector/main.py

def introspect(node_id, token=None):
node_info = node_cache.start_introspection(node.uuid,#更新了ipmi信息,在attributes表里添加bmc_address信息
bmc_address=bmc_address,
ironic=ironic)
utils.executor().submit(_background_introspect, node_info, ironic) def _background_introspect(node_info, ironic):
......
......
node_info.acquire_lock()
_background_introspect_locked(node_info, ironic)#调用 _background_introspect做主机发现。 def _background_introspect_locked(node_info, ironic):
......
try:
ironic.node.set_boot_device(node_info.uuid, 'pxe',
persistent=False)
except Exception as exc:
LOG.warning('Failed to set boot device to PXE: %s',
exc, node_info=node_info)
try:
ironic.node.set_power_state(node_info.uuid, 'reboot')
except Exception as exc:
raise utils.Error(_('Failed to power on the node, check it\'s '
'power management configuration: %s'),
exc, node_info=node_info)

ironic_inspector/introspect.py

ipa阶段

class IronicPythonAgent(base.ExecuteCommandMixin):
......
......
def run(self):
self.started_at = _time()
hardware.load_managers()
if self.hardware_initialization_delay > 0:
LOG.info('Waiting %d seconds before proceeding',
self.hardware_initialization_delay)
time.sleep(self.hardware_initialization_delay)
if not self.standalone:
uuid = None
if cfg.CONF.inspection_callback_url:
uuid = inspector.inspect()#因配置了callback_url,跳转到inspect

ironic_python_agent/agent.py

def inspect():
....
if not CONF.inspection_callback_url:
LOG.info('Inspection is disabled, skipping')
return
collector_names = [x.strip() for x in CONF.inspection_collectors.split(',')
if x.strip()]
LOG.info('inspection is enabled with collectors %s', collector_names)
failures = utils.AccumulatedFailures(exc_class=errors.InspectionError)
data = {} try:
# 对应该文件中的collect_*函数,默认为default,对应collect_default
ext_mgr = extension_manager(collector_names)
collectors = [(ext.name, ext.plugin) for ext in ext_mgr]
except Exception as exc:
with excutils.save_and_reraise_exception():
failures.add(exc)
call_inspector(data, failures) for name, collector in collectors:
try:
# 例:此处为collect_default
collector(data, failures)
except Exception as exc:
failures.add('collector %s failed: %s', name, exc)
# 跳转到call_inspector函数,该函数用于发送data给inspector
resp = call_inspector(data, failures)
failures.raise_if_needed()
if resp is None:
LOG.info('stopping inspection, as inspector returned an error')
return
LOG.info('inspection finished successfully')
return resp.get('uuid') def collect_default(data, failures):
# 调用ironic_python_agent.hardware.py中的list_hardware_info函数
inventory = hardware.dispatch_to_managers('list_hardware_info')
# 添加到data中
data['inventory'] = inventory

ironic_python_agent/inspector.py

ipa 可以看到除了collect_default,还提供了collect_logs、collect_extra_hardware、collect_pci_devices_info三个函数,分别用于收集系统日志、收集benchmark、收集pci设备信息 
ironic_python_agent.hardware.py 可以看看collect_default收集了哪些信息

class HardwareManager(object):
......
.....
def list_hardware_info(self):
hardware_info = {}
hardware_info['interfaces'] = self.list_network_interfaces()#网卡
hardware_info['cpu'] = self.get_cpus()#cpu
hardware_info['disks'] = self.list_block_devices()#硬盘
hardware_info['memory'] = self.get_memory()#内存
hardware_info['bmc_address'] = self.get_bmc_address()#bmc地址
hardware_info['system_vendor'] = self.get_system_vendor_info()#系统厂商信息
hardware_info['boot'] = self.get_boot_info()#启动信息
return hardware_info#返回硬件信息

ironic_python_agent/hardware.py

ipa收集BM信息并将其发送给ipa-inspection-callback-url

@api('/v1/continue', rule="introspection:continue", is_public_api=True,
methods=['POST'])
def api_continue():
data = flask.request.get_json(force=True)#检查是否是json格式的数据
if not isinstance(data, dict):
raise utils.Error(_('Invalid data: expected a JSON object, got %s') %
data.__class__.__name__) logged_data = {k: (v if k not in _LOGGING_EXCLUDED_KEYS else '<hidden>')
for k, v in data.items()}
LOG.debug("Received data from the ramdisk: %s", logged_data,
data=data) return flask.jsonify(process.process(data))#跳转到process函数,处理来自ipa的自省数据

ironic_inspector/main.py

def process(introspection_data):
unprocessed_data = copy.deepcopy(introspection_data)
failures = []
_run_pre_hooks(introspection_data, failures)
node_info = _find_node_info(introspection_data, failures)#根据ipmi_address和macs获取inpsector node
if node_info:
node_info.acquire_lock()
......
utils.executor().submit(_store_unprocessed_data, node_info,
unprocessed_data)#多线程处理_store_unprocessed_data函数,存储数据
try:
node = node_info.node()#从node_info中提取node
.....
try:
result = _process_node(node_info, node, introspection_data) #跳转到_process_node函数,该函数会重复检查node信息 def _process_node(node_info, node, introspection_data):
ir_utils.check_provision_state(node)#检查node自省状态
_run_post_hooks(node_info, introspection_data)
_store_data(node_info, introspection_data)#存储数据,如ironic-inspector配置中store_data为none,则不存储 ironic = ir_utils.get_client()#调用ironic client
pxe_filter.driver().sync(ironic) node_info.invalidate_cache()#清除所有缓存的信息,以便下次重新加载
rules.apply(node_info, introspection_data)#对node应用规则 resp = {'uuid': node.uuid}
#结束inspect流程,调用_finish函数,该函数处理关闭电源的过程
utils.executor().submit(_finish, node_info, ironic, introspection_data,
power_off=CONF.processing.power_off)
return resp def _finish(node_info, ironic, introspection_data, power_off=True):
if power_off:
LOG.debug('Forcing power off of node %s', node_info.uuid)
try:
ironic.node.set_power_state(node_info.uuid, 'off')
except Exception as exc:
if node_info.node().provision_state == 'enroll':
LOG.info("Failed to power off the node in"
"'enroll' state, ignoring; error was "
"%s", exc, node_info=node_info,
data=introspection_data)
else:
msg = (_('Failed to power off node %(node)s, check '
'its power management configuration: '
'%(exc)s') % {'node': node_info.uuid, 'exc':
exc})
raise utils.Error(msg, node_info=node_info,
data=introspection_data)
LOG.info('Node powered-off', node_info=node_info,
data=introspection_data) node_info.finished(istate.Events.finish)
LOG.info('Introspection finished successfully',
node_info=node_info, data=introspection_data)

ironic_inspector.process.py

inspect流程的更多相关文章

  1. install ironic-inspector

    安装相应的包和组件 yum install openstack-ironic-inspector python-ironic-inspector-client -y 创建user openstack ...

  2. jQuery-1.9.1源码分析系列(十六)ajax——ajax处理流程以及核心函数

    先来看一看jQuery的ajax核心处理流程($.ajax) a. ajax( [url,] options )执行流程 第一步,为传递的参数做适配.url可以包含在options中 //传递的参数只 ...

  3. 利用Sonar规则结合WebStorm进行Code Inspect

    1.目的 在编写代码时会受到公司Sonar规则的限制,不想在编写完成后再对代码进行Inspect,回头再来一个个修正,费时费力. 那么,下面将通过优秀的WebStorm开发工具自身的CodeInspe ...

  4. chrome://inspect 移动前端调试方案(Android + Chrome 实现远程调试)

    一:背景通常情况我们调试移动端页面最常用的方法就是:切换pc端浏览器的userAgent来模拟手机或其他移动设备调试页面 然后用手机打开要调试的页面 刷新页面查看调试结果 但是这就存在两个问题 在pc ...

  5. Dockerfile与Docker构建流程解读

    摘要 本文主要讨论了对docker build的源码流程进行了梳理和解读,并分享了在制作Dockerfile过程中的一些实践经验,包括如何调试.优化和build中的一些要点.另外,还针对现有Docke ...

  6. PHP容器--Pimple运行流程浅析

    需要具备的知识点 闭包 闭包和匿名函数在PHP5.3.0中引入的. 闭包是指:创建时封装周围状态的函数.即使闭包所处的环境不存在了,闭包中封装的状态依然存在. 理论上,闭包和匿名函数是不同的概念.但是 ...

  7. Webpack系列-第三篇流程杂记

    系列文章 Webpack系列-第一篇基础杂记 Webpack系列-第二篇插件机制杂记 Webpack系列-第三篇流程杂记 前言 本文章个人理解, 只是为了理清webpack流程, 没有关注内部过多细节 ...

  8. asp.net core 2.0发布到IIS流程及报错解决方案

      我这是个新装的服务器,没有安装任何软件. 一.发布流程 1.安装AspNetCoreModule托管模块,同时会自动安装..net core runtime DotNetCore.2.0.8-Wi ...

  9. asyncio源码分析之基本执行流程

    基于async关键字的原生协程 # 定义一个简单的原生协程cor async def cor(): print('enter cor') print('exit cor') print(type(co ...

随机推荐

  1. 木棒,POJ(1011)

    题目链接:http://poj.org/problem?id=1011 解题报告: #include <cstdio> #include <cstring> #include ...

  2. 【转】android布局--Android fill_parent、wrap_content和match_parent的区别

    三个属性都用来适应视图的水平或垂直大小,一个以视图的内容或尺寸为基础的布局比精确地指定视图范围更加方便. 1)fill_parent 设置一个构件的布局为fill_parent将强制性地使构件扩展,以 ...

  3. python 合并字符串

    [root@chenbj python]# cat name.py #!/usr/bin/env python # _*_ coding:utf-8 _*_ first_name = "ch ...

  4. vector的几种初始化和遍历

    随着C++11标准的出现,vector出现了新的初始化和遍历用法,但是vs2010和较高版本并没有能完全支持C++11标准,所以我就将它的所有的用法归纳了一下. vector的初始化 vector基本 ...

  5. Layer弹出层关闭后刷新父页面

    API地址:http://layer.layui.com/api.html#end 调用END回调方法: end - 层销毁后触发的回调 类型:Function,默认:null 无论是确认还是取消,只 ...

  6. 3、SpringBoot------邮件发送(1)

    开发工具:STS 代码下载链接:https://github.com/theIndoorTrain/Springboot/tree/8878e8e89ce01ceb967ef8c1193ac740a6 ...

  7. Session的生命同期

    一.什么是Session,怎么用 Session是存放用户与web服务器之间的会话,即服务器为浏览器开辟的存储空间. 由于浏览器与服务器之间的会话是无状态(无状态的意思是会话之间无关联性,无法识别该用 ...

  8. Charles Dickens【查尔斯·狄更斯】

    Charles Dickens In 1812, the year Charles Dickens was born, there were 66 novels published in Britai ...

  9. python文件,字符串,二进制的读写

    读文件: f = open('/Users/michael/test.txt', 'r') #一次读取文件的全部内容 f.read() #文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且 ...

  10. 大话卷积神经网络(CNN)

      这几年深度学习快速发展,在图像识别.语音识别.物体识别等各种场景上取得了巨大的成功,例如AlphaGo击败世界围棋冠军,iPhone X内置了人脸识别解锁功能等等,很多AI产品在世界上引起了很大的 ...