root / snf-cyclades-app / synnefo / admin / stats.py @ d58ea30a
History | View | Annotate | Download (9.6 kB)
1 | bda47e03 | Christos Stavrakakis | # Copyright 2013 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | bda47e03 | Christos Stavrakakis | #
|
3 | bda47e03 | Christos Stavrakakis | # Redistribution and use in source and binary forms, with or
|
4 | bda47e03 | Christos Stavrakakis | # without modification, are permitted provided that the following
|
5 | bda47e03 | Christos Stavrakakis | # conditions are met:
|
6 | bda47e03 | Christos Stavrakakis | #
|
7 | bda47e03 | Christos Stavrakakis | # 1. Redistributions of source code must retain the above
|
8 | bda47e03 | Christos Stavrakakis | # copyright notice, this list of conditions and the following
|
9 | bda47e03 | Christos Stavrakakis | # disclaimer.
|
10 | bda47e03 | Christos Stavrakakis | #
|
11 | bda47e03 | Christos Stavrakakis | # 2. Redistributions in binary form must reproduce the above
|
12 | bda47e03 | Christos Stavrakakis | # copyright notice, this list of conditions and the following
|
13 | bda47e03 | Christos Stavrakakis | # disclaimer in the documentation and/or other materials
|
14 | bda47e03 | Christos Stavrakakis | # provided with the distribution.
|
15 | bda47e03 | Christos Stavrakakis | #
|
16 | bda47e03 | Christos Stavrakakis | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | bda47e03 | Christos Stavrakakis | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | bda47e03 | Christos Stavrakakis | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | bda47e03 | Christos Stavrakakis | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | bda47e03 | Christos Stavrakakis | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | bda47e03 | Christos Stavrakakis | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | bda47e03 | Christos Stavrakakis | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | bda47e03 | Christos Stavrakakis | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | bda47e03 | Christos Stavrakakis | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | bda47e03 | Christos Stavrakakis | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | bda47e03 | Christos Stavrakakis | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | bda47e03 | Christos Stavrakakis | # POSSIBILITY OF SUCH DAMAGE.
|
28 | bda47e03 | Christos Stavrakakis | #
|
29 | bda47e03 | Christos Stavrakakis | # The views and conclusions contained in the software and
|
30 | bda47e03 | Christos Stavrakakis | # documentation are those of the authors and should not be
|
31 | bda47e03 | Christos Stavrakakis | # interpreted as representing official policies, either expressed
|
32 | bda47e03 | Christos Stavrakakis | # or implied, of GRNET S.A.
|
33 | bda47e03 | Christos Stavrakakis | |
34 | bda47e03 | Christos Stavrakakis | |
35 | bda47e03 | Christos Stavrakakis | import itertools |
36 | bda47e03 | Christos Stavrakakis | import operator |
37 | bda47e03 | Christos Stavrakakis | import datetime |
38 | bda47e03 | Christos Stavrakakis | |
39 | bda47e03 | Christos Stavrakakis | from collections import defaultdict # , OrderedDict |
40 | bda47e03 | Christos Stavrakakis | from copy import copy |
41 | bda47e03 | Christos Stavrakakis | from django.conf import settings |
42 | bda47e03 | Christos Stavrakakis | from django.db.models import Count, Sum |
43 | bda47e03 | Christos Stavrakakis | |
44 | bda47e03 | Christos Stavrakakis | from snf_django.lib.astakos import UserCache |
45 | bda47e03 | Christos Stavrakakis | from synnefo.db.models import VirtualMachine, Network, Backend |
46 | e780930a | Christos Stavrakakis | from synnefo.plankton.utils import image_backend |
47 | bda47e03 | Christos Stavrakakis | from synnefo.logic import backend as backend_mod |
48 | bda47e03 | Christos Stavrakakis | |
49 | bda47e03 | Christos Stavrakakis | |
50 | bda47e03 | Christos Stavrakakis | def get_cyclades_stats(backend=None, clusters=True, servers=True, |
51 | bda47e03 | Christos Stavrakakis | resources=True, networks=True, images=True): |
52 | bda47e03 | Christos Stavrakakis | stats = {"datetime": datetime.datetime.now().strftime("%c")} |
53 | bda47e03 | Christos Stavrakakis | if clusters:
|
54 | bda47e03 | Christos Stavrakakis | stats["clusters"] = get_cluster_stats(backend=backend)
|
55 | bda47e03 | Christos Stavrakakis | if servers:
|
56 | bda47e03 | Christos Stavrakakis | stats["servers"] = get_servers_stats(backend=backend)
|
57 | bda47e03 | Christos Stavrakakis | if resources:
|
58 | bda47e03 | Christos Stavrakakis | stats["resources"] = get_resources_stats(backend=backend)
|
59 | bda47e03 | Christos Stavrakakis | if networks:
|
60 | bda47e03 | Christos Stavrakakis | stats["networks"] = get_networks_stats()
|
61 | bda47e03 | Christos Stavrakakis | if images:
|
62 | bda47e03 | Christos Stavrakakis | stats["images"] = get_images_stats(backend=None) |
63 | bda47e03 | Christos Stavrakakis | return stats
|
64 | bda47e03 | Christos Stavrakakis | |
65 | bda47e03 | Christos Stavrakakis | |
66 | bda47e03 | Christos Stavrakakis | def get_cluster_stats(backend): |
67 | bda47e03 | Christos Stavrakakis | total = Backend.objects.all() |
68 | bda47e03 | Christos Stavrakakis | stats = {"total": total.count(),
|
69 | bda47e03 | Christos Stavrakakis | "drained": total.filter(drained=True).count(), |
70 | bda47e03 | Christos Stavrakakis | "offline": total.filter(offline=True).count()} |
71 | bda47e03 | Christos Stavrakakis | return stats
|
72 | bda47e03 | Christos Stavrakakis | |
73 | bda47e03 | Christos Stavrakakis | |
74 | bda47e03 | Christos Stavrakakis | def _get_total_servers(backend=None): |
75 | bda47e03 | Christos Stavrakakis | total_servers = VirtualMachine.objects.all() |
76 | bda47e03 | Christos Stavrakakis | if backend is not None: |
77 | bda47e03 | Christos Stavrakakis | total_servers = total_servers.filter(backend=backend) |
78 | bda47e03 | Christos Stavrakakis | return total_servers
|
79 | bda47e03 | Christos Stavrakakis | |
80 | bda47e03 | Christos Stavrakakis | |
81 | bda47e03 | Christos Stavrakakis | def get_servers_stats(backend=None): |
82 | bda47e03 | Christos Stavrakakis | total_servers = _get_total_servers(backend=backend) |
83 | bda47e03 | Christos Stavrakakis | per_state = total_servers.values("operstate")\
|
84 | bda47e03 | Christos Stavrakakis | .annotate(count=Count("operstate"))
|
85 | bda47e03 | Christos Stavrakakis | stats = {"total": 0} |
86 | bda47e03 | Christos Stavrakakis | [stats.setdefault(s[0], 0) for s in VirtualMachine.OPER_STATES] |
87 | bda47e03 | Christos Stavrakakis | for x in per_state: |
88 | bda47e03 | Christos Stavrakakis | stats[x["operstate"]] = x["count"] |
89 | bda47e03 | Christos Stavrakakis | stats["total"] += x["count"] |
90 | bda47e03 | Christos Stavrakakis | return stats
|
91 | bda47e03 | Christos Stavrakakis | |
92 | bda47e03 | Christos Stavrakakis | |
93 | bda47e03 | Christos Stavrakakis | def get_resources_stats(backend=None): |
94 | bda47e03 | Christos Stavrakakis | total_servers = _get_total_servers(backend=backend) |
95 | bda47e03 | Christos Stavrakakis | active_servers = total_servers.filter(deleted=False)
|
96 | bda47e03 | Christos Stavrakakis | |
97 | bda47e03 | Christos Stavrakakis | allocated = {} |
98 | bda47e03 | Christos Stavrakakis | server_count = {} |
99 | bda47e03 | Christos Stavrakakis | for res in ["cpu", "ram", "disk", "disk_template"]: |
100 | bda47e03 | Christos Stavrakakis | server_count[res] = {} |
101 | bda47e03 | Christos Stavrakakis | allocated[res] = 0
|
102 | bda47e03 | Christos Stavrakakis | val = "flavor__%s" % res
|
103 | bda47e03 | Christos Stavrakakis | results = active_servers.values(val).annotate(count=Count(val)) |
104 | bda47e03 | Christos Stavrakakis | for result in results: |
105 | bda47e03 | Christos Stavrakakis | server_count[res][result[val]] = result["count"]
|
106 | bda47e03 | Christos Stavrakakis | if res != "disk_template": |
107 | 776b42a6 | Christos Stavrakakis | prod = (result["count"] * int(result[val])) |
108 | 776b42a6 | Christos Stavrakakis | if res == "disk": |
109 | 776b42a6 | Christos Stavrakakis | prod = prod << 10
|
110 | 776b42a6 | Christos Stavrakakis | allocated[res] += prod |
111 | bda47e03 | Christos Stavrakakis | |
112 | bda47e03 | Christos Stavrakakis | resources_stats = get_backend_stats(backend=backend) |
113 | bda47e03 | Christos Stavrakakis | for res in ["cpu", "ram", "disk", "disk_template"]: |
114 | bda47e03 | Christos Stavrakakis | if res not in resources_stats: |
115 | bda47e03 | Christos Stavrakakis | resources_stats[res] = {} |
116 | bda47e03 | Christos Stavrakakis | resources_stats[res]["servers"] = server_count[res]
|
117 | bda47e03 | Christos Stavrakakis | resources_stats[res]["allocated"] = allocated[res]
|
118 | bda47e03 | Christos Stavrakakis | |
119 | bda47e03 | Christos Stavrakakis | return resources_stats
|
120 | bda47e03 | Christos Stavrakakis | |
121 | bda47e03 | Christos Stavrakakis | |
122 | bda47e03 | Christos Stavrakakis | def get_images_stats(backend=None): |
123 | bda47e03 | Christos Stavrakakis | total_servers = _get_total_servers(backend=backend) |
124 | bda47e03 | Christos Stavrakakis | active_servers = total_servers.filter(deleted=False)
|
125 | bda47e03 | Christos Stavrakakis | |
126 | bda47e03 | Christos Stavrakakis | active_servers_images = active_servers.values("imageid", "userid")\ |
127 | bda47e03 | Christos Stavrakakis | .annotate(number=Count("imageid"))
|
128 | e780930a | Christos Stavrakakis | |
129 | bda47e03 | Christos Stavrakakis | image_cache = ImageCache() |
130 | bda47e03 | Christos Stavrakakis | image_stats = defaultdict(int)
|
131 | bda47e03 | Christos Stavrakakis | for result in active_servers_images: |
132 | bda47e03 | Christos Stavrakakis | imageid = image_cache.get_image(result["imageid"], result["userid"]) |
133 | bda47e03 | Christos Stavrakakis | image_stats[imageid] += result["number"]
|
134 | bda47e03 | Christos Stavrakakis | return dict(image_stats) |
135 | bda47e03 | Christos Stavrakakis | |
136 | bda47e03 | Christos Stavrakakis | |
137 | bda47e03 | Christos Stavrakakis | def get_networks_stats(): |
138 | bda47e03 | Christos Stavrakakis | total_networks = Network.objects.all() |
139 | bda47e03 | Christos Stavrakakis | stats = {"public_ips": get_ip_stats(),
|
140 | bda47e03 | Christos Stavrakakis | "total": 0} |
141 | bda47e03 | Christos Stavrakakis | per_state = total_networks.values("state")\
|
142 | bda47e03 | Christos Stavrakakis | .annotate(count=Count("state"))
|
143 | bda47e03 | Christos Stavrakakis | [stats.setdefault(s[0], 0) for s in Network.OPER_STATES] |
144 | bda47e03 | Christos Stavrakakis | for x in per_state: |
145 | bda47e03 | Christos Stavrakakis | stats[x["state"]] = x["count"] |
146 | bda47e03 | Christos Stavrakakis | stats["total"] += x["count"] |
147 | bda47e03 | Christos Stavrakakis | return stats
|
148 | bda47e03 | Christos Stavrakakis | |
149 | bda47e03 | Christos Stavrakakis | |
150 | bda47e03 | Christos Stavrakakis | def group_by_resource(objects, resource): |
151 | bda47e03 | Christos Stavrakakis | stats = {} |
152 | bda47e03 | Christos Stavrakakis | key = operator.attrgetter("flavor."+resource)
|
153 | bda47e03 | Christos Stavrakakis | grouped = itertools.groupby(sorted(objects, key=key), key)
|
154 | bda47e03 | Christos Stavrakakis | for val, group in grouped: |
155 | bda47e03 | Christos Stavrakakis | stats[val] = len(list(group)) |
156 | bda47e03 | Christos Stavrakakis | return stats
|
157 | bda47e03 | Christos Stavrakakis | |
158 | bda47e03 | Christos Stavrakakis | |
159 | bda47e03 | Christos Stavrakakis | def get_ip_stats(): |
160 | bda47e03 | Christos Stavrakakis | total, free = 0, 0, |
161 | bda47e03 | Christos Stavrakakis | for network in Network.objects.filter(public=True, deleted=False): |
162 | bda47e03 | Christos Stavrakakis | try:
|
163 | bda47e03 | Christos Stavrakakis | net_total, net_free = network.ip_count() |
164 | bda47e03 | Christos Stavrakakis | except AttributeError: |
165 | bda47e03 | Christos Stavrakakis | # TODO: Check that this works..
|
166 | bda47e03 | Christos Stavrakakis | pool = network.get_pool(locked=False)
|
167 | bda47e03 | Christos Stavrakakis | net_total = pool.pool_size |
168 | bda47e03 | Christos Stavrakakis | net_free = pool.count_available() |
169 | bda47e03 | Christos Stavrakakis | if not network.drained: |
170 | bda47e03 | Christos Stavrakakis | total += net_total |
171 | bda47e03 | Christos Stavrakakis | free += net_free |
172 | bda47e03 | Christos Stavrakakis | return {"total": total, |
173 | bda47e03 | Christos Stavrakakis | "free": free}
|
174 | bda47e03 | Christos Stavrakakis | |
175 | bda47e03 | Christos Stavrakakis | |
176 | bda47e03 | Christos Stavrakakis | def get_backend_stats(backend=None): |
177 | bda47e03 | Christos Stavrakakis | if backend is None: |
178 | bda47e03 | Christos Stavrakakis | backends = Backend.objects.filter(offline=False)
|
179 | bda47e03 | Christos Stavrakakis | else:
|
180 | bda47e03 | Christos Stavrakakis | if backend.offline:
|
181 | bda47e03 | Christos Stavrakakis | return {}
|
182 | bda47e03 | Christos Stavrakakis | backends = [backend] |
183 | bda47e03 | Christos Stavrakakis | [backend_mod.update_backend_resources(b) for b in backends] |
184 | bda47e03 | Christos Stavrakakis | resources = {} |
185 | bda47e03 | Christos Stavrakakis | for attr in ("dfree", "dtotal", "mfree", "mtotal", "ctotal"): |
186 | bda47e03 | Christos Stavrakakis | resources[attr] = 0
|
187 | bda47e03 | Christos Stavrakakis | for b in backends: |
188 | bda47e03 | Christos Stavrakakis | resources[attr] += getattr(b, attr)
|
189 | bda47e03 | Christos Stavrakakis | |
190 | bda47e03 | Christos Stavrakakis | return {"disk": {"free": resources["dfree"], "total": resources["dtotal"]}, |
191 | bda47e03 | Christos Stavrakakis | "ram": {"free": resources["mfree"], "total": resources["mtotal"]}, |
192 | bda47e03 | Christos Stavrakakis | "cpu": {"free": resources["ctotal"], "total": resources["ctotal"]}, |
193 | bda47e03 | Christos Stavrakakis | "disk_template": {"free": 0, "total": 0}} |
194 | bda47e03 | Christos Stavrakakis | |
195 | bda47e03 | Christos Stavrakakis | |
196 | bda47e03 | Christos Stavrakakis | class ImageCache(object): |
197 | bda47e03 | Christos Stavrakakis | def __init__(self): |
198 | bda47e03 | Christos Stavrakakis | self.images = {}
|
199 | 236935bb | Christos Stavrakakis | usercache = UserCache(settings.ASTAKOS_AUTH_URL, |
200 | bda47e03 | Christos Stavrakakis | settings.CYCLADES_SERVICE_TOKEN) |
201 | bda47e03 | Christos Stavrakakis | self.system_user_uuid = \
|
202 | bda47e03 | Christos Stavrakakis | usercache.get_uuid(settings.SYSTEM_IMAGES_OWNER) |
203 | bda47e03 | Christos Stavrakakis | |
204 | bda47e03 | Christos Stavrakakis | def get_image(self, imageid, userid): |
205 | bda47e03 | Christos Stavrakakis | if not imageid in self.images: |
206 | bda47e03 | Christos Stavrakakis | try:
|
207 | e780930a | Christos Stavrakakis | with image_backend(userid) as ib: |
208 | e780930a | Christos Stavrakakis | image = ib.get_image(imageid) |
209 | e780930a | Christos Stavrakakis | properties = image.get("properties")
|
210 | e780930a | Christos Stavrakakis | os = properties.get("os",
|
211 | e780930a | Christos Stavrakakis | properties.get("osfamily", "unknown")) |
212 | bda47e03 | Christos Stavrakakis | owner = image["owner"]
|
213 | bda47e03 | Christos Stavrakakis | owner = "system" if image["owner"] == self.system_user_uuid\ |
214 | bda47e03 | Christos Stavrakakis | else "user" |
215 | e780930a | Christos Stavrakakis | self.images[imageid] = owner + ":" + os |
216 | bda47e03 | Christos Stavrakakis | except Exception: |
217 | bda47e03 | Christos Stavrakakis | self.images[imageid] = "unknown:unknown" |
218 | bda47e03 | Christos Stavrakakis | |
219 | bda47e03 | Christos Stavrakakis | return self.images[imageid] |
220 | bda47e03 | Christos Stavrakakis | |
221 | bda47e03 | Christos Stavrakakis | |
222 | bda47e03 | Christos Stavrakakis | def get_public_stats(): |
223 | bda47e03 | Christos Stavrakakis | # VirtualMachines
|
224 | bda47e03 | Christos Stavrakakis | vm_objects = VirtualMachine.objects |
225 | bda47e03 | Christos Stavrakakis | servers = vm_objects.values("deleted", "operstate")\ |
226 | bda47e03 | Christos Stavrakakis | .annotate(count=Count("id"),
|
227 | bda47e03 | Christos Stavrakakis | cpu=Sum("flavor__cpu"),
|
228 | bda47e03 | Christos Stavrakakis | ram=Sum("flavor__ram"),
|
229 | bda47e03 | Christos Stavrakakis | disk=Sum("flavor__disk"))
|
230 | bda47e03 | Christos Stavrakakis | zero_stats = {"count": 0, "cpu": 0, "ram": 0, "disk": 0} |
231 | bda47e03 | Christos Stavrakakis | server_stats = {} |
232 | bda47e03 | Christos Stavrakakis | for state in VirtualMachine.RSAPI_STATE_FROM_OPER_STATE.values(): |
233 | bda47e03 | Christos Stavrakakis | server_stats[state] = copy(zero_stats) |
234 | bda47e03 | Christos Stavrakakis | |
235 | bda47e03 | Christos Stavrakakis | for stats in servers: |
236 | bda47e03 | Christos Stavrakakis | deleted = stats.pop("deleted")
|
237 | bda47e03 | Christos Stavrakakis | operstate = stats.pop("operstate")
|
238 | bda47e03 | Christos Stavrakakis | state = VirtualMachine.RSAPI_STATE_FROM_OPER_STATE.get(operstate) |
239 | bda47e03 | Christos Stavrakakis | if deleted:
|
240 | bda47e03 | Christos Stavrakakis | for key in zero_stats.keys(): |
241 | bda47e03 | Christos Stavrakakis | server_stats["DELETED"][key] += stats.get(key, 0) |
242 | bda47e03 | Christos Stavrakakis | elif state:
|
243 | bda47e03 | Christos Stavrakakis | for key in zero_stats.keys(): |
244 | bda47e03 | Christos Stavrakakis | server_stats[state][key] += stats.get(key, 0)
|
245 | bda47e03 | Christos Stavrakakis | |
246 | bda47e03 | Christos Stavrakakis | #Networks
|
247 | bda47e03 | Christos Stavrakakis | net_objects = Network.objects |
248 | bda47e03 | Christos Stavrakakis | networks = net_objects.values("deleted", "state")\ |
249 | bda47e03 | Christos Stavrakakis | .annotate(count=Count("id"))
|
250 | bda47e03 | Christos Stavrakakis | zero_stats = {"count": 0} |
251 | bda47e03 | Christos Stavrakakis | network_stats = {} |
252 | bda47e03 | Christos Stavrakakis | for state in Network.RSAPI_STATE_FROM_OPER_STATE.values(): |
253 | bda47e03 | Christos Stavrakakis | network_stats[state] = copy(zero_stats) |
254 | bda47e03 | Christos Stavrakakis | |
255 | bda47e03 | Christos Stavrakakis | for stats in networks: |
256 | bda47e03 | Christos Stavrakakis | deleted = stats.pop("deleted")
|
257 | bda47e03 | Christos Stavrakakis | state = stats.pop("state")
|
258 | bda47e03 | Christos Stavrakakis | state = Network.RSAPI_STATE_FROM_OPER_STATE.get(state) |
259 | bda47e03 | Christos Stavrakakis | if deleted:
|
260 | bda47e03 | Christos Stavrakakis | for key in zero_stats.keys(): |
261 | bda47e03 | Christos Stavrakakis | network_stats["DELETED"][key] += stats.get(key, 0) |
262 | bda47e03 | Christos Stavrakakis | elif state:
|
263 | bda47e03 | Christos Stavrakakis | for key in zero_stats.keys(): |
264 | bda47e03 | Christos Stavrakakis | network_stats[state][key] += stats.get(key, 0)
|
265 | bda47e03 | Christos Stavrakakis | |
266 | bda47e03 | Christos Stavrakakis | statistics = {"servers": server_stats,
|
267 | bda47e03 | Christos Stavrakakis | "networks": network_stats}
|
268 | bda47e03 | Christos Stavrakakis | return statistics |