[PATCH 0/2] Host stats history

From: Aline Manera <alinefm@br.ibm.com> Aline Manera (2): Add API to return host stats history Host stats history: Update test cases docs/API.md | 28 +++++++++++++++++++ src/kimchi/control/host.py | 10 +++++++ src/kimchi/mockmodel.py | 8 ++++++ src/kimchi/model/host.py | 66 ++++++++++++++++++++++++++++++-------------- tests/test_model.py | 12 ++++---- tests/test_rest.py | 12 ++++---- 6 files changed, 105 insertions(+), 31 deletions(-) -- 1.7.10.4

From: Aline Manera <alinefm@br.ibm.com> GET /host/stats/history will return the host stats history - the last 60 values. That way the grid in UI can show the history when displaying the host tab and then use /host/stats to get the new updated values - item by item. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- docs/API.md | 28 +++++++++++++++++++ src/kimchi/control/host.py | 10 +++++++ src/kimchi/mockmodel.py | 8 ++++++ src/kimchi/model/host.py | 66 ++++++++++++++++++++++++++++++-------------- 4 files changed, 91 insertions(+), 21 deletions(-) diff --git a/docs/API.md b/docs/API.md index 716c983..1fd2c3c 100644 --- a/docs/API.md +++ b/docs/API.md @@ -768,6 +768,34 @@ Contains the host sample data. *No actions defined* +### Resource: HostStatsHistory + +**URI:** /host/stats/history + +It is the sub-resource of Host Stats and the client uses it to get the host +stats history + +**Methods:** + +* **GET**: Retrieve host sample data history + * cpu_utilization: CPU utilization history + * memory: Memory statistics history + * total: Total amount of memory. The unit is Bytes. + * free: The amount of memory left unused by the system. The unit is Bytes. + * buffers: The amount of memory used for file buffers. The unit is Bytes. + * cached: The amount of memory used as cache memory. The unit is Bytes. + * avail: The total amount of buffer, cache and free memory. The unit is Bytes. + * disk_read_rate: IO throughput for reads history + * disk_write_rate: IO throughput for writes history + * net_sent_rate: Network throughput for writes history + * net_recv_rate: Network throughput for reads history + +* **POST**: *See HostStatsHistory Actions* + +**Actions (POST):** + +*No actions defined* + ### Collection: Plugins **URI:** /plugins diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py index 003c4b9..ad34919 100644 --- a/src/kimchi/control/host.py +++ b/src/kimchi/control/host.py @@ -56,6 +56,16 @@ class Host(Resource): class HostStats(Resource): + def __init__(self, model, id=None): + super(HostStats, self).__init__(model, id) + self.history = HostStatsHistory(self.model) + + @property + def data(self): + return self.info + + +class HostStatsHistory(Resource): @property def data(self): return self.info diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 866ad2c..ca1bea6 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -810,6 +810,14 @@ class MockModel(object): 'net_recv_rate': round(random.uniform(0, 4000), 1), 'net_sent_rate': round(random.uniform(0, 4000), 1)} + def hoststatshistory_lookup(self, *name): + return {'cpu_utilization': random.sample(range(100), 30), + 'memory': random.sample(range(4000), 30), + 'disk_read_rate': random.sample(range(4000), 30), + 'disk_write_rate': random.sample(range(4000), 30), + 'net_recv_rate': random.sample(range(4000), 30), + 'net_sent_rate': random.sample(range(4000), 30)} + def users_get_list(self): return ["userA", "userB", "userC"] diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index e0ac760..3e2c827 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -119,18 +119,18 @@ class HostStatsModel(object): __metaclass__ = Singleton def __init__(self, **kargs): - self.host_stats = defaultdict(int) + self.host_stats = defaultdict(list) self.host_stats_thread = BackgroundTask(HOST_STATS_INTERVAL, self._update_host_stats) self.host_stats_thread.start() def lookup(self, *name): - return {'cpu_utilization': self.host_stats['cpu_utilization'], - 'memory': self.host_stats.get('memory'), - 'disk_read_rate': self.host_stats['disk_read_rate'], - 'disk_write_rate': self.host_stats['disk_write_rate'], - 'net_recv_rate': self.host_stats['net_recv_rate'], - 'net_sent_rate': self.host_stats['net_sent_rate']} + return {'cpu_utilization': self.host_stats['cpu_utilization'][-1], + 'memory': self.host_stats['memory'][-1], + 'disk_read_rate': self.host_stats['disk_read_rate'][-1], + 'disk_write_rate': self.host_stats['disk_write_rate'][-1], + 'net_recv_rate': self.host_stats['net_recv_rate'][-1], + 'net_sent_rate': self.host_stats['net_sent_rate'][-1]} def _update_host_stats(self): preTimeStamp = self.host_stats['timestamp'] @@ -148,6 +148,12 @@ class HostStatsModel(object): self._get_percentage_host_cpu_usage() self._get_host_memory_stats() + # store only 60 stats (1 min) + for key, value in self.host_stats.iteritems(): + if isinstance(value, list): + if len(value) == 60: + self.host_stats[key] = value[10:] + def _get_percentage_host_cpu_usage(self): # This is cpu usage producer. This producer will calculate the usage # at an interval of HOST_STATS_INTERVAL. @@ -155,7 +161,7 @@ class HostStatsModel(object): # psutil.cpu_percent maintains a cpu time sample. # It will update the cpu time sample when it is called. # So only this producer can call psutil.cpu_percent in kimchi. - self.host_stats['cpu_utilization'] = psutil.cpu_percent(None) + self.host_stats['cpu_utilization'].append(psutil.cpu_percent(None)) def _get_host_memory_stats(self): virt_mem = psutil.virtual_memory() @@ -169,11 +175,13 @@ class HostStatsModel(object): 'cached': virt_mem.cached, 'buffers': virt_mem.buffers, 'avail': virt_mem.available} - self.host_stats['memory'] = memory_stats + self.host_stats['memory'].append(memory_stats) def _get_host_disk_io_rate(self, seconds): - prev_read_bytes = self.host_stats['disk_read_bytes'] - prev_write_bytes = self.host_stats['disk_write_bytes'] + disk_read_bytes = self.host_stats['disk_read_bytes'] + disk_write_bytes = self.host_stats['disk_write_bytes'] + prev_read_bytes = disk_read_bytes[-1] if disk_read_bytes else 0 + prev_write_bytes = disk_write_bytes[-1] if disk_write_bytes else 0 disk_io = psutil.disk_io_counters(False) read_bytes = disk_io.read_bytes @@ -182,14 +190,16 @@ class HostStatsModel(object): rd_rate = int(float(read_bytes - prev_read_bytes) / seconds + 0.5) wr_rate = int(float(write_bytes - prev_write_bytes) / seconds + 0.5) - self.host_stats.update({'disk_read_rate': rd_rate, - 'disk_write_rate': wr_rate, - 'disk_read_bytes': read_bytes, - 'disk_write_bytes': write_bytes}) + self.host_stats['disk_read_rate'].append(rd_rate) + self.host_stats['disk_write_rate'].append(wr_rate) + self.host_stats['disk_read_bytes'].append(read_bytes) + self.host_stats['disk_write_bytes'].append(write_bytes) def _get_host_network_io_rate(self, seconds): - prev_recv_bytes = self.host_stats['net_recv_bytes'] - prev_sent_bytes = self.host_stats['net_sent_bytes'] + net_recv_bytes = self.host_stats['net_recv_bytes'] + net_sent_bytes = self.host_stats['net_sent_bytes'] + prev_recv_bytes = net_recv_bytes[-1] if net_recv_bytes else 0 + prev_sent_bytes = net_sent_bytes[-1] if net_sent_bytes else 0 net_ios = psutil.network_io_counters(True) recv_bytes = 0 @@ -202,10 +212,24 @@ class HostStatsModel(object): rx_rate = int(float(recv_bytes - prev_recv_bytes) / seconds + 0.5) tx_rate = int(float(sent_bytes - prev_sent_bytes) / seconds + 0.5) - self.host_stats.update({'net_recv_rate': rx_rate, - 'net_sent_rate': tx_rate, - 'net_recv_bytes': recv_bytes, - 'net_sent_bytes': sent_bytes}) + self.host_stats['net_recv_rate'].append(rx_rate) + self.host_stats['net_sent_rate'].append(tx_rate) + self.host_stats['net_recv_bytes'].append(recv_bytes) + self.host_stats['net_sent_bytes'].append(sent_bytes) + + +class HostStatsHistoryModel(object): + def __init__(self, **kargs): + self.history = HostStatsModel(**kargs) + pass + + def lookup(self, *name): + return {'cpu_utilization': self.history.host_stats['cpu_utilization'], + 'memory': self.history.host_stats['memory'], + 'disk_read_rate': self.history.host_stats['disk_read_rate'], + 'disk_write_rate': self.history.host_stats['disk_write_rate'], + 'net_recv_rate': self.history.host_stats['net_recv_rate'], + 'net_sent_rate': self.history.host_stats['net_sent_rate']} class PartitionsModel(object): -- 1.7.10.4

On 04/22/2014 09:41 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
GET /host/stats/history will return the host stats history - the last 60 values. That way the grid in UI can show the history when displaying the host tab and then use /host/stats to get the new updated values - item by item.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- docs/API.md | 28 +++++++++++++++++++ src/kimchi/control/host.py | 10 +++++++ src/kimchi/mockmodel.py | 8 ++++++ src/kimchi/model/host.py | 66 ++++++++++++++++++++++++++++++-------------- 4 files changed, 91 insertions(+), 21 deletions(-)
diff --git a/docs/API.md b/docs/API.md index 716c983..1fd2c3c 100644 --- a/docs/API.md +++ b/docs/API.md @@ -768,6 +768,34 @@ Contains the host sample data.
*No actions defined*
+### Resource: HostStatsHistory + +**URI:** /host/stats/history + +It is the sub-resource of Host Stats and the client uses it to get the host +stats history + +**Methods:** + +* **GET**: Retrieve host sample data history + * cpu_utilization: CPU utilization history + * memory: Memory statistics history + * total: Total amount of memory. The unit is Bytes. + * free: The amount of memory left unused by the system. The unit is Bytes. + * buffers: The amount of memory used for file buffers. The unit is Bytes. + * cached: The amount of memory used as cache memory. The unit is Bytes. + * avail: The total amount of buffer, cache and free memory. The unit is Bytes. + * disk_read_rate: IO throughput for reads history + * disk_write_rate: IO throughput for writes history + * net_sent_rate: Network throughput for writes history + * net_recv_rate: Network throughput for reads history + +* **POST**: *See HostStatsHistory Actions* + +**Actions (POST):** + +*No actions defined* + ### Collection: Plugins
**URI:** /plugins diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py index 003c4b9..ad34919 100644 --- a/src/kimchi/control/host.py +++ b/src/kimchi/control/host.py @@ -56,6 +56,16 @@ class Host(Resource):
class HostStats(Resource): + def __init__(self, model, id=None): + super(HostStats, self).__init__(model, id) + self.history = HostStatsHistory(self.model) + + @property + def data(self): + return self.info + + +class HostStatsHistory(Resource): @property def data(self): return self.info diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 866ad2c..ca1bea6 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -810,6 +810,14 @@ class MockModel(object): 'net_recv_rate': round(random.uniform(0, 4000), 1), 'net_sent_rate': round(random.uniform(0, 4000), 1)}
+ def hoststatshistory_lookup(self, *name): + return {'cpu_utilization': random.sample(range(100), 30), + 'memory': random.sample(range(4000), 30), + 'disk_read_rate': random.sample(range(4000), 30), + 'disk_write_rate': random.sample(range(4000), 30), + 'net_recv_rate': random.sample(range(4000), 30), + 'net_sent_rate': random.sample(range(4000), 30)} + def users_get_list(self): return ["userA", "userB", "userC"]
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index e0ac760..3e2c827 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -119,18 +119,18 @@ class HostStatsModel(object): __metaclass__ = Singleton
def __init__(self, **kargs): - self.host_stats = defaultdict(int) + self.host_stats = defaultdict(list) self.host_stats_thread = BackgroundTask(HOST_STATS_INTERVAL, self._update_host_stats) self.host_stats_thread.start()
def lookup(self, *name): - return {'cpu_utilization': self.host_stats['cpu_utilization'], - 'memory': self.host_stats.get('memory'), - 'disk_read_rate': self.host_stats['disk_read_rate'], - 'disk_write_rate': self.host_stats['disk_write_rate'], - 'net_recv_rate': self.host_stats['net_recv_rate'], - 'net_sent_rate': self.host_stats['net_sent_rate']} + return {'cpu_utilization': self.host_stats['cpu_utilization'][-1], + 'memory': self.host_stats['memory'][-1], + 'disk_read_rate': self.host_stats['disk_read_rate'][-1], + 'disk_write_rate': self.host_stats['disk_write_rate'][-1], + 'net_recv_rate': self.host_stats['net_recv_rate'][-1], + 'net_sent_rate': self.host_stats['net_sent_rate'][-1]}
def _update_host_stats(self): preTimeStamp = self.host_stats['timestamp'] @@ -148,6 +148,12 @@ class HostStatsModel(object): self._get_percentage_host_cpu_usage() self._get_host_memory_stats()
+ # store only 60 stats (1 min) + for key, value in self.host_stats.iteritems(): + if isinstance(value, list): + if len(value) == 60: + self.host_stats[key] = value[10:] + def _get_percentage_host_cpu_usage(self): # This is cpu usage producer. This producer will calculate the usage # at an interval of HOST_STATS_INTERVAL. @@ -155,7 +161,7 @@ class HostStatsModel(object): # psutil.cpu_percent maintains a cpu time sample. # It will update the cpu time sample when it is called. # So only this producer can call psutil.cpu_percent in kimchi. - self.host_stats['cpu_utilization'] = psutil.cpu_percent(None) + self.host_stats['cpu_utilization'].append(psutil.cpu_percent(None))
def _get_host_memory_stats(self): virt_mem = psutil.virtual_memory() @@ -169,11 +175,13 @@ class HostStatsModel(object): 'cached': virt_mem.cached, 'buffers': virt_mem.buffers, 'avail': virt_mem.available} - self.host_stats['memory'] = memory_stats + self.host_stats['memory'].append(memory_stats)
def _get_host_disk_io_rate(self, seconds): - prev_read_bytes = self.host_stats['disk_read_bytes'] - prev_write_bytes = self.host_stats['disk_write_bytes'] + disk_read_bytes = self.host_stats['disk_read_bytes'] + disk_write_bytes = self.host_stats['disk_write_bytes'] + prev_read_bytes = disk_read_bytes[-1] if disk_read_bytes else 0 + prev_write_bytes = disk_write_bytes[-1] if disk_write_bytes else 0
disk_io = psutil.disk_io_counters(False) read_bytes = disk_io.read_bytes @@ -182,14 +190,16 @@ class HostStatsModel(object): rd_rate = int(float(read_bytes - prev_read_bytes) / seconds + 0.5) wr_rate = int(float(write_bytes - prev_write_bytes) / seconds + 0.5)
- self.host_stats.update({'disk_read_rate': rd_rate, - 'disk_write_rate': wr_rate, - 'disk_read_bytes': read_bytes, - 'disk_write_bytes': write_bytes}) + self.host_stats['disk_read_rate'].append(rd_rate) + self.host_stats['disk_write_rate'].append(wr_rate) + self.host_stats['disk_read_bytes'].append(read_bytes) + self.host_stats['disk_write_bytes'].append(write_bytes)
def _get_host_network_io_rate(self, seconds): - prev_recv_bytes = self.host_stats['net_recv_bytes'] - prev_sent_bytes = self.host_stats['net_sent_bytes'] + net_recv_bytes = self.host_stats['net_recv_bytes'] + net_sent_bytes = self.host_stats['net_sent_bytes'] + prev_recv_bytes = net_recv_bytes[-1] if net_recv_bytes else 0 + prev_sent_bytes = net_sent_bytes[-1] if net_sent_bytes else 0
net_ios = psutil.network_io_counters(True) recv_bytes = 0 @@ -202,10 +212,24 @@ class HostStatsModel(object): rx_rate = int(float(recv_bytes - prev_recv_bytes) / seconds + 0.5) tx_rate = int(float(sent_bytes - prev_sent_bytes) / seconds + 0.5)
- self.host_stats.update({'net_recv_rate': rx_rate, - 'net_sent_rate': tx_rate, - 'net_recv_bytes': recv_bytes, - 'net_sent_bytes': sent_bytes}) + self.host_stats['net_recv_rate'].append(rx_rate) + self.host_stats['net_sent_rate'].append(tx_rate) + self.host_stats['net_recv_bytes'].append(recv_bytes) + self.host_stats['net_sent_bytes'].append(sent_bytes) + + +class HostStatsHistoryModel(object): + def __init__(self, **kargs): + self.history = HostStatsModel(**kargs) + pass "Pass" is not necessary
+ + def lookup(self, *name): + return {'cpu_utilization': self.history.host_stats['cpu_utilization'], + 'memory': self.history.host_stats['memory'], + 'disk_read_rate': self.history.host_stats['disk_read_rate'], + 'disk_write_rate': self.history.host_stats['disk_write_rate'], + 'net_recv_rate': self.history.host_stats['net_recv_rate'], + 'net_sent_rate': self.history.host_stats['net_sent_rate']}
class PartitionsModel(object):

On 04/24/2014 03:46 PM, Rodrigo Trujillo wrote:
On 04/22/2014 09:41 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
GET /host/stats/history will return the host stats history - the last 60 values. That way the grid in UI can show the history when displaying the host tab and then use /host/stats to get the new updated values - item by item.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- docs/API.md | 28 +++++++++++++++++++ src/kimchi/control/host.py | 10 +++++++ src/kimchi/mockmodel.py | 8 ++++++ src/kimchi/model/host.py | 66 ++++++++++++++++++++++++++++++-------------- 4 files changed, 91 insertions(+), 21 deletions(-)
diff --git a/docs/API.md b/docs/API.md index 716c983..1fd2c3c 100644 --- a/docs/API.md +++ b/docs/API.md @@ -768,6 +768,34 @@ Contains the host sample data.
*No actions defined*
+### Resource: HostStatsHistory + +**URI:** /host/stats/history + +It is the sub-resource of Host Stats and the client uses it to get the host +stats history + +**Methods:** + +* **GET**: Retrieve host sample data history + * cpu_utilization: CPU utilization history + * memory: Memory statistics history + * total: Total amount of memory. The unit is Bytes. + * free: The amount of memory left unused by the system. The unit is Bytes. + * buffers: The amount of memory used for file buffers. The unit is Bytes. + * cached: The amount of memory used as cache memory. The unit is Bytes. + * avail: The total amount of buffer, cache and free memory. The unit is Bytes. + * disk_read_rate: IO throughput for reads history + * disk_write_rate: IO throughput for writes history + * net_sent_rate: Network throughput for writes history + * net_recv_rate: Network throughput for reads history + +* **POST**: *See HostStatsHistory Actions* + +**Actions (POST):** + +*No actions defined* + ### Collection: Plugins
**URI:** /plugins diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py index 003c4b9..ad34919 100644 --- a/src/kimchi/control/host.py +++ b/src/kimchi/control/host.py @@ -56,6 +56,16 @@ class Host(Resource):
class HostStats(Resource): + def __init__(self, model, id=None): + super(HostStats, self).__init__(model, id) + self.history = HostStatsHistory(self.model) + + @property + def data(self): + return self.info + + +class HostStatsHistory(Resource): @property def data(self): return self.info diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 866ad2c..ca1bea6 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -810,6 +810,14 @@ class MockModel(object): 'net_recv_rate': round(random.uniform(0, 4000), 1), 'net_sent_rate': round(random.uniform(0, 4000), 1)}
+ def hoststatshistory_lookup(self, *name): + return {'cpu_utilization': random.sample(range(100), 30), + 'memory': random.sample(range(4000), 30), + 'disk_read_rate': random.sample(range(4000), 30), + 'disk_write_rate': random.sample(range(4000), 30), + 'net_recv_rate': random.sample(range(4000), 30), + 'net_sent_rate': random.sample(range(4000), 30)} + def users_get_list(self): return ["userA", "userB", "userC"]
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index e0ac760..3e2c827 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -119,18 +119,18 @@ class HostStatsModel(object): __metaclass__ = Singleton
def __init__(self, **kargs): - self.host_stats = defaultdict(int) + self.host_stats = defaultdict(list) self.host_stats_thread = BackgroundTask(HOST_STATS_INTERVAL, self._update_host_stats) self.host_stats_thread.start()
def lookup(self, *name): - return {'cpu_utilization': self.host_stats['cpu_utilization'], - 'memory': self.host_stats.get('memory'), - 'disk_read_rate': self.host_stats['disk_read_rate'], - 'disk_write_rate': self.host_stats['disk_write_rate'], - 'net_recv_rate': self.host_stats['net_recv_rate'], - 'net_sent_rate': self.host_stats['net_sent_rate']} + return {'cpu_utilization': self.host_stats['cpu_utilization'][-1], + 'memory': self.host_stats['memory'][-1], + 'disk_read_rate': self.host_stats['disk_read_rate'][-1], + 'disk_write_rate': self.host_stats['disk_write_rate'][-1], + 'net_recv_rate': self.host_stats['net_recv_rate'][-1], + 'net_sent_rate': self.host_stats['net_sent_rate'][-1]}
def _update_host_stats(self): preTimeStamp = self.host_stats['timestamp'] @@ -148,6 +148,12 @@ class HostStatsModel(object): self._get_percentage_host_cpu_usage() self._get_host_memory_stats()
+ # store only 60 stats (1 min) + for key, value in self.host_stats.iteritems(): + if isinstance(value, list): + if len(value) == 60: + self.host_stats[key] = value[10:] + def _get_percentage_host_cpu_usage(self): # This is cpu usage producer. This producer will calculate the usage # at an interval of HOST_STATS_INTERVAL. @@ -155,7 +161,7 @@ class HostStatsModel(object): # psutil.cpu_percent maintains a cpu time sample. # It will update the cpu time sample when it is called. # So only this producer can call psutil.cpu_percent in kimchi. - self.host_stats['cpu_utilization'] = psutil.cpu_percent(None) + self.host_stats['cpu_utilization'].append(psutil.cpu_percent(None))
def _get_host_memory_stats(self): virt_mem = psutil.virtual_memory() @@ -169,11 +175,13 @@ class HostStatsModel(object): 'cached': virt_mem.cached, 'buffers': virt_mem.buffers, 'avail': virt_mem.available} - self.host_stats['memory'] = memory_stats + self.host_stats['memory'].append(memory_stats)
def _get_host_disk_io_rate(self, seconds): - prev_read_bytes = self.host_stats['disk_read_bytes'] - prev_write_bytes = self.host_stats['disk_write_bytes'] + disk_read_bytes = self.host_stats['disk_read_bytes'] + disk_write_bytes = self.host_stats['disk_write_bytes'] + prev_read_bytes = disk_read_bytes[-1] if disk_read_bytes else 0 + prev_write_bytes = disk_write_bytes[-1] if disk_write_bytes else 0
disk_io = psutil.disk_io_counters(False) read_bytes = disk_io.read_bytes @@ -182,14 +190,16 @@ class HostStatsModel(object): rd_rate = int(float(read_bytes - prev_read_bytes) / seconds + 0.5) wr_rate = int(float(write_bytes - prev_write_bytes) / seconds + 0.5)
- self.host_stats.update({'disk_read_rate': rd_rate, - 'disk_write_rate': wr_rate, - 'disk_read_bytes': read_bytes, - 'disk_write_bytes': write_bytes}) + self.host_stats['disk_read_rate'].append(rd_rate) + self.host_stats['disk_write_rate'].append(wr_rate) + self.host_stats['disk_read_bytes'].append(read_bytes) + self.host_stats['disk_write_bytes'].append(write_bytes)
def _get_host_network_io_rate(self, seconds): - prev_recv_bytes = self.host_stats['net_recv_bytes'] - prev_sent_bytes = self.host_stats['net_sent_bytes'] + net_recv_bytes = self.host_stats['net_recv_bytes'] + net_sent_bytes = self.host_stats['net_sent_bytes'] + prev_recv_bytes = net_recv_bytes[-1] if net_recv_bytes else 0 + prev_sent_bytes = net_sent_bytes[-1] if net_sent_bytes else 0
net_ios = psutil.network_io_counters(True) recv_bytes = 0 @@ -202,10 +212,24 @@ class HostStatsModel(object): rx_rate = int(float(recv_bytes - prev_recv_bytes) / seconds + 0.5) tx_rate = int(float(sent_bytes - prev_sent_bytes) / seconds + 0.5)
- self.host_stats.update({'net_recv_rate': rx_rate, - 'net_sent_rate': tx_rate, - 'net_recv_bytes': recv_bytes, - 'net_sent_bytes': sent_bytes}) + self.host_stats['net_recv_rate'].append(rx_rate) + self.host_stats['net_sent_rate'].append(tx_rate) + self.host_stats['net_recv_bytes'].append(recv_bytes) + self.host_stats['net_sent_bytes'].append(sent_bytes) + + +class HostStatsHistoryModel(object): + def __init__(self, **kargs): + self.history = HostStatsModel(**kargs) + pass "Pass" is not necessary
ops... I will remove before applying
+ + def lookup(self, *name): + return {'cpu_utilization': self.history.host_stats['cpu_utilization'], + 'memory': self.history.host_stats['memory'], + 'disk_read_rate': self.history.host_stats['disk_read_rate'], + 'disk_write_rate': self.history.host_stats['disk_write_rate'], + 'net_recv_rate': self.history.host_stats['net_recv_rate'], + 'net_sent_rate': self.history.host_stats['net_sent_rate']}
class PartitionsModel(object):

From: Aline Manera <alinefm@br.ibm.com> Add new tests to verify the URI /host/stats/history Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- tests/test_model.py | 12 +++++++----- tests/test_rest.py | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/test_model.py b/tests/test_model.py index 2fb4446..4ff0813 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -986,6 +986,9 @@ class ModelTests(unittest.TestCase): objstore_loc=self.tmp_store) time.sleep(1.5) stats = inst.hoststats_lookup() + stats_keys = ['cpu_utilization', 'memory', 'disk_read_rate', + 'disk_write_rate', 'net_recv_rate', 'net_sent_rate'] + self.assertEquals(sorted(stats_keys), sorted(stats.keys())) cpu_utilization = stats['cpu_utilization'] # cpu_utilization is set int 0, after first stats sample # the cpu_utilization is float in range [0.0, 100.0] @@ -1000,11 +1003,10 @@ class ModelTests(unittest.TestCase): self.assertIn('buffers', memory_stats) self.assertIn('avail', memory_stats) - self.assertIn('disk_read_rate', stats) - self.assertIn('disk_write_rate', stats) - - self.assertIn('net_recv_rate', stats) - self.assertIn('net_sent_rate', stats) + history = inst.hoststatshistory_lookup() + self.assertEquals(sorted(stats_keys), sorted(history.keys())) + for key, value in history.iteritems(): + self.assertEquals(type(value), list) @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): diff --git a/tests/test_rest.py b/tests/test_rest.py index 06396db..76e5e13 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -1555,8 +1555,12 @@ class RestTests(unittest.TestCase): self.assertEquals(6114058240, info['memory']) def test_hoststats(self): + stats_keys = ['cpu_utilization', 'memory', 'disk_read_rate', + 'disk_write_rate', 'net_recv_rate', 'net_sent_rate'] resp = self.request('/host/stats').read() stats = json.loads(resp) + self.assertEquals(sorted(stats_keys), sorted(stats.keys())) + cpu_utilization = stats['cpu_utilization'] self.assertIsInstance(cpu_utilization, float) self.assertGreaterEqual(cpu_utilization, 0.0) @@ -1569,11 +1573,9 @@ class RestTests(unittest.TestCase): self.assertIn('buffers', memory_stats) self.assertIn('avail', memory_stats) - self.assertIn('disk_read_rate', stats) - self.assertIn('disk_write_rate', stats) - - self.assertIn('net_recv_rate', stats) - self.assertIn('net_sent_rate', stats) + resp = self.request('/host/stats/history').read() + history = json.loads(resp) + self.assertEquals(sorted(stats_keys), sorted(history.keys())) def test_packages_update(self): resp = self.request('/host/packagesupdate', None, 'GET') -- 1.7.10.4

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 04/22/2014 09:41 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Add new tests to verify the URI /host/stats/history
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- tests/test_model.py | 12 +++++++----- tests/test_rest.py | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/tests/test_model.py b/tests/test_model.py index 2fb4446..4ff0813 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -986,6 +986,9 @@ class ModelTests(unittest.TestCase): objstore_loc=self.tmp_store) time.sleep(1.5) stats = inst.hoststats_lookup() + stats_keys = ['cpu_utilization', 'memory', 'disk_read_rate', + 'disk_write_rate', 'net_recv_rate', 'net_sent_rate'] + self.assertEquals(sorted(stats_keys), sorted(stats.keys())) cpu_utilization = stats['cpu_utilization'] # cpu_utilization is set int 0, after first stats sample # the cpu_utilization is float in range [0.0, 100.0] @@ -1000,11 +1003,10 @@ class ModelTests(unittest.TestCase): self.assertIn('buffers', memory_stats) self.assertIn('avail', memory_stats)
- self.assertIn('disk_read_rate', stats) - self.assertIn('disk_write_rate', stats) - - self.assertIn('net_recv_rate', stats) - self.assertIn('net_sent_rate', stats) + history = inst.hoststatshistory_lookup() + self.assertEquals(sorted(stats_keys), sorted(history.keys())) + for key, value in history.iteritems(): + self.assertEquals(type(value), list)
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): diff --git a/tests/test_rest.py b/tests/test_rest.py index 06396db..76e5e13 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -1555,8 +1555,12 @@ class RestTests(unittest.TestCase): self.assertEquals(6114058240, info['memory'])
def test_hoststats(self): + stats_keys = ['cpu_utilization', 'memory', 'disk_read_rate', + 'disk_write_rate', 'net_recv_rate', 'net_sent_rate'] resp = self.request('/host/stats').read() stats = json.loads(resp) + self.assertEquals(sorted(stats_keys), sorted(stats.keys())) + cpu_utilization = stats['cpu_utilization'] self.assertIsInstance(cpu_utilization, float) self.assertGreaterEqual(cpu_utilization, 0.0) @@ -1569,11 +1573,9 @@ class RestTests(unittest.TestCase): self.assertIn('buffers', memory_stats) self.assertIn('avail', memory_stats)
- self.assertIn('disk_read_rate', stats) - self.assertIn('disk_write_rate', stats) - - self.assertIn('net_recv_rate', stats) - self.assertIn('net_sent_rate', stats) + resp = self.request('/host/stats/history').read() + history = json.loads(resp) + self.assertEquals(sorted(stats_keys), sorted(history.keys()))
def test_packages_update(self): resp = self.request('/host/packagesupdate', None, 'GET')

Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available. Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 18 ++++++- ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 92 insertions(+), 58 deletions(-) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..4bcf072 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -78,7 +78,7 @@ var kimchi = { }, /** - * Get the dynamic host stats (usually used for monitoring). + * Get the dynamic host stats (usually used for monitoring. */ getHostStats : function(suc, err) { kimchi.requestJSON({ @@ -94,6 +94,22 @@ var kimchi = { }, /** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..1835bfd 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); }); - var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE); + unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { }; var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + }; + if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); }; var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() { var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; } @@ -743,12 +771,10 @@ kimchi.host_main = function() { }; $('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + } repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div> -- 1.9.0

Reviewed-by: Aline Manera <alinefm@linux.vnet.ibm.com> On 04/23/2014 09:04 PM, Adam King wrote:
Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available.
Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 18 ++++++- ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 92 insertions(+), 58 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..4bcf072 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -78,7 +78,7 @@ var kimchi = { },
/** - * Get the dynamic host stats (usually used for monitoring). + * Get the dynamic host stats (usually used for monitoring. */ getHostStats : function(suc, err) { kimchi.requestJSON({ @@ -94,6 +94,22 @@ var kimchi = { },
/** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..1835bfd 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); });
- var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE); + unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { };
var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + }; + if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); };
var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() {
var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; }
@@ -743,12 +771,10 @@ kimchi.host_main = function() { };
$('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + }
repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div>

Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available.
Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 18 ++++++- ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 92 insertions(+), 58 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..4bcf072 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -78,7 +78,7 @@ var kimchi = { },
/** - * Get the dynamic host stats (usually used for monitoring). + * Get the dynamic host stats (usually used for monitoring. The right parenthesis is lost. */ getHostStats : function(suc, err) { kimchi.requestJSON({ @@ -94,6 +94,22 @@ var kimchi = { },
/** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..1835bfd 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); });
- var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE); We need (SIZE + 1) points here, so it should be:
On 04/24/2014 08:04 AM, Adam King wrote: ps.splice(0, ps.length - SIZE - 1);
+ unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { };
var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + };
+ if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } What's the case of multiple memory status? Is it for physical and logical memories? + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + +
+ var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); };
var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() {
var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; }
@@ -743,12 +771,10 @@ kimchi.host_main = function() { };
$('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + }
repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div>

On 04/23/2014 10:49 PM, Hongliang Wang wrote:
On 04/24/2014 08:04 AM, Adam King wrote:
Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available.
Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 18 ++++++- ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 92 insertions(+), 58 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..4bcf072 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -78,7 +78,7 @@ var kimchi = { },
/** - * Get the dynamic host stats (usually used for monitoring). + * Get the dynamic host stats (usually used for monitoring. The right parenthesis is lost.
Addressed in v2
*/ getHostStats : function(suc, err) { kimchi.requestJSON({ @@ -94,6 +94,22 @@ var kimchi = { },
/** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..1835bfd 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); });
- var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE);
We need (SIZE + 1) points here, so it should be: ps.splice(0, ps.length - SIZE - 1); Addressed in v2
+ unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { };
var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + };
+ if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } What's the case of multiple memory status? Is it for physical and logical memories? When historical data is gotten, the response includes multiple values representing the stats over time. + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + +
+ var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); };
var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() {
var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; }
@@ -743,12 +771,10 @@ kimchi.host_main = function() { };
$('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + }
repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div>
-- Adam King <rak@linux.vnet.ibm.com> IBM CSI

Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available. Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 16 ++++++ ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 91 insertions(+), 57 deletions(-) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..8dfa473 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -94,6 +94,22 @@ var kimchi = { }, /** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..9337a3b 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); }); - var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE-1); + unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { }; var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + }; + if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); }; var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() { var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; } @@ -743,12 +771,10 @@ kimchi.host_main = function() { }; $('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + } repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div> -- 1.9.0

Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available. Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 16 ++++++ ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 91 insertions(+), 57 deletions(-) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..8dfa473 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -94,6 +94,22 @@ var kimchi = { }, /** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..9337a3b 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); }); - var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE-1); + unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { }; var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + }; + if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); }; var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() { var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; } @@ -743,12 +771,10 @@ kimchi.host_main = function() { }; $('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + } repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div> -- 1.9.0

Reviewed-by: Aline Manera <alinefm@linux.vnet.ibm.com> On 04/24/2014 11:09 AM, Adam King wrote:
Update the host tab statistics graphs to make use of the newly available historical data. Removed option to continue collecting data while the host tab is out of view, as the server always has the historcal data available.
Signed-off-by: Adam King <rak@linux.vnet.ibm.com> --- ui/js/src/kimchi.api.js | 16 ++++++ ui/js/src/kimchi.host.js | 124 ++++++++++++++++++++++++++----------------- ui/pages/tabs/host.html.tmpl | 8 --- 3 files changed, 91 insertions(+), 57 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index e96a67a..8dfa473 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -94,6 +94,22 @@ var kimchi = { },
/** + * Get the historic host stats. + */ + getHostStatsHistory : function(suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'host/stats/history', + type : 'GET', + resend: true, + contentType : 'application/json', + headers: {'Kimchi-Robot': 'kimchi-robot'}, + dataType : 'json', + success : suc, + error: err + }); + }, + + /** * * Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu', * template: '/templates/ubuntu_base' }, creationSuc, creationErr); diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index 966ee54..9337a3b 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -448,12 +448,6 @@ kimchi.host_main = function() { }); });
- var keepMonitoringCheckbox = $('#keep-monitoring-checkbox'); - keepMonitoringCheckbox.prop('checked', kimchi.keepMonitoringHost === true); - keepMonitoringCheckbox.on('change', function(event) { - kimchi.keepMonitoringHost = this['checked']; - }); - kimchi.getCapabilities(function(capabilities) { kimchi.host.capabilities=capabilities; if((capabilities['repo_mngt_tool']) && (capabilities['repo_mngt_tool']!="None")) { @@ -566,9 +560,17 @@ kimchi.host_main = function() { var max = item[metrics]['max']; var unifiedMetrics = statsArray[key][metrics]; var ps = unifiedMetrics['points']; - ps.push(value); - ps.length > SIZE + 1 && - ps.shift(); + if(!Array.isArray(value)){ + ps.push(value); + if(ps.length > SIZE + 1) { + ps.shift(); + } + } + else{ + ps=ps.concat(value); + ps.splice(0, ps.length-SIZE-1); + unifiedMetrics['points']=ps; + } if(max !== undefined) { unifiedMetrics['max'] = max; } @@ -645,47 +647,76 @@ kimchi.host_main = function() { };
var self = this; - var track = function() { - kimchi.getHostStats(function(stats) { - var unifiedStats = { - cpu: { - u: { - v: stats['cpu_utilization'] - } - }, - memory: { - u: { - v: stats['memory']['avail'], - max: stats['memory']['total'] - } + + var UnifyStats = function(stats) { + var result= { + cpu: { + u: { + v: stats['cpu_utilization'] + } + }, + memory: { + u: { + } + }, + diskIO: { + r: { + v: stats['disk_read_rate'] }, - diskIO: { - r: { - v: stats['disk_read_rate'] - }, - w: { - v: stats['disk_write_rate'] - } + w: { + v: stats['disk_write_rate'] + } + }, + networkIO: { + r: { + v: stats['net_recv_rate'] }, - networkIO: { - r: { - v: stats['net_recv_rate'] - }, - s: { - v: stats['net_sent_rate'] - } + s: { + v: stats['net_sent_rate'] } - }; + } + }; + if(Array.isArray(stats['memory'])){ + result.memory.u['v']=[]; + result.memory.u['max']=-Infinity; + for(var i=0;i<stats['memory'].length;i++){ + result.memory.u['v'].push(stats['memory'][i]['avail']); + result.memory.u['max']=Math.max(result.memory.u['max'],stats['memory'][i]['total']); + } + + } + else { + result.memory.u['v']=stats['memory']['avail'], + result.memory.u['max']=stats['memory']['total'] + } + return(result); + }; + + + var statsCallback = function(stats) { + var unifiedStats = UnifyStats(stats); statsPool.add(unifiedStats); for(var key in charts) { var chart = charts[key]; chart.updateUI(statsPool.get(key)); } timer = setTimeout(function() { - track(); + continueTrack(); }, 1000); - }, function() { - }); + }; + + var track = function() { + kimchi.getHostStatsHistory(statsCallback, + function() { + continueTrack(); + }); + }; + + var continueTrack = function() { + kimchi.getHostStats(statsCallback, + function() { + continueTrack(); + }); };
var destroy = function() { @@ -702,11 +733,8 @@ kimchi.host_main = function() {
var initTracker = function() { // TODO: Extend tabs with onUnload event to unregister timers. - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { - var timer = kimchi.hostTimer; - timer.stop(); - timer = null; - kimchi.hostTimer = null; + if(kimchi.hostTimer) { + kimchi.hostTimer.stop(); delete kimchi.hostTimer; }
@@ -743,12 +771,10 @@ kimchi.host_main = function() { };
$('#host-root-container').on('remove', function() { - if(!kimchi.keepMonitoringHost && kimchi.hostTimer) { + if(kimchi.hostTimer) { kimchi.hostTimer.stop(); - kimchi.hostTimer = null; - kimchi.hostTimer = null; delete kimchi.hostTimer; - } + }
repositoriesGrid && repositoriesGrid.destroy(); kimchi.topic('kimchi/repositoryAdded') diff --git a/ui/pages/tabs/host.html.tmpl b/ui/pages/tabs/host.html.tmpl index e59513b..75cf54d 100644 --- a/ui/pages/tabs/host.html.tmpl +++ b/ui/pages/tabs/host.html.tmpl @@ -87,14 +87,6 @@ </h3> <div id="content-sys-statistics" class="section-content"> <div class="section-row"> - <div class="section-label"></div> - <div class="section-value"> - <input id="keep-monitoring-checkbox" type="checkbox" value="" /> - <label for="keep-monitoring-checkbox">$_("Collecting data after leaving this page")</label> - </div> - </div> - - <div class="section-row"> <div class="section-label">$_("CPU")</div> <div class="section-value"> <div id="container-chart-cpu" class="inline-block"></div>
participants (4)
-
Adam King
-
Aline Manera
-
Hongliang Wang
-
Rodrigo Trujillo