heat使用trust流程简析
heat是openstack中的一个编排模块,里面有一个比较有意思的特性:弹性伸缩。但是当heat触发弹性伸的时候,如果遇到创建虚拟机,则应该使用创建这个弹性伸缩组的用户/租户的权限来进行创建。这就要求heat需要保存创建弹性伸缩组的用户信息,并且连密码也需要保存,这种方式比较古老。 通过keystone v3提供的新特性:trust,可以授权指定用户具有某一个...
heat是openstack中的一个编排模块,里面有一个比较有意思的特性:弹性伸缩。
但是当heat触发弹性伸的时候,如果遇到创建虚拟机,则应该使用创建这个弹性伸缩组的用户/租户的权限来进行创建。
这就要求heat需要保存创建弹性伸缩组的用户信息,并且连密码也需要保存,这种方式比较古老。
通过keystone v3提供的新特性:trust,可以授权指定用户具有某一个项目下的特定操作权限。
本文主要描述了下该trust在heat中的简单流程。
一、api入口
位于 heat/api/openstack/v1/stacks.py 中的 create 方法
@util.policy_enforce
def create(self, req, body):
data = InstantiationData(body)
args = self.prepare_args(data)
result = self.rpc_client.create_stack(
req.context,
data.stack_name(),
data.template(),
data.environment(),
data.files(),
args,
environment_files=data.environment_files())
formatted_stack = stacks_view.format_stack(
req,
{rpc_api.STACK_ID: result}
)
return {'stack': formatted_stack}
二、通过rpc走到heat-engine中的service回调接口
路径:heat/engine/service.py
@context.request_context
def create_stack(self, cnxt, stack_name, template, params, files,
args, environment_files=None,
owner_id=None, nested_depth=0, user_creds_id=None,
stack_user_project_id=None, parent_resource_name=None,
template_id=None):
"""Create a new stack using the template provided.
Note that at this stage the template has already been fetched from the
heat-api process if using a template-url.
:param cnxt: RPC context.
:param stack_name: Name of the stack you want to create.
:param template: Template of stack you want to create.
:param params: Stack Input Params
:param files: Files referenced from the template
:param args: Request parameters/args passed from API
:param environment_files: optional ordered list of environment file
names included in the files dict
:type environment_files: list or None
:param owner_id: parent stack ID for nested stacks, only expected when
called from another heat-engine (not a user option)
:param nested_depth: the nested depth for nested stacks, only expected
when called from another heat-engine
:param user_creds_id: the parent user_creds record for nested stacks
:param stack_user_project_id: the parent stack_user_project_id for
nested stacks
:param parent_resource_name: the parent resource name
:param template_id: the ID of a pre-stored template in the DB
"""
LOG.info(_LI('Creating stack %s'), stack_name)
def _create_stack_user(stack):
if not stack.stack_user_project_id:
try:
stack.create_stack_user_project_id()
except exception.AuthorizationFailure as ex:
stack.state_set(stack.action, stack.FAILED,
six.text_type(ex))
def _stack_create(stack, msg_queue=None):
# Create/Adopt a stack, and create the periodic task if successful
if stack.adopt_stack_data:
stack.adopt()
elif stack.status != stack.FAILED:
stack.create(msg_queue=msg_queue)
if (stack.action in (stack.CREATE, stack.ADOPT)
and stack.status == stack.COMPLETE):
if self.stack_watch:
# Schedule a periodic watcher task for this stack
self.stack_watch.start_watch_task(stack.id, cnxt)
else:
LOG.info(_LI("Stack create failed, status %s"), stack.status)
convergence = cfg.CONF.convergence_engine
stack = self._parse_template_and_validate_stack(
cnxt, stack_name, template, params, files, environment_files,
args, owner_id, nested_depth, user_creds_id,
stack_user_project_id, convergence, parent_resource_name,
template_id)
self.resource_enforcer.enforce_stack(stack)
# 这里创建trust
stack_id = stack.store()
if cfg.CONF.reauthentication_auth_method == 'trusts':
stack = parser.Stack.load(
cnxt, stack_id=stack_id, use_stored_context=True)
_create_stack_user(stack)
if convergence:
action = stack.CREATE
if stack.adopt_stack_data:
action = stack.ADOPT
stack.thread_group_mgr = self.thread_group_mgr
stack.converge_stack(template=stack.t, action=action)
else:
msg_queue = eventlet.queue.LightQueue()
th = self.thread_group_mgr.start_with_lock(cnxt, stack,
self.engine_id,
_stack_create, stack,
msg_queue=msg_queue)
th.link(self.thread_group_mgr.remove_msg_queue,
stack.id, msg_queue)
self.thread_group_mgr.add_msg_queue(stack.id, msg_queue)
return dict(stack.identifier())
三、保存栈信息,并创建信任授权信息
@profiler.trace('Stack.store', hide_args=False)
def store(self, backup=False, exp_trvsl=None,
ignore_traversal_check=False):
"""Store the stack in the database and return its ID.
If self.id is set, we update the existing stack.
"""
s = self.get_kwargs_for_cloning(keep_status=True, only_db=True)
s['name'] = self.name
s['backup'] = backup
s['updated_at'] = self.updated_time
if self.t.id is None:
stack_object.Stack.encrypt_hidden_parameters(self.t)
s['raw_template_id'] = self.t.store(self.context)
else:
s['raw_template_id'] = self.t.id
if self.id:
if exp_trvsl is None and not ignore_traversal_check:
exp_trvsl = self.current_traversal
if self.convergence:
# do things differently for convergence
updated = stack_object.Stack.select_and_update(
self.context, self.id, s, exp_trvsl=exp_trvsl)
if not updated:
return None
else:
stack_object.Stack.update_by_id(self.context, self.id, s)
else:
if not self.user_creds_id:
# Create a context containing a trust_id and trustor_user_id
# if trusts are enabled
# 调用keystone 的代码,使用trust创建租户间的信任
# create_trust_context 里面即为trust授权,具体的流程机制见文档末尾的链接
if cfg.CONF.deferred_auth_method == 'trusts':
keystone = self.clients.client('keystone')
trust_ctx = keystone.create_trust_context()
new_creds = ucreds_object.UserCreds.create(trust_ctx)
else:
new_creds = ucreds_object.UserCreds.create(self.context)
s['user_creds_id'] = new_creds.id
self.user_creds_id = new_creds.id
if self.convergence:
# create a traversal ID
self.current_traversal = uuidutils.generate_uuid()
s['current_traversal'] = self.current_traversal
new_s = stack_object.Stack.create(self.context, s)
self.id = new_s.id
self.created_time = new_s.created_at
if self.tags:
stack_tag_object.StackTagList.set(self.context, self.id, self.tags)
self._set_param_stackid()
return self.id
四、相关资料
openstack keystone trust信任机制相关资料:
http://www.tuicool.com/articles/N3aM7b
https://docs.openstack.org/admin-guide/orchestration-auth-model.html
更多推荐
所有评论(0)