Skip to content

Commit

Permalink
Added ability to fetch all Site Metrics as JSON. Creating charts as P…
Browse files Browse the repository at this point in the history
…NG link for servers is not yet supported. Added many more options for adding a new site monitor: e.g. from which monitoring location to monitor, keyword alerts, different protocols and ports, ...
  • Loading branch information
Jan Loeffler committed May 2, 2023
1 parent 0b53e4c commit d15adfa
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 15 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.0.19

* [*] Added ability to fetch all Site Metrics as JSON. Creating charts as PNG link for servers is not yet supported.
* [*] Added many more options for adding a new site monitor: e.g. from which monitoring location to monitor, keyword alerts, different protocols and ports, ...

# 1.0.18

* [*] Added ability to list all monitoring locations (nodes).
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ You can easily test and run 360 Monitoring CLI for production by running the pre

$ docker run -it --rm ubuntu /bin/bash
$ apt-get update && apt-get install -y python3 && apt-get install -y pip
$ pip install -i https://test.pypi.org/simple/ --force-reinstall -v "360monitoringcli==1.0.18"
$ pip install -i https://test.pypi.org/simple/ --force-reinstall -v "360monitoringcli==1.0.19"

### For developement, install required Python modules

Expand Down
11 changes: 11 additions & 0 deletions cli360monitoring/lib/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ def list(self, id: str = '', name: str = '', sort: str = 'Name', reverse: bool =

self.printFooter(sort=sort, reverse=reverse, limit=limit)

def getNodeId(self, name: str):
"""Return Node Id for the location with the specified name. Only the first matching entry (exact match) is returned or empty string if not found"""

if name and self.fetchData():
# Iterate through list of nodes and find the specified one
for node in self.nodes:
if name in node['pretty_name']:
return node['id']

return ''

def printFooter(self, sort: str = '', reverse: bool = False, limit: int = 0):
"""Print table if table format requested"""

Expand Down
11 changes: 8 additions & 3 deletions cli360monitoring/lib/servercharts.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ServerCharts(object):
def __init__(self, config: Config):
self.config = config

def create(self, serverId: str, metric: str = 'cpu', startTimestamp: float = 0, endTimestamp: float = 0):
def create(self, serverId: str, metric: str = 'cpu', startTimestamp: float = 0, endTimestamp: float = 0, dataAsJSON: bool = False):
"""Create a server metrics chart for the specified server id"""

if not serverId:
Expand All @@ -24,7 +24,9 @@ def create(self, serverId: str, metric: str = 'cpu', startTimestamp: float = 0,
return ''

params = self.config.params()
params['output'] = 'png'

if not dataAsJSON:
params['output'] = 'png'
# metrics can be one of [bitninja, cpu, httpd, mem, network, nginx, ping, process, swap, uptime, wp-toolkit]
params['metric'] = metric
if startTimestamp > 0:
Expand All @@ -34,7 +36,10 @@ def create(self, serverId: str, metric: str = 'cpu', startTimestamp: float = 0,

response_json = apiGet('server/' + serverId + '/metrics', 200, self.config, params)
if response_json:
if 'uri' in response_json:
if dataAsJSON:
print(json.dumps(response_json, indent=4))
return ''
elif 'uri' in response_json:
uri = response_json['uri']
print(uri)
return uri
Expand Down
44 changes: 44 additions & 0 deletions cli360monitoring/lib/sitecharts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python3

import json
from datetime import datetime

from .api import apiGet
from .config import Config
from .functions import printError, printWarn

class SiteCharts(object):

def __init__(self, config: Config):
self.config = config

def create(self, siteId: str, startTimestamp: float = 0, endTimestamp: float = 0):
"""Create a site metrics chart for the specified site id"""

if not siteId:
printError('No site id specified')
return ''

params = self.config.params()
params['output'] = 'png'
if startTimestamp > 0:
params['start'] = int(startTimestamp)
if endTimestamp > 0:
params['end'] = int(endTimestamp)

response_json = apiGet('monitor/' + siteId + '/metrics', 200, self.config, params)
if response_json:
print(json.dumps(response_json, indent=4))
print()
print('Only JSON output supported currently. PNG export not yet implemented.')
'''
if 'uri' in response_json:
uri = response_json['uri']
print(uri)
return uri
else:
printWarn('Site with id', siteId, 'not found')
return ''
'''
else:
return ''
14 changes: 11 additions & 3 deletions cli360monitoring/lib/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def list(self, id: str = '', url: str = '', name: str = '', location: str = '',

self.printFooter(sort=sort, reverse=reverse, limit=limit)

def add(self, url: str, protocol: str = 'https', name: str = '', force: bool = False):
def add(self, url: str, protocol: str = 'https', name: str = '', port: int = 443, keyword: str = '', matchType:str = '', nodeId: str = '', force: bool = False):
"""Add a monitor for the given URL"""

if url and self.fetchData():
Expand All @@ -126,15 +126,23 @@ def add(self, url: str, protocol: str = 'https', name: str = '', force: bool = F

# other parameters:
# port: int (e.g. 443, 80)
# keyword: string that needs to be in the http response body (e.g. "error")
# redirects: int (e.g. 3 max redirects; 0 for no redirects)
# timeout: int (e.g. 30 seconds)
# interval: int # How often to perform the check in seconds
# keyword: str # Alert when error on my page is found in the page HTML
# match_type: str 'yes' or 'no' # If set to yes it will alert when keyword is found on page, if no alert when keyword not found
# monitor: str
# protocol: str [http, https, icmp, tcp]

# Make request to API endpoint
data = {
'url': url,
'name': name,
'protocol': protocol
'port': port,
'protocol': protocol,
'keyword': keyword,
'match_type': matchType,
'monitor': nodeId,
}
apiPost('monitors', self.config, data=data, expectedStatusCode=200, successMessage='Added site monitor: ' + url, errorMessage='Failed to add site monitor ' + url + '')

Expand Down
61 changes: 54 additions & 7 deletions cli360monitoring/monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
from .lib.servercharts import ServerCharts
from .lib.servernotifications import ServerNotifications
from .lib.sites import Sites
from .lib.sitecharts import SiteCharts
from .lib.sitenotifications import SiteNotifications
from .lib.statistics import Statistics
from .lib.usertokens import UserTokens
from .lib.wptoolkit import WPToolkit

__version__ = '1.0.18'
__version__ = '1.0.19'

# only runs on Python 3.x; throw exception on 2.x
if sys.version_info[0] < 3:
Expand Down Expand Up @@ -213,8 +214,6 @@ def servers_add(args):
print()
print('wget -q -N monitoring.platform360.io/agent360.sh && bash agent360.sh', token)

# --- magiclink functions ---

def servers_charts(args):
"""Sub command for servers charts"""
cli_subcommands[args.subparser].print_help()
Expand Down Expand Up @@ -293,20 +292,53 @@ def signup(args):
def sites_add(args):
"""Sub command for sites add"""
sites = Sites(cfg)
nodeId = ''

if args.node_id:
nodeId = args.node_id
elif args.node_name:
nodes = Nodes(cfg)
nodeId = nodes.getNodeId(args.node_name)

if args.file:
if os.path.isfile(args.file):
with open(args.file) as file:
lines = file.readlines()
for line in lines:
sites.add(line.strip())
sites.add(line.strip(), protocol=args.protocol, name=args.name, port=args.port, keyword=args.keyword, matchType=args.match_type, nodeId=nodeId, force=args.force)
else:
print('ERROR: File', args.file, 'to import not found')
elif args.url:
sites.add(args.url, protocol=args.protocol, name=args.name, force=args.force)
sites.add(args.url, protocol=args.protocol, name=args.name, port=args.port, keyword=args.keyword, matchType=args.match_type, nodeId=nodeId, force=args.force)
else:
print('You need to specify at least a name with --name [name]')

def sites_charts(args):
"""Sub command for sites charts"""
cli_subcommands[args.subparser].print_help()

def sites_charts_create(args):
"""Sub command for sites charts"""
siteId = ''
startDate = datetime.strptime(args.start.strip('\"'), '%Y-%m-%d').timestamp() if args.start else 0
endDate = datetime.strptime(args.end.strip('\"'), '%Y-%m-%d').timestamp() if args.end else 0

if args.id:
siteId = args.id
elif args.url:
# find correct server id for the server with the specified name
sites = Sites(cfg)
siteId = sites.getSiteId(args.url)

if siteId:
charts = SiteCharts(cfg)
chart_url = charts.create(siteId, startDate, endDate)

if chart_url and args.open:
webbrowser.open(chart_url)
else:
print('Please specify an existing site either by "--id id" or "--url url"')

def sites_events(args):
"""Sub command for sites events"""
siteId = ''
Expand Down Expand Up @@ -623,11 +655,26 @@ def performCLI():
cli_sites_add.set_defaults(func=sites_add)
cli_sites_add.add_argument('--url', nargs='?', metavar='url', help='url of site that should be monitored')
cli_sites_add.add_argument('--name', nargs='?', metavar='name', help='name of site that should be monitored (optional)')
cli_sites_add.add_argument('--protocol', nargs='?', default='https', metavar='protocol', help='specify a different protocol than https')
# cli_sites_add.add_argument('--port', nargs='?', default=443, type=int, metavar='port', help='specify a different port than 443')
cli_sites_add.add_argument('--protocol', choices=['http', 'https', 'icmp', 'tcp'], default='https', metavar='protocol', help='specify a different protocol than https')
cli_sites_add.add_argument('--port', nargs='?', default=443, type=int, metavar='port', help='specify a different port than 443')
cli_sites_add.add_argument('--keyword', nargs='?', metavar='keyword', help='alert when the specified keyword is found/not found in the page HTML (optional)')
cli_sites_add.add_argument('--match-type', choices=['', 'yes', 'no'], default='', metavar='type', help='if set to \"yes\" it will alert when keyword is found on page, if \"no\" alert when keyword not found')
cli_sites_add.add_argument('--node-id', nargs='?', metavar='id', help='id of the monitoring node location that should monitor the url (optional)')
cli_sites_add.add_argument('--node-name', nargs='?', metavar='id', help='name of the monitoring node location that should monitor the url. In doubt, take the first match. (optional)')
cli_sites_add.add_argument('--force', action='store_true', help='add new monitor even if already exists')
cli_sites_add.add_argument('--file', nargs='?', default='', metavar='file', help='file containing one URL per line to monitor')

cli_sites_charts = cli_sites_subparsers.add_parser('charts', help='create a metrics chart as PNG file and print its url or open it in your browser')
cli_sites_charts.set_defaults(func=sites_charts)
cli_sites_charts_subparsers = cli_sites_charts.add_subparsers(title='commands', dest='subparser')
cli_sites_charts_create = cli_sites_charts_subparsers.add_parser('create', help='create a metrics chart as PNG file and print its url or open it in your browser')
cli_sites_charts_create.set_defaults(func=sites_charts_create)
cli_sites_charts_create.add_argument('--id', nargs='?', default='', metavar='id', help='show metrics for server with given ID')
cli_sites_charts_create.add_argument('--url', nargs='?', default='', metavar='url', help='show metrics for server with given url')
cli_sites_charts_create.add_argument('--start', nargs='?', default='', metavar='start', help='select start date of chart period in form of \"yyyy-mm-dd\" (optional)')
cli_sites_charts_create.add_argument('--end', nargs='?', default='', metavar='end', help='select end date of chart period in form of \"yyyy-mm-dd\" (optional)')
cli_sites_charts_create.add_argument('--open', action='store_true', help='open the metrics chart directly in the default web browser (optional)')

cli_sites_events = cli_sites_subparsers.add_parser('events', help='list event notifications of a specified site')
cli_sites_events.set_defaults(func=sites_events)
cli_sites_events.add_argument('--id', nargs='?', default='', metavar='id', help='show event notifications for site with given ID')
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

setuptools.setup(
name='360monitoringcli',
version='1.0.18',
version='1.0.19',
description='360 Monitoring CLI',
long_description_content_type='text/markdown',
long_description=readme,
Expand Down

0 comments on commit d15adfa

Please sign in to comment.