hardware management 的技术发展了很多年,很多公司有自己的系统,deploy os 作为hardware management中最常用的功能之一,每个公司
可能都有几种自己的系统来完成这一操作,虽然实际的底层技术大同小异,但是每个系统封装的不同,实际扩展ironic时(ironic的确给出了一个框架,但是
有框架就有限制),需要对现有的框架有充分的认识,才能游刃有余,这其中比较晦涩的部分,当属:provision。
ironic/api/controller/v1/node.py中的provision中:
m = ir_states.machine.copy() #deep copy了一个fsm.FSM()
在ironic/common/states.py中,我们可以看到一堆类似这样的东西:
machine.add_state(MANAGEABLE, stable=True, **watchers)
machine.add_state(DEPLOYING, target=ACTIVE, **watchers)
#trace 进入 add_state:
def add_state(self, state, on_enter=None, on_exit=None, target=None, terminal=None, stable=False):
这样翻译一下add_state,对于state来说,进入和退出该state时候分别执行on_enter和on_exit方法,实际就是打了log,stable表示该状态是否是稳定状态,
即不会转移成为其他状态,只有稳定的状态才能成为target,而稳定的状态包括以下几个:manageable,available,active和error
machine.add_state(MANAGEABLE, stable=True, **watchers)
machine.add_state(AVAILABLE, stable=True, **watchers)
machine.add_state(ACTIVE, stable=True, **watchers)
machine.add_state(ERROR, stable=True, **watchers)
terminal是终止态,状态机终止,目前add_state中还没有terminal态。
machine.add_transition(AVAILABLE, DEPLOYING, 'deploy')
#trace进入add_transition:
def add_transition(self, start, end, event):
这个也很简单,主体就是一句:
self._transitions[start][event] = _Jump(end, self._states[end]['on_enter'], self._states[start]['on_exit'])
翻译一下就是:状态机在start state下,遇到event,就跳转到end state,上面的例子中,available状态遇到deploy就成为deploying状态。
再一次特别需要指出的是:
ironic是一个发展很快的项目,特别是J版到K版,变化比较大,J版很多东西都不成熟,而在K版则改进了不少,在创建node的时候K版中:
if 'uuid' not in values:
values['uuid'] = uuidutils.generate_uuid()
if 'power_state' not in values:
values['power_state'] = states.NOSTATE
if 'provision_state' not in values:
# TODO(deva): change this to ENROLL
values['provision_state'] = states.AVAILABLE #注意,在J版中,初始化provision state是NOSTATE,即“None”,K版会将NOSTATE变为available(后面会说)
接着上面provision函数:
m.initialize(rpc_node.provision_state),即:
self._current = _Jump(state, None, None)
self._target_state = self._states[state]['target'] #_state['available']['target']为None
从_add_transitions中的状态变化可以看出,对于:
if not m.is_valid_event(ir_states.VERBS.get(target, target)):
raise exception.InvalidStateRequested(
action=target, node=rpc_node.uuid,
state=rpc_node.provision_state)
available 遇到 deploy event 会变为deploying,而rebuild只有是当前provision 状态是active,或者deploy failed才会是valid event!这告诉我们什么时候
用active,什么时候用rebuild。
当target状态为active或者rebuild时,执行do_node_deploy,通过rpc call 会执行ironic/conductor/manager.py中的ConductorManager的方法:do_node_deploy!
with task_manager.acquire(context, node_id, shared=False) as task:
#得到task_manager,这其中做了几件事,trace code很容易知道:
1. task 初始化其fsm,该自动机有初始state和transition
2. 如果node不是shared,就reserve该node,对应的是node的reservation字段
3. 如果provision state是NOSTATE,就转变为available,在这儿做的!
继续trace这一过程:
1. 如果是node 是 maintenance状态就报错
2. 如果是rebuild则清空instance_info;
3. 更新driver_instance_info
4. check 该node对应的driver,power和deploy实现接口是否完整(其validation 函数执行是否通过)
5. 终于到了最关键的一步:
task.process_event(event, callback=self._spawn_worker,
call_args=(do_node_deploy, task,
self.conductor.id,
configdrive),
err_handler=provisioning_error_handler)
中task_manager中的process_event方法,传进回调函数等等,在process_event中:
self.fsm.process_event(event):trace FSM中的process_event,做了什么事?主要是得到target state:
replacement = self._transitions[current.name][event],得到replacement,event是rebuild或者active,会再次check,current.name是否可以通过event
进行状态转变,available遇到active变成deploying,active或者deploy failed遇到rebuild变成deploying,从前面add_state看到:
machine.add_state(DEPLOYING, target=ACTIVE, **watchers)
因此self._target_state变为active
6. 前面提到过使用python 的with 语法糖,是的task_manager的process_event传进去的回调函数最终会再次call do_node_deploy(此为ironic/conductor/task_manager
中的module 方法)
7.在module中的do_node_deploy中做了几件事:
1. 一旦发生错误,不论是config drive造成的,prepare造成的,还是deploy造成的,处理”fail“ event,provision state则变成deploy failed
2. new_state = task.driver.deploy.deploy(task),调用driver 的deploy方法,返回一个状态,若状态是deploy complete则处理done,变成active状态,属于stable状态
, 如果返回状态是deploy wait,则处理wait状态,self._target_state还是active,因此在deploy wait状态下会等待resume,fail,delete
3. bootloader安装成功后会和前面说的pass_deploy_info类似,image builder生成的image,对应的bootloader起来后,发一个rest call给ironic服务,调
用vendor中的”pass_bootloader_install_info“方法,让task_manager处理”resume“事件;
4. 和2中对应,FSM接收到resume后,再次变成deploying,等待接收done事件
5. 验证bootloader的状态成功后,重启机器,deploy完成后,发送done事件,deploy成功