@@ -10,8 +10,7 @@ def get_capacity_per_flavor(placement_client, flavors):
10
10
capacity_per_flavor = {}
11
11
12
12
for flavor in flavors :
13
- resources , traits = get_placement_request (flavor )
14
- max_per_host = get_max_per_host (placement_client , resources , traits )
13
+ max_per_host = get_max_per_host (placement_client , flavor )
15
14
capacity_per_flavor [flavor .name ] = max_per_host
16
15
17
16
return capacity_per_flavor
@@ -46,7 +45,8 @@ def add_defaults(resources, flavor, skip_vcpu=False):
46
45
return resources , required_traits
47
46
48
47
49
- def get_max_per_host (placement_client , resources , required_traits ):
48
+ def get_max_per_host (placement_client , flavor ):
49
+ resources , required_traits = get_placement_request (flavor )
50
50
resource_str = "," .join (
51
51
[key + ":" + str (value ) for key , value in resources .items () if value ]
52
52
)
@@ -80,7 +80,7 @@ def get_max_per_host(placement_client, resources, required_traits):
80
80
if max_counts :
81
81
count_per_rp [rp_uuid ] = min (max_counts )
82
82
if not count_per_rp :
83
- print (f"# WARNING - no candidates for: { params } " )
83
+ print (f"# WARNING - no candidates hosts for flavor: { flavor . name } { params } " )
84
84
return count_per_rp
85
85
86
86
@@ -178,12 +178,52 @@ def print_host_details(compute_client, placement_client):
178
178
for project , names in project_to_aggregate .items ():
179
179
for name in names :
180
180
print (
181
- f'openstack_project_filter_aggregate{{project ="{ project } ",aggregate="{ name } "}} 1'
181
+ f'openstack_project_filter_aggregate{{project_id ="{ project } ",aggregate="{ name } "}} 1'
182
182
)
183
183
184
184
185
- def print_project_usage_ (indentity_client , placement_client ):
186
- pass
185
+ def print_project_usage (indentity_client , placement_client , compute_client ):
186
+ projects = {proj .id : dict (name = proj .name ) for proj in indentity_client .projects ()}
187
+ for project_id in projects .keys ():
188
+ # TODO(johngarbutt) On Xena we should do consumer_type=INSTANCE using 1.38!
189
+ response = placement_client .get (
190
+ f"/usages?project_id={ project_id } " ,
191
+ headers = {"OpenStack-API-Version" : "placement 1.19" },
192
+ )
193
+ response .raise_for_status ()
194
+ usages = response .json ()
195
+ projects [project_id ]["usages" ] = usages ["usages" ]
196
+
197
+ response = compute_client .get (
198
+ f"/os-quota-sets/{ project_id } " ,
199
+ headers = {"OpenStack-API-Version" : "compute 2.20" },
200
+ )
201
+ response .raise_for_status ()
202
+ quotas = response .json ().get ("quota_set" , {})
203
+ projects [project_id ]["quotas" ] = dict (
204
+ CPUS = quotas .get ("cores" ), MEMORY_MB = quotas .get ("ram" )
205
+ )
206
+
207
+ # print(json.dumps(projects, indent=2))
208
+ for project_id , data in projects .items ():
209
+ name = data ["name" ]
210
+ project_usages = data ["usages" ]
211
+ for resource , amount in project_usages .items ():
212
+ print (
213
+ f'openstack_project_usage{{project_id="{ project_id } ",'
214
+ f'project_name="{ name } ",resource="{ resource } "}} { amount } '
215
+ )
216
+
217
+ if not project_usages :
218
+ # skip projects with zero usage?
219
+ print (f"# WARNING no usage for project: { name } { project_id } " )
220
+ continue
221
+ project_quotas = data ["quotas" ]
222
+ for resource , amount in project_quotas .items ():
223
+ print (
224
+ f'openstack_project_quota{{project_id="{ project_id } ",'
225
+ f'project_name="{ name } ",resource="{ resource } "}} { amount } '
226
+ )
187
227
188
228
189
229
def print_exporter_data (app ):
@@ -193,3 +233,4 @@ def print_exporter_data(app):
193
233
if __name__ == "__main__" :
194
234
conn = openstack .connect ()
195
235
print_host_details (conn .compute , conn .placement )
236
+ print_project_usage (conn .identity , conn .placement , conn .compute )
0 commit comments