diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 0000000..d2a7bd4
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,4 @@
+{
+ "directory": "www/vendor/",
+ "analytics": false
+}
diff --git a/.gitignore b/.gitignore
index cb7a60f..fab8eb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,4 +60,4 @@ target/
# application
www/*.html
www/hosts/*.html
-www/networks/*.html
+www/vendor
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..433de40
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,11 @@
+{
+ "name": "saltinventory",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "jquery": ">=2.1.4",
+ "jquery-number": ">=2.1.6",
+ "datatables": ">=1.10.9",
+ "bootstrap": "~3.3.5"
+ }
+}
diff --git a/saltinventory.py b/saltinventory.py
index 7471207..118ccc8 100755
--- a/saltinventory.py
+++ b/saltinventory.py
@@ -4,19 +4,17 @@
# Requirements:
#
# * salt
-# * python-netaddr
#
import salt.client
-from netaddr import *
+import salt.runner
+import salt.config
from jinja2 import Template, BaseLoader, TemplateNotFound, FileSystemLoader, Environment
# settings
config = {
'base_path': 'www/',
-'host_page_path': 'www/hosts/',
-'network_page_path': 'www/networks/',
'template_path': 'templates/',
}
@@ -26,94 +24,35 @@ class Inventorizer:
config = None
saltcmd = None
+ saltrun = None
host_list = {}
- network_list = {}
def __init__(self, config):
self.config = config
+
self.saltcmd = salt.client.LocalClient()
+
+ opts = salt.config.master_config('/etc/salt/master')
+ self.saltrun = salt.runner.RunnerClient(opts)
+
self.process()
def process(self):
self.collectHostData()
self.createHostList()
- self.collectNetworkData()
- self.createHostPages()
- self.createNetworkList()
- self.createNetworkPages()
def collectHostData(self):
self.host_list = self.saltcmd.cmd('*', 'grains.items')
-
- def collectNetworkData(self):
- result = self.saltcmd.cmd('*', 'network.interfaces')
- for hostname, hostdata in result.iteritems():
- for interface, interfacedata in hostdata.iteritems():
-
- if interfacedata.has_key('inet'):
- for netdata in interfacedata['inet']:
- ip = IPNetwork(netdata['address'] + '/' + netdata['netmask'])
- host = {'hostname': hostname, 'address': netdata['address'], 'netobj': ip}
- self.addNetworkHost(ip, host)
-
- if interfacedata.has_key('secondary'):
- for netdata in interfacedata['secondary']:
- ip = IPNetwork(netdata['address'] + '/' + netdata['netmask'])
- host = {'hostname': hostname, 'address': netdata['address'], 'netobj': ip}
- self.addNetworkHost(ip, host)
-
- if interfacedata.has_key('inet6'):
- for netdata in interfacedata['inet6']:
- ip = IPNetwork(netdata['address'] + '/' + netdata['prefixlen'])
- host = {'hostname': hostname, 'address': netdata['address'], 'netobj': ip}
- self.addNetworkHost(ip, host)
-
-
- def addNetworkHost(self, ip, host):
- if self.network_list.has_key(ip.cidr):
- self.network_list[ip.cidr].append(host)
- else:
- self.network_list[ip.cidr] = [host]
+ self.stat_list = self.saltrun.cmd('manage.status')
def createHostList(self):
fo = open(self.config['base_path'] + "hostlist.html", "wb")
env = Environment(loader = FileSystemLoader(config['template_path']))
template = env.get_template('hostlist_template.html')
- fo.write(template.render({'hostlist': self.host_list}))
+ fo.write(template.render({'hostlist': self.host_list, 'statlist': self.stat_list}))
fo.close
- def createHostPages(self):
- for hostname, hostdata in self.host_list.iteritems():
- self.createHostPage(hostname, hostdata)
-
- def createHostPage(self, hostname, hostdata):
- fo = open(self.config['host_page_path'] + hostname + ".html", "wb")
- env = Environment(loader = FileSystemLoader(config['template_path']))
- template = env.get_template('host_template.html')
- fo.write(template.render(hostdata))
- fo.close
-
- def createNetworkList(self):
- fo = open(self.config['base_path'] + "networklist.html", "wb")
- env = Environment(loader = FileSystemLoader(config['template_path']))
- env.filters['len'] = self.lenFilter
- template = env.get_template('networklist_template.html')
- fo.write(template.render({'networklist': self.network_list}))
- fo.close
-
- def createNetworkPages(self):
- for network, networkdata in self.network_list.iteritems():
- self.createNetworkPage(network, networkdata)
-
- def createNetworkPage(self, network, networkdata):
- fo = open(self.config['network_page_path'] + str(network.cidr).replace('/', '_') + ".html", "wb")
- env = Environment(loader = FileSystemLoader(config['template_path']))
- env.filters['replace'] = self.replaceFilter
- template = env.get_template('network_template.html')
- fo.write(template.render({'network': network, 'data': networkdata}))
- fo.close
-
def lenFilter(self, list):
return len(list)
diff --git a/templates/host_template.html b/templates/host_template.html
deleted file mode 100644
index 59eb696..0000000
--- a/templates/host_template.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
- {{ id }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- System information
- Generic
-
- - Operating System: {{ kernel }} ({{ kernelrelease }})
- - Distribution: {{ lsb_distrib_description }}
- - Machine type: {% if virtual != "physical" %} Virtual ({{ virtual }}) {% else %} Physical {% endif %}
- - Architecture: {{ osarch }}
- - Salt version: {{ saltversion }}
-
- CPU
-
- - Numer of CPUs: {{ num_cpus }}
- - CPU architecture: {{ cpuarch }}
- - CPU model: {{ cpu_model }}
-
- Memory
-
- - Total memory: {{ mem_total }}
-
- Storage
-
- Network
-
-
-
-
diff --git a/templates/hostlist_template.html b/templates/hostlist_template.html
index 8002c2f..4dab9d1 100644
--- a/templates/hostlist_template.html
+++ b/templates/hostlist_template.html
@@ -1,137 +1,137 @@
-
Host list
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
Inventory Salt minions list
+
-
- Hosts
+
+
+
+
Available minions
+
+
+
+ Name |
+ Machine type |
+ OS |
+ Roles |
+ IP |
+ RAM (MB) |
+ # CPUs |
+
+
+ Name |
+ Machine type |
+ OS |
+ Roles |
+ IP |
+ RAM (MB) |
+ # CPUs |
+
+
+
+ {% for name, data in hostlist.iteritems() %}
+
+
+
+ {{ name }}
+ |
+ {% if data.virtual != "physical" %} Virtual ({{ data.virtual }}) {% else %} Physical {% endif %} |
+ {{ data.lsb_distrib_description }} |
+ {% for role in data.roles %} {{ role }} {% endfor %} |
+ {{ data.fqdn_ip }} |
+ {{ data.mem_total }} |
+ {{ data.num_cpus }} |
+
+ {% endfor %}
+
+
+
+ Total:
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
Disconnected minions
+
+
+
+ Name |
+
+
+
+ {% for name in statlist %}
+
+ {{ name }} |
+
+ {% endfor %}
+
+
+
+
+
+
+ {% for name, data in hostlist.iteritems() %}
+
+
+
+
+
+
System information
+
Generic
+
+ - Operating System: {{ data.kernel }} ({{ data.kernelrelease }})
+ - Distribution: {{ data.lsb_distrib_description }}
+ - Machine type: {% if data.virtual != "physical" %} Virtual ({{ data.virtual }}) {% else %} Physical {% endif %}
+ - Architecture: {{ data.osarch }}
+ - Salt version: {{ data.saltversion }}
+
+
CPU
+
+ - Numer of CPUs: {{ data.num_cpus }}
+ - CPU architecture: {{ data.cpuarch }}
+ - CPU model: {{ data.cpu_model }}
+
+
Memory
+
+ - Total memory: {{ data.mem_total }}
+
+
Roles
+
+ {% for role in data.roles %}
+ - {{ role }}
+ {% endfor %}
+
+
+
+
+
+ {% endfor %}
+
-
-
-
-
- Name |
- OS |
- RAM (MB) |
- # CPUs |
-
-
- Name
- | OS
- | RAM
- | # CPUs
- |
-
-
- {% for name, data in hostlist.iteritems() %}
-
- {{ name }} |
- {{ data.lsb_distrib_description }} |
- {{ data.mem_total }} |
- {{ data.num_cpus }} |
-
- {% endfor %}
-
-
-
- |
- |
- |
- |
-
-
-
-
-
diff --git a/templates/network_template.html b/templates/network_template.html
deleted file mode 100644
index 04383e7..0000000
--- a/templates/network_template.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
{{ network.cidr }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Adresses
-
-
-
- Address |
- Host |
-
-
- Address
- | Host
- |
-
-
- {% for netdata in data %}
-
- {{ netdata['address'] }} |
- {{ netdata['hostname'] }} |
-
- {% endfor %}
-
-
-
- |
- |
-
-
-
-
-
-
diff --git a/templates/networklist_template.html b/templates/networklist_template.html
deleted file mode 100644
index 150fa97..0000000
--- a/templates/networklist_template.html
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
-
Network list
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Networks
-
-
-
-
- Network |
- Usage |
-
-
- Network
- | Usage
- |
-
-
- {% for network, data in networklist.iteritems() %}
-
- {{ network.cidr }} |
- {{ data|len }} |
-
- {% endfor %}
-
-
-
- |
- |
-
-
-
-
-
-
-
diff --git a/www/networks/.keep b/www/networks/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/www/res/inittable.js b/www/res/inittable.js
new file mode 100644
index 0000000..5e8b934
--- /dev/null
+++ b/www/res/inittable.js
@@ -0,0 +1,68 @@
+$(document).ready(function() {
+ $('#hostlist thead td').each( function () {
+ var title = $('#hostlist thead th').eq( $(this).index() ).text();
+ $(this).html( '
' );
+ } );
+
+ var table = $('#hostlist').DataTable({
+ 'paging': false,
+ 'info': false,
+ 'dom': 't',
+ 'footerCallback': function ( row, data, start, end, display ) {
+ var api = this.api(), data;
+
+ // Remove the formatting to get integer data for summation
+ var intVal = function ( i ) {
+ return typeof i === 'string' ?
+ i.replace(/[\$,]/g, '')*1 :
+ typeof i === 'number' ?
+ i : 0;
+ };
+
+ // Total over this page
+ hostsTotal = api
+ .rows()
+ .count();
+
+ // mem
+ memTotal = api
+ .column( 5, { page: 'current'} )
+ .data()
+ .reduce( function (a, b) {
+ return intVal(a) + intVal(b);
+ }, 0 );
+ // cpu
+ cpuTotal = api
+ .column( 6, { page: 'current'} )
+ .data()
+ .reduce( function (a, b) {
+ return intVal(a) + intVal(b);
+ }, 0 );
+
+ // Update footer
+ $( api.column( 1 ).footer() ).html(
+ $.number(hostsTotal, 0, '.', ' ')
+ );
+
+ $( api.column( 5 ).footer() ).html(
+ $.number(memTotal, 0, '.', ' ')
+ );
+
+ $( api.column( 6 ).footer() ).html(
+ cpuTotal
+ );
+ }
+ });
+
+ // Apply the search
+ table.columns().eq( 0 ).each( function ( colIdx ) {
+ $( 'input', table.column( colIdx ).header() ).on( 'keyup change', function () {
+ table
+ .column( colIdx )
+ .search( this.value, true )
+ .draw();
+ } );
+ } );
+
+ $('td.number').number( true, 0, '.', ' ' );
+});