Statistics
| Branch: | Tag: | Revision:

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