Statistics
| Branch: | Tag: | Revision:

root / commissioning / highlevel / api.py @ 3e7b1de1

History | View | Annotate | Download (7.5 kB)

1
from util import parent_node_name_of
2
from util import check_node_name
3
from util import check_node_key
4
from util import is_system_node
5
from util import check_context
6
from util import check_string
7
from util import method_accepts
8
from util import returns
9
from util import NameOfSystemNode
10
from util import NameOfResourcesNode
11
from util import NameOfGroupsNode
12
from util import NameOfUsersNode
13

    
14
class HighLevelAPI(object):
15
    """
16
    High-level Quota Holder API that supports definitions of resources, resource pools, groups and users and
17
    the transfer of resource quotas from respective pools to both groups and users.
18
    """
19

    
20
    def __init__(self, qh, **kwd):
21
        self.__qh = qh
22
        self.__context = check_context(kwd.get('context') or {})
23
        self.__node_keys = {
24
            NameOfSystemNode: check_string('system_key', kwd.get('system_key') or ''),
25
            NameOfResourcesNode: check_string('resources_key', kwd.get('resources_key') or ''),
26
            NameOfGroupsNode: check_string('groups_key', kwd.get('groups_key') or '')
27
        }
28

    
29

    
30
    @method_accepts(str)
31
    @returns(str)
32
    def get_cached_node_key(self, node_name):
33
        check_node_name(node_name)
34
        return self.__node_keys.get(node_name) or '' # sane default
35

    
36

    
37
    @method_accepts(str, str)
38
    @returns(type(None))
39
    def set_cached_node_key(self, node_name, node_key):
40
        check_node_name(node_name)
41
        check_node_key(node_key)
42
        if node_key is None:
43
            node_key = ''
44
        self.__node_keys[node_name] = node_key
45

    
46

    
47
    @returns(dict)
48
    def node_keys(self):
49
        return self.__node_keys.copy() # Client cannot mess with the original
50

    
51

    
52
    @method_accepts(str)
53
    @returns(str)
54
    def qh_create_node(self, node_name):
55
        check_node_name(node_name)
56
        if is_system_node(node_name):
57
            return node_name
58

    
59
        parent_node_name = parent_node_name_of(node_name)
60
        self.ensure_node(parent_node_name) # Recursively create hierarchy. Beware the keys must be known.
61

    
62
        node_key = self.get_cached_node_key(node_name)
63
        parent_node_key = self.get_cached_node_key(parent_node_name)
64

    
65
        rejected = self.__qh.create_entity(
66
            context=self.__context,
67
            create_entity=[
68
                (
69
                    node_name,
70
                    parent_node_name,
71
                    node_key,
72
                    parent_node_key
73
                    )
74
            ]
75
        )
76
        if(len(rejected) > 0):
77
            raise Exception("Could not create node '%s'" % (node_name,))
78
        else:
79
            return node_name
80

    
81

    
82
    @method_accepts(str)
83
    @returns(str)
84
    def ensure_node(self, node_name):
85
        if not self.qh_has_node(node_name):
86
            return self.qh_create_node(node_name)
87
        else:
88
            return node_name
89

    
90

    
91
    @method_accepts(str)
92
    @returns(bool)
93
    def qh_has_node(self, node_name):
94
        check_node_name(node_name)
95
        node_key = self.get_cached_node_key(node_name)
96
        entity_owner_list = self.__qh.get_entity(
97
            context=self.__context,
98
            get_entity=[(node_name, node_key)]
99
        )
100
        return len(entity_owner_list) == 1 # TODO: any other check here?
101

    
102

    
103
    @returns(str)
104
    def ensure_resources_node(self):
105
        """
106
        Ensure that the node 'system/resources' exists.
107
        """
108
        return self.ensure_node(NameOfResourcesNode)
109

    
110

    
111
    @returns(str)
112
    def ensure_groups_node(self):
113
        """
114
        Ensure that the node 'system/groups' exists.
115
        """
116
        return self.ensure_node(NameOfGroupsNode)
117

    
118

    
119
    @returns(str)
120
    def ensure_users_node(self):
121
        """
122
        Ensure that the node 'system/users' exists.
123
        """
124
        return self.ensure_node(NameOfUsersNode)
125

    
126

    
127
    @method_accepts(str, str)
128
    @returns(str)
129
    def normalize_child_node_name(self, child_node_name, parent_node_name):
130
        check_node_name(child_node_name)
131
        check_node_name(parent_node_name)
132
        last_part_child_node_name = self.last_part_of_node_name(child_node_name)
133
        normalized_child_node_name = '%s/%s' % (
134
            parent_node_name,
135
            last_part_child_node_name
136
        ) # recreate full node name
137
        return normalized_child_node_name
138

    
139

    
140
    @method_accepts(str)
141
    @returns(str)
142
    def normalize_group_node_name(self, group_node_name):
143
        return self.normalize_child_node_name(group_node_name, NameOfGroupsNode)
144

    
145

    
146
    @method_accepts(str)
147
    @returns(str)
148
    def last_part_of_node_name(self, node_name):
149
        """
150
        Collapses a full node name to its last part, that is the name after the last slash,
151
        and returns that last part.
152

153
        So, a name 'system/groups/foogrooop' is collapsed to 'foogrooop' and the
154
        latter is returned.
155
        """
156
        check_node_name(node_name)
157
        bottom_node_name = node_name.split('/')[-1:] # collapse and keep the last part
158
        return bottom_node_name
159

    
160

    
161
    @method_accepts(str, str)
162
    @returns(str)
163
    def create_group(self, group_node_name, group_node_key):
164
        """
165
        Creates a new group under 'system/groups'.
166

167
        The ``group_node_name`` can either be a full path (e.g. 'system/groups/mygroup') or just the last part
168
        (e.g. 'mygroup'). Note that if it is the full path, then everything but the last part is ignored.
169
        You must always use the returned ``group_node_name`` as the most authoritative value instead of
170
        the one passed as a parameter.
171

172
        No further resource assignment is done, you must use ````.
173

174
        ``group_name`` - The name of the new group.
175
        ``group_key``  - The key (password) for the new group.
176

177
        :type group_node_key: str
178
        :type group_node_name: str
179
        """
180
        check_node_name(group_node_name)
181
        check_node_key(group_node_key)
182

    
183
        groups_node_name = self.ensure_groups_node()
184

    
185
        group_node_name = self.normalize_group_node_name(group_node_name) # We are forgiving...
186
        group_node_name = self.qh_create_node(
187
            group_node_name,
188
            groups_node_name,
189
            group_node_key,
190
            self.__groups_key)
191
        self.set_cached_node_key(group_node_name, group_node_key)
192

    
193
        return group_node_name
194

    
195

    
196
    @method_accepts(str, str, int, int, int)
197
    @returns(str)
198
    def group_define_resource(self,
199
                              group_node_name,
200
                              resource_node_name,
201
                              limit_per_user,
202
                              bucket_quantity,
203
                              bucket_capacity):
204
        """
205
        Defines a resource that a group provides to its users.
206
        """
207
        check_node_name(group_node_name)
208
        check_node_name(resource_node_name)
209

    
210
        # 1. Create a definitional resource node under the group.
211
        #    This resource defines the limit per user.
212
        #    E.g. A resource named 'pithos+' gives rise to a resource/node named 'def_pithos+'
213
        last_resource_node_name = self.last_part_of_node_name(resource_node_name)
214
        def_last_resource_node_name = 'def_%s' % (last_resource_node_name,)
215
        def_resource_node_name = self.normalize_child_node_name(
216
            def_last_resource_node_name,
217
            group_node_name
218
        )
219
        if not self.qh_has_node(def_resource_node_name):
220
            def_resource_node_name = self.qh_create_node(def_resource_node_name)
221
        # TODO: make policy with the limit
222

    
223
        # 2. Create the operational resource node under the group.
224
        #    This resource is a big bucket with the operational quantity and capacity.
225
        #    Everything is put into and out of this bucket.
226

    
227

    
228

    
229