Intro
I use monit intensively in my daily pro life, and I plugged that to a django application to always know how the ~300 VM are going.
In that article in the first part, I will describe all the possibilities I found with monit and the second, how to get the results of the probes and put that in a django app.
As I said, as I manage ~300VM, all the installation and configuration of monit is done with 2 ansible playbook, one to install the package, one to set monit and add new probes for all services (like oracle, tomcat, jboss, business services and so on) on each server
I - Monit
Install
yum install monit
or
apt install monit
Commands
monit summary
monit status
monit allows us to "group" the result of probe with a tag group eg
monit summary -g server
monit status -g server
monit summary
will render a table ; monit status
will render the details of each probe
Settings
depending on your OS or even version of distribution the config file can be /etc/monit/monitrc
or /etc/monit/monit.conf
sections of the config file
- run monit each ...
set daemon 30
- limit of various tests
set limits {
programOutput: 2 MB, # check program's output truncate limit
sendExpectBuffer: 256 B, # limit for send/expect protocol test
fileContentBuffer: 512 B, # limit for file content test
httpContentBuffer: 1 MB, # limit for HTTP content test
networkTimeout: 5 seconds # timeout for network I/O
programTimeout: 300 seconds # timeout for check program
stopTimeout: 30 seconds # timeout for service stop
startTimeout: 30 seconds # timeout for service start
restartTimeout: 30 seconds # timeout for service restart
}
you will need to change the default value of each of them when the programOutput
content will become larger (with custom programs for example)
- sending mail
set mailserver localhost
we set the name of the server that will send mail when alerts will occur
- mail content
set mail-format {
from: Monit <monit@$HOST>
subject: monit alert -- $EVENT $SERVICE
message: $EVENT Service $SERVICE
Date: $DATE
Action: $ACTION
Host: $HOST
Description: $DESCRIPTION
Your faithful employee,
Monit
--8<--
}
this will be the content of the mail that will be send when alerts will occur
- email to receive alert
set alert john@doe.com not on { instance, action }
- allow the http console to be accessing from a browser or curl
set httpd port 2812 and use address nameoftheserver_or_localhost
# use address localhost # only accept connection from localhost (drop if you use M/Monit)
allow localhost # allow localhost to connect to the server and
allow admin:monit # require user 'admin' with password 'monit'
#with ssl { # enable SSL/TLS and set path to server certificate
# pemfile: /etc/ssl/certs/monit.pem
#}
- checking system
check system $HOST
if loadavg (1min) > 22 for 20 cycles then alert
if loadavg (5min) > 17 for 20 cycles then alert
if cpu usage > 95% for 10 cycles then alert
if memory usage > 75% for 20 cycles then alert
if swap usage > 25% for 20 cycles then alert
- check filesystem
check filesystem root with path /
if space usage > 90% then alert
group server
check filesystem home with path /home
if space usage > 90% then alert
group server
this will check 2 partitions /
and /home
checking other services
we can check the existence of the PID file or a process matching a path like as follow
- nginx
check process nginx with pidfile /var/run/nginx.pid
start program = "/usr/sbin/service nginx start" with timeout 60 seconds
stop program = "/usr/sbin/service nginx stop"
if cpu > 60% for 2 cycles then alert
if cpu > 80% for 5 cycles then restart
if totalmem > 200.0 MB for 5 cycles then restart
if children > 250 then restart
if disk read > 500 kb/s for 10 cycles then alert
if disk write > 500 kb/s for 10 cycles then alert
if failed host localhost port 80 protocol http and request "/index.html" then restart
if 3 restarts within 5 cycles then unmonitor
group server
- postgresql
check process postgresql with pidfile /var/lib/pgsql/13/data/postmaster.pid
start program = "/usr/sbin/service postgresql-13 start"
stop program = "/usr/sbin/service postgresql-13 stop"
if failed host localhost port 5432 protocol pgsql then alert
group database
if the pid file disepears, an alert is raised
- oracle
check process MYORACLEDB matching "ora_pmon_MYORACLEDB"
if failed port 1521 then alert
group database
we just check the pmon process and its default 1521 port
- redis
check process redis matching "/usr/bin/redis-server"
start program = "/usr/sbin/service redis start"
stop program = "/usr/sbin/service redis stop"
if 2 restarts within 3 cycles then timeout
if totalmem > 100 Mb then alert
if children > 255 for 5 cycles then stop
if cpu usage > 95% for 3 cycles then restart
if failed host 127.0.0.1 port 6379 then restart
if 5 restarts within 5 cycles then timeout
group server
check process redis-sentinel matching "/usr/bin/redis-sentinel"
if failed port 26379 then alert
group server
- jboss and tomcat same thing (except for the match string)
check process MYJBOSS matching "Djboss.home.dir=/var/lib/MYJBOSS"
if failed
port 8082
for 3 cycles
then unmonitor
group appserver
we check that a process matches the expected string + check if the port 8082 is opened
- WebSphere
# check the PID of the appserver
check process WASINSTANCE with pidfile "/opt/IBM/WebSphere/AppServer/profiles/foxmask/logs/server1/server1.pid"
if failed
port 9093
for 3 cycles
then unmonitor
group appserver
- checking a django project
check process myproject with pidfile '/home/foxmask/Projects/nyuseu/gunicorn_nyuseu.pid'
if failed port 8001 for 2 cycles then alert
group server
- running "a ping" to check if one of my 'server' is still here
check host the_name_i_want_for_my_probe with address anotherserver
if failed ping then alert # IPv4 or IPv6
every "0,5,10,15,20,25,30,35,40,45,50,55 8-19 * * *"
group server
custom mail alert content
you may want to receive email with few of more details from a given probe that return an alert. Here is an example to send an alert with a different 'default' format we saw earlier.
check host partner_server with address partner.company1.com
if failed
port 443 protocol https
and request /GAMES/ with content = "Login"
then alert
alert joe.doe@company0.com
alert jane.doe@company0.com
with mail-format {
from: IT_Support@company0.com
subject: [$HOST] partner.company1.com does not respond $DATE
message: The application at the URL https://partner.company1.com with address https://partner.company1.com/GAMES/ is unavailable
}
every "13 8-19 * * 1-5"
group server
thus here, each 13 min from 8h to 19h from Monday to Friday, the server partner.company1.com is checked and if the https://partner.company1.com/GAMES/ is not found, raise an alert send to joe and jane with the given
sending alert to a Slack channel
check host server101 with address server101
if failed ping then exec "/home/foxmask/scripts/slack.sh" else if succeeded then exec "/home/foxmask/scripts/slack.sh"
alert joe.doe@company0.com
alert jane.doe@company0.com
with mail-format {
from: IT_Support@company0.com
subject: [$HOST] partner.company1.com does not respond $DATE
message: Ping has failed to server server101 $DATE
}
every "0,5,10,15,20,25,30,35,40,45,50,55 8-19 * * *"
group server
slack.sh
will look like this
set -e
set -u
URL=https://hooks.slack.com/services/<THE ID OR YOUR CUSTOM HOOK>
if test -z $URL
then
>&2 echo "No Slack webhook URL provided"
exit 1
fi
CHANNEL=projet
STATUS=${MONIT_EVENT:-unknown}
SERVICE=${MONIT_SERVICE:-?}
PAYLOAD="{
\"channel\": \"#${CHANNEL:-alerts}\",
\"username\": \"Monit\",
\"icon_emoji\": \":robot_face:\",
\"attachments\": [{
\"fallback\": \"${SERVICE} – ${MONIT_DESCRIPTION:-?}\",
\"mrkdwn_in\": [\"pretext\"],
\"pretext\": \"*${SERVICE}*\",
\"text\": \"${MONIT_DESCRIPTION:-?}\",
\"color\": \"${MONIT_COLOR:-$([[ $STATUS == *"succeeded"* ]] && echo good || echo danger)}\",
\"fields\": [
{ \"title\": \"Date\", \"value\": \"${MONIT_DATE:-$(date -R)}\", \"short\": true },
{ \"title\": \"Host\", \"value\": \"${MONIT_HOST:-$(hostname)}\", \"short\": true },
{ \"title\": \"Service\", \"value\": \"${SERVICE}\", \"short\": true },
{ \"title\": \"Status\", \"value\": \"${STATUS}\", \"short\": true }
]}
]
}"
curl -s -X POST --data-urlencode "payload=$PAYLOAD" $URL
(source https://peteris.rocks/blog/monit-configuration-with-slack/)
in the previous example, "group server", "group database" allow us to requests status of probe grouped by this keyword, for exemple :
$ monit summary -g server
$ monit status -g server
$ monit status -g database
II - Django application
After all those configuration,
- I made a management command that will read the "Servers" model
- run curl -XGET http://login:pass@server/_status?format=xml for each server
- convert the XML into a dict (thanks to xmltodict)
- update the data (probes) of the server into the database
models.py
a model a little bit long with manager with a Service
models that matches all monit use case.
# coding: utf-8
from django.db import models
class Server(models.Model):
"""
Server
"""
name = models.CharField(max_length=200, unique=True)
watch = models.BooleanField(default=True)
swap_limit = models.IntegerField()
cpu_limit = models.IntegerField()
vm = models.BooleanField(default=False)
class ServicesQS(models.QuerySet):
def ok(self):
return self.filter(status=True)
def ko(self):
return self.filter(status=False)
def system(self):
return self.filter(type="System")
def system_ok(self):
return self.filter(type="System", status=True)
def system_ko(self):
return self.filter(type="System", status=False)
def filesystem(self):
return self.filter(type="FileSystem")
def filesystem_ok(self):
return self.filter(type="FileSystem", status=True)
def file_system_ko(self):
return self.filter(type="FileSystem", status=False)
def network(self):
return self.filter(type="Network")
def network_ok(self):
return self.filter(type="Network", status=True)
def network_ko(self):
return self.filter(type="Network", status=False)
def files(self):
return self.filter(type="Files")
def files_ok(self):
return self.filter(type="Files", status=True)
def files_ko(self):
return self.filter(type="Files", status=False)
def directory(self):
return self.filter(type="Directory")
def directory_ok(self):
return self.filter(type="Directory", status=True)
def directory_ko(self):
return self.filter(type="Directory", status=False)
def host(self):
return self.filter(type="Host")
def host_ok(self):
return self.filter(type="Host", status=True)
def host_ko(self):
return self.filter(type="Host", status=False)
def process(self):
return self.filter(type="Process")
def process_ok(self):
return self.filter(type="Process", status=True)
def process_ko(self):
return self.filter(type="Process", status=False)
def services(self):
return self.filter(type="Services")
def services_ok(self):
return self.filter(type="Services", status=True)
def services_ko(self):
return self.filter(type="Services", status=False)
class ServicesMgr(models.Manager):
def get_queryset(self):
return ServicesQS(self.model, using=self._db) # Important!
def ok(self):
return self.get_queryset().ok()
def ko(self):
return self.get_queryset().ko()
def system(self):
return self.get_queryset().system()
def system_ok(self):
return self.get_queryset().system_ok()
def system_ko(self):
return self.get_queryset().system_ko()
def file_system(self):
return self.get_queryset().filesystem()
def filesystem_ok(self):
return self.get_queryset().filesystem_ok()
def filesystem_ko(self):
return self.get_queryset().file_system_ko()
def network(self):
return self.get_queryset().network()
def network_ok(self):
return self.get_queryset().network_ok()
def network_ko(self):
return self.get_queryset().network_ko()
def files(self):
return self.get_queryset().files()
def files_ok(self):
return self.get_queryset().files_ok()
def files_ko(self):
return self.get_queryset().files_ko()
def directory(self):
return self.get_queryset().directory()
def directory_ok(self):
return self.get_queryset().directory_ok()
def directory_ko(self):
return self.get_queryset().directory_ko()
def host(self):
return self.get_queryset().host()
def host_ok(self):
return self.get_queryset().host_ok()
def host_ko(self):
return self.get_queryset().host_ko()
def process(self):
return self.get_queryset().process()
def process_ok(self):
return self.get_queryset().process_ok()
def process_ko(self):
return self.get_queryset().process_ko()
def services(self):
return self.get_queryset().services()
def services_ok(self):
return self.get_queryset().services_ok()
def services_ko(self):
return self.get_queryset().services_ko()
class Services(models.Model):
"""
Service
"""
name = models.CharField(max_length=200)
server = models.ForeignKey(Server, blank=True, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now=True)
status = models.BooleanField()
status_string = models.TextField()
data_collected = models.DateTimeField(blank=True, null=True)
type = models.CharField(max_length=10, null=True)
objects = ServicesMgr() # manager to get the status ok/ko
class MonitServers(models.Model):
"""
MonitServer
"""
server = models.OneToOneField(
Server,
related_name="monit",
on_delete=models.CASCADE,
null=True
)
monit_user = models.CharField(max_length=10)
monit_pass = models.CharField(max_length=20)
monit_ip = models.CharField(max_length=40)
monit_port = models.IntegerField()
admin.py
from django.contrib import admin
from monitoring.models import Server, Services, MonitServers
class ServerAdmin(admin.ModelAdmin):
list_display = ('name', 'vm', 'swap_limit', 'cpu_limit')
ordering = ['name']
fields = ('name', 'watch', 'swap_limit', 'cpu_limit', 'vm')
search_fields = ['name']
class Meta:
ordering = ['name']
class ServicesAdmin(admin.ModelAdmin):
list_display = ('type', 'name', 'server', 'status', 'data_collected')
ordering = ['type', 'name']
search_fields = ['name', 'server__name']
class MonitServersAdmin(admin.ModelAdmin):
list_display = ('server', 'monit_user', 'monit_ip', 'monit_port')
ordering = ['server']
search_fields = ['server__name']
admin.site.register(Server, ServerAdmin)
admin.site.register(Services, ServicesAdmin)
admin.site.register(MonitServers, MonitServersAdmin)
management/commands/monit.py
# coding: utf-8
from datetime import datetime
from django.core.management.base import BaseCommand
from logging import getLogger
from monitoring.models import Server, MonitServers
from rich.console import Console
import xmltodict
# create logger
logger = getLogger('monitoring.monit')
console = Console()
console_warning = "bold yellow"
console_danger = "bold red"
console_info = "blue"
console_success = "green"
def get_monit_json(monit_obj):
"""
get the status of the server
:param server:
:param monit_ip:
:return: stats in json
"""
allstat = {'monit': {}}
url = "http://{monit_ip}:{monit_port}/_status?format=xml".format(monit_ip=monit_obj.monit_ip,
monit_port=monit_obj.monit_port)
console.print(monit_obj.monit_ip, url, style=console_info)
try:
res = requests.get(url, auth=(monit_obj.monit_user, monit_obj.monit_pass))
if res.status_code == 200:
try:
allstat = json.loads(json.dumps(xmltodict.parse(res.text)))
except xml.parsers.expat.ExpatError as e:
logger_error.error(e)
console.print(e, style=console_warning)
except requests.ConnectionError as e:
logger_error.error(e)
console.print(e, style=console_warning)
return allstat['monit']
def server_check_service(allstat):
"""
:return:
"""
# server info
server_memory = round(float(int(allstat['platform']['memory']) / 1024 / 1024), 2)
server_swap = round(float(int(allstat['platform']['swap']) / 1024 / 1024), 2)
# services
services = allstat['service']
# read the service returned by the curl for example
for service in services:
# type = FileSystem
if service['@type'] == '0':
programs = add_filesystem(programs, service)
# type = directory
elif service['@type'] == '1':
programs = add_dir(programs, service)
# type = file
elif service['@type'] == '2':
programs = add_files(programs, service)
# type = process
elif service['@type'] == '3':
programs = add_process(programs, service)
# type = host
elif service['@type'] == '4':
programs = add_hosts(programs, service)
# type = info Operating System
elif service['@type'] == '5':
programs = add_os(programs, service, server_memory, server_swap)
# type = 'custom probe' not covered in that blog post ;)
# elif service['@type'] == '7':
# [...]
return programs
class Command(BaseCommand):
help = 'Check the status of the servers'
def add_arguments(self, parser):
parser.add_argument('server',
type=str,
help='server name or "ALL"')
def handle(self, *args, **options):
"""
"""
console.print("Begin : Check services", style=console_success)
if options.get('server') == 'ALL':
servers = Server.objects.all()
else:
servers = Server.objects.filter(name=options.get('server'))
if len(servers) == 0:
log = "server {server} not found".format(server=options.get('server'))
console.print(log, style=console_danger)
for line in servers:
log = "Reresh data of {line}".format(line=line)
console.print(log, style=console_info)
monit_obj, created = MonitServers.objects.get_or_create(
server=line,
defaults={'monit_user': 'admin',
'monit_pass': 'monit',
'monit_ip': '127.0.0.1',
'monit_port': 2812},
)
programs = get_monit_json(monit_obj)
if len(programs) == 0:
trace = "Getting services from {server} failed from " \
"http://{monit_user}:***@{monit_ip}:{monit_port}/_status?format=xml"
trace = trace.format(server=monit_obj,
monit_user=monit_obj.monit_user,
monit_ip=monit_obj.monit_ip,
monit_port=monit_obj.monit_port)
logger_error.error(trace)
console.print(trace, style=console_danger)
return
if programs:
for program in programs:
log = "{} {} {} {}".format(line.name, program['name'], program['status'], program['status_string'])
logger.debug(log)
# [...]
# update Services model
console.print("End : Check services", style=console_success)
this command will launch a curl for each server which will requests the "monit" data then will convert XML to Dict and then update the model Service
views.py
a short view which display the list of services by server + the details of all service for the choosen server
# coding: utf-8
from django.db.models import Count
from django.views.generic import ListView, DetailView
from monitoring.models import Server
class Home(ListView):
"""
Home page
"""
context_object_name = "servers_list"
template_name = 'monitoring/home.html'
model = Server
def get_queryset(self):
return Server.objects.annotate(num_services=Count('services')).filter(num_services__gt=0).order_by('name')
class MonitoringServerDetail(DetailView):
"""
Detail page of a server
"""
model = Server
slug_field = 'name'
template_name = 'monitoring/server_detail.html'
def get_queryset(self):
return Server.objects.filter(name=self.kwargs['slug'])
templates/monitoring/home.html
that page will display all the server and the status of each probe
{% extends "base.html" %}
{% load static %}
{% block title %}Server Monitoring{% endblock %}
{% block menu_left %}
{% endblock %}
{% block bootstrap_css %}
<!-- CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
{% endblock %}
{% block content %}
<div class="col-lg-12 col-md-12">
<h1>Monitoring - <small class="text-muted">Server status</small></h1>
<div class="row row-cols-4 row-cols-md-4">
{% for server in servers_list %}
<div class="card-deck mb-3">
<div class="card">
<div class="card-body">
<div class="card_title">
<h5><a title="View details of server" href="{% url 'monitoring_server_detail' server.name %}">{{ server.name }}</a></h5>
</div>
<div class="card-text">
<table class="table table-hover">
<tbody>
<tr><td>System</td><td class="
{% if server.services_set.system_ok.count > 0 and server.services_set.system_ko.count == 0 %}table-success
{% elif server.services_set.system_ok.count > 0 and server.services_set.system_ko.count > 0 %}table-warning
{% elif server.services_set.system_ok.count == 0 and server.services_set.system_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}
"> </td></tr>
<tr><td>Filesystem</td><td class="
{% if server.services_set.filesystem_ok.count > 0 and server.services_set.filesystem_ko.count == 0 %}table-success
{% elif server.services_set.filesystem_ok.count > 0 and server.services_set.filesystem_ko.count > 0 %}table-warning
{% elif server.services_set.filesystem_ok.count == 0 and server.services_set.filesystem_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
<tr><td>File</td><td class="
{% if server.services_set.files_ok.count > 0 and server.services_set.files_ko.count == 0 %}table-success
{% elif server.services_set.files_ok.count > 0 and server.services_set.files_ko.count > 0 %}table-warning
{% elif server.services_set.files_ok.count == 0 and server.services_set.files_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
<tr><td>Directory</td><td class="
{% if server.services_set.directory_ok.count > 0 and server.services_set.directory_ko.count == 0 %}table-success
{% elif server.services_set.directory_ok.count > 0 and server.services_set.directory_ko.count > 0 %}table-warning
{% elif server.services_set.directory_ok.count == 0 and server.services_set.directory_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
<tr><td>Network</td><td class="
{% if server.services_set.network_ok.count > 0 and server.services_set.network_ko.count == 0 %}table-success
{% elif server.services_set.network_ok.count > 0 and server.services_set.network_ko.count > 0 %}table-warning
{% elif server.services_set.network_ok.count == 0 and server.services_set.network_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
<tr><td>Host</t><td class="
{% if server.services_set.host_ok.count > 0 and server.services_set.host_ko.count == 0 %}table-success
{% elif server.services_set.host_ok.count > 0 and server.services_set.host_ko.count > 0 %}table-warning
{% elif server.services_set.host_ok.count == 0 and server.services_set.host_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
<tr><td>Services</td><td class="
{% if server.services_set.services_ok.count > 0 and server.services_set.services_ko.count == 0 %}table-success
{% elif server.services_set.services_ok.count > 0 and server.services_set.services_ko.count > 0 %}table-warning
{% elif server.services_set.services_ok.count == 0 and server.services_set.services_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
<tr><td>Process</td><td class="
{% if server.services_set.process_ok.count > 0 and server.services_set.process_ko.count == 0 %}table-success
{% elif server.services_set.process_ok.count > 0 and server.services_set.process_ko.count > 0 %}table-warning
{% elif server.services_set.process_ok.count == 0 and server.services_set.process_ko.count == 0 %}table-secondary
{% else %}table-danger{% endif %}"> </td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<span class="badge btn btn-success"> all is ok </span>
<span class="badge btn btn-warning"> some services are ko </span>
<span class="badge btn btn-danger "> all is ko </span>
<span class="badge btn btn-secondary"> non monitored </span>
</div>
{% endblock %}
{% block bootstrap_js %}
<!-- jQuery and JS bundle w/ Popper.js -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
{% endblock bootstrap_js %}
that page will display the status details of one server
templates/monitoring/server_detail.html
{% extends "base.html" %}
{% block title %}Service monitoring - {{ object }}{% endblock %}
{% block menu_left %}
{% endblock %}
{% block content %}
<div class="col-sm-12 col-md-12">
<a href="{% url 'monitoring_home' %}" class="glyphicon glyphicon-arrow-left btn btn-success"> Retour</a>
<div class="thumbnail">
<div class="caption">
<h3><span class="glyphicon glyphicon-tasks"></span> {{ server.name }}</h3>
<div>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#system_{{ server.name }}" aria-controls="system_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-hdd"></span> System</a></li>
<li role="presentation"><a href="#filesystem_{{ server.name }}" aria-controls="fileystem_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-list"></span> FileSystem</a></li>
<li role="presentation"><a href="#file_{{ server.name }}" aria-controls="file_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-list"></span> File</a></li>
<li role="presentation"><a href="#directory_{{ server.name }}" aria-controls="directory_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-folder-open"></span> Directory</a></li>
<li role="presentation"><a href="#network_{{ server.name }}" aria-controls="network_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-signal"></span> Network</a></li>
<li role="presentation"><a href="#host_{{ server.name }}" aria-controls="host_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-home"></span> Host</a></li>
<li role="presentation"><a href="#process_{{ server.name }}" aria-controls="process_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-home"></span> Process</a></li>
<li role="presentation"><a href="#services_{{ server.name }}" aria-controls="services_{{ server.name }}" role="tab" data-toggle="tab"><span class="glyphicon glyphicon-retweet"></span> Services</a></li>
</ul>
</div>
<div class="tab-content">
{% include "monitoring/probes.html" with probe_name="system" server_name=server.name services_ko=server.services_set.system_ko services_ok=server.services_set.system_ok %}
{% include "monitoring/probes.html" with probe_name="filesystem" server_name=server.name services_ko=server.services_set.filesystem_ko services_ok=server.services_set.filesystem_ok %}
{% include "monitoring/probes.html" with probe_name="file" server_name=server.name services_ko=server.services_set.file_ko services_ok=server.services_set.files_ok %}
{% include "monitoring/probes.html" with probe_name="directory" server_name=server.name services_ko=server.services_set.directory_ko services_ok=server.services_set.directory_ok %}
{% include "monitoring/probes.html" with probe_name="network" server_name=server.name services_ko=server.services_set.network_ko services_ok=server.services_set.network_ok %}
{% include "monitoring/probes.html" with probe_name="host" server_name=server.name services_ko=server.services_set.host_ko services_ok=server.services_set.host_ok %}
{% include "monitoring/probes.html" with probe_name="services" server_name=server.name services_ko=server.services_set.services_ko services_ok=server.services_set.services_ok %}
{% include "monitoring/probes.html" with probe_name="process" server_name=server.name services_ko=server.services_set.process_ko services_ok=server.services_set.process_ok %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block extrajs %}
<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
$('li.connection-top').hide()
setTimeout(function() {
$('p.connection-middle').slideUp("slow", function() {
$('li.connection-top').show("slow")
});
}, 4000);
});
//]]>
</script>
{% endblock extrajs %}
templates/monitoring/probes.html
<div role="tabpanel" class="tab-pane fade {% if probe_name == 'system' %} in active {% endif %}" id="{{ probe_name }}_{{ server_name }}">
<table class="table table-striped table-hover">
<tbody>
{% for service in services_ko %}
<tr class="table-success">
<td>{{ service.name }}</td>
<td>
<button type="button" class="btn btn-lg btn-danger" data-toggle="tooltips" title="{{ service.status_string }}"><span class="glyphicon glyphicon-minus-sign"></span></button>
</td>
</tr>
{% endfor %}
{% for service in services_ok %}
<tr class="table-danger">
<td>{{ service.name }}</td>
<td>
<button type="button" class="btn btn-lg btn-success" data-toggle="tooltips" title="{{ service.status_string }}"><span class="glyphicon glyphicon-ok-sign"></span></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
And , That's all Folks!!