mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-22 16:51:35 +03:00
Merge branch 'issue1029' into develop
This commit is contained in:
commit
dbb59bca02
1
NEWS
1
NEWS
@ -9,6 +9,7 @@ Enhancements and new features:
|
||||
|
||||
* Use new sensors-related APIs of Psutil 5.1.0 (issue #1018)
|
||||
=> Remove Py3Sensors and Batinfo dependencies
|
||||
* Add a "Cloud" plugin to grab stats inside the AWS EC2 API (issue #1029)
|
||||
|
||||
Bugs corrected:
|
||||
|
||||
|
@ -11,6 +11,9 @@ Additionally, on GNU/Linux, it also shows the kernel version.
|
||||
|
||||
In client mode, the server connection status is also displayed.
|
||||
|
||||
If you are hosted on an AWS EC2 instance, some additional information
|
||||
can be displayed (AMI-ID, region).
|
||||
|
||||
**Connected**:
|
||||
|
||||
.. image:: ../_static/connected.png
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "GLANCES" "1" "Feb 11, 2017" "2.8.3_DEVELOP" "Glances"
|
||||
.TH "GLANCES" "1" "Feb 12, 2017" "2.8.3_DEVELOP" "Glances"
|
||||
.SH NAME
|
||||
glances \- An eye on your system
|
||||
.
|
||||
|
@ -103,6 +103,8 @@ Start the client browser (browser mode):\n\
|
||||
dest='disable_alert', help='disable alert module')
|
||||
parser.add_argument('--disable-amps', action='store_true', default=False,
|
||||
dest='disable_amps', help='disable applications monitoring process (AMP) module')
|
||||
parser.add_argument('--disable-cloud', action='store_true', default=False,
|
||||
dest='disable_cloud', help='disable Cloud module')
|
||||
parser.add_argument('--disable-cpu', action='store_true', default=False,
|
||||
dest='disable_cpu', help='disable CPU module')
|
||||
parser.add_argument('--disable-diskio', action='store_true', default=False,
|
||||
|
@ -54,11 +54,12 @@ class _GlancesCurses(object):
|
||||
'3': {'switch': 'disable_quicklook'},
|
||||
'6': {'switch': 'meangpu'},
|
||||
'/': {'switch': 'process_short_name'},
|
||||
'd': {'switch': 'disable_diskio'},
|
||||
'A': {'switch': 'disable_amps'},
|
||||
'b': {'switch': 'byte'},
|
||||
'B': {'switch': 'diskio_iops'},
|
||||
'C': {'switch': 'disable_cloud'},
|
||||
'D': {'switch': 'disable_docker'},
|
||||
'd': {'switch': 'disable_diskio'},
|
||||
'F': {'switch': 'fs_free_space'},
|
||||
'G': {'switch': 'disable_gpu'},
|
||||
'h': {'switch': 'help_tag'},
|
||||
@ -545,6 +546,7 @@ class _GlancesCurses(object):
|
||||
|
||||
# =====================================
|
||||
# Display first line (system+ip+uptime)
|
||||
# Optionnaly: Cloud on second line
|
||||
# =====================================
|
||||
self.__display_firstline(__stat_display)
|
||||
|
||||
@ -628,7 +630,11 @@ class _GlancesCurses(object):
|
||||
# Space between column
|
||||
self.space_between_column = 3
|
||||
self.new_column()
|
||||
self.display_plugin(stat_display["uptime"])
|
||||
self.display_plugin(stat_display["uptime"],
|
||||
add_space=self.get_stats_display_width(stat_display["cloud"]) == 0)
|
||||
self.init_column()
|
||||
self.new_line()
|
||||
self.display_plugin(stat_display["cloud"])
|
||||
|
||||
def __display_secondline(self, stat_display, stats):
|
||||
"""Display the second line in the Curses interface.
|
||||
@ -829,7 +835,8 @@ class _GlancesCurses(object):
|
||||
def display_plugin(self, plugin_stats,
|
||||
display_optional=True,
|
||||
display_additional=True,
|
||||
max_y=65535):
|
||||
max_y=65535,
|
||||
add_space=True):
|
||||
"""Display the plugin_stats on the screen.
|
||||
|
||||
If display_optional=True display the optional stats
|
||||
@ -913,6 +920,10 @@ class _GlancesCurses(object):
|
||||
self.next_column, x_max + self.space_between_column)
|
||||
self.next_line = max(self.next_line, y + self.space_between_line)
|
||||
|
||||
if not add_space and self.next_line > 0:
|
||||
# Do not have empty line after
|
||||
self.next_line -= 1
|
||||
|
||||
def erase(self):
|
||||
"""Erase the content of the screen."""
|
||||
self.term_window.erase()
|
||||
|
173
glances/plugins/glances_cloud.py
Normal file
173
glances/plugins/glances_cloud.py
Normal file
@ -0,0 +1,173 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This file is part of Glances.
|
||||
#
|
||||
# Copyright (C) 2017 Nicolargo <nicolas@nicolargo.com>
|
||||
#
|
||||
# Glances is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Glances is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Cloud plugin.
|
||||
|
||||
Supported Cloud API:
|
||||
- AWS EC2 (class ThreadAwsEc2Grabber, see bellow)
|
||||
"""
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
cloud_tag = False
|
||||
else:
|
||||
cloud_tag = True
|
||||
|
||||
import threading
|
||||
|
||||
from glances.compat import iteritems
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.logger import logger
|
||||
|
||||
|
||||
class Plugin(GlancesPlugin):
|
||||
|
||||
"""Glances' cloud plugin.
|
||||
|
||||
The goal of this plugin is to retreive additional information
|
||||
concerning the datacenter where the host is connected.
|
||||
|
||||
See https://github.com/nicolargo/glances/issues/1029
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
def __init__(self, args=None):
|
||||
"""Init the plugin."""
|
||||
super(Plugin, self).__init__(args=args)
|
||||
|
||||
# We want to display the stat in the curse interface
|
||||
self.display_curse = True
|
||||
|
||||
# Init the stats
|
||||
self.reset()
|
||||
|
||||
# Init thread to grab AWS EC2 stats asynchroniously
|
||||
self.aws_ec2 = ThreadAwsEc2Grabber()
|
||||
|
||||
# Run the thread
|
||||
self.aws_ec2. start()
|
||||
|
||||
def reset(self):
|
||||
"""Reset/init the stats."""
|
||||
self.stats = {}
|
||||
|
||||
def exit(self):
|
||||
"""Overwrite the exit method to close threads"""
|
||||
self.aws_ec2.stop()
|
||||
# Call the father class
|
||||
super(Plugin, self).exit()
|
||||
|
||||
@GlancesPlugin._check_decorator
|
||||
@GlancesPlugin._log_result_decorator
|
||||
def update(self):
|
||||
"""Update the cloud stats.
|
||||
|
||||
Return the stats (dict)
|
||||
"""
|
||||
# Reset stats
|
||||
self.reset()
|
||||
|
||||
# Requests lib is needed to get stats from the Cloud API
|
||||
if not cloud_tag:
|
||||
return self.stats
|
||||
|
||||
# Update the stats
|
||||
if self.input_method == 'local':
|
||||
self.stats = self.aws_ec2.stats
|
||||
|
||||
return self.stats
|
||||
|
||||
def msg_curse(self, args=None):
|
||||
"""Return the string to display in the curse interface."""
|
||||
# Init the return message
|
||||
ret = []
|
||||
|
||||
if not self.stats \
|
||||
or self.stats == {} \
|
||||
or self.is_disable():
|
||||
return ret
|
||||
|
||||
# Generate the output
|
||||
if 'ami-id' in self.stats and 'region' in self.stats:
|
||||
msg = 'AWS EC2'
|
||||
ret.append(self.curse_add_line(msg, "TITLE"))
|
||||
msg = ' instance {} ({})'.format(self.stats['ami-id'],
|
||||
self.stats['region'])
|
||||
ret.append(self.curse_add_line(msg))
|
||||
|
||||
# Return the message with decoration
|
||||
logger.info(ret)
|
||||
return ret
|
||||
|
||||
|
||||
class ThreadAwsEc2Grabber(threading.Thread):
|
||||
"""
|
||||
Specific thread to grab AWS EC2 stats.
|
||||
|
||||
stats is a dict
|
||||
"""
|
||||
|
||||
# AWS EC2
|
||||
# http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
|
||||
AWS_EC2_API_URL = 'http://169.254.169.254/latest/meta-data'
|
||||
AWS_EC2_API_METADATA = {'ami-id': 'ami-id',
|
||||
'region': 'placement/availability-zone'}
|
||||
|
||||
def __init__(self):
|
||||
"""Init the class"""
|
||||
logger.debug("cloud plugin - Create thread for AWS EC2")
|
||||
super(ThreadAwsEc2Grabber, self).__init__()
|
||||
# Event needed to stop properly the thread
|
||||
self._stopper = threading.Event()
|
||||
# The class return the stats as a dict
|
||||
self._stats = {}
|
||||
|
||||
def run(self):
|
||||
"""Function called to grab stats.
|
||||
Infinite loop, should be stopped by calling the stop() method"""
|
||||
|
||||
for k, v in iteritems(self.AWS_EC2_API_METADATA):
|
||||
r_url = '{}/{}'.format(self.AWS_EC2_API_URL, v)
|
||||
try:
|
||||
r = requests.get(r_url)
|
||||
except Exception as e:
|
||||
logger.debug('Can not connect to the AWS EC2 API {}'.format(r_url, e))
|
||||
else:
|
||||
self._stats[k] = r
|
||||
|
||||
@property
|
||||
def stats(self):
|
||||
"""Stats getter"""
|
||||
return self._stats
|
||||
|
||||
@stats.setter
|
||||
def stats(self, value):
|
||||
"""Stats setter"""
|
||||
self._stats = value
|
||||
|
||||
def stop(self, timeout=None):
|
||||
"""Stop the thread"""
|
||||
logger.debug("cloud plugin - Close thread for AWS EC2")
|
||||
self._stopper.set()
|
||||
|
||||
def stopped(self):
|
||||
"""Return True is the thread is stopped"""
|
||||
return self._stopper.isSet()
|
Loading…
Reference in New Issue
Block a user