~ubuntu-cloud-archive/ubuntu/precise/quantum/folsom

« back to all changes in this revision

Viewing changes to quantum/policy.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandelman, Chuck Short
  • Date: 2012-09-12 13:41:20 UTC
  • mfrom: (2.1.12)
  • Revision ID: package-import@ubuntu.com-20120912134120-sheqxy7c2q5x7m34
Tags: 2012.2~rc1-0ubuntu1
[ Adam Gandelman ]
* debain/*.postrm: Fix argument-less calls to update-rc.d, redirect
  to /dev/null.  (LP: #1047560)
* debian/quantum-server.upstart: Invoke start-stop-daemon properly.
  (LP: #1047404)
* debain/*.postrm, *.upstart: Ensure files are named for corresponding
  agent package, not plugin package.
* debian/control:
  - Group agents with plugins.
  - Fix some copy/paste mistakes.
  - Set dependencies between agents and corresponding plugins.
  - Recommend quantum-plugin-openvswitch for quantum-server.
  - Require the same version of quantum-common and python-quantum.
  - Add quantum-netns-cleanup utility to quantum-common.
* debian/patches/fix-quantum-configuration.patch: Use correct database
  for linuxbridge plugin, use OVS plugin by default, call quantum-rootwrap
  correctly. (LP: #1048668)
* Fix all use of /usr/sbin, things should go in /usr/bin.
* Remove dhcp and l3 plugins, they are not actually plugins.
* Rename packages quantum-plugin-{l3, dhcp}-agent to
  quantum-{l3, dhcp}-agent.
* debain/quantum-*-agent.upstart: Specify config files as a
  parameter to --config-file, specify log files for all.
* debian/*.logrotate: Add logrotate configs for server and agents.
* Install quantum_sudoers with quantum-common, not quantum-server.
* Install rootwrap filters only with the packages that require them.
* debian/*-agent.upstart: Specify --config-file=/etc/quantum/quantum.conf
  in addition to plugin-specific config.  Specify log files for all agents.
* Allow group 'adm' read access to /var/log/quantum.
* debian/quantum-server.postinst: Drop, all has been moved to quantum-common.
* Add packaging for quantum-plugin-nec.

[ Chuck Short ]
* New usptream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
"""
19
19
Policy engine for quantum.  Largely copied from nova.
20
20
"""
 
21
import logging
 
22
 
21
23
from quantum.api.v2 import attributes
22
24
from quantum.common import exceptions
23
25
from quantum.openstack.common import cfg
24
26
import quantum.common.utils as utils
25
27
from quantum.openstack.common import policy
26
28
 
 
29
 
 
30
LOG = logging.getLogger(__name__)
27
31
_POLICY_PATH = None
28
32
_POLICY_CACHE = {}
29
33
 
49
53
                           reload_func=_set_brain)
50
54
 
51
55
 
 
56
def get_resource_and_action(action):
 
57
    """ Extract resource and action (write, read) from api operation """
 
58
    data = action.split(':', 1)[0].split('_', 1)
 
59
    return ("%ss" % data[-1], data[0] != 'get')
 
60
 
 
61
 
52
62
def _set_brain(data):
53
63
    default_rule = 'default'
54
64
    policy.set_brain(policy.Brain.load_json(data, default_rule))
55
65
 
56
66
 
57
 
def _get_resource_and_action(action):
58
 
    data = action.split(':', 1)[0].split('_', 1)
59
 
    return ("%ss" % data[-1], data[0] != 'get')
60
 
 
61
 
 
62
67
def _is_attribute_explicitly_set(attribute_name, resource, target):
63
68
    """Verify that an attribute is present and has a non-default value"""
64
69
    if ('default' in resource[attribute_name] and
76
81
    "parent" resource of the targeted one.
77
82
    """
78
83
    target = original_target.copy()
79
 
    resource, _w = _get_resource_and_action(action)
 
84
    resource, _a = get_resource_and_action(action)
80
85
    hierarchy_info = attributes.RESOURCE_HIERARCHY_MAP.get(resource, None)
81
86
    if hierarchy_info and plugin:
82
87
        # use the 'singular' version of the resource name
90
95
    return target
91
96
 
92
97
 
93
 
def _create_access_rule_match(resource, is_write, shared):
94
 
    if shared == resource[attributes.SHARED]:
95
 
        return ('rule:%s:%s:%s' % (resource,
96
 
                                   shared and 'shared' or 'private',
97
 
                                   is_write and 'write' or 'read'), )
98
 
 
99
 
 
100
 
def _build_perm_match(action, target):
101
 
    """Create the permission rule match.
102
 
 
103
 
    Given the current access right on a network (shared/private), and
104
 
    the type of the current operation (read/write), builds a match
105
 
    rule of the type <resource>:<sharing_mode>:<operation_type>
106
 
    """
107
 
    resource, is_write = _get_resource_and_action(action)
108
 
    res_map = attributes.RESOURCE_ATTRIBUTE_MAP
109
 
    if (resource in res_map and
110
 
            attributes.SHARED in res_map[resource] and
111
 
            attributes.SHARED in target):
112
 
        return ('rule:%s:%s:%s' % (resource,
113
 
                                   target[attributes.SHARED]
114
 
                                   and 'shared' or 'private',
115
 
                                   is_write and 'write' or 'read'), )
116
 
 
117
 
 
118
98
def _build_match_list(action, target):
119
99
    """Create the list of rules to match for a given action.
120
100
 
127
107
    """
128
108
 
129
109
    match_list = ('rule:%s' % action,)
130
 
    resource, is_write = _get_resource_and_action(action)
131
 
    # assigning to variable with short name for improving readability
132
 
    res_map = attributes.RESOURCE_ATTRIBUTE_MAP
133
 
    if resource in res_map:
134
 
        for attribute_name in res_map[resource]:
135
 
            if _is_attribute_explicitly_set(attribute_name,
136
 
                                            res_map[resource],
137
 
                                            target):
138
 
                attribute = res_map[resource][attribute_name]
139
 
                if 'enforce_policy' in attribute and is_write:
140
 
                    match_list += ('rule:%s:%s' % (action,
141
 
                                                   attribute_name),)
142
 
    # add permission-based rule (for shared resources)
143
 
    perm_match = _build_perm_match(action, target)
144
 
    if perm_match:
145
 
        match_list += perm_match
146
 
    # the policy engine must AND between all the rules
 
110
    resource, is_write = get_resource_and_action(action)
 
111
    if is_write:
 
112
        # assigning to variable with short name for improving readability
 
113
        res_map = attributes.RESOURCE_ATTRIBUTE_MAP
 
114
        if resource in res_map:
 
115
            for attribute_name in res_map[resource]:
 
116
                if _is_attribute_explicitly_set(attribute_name,
 
117
                                                res_map[resource],
 
118
                                                target):
 
119
                    attribute = res_map[resource][attribute_name]
 
120
                    if 'enforce_policy' in attribute and is_write:
 
121
                        match_list += ('rule:%s:%s' % (action,
 
122
                                                       attribute_name),)
147
123
    return [match_list]
148
124
 
149
125
 
 
126
@policy.register('field')
 
127
def check_field(brain, match_kind, match, target_dict, cred_dict):
 
128
    # If this method is invoked for the wrong kind of match
 
129
    # which should never happen, just skip the check and don't
 
130
    # fail the policy evaluation
 
131
    if match_kind != 'field':
 
132
        LOG.warning("Field check function invoked with wrong match_kind:%s",
 
133
                    match_kind)
 
134
        return True
 
135
    resource, field_value = match.split(':', 1)
 
136
    field, value = field_value.split('=', 1)
 
137
    target_value = target_dict.get(field)
 
138
    # target_value might be a boolean, explicitly compare with None
 
139
    if target_value is None:
 
140
        LOG.debug("Unable to find requested field: %s in target: %s",
 
141
                  field, target_dict)
 
142
        return False
 
143
    # Value migth need conversion - we need help from the attribute map
 
144
    conv_func = attributes.RESOURCE_ATTRIBUTE_MAP[resource][field].get(
 
145
        'convert_to', lambda x: x)
 
146
    if target_value != conv_func(value):
 
147
        LOG.debug("%s does not match the value in the target object:%s",
 
148
                  conv_func(value), target_value)
 
149
        return False
 
150
    # If we manage to get here, the policy check is successful
 
151
    return True
 
152
 
 
153
 
150
154
def check(context, action, target, plugin=None):
151
155
    """Verifies that the action is valid on the target in this context.
152
156
 
184
188
    """
185
189
 
186
190
    init()
187
 
 
188
191
    real_target = _build_target(action, target, plugin, context)
189
192
    match_list = _build_match_list(action, real_target)
190
193
    credentials = context.to_dict()
191
 
 
192
194
    policy.enforce(match_list, real_target, credentials,
193
195
                   exceptions.PolicyNotAuthorized, action=action)