目标:
弄清楚run action原理
目录:
0 st2api调试代码前准备
1 st2api服务分析
2 关键方法publish_request分析
3 st2actionrunner调试代码前准备
4 st2actionrunner服务分析
5 总结
0 st2api调试代码前准备
将st2api容器启动命令修改
将
containers:
- command:
- bash
- -c
- exec /opt/stackstorm/st2/bin/gunicorn st2api.wsgi:application -k eventlet
-b 0.0.0.0:9101 --workers 1 --threads 1 --graceful-timeout 10 --timeout
30
修改为:
containers:
- command:
- sleep
- 3d
等待st2api的pod启动后
修改/etc/st2/st2.conf
[auth]
host = 127.0.0.1
[api]
host = 127.0.0.1
的host的值修改为0.0.0.0
原因:
服务监听127.0.0.1只有本机才可以监听,而
0.0.0.0则表示其他节点可以发送请求,这样监听服务也可以监听到其他节点的请求。
修改为:
sudo /opt/stackstorm/st2/bin/st2api --config-file /etc/st2/st2.conf
进入st2任意的pod,执行st2 login命令后,然后执行如下命令:
st2 run core.local cmd=ls
1 st2api服务分析
代码入口
/opt/stackstorm/st2/lib/python2.7/site-packages/st2api/controllers/v1/actionexecutions.py的post()
代码如下:
class ActionExecutionsController(BaseResourceIsolationControllerMixin,
ActionExecutionsControllerMixin, ResourceController):
def post(self, liveaction_api, requester_user, context_string=None, show_secrets=False):
return self._handle_schedule_execution(liveaction_api=liveaction_api,
requester_user=requester_user,
context_string=context_string,
show_secrets=show_secrets)
分析:
1.1)执行run action命令进入到
上述st2api的代码
对应输入参数样例如下:
(Pdb) p liveaction_api
<st2common.router.Body object at 0x4090e50>
(Pdb) p liveaction_api.__dict__
{u'action': u'core.local', u'user': None, u'parameters': {u'cmd': u'ls'}}
(Pdb) p requester_user
<UserDB: UserDB(id=5ed81d6197474e0001587c06, is_service=False, name="admin@example.org", nicknames={})>
(Pdb) p requester_user.__dict__
{'_cls': 'UserDB'}
(Pdb) p context_string
None
(Pdb) p show_secrets
None
1.2)继续进入
class ActionExecutionsControllerMixin(BaseRestControllerMixin):
def _handle_schedule_execution(self, liveaction_api, requester_user, context_string=None,
show_secrets=False):
"""
:param liveaction: LiveActionAPI object.
:type liveaction: :class:`LiveActionAPI`
"""
if not requester_user:
requester_user = UserDB(cfg.CONF.system_user.user)
# Assert action ref is valid
action_ref = liveaction_api.action
action_db = action_utils.get_action_by_ref(action_ref)
if not action_db:
message = 'Action "%s" cannot be found.' % action_ref
LOG.warning(message)
abort(http_client.BAD_REQUEST, message)
# Assert the permissions
assert_user_has_resource_db_permission(user_db=requester_user, resource_db=action_db,
permission_type=PermissionType.ACTION_EXECUTE)
# Validate that the authenticated user is admin if user query param is provided
user = liveaction_api.user or requester_user.name
assert_user_is_admin_if_user_query_param_is_provided(user_db=requester_user,
user=user)
try:
return self._schedule_execution(liveaction=liveaction_api,
requester_user=requester_user,
user=user,
context_string=context_string,
show_secrets=show_secrets,
pack=action_db.pack)
except ValueError as e:
LOG.exception('Unable to execute action.')
......
分析:
上述主要处理逻辑是:
根据action_ref查询得到action_db,调用_schedule_execution获取执行结果
1.3) 分析_schedule_execution方法
class ActionExecutionsControllerMixin(BaseRestControllerMixin):
def _schedule_execution(self,
liveaction,
requester_user,
user=None,
context_string=None,
show_secrets=False,
pack=None):
# Initialize execution context if it does not exist.
if not hasattr(liveaction, 'context'):
liveaction.context = dict()
liveaction.context['user'] = user
liveaction.context['pack'] = pack
LOG.debug('User is: %s' % liveaction.context['user'])
# Retrieve other st2 context from request header.
if context_string:
context = try_loads(context_string)
if not isinstance(context, dict):
raise ValueError('Unable to convert st2-context from the headers into JSON.')
liveaction.context.update(context)
# Include RBAC context (if RBAC is available and enabled)
if cfg.CONF.rbac.enable:
user_db = UserDB(name=user)
role_dbs = rbac_service.get_roles_for_user(user_db=user_db, include_remote=True)
roles = [role_db.name for role_db in role_dbs]
liveaction.context['rbac'] = {
'user': user,
'roles': roles
}
# Schedule the action execution.
liveaction_db = LiveActionAPI.to_model(liveaction)
action_db = action_utils.get_action_by_ref(liveaction_db.action)
runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])
try:
liveaction_db.parameters = param_utils.render_live_params(
runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters,
liveaction_db.context)
except param_exc.ParamException:
# We still need to create a request, so liveaction_db is assigned an ID
liveaction_db, actionexecution_db = action_service.create_request(liveaction_db)
# By this point the execution is already in the DB therefore need to mark it failed.
_, e, tb = sys.exc_info()
action_service.update_status(
liveaction=liveaction_db,
new_status=action_constants.LIVEACTION_STATUS_FAILED,
result={'error': str(e), 'traceback': ''.join(traceback.format_tb(tb, 20))})
# Might be a good idea to return the actual ActionExecution rather than bubble up
# the exception.
raise validation_exc.ValueValidationException(str(e))
# The request should be created after the above call to render_live_params
# so any templates in live parameters have a chance to render.
liveaction_db, actionexecution_db = action_service.create_request(liveaction_db)
liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)
_, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets)
return Response(json=execution_api, status=http_client.CREATED)
分析:
1)_schedule_execution方法
1 根据输入参数,形如
(Pdb) p liveaction_api
<st2common.router.Body object at 0x4090e50>
(Pdb) p liveaction_api.__dict__
{u'action': u'core.local', u'user': None, u'parameters': {u'cmd': u'ls'}}
(Pdb) p requester_user
<UserDB: UserDB(id=5ed81d6197474e0001587c06, is_service=False, name="admin@example.org", nicknames={})>
(Pdb) p requester_user.__dict__
{'_cls': 'UserDB'}
(Pdb) p context_string
None
(Pdb) p show_secrets
None
pack : core
2 根据action_ref查询得到action_db,根据runner_type名称(例如: 'local-shell-cmd')查询得到runnertype_db
3 获取action实例的参数(例如: liveaction_db.parameters{u'cmd': u'ls'})
4 调用create_request(liveaction): 创建一个action的执行,返回(liveaction, execution),具体是:
向live_action_d_b表添加或更新liveaction
创建execution
5 调用publish_request(liveaction, execution)方法,具体是:
发送liveaction消息到'st2.liveaction'这个exchange, routing_key为'create'
发送liveaction消息到'st2.liveaction.status'这个exchange, routing_key为'requested'
发送actionexecution消息到'st2.execution'这个exchange, routing_key为'create'
返回: liveaction, execution
6 将execution返回
其中最为关键的就是5 调用publish_request(liveaction, execution)方法
发送liveaction消息到'st2.liveaction.status'这个exchange, routing_key为'requested'
具体参见2的分析
2 关键方法publish_request分析
_, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
进行liveaction状态的修改,导致actionrunner接收到消息并进行处理
下面是actionrunner的日志
2020-06-05T08:36:02.974507088Z 2020-06-05 16:36:02,925 AUDIT [-] The status of action execution is changed from requested to scheduled.