55from cloudharness_model .models import ApplicationConfig
66from cloudharness import log
77
8+ from .user_attributes import UserNotFound , _filter_attrs , _construct_attribute_tree , _compute_attributes_from_tree , get_user_attributes
89# quota tree node to hold the tree quota attributes
910
1011
11- class QuotaNode :
12- def __init__ (self , name , attrs ):
13- self .attrs = attrs
14- self .name = name
15- self .children = []
16-
17- def addChild (self , child ):
18- self .children .append (child )
19-
20-
21- def _filter_quota_attrs (attrs , valid_keys_map ):
22- # only use the attributes defined by the valid keys map
23- valid_attrs = {}
24- if attrs is None :
25- return valid_attrs
26- for key in attrs :
27- if key in valid_keys_map :
28- # map to value
29- valid_attrs .update ({key : attrs [key ][0 ]})
30- return valid_attrs
31-
32-
3312def get_group_quotas (group , application_config : ApplicationConfig ):
3413 base_quotas = application_config .get ("harness" , {}).get ("quotas" , {})
3514 valid_keys_map = {key for key in base_quotas }
36- return _compute_quotas_from_tree (_construct_quota_tree ([group ], valid_keys_map ))
37-
38-
39- def _construct_quota_tree (groups , valid_keys_map ) -> QuotaNode :
40- root = QuotaNode ("root" , {})
41- for group in groups :
42- r = root
43- paths = group ["path" ].split ("/" )[1 :]
44- # loop through all segements except the last segment
45- # the last segment is the one we want to add the attributes to
46- for segment in paths [0 : len (paths ) - 1 ]:
47- for child in r .children :
48- if child .name == segment :
49- r = child
50- break
51- else :
52- # no child found, add it with the segment name of the path
53- n = QuotaNode (segment , {})
54- r .addChild (n )
55- r = n
56- # add the child with it's attributes and last segment name
57- n = QuotaNode (
58- paths [len (paths ) - 1 ],
59- _filter_quota_attrs (group ["attributes" ], valid_keys_map )
60- )
61- r .addChild (n )
62- return root
63-
64-
65- def _compute_quotas_from_tree (node : QuotaNode ):
66- """Recursively traverse the tree and find the quota per level
67- the lower leafs overrule parent leafs values
68-
69- Args:
70- node (QuotaNode): the quota tree of QuotaNodes of the user for the given application
71-
72- Returns:
73- dict: key/value pairs of the quotas
74-
75- Example:
76- {'quota-ws-maxcpu': 1000, 'quota-ws-open': 10, 'quota-ws-max': 8}
77-
78- Algorithm explanation:
79- /Base {'quota-ws-max': 12345, 'quota-ws-maxcpu': 50, 'quota-ws-open': 1}\n
80- /Base/Base 1/Base 1 1 {'quota-ws-maxcpu': 2, 'quota-ws-open': 10}\n
81- /Base/Base 2 {'quota-ws-max': 8, 'quota-ws-maxcpu': 250}\n
82- /Low CPU {'quota-ws-max': 3, 'quota-ws-maxcpu': 1000, 'quota-ws-open': 1}\n
83-
84- result: {'quota-ws-maxcpu': 1000, 'quota-ws-open': 10, 'quota-ws-max': 8}\n
85- quota-ws-maxcpu from path "/Low CPU"\n
86- --> overrules paths "/Base/Base 1/Base 1 1" and "/Base/Base 2" (higher value)\n
87- --> /Base quota-ws-max is not used because this one is not the lowest
88- leaf with this attribute (Base 1 1 and Base 2 are "lower")\n
89- quota-ws-open from path "/Base/Base 1/Base 1 1"\n
90- quota-ws-max from path "/Base/Base 2"\n
91- """
92- new_attrs = {}
93- for child in node .children :
94- child_attrs = _compute_quotas_from_tree (child )
95- for key in child_attrs :
96- try :
97- # we expect all quota values to be numbers: the unit is implicit and
98- # defined at usage time
99- child_val = attribute_to_quota (child_attrs [key ])
100- except :
101- # value not a float, skip
102- continue
103- if not key in new_attrs or new_attrs [key ] < child_val :
104- new_attrs .update ({key : child_val })
105- for key in new_attrs :
106- node .attrs .update ({key : new_attrs [key ]})
107- return node .attrs
15+ return _compute_attributes_from_tree (_construct_attribute_tree ([group ], valid_keys_map ))
10816
10917
11018def attribute_to_quota (attr_value : str ):
@@ -126,28 +34,13 @@ def get_user_quotas(application_config: ApplicationConfig = None, user_id: str =
12634 """
12735 if not application_config :
12836 application_config = get_current_configuration ()
129-
13037 base_quotas = application_config .get ("harness" , {}).get ("quotas" , {})
131- try :
132- auth_client = AuthClient ()
133- if not user_id :
134- user_id = auth_client .get_current_user ()["id" ]
135- user = auth_client .get_user (user_id , with_details = True )
136- except KeycloakError as e :
137- log .warning ("Quotas not available: error retrieving user: %s" , user_id )
138- return base_quotas
13938
14039 valid_keys_map = {key for key in base_quotas }
14140
142- group_quotas = _compute_quotas_from_tree (
143- _construct_quota_tree (
144- user ["userGroups" ],
145- valid_keys_map ))
146- user_quotas = _filter_quota_attrs (user ["attributes" ], valid_keys_map )
147- for key in group_quotas :
148- if key not in user_quotas :
149- user_quotas .update ({key : group_quotas [key ]})
150- for key in base_quotas :
151- if key not in user_quotas :
152- user_quotas .update ({key : attribute_to_quota (base_quotas [key ])})
153- return user_quotas
41+ try :
42+ return get_user_attributes (user_id , valid_keys = valid_keys_map , default_attributes = base_quotas )
43+
44+ except UserNotFound as e :
45+ log .warning ("Quotas not available: error retrieving user: %s" , user_id )
46+ return base_quotas
0 commit comments