Skip to content

Commit 9e96f26

Browse files
committed
Implements: #1353
1 parent c431995 commit 9e96f26

File tree

3 files changed

+201
-1
lines changed

3 files changed

+201
-1
lines changed

IM/InfrastructureManager.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from IM.openid.JWT import JWT
4141
from IM.openid.OpenIDClient import OpenIDClient
4242
from IM.vault import VaultCredentials
43-
43+
from IM.Stats import Stats
4444

4545
if Config.MAX_SIMULTANEOUS_LAUNCHES > 1:
4646
from multiprocessing.pool import ThreadPool
@@ -1731,3 +1731,24 @@ def ChangeInfrastructureAuth(inf_id, new_auth, overwrite, auth):
17311731
sel_inf.change_auth(new_auth, overwrite)
17321732
IM.InfrastructureList.InfrastructureList.save_data(inf_id)
17331733
return ""
1734+
1735+
@staticmethod
1736+
def GetStats(date, auth):
1737+
"""
1738+
Get the statistics from the IM DB.
1739+
1740+
Args:
1741+
1742+
- init_date(str): Only will be returned infrastructure created afther this date.
1743+
- auth(Authentication): parsed authentication tokens.
1744+
1745+
Return: a list of dict with the stats.
1746+
"""
1747+
# First check the auth data
1748+
auth = InfrastructureManager.check_auth_data(auth)
1749+
im_auth = auth.getAuthInfo("InfrastructureManager")[0]
1750+
stats = Stats.get_stats(date, im_auth)
1751+
if not stats:
1752+
raise Exception("ERROR connecting with the database!.")
1753+
else:
1754+
return stats

IM/Stats.py

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# IM - Infrastructure Manager
2+
# Copyright (C) 2011 - GRyCAP - Universitat Politecnica de Valencia
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
import os.path
18+
import datetime
19+
import json
20+
import yaml
21+
import logging
22+
23+
from IM.db import DataBase
24+
from IM.auth import Authentication
25+
from IM.config import Config
26+
from IM.VirtualMachine import VirtualMachine
27+
28+
29+
class Stats():
30+
31+
logger = logging.getLogger('InfrastructureManager')
32+
"""Logger object."""
33+
34+
@staticmethod
35+
def _get_data(str_data, auth=None):
36+
dic = json.loads(str_data)
37+
resp = {'creation_date': None}
38+
if 'creation_date' in dic and dic['creation_date']:
39+
resp['creation_date'] = str(datetime.datetime.fromtimestamp(float(dic['creation_date'])))
40+
auth = Authentication.deserialize(dic['auth'])
41+
resp['icon'] = None
42+
im_auth = auth.getAuthInfo("InfrastructureManager")[0]
43+
if 'extra_info' in dic and dic['extra_info'] and "TOSCA" in dic['extra_info']:
44+
try:
45+
tosca = yaml.safe_load(dic['extra_info']['TOSCA'])
46+
icon = tosca.get("metadata", {}).get("icon", "")
47+
resp['icon'] = os.path.basename(icon)[:-4]
48+
except Exception:
49+
Stats.logger.exception("Error loading TOSCA.")
50+
51+
resp['vm_count'] = 0
52+
resp['cpu_count'] = 0
53+
resp['memory_size'] = 0
54+
resp['cloud_type'] = None
55+
resp['cloud_host'] = None
56+
resp['hybrid'] = False
57+
for vm_data in dic['vm_list']:
58+
vm = VirtualMachine.deserialize(vm_data)
59+
60+
# only get the cloud of the first VM
61+
if not resp['cloud_type']:
62+
resp['cloud_type'] = vm.cloud.type
63+
if not resp['cloud_host']:
64+
resp['cloud_host'] = vm.cloud.get_url()
65+
elif resp['cloud_host'] != vm.cloud.get_url():
66+
resp['hybrid'] = True
67+
68+
vm_sys = vm.info.systems[0]
69+
if vm_sys.getValue('cpu.count'):
70+
resp['cpu_count'] += vm_sys.getValue('cpu.count')
71+
if vm_sys.getValue('memory.size'):
72+
resp['memory_size'] += vm_sys.getFeature('memory.size').getValue('M')
73+
resp['vm_count'] += 1
74+
75+
if auth is None or im_auth.compare(auth):
76+
resp['im_user'] = im_auth.get('username', "")
77+
return resp
78+
else:
79+
return None
80+
81+
@staticmethod
82+
def get_stats(init_date="1970-01-01", auth=None):
83+
"""
84+
Get the statistics from the IM DB.
85+
86+
Args:
87+
88+
- init_date(str): Only will be returned infrastructure created afther this date.
89+
- auth(Authentication): parsed authentication tokens.
90+
91+
Return: a list of dict with the stats.
92+
"""
93+
stats = []
94+
db = DataBase(Config.DATA_DB)
95+
if db.connect():
96+
res = db.select("SELECT data, date, id FROM inf_list WHERE date > '%s' order by rowid desc;" % init_date)
97+
for elem in res:
98+
data = elem[0]
99+
date = elem[1]
100+
inf_id = elem[2]
101+
res = Stats._get_data(data.decode(), auth)
102+
if res:
103+
res['inf_id'] = inf_id
104+
res['last_date'] = str(date)
105+
stats.append(res)
106+
107+
db.close()
108+
return stats
109+
else:
110+
Stats.logger.error("ERROR connecting with the database!.")
111+
return None

test/unit/test_im_logic.py

+68
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,74 @@ def test_change_inf_auth(self):
13891389
self.assertEqual(str(ex.exception), ("Invalid new infrastructure data provided: No credentials"
13901390
" provided for the InfrastructureManager."))
13911391

1392+
@patch('IM.Stats.DataBase')
1393+
def test_get_stats(self, DataBase):
1394+
1395+
radl = """
1396+
network public ( outbound = 'yes' )
1397+
system plants (
1398+
name = 'plants' and
1399+
memory.size = 488M and
1400+
script = '#!/bin/bash
1401+
echo "Hola"
1402+
' and
1403+
cpu.count = 0.5 and
1404+
disk.0.image.url = 'oscar://sharp-elbakyan5.im.grycap.net/grycap/image' and
1405+
input.0.provider = 'minio.default' and
1406+
input.0.path = 'input' and
1407+
output.0.provider = 'minio.default' and
1408+
output.0.path = 'output' and
1409+
alpine = 0 and
1410+
net_interface.0.connection = 'public' and
1411+
state = 'configured' and
1412+
provider.type = 'OSCAR' and
1413+
instance_id = 'plants' and
1414+
net_interface.0.dns_name = 'vnode-0' and
1415+
token = 'ebfb145ab57a35520669fc89bc115edab1b231a5c8f92e895ecaee256f841bac'
1416+
)
1417+
1418+
configure plants ()
1419+
contextualize (
1420+
system plants configure plants step 1
1421+
)
1422+
deploy plants 1
1423+
1424+
"""
1425+
1426+
db = MagicMock()
1427+
inf_data = {
1428+
"id": "1",
1429+
"auth": [
1430+
{"password": "https://aai.egi.eu/oidc/a67fff9c06e62401975aeb29ad35b8faf7c4fc74b4526a5504e5132b01496831@egi.eu",
1431+
"type": "InfrastructureManager",
1432+
"username": "__OPENID__mcaballer"
1433+
}
1434+
],
1435+
"vm_list": [
1436+
{"last_update": 1646656730,
1437+
"destroy": True,
1438+
"state": "deleting",
1439+
"id": "plants",
1440+
"im_id": 0,
1441+
"cloud": {
1442+
"id": "oscar",
1443+
"type": "OSCAR",
1444+
"server": "sharp-elbakyan5.im.grycap.net",
1445+
"protocol": "https"
1446+
},
1447+
"info": radl,
1448+
"cont_out": "",
1449+
"configured": True,
1450+
"creation_date": 1646655378
1451+
},
1452+
"extra_info": {"TOSCA": {"metadata": {"icon": "kubernetes.png"}}}
1453+
]
1454+
}
1455+
db.select.return_value = [(inf_data, '2022-03-23', '1')]
1456+
DataBase.return_value = db
1457+
1458+
IM.GetStats()
1459+
13921460

13931461
if __name__ == "__main__":
13941462
unittest.main()

0 commit comments

Comments
 (0)