Quantum 资源属性映射

本文地址:http://blog.csdn.net/spch2008/article/details/9712463

先前做QoS功能时,对于RESOURCE_ATTRIBUTE_MAP了解甚少,都是靠模仿者来做的。

本文针对quantum\api\v2\attributs.py中的port做相应的解释,为求简便,省略了部分属性。

'ports': {
    'id': {'allow_post': False, 'allow_put': False,
           'validate': {'type:uuid': None},
           'is_visible': True,
           'primary_key': True},
    'admin_state_up': {'allow_post': True, 'allow_put': True,
                       'default': True,
                       'convert_to': convert_to_boolean,
                       'is_visible': True},
    'mac_address': {'allow_post': True, 'allow_put': False,
                    'default': ATTR_NOT_SPECIFIED,
                    'validate': {'type:mac_address': None},
                    'enforce_policy': True,
                    'is_visible': True},
    'tenant_id': {'allow_post': True, 'allow_put': False,
                  'validate': {'type:string': None},
                  'required_by_policy': True,
                  'is_visible': True},
},
而资源属性映射的主要应用在quantum\api\v2\base.py中,结合该文件对资源属性映射进行分析。

1. allow_post 与资源创建有关。比如要新建一个端口,则会检测allow_post   

if is_create:  # POST
    for attr, attr_vals in attr_info.iteritems():
        if attr_vals['allow_post']:
            if ('default' not in attr_vals and
                attr not in res_dict):
                msg = _("Failed to parse request. Required "
                        "attribute '%s' not specified") % attr
                raise webob.exc.HTTPBadRequest(msg)
            res_dict[attr] = res_dict.get(attr,
                                          attr_vals.get('default'))
        else:
            if attr in res_dict:
                msg = _("Attribute '%s' not allowed in POST") % attr
                raise webob.exc.HTTPBadRequest(msg)
rest_dict是用户提交的创建信息。如果allow_post为True,则要求用户提交的信息中包含属性与值,比如name:spch2008。

如果允许提交信息,但用户却没有给定,如果给该属性配置了默认值“default"则取默认值,否则报错。如果不允许用户提交,而用户提交了该信息,就会报错。

2. default 如上所述,当需要用户提交创建信息,但用户没有提交时,使用默认信息。

3.allow_put 与资源更新有关。即创建以后,是否允许用户进行修改。

else:  # PUT
    for attr, attr_vals in attr_info.iteritems():
        if attr in res_dict and not attr_vals['allow_put']:
            msg = _("Cannot update read-only attribute %s") % attr
            raise webob.exc.HTTPBadRequest(msg)
如果用户提交的更改内容不允许更改,则会报错。

4.validate 验证用户给定信息是否有效

#rule  字典键值 type:uuid
for rule in attr_vals['validate']:
    res = attributes.validators[rule](res_dict[attr],
                                      attr_vals['validate'][rule])
    if res:
        msg_dict = dict(attr=attr, reason=res)
        msg = _("Invalid input for %(attr)s. "
                "Reason: %(reason)s.") % msg_dict
        raise webob.exc.HTTPBadRequest(msg)
在attribute.py中定义了许多验证器

validators = {'type:dict': _validate_dict,
              'type:dict_or_none': _validate_dict_or_none,
              'type:ip_address': _validate_ip_address,
              'type:mac_address': _validate_mac_address,
              'type:uuid': _validate_uuid,}
验证器对应相应的验证函数

def _validate_uuid(data, valid_values=None):
    if not uuidutils.is_uuid_like(data):
        msg = _("'%s' is not a valid UUID") % data
        LOG.debug(msg)
        return msg
取得对应的验证函数,验证信息是否有效。

5.convert_to将用户提交的数据转换成相应类型

if 'convert_to' in attr_vals:
    res_dict[attr] = attr_vals['convert_to'](res_dict[attr])
上述admin_state_up中要求转换成bool类型,对应于attribute.py中的函数

def convert_to_boolean(data):
    if isinstance(data, basestring):
        val = data.lower()
        if val == "true" or val == "1":
            return True
        if val == "false" or val == "0":
            return False
    elif isinstance(data, bool):
        return data
    elif isinstance(data, int):
        if data == 0:
            return False
        elif data == 1:
            return True
    msg = _("'%s' cannot be converted to boolean") % data
    raise q_exc.InvalidInput(error_message=msg)
5. is_visible 是否允许用户查看该属性

def _is_visible(self, attr):
    attr_val = self._attr_info.get(attr)
    return attr_val and attr_val['is_visible']
如果该属性不允许用户查看,则将查询结果中的该属性屏蔽掉。

6.required_by_policy 从字面上理解就是权限认证的时候需要该属性

首先看一个quantum port-show 命令

root@nova-controller:/etc/quantum# quantum port-show c5975e89-c3cb-4cce-a751-5931258c42d1 
+----------------+-----------------------------------------------------------------------------------+
| Field          | Value                                                                             |
+----------------+-----------------------------------------------------------------------------------+
| admin_state_up | True                                                                              |
| device_id      | dhcp23842b6d-1b21-5315-86af-417875e3667e-404daf26-f0a9-46a2-8fa9-dafaf112d221     |
| device_owner   | network:dhcp                                                                      |
| fixed_ips      | {"subnet_id": "262350ee-c1fd-426f-a6a5-23a90cabbf5f", "ip_address": "10.10.10.2"} |
| id             | c5975e89-c3cb-4cce-a751-5931258c42d1                                              |
| mac_address    | fa:16:3e:4e:3e:12                                                                 |
| name           | spch2008                                                                          |
| network_id     | 404daf26-f0a9-46a2-8fa9-dafaf112d221                                              |
| status         | ACTIVE                                                                            |
| tenant_id      | 9b320e2822da4461967232e938d92d18                                                  |
+----------------+-----------------------------------------------------------------------------------+
由于quantumclient支持使用名字进行查询,如下:

root@nova-controller:/etc/quantum# quantum port-show spch2008
+----------------+-----------------------------------------------------------------------------------+
| Field          | Value                                                                             |
+----------------+-----------------------------------------------------------------------------------+
| admin_state_up | True                                                                              |
| device_id      | dhcp23842b6d-1b21-5315-86af-417875e3667e-404daf26-f0a9-46a2-8fa9-dafaf112d221     |
| device_owner   | network:dhcp                                                                      |
| fixed_ips      | {"subnet_id": "262350ee-c1fd-426f-a6a5-23a90cabbf5f", "ip_address": "10.10.10.2"} |
| id             | c5975e89-c3cb-4cce-a751-5931258c42d1                                              |
| mac_address    | fa:16:3e:4e:3e:12                                                                 |
| name           | spch2008                                                                          |
| network_id     | 404daf26-f0a9-46a2-8fa9-dafaf112d221                                              |
| status         | ACTIVE                                                                            |
| tenant_id      | 9b320e2822da4461967232e938d92d18                                                  |
+----------------+-----------------------------------------------------------------------------------+
当使用名字的时候,需要到控制节点查询名字对应的id,然后在使用id进行一次查询,得到结果。可以在quantumclient\quantum\v2_0\__init__.py中

找到证据。ShowCommand类的get_data方法,调用find_resourceid_by_name_or_id,会使用list(相当于port-list)取得所有名字为spch2008的项,

如果返回结果大于1,则报错,这样得到id后,相当于port-show id。如果用户给定的是id,仍需要list去数据库中找是否包含此项。

由于只想取得id,不需要端口的其它信息,所以调用的时候指定参数fields='id'(data = obj_lister(name=name, fields='id')),由于指定了field,会过滤掉其它

内容,只保留id。但是,上一权限认证介绍过,权限认证需要相应的信息,如tenant_id等,如果没有这些验证信息,可能导致权限验证失败。所以呢,required_by_policy

字段,保证该属性在权限认证的时候存在,而最终返回给用户的时候删掉。

quantumclient通过上述方式提交的url如下:

输入名字(quantum port-show spch2008):
/v2.0/ports.json?fields=id&name=spch2008 HTTP/1.0

输入uuid(quantum port-show uuid):
/v2.0/ports.json?fields=id&id=uuid HTTP/1.0

由于quantumclient调用的是list方法去取得名字对应的id,所以到base.py中查看list对应的方法index,进而转到_items,一下为_items涉及的语句。

original_fields, fields_to_add = self._do_field_list(
            api_common.list_args(request, 'fields'))
        
filters = api_common.get_filters(request, self._attr_info,
                                 ['fields', 'sort_key', 'sort_dir',
                                  'limit', 'marker', 'page_reverse'])
kwargs = {'filters': filters,
                  'fields': original_fields}
实际上通过_do_field_list扩展了original_fields,将权限认证需要的信息加入其中,这样,最终取得的结果包含它们。

def _do_field_list(self, original_fields):
    fields_to_add = None
    if original_fields:
        fields_to_add = [attr for attr in self._policy_attrs
                         if attr not in original_fields]
        original_fields.extend(self._policy_attrs)

    return original_fields, fields_to_add
_policy_attrs为权限认证需要的信息,如果original_fields中没有,加入fields_to_add中,最终扩展到original_fields。之所以要保留

fields_to_add是因为这一部分是我们增加的,用户并不需要,等权限认证结束后,需要将这些属性去除,然后将结果返回给用户。

看一下如何去除属性,_view方法。调用该函数时,fields_to_add对应于fields_to_strip。

def _view(self, data, fields_to_strip=None):
    if not fields_to_strip:
        fields_to_strip = []

    return dict(item for item in data.iteritems()
                if (self._is_visible(item[0]) and
                    item[0] not in fields_to_strip))
主要功能是:判断是否允许显示,是否要被剔除。

7.enforce_policy 修改属性的时候,需要进行验证,验证用户是否有权限进行修改。

上一篇,介绍_build_match_rule时候,省略了这部分。

def _build_match_rule(action, target):
    
    match_rule = policy.RuleCheck('rule', action)
    resource, is_write = get_resource_and_action(action)
    if is_write:
        # assigning to variable with short name for improving readability
        res_map = attributes.RESOURCE_ATTRIBUTE_MAP
        if resource in res_map:
            for attribute_name in res_map[resource]:
                if _is_attribute_explicitly_set(attribute_name,
                                                res_map[resource],
                                                target):
                    attribute = res_map[resource][attribute_name]
                    if 'enforce_policy' in attribute and is_write:
                        attr_rule = policy.RuleCheck('rule', '%s:%s' %
                                                     (action, attribute_name))
                        match_rule = policy.AndCheck([match_rule, attr_rule])

    return match_rule
如果要更改属性切该属性有enforce_policy限制,则需要进行验证。

比如action 对应于 create_port,而attribute_name 对应于mac_address,这样,创建一个RuleCheck,对这个RuleCheck包装一下,

建立一个AndCheck,即要满足二者,才放行。

"create_port:mac_address": [["rule:admin_or_network_owner"]]
policy.json数据格式如上所示。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值