You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

447 lines
20 KiB

4 years ago
  1. # -*- coding: utf-8 -*-
  2. #
  3. # This file is part of Glances.
  4. #
  5. # Copyright (C) 2018 Nicolargo <nicolas@nicolargo.com>
  6. #
  7. # Glances is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU Lesser General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Glances is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Lesser General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Lesser General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. """Glances main class."""
  20. import argparse
  21. import sys
  22. import tempfile
  23. from glances import __version__, psutil_version
  24. from glances.compat import input
  25. from glances.config import Config
  26. from glances.globals import WINDOWS
  27. from glances.logger import logger
  28. def disable(class_name, var):
  29. """Set disable_<var> to True in the class class_name."""
  30. setattr(class_name, 'disable_' + var, True)
  31. def enable(class_name, var):
  32. """Set disable_<var> to False in the class class_name."""
  33. setattr(class_name, 'disable_' + var, False)
  34. class GlancesMain(object):
  35. """Main class to manage Glances instance."""
  36. # Default stats' refresh time is 3 seconds
  37. refresh_time = 3
  38. # Set the default cache lifetime to 1 second (only for server)
  39. cached_time = 1
  40. # By default, Glances is ran in standalone mode (no client/server)
  41. client_tag = False
  42. # Server TCP port number (default is 61209)
  43. server_port = 61209
  44. # Web Server TCP port number (default is 61208)
  45. web_server_port = 61208
  46. # Default username/password for client/server mode
  47. username = "glances"
  48. password = ""
  49. # Examples of use
  50. example_of_use = """
  51. Examples of use:
  52. Monitor local machine (standalone mode):
  53. $ glances
  54. Display all Glances modules (plugins and exporters) and exit:
  55. $ glances --module-list
  56. Monitor local machine with the Web interface and start RESTful server:
  57. $ glances -w
  58. Glances web server started on http://0.0.0.0:61208/
  59. Only start RESTful API (without the WebUI):
  60. $ glances -w --disable-webui
  61. Glances API available on http://0.0.0.0:61208/api/
  62. Monitor local machine and export stats to a CSV file (standalone mode):
  63. $ glances --export csv --export-csv-file /tmp/glances.csv
  64. Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode):
  65. $ glances -t 5 --export influxdb
  66. Start a Glances XML/RCP server (server mode):
  67. $ glances -s
  68. Connect Glances to a Glances XML/RCP server (client mode):
  69. $ glances -c <ip_server>
  70. Connect Glances to a Glances server and export stats to a StatsD server (client mode):
  71. $ glances -c <ip_server> --export statsd
  72. Start the client browser (browser mode):
  73. $ glances --browser
  74. Display stats to stdout:
  75. $ glances --stdout cpu.user,mem.used,load
  76. Disable some plugins (any modes):
  77. $ glances --disable-plugin network,ports
  78. """
  79. def __init__(self):
  80. """Manage the command line arguments."""
  81. # Read the command line arguments
  82. self.args = self.parse_args()
  83. def init_args(self):
  84. """Init all the command line arguments."""
  85. version = "Glances v" + __version__ + " with psutil v" + psutil_version
  86. parser = argparse.ArgumentParser(
  87. prog='glances',
  88. conflict_handler='resolve',
  89. formatter_class=argparse.RawDescriptionHelpFormatter,
  90. epilog=self.example_of_use)
  91. parser.add_argument(
  92. '-V', '--version', action='version', version=version)
  93. parser.add_argument('-d', '--debug', action='store_true', default=False,
  94. dest='debug', help='enable debug mode')
  95. parser.add_argument('-C', '--config', dest='conf_file',
  96. help='path to the configuration file')
  97. # Disable plugin
  98. parser.add_argument('--modules-list', '--module-list',
  99. action='store_true', default=False,
  100. dest='modules_list',
  101. help='display modules (plugins & exports) list and exit')
  102. parser.add_argument('--disable-plugin', dest='disable_plugin',
  103. help='disable plugin (comma separed list)')
  104. parser.add_argument('--disable-process', action='store_true', default=False,
  105. dest='disable_process', help='disable process module')
  106. # Enable or disable option
  107. parser.add_argument('--disable-webui', action='store_true', default=False,
  108. dest='disable_webui', help='disable the Web Interface')
  109. parser.add_argument('--light', '--enable-light', action='store_true',
  110. default=False, dest='enable_light',
  111. help='light mode for Curses UI (disable all but top menu)')
  112. parser.add_argument('-0', '--disable-irix', action='store_true', default=False,
  113. dest='disable_irix', help='task\'s cpu usage will be divided by the total number of CPUs')
  114. parser.add_argument('-1', '--percpu', action='store_true', default=False,
  115. dest='percpu', help='start Glances in per CPU mode')
  116. parser.add_argument('-2', '--disable-left-sidebar', action='store_true',
  117. default=False, dest='disable_left_sidebar',
  118. help='disable network, disk I/O, FS and sensors modules')
  119. parser.add_argument('-3', '--disable-quicklook', action='store_true', default=False,
  120. dest='disable_quicklook', help='disable quick look module')
  121. parser.add_argument('-4', '--full-quicklook', action='store_true', default=False,
  122. dest='full_quicklook', help='disable all but quick look and load')
  123. parser.add_argument('-5', '--disable-top', action='store_true',
  124. default=False, dest='disable_top',
  125. help='disable top menu (QL, CPU, MEM, SWAP and LOAD)')
  126. parser.add_argument('-6', '--meangpu', action='store_true', default=False,
  127. dest='meangpu', help='start Glances in mean GPU mode')
  128. parser.add_argument('--disable-history', action='store_true', default=False,
  129. dest='disable_history', help='disable stats history')
  130. parser.add_argument('--disable-bold', action='store_true', default=False,
  131. dest='disable_bold', help='disable bold mode in the terminal')
  132. parser.add_argument('--disable-bg', action='store_true', default=False,
  133. dest='disable_bg', help='disable background colors in the terminal')
  134. parser.add_argument('--enable-irq', action='store_true', default=False,
  135. dest='enable_irq', help='enable IRQ module'),
  136. parser.add_argument('--enable-process-extended', action='store_true', default=False,
  137. dest='enable_process_extended', help='enable extended stats on top process')
  138. # Export modules feature
  139. parser.add_argument('--export', dest='export',
  140. help='enable export module (comma separed list)')
  141. parser.add_argument('--export-csv-file',
  142. default='./glances.csv',
  143. dest='export_csv_file',
  144. help='file path for CSV exporter')
  145. parser.add_argument('--export-json-file',
  146. default='./glances.json',
  147. dest='export_json_file',
  148. help='file path for JSON exporter')
  149. parser.add_argument('--export-graph-path',
  150. default=tempfile.gettempdir(),
  151. dest='export_graph_path',
  152. help='Folder for Graph exporter')
  153. # Client/Server option
  154. parser.add_argument('-c', '--client', dest='client',
  155. help='connect to a Glances server by IPv4/IPv6 address or hostname')
  156. parser.add_argument('-s', '--server', action='store_true', default=False,
  157. dest='server', help='run Glances in server mode')
  158. parser.add_argument('--browser', action='store_true', default=False,
  159. dest='browser', help='start the client browser (list of servers)')
  160. parser.add_argument('--disable-autodiscover', action='store_true', default=False,
  161. dest='disable_autodiscover', help='disable autodiscover feature')
  162. parser.add_argument('-p', '--port', default=None, type=int, dest='port',
  163. help='define the client/server TCP port [default: {}]'.format(self.server_port))
  164. parser.add_argument('-B', '--bind', default='0.0.0.0', dest='bind_address',
  165. help='bind server to the given IPv4/IPv6 address or hostname')
  166. parser.add_argument('--username', action='store_true', default=False, dest='username_prompt',
  167. help='define a client/server username')
  168. parser.add_argument('--password', action='store_true', default=False, dest='password_prompt',
  169. help='define a client/server password')
  170. parser.add_argument('--snmp-community', default='public', dest='snmp_community',
  171. help='SNMP community')
  172. parser.add_argument('--snmp-port', default=161, type=int,
  173. dest='snmp_port', help='SNMP port')
  174. parser.add_argument('--snmp-version', default='2c', dest='snmp_version',
  175. help='SNMP version (1, 2c or 3)')
  176. parser.add_argument('--snmp-user', default='private', dest='snmp_user',
  177. help='SNMP username (only for SNMPv3)')
  178. parser.add_argument('--snmp-auth', default='password', dest='snmp_auth',
  179. help='SNMP authentication key (only for SNMPv3)')
  180. parser.add_argument('--snmp-force', action='store_true', default=False,
  181. dest='snmp_force', help='force SNMP mode')
  182. parser.add_argument('-t', '--time', default=self.refresh_time, type=float,
  183. dest='time', help='set refresh time in seconds [default: {} sec]'.format(self.refresh_time))
  184. parser.add_argument('-w', '--webserver', action='store_true', default=False,
  185. dest='webserver', help='run Glances in web server mode (bottle needed)')
  186. parser.add_argument('--cached-time', default=self.cached_time, type=int,
  187. dest='cached_time', help='set the server cache time [default: {} sec]'.format(self.cached_time))
  188. parser.add_argument('--open-web-browser', action='store_true', default=False,
  189. dest='open_web_browser', help='try to open the Web UI in the default Web browser')
  190. # Display options
  191. parser.add_argument('-q', '--quiet', default=False, action='store_true',
  192. dest='quiet', help='do not display the curses interface')
  193. parser.add_argument('-f', '--process-filter', default=None, type=str,
  194. dest='process_filter', help='set the process filter pattern (regular expression)')
  195. parser.add_argument('--process-short-name', action='store_true', default=False,
  196. dest='process_short_name', help='force short name for processes name')
  197. parser.add_argument('--stdout', default=None,
  198. dest='stdout', help='display stats to stdout (comma separated list of plugins/plugins.attribute)')
  199. if not WINDOWS:
  200. parser.add_argument('--hide-kernel-threads', action='store_true', default=False,
  201. dest='no_kernel_threads', help='hide kernel threads in process list (not available on Windows)')
  202. parser.add_argument('-b', '--byte', action='store_true', default=False,
  203. dest='byte', help='display network rate in byte per second')
  204. parser.add_argument('--diskio-show-ramfs', action='store_true', default=False,
  205. dest='diskio_show_ramfs', help='show RAM Fs in the DiskIO plugin')
  206. parser.add_argument('--diskio-iops', action='store_true', default=False,
  207. dest='diskio_iops', help='show IO per second in the DiskIO plugin')
  208. parser.add_argument('--fahrenheit', action='store_true', default=False,
  209. dest='fahrenheit', help='display temperature in Fahrenheit (default is Celsius)')
  210. parser.add_argument('--fs-free-space', action='store_true', default=False,
  211. dest='fs_free_space', help='display FS free space instead of used')
  212. parser.add_argument('--theme-white', action='store_true', default=False,
  213. dest='theme_white', help='optimize display colors for white background')
  214. # Globals options
  215. parser.add_argument('--disable-check-update', action='store_true', default=False,
  216. dest='disable_check_update', help='disable online Glances version ckeck')
  217. return parser
  218. def parse_args(self):
  219. """Parse command line arguments."""
  220. args = self.init_args().parse_args()
  221. # Load the configuration file, if it exists
  222. self.config = Config(args.conf_file)
  223. # Debug mode
  224. if args.debug:
  225. from logging import DEBUG
  226. logger.setLevel(DEBUG)
  227. else:
  228. from warnings import simplefilter
  229. simplefilter("ignore")
  230. # Plugins disable/enable
  231. if args.disable_plugin is not None:
  232. for p in args.disable_plugin.split(','):
  233. disable(args, p)
  234. # Exporters activation
  235. if args.export is not None:
  236. for p in args.export.split(','):
  237. setattr(args, 'export_' + p, True)
  238. # Client/server Port
  239. if args.port is None:
  240. if args.webserver:
  241. args.port = self.web_server_port
  242. else:
  243. args.port = self.server_port
  244. # Port in the -c URI #996
  245. if args.client is not None:
  246. args.client, args.port = (x if x else y for (x, y) in zip(args.client.partition(':')[::2], (args.client, args.port)))
  247. # Autodiscover
  248. if args.disable_autodiscover:
  249. logger.info("Auto discover mode is disabled")
  250. # By default Windows is started in Web mode
  251. if WINDOWS:
  252. args.webserver = True
  253. # In web server mode, default refresh time: 5 sec
  254. if args.webserver:
  255. args.time = 5
  256. args.process_short_name = True
  257. # Server or client login/password
  258. if args.username_prompt:
  259. # Every username needs a password
  260. args.password_prompt = True
  261. # Prompt username
  262. if args.server:
  263. args.username = self.__get_username(
  264. description='Define the Glances server username: ')
  265. elif args.webserver:
  266. args.username = self.__get_username(
  267. description='Define the Glances webserver username: ')
  268. elif args.client:
  269. args.username = self.__get_username(
  270. description='Enter the Glances server username: ')
  271. else:
  272. # Default user name is 'glances'
  273. args.username = self.username
  274. if args.password_prompt:
  275. # Interactive or file password
  276. if args.server:
  277. args.password = self.__get_password(
  278. description='Define the Glances server password ({} username): '.format(
  279. args.username),
  280. confirm=True,
  281. username=args.username)
  282. elif args.webserver:
  283. args.password = self.__get_password(
  284. description='Define the Glances webserver password ({} username): '.format(
  285. args.username),
  286. confirm=True,
  287. username=args.username)
  288. elif args.client:
  289. args.password = self.__get_password(
  290. description='Enter the Glances server password ({} username): '.format(
  291. args.username),
  292. clear=True,
  293. username=args.username)
  294. else:
  295. # Default is no password
  296. args.password = self.password
  297. # By default help is hidden
  298. args.help_tag = False
  299. # Display Rx and Tx, not the sum for the network
  300. args.network_sum = False
  301. args.network_cumul = False
  302. # Manage light mode
  303. if args.enable_light:
  304. logger.info("Light mode is on")
  305. args.disable_left_sidebar = True
  306. disable(args, 'process')
  307. disable(args, 'alert')
  308. disable(args, 'amps')
  309. disable(args, 'docker')
  310. # Manage full quicklook option
  311. if args.full_quicklook:
  312. logger.info("Full quicklook mode")
  313. enable(args, 'quicklook')
  314. disable(args, 'cpu')
  315. disable(args, 'mem')
  316. disable(args, 'memswap')
  317. enable(args, 'load')
  318. # Manage disable_top option
  319. if args.disable_top:
  320. logger.info("Disable top menu")
  321. disable(args, 'quicklook')
  322. disable(args, 'cpu')
  323. disable(args, 'mem')
  324. disable(args, 'memswap')
  325. disable(args, 'load')
  326. # Init the generate_graph tag
  327. # Should be set to True to generate graphs
  328. args.generate_graph = False
  329. # Control parameter and exit if it is not OK
  330. self.args = args
  331. # Export is only available in standalone or client mode (issue #614)
  332. export_tag = self.args.export is not None and any(self.args.export)
  333. if WINDOWS and export_tag:
  334. # On Windows, export is possible but only in quiet mode
  335. # See issue #1038
  336. logger.info("On Windows OS, export disable the Web interface")
  337. self.args.quiet = True
  338. self.args.webserver = False
  339. elif not (self.is_standalone() or self.is_client()) and export_tag:
  340. logger.critical("Export is only available in standalone or client mode")
  341. sys.exit(2)
  342. # Filter is only available in standalone mode
  343. if args.process_filter is not None and not self.is_standalone():
  344. logger.critical(
  345. "Process filter is only available in standalone mode")
  346. sys.exit(2)
  347. # Disable HDDTemp if sensors are disabled
  348. if getattr(args, 'disable_sensors', False):
  349. disable(args, 'hddtemp')
  350. logger.debug("Sensors and HDDTemp are disabled")
  351. return args
  352. def is_standalone(self):
  353. """Return True if Glances is running in standalone mode."""
  354. return (not self.args.client and
  355. not self.args.browser and
  356. not self.args.server and
  357. not self.args.webserver)
  358. def is_client(self):
  359. """Return True if Glances is running in client mode."""
  360. return (self.args.client or self.args.browser) and not self.args.server
  361. def is_client_browser(self):
  362. """Return True if Glances is running in client browser mode."""
  363. return self.args.browser and not self.args.server
  364. def is_server(self):
  365. """Return True if Glances is running in server mode."""
  366. return not self.args.client and self.args.server
  367. def is_webserver(self):
  368. """Return True if Glances is running in Web server mode."""
  369. return not self.args.client and self.args.webserver
  370. def get_config(self):
  371. """Return configuration file object."""
  372. return self.config
  373. def get_args(self):
  374. """Return the arguments."""
  375. return self.args
  376. def get_mode(self):
  377. """Return the mode."""
  378. return self.mode
  379. def __get_username(self, description=''):
  380. """Read an username from the command line."""
  381. return input(description)
  382. def __get_password(self, description='',
  383. confirm=False, clear=False, username='glances'):
  384. """Read a password from the command line.
  385. - if confirm = True, with confirmation
  386. - if clear = True, plain (clear password)
  387. """
  388. from glances.password import GlancesPassword
  389. password = GlancesPassword(username=username)
  390. return password.get_password(description, confirm, clear)