ironic-conductor与ipa交互clean部分代码分析
clean的动作会在provide和delete阶段才会触发
从代码分析:
对节点执行的node provide/deleted/clean会先发送到ironicclient ironicclient.call("node.set_provision_state", node.uuid,"deleted")
class Client(object):
self.node = node.NodeManager(self.http_client)
class NodeManager(base.CreateManager):
def set_provision_state(self, node_uuid, state, configdrive=None,
cleansteps=None, rescue_password=None)
在这个函数里面会构造一个http请求,包含一个url和一个body:
url = /v1/nodes/node_id/states/provision
patch = {'target': deleted}
然后发送给ironic-api
nova/virt/ironic/driver.py
ironic/api/controllers/v1/__init__.py ------>>>
class Controller(rest.RestController): nodes = node.NodesController()
ports = port.PortsController()
portgroups = portgroup.PortgroupsController()
chassis = chassis.ChassisController()
drivers = driver.DriversController()
volume = volume.VolumeController()
lookup = ramdisk.LookupController()
heartbeat = ramdisk.HeartbeatController() ironic/api/controllers/v1/node.py ---->>>
class NodesController(rest.RestController):
states = NodeStatesController() ironic/api/controllers/v1/node.py ---->>>
class NodeStatesController(rest.RestController):
_custom_actions = {
'power': ['PUT'],
'provision': ['PUT'],
'raid': ['PUT'],
}
def provision(self, node_ident, target, configdrive=None,
clean_steps=None, rescue_password=None):
......
......
elif target == ir_states.DELETED:
pecan.request.rpcapi.do_node_tear_down(
pecan.request.context, rpc_node.uuid, topic) elif target == ir_states.VERBS['clean']:
if not clean_steps:
msg = (_('"clean_steps" is required when setting target '
'provision state to %s') % ir_states.VERBS['clean'])
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
_check_clean_steps(clean_steps)
pecan.request.rpcapi.do_node_clean(
pecan.request.context, rpc_node.uuid, clean_steps, topic) elif target in PROVISION_ACTION_STATES:
pecan.request.rpcapi.do_provisioning_action(
pecan.request.context, rpc_node.uuid, target, topic) ironic/conductor/manager.py ----->>>
class ConductorManager(base_manager.BaseConductorManager):
......
......
def do_node_tear_down(self, context, node_id):
......
try:
task.process_event(
'delete',
callback=self._spawn_worker,
call_args=(self._do_node_tear_down, task,
task.node.provision_state),
err_handler=utils.provisioning_error_handler) def do_node_clean(self, context, node_id, clean_steps):
......
try:
task.process_event(
'clean',
callback=self._spawn_worker,
call_args=(self._do_node_clean, task, clean_steps),
err_handler=utils.provisioning_error_handler,
target_state=states.MANAGEABLE) def do_provisioning_action(self, context, node_id, action):
......
with task_manager.acquire(context, node_id, shared=False,
purpose='provision action %s'
% action) as task:
node = task.node
if (action == states.VERBS['provide'] and
node.provision_state == states.MANAGEABLE):
task.process_event(
'provide',
callback=self._spawn_worker,
call_args=(self._do_node_clean, task),
err_handler=utils.provisioning_error_handler)
return
最终都会调用到ironic-conductor的def _do_node_clean()函数,执行清理 ironic/conductor/manager.py ----->>>
class ConductorManager(base_manager.BaseConductorManager):
def _do_node_clean(self, task, clean_steps=None):
node = task.node
manual_clean = clean_steps is not None
clean_type = 'manual' if manual_clean else 'automated'
在这块就根据根据clean_setp判断清理是自动还是手动清理
如果在ironic.conf中automated_clean为false,且没有指定clean_steps,则直接进入available状态
if not manual_clean and not CONF.conductor.automated_clean:
# Skip cleaning, move to AVAILABLE.
node.clean_step = None
node.save()
task.process_event('done')
LOG.info('Automated cleaning is disabled, node %s has been '
'successfully moved to AVAILABLE state.', node.uuid)
return
ironic/drivers/modules/agent.py ----->>> class AgentDeploy(AgentDeployMixin, base.DeployInterface):
def prepare_cleaning(self, task):
return deploy_utils.prepare_inband_cleaning(
task, manage_boot=CONF.agent.manage_agent_boot)
引导ramdisk准备带内清理
ironic/drivers/modules/deploy_utils.py ---->>>
def prepare_inband_cleaning(task, manage_boot=True):
task.driver.network.add_cleaning_network(task)
agent_add_clean_params(task)
if manage_boot:
ramdisk_opts = build_agent_options(task.node)
task.driver.boot.prepare_ramdisk(task, ramdisk_opts) manager_utils.node_power_action(task, states.REBOOT)
return states.CLEANWAIT 等待节点启动,ipa发送心跳回来。ipa执行完所有clean步骤后,执行tear_down_cleaning
ironic/conductor/manager.py ----->>>
def _do_next_clean_step(self, task, step_index):
node = task.node
manual_clean = node.target_provision_state == states.MANAGEABLE
driver_internal_info = node.driver_internal_info
if step_index is None:
steps = []
else:
steps = driver_internal_info['clean_steps'][step_index:] LOG.info('Executing %(state)s on node %(node)s, remaining steps: '
'%(steps)s', {'node': node.uuid, 'steps': steps,
'state': node.provision_state}) ironic/drivers/modules/agent.py ----->>>
def tear_down_cleaning(self, task):
deploy_utils.tear_down_inband_cleaning(
task, manage_boot=CONF.agent.manage_agent_boot)
移除clean network,清理掉ipxe和dhcp相关的文件 ironic/drivers/modules/network/neutron.py --->>>
def remove_cleaning_network(self, task):
neutron.remove_ports_from_network(
task, self.get_cleaning_network_uuid(task))
for port in task.ports:
if 'cleaning_vif_port_id' in port.internal_info:
internal_info = port.internal_info
del internal_info['cleaning_vif_port_id']
port.internal_info = internal_info
port.save()
ipa和conductor通信部分见另外一篇文章,ipa和ironic-conductor交互
IPA加载后通过心跳触发ironic-conductor继续clean动作
ironic/drivers/modules/agent_base_vendor.py --->>>处理ipa返回的心跳
class HeartbeatMixin(object):
def heartbeat(self, task, callback_url, agent_version):
......
......
elif node.provision_state == states.CLEANWAIT:
self.continue_cleaning(task) ironic/drivers/modules/agent_base_vendor.py --->>>
class AgentDeployMixin(HeartbeatMixin):
def continue_cleaning(self, task, **kwargs):
.....
elif node.provision_state == states.CLEANWAIT:
_notify_conductor_resume_clean(task) ironic/drivers/modules/agent_base_vendor.py --->>>
def _notify_conductor_resume_clean(task):
uuid = task.node.uuid
rpc = rpcapi.ConductorAPI()
topic = rpc.get_topic_for(task.node)
task.release_resources()
rpc.continue_node_clean(task.context, uuid, topic=topic) ironic/conductor/rpcapi.py --->>>向conductor服务发出信号,启动下一个清理动作。
def continue_node_clean(self, context, node_id, topic=None):
cctxt = self.client.prepare(topic=topic or self.topic, version='1.27')
return cctxt.cast(context, 'continue_node_clean',
node_id=node_id) ironic/conductor/manager.py --->>>
def continue_node_clean(self, context, node_id):
......
task.spawn_after(
self._spawn_worker,
self._do_next_clean_step,
task, next_step_index) def _do_next_clean_step(self, task, step_index):
......
try:
result = interface.execute_clean_step(task, step)
如果该清理步骤未完成,则result为CLEANWAIT,该函数返回,等待下次心跳再次调用该函数
if result == states.CLEANWAIT:
LOG.info('Clean step %(step)s on node %(node)s being '
'executed asynchronously, waiting for driver.',
{'node': node.uuid, 'step': step})
target_state = states.MANAGEABLE if manual_clean else None
task.process_event('wait', target_state=target_state)
return
该步骤执行完毕后,会从driver_internal_info中将该清理步骤去掉
node.clean_step = None
driver_internal_info['clean_steps'] = None
driver_internal_info.pop('clean_step_index', None)
node.driver_internal_info = driver_internal_info
node.save() 传送给ipa来执行对应的clean command
ironic/drivers/modules/deploy_utils.py ---->>>
def agent_execute_clean_step(task, step):
client = agent_client.AgentClient()
ports = objects.Port.list_by_node_id(
task.context, task.node.id)
result = client.execute_clean_step(step, task.node, ports) ironic/drivers/modules/agent_client.py --->>>
class AgentClient(object):
def execute_clean_step(self, step, node, ports):
params = {
'step': step,
'node': node.as_dict(),
'ports': [port.as_dict() for port in ports],
'clean_version': node.driver_internal_info.get(
'hardware_manager_version')
}
return self._command(node=node,
method='clean.execute_clean_step',
params=params)
与ipa API交互
def _command(self, node, method, params, wait=False):
url = self._get_command_url(node)
body = self._get_command_body(method, params)
request_params = {
'wait': str(wait).lower()
try:
response = self.session.post(url, params=request_params, data=body)
ironic/drivers/modules/agent_base_vendor.py
IPA代码执行clean过程
ironic-python-agent/extentions/clean.py --->>>执行一个清理的步骤
class CleanExtension(base.BaseAgentExtension):
def execute_clean_step(self, step, node, ports, clean_version=None,**kwargs):
......
......
result = hardware.dispatch_to_managers(step['step'], node, ports)调用hardware的方法,按优先级获取硬件清理方法
清理磁盘
ironic_python_agent/hardware.py --->>>
class HardwareManager(object):
清除任何保存用户数据的设备
def erase_devices(self, node, ports):
erase_results = {}
block_devices = self.list_block_devices()
for block_device in block_devices:
result = dispatch_to_managers(
'erase_block_device', node=node, block_device=block_device)
erase_results[block_device.name] = result
return erase_results def erase_block_device(self, node, block_device):
if self._is_virtual_media_device(block_device):
LOG.info("Skipping the erase of virtual media device %s",
block_device.name)
return
try:
if self._ata_erase(block_device):判断设备是否支持安全擦除
return
.......
if self._shred_block_device(node, block_device):
return def _ata_erase(self, block_device):如果支持安全擦除则调用haparm命令进行擦除
security_lines = self._get_ata_security_lines(block_device)
......
if 'enabled' in security_lines:
try:
utils.execute('hdparm', '--user-master', 'u',
'--security-unlock', 'NULL', block_device.name)
security_lines = self._get_ata_security_lines(block_device)
def _shred_block_device(self, node, block_device):或者用shred擦除磁盘
info = node.get('driver_internal_info', {})
npasses = info.get('agent_erase_devices_iterations', 1)
args = ('shred', '--force') if info.get('agent_erase_devices_zeroize', True):
args += ('--zero', ) args += ('--verbose', '--iterations', str(npasses), block_device.name)
ironic-conductor与ipa交互clean部分代码分析的更多相关文章
- 例子Architecting Android…The clean way?----代码分析
Presention层: 整个应用启动的时候,就执行依赖的初始化.编译项目之后,Dagger依赖框架使用ApplicationComponent生成一个DaggerApplicationCOmpo ...
- 在android程序中加入widget(窗口小部件)并与之交互的关键代码
摘要: widget(窗口小部件)可以增强应用程序的交互性, 是很多应用中都会用到的功能,本文不求大而全,但是会给出程序与widget交互的关键代码 正文: 其实widget是嵌入(embedded) ...
- delphi 一个线程和主界面的交互的演示代码
求一个线程和主界面的交互的演示代码求一个线程和主界面的交互的演示代码.线程和主界面处于两个Unit.线程中的user中不能引用主窗口.我只是想学习一下,线程和主界面交互的方法.去网上查了好几天资料,能 ...
- Django与JS交互的示例代码-django js 获取 python 字典-Django 前后台的数据传递
Django与JS交互的示例代码 Django 前后台的数据传递 https://www.cnblogs.com/xibuhaohao/p/10192052.html 应用一:有时候我们想把一个 li ...
- 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)
构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...
- wifi display代码 分析
转自:http://blog.csdn.net/lilian0118/article/details/23168531 这一章中我们来看Wifi Display连接过程的建立,包含P2P的部分和RTS ...
- lighttpd与fastcgi+cgilua原理、代码分析与安装
原理 http://www.cnblogs.com/skynet/p/4173450.html 快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关 ...
- AngularJS PhoneCat代码分析
转载自:http://www.tuicool.com/articles/ym6Jfen AngularJS 官方网站提供了一个用于学习的示例项目:PhoneCat.这是一个Web应用,用户可以浏览一些 ...
- 使用 Gradle 插件进行代码分析(转)
代码分析在大多数项目中通常是作为最后一个步骤(如果做了的话)完成的.其通常难以配置及与现有代码整合. 本文旨在勾勒出使用 Gradle 整合 PMD 与 FindBugs 的步骤,并将其与一个现有的 ...
随机推荐
- 带有data-ng-bind表达式
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- android design 新控件
转载请标明出处: http://blog.csdn.net/forezp/article/details/51873137 本文出自方志朋的博客 最近在研究android 开发的新控件,包括drawe ...
- SpringBoot学习8:springboot整合freemarker
1.创建maven项目,添加pom依赖 <!--springboot项目依赖的父项目--> <parent> <groupId>org.springframewor ...
- 电话状态监听 - iOS
今天接到一个监听状态的需求,当使用 App 时若电话介入需要对当前状态进行监听操作(注:并非通话内容),根据不同的状态实行相关的需求操作,废话不多说步骤如下. 首先,常规操作先引用对应的头文件,来为后 ...
- Aspects– iOS的AOP面向切面编程的库
简介 一个简洁高效的用于使iOS支持AOP面向切面编程的库.它可以帮助你在不改变一个类或类实例的代码的前提下,有效更改类的行为.比iOS传统的 AOP方法,更加简单高效.支持在方法执行的前/后或替代原 ...
- Unicode编码字符 转换成汉字
转载:http://www.chengxuyuans.com/iPhone_IOS/48128.html - (NSString *)replaceUnicode:(NSString *)unicod ...
- java使用优先级队列实现哈夫曼编码
思路: 构建小根堆 根据小根堆实现哈夫曼树 根据哈夫曼树对数据进行编码 代码实现如下: /** * @Author: DaleyZou * @Description: 使用java实现一个哈夫曼编码的 ...
- Scott Young-《如何高效学习》
1.如果你只用一种方式了解某样事物,那么你就没有真正了解它.事情真正含义的秘密取决于我们如何将其与我们所了解的其他事情相联系.很好联系的内容可使你将想法融于脑中,从各种角度看问题,直至你找到合适自己的 ...
- 没有CTO的Netflix有哪些值得我们学习的工程文化?
作者介绍: 杨波,拍拍贷基础框架研发总监.具有超过 10 年的互联网分布式系统研发和架构经验,曾先后就职于:eBay 中国研发中心(eBay CDC),任资深研发工程师,参与亿贝开放 API 平台研发 ...
- delphi的消息对话框
delphi的消息对话框,类似VFP中的WAIT和MESSAGEBOXdelphi的消息对话框,类似VFP中的WAIT和MESSAGEBOX1.最简单的是:showmessage() 它只有一个OK按 ...