├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── Puppetfile ├── README.md ├── Rakefile ├── files ├── config │ └── host │ │ └── rrdcached.service └── plugins │ ├── gentoo_lastupdated │ ├── kvm_cpu │ ├── kvm_cpu.CentOS.7 │ ├── kvm_io │ ├── kvm_io.CentOS.7 │ ├── kvm_mem │ ├── kvm_mem.CentOS.7 │ ├── kvm_net │ ├── kvm_net.CentOS.7 │ ├── rrdcached │ ├── tinydns │ ├── xen │ ├── xen_cpu │ ├── xen_mem │ ├── xen_memory │ ├── xen_traffic_all │ ├── xen_vbd │ └── xen_vm ├── lib └── facter │ ├── acpi_available.rb │ └── legacy_interfaces.rb ├── manifests ├── client.pp ├── client │ ├── base.pp │ ├── darwin.pp │ ├── debian.pp │ ├── gentoo.pp │ ├── openbsd.pp │ └── params.pp ├── host.pp ├── host │ └── cgi.pp ├── plugin.pp ├── plugin │ ├── deploy.pp │ └── scriptpaths.pp ├── plugins │ ├── base.pp │ ├── debian.pp │ ├── djbdns.pp │ ├── dom0.pp │ ├── gentoo.pp │ ├── interfaces.pp │ ├── kvm.pp │ ├── linux.pp │ ├── muninhost.pp │ ├── openbsd.pp │ ├── physical.pp │ ├── selinux.pp │ ├── setup.pp │ └── vserver.pp ├── register.pp ├── register │ └── snmp.pp ├── remoteplugin.pp └── snmp_collector.pp ├── metadata.json ├── spec ├── classes │ ├── munin_client_base_spec.rb │ ├── munin_client_spec.rb │ ├── munin_host_cgi_spec.rb │ ├── munin_host_spec.rb │ └── munin_plugins_interfaces_spec.rb ├── defines │ └── munin_plugin_spec.rb ├── spec_helper.rb └── spec_helper_system.rb └── templates ├── client.erb └── munin-node.conf.erb /.gitignore: -------------------------------------------------------------------------------- 1 | spec/fixtures/ 2 | vendor/ 3 | .tmp/* 4 | .librarian/* 5 | *.lock 6 | pkg/ 7 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 1.8.7 3 | - 1.9.3 4 | - 2.0.0 5 | script: 'bundle exec rake spec' 6 | env: 7 | - PUPPET_VERSION=3.8.6 8 | - PUPPET_VERSION=4.0.0 9 | matrix: 10 | exclude: 11 | - rvm: 1.8.7 12 | env: PUPPET_VERSION=4.0.0 13 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | if ENV.key?('PUPPET_VERSION') 4 | puppetversion = "~> #{ENV['PUPPET_VERSION']}" 5 | else 6 | puppetversion = ['>= 7.0'] 7 | end 8 | 9 | gem 'rake' 10 | gem 'librarian-puppet' 11 | gem 'puppet', puppetversion 12 | gem 'puppet-lint' 13 | gem 'puppetlabs_spec_helper' 14 | -------------------------------------------------------------------------------- /Puppetfile: -------------------------------------------------------------------------------- 1 | forge 'https://forge.puppetlabs.com' 2 | 3 | mod 'puppetlabs/stdlib' 4 | mod 'puppetlabs/concat' 5 | mod 'camptocamp/systemd' 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Puppet-Munin 2 | 3 | [![Build Status](https://travis-ci.org/duritong/puppet-munin.png?branch=master)](https://travis-ci.org/duritong/puppet-munin) 4 | 5 | Munin is a performance monitoring system which creates nice RRD graphs and has 6 | a very easy plugin interface. The munin homepage is http://munin.projects.linpro.no/ 7 | 8 | ## Requirements 9 | 10 | * puppet 2.7 or newer 11 | * install the `concat` and `stdlib` modules - the munin module depends on functions that are defined and installed via these modules 12 | * you will need storedconfigs enabled in your puppet setup, to do that you need to add a line to your `puppet.conf` in your `[puppetmasterd]` section which says: 13 | 14 | storeconfigs=true 15 | 16 | * You may wish to immediately setup a `mysql`/ `pgsql` database for your storedconfigs, as 17 | the default method uses sqlite, and is not very efficient, to do that you need lines 18 | such as the following below the `storeconfigs=true` line (adjust as needed): 19 | 20 | dbadapter=mysql 21 | dbserver=localhost 22 | dbuser=puppet 23 | dbpassword=puppetspasswd 24 | 25 | ## Usage 26 | 27 | Your modules directory will need all the files included in this repository placed under a directory called `munin`. 28 | 29 | ### Master configuration 30 | 31 | In the node definition in your site.pp for your main munin host, add the following: 32 | 33 | class { 'munin::host': } 34 | 35 | If you want cgi graphing you can pass `cgi_graphing => true`. (For CentOS this is enabled in the default header config) for more information, see: http://munin.projects.linpro.no/wiki/CgiHowto 36 | 37 | ### Client configuration 38 | 39 | For every host you wish to gather munin statistics, add the class `munin::client` to that 40 | node. You will want to set the class parameter `allow` to be the IP(s) of the munin 41 | collector, this defines what IP is permitted to connect to the node, for example: 42 | 43 | node foo { 44 | class { 'munin::client': allow => '192.168.0.1'} 45 | } 46 | 47 | for multiple munin nodes, you can pass an array: 48 | 49 | class { 'munin::client': allow => [ '192.168.0.1', '10.0.0.1' ] } 50 | 51 | 3. In the node definition in your site.pp for your main munin host, add the following: 52 | 53 | ### Local plugins 54 | 55 | If there are particular munin plugins you want to enable or configure, you define them 56 | in the node definition, like follows: 57 | 58 | # Enable monitoring of disk stats in bytes 59 | munin::plugin { 'df_abs': } 60 | 61 | # Use a non-standard plugin path to use custom plugins 62 | munin::plugin { 'spamassassin': 63 | ensure => present, 64 | script_path_in => '/usr/local/share/munin-plugins', 65 | } 66 | 67 | # For wildcard plugins (eg. ip_, snmp_, etc.), use the name variable to 68 | # configure the plugin name, and the ensure parameter to indicate the base 69 | # plugin name to which you want a symlink, for example: 70 | munin::plugin { [ 'ip_192.168.0.1', 'ip_10.0.0.1' ]: 71 | ensure => 'ip_' 72 | } 73 | 74 | # Use a special config to pass parameters to the plugin 75 | munin::plugin { 76 | [ 'apache_accesses', 'apache_processes', 'apache_volume' ]: 77 | ensure => present, 78 | config => 'env.url http://127.0.0.1:80/server-status?auto' 79 | } 80 | 81 | Note: The plugin must be installed at the client. For listing available plugins run as root `munin-node-configure --suggest` 82 | 83 | ### External plugins 84 | 85 | For deploying plugins which are not available at client, you can fetch them from puppet 86 | master using `munin::plugin::deploy`. 87 | 88 | munin::plugin::deploy { 'redis': 89 | source => 'munin/plugins/redis/redis_', 90 | config => '' # pass parameters to plugin 91 | } 92 | 93 | In this example the file on master would be located in: 94 | 95 | {modulepath}/munin/files/plugins/redis/redis_ 96 | 97 | Module path is specified in `puppet.conf`, you can find out your `{modulepath}` easily by tying 98 | in console `puppet config print modulepath`. 99 | 100 | 101 | ### Multiple munin instances 102 | 103 | If you have Linux-Vservers configured, you will likely have multiple munin-node processes 104 | competing for the default port 4949, for those nodes, set an alternate port for munin-node 105 | to run on by putting something similar to the following class parameter: 106 | 107 | class { 'munin::client': allow => '192.168.0.1', port => '4948' } 108 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler.require(:rake) 3 | 4 | require 'puppetlabs_spec_helper/rake_tasks' 5 | require 'puppet-lint/tasks/puppet-lint' 6 | 7 | Rake::Task[:lint].clear 8 | PuppetLint::RakeTask.new :lint do |config| 9 | config.ignore_paths = ["spec/**/*.pp", "vendor/**/*.pp"] 10 | config.log_format = '%{path}:%{line}:%{KIND}: %{message}' 11 | config.disable_checks = [ "class_inherits_from_params_class", "80chars" ] 12 | end 13 | 14 | # use librarian-puppet to manage fixtures instead of .fixtures.yml 15 | # offers more possibilities like explicit version management, forge downloads,... 16 | task :librarian_spec_prep do 17 | sh "librarian-puppet install --path=spec/fixtures/modules/" 18 | pwd = `pwd`.strip 19 | unless File.directory?("#{pwd}/spec/fixtures/modules/munin") 20 | sh "ln -s #{pwd} #{pwd}/spec/fixtures/modules/munin" 21 | end 22 | end 23 | task :spec_prep => :librarian_spec_prep 24 | 25 | 26 | task :default => [:spec, :lint] 27 | -------------------------------------------------------------------------------- /files/config/host/rrdcached.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Munin rrdcached 3 | 4 | [Service] 5 | Restart=always 6 | User=munin 7 | Group=munin 8 | ExecStart=/usr/bin/rrdcached \ 9 | -g -B -b /var/lib/munin/ \ 10 | -p /run/munin/munin-rrdcached.pid \ 11 | -F -j /var/lib/munin/rrdcached-journal/ \ 12 | -m 0660 -l unix:/run/munin/rrdcached.sock \ 13 | -w 1800 -z 1800 -f 3600 14 | ExecStartPost=/bin/sleep 1 ; /bin/setfacl -m u:apache:rw /run/munin/rrdcached.sock 15 | 16 | [Install] 17 | WantedBy=multi-user.target 18 | -------------------------------------------------------------------------------- /files/plugins/gentoo_lastupdated: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # -*- perl -*- 3 | # 4 | # (C) 2007 immerda project 5 | # 6 | # Plugin to monitor the last update of the gentoo 7 | # 8 | # Parameters: 9 | # 10 | # config 11 | # autoconf 12 | # 13 | # $Id: users.in 1212 2006-10-29 20:11:58Z janl $ 14 | # 15 | #%# family=auto 16 | #%# capabilities=autoconf 17 | 18 | # update /etc/munin/plugin-conf.d/munin-node with: 19 | # [gentoo_*] 20 | # user root 21 | # env.logfile /var/log/emerge.log 22 | # env.tail /usr/bin/tail 23 | # env.grep /bin/grep 24 | 25 | my $logfile = $ENV{'logfile'} || '/var/log/emerge.log'; 26 | my $grep = $ENV{'grep'} || `which grep`; 27 | my $date = $ENV{'date'} || `which date`; 28 | my $tail = $ENV{'tail'} || `which tail`; 29 | chomp($grep); 30 | chomp($date); 31 | chomp($tail); 32 | 33 | if ( defined($ARGV[0])) { 34 | if ($ARGV[0] eq 'autoconf') { 35 | print "yes\n"; 36 | exit 0; 37 | } 38 | 39 | if ( $ARGV[0] eq "config" ) { 40 | print "graph_title Gentoo: Last update X days ago\n"; 41 | #print "graph_args --base 1000 -l 0\n"; 42 | print "graph_vlabel days\n"; 43 | print "graph_scale no\n"; 44 | print "graph_category system\n"; 45 | #print "graph_printf %.1lf\n"; 46 | print "lastupdated.label last updated [d ago]\n"; 47 | print "lastupdated.type GAUGE\n"; 48 | #print "tty.draw AREASTACK\n"; 49 | #print "tty.colour 00FF00\n"; 50 | exit 0; 51 | } 52 | } 53 | 54 | $days = 0; 55 | $last = 0; 56 | $now = 0; 57 | 58 | $l=`$grep "emerge" $logfile | $grep world | $grep -v fetchonly | tail -1`; 59 | 60 | ($last,$rest) = split /:/,$l; 61 | $now = `$date +%s`; 62 | if($last eq "" or $last == 0 or $now == 0 or $date eq ""){ 63 | $days = ""; 64 | }else{ 65 | $days=($now-$last)/60/60/24; # in tagen 66 | } 67 | 68 | print "lastupdated.value $days\n"; 69 | 70 | # vim:syntax=perl 71 | 72 | -------------------------------------------------------------------------------- /files/plugins/kvm_cpu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | =encoding utf8 4 | 5 | =head1 NAME 6 | 7 | kvm_cpu - show CPU usage of VM 8 | 9 | 10 | =head1 CONFIGURATION 11 | 12 | Parsed environment variables: 13 | 14 | vmsuffix: part of VM name to be removed 15 | 16 | 17 | =head1 LICENSE 18 | 19 | GPLv3 20 | 21 | SPDX-License-Identifier: GPL-3.0-only 22 | 23 | 24 | =head1 AUTHORS 25 | 26 | Maxence Dunnewind 27 | 28 | Rodolphe Quiédeville 29 | 30 | 31 | =head1 MAGIC MARKERS 32 | 33 | #%# capabilities=autoconf 34 | #%# family=contrib 35 | 36 | =cut 37 | """ 38 | 39 | import os 40 | import re 41 | import sys 42 | from subprocess import Popen, PIPE 43 | 44 | 45 | def config(vm_names): 46 | ''' Print the plugin's config 47 | @param vm_names : a list of "cleaned" vms' name 48 | ''' 49 | percent = 100 * len( 50 | list( 51 | filter( 52 | lambda x: x[0:3] == 'cpu' and x[3] != ' ', open('/proc/stat', 'r').readlines()))) 53 | 54 | base_config = """graph_title KVM Virtual Machine CPU usage 55 | graph_vlabel %% 56 | graph_category virtualization 57 | graph_scale no 58 | graph_period second 59 | graph_info This graph shows the current CPU used by virtual machines 60 | graph_args --base 1000 -r --lower-limit 0 --upper-limit %d""" % percent 61 | print(base_config) 62 | for vm in vm_names: 63 | print("%s_cpu.label %s" % (vm, vm)) 64 | print("%s_cpu.min 0" % vm) 65 | print("%s_cpu.type DERIVE" % vm) 66 | print("%s_cpu.draw AREASTACK" % vm) 67 | print("%s_cpu.info percent of cpu time used by virtual machine" % vm) 68 | 69 | 70 | def clean_vm_name(vm_name): 71 | ''' Replace all special chars 72 | @param vm_name : a vm's name 73 | @return cleaned vm's name 74 | ''' 75 | # suffix part defined in conf 76 | suffix = os.getenv('vmsuffix') 77 | if suffix: 78 | vm_name = re.sub(suffix, '', vm_name) 79 | # proxmox uses kvm with -name parameter 80 | parts = vm_name.split('\x00') 81 | if parts[0].endswith('kvm'): 82 | try: 83 | return parts[parts.index('-name') + 1] 84 | except ValueError: 85 | pass 86 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 87 | 88 | 89 | def detect_kvm(): 90 | ''' Check if kvm is installed ''' 91 | if os.path.isfile("/usr/libexec/qemu-kvm"): 92 | return True 93 | else: 94 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 95 | kvm.communicate() 96 | return not bool(kvm.returncode) 97 | 98 | def find_vm_names(pids): 99 | '''Find and clean vm names from pids 100 | @return a dictionary of {pids : cleaned vm name} 101 | ''' 102 | result = {} 103 | for pid in pids: 104 | cmdline = open("/proc/%s/cmdline" % pid, "r") 105 | result[pid] = clean_vm_name( 106 | re.sub(r"^.*guest=([a-zA-Z0-9.-_-]*).*$", r"\1", cmdline.readline())) 107 | return result 108 | 109 | 110 | def list_pids(): 111 | ''' Find the pid of kvm processes 112 | @return a list of pids from running kvm 113 | ''' 114 | pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE) 115 | return pid.communicate()[0].decode().split() 116 | 117 | 118 | def fetch(vms): 119 | ''' Fetch values for a list of pids 120 | @param dictionary {kvm_pid: cleaned vm name} 121 | ''' 122 | for pid, name in vms.items(): 123 | user, system = open("/proc/%s/stat" % pid, 'r').readline().split(' ')[13:15] 124 | print('%s_cpu.value %d' % (name, int(user) + int(system))) 125 | 126 | 127 | if __name__ == "__main__": 128 | if len(sys.argv) > 1: 129 | if sys.argv[1] in ['autoconf', 'detect']: 130 | if detect_kvm(): 131 | print("yes") 132 | else: 133 | print("no") 134 | elif sys.argv[1] == "config": 135 | config(find_vm_names(list_pids()).values()) 136 | else: 137 | fetch(find_vm_names(list_pids())) 138 | else: 139 | fetch(find_vm_names(list_pids())) 140 | -------------------------------------------------------------------------------- /files/plugins/kvm_cpu.CentOS.7: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show CPU used by vm 6 | # 7 | # Copyright Maxence Dunnewind, Rodolphe Quiédeville 8 | # 9 | # License : GPLv3 10 | # 11 | # parsed environment variables: 12 | # vmsuffix: part of vm name to be removed 13 | # 14 | #%# capabilities=autoconf 15 | #%# family=contrib 16 | 17 | import re, os, sys 18 | from subprocess import Popen, PIPE 19 | 20 | def config(vm_names): 21 | ''' Print the plugin's config 22 | @param vm_names : a list of "cleaned" vms' name 23 | ''' 24 | percent = len(filter(lambda x: x[0:3] == 'cpu' and x[3] != ' ', open('/proc/stat', 'r').readlines())) * 100 25 | 26 | base_config = """graph_title KVM Virtual Machine CPU usage 27 | graph_vlabel %% 28 | graph_category KVM 29 | graph_scale no 30 | graph_period second 31 | graph_info This graph shows the current CPU used by virtual machines 32 | graph_args --base 1000 -r --lower-limit 0 --upper-limit %d""" % percent 33 | print base_config 34 | draw = "AREA" 35 | for vm in vm_names: 36 | print "%s_cpu.label %s" % (vm, vm) 37 | print "%s_cpu.min 0" % vm 38 | print "%s_cpu.type DERIVE" % vm 39 | print "%s_cpu.draw %s" % (vm, draw) 40 | print "%s_cpu.info percent of cpu time used by virtual machine" % vm 41 | draw = "STACK" 42 | 43 | 44 | def clean_vm_name(vm_name): 45 | ''' Replace all special chars 46 | @param vm_name : a vm's name 47 | @return cleaned vm's name 48 | ''' 49 | 50 | # suffix part defined in conf 51 | suffix = os.getenv('vmsuffix') 52 | if suffix: 53 | vm_name = re.sub(suffix,'',vm_name) 54 | 55 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 56 | 57 | def detect_kvm(): 58 | ''' Check if kvm is installed 59 | ''' 60 | if os.path.isfile("/usr/libexec/qemu-kvm"): 61 | return True 62 | else: 63 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 64 | kvm.communicate() 65 | return not bool(kvm.returncode) 66 | 67 | def find_vm_names(pids): 68 | '''Find and clean vm names from pids 69 | @return a dictionnary of {pids : cleaned vm name} 70 | ''' 71 | result = {} 72 | for pid in pids: 73 | cmdline = open("/proc/%s/cmdline" % pid, "r") 74 | result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",r"\1", cmdline.readline())) 75 | return result 76 | 77 | def list_pids(): 78 | ''' Find the pid of kvm processes 79 | @return a list of pids from running kvm 80 | ''' 81 | pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE) 82 | return pid.communicate()[0].split() 83 | 84 | def fetch(vms): 85 | ''' Fetch values for a list of pids 86 | @param dictionnary {kvm_pid: cleaned vm name} 87 | ''' 88 | for ( pid, name ) in vms.iteritems(): 89 | ( user, system ) = open("/proc/%s/stat" % pid, 'r').readline().split(' ')[13:15] 90 | print '%s_cpu.value %d' % ( name, int(user) + int(system) ) 91 | 92 | if __name__ == "__main__": 93 | if len(sys.argv) > 1: 94 | if sys.argv[1] in ['autoconf', 'detect']: 95 | if detect_kvm(): 96 | print "yes" 97 | else: 98 | print "no" 99 | elif sys.argv[1] == "config": 100 | config(find_vm_names(list_pids()).values()) 101 | else: 102 | fetch(find_vm_names(list_pids())) 103 | else: 104 | fetch(find_vm_names(list_pids())) 105 | -------------------------------------------------------------------------------- /files/plugins/kvm_io: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show io by vm 6 | # 7 | # Copyright Maxence Dunnewind, Rodolphe Quiédeville 8 | # 9 | # License : GPLv3 10 | # 11 | # parsed environment variables: 12 | # vmsuffix: part of vm name to be removed 13 | # 14 | #%# capabilities=autoconf 15 | #%# family=contrib 16 | 17 | import re, os, sys 18 | from subprocess import Popen, PIPE 19 | 20 | def config(vm_names): 21 | ''' Print the plugin's config 22 | @param vm_names : a list of "cleaned" vms' name 23 | ''' 24 | base_config = """graph_title KVM Virtual Machine IO usage 25 | graph_vlabel Bytes read(-)/written(+) per second 26 | graph_category virtualization 27 | graph_info This graph shows the block device I/O used of virtual machines 28 | graph_args --base 1024 29 | """ 30 | print(base_config) 31 | 32 | for vm in vm_names: 33 | print("%s_read.label %s" % (vm, vm)) 34 | print("%s_read.type COUNTER" % vm) 35 | print("%s_read.min 0" % vm) 36 | print("%s_read.info I/O used by virtual machine %s" % (vm, vm)) 37 | print("%s_read.graph no" % vm) 38 | print("%s_write.label %s" % (vm, vm)) 39 | print("%s_write.type COUNTER" % vm) 40 | print("%s_write.min 0" % vm) 41 | print("%s_write.negative %s_read" % (vm, vm)) 42 | print("%s_write.info I/O used by virtual machine %s" % (vm, vm)) 43 | 44 | def clean_vm_name(vm_name): 45 | ''' Replace all special chars 46 | @param vm_name : a vm's name 47 | @return cleaned vm's name 48 | ''' 49 | # suffix part defined in conf 50 | suffix = os.getenv('vmsuffix') 51 | if suffix: 52 | vm_name = re.sub(suffix,'',vm_name) 53 | # proxmox uses kvm with -name parameter 54 | parts = vm_name.split('\x00') 55 | if (parts[0].endswith('kvm')): 56 | try: 57 | return parts[parts.index('-name')+1] 58 | except ValueError: 59 | pass 60 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 61 | 62 | def fetch(vms): 63 | ''' Fetch values for a list of pids 64 | @param dictionary {kvm_pid: cleaned vm name} 65 | ''' 66 | res = {} 67 | for pid in vms: 68 | f = open("/proc/%s/io" % pid, "r") 69 | for line in f.readlines(): 70 | if "read_bytes" in line: 71 | read = line.split()[1] 72 | print("%s_read.value %s" % (vms[pid], read)) 73 | if "write_bytes" in line: 74 | write = line.split()[1] 75 | print("%s_write.value %s" % (vms[pid], write)) 76 | break 77 | f.close() 78 | 79 | def detect_kvm(): 80 | ''' Check if kvm is installed 81 | ''' 82 | if os.path.isfile("/usr/libexec/qemu-kvm"): 83 | return True 84 | else: 85 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 86 | kvm.communicate() 87 | return not bool(kvm.returncode) 88 | 89 | def find_vm_names(pids): 90 | '''Find and clean vm names from pids 91 | @return a dictionary of {pids : cleaned vm name} 92 | ''' 93 | result = {} 94 | for pid in pids: 95 | cmdline = open("/proc/%s/cmdline" % pid, "r") 96 | result[pid] = clean_vm_name(re.sub(r"^.*guest=([a-zA-Z0-9.-_-]*).*$",r"\1", cmdline.readline())) 97 | return result 98 | 99 | def list_pids(): 100 | ''' Find the pid of kvm processes 101 | @return a list of pids from running kvm 102 | ''' 103 | pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE) 104 | return pid.communicate()[0].decode().split() 105 | 106 | if __name__ == "__main__": 107 | if len(sys.argv) > 1: 108 | if sys.argv[1] in ['autoconf', 'detect']: 109 | if detect_kvm(): 110 | print("yes") 111 | else: 112 | print("no") 113 | elif sys.argv[1] == "config": 114 | config(find_vm_names(list_pids()).values()) 115 | else: 116 | fetch(find_vm_names(list_pids())) 117 | else: 118 | fetch(find_vm_names(list_pids())) 119 | -------------------------------------------------------------------------------- /files/plugins/kvm_io.CentOS.7: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show io by vm 6 | # 7 | # Copyright Maxence Dunnewind, Rodolphe Quiédeville 8 | # 9 | # License : GPLv3 10 | # 11 | # parsed environment variables: 12 | # vmsuffix: part of vm name to be removed 13 | # 14 | #%# capabilities=autoconf 15 | #%# family=contrib 16 | 17 | import re, os, sys 18 | from subprocess import Popen, PIPE 19 | 20 | def config(vm_names): 21 | ''' Print the plugin's config 22 | @param vm_names : a list of "cleaned" vms' name 23 | ''' 24 | base_config = """graph_title KVM Virtual Machine IO usage 25 | graph_vlabel Bytes read(-)/written(+) per second 26 | graph_category KVM 27 | graph_info This graph shows the block device I/O used of virtual machines 28 | graph_args --base 1024""" 29 | print base_config 30 | 31 | for vm in vm_names: 32 | print "%s_read.label %s" % (vm, vm) 33 | print "%s_read.type COUNTER" % vm 34 | print "%s_read.min 0" % vm 35 | print "%s_read.draw LINE1" % vm 36 | print "%s_read.info I/O used by virtual machine %s" % (vm, vm) 37 | print "%s_write.label %s" % (vm, vm) 38 | print "%s_write.type COUNTER" % vm 39 | print "%s_write.min 0" % vm 40 | print "%s_write.draw LINE1" % vm 41 | print "%s_write.negative %s_read" % (vm, vm) 42 | print "%s_write.info I/O used by virtual machine %s" % (vm, vm) 43 | 44 | def clean_vm_name(vm_name): 45 | ''' Replace all special chars 46 | @param vm_name : a vm's name 47 | @return cleaned vm's name 48 | ''' 49 | # suffix part defined in conf 50 | suffix = os.getenv('vmsuffix') 51 | if suffix: 52 | vm_name = re.sub(suffix,'',vm_name) 53 | 54 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 55 | 56 | def fetch(vms): 57 | ''' Fetch values for a list of pids 58 | @param dictionnary {kvm_pid: cleaned vm name} 59 | ''' 60 | res = {} 61 | for pid in vms: 62 | f = open("/proc/%s/io" % pid, "r") 63 | for line in f.readlines(): 64 | if "read_bytes" in line: 65 | read = line.split()[1] 66 | print "%s_read.value %s" % (vms[pid], read) 67 | if "write_bytes" in line: 68 | write = line.split()[1] 69 | print "%s_write.value %s" % (vms[pid], write) 70 | break 71 | f.close() 72 | 73 | def detect_kvm(): 74 | ''' Check if kvm is installed 75 | ''' 76 | if os.path.isfile("/usr/libexec/qemu-kvm"): 77 | return True 78 | else: 79 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 80 | kvm.communicate() 81 | return not bool(kvm.returncode) 82 | 83 | def find_vm_names(pids): 84 | '''Find and clean vm names from pids 85 | @return a dictionnary of {pids : cleaned vm name} 86 | ''' 87 | result = {} 88 | for pid in pids: 89 | cmdline = open("/proc/%s/cmdline" % pid, "r") 90 | result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",r"\1", cmdline.readline())) 91 | return result 92 | 93 | def list_pids(): 94 | ''' Find the pid of kvm processes 95 | @return a list of pids from running kvm 96 | ''' 97 | pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE) 98 | return pid.communicate()[0].split() 99 | 100 | if __name__ == "__main__": 101 | if len(sys.argv) > 1: 102 | if sys.argv[1] in ['autoconf', 'detect']: 103 | if detect_kvm(): 104 | print "yes" 105 | else: 106 | print "no" 107 | elif sys.argv[1] == "config": 108 | config(find_vm_names(list_pids()).values()) 109 | else: 110 | fetch(find_vm_names(list_pids())) 111 | else: 112 | fetch(find_vm_names(list_pids())) 113 | -------------------------------------------------------------------------------- /files/plugins/kvm_mem: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show amount of memory used by vm 6 | # 7 | # Copyright Maxence Dunnewind, Rodolphe Quiédeville, Adrien Pujol 8 | # 9 | # License : GPLv3 10 | # 11 | # parsed environment variables: 12 | # vmsuffix: part of vm name to be removed 13 | # 14 | #%# capabilities=autoconf 15 | #%# family=contrib 16 | 17 | import re, os, sys 18 | from subprocess import Popen, PIPE 19 | 20 | def config(vm_names): 21 | ''' Print the plugin's config 22 | @param vm_names : a list of "cleaned" vms' name 23 | ''' 24 | base_config = """graph_title KVM Virtual Machine Memory usage 25 | graph_vlabel Bytes 26 | graph_category virtualization 27 | graph_info This graph shows the current amount of memory used by virtual machines 28 | graph_args --base 1024 -l 0""" 29 | print(base_config) 30 | for vm in vm_names: 31 | print("%s_mem.label %s" % (vm, vm)) 32 | print("%s_mem.type GAUGE" % vm) 33 | print("%s_mem.draw %s" % (vm, "AREASTACK")) 34 | print("%s_mem.info memory used by virtual machine %s" % (vm, vm)) 35 | 36 | 37 | def clean_vm_name(vm_name): 38 | ''' Replace all special chars 39 | @param vm_name : a vm's name 40 | @return cleaned vm's name 41 | ''' 42 | # suffix part defined in conf 43 | suffix = os.getenv('vmsuffix') 44 | if suffix: 45 | vm_name = re.sub(suffix,'',vm_name) 46 | 47 | # proxmox uses kvm with -name parameter 48 | parts = vm_name.split('\x00') 49 | if (parts[0].endswith('kvm')): 50 | try: 51 | return parts[parts.index('-name')+1] 52 | except ValueError: 53 | pass 54 | 55 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 56 | 57 | def fetch(vms): 58 | ''' Fetch values for a list of pids 59 | @param dictionary {kvm_pid: cleaned vm name} 60 | ''' 61 | res = {} 62 | for pid in vms: 63 | try: 64 | cmdline = open("/proc/%s/cmdline" % pid, "r") 65 | amount = re.sub(r"^.*-m\x00(.*)\x00-smp.*$",r"\1", cmdline.readline()) 66 | amount = int(amount) * 1024 * 1024 67 | print("%s_mem.value %s" % (vms[pid], amount)) 68 | except: 69 | cmdline = open("/proc/%s/cmdline" % pid, "r") 70 | amount = re.sub(r"^.*-m\x00(\d+).*$",r"\1", cmdline.readline()) 71 | amount = int(amount) * 1024 * 1024 72 | print("%s_mem.value %s" % (vms[pid], amount)) 73 | 74 | def detect_kvm(): 75 | ''' Check if kvm is installed 76 | ''' 77 | if os.path.isfile("/usr/libexec/qemu-kvm"): 78 | return True 79 | else: 80 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 81 | kvm.communicate() 82 | return not bool(kvm.returncode) 83 | 84 | def find_vm_names(pids): 85 | '''Find and clean vm names from pids 86 | @return a dictionary of {pids : cleaned vm name} 87 | ''' 88 | result = {} 89 | for pid in pids: 90 | cmdline = open("/proc/%s/cmdline" % pid, "r") 91 | result[pid] = clean_vm_name(re.sub(r"^.*guest=([a-zA-Z0-9.-_-]*).*$",r"\1", cmdline.readline())) 92 | return result 93 | 94 | def list_pids(): 95 | ''' Find the pid of kvm processes 96 | @return a list of pids from running kvm 97 | ''' 98 | pid = Popen("pidof qemu-kvm qemu-system-x86_64 kvm", shell=True, stdout=PIPE) 99 | return pid.communicate()[0].decode().split() 100 | 101 | if __name__ == "__main__": 102 | if len(sys.argv) > 1: 103 | if sys.argv[1] in ['autoconf', 'detect']: 104 | if detect_kvm(): 105 | print("yes") 106 | else: 107 | print("no") 108 | elif sys.argv[1] == "config": 109 | config(find_vm_names(list_pids()).values()) 110 | else: 111 | fetch(find_vm_names(list_pids())) 112 | else: 113 | fetch(find_vm_names(list_pids())) 114 | -------------------------------------------------------------------------------- /files/plugins/kvm_mem.CentOS.7: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show amount of memory used by vm 6 | # 7 | # Copyright Maxence Dunnewind, Rodolphe Quiédeville, Adrien Pujol 8 | # 9 | # License : GPLv3 10 | # 11 | # parsed environment variables: 12 | # vmsuffix: part of vm name to be removed 13 | # 14 | #%# capabilities=autoconf 15 | #%# family=contrib 16 | 17 | import re, os, sys 18 | from subprocess import Popen, PIPE 19 | 20 | def config(vm_names): 21 | ''' Print the plugin's config 22 | @param vm_names : a list of "cleaned" vms' name 23 | ''' 24 | base_config = """graph_title KVM Virtual Machine Memory usage 25 | graph_vlabel Bytes 26 | graph_category KVM 27 | graph_info This graph shows the current amount of memory used by virtual machines 28 | graph_args --base 1024""" 29 | print base_config 30 | draw = "AREA" 31 | for vm in vm_names: 32 | print "%s_mem.label %s" % (vm, vm) 33 | print "%s_mem.type GAUGE" % vm 34 | if draw == 'AREA': 35 | print "%s_mem.min 0" % vm 36 | print "%s_mem.draw %s" % (vm, draw) 37 | print "%s_mem.info memory used by virtual machine %s" % (vm, vm) 38 | draw = "STACK" 39 | 40 | 41 | def clean_vm_name(vm_name): 42 | ''' Replace all special chars 43 | @param vm_name : a vm's name 44 | @return cleaned vm's name 45 | ''' 46 | # suffix part defined in conf 47 | suffix = os.getenv('vmsuffix') 48 | if suffix: 49 | vm_name = re.sub(suffix,'',vm_name) 50 | 51 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 52 | 53 | def fetch(vms): 54 | ''' Fetch values for a list of pids 55 | @param dictionnary {kvm_pid: cleaned vm name} 56 | ''' 57 | res = {} 58 | for pid in vms: 59 | try: 60 | cmdline = open("/proc/%s/cmdline" % pid, "r") 61 | amount = re.sub(r"^.*-m\x00(.*)\x00-smp.*$",r"\1", cmdline.readline()) 62 | ammount = int(amount) * 1024 * 1024 63 | print "%s_mem.value %s" % (vms[pid], ammount) 64 | except: 65 | cmdline = open("/proc/%s/cmdline" % pid, "r") 66 | amount = re.sub(r"^.*-m\x00(\d+).*$",r"\1", cmdline.readline()) 67 | ammount = int(amount) * 1024 * 1024 68 | print "%s_mem.value %s" % (vms[pid], ammount) 69 | 70 | def detect_kvm(): 71 | ''' Check if kvm is installed 72 | ''' 73 | if os.path.isfile("/usr/libexec/qemu-kvm"): 74 | return True 75 | else: 76 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 77 | kvm.communicate() 78 | return not bool(kvm.returncode) 79 | 80 | def find_vm_names(pids): 81 | '''Find and clean vm names from pids 82 | @return a dictionnary of {pids : cleaned vm name} 83 | ''' 84 | result = {} 85 | for pid in pids: 86 | cmdline = open("/proc/%s/cmdline" % pid, "r") 87 | result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",r"\1", cmdline.readline())) 88 | return result 89 | 90 | def list_pids(): 91 | ''' Find the pid of kvm processes 92 | @return a list of pids from running kvm 93 | ''' 94 | pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE) 95 | return pid.communicate()[0].split() 96 | 97 | if __name__ == "__main__": 98 | if len(sys.argv) > 1: 99 | if sys.argv[1] in ['autoconf', 'detect']: 100 | if detect_kvm(): 101 | print "yes" 102 | else: 103 | print "no" 104 | elif sys.argv[1] == "config": 105 | config(find_vm_names(list_pids()).values()) 106 | else: 107 | fetch(find_vm_names(list_pids())) 108 | else: 109 | fetch(find_vm_names(list_pids())) 110 | -------------------------------------------------------------------------------- /files/plugins/kvm_net: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show the network I/O per vm 6 | # On redhat based systems 7 | # 8 | # Copyright Igor Borodikhin 9 | # Copyright Peter Meier 10 | # 11 | # License : GPLv3 12 | # 13 | # 14 | # parsed environment variables: 15 | # vmsuffix: part of vm name to be removed 16 | # 17 | #%# capabilities=autoconf 18 | #%# family=contrib 19 | 20 | import re, os, sys 21 | from subprocess import Popen, PIPE 22 | 23 | def config(vms): 24 | ''' Print the plugin's config 25 | @param vm_names : a list of "cleaned" vms' name 26 | ''' 27 | base_config = """graph_title KVM Network I/O 28 | graph_vlabel Bytes rx(-)/tx(+) per second 29 | graph_category virtualization 30 | graph_info This graph shows the network I/O of the virtual machines 31 | graph_args --base 1024""" 32 | print(base_config) 33 | for pid in vms: 34 | macs = get_vm_macs(pid) 35 | i = 0 36 | for mac in macs: 37 | print("%s_eth%s_in.label %s_eth%s" % (vms[pid],i, vms[pid], i)) 38 | print("%s_eth%s_in.type COUNTER" % (vms[pid], i)) 39 | print("%s_eth%s_in.min 0" % (vms[pid],i)) 40 | print("%s_eth%s_in.draw LINE2" % (vms[pid],i)) 41 | print("%s_eth%s_out.negative %s_eth%s_in" % (vms[pid], i, vms[pid], i)) 42 | print("%s_eth%s_out.label %s_eth%s" % (vms[pid], i, vms[pid], i)) 43 | print("%s_eth%s_out.type COUNTER" % (vms[pid], i)) 44 | print("%s_eth%s_out.min 0" % (vms[pid], i)) 45 | print("%s_eth%s_out.draw LINE2" % (vms[pid], i)) 46 | i += 1 47 | 48 | def clean_vm_name(vm_name): 49 | ''' Replace all special chars 50 | @param vm_name : a vm's name 51 | @return cleaned vm's name 52 | ''' 53 | # suffix part defined in conf 54 | suffix = os.getenv('vmsuffix') 55 | if suffix: 56 | vm_name = re.sub(suffix,'',vm_name) 57 | 58 | return re.sub(r"[^a-zA-Z0-9_\-]", "_", vm_name) 59 | 60 | def fetch(vms): 61 | ''' Fetch values for a list of pids 62 | @param dictionnary {kvm_pid: cleaned vm name} 63 | ''' 64 | res = {} 65 | macs_to_inf = find_macs_to_inf() 66 | interfaces = {} 67 | for pid in vms: 68 | macs = get_vm_macs(pid) 69 | i = 0 70 | for mac in macs: 71 | inf = macs_to_inf[mac] 72 | with open("/sys/class/net/%s/statistics/rx_packets" % inf, 'r') as f: 73 | print("%s_eth%s_in.value %s" % (vms[pid], i, f.readline().split("\n")[0])), 74 | with open("/sys/class/net/%s/statistics/tx_packets" % inf, 'r') as f: 75 | print("%s_eth%s_out.value %s" % (vms[pid], i, f.readline().split("\n")[0])), 76 | i += 1 77 | 78 | def detect_kvm(): 79 | ''' Check if kvm is installed 80 | ''' 81 | if os.path.isfile("/usr/libexec/qemu-kvm"): 82 | return True 83 | else: 84 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 85 | kvm.communicate() 86 | return not bool(kvm.returncode) 87 | 88 | def find_vm_names(pids): 89 | '''Find and clean vm names from pids 90 | @return a dictionnary of {pids : cleaned vm name} 91 | ''' 92 | result = {} 93 | for pid in pids: 94 | cmdline = open("/proc/%s/cmdline" % pid, "r") 95 | result[pid] = clean_vm_name(re.sub(r"^.*guest=([a-zA-Z0-9.-_-]*).*$",r"\1", cmdline.readline())) 96 | return result 97 | 98 | def get_vm_macs(pid): 99 | '''Find macs for a pid 100 | @return the mac addresses for a specified pid 101 | ''' 102 | cmdline = open("/proc/%s/cmdline" % pid, "r") 103 | line = cmdline.readline() 104 | # macs are fe:... on the host 105 | macs = [ re.sub(r"^\d{2}",'fe',p.split('=')[1]) for p in line.split(",") if re.match(r"^mac(addr)?=",p) ] 106 | return macs 107 | 108 | def list_pids(): 109 | ''' Find the pid of kvm processes 110 | @return a list of pids from running kvm 111 | ''' 112 | pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE) 113 | return pid.communicate()[0].decode().split() 114 | 115 | def find_macs_to_inf(): 116 | ''' Find interfaces for vms 117 | @return a dictionary of macs to inf 118 | ''' 119 | result = {} 120 | inf = "" 121 | kvm = Popen("ip a | grep -E -A 1 '(tap|vnet)' | awk '{print $2}' | grep -v '^$'", shell=True, stdout=PIPE) 122 | res = kvm.communicate()[0].decode().split('\n') 123 | for line in res: 124 | if len(line) > 0: 125 | if re.match(r"^tap.*", line): 126 | inf = re.sub(r"(tap[^:]+):", r"\1", line) 127 | elif re.match(r"^vnet.*", line): 128 | inf = re.sub(r"(vnet[^:]+):", r"\1", line) 129 | else: 130 | result[line] = inf 131 | 132 | return result 133 | 134 | if __name__ == "__main__": 135 | if len(sys.argv) > 1: 136 | if sys.argv[1] in ['autoconf', 'detect']: 137 | if detect_kvm(): 138 | print("yes") 139 | else: 140 | print("no") 141 | elif sys.argv[1] == "config": 142 | config(find_vm_names(list_pids())) 143 | else: 144 | fetch(find_vm_names(list_pids())) 145 | else: 146 | fetch(find_vm_names(list_pids())) 147 | 148 | -------------------------------------------------------------------------------- /files/plugins/kvm_net.CentOS.7: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # vim: set fileencoding=utf-8 4 | # 5 | # Munin plugin to show the network I/O per vm 6 | # On redhat based systems 7 | # 8 | # Copyright Igor Borodikhin 9 | # Copyright Peter Meier 10 | # 11 | # License : GPLv3 12 | # 13 | # 14 | # parsed environment variables: 15 | # vmsuffix: part of vm name to be removed 16 | # 17 | #%# capabilities=autoconf 18 | #%# family=contrib 19 | 20 | import re, os, sys 21 | from subprocess import Popen, PIPE 22 | 23 | def config(vms): 24 | ''' Print the plugin's config 25 | @param vm_names : a list of "cleaned" vms' name 26 | ''' 27 | base_config = """graph_title KVM Network I/O 28 | graph_vlabel Bytes rx(-)/tx(+) per second 29 | graph_category KVM 30 | graph_info This graph shows the network I/O of the virtual machines 31 | graph_args --base 1024""" 32 | print base_config 33 | for pid in vms: 34 | macs = get_vm_macs(pid) 35 | i = 0 36 | for mac in macs: 37 | print "%s_eth%s_in.label %s_eth%s" % (vms[pid],i, vms[pid], i) 38 | print "%s_eth%s_in.type COUNTER" % (vms[pid], i) 39 | print "%s_eth%s_in.min 0" % (vms[pid],i) 40 | print "%s_eth%s_in.draw LINE2" % (vms[pid],i) 41 | print "%s_eth%s_out.negative %s_eth%s_in" % (vms[pid], i, vms[pid], i) 42 | print "%s_eth%s_out.label %s_eth%s" % (vms[pid], i, vms[pid], i) 43 | print "%s_eth%s_out.type COUNTER" % (vms[pid], i) 44 | print "%s_eth%s_out.min 0" % (vms[pid], i) 45 | print "%s_eth%s_out.draw LINE2" % (vms[pid], i) 46 | i += 1 47 | 48 | def clean_vm_name(vm_name): 49 | ''' Replace all special chars 50 | @param vm_name : a vm's name 51 | @return cleaned vm's name 52 | ''' 53 | # suffix part defined in conf 54 | suffix = os.getenv('vmsuffix') 55 | if suffix: 56 | vm_name = re.sub(suffix,'',vm_name) 57 | 58 | return re.sub(r"[^a-zA-Z0-9_]", "_", vm_name) 59 | 60 | def fetch(vms): 61 | ''' Fetch values for a list of pids 62 | @param dictionnary {kvm_pid: cleaned vm name} 63 | ''' 64 | res = {} 65 | macs_to_inf = find_macs_to_inf() 66 | interfaces = {} 67 | for pid in vms: 68 | macs = get_vm_macs(pid) 69 | i = 0 70 | for mac in macs: 71 | inf = macs_to_inf[mac] 72 | with open("/sys/class/net/%s/statistics/rx_packets" % inf, 'r') as f: 73 | print "%s_eth%s_in.value %s" % (vms[pid], i, f.readline()), 74 | with open("/sys/class/net/%s/statistics/tx_packets" % inf, 'r') as f: 75 | print "%s_eth%s_out.value %s" % (vms[pid], i, f.readline()), 76 | i += 1 77 | 78 | def detect_kvm(): 79 | ''' Check if kvm is installed 80 | ''' 81 | if os.path.isfile("/usr/libexec/qemu-kvm"): 82 | return True 83 | else: 84 | kvm = Popen("which kvm", shell=True, stdout=PIPE) 85 | kvm.communicate() 86 | return not bool(kvm.returncode) 87 | 88 | def find_vm_names(pids): 89 | '''Find and clean vm names from pids 90 | @return a dictionnary of {pids : cleaned vm name} 91 | ''' 92 | result = {} 93 | for pid in pids: 94 | cmdline = open("/proc/%s/cmdline" % pid, "r") 95 | result[pid] = clean_vm_name(re.sub(r"^.*-name\x00([a-zA-Z0-9.-_-]*)\x00\-.*$",r"\1", cmdline.readline())) 96 | return result 97 | 98 | def get_vm_macs(pid): 99 | '''Find macs for a pid 100 | @return the mac addresses for a specified pid 101 | ''' 102 | cmdline = open("/proc/%s/cmdline" % pid, "r") 103 | line = cmdline.readline() 104 | # macs are fe:... on the host 105 | macs = [ re.sub(r"^\d{2}",'fe',p.split('=')[1]) for p in line.split(",") if re.match(r"^mac(addr)?=",p) ] 106 | return macs 107 | 108 | def list_pids(): 109 | ''' Find the pid of kvm processes 110 | @return a list of pids from running kvm 111 | ''' 112 | pid = Popen("pidof qemu-kvm kvm", shell=True, stdout=PIPE) 113 | return pid.communicate()[0].split() 114 | 115 | def find_macs_to_inf(): 116 | ''' Find interfaces for vms 117 | @return a dictionary of macs to inf 118 | ''' 119 | result = {} 120 | inf = "" 121 | kvm = Popen("ip a | grep -E -A 1 '(tap|vnet)' | awk '{print $2}' | grep -v '^$'", shell=True, stdout=PIPE) 122 | res = kvm.communicate()[0].split('\n') 123 | for line in res: 124 | if len(line) > 0: 125 | if re.match(r"^tap.*", line): 126 | inf = re.sub(r"(tap[^:]+):", r"\1", line) 127 | elif re.match(r"^vnet.*", line): 128 | inf = re.sub(r"(vnet[^:]+):", r"\1", line) 129 | else: 130 | result[line] = inf 131 | 132 | return result 133 | 134 | if __name__ == "__main__": 135 | if len(sys.argv) > 1: 136 | if sys.argv[1] in ['autoconf', 'detect']: 137 | if detect_kvm(): 138 | print "yes" 139 | else: 140 | print "no" 141 | elif sys.argv[1] == "config": 142 | config(find_vm_names(list_pids())) 143 | else: 144 | fetch(find_vm_names(list_pids())) 145 | else: 146 | fetch(find_vm_names(list_pids())) 147 | 148 | -------------------------------------------------------------------------------- /files/plugins/rrdcached: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # from https://raw.githubusercontent.com/munin-monitoring/munin/stable-2.0/plugins/node.d.debug/rrdcached.in 3 | 4 | use strict; 5 | use warnings; 6 | 7 | use IO::Socket::UNIX; 8 | 9 | $| = 1; 10 | 11 | my $arg = shift; 12 | if ($arg && $arg eq "config") { 13 | print "graph_title rrdcached stats\n"; 14 | print "QueueLength.label Queue length\n"; 15 | print "UpdatesReceived.label UpdatesReceived\n"; 16 | print "UpdatesReceived.type DERIVE\n"; 17 | print "FlushesReceived.label FlushesReceived\n"; 18 | print "FlushesReceived.type DERIVE\n"; 19 | print "UpdatesWritten.label UpdatesWritten\n"; 20 | print "UpdatesWritten.type DERIVE\n"; 21 | print "DataSetsWritten.label DataSetsWritten\n"; 22 | print "DataSetsWritten.type DERIVE\n"; 23 | print "TreeNodesNumber.label TreeNodesNumber\n"; 24 | print "TreeDepth.label TreeDepth\n"; 25 | print "JournalBytes.label JournalBytes\n"; 26 | print "JournalBytes.type DERIVE\n"; 27 | print "JournalRotate.label JournalRotate\n"; 28 | print "JournalRotate.type DERIVE\n"; 29 | exit 0; 30 | } 31 | 32 | my $sock = new IO::Socket::UNIX( 33 | Type => SOCK_STREAM, 34 | Peer => "/run/munin/rrdcached.sock", 35 | ) or die "Cannot open socket : $!"; 36 | 37 | print $sock "STATS\n"; 38 | print $sock "QUIT\n"; 39 | 40 | # skip first line 41 | <$sock>; 42 | print map { s/: /.value /; $_; } <$sock>; 43 | 44 | exit 0; 45 | -------------------------------------------------------------------------------- /files/plugins/tinydns: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -T 2 | 3 | # tinydns-munin-plugin + 4 | # Copyright (C) 2007 admin at immerda.ch 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | # with the HELP of 21 | # tinygraph -- a RRDtool frontend for tinydns statistics 22 | # Copyright (C) 2005 Ulrich Zehl 23 | 24 | #use strict; # to activate .... 25 | 26 | 27 | #use Time::TAI64 qw(tai2unix); 28 | 29 | $A = 0; 30 | $NS = 0; 31 | $CNAME = 0; 32 | $SOA = 0; 33 | $PTR = 0; 34 | $HINFO = 0; 35 | $MX = 0; 36 | $TXT = 0; 37 | $RP = 0; 38 | $SIG = 0; 39 | $KEY = 0; 40 | $AAAA = 0; 41 | $A6 = 0; 42 | $IXFR = 0; 43 | $AXFR = 0; 44 | $ANY = 0; 45 | 46 | $logfile = $ENV{logdir} || "/var/tinydns/log/main/current"; 47 | 48 | if ( $ARGV[0] and $ARGV[0] eq "config" ) 49 | { 50 | print "host_name $ENV{FQDN}\n"; 51 | print "graph_title tinydns\n"; 52 | print "graph_args --base 1000 -l 0\n"; 53 | print "graph_category DNS\n"; 54 | print "a.type COUNTER\n"; 55 | print "mx.type COUNTER\n"; 56 | 57 | print "a.label A\n"; 58 | print "ns.label NS\n"; 59 | print "cname.label CNAME\n"; 60 | print "soa.label SOA\n"; 61 | print "ptr.label PTR\n"; 62 | print "mx.label MX\n"; 63 | print "aaaa.label AAAA\n"; 64 | print "any.label ANY\n"; 65 | print "hinfo.label HINFO\n"; 66 | print "txt.label TXT\n"; 67 | print "rp.label RP\n"; 68 | print "sig.label SIG\n"; 69 | print "key.label KEY\n"; 70 | print "a6.label A6\n"; 71 | print "ixfr.label IXFR\n"; 72 | print "axfr.label AXFR\n"; 73 | 74 | print "a.type COUNTER\n"; 75 | print "ns.type COUNTER\n"; 76 | print "cname.type COUNTER\n"; 77 | print "soa.type COUNTER\n"; 78 | print "ptr.type COUNTER\n"; 79 | print "mx.type COUNTER\n"; 80 | print "aaaa.type COUNTER\n"; 81 | print "any.type COUNTER\n"; 82 | print "hinfo.type COUNTER\n"; 83 | print "txt.type COUNTER\n"; 84 | print "rp.type COUNTER\n"; 85 | print "sig.type COUNTER\n"; 86 | print "key.type COUNTER\n"; 87 | print "a6.type COUNTER\n"; 88 | print "ixfr.type COUNTER\n"; 89 | print "axfr.type COUNTER\n"; 90 | exit 0; 91 | } 92 | 93 | my %querytypes = ( 94 | '0001' => 'A', 95 | '0002' => 'NS', 96 | '0005' => 'CNAME', 97 | '0006' => 'SOA', 98 | '000c' => 'PTR', 99 | '000d' => 'HINFO', 100 | '000f' => 'MX', 101 | '0010' => 'TXT', 102 | '0011' => 'RP', 103 | '0018' => 'SIG', 104 | '0019' => 'KEY', 105 | '001c' => 'AAAA', 106 | '0026' => 'A6', 107 | '00fb' => 'IXFR', 108 | '00fc' => 'AXFR', 109 | '00ff' => 'ANY', 110 | ); 111 | 112 | my %sum = ( 113 | (map {$_ => 0} values %querytypes), 114 | ); 115 | 116 | sub process_line($) 117 | { 118 | my $line = shift; 119 | if ($line =~ /^(@[a-f0-9]{24}) ([a-f0-9]{8}):[a-f0-9]{4}:[a-f0-9]{4} ([\+\-IC\/]) ([a-f0-9]{4}) (.+)$/) 120 | { 121 | #my $time = tai2unix($1); 122 | my $ip = join(".", unpack("C*", pack("H8", $2))); 123 | my $rtype = $3; 124 | my $qtype = $querytypes{$4}; 125 | #my $qstring = $5; # currently unused 126 | 127 | if ($rtype eq '+') 128 | { 129 | if ($qtype eq 'A'){$A++;}; 130 | if ($qtype eq 'NS'){$NS++;}; 131 | if ($qtype eq 'CNAME'){$CNAME++;}; 132 | if ($qtype eq 'SOA'){$SOA++;}; 133 | if ($qtype eq 'PTR'){$PTR++;}; 134 | if ($qtype eq 'HINFO'){$HINFO++;}; 135 | if ($qtype eq 'MX'){$MX++;}; 136 | if ($qtype eq 'TXT'){$TXT++;}; 137 | if ($qtype eq 'RP'){$RP++;}; 138 | if ($qtype eq 'SIG'){$SIG++;}; 139 | if ($qtype eq 'KEY'){$KEY++;}; 140 | if ($qtype eq 'AAAA'){$AAAA++;}; 141 | if ($qtype eq 'A6'){$A6++;}; 142 | if ($qtype eq 'IXFR'){$IXFR++;}; 143 | if ($qtype eq 'AXFR'){$AXFR++;}; 144 | if ($qtype eq 'ANY'){$ANY++;}; 145 | } 146 | } 147 | } 148 | 149 | open(LOG, "<$logfile") or die "Error opening $logfile: $!"; 150 | 151 | while () 152 | { 153 | process_line($_); 154 | } 155 | 156 | print "a.value $A\n"; 157 | print "ns.value $NS\n"; 158 | print "cname.value $CNAME\n"; 159 | print "soa.value $SOA\n"; 160 | print "ptr.value $PTR\n"; 161 | print "mx.value $MX\n"; 162 | print "aaaa.value $AAAA\n"; 163 | print "any.value $ANY\n"; 164 | print "hinfo.value $HINFO\n"; 165 | print "txt.value $TXT\n"; 166 | print "rp.value $RP\n"; 167 | print "sig.value $SIG\n"; 168 | print "key.value $KEY\n"; 169 | print "a6.value $A6\n"; 170 | print "ixfr.value $IXFR\n"; 171 | print "axfr.value $AXFR\n"; 172 | 173 | -------------------------------------------------------------------------------- /files/plugins/xen: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Script to monitor CPU usage of Xen domains 4 | # 5 | # Parameters understood: 6 | # 7 | # conifg (required) 8 | # autoconf (optinal - used by munin-config) 9 | # 10 | 11 | if [ "$1" = "autoconf" ]; then 12 | if which xm > /dev/null ; then 13 | echo yes 14 | exit 0 15 | fi 16 | echo "no (xm not found)" 17 | exit 1 18 | fi 19 | 20 | # we cache xm list for 5 min for perfomance reasons 21 | ((find /var/lib/munin/plugin-state/xm_list.state -mmin -5 2>&1 | grep -qE '^\/var\/lib\/munin\/plugin-state\/xm_list\.state$') && \ 22 | [ `cat /var/lib/munin/plugin-state/xm_list.state | wc -l` -gt 1 ]) || \ 23 | /usr/sbin/xm list | grep -v "^Name .* ID" > /var/lib/munin/plugin-state/xm_list.state 24 | 25 | if [ "$1" = "config" ]; then 26 | 27 | echo 'graph_title Xen Domain Utilerisation' 28 | echo 'graph_args --base 1000 -l 0' 29 | echo 'graph_scale no' 30 | echo 'graph_vlabel mS' 31 | echo 'graph_category xen' 32 | echo 'graph_info This graph shows of many mS wall time where used by a domain' 33 | cat /var/lib/munin/plugin-state/xm_list.state | \ 34 | while read name domid mem cpu state time console; do 35 | name=`echo $name | sed -e"s/-/_/"` 36 | echo "$name.label $name" 37 | echo "$name.type COUNTER" 38 | # if [ "$name" = "Domain_0" ]; then 39 | # echo "$name.draw AREA" 40 | # else 41 | # echo "$name.draw STACK" 42 | # fi 43 | echo "$name.min 0" 44 | echo "$name.info Wall clock time spend for $name" 45 | done 46 | exit 0 47 | fi 48 | 49 | cat /var/lib/munin/plugin-state/xm_list.state | \ 50 | while read name domid mem cpu state time console; do 51 | name=`echo $name | sed -e"s/-/_/"` 52 | time=`echo $time | sed -e "s/\.//"` 53 | echo "$name.value $time" 54 | done 55 | 56 | -------------------------------------------------------------------------------- /files/plugins/xen_cpu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # xen_cpu_v2.pl 1.00 4 | # Script to minitor the CPU usage of Xen domains 5 | # Zoltan HERPAI (c) 2009, wigyori@uid0.hu 6 | # 7 | # Based loosely on Adam Crews' xen_cpu script 8 | # 9 | # This script tries to measure the CPU usage of the Xen guests 10 | # accurately. 11 | # The problem with the current monitoring script is that these 12 | # scripts use the CPU output of xentop or xm list, which might be 13 | # inaccurate due to the resources used up at the time of the query by 14 | # the xm or xentop command. 15 | # 16 | # This script stores the previous value of the CPU sec value of the given 17 | # guests in a tempfile, then does some simple calculations to get the real 18 | # CPU usage percentage of the guests. 19 | # 20 | 21 | #%# family=auto 22 | #%# capabilities=autoconf 23 | 24 | use strict; 25 | use POSIX; 26 | 27 | # Define where to find xm tools 28 | my $XM = '/usr/sbin/xm'; 29 | my $XMTOP = '/usr/sbin/xentop'; 30 | my $curtime = time(); 31 | my $basename = `/usr/bin/env basename $0`; chop ($basename); 32 | my $TEMPFILE = "/tmp/$basename"; 33 | 34 | my $debug = 0; 35 | 36 | ############## 37 | # You should not need to edit anything below here 38 | # 39 | 40 | $ENV{PATH} = '/bin:/usr/bin:/usr/sbin'; 41 | 42 | my $arg; 43 | if ( defined($ARGV[0]) ) 44 | { 45 | if ( $ARGV[0] eq 'config' ) 46 | { 47 | $arg = 'config'; 48 | } 49 | if ( $ARGV[0] eq 'autoconf' ) 50 | { 51 | $arg = 'autoconf'; 52 | } 53 | 54 | if ( $arg eq 'autoconf') 55 | { 56 | if ( -e $XM && -e $XMTOP ) 57 | { 58 | print "yes\n"; 59 | exit 0; 60 | } 61 | else 62 | { 63 | print "no ($XM and/or $XMTOP not found\n"; 64 | exit 1; 65 | } 66 | } 67 | 68 | if ( $arg eq 'config' ) 69 | { 70 | my %cnf; 71 | %cnf = ( 72 | 'graph_title' => 'Xen Domain CPU Usage v2', 73 | 'graph_args' => '--base 1000 -l 0 --upper-limit 100 --rigid', 74 | 'graph_vlabel' => 'Percent (%)', 75 | 'graph_category' => 'xen', 76 | 'graph_info' => 'Display the % of CPU Usage for each domain', 77 | ); 78 | 79 | my @domains = `$XM list`; 80 | my $cnt = 0; 81 | shift(@domains); # we dont need the header line 82 | foreach my $domain ( @domains ) 83 | { 84 | my ($dom,undef) = split(/\s/, $domain, 2); 85 | $dom =~ s/[-.]/_/g; 86 | $cnf{ "$dom" . '.label' } = "$dom"; 87 | $cnf{ "$dom" . '.draw' } = 'STACK'; 88 | $cnf{ "$dom" . '.min' } = '0'; 89 | $cnf{ "$dom" . '.max' } = '100'; 90 | $cnf{ "$dom" . '.info' } = '% CPU used for ' . "$dom"; 91 | # $cnf{ "$dom" . '.draw' } = 'AREA'; 92 | if ( $cnt == 0 ) 93 | { 94 | $cnf{ "$dom" . '.draw' } = 'AREA'; 95 | } 96 | $cnt++; 97 | } 98 | foreach my $key (sort(keys(%cnf))) 99 | { 100 | print "$key $cnf{$key}\n"; 101 | } 102 | exit 0; 103 | } 104 | } 105 | 106 | my @xmlist = `$XM list`; 107 | shift (@xmlist); 108 | 109 | my %dom; my $name; my $oldtime; 110 | # Read old data 111 | if ( -e $TEMPFILE ) 112 | { 113 | open(FH, "<", $TEMPFILE) or die $!; 114 | $oldtime = ; 115 | 116 | if ( $debug ) 117 | { 118 | print "Oldtime: $oldtime\n"; 119 | } 120 | 121 | while () 122 | { 123 | # Get the guest name and its CPU usage, and store it in $dom 124 | $_ =~ /(\S+)\s+\S+\s+\S+\s+\d+\s+\S+\s+(\S+)/; 125 | $dom{$1}->{'oldtime'} = $2; 126 | } 127 | 128 | close FH; 129 | } 130 | 131 | my $diff; my $cpusum = 0; 132 | foreach my $domain ( @xmlist ) 133 | { 134 | # Get the domains' name and current CPU usage, store it in $dom 135 | $domain =~ /(\S+)\s+\S+\s+\S+\s+\d+\s+\S+\s+(\S+)/; 136 | $dom{$1}->{'newtime'} = $2; 137 | 138 | $diff = $dom{$1}->{'newtime'} - $dom{$1}->{'oldtime'}; 139 | $diff = sprintf("%.2f", $diff); 140 | 141 | # Calc the diff between old and new cputime, or reset the counter 142 | if ( $diff < 0 ) 143 | { 144 | $diff = $dom{$1}->{'newtime'}; 145 | } 146 | $dom{$1}->{'diff'} = $diff; 147 | 148 | # Calc a sum CPU usage 149 | $cpusum = $cpusum + $diff; 150 | } 151 | 152 | my $numcpus = `$XM info |grep nr_cpus |cut -d \: -f 2`; 153 | my $timediff = $curtime - $oldtime; 154 | my $tcpuavail = $numcpus * $timediff; 155 | 156 | if ( $debug ) 157 | { 158 | print "UsedCPUtime sum: $cpusum\n"; 159 | print "CPUs: $numcpus\n"; 160 | print "Timediff: $timediff\n"; 161 | print "Total CPU time available: $tcpuavail\n"; 162 | } 163 | 164 | my $key; my $value; 165 | while (($key, $value) = each %dom) 166 | { 167 | # Calc a percentage based on the used CPU time sum 168 | my $tmp = 0; 169 | $tmp = ( $dom{$key}->{'diff'} / $cpusum ) * 100; 170 | $dom{$key}->{'pc_time'} = sprintf("%.2f", $tmp); 171 | 172 | # Calc a percentage based on the _total_ available CPU time 173 | $tmp = 0; 174 | $tmp = ( $dom{$key}->{'diff'} / $tcpuavail ) * 100; 175 | $dom{$key}->{'pc_tcpu'} = sprintf("%.2f", $tmp); 176 | 177 | if ( $debug ) 178 | { 179 | print "$key newtime: ".$dom{$key}->{'newtime'}.", oldtime: ".$dom{$key}->{'oldtime'}.", diff: ".$dom{$key}->{'diff'}.", pc_bytime ".$dom{$key}->{'pc_time'}.", pc_bytcpu ".$dom{$key}->{'pc_tcpu'}."\n"; 180 | } 181 | print "$key.value ".$dom{$key}->{'pc_tcpu'}."\n"; 182 | } 183 | 184 | # We'll need to log out the current "xm list" output, and the current time also. 185 | open(FH, ">", $TEMPFILE) or die $!; 186 | print FH $curtime."\n"; 187 | print FH @xmlist; 188 | close FH; 189 | 190 | -------------------------------------------------------------------------------- /files/plugins/xen_mem: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (C) 2006 Rodolphe Quiedeville 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; version 2 dated June, 8 | # 1991. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | # 19 | # 20 | # Script to monitor affected memory by domain 21 | # 22 | # $Log$ 23 | # Revision 1.0 2006/09/08 19:20:19 rodo 24 | # Created by Rodolphe Quiedeville 25 | # 26 | # Need to be run as root, add the following lines ... 27 | # 28 | # [xen*] 29 | # user root 30 | # 31 | # to /etc/munin/plugin-conf.d/munin-node 32 | # 33 | # 34 | # Parameters understood: 35 | # 36 | # config (required) 37 | # autoconf (optional - used by munin-config) 38 | # 39 | # 40 | # Magic markers (optional - used by munin-config and installation 41 | # scripts): 42 | # 43 | #%# family=auto 44 | #%# capabilities=autoconf 45 | 46 | # we cache xm list for 5 min for perfomance reasons 47 | ((find /var/lib/munin/plugin-state/xm_list.state -mmin -5 2>&1 | grep -qE '^\/var\/lib\/munin\/plugin-state\/xm_list\.state$') && \ 48 | [ `cat /var/lib/munin/plugin-state/xm_list.state | wc -l` -gt 1 ]) || \ 49 | /usr/sbin/xm list | grep -v "^Name .* ID" > /var/lib/munin/plugin-state/xm_list.state 50 | 51 | if [ "$1" = "autoconf" ]; then 52 | echo yes 53 | exit 0 54 | fi 55 | 56 | if [ "$1" = "config" ]; then 57 | 58 | echo 'graph_title Xen affected memory' 59 | echo 'graph_args --base 1024 --upper-limit 1024 -l 0' 60 | echo 'graph_vlabel Memory' 61 | echo 'graph_category xen' 62 | echo 'graph_total Total' 63 | echo 'graph_info This graph shows affected memory for each domain.' 64 | echo 'Domain_0.label Domain-0' 65 | echo 'Domain_0.draw AREA' 66 | cat /var/lib/munin/plugin-state/xm_list.state | grep -v 'Domain-0' | while read i; do 67 | name=`echo $i | awk '{ print $1 }' | sed 's/[\/.-]/_/g'` 68 | echo -n "$name.label " 69 | echo $i | awk '{ print $1 }' 70 | echo "$name.draw STACK" 71 | done 72 | 73 | exit 0 74 | fi 75 | 76 | cat /var/lib/munin/plugin-state/xm_list.state | while read i; do 77 | name=`echo $i | awk '{ print $1 }' | sed 's/[\/.-]/_/g'` 78 | echo -n "$name.value " 79 | echo $i | awk '{ print $3 * 1024 * 1024 }' 80 | done 81 | -------------------------------------------------------------------------------- /files/plugins/xen_memory: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Script to monitor memory status of the xen host 4 | # 5 | # Parameters understood: 6 | # 7 | # config (required) 8 | # autoconf (optional - used by munin-config) 9 | # 10 | 11 | MAXDOMAINS=16 12 | 13 | if [ "$1" = "autoconf" ]; then 14 | if which xm > /dev/null ; then 15 | echo yes 16 | exit 0 17 | fi 18 | echo "no (xm not found)" 19 | exit 1 20 | fi 21 | 22 | if [ "$1" = "config" ]; then 23 | 24 | echo 'graph_title Xen Memory' 25 | echo 'graph_args --base 1000 -l 0' 26 | echo 'graph_scale no' 27 | echo 'graph_vlabel MB' 28 | echo 'graph_category xen' 29 | echo 'graph_info This graph shows of many mS wall time where used by a domain' 30 | # xm info | while read name bla value; do echo "$name $value"; done 31 | /usr/sbin/xm info | while read name bla value; do 32 | #total_memory 2047 33 | #free_memory 1476 34 | name=`echo $name | sed -e"s/-/_/"` 35 | 36 | if [ "$name" = "total_memory" ]; then 37 | echo "$name.label $name" 38 | echo "$name.type GAUGE" 39 | echo "$name.min 0" 40 | echo "$name.info total memory" 41 | fi 42 | if [ "$name" = "free_memory" ]; then 43 | echo "$name.label $name" 44 | echo "$name.type GAUGE" 45 | echo "$name.draw AREA" 46 | # echo "$name.draw STACK" 47 | echo "$name.min 0" 48 | echo "$name.info free memory" 49 | fi 50 | done 51 | exit 0 52 | fi 53 | 54 | /usr/sbin/xm info | while read name bla value; do 55 | name=`echo $name | sed -e"s/-/_/"` 56 | if [ "$name" = "total_memory" ]; then 57 | echo "$name.value $value" 58 | fi 59 | if [ "$name" = "free_memory" ]; then 60 | echo "$name.value $value" 61 | fi 62 | done 63 | 64 | -------------------------------------------------------------------------------- /files/plugins/xen_traffic_all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Author: mario manno 3 | # Description: measure traffic for all xen hosts 4 | # 5 | # 16.07.2008: improved the Plugin by Puzzle ITC to 6 | # enable the traffic monitoring for domains 7 | # with more than 1 one interface 8 | # If there is more than one device, the domainname 9 | # will get the vif name appended. 10 | # 11 | #%# family=auto 12 | #%# capabilities=autoconf 13 | 14 | # we cache xm list for 5 min for perfomance reasons 15 | ((find /var/lib/munin/plugin-state/xm_list.state -mmin -5 2>&1 | grep -qE '^\/var\/lib\/munin\/plugin-state\/xm_list\.state$') && \ 16 | [ `cat /var/lib/munin/plugin-state/xm_list.state | wc -l` -gt 1 ]) || \ 17 | /usr/sbin/xm list | grep -v "^Name .* ID" > /var/lib/munin/plugin-state/xm_list.state 18 | 19 | if [ "$1" = "autoconf" ]; then 20 | if which xm > /dev/null ; then 21 | echo yes 22 | else 23 | echo "no (xm not found)" 24 | exit 1 25 | fi 26 | if [ -r /proc/net/dev ]; then 27 | echo yes 28 | else 29 | echo "no (/proc/net/dev not found)" 30 | exit 1 31 | fi 32 | exit 0 33 | fi 34 | 35 | # we update network devices only twice an hour 36 | function net_state { 37 | dom=$1 38 | if [ `find /var/lib/munin/plugin-state/xm_net_$dom.state -mmin +30 2> /dev/null | wc -l` -gt 0 ] || [ ! -f /var/lib/munin/plugin-state/xm_net_$dom.state ]; then 39 | content=$(/usr/sbin/xm network-list $dom) 40 | if [ $? -eq 0 ]; then 41 | echo "${content}" | egrep "^[0-9]+" | sed 's@^.*vif/\([0-9]*\)/\([0-9]*\).*$@vif\1.\2@' > /var/lib/munin/plugin-state/xm_net_$dom.state 42 | else 43 | [ -f /var/lib/munin/plugin-state/xm_net_$dom.state ] && rm /var/lib/munin/plugin-state/xm_net_$dom.state 44 | fi 45 | fi 46 | } 47 | 48 | if [ "$1" = "config" ]; then 49 | echo 'graph_title Xen Traffic' 50 | echo 'graph_vlabel bits received (-) / sent (+) per ${graph_period}' 51 | echo 'graph_args --base 1024 -l 0' 52 | echo 'graph_category xen' 53 | DOMAINS=$(cat /var/lib/munin/plugin-state/xm_list.state | awk '{print $1}' | egrep -v "^(Name|Domain-0)") 54 | for dom in $DOMAINS; do 55 | net_state $dom 56 | if [ -f /var/lib/munin/plugin-state/xm_net_$dom.state ]; then 57 | devs=$(cat /var/lib/munin/plugin-state/xm_net_$dom.state) 58 | real_name=$( echo $dom | sed -e's/-/_/g' ) 59 | name=$real_name 60 | for dev in $devs; do 61 | if [ ${#devs} -gt 1 ]; then 62 | name=$real_name"_"`echo $dev | sed 's/\./\_/'` 63 | fi 64 | 65 | echo $name'Down.label received' 66 | echo $name'Down.type COUNTER' 67 | echo $name'Down.graph no' 68 | echo "${name}Down.cdef ${name}Down,8,*" 69 | echo "${name}Up.label ${name}" 70 | echo $name'Up.type COUNTER' 71 | echo "${name}Up.negative ${name}Down" 72 | echo "${name}Up.cdef ${name}Up,8,*" 73 | done 74 | fi 75 | done 76 | exit 0 77 | fi 78 | 79 | DOMAINS=$(cat /var/lib/munin/plugin-state/xm_list.state | awk '{print $1}' | egrep -v "^(Name|Domain-0)") 80 | for dom in $DOMAINS; do 81 | net_state $dom 82 | if [ -f /var/lib/munin/plugin-state/xm_net_$dom.state ]; then 83 | devs=$(cat /var/lib/munin/plugin-state/xm_net_$dom.state) 84 | real_name=$( echo $dom | sed -e's/-/_/g' ) 85 | name=$real_name 86 | for dev in $devs; do 87 | if [ ${#devs} -gt 1 ]; then 88 | name=$real_name"_"`echo $dev | sed 's/\./\_/'` 89 | fi 90 | awk -v name="$name" -v interface="$dev" \ 91 | 'BEGIN { gsub(/\./, "\\.", interface) } \ 92 | $1 ~ "^" interface ":" { 93 | split($0, a, /: */); $0 = a[2]; \ 94 | print name"Down.value " $1 "\n"name"Up.value " $9 \ 95 | }' \ 96 | /proc/net/dev 97 | done 98 | fi 99 | done 100 | 101 | -------------------------------------------------------------------------------- /files/plugins/xen_vbd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # 2007-06-01 Zoltan HERPAI 4 | # 5 | # Credits goes for: 6 | # Adam Crews for his xen_cpu plugin 7 | # Mario Manno for his xen_traffic_all plugin 8 | # 9 | # Script to monitor the I/O usage of Xen domains 10 | # Version 0.1 11 | # 12 | #%# family=auto 13 | #%# capabilities=autoconf 14 | 15 | # Location of xm tools 16 | $XM = '/usr/sbin/xm'; 17 | $XMTOP = '/usr/sbin/xentop'; 18 | 19 | # we cache xm list for 5 min for perfomance reasons 20 | system('((find /var/lib/munin/plugin-state/xm_list.state -mmin -5 2>&1 | grep -qE \'^\/var\/lib\/munin\/plugin-state\/xm_list\.state$\') && [ `cat /var/lib/munin/plugin-state/xm_list.state | wc -l` -gt 1 ]) || /usr/sbin/xm list | grep -v "^Name .* ID" > /var/lib/munin/plugin-state/xm_list.state'); 21 | system('((find /var/lib/munin/plugin-state/xm_top.state -mmin -5 2>&1 | grep -qE \'^\/var\/lib\/munin\/plugin-state\/xm_top\.state$\') && [ `cat /var/lib/munin/plugin-state/xm_top.state | wc -l` -gt 1 ]) || /usr/sbin/xentop -b -i1 | grep -E "^ " > /var/lib/munin/plugin-state/xm_top.state'); 22 | 23 | # ah, parameters coming in 24 | if ( defined($ARGV[0])) 25 | { 26 | if ($ARGV[0] eq 'config') { $arg = 'config'; } 27 | if ($ARGV[0] eq 'autoconf') { $arg = 'autoconf'; } 28 | 29 | if ( $arg eq 'autoconf' ) 30 | { 31 | if ( -e $XM && -e $XMTOP ) 32 | { 33 | print "yes\n"; 34 | exit 0; 35 | } 36 | else 37 | { 38 | print "no ($XM and/or $XMTOP not found\n"; 39 | exit 0; 40 | } 41 | } 42 | 43 | if ( $arg eq 'config' ) 44 | { 45 | %cnf = ( 46 | 'graph_title' => 'Xen Domain I/O usage', 47 | 'graph_args' => '--base 1024 -l 0', 48 | 'graph_vlabel' => 'read (-), write (+)', 49 | 'graph_category' => 'xen', 50 | 'graph_info' => 'Display the I/O operations for each domain', 51 | ); 52 | 53 | @domains = `cat /var/lib/munin/plugin-state/xm_list.state | grep -v 'Domain-0'`; 54 | 55 | foreach $domain ( @domains ) 56 | { 57 | ($dom, undef) = split(/\s/, $domain); 58 | $dom =~ s/[-.]/_/g; 59 | 60 | $cnf{ $dom.'RD' . '.label' } = 'read'; 61 | $cnf{ $dom.'RD' . '.type' } = 'COUNTER'; 62 | $cnf{ $dom.'RD' . '.graph' } = 'no'; 63 | $cnf{ $dom.'RD' . '.cdef' } = $dom.'RD,8,*'; 64 | 65 | $cnf{ $dom.'WR' . '.label' } = $dom; 66 | $cnf{ $dom.'WR' . '.type' } = 'COUNTER'; 67 | $cnf{ $dom.'WR' . '.negative' } = $dom.'RD'; 68 | $cnf{ $dom.'WR' . '.cdef' } = $dom.'WR,8,*'; 69 | 70 | if ( "$cnt" == "0" ) 71 | { 72 | $cnf { "$dom" . '.draw' } = 'AREA'; 73 | } 74 | $cnt++; 75 | } 76 | 77 | foreach $key ( sort(keys(%cnf)) ) 78 | { 79 | print "$key $cnf{$key}\n"; 80 | } 81 | exit 0; 82 | 83 | } 84 | } 85 | 86 | 87 | # No args, get rolling 88 | my @stats = `cat /var/lib/munin/plugin-state/xm_top.state | grep -v 'Domain-0'`; 89 | 90 | # remove the first line 91 | shift(@stats); 92 | 93 | my %vals; undef(%vals); 94 | 95 | foreach my $domain (@stats) { 96 | # trim the leading whitespace 97 | $domain =~ s/^\s+//; 98 | my @tmp = split(/\s+/, $domain); 99 | 100 | # we need to change - and . to _ or things get weird with the graphs 101 | # some decent quoting would probably fix this, but this works for now 102 | $tmp[0] =~ s/[-.]/_/g; 103 | 104 | $domname = $tmp[0]; 105 | $domname =~ s/[-.]/_/g; 106 | $vbdrd = $tmp[14]; 107 | $vbdwr = $tmp[15]; 108 | 109 | $vals{$domname."RD"}{'value'} = $vbdrd; 110 | $vals{$domname."WR"}{'value'} = $vbdwr; 111 | } 112 | 113 | foreach $key ( sort(keys(%vals)) ) 114 | { 115 | print "$key.value " . ($vals{$key}{'value'}) . "\n"; 116 | } 117 | 118 | -------------------------------------------------------------------------------- /files/plugins/xen_vm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (C) 2006 Rodolphe Quiedeville 4 | # 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; version 2 dated June, 8 | # 1991. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | # 19 | # 20 | # Monitor number of vm running on a xen dom0. 21 | # 22 | # $Log$ 23 | # Revision 1.0 2006/09/08 19:20:19 rodo 24 | # Created by Rodolphe Quiedeville 25 | # 26 | # Need to be run as root, add the following lines ... 27 | # 28 | # [xen*] 29 | # user root 30 | # 31 | # to /etc/munin/plugin-conf.d/munin-node 32 | # 33 | # 34 | # Parameters understood: 35 | # 36 | # config (required) 37 | # autoconf (optional - used by munin-config) 38 | # 39 | # 40 | # Magic markers (optional - used by munin-config and installation 41 | # scripts): 42 | # 43 | #%# family=auto 44 | #%# capabilities=autoconf 45 | 46 | XM="/usr/sbin/xm" 47 | 48 | # we cache xm list for 5 min for perfomance reasons 49 | ((find /var/lib/munin/plugin-state/xm_list.state -mmin -5 2>&1 | grep -qE '^\/var\/lib\/munin\/plugin-state\/xm_list\.state$') && \ 50 | [ `cat /var/lib/munin/plugin-state/xm_list.state | wc -l` -gt 1 ]) || \ 51 | /usr/sbin/xm list | grep -v "^Name .* ID" > /var/lib/munin/plugin-state/xm_list.state 52 | 53 | if [ "$1" = "autoconf" ]; then 54 | echo yes 55 | exit 0 56 | fi 57 | 58 | if [ "$1" = "config" ]; then 59 | 60 | echo 'graph_title Xen Virtual Machines' 61 | echo 'graph_args --base 1000 -l 0' 62 | echo 'graph_vlabel vm' 63 | echo 'graph_category xen' 64 | echo 'graph_info This graph shows how many virtual machines runs on dom0.' 65 | echo 'domains.label vm' 66 | exit 0 67 | fi 68 | 69 | domains=`cat /var/lib/munin/plugin-state/xm_list.state | wc -l` 70 | 71 | echo -n "domains.value " 72 | echo $(($domains-1)) 73 | -------------------------------------------------------------------------------- /lib/facter/acpi_available.rb: -------------------------------------------------------------------------------- 1 | # return whether acpi is available -- used for deciding whether to install the munin plugin 2 | Facter.add("acpi_available") do 3 | setcode do 4 | if not Facter::Util::Resolution.which('acpi') or `acpi -t -B -A 2>/dev/null`.match(/\d/).nil? 5 | "absent" 6 | else 7 | "present" 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/facter/legacy_interfaces.rb: -------------------------------------------------------------------------------- 1 | # return the set of active interfaces as an array 2 | Facter.add("legacy_interfaces") do 3 | setcode do 4 | `ip -o link show`.split(/\n/).collect do |line| 5 | matches = line.match(/^\d*: ([^:]*): <(.*,)?UP(,.*)?>/) 6 | if !matches.nil? 7 | matches[1].split('@',2).first 8 | else 9 | nil 10 | end 11 | end.compact.sort.join(',') 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /manifests/client.pp: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007 David Schmitt 2 | # See LICENSE for the full license granted to you. 3 | # Adapted and improved by admin(at)immerda.ch 4 | 5 | # configure a munin node 6 | class munin::client ( 7 | Array[Stdlib::IP::Address::V4] $allow = ['127.0.0.1'], 8 | Array[Stdlib::IP::Address::V6] $allow6 = ['::1'], 9 | String $host = '*', 10 | String $host_to_export = $facts['networking']['fqdn'], 11 | String[1] $host_name = $facts['networking']['fqdn'], 12 | Stdlib::Port $port = 4949, 13 | Boolean $use_ssh = false, 14 | Boolean $use_firewall = false, 15 | Array[String[1]] $firewall_collector_source = ['net'], 16 | String[1] $description = 'absent', 17 | String[1] $munin_group = 'absent', 18 | ) { 19 | case $facts['os']['name'] { 20 | 'OpenBSD': { include munin::client::openbsd } 21 | 'Darwin': { include munin::client::darwin } 22 | 'Debian','Ubuntu': { include munin::client::debian } 23 | 'Gentoo': { include munin::client::gentoo } 24 | 'CentOS': { include munin::client::base } 25 | default: { include munin::client::base } 26 | } 27 | if $munin::client::use_firewall { 28 | if size($allow) < 2 { 29 | $munin_collector = $allow 30 | } else { 31 | $munin_collector = delete($allow,'127.0.0.1') 32 | } 33 | if size($allow6) < 2 { 34 | $munin_collector6 = $allow6 35 | } else { 36 | $munin_collector6 = delete($allow6,'::1') 37 | } 38 | class { 'firewall::rules::munin': 39 | port => $port, 40 | collector => $munin_collector, 41 | collector6 => $munin_collector6, 42 | collector_source => $firewall_collector_source, 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /manifests/client/base.pp: -------------------------------------------------------------------------------- 1 | # Install a basic munin client 2 | class munin::client::base { 3 | include munin::client::params 4 | package { 'munin-node': 5 | ensure => installed, 6 | } -> file {'/etc/munin/munin-node.conf': 7 | content => template('munin/munin-node.conf.erb'), 8 | # this has to be installed before the package, so the postinst can 9 | # boot the munin-node without failure! 10 | mode => '0644', 11 | owner => root, 12 | group => 0, 13 | } ~> service { 'munin-node': 14 | ensure => running, 15 | name => $munin::client::params::service, 16 | enable => true, 17 | hasstatus => true, 18 | hasrestart => true, 19 | require => Package[munin-node], 20 | } 21 | file {'/etc/munin': 22 | ensure => directory, 23 | mode => '0755', 24 | owner => root, 25 | group => 0, 26 | } 27 | if $munin::client::host_to_export == '' { 28 | $_host_to_export = $facts['networking']['fqdn'] 29 | } else { 30 | $_host_to_export = $munin::client::host_to_export 31 | } 32 | 33 | munin::register { $facts['networking']['fqdn']: 34 | host => $_host_to_export, 35 | port => $munin::client::port, 36 | use_ssh => $munin::client::use_ssh, 37 | description => $munin::client::description, 38 | group => $munin::client::munin_group, 39 | config => [ 'use_node_name yes', 'load.load.warning 5', 40 | 'load.load.critical 10'], 41 | } 42 | include munin::plugins::base 43 | 44 | if $munin::client::port != '4949' and $facts['os']['selinux']['enabled'] { 45 | selinux::seport{ 46 | "${munin::client::port}": 47 | setype => 'munin_port_t', 48 | before => Service['munin-node']; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /manifests/client/darwin.pp: -------------------------------------------------------------------------------- 1 | # Install a munin client on darwin 2 | class munin::client::darwin { 3 | file { '/usr/share/snmp/snmpd.conf': 4 | mode => '0744', 5 | content => template('munin/darwin_snmpd.conf.erb'), 6 | group => 0, 7 | owner => root, 8 | } 9 | line{'startsnmpdno': 10 | ensure => absent, 11 | file => '/etc/hostconfig', 12 | line => 'SNMPSERVER=-NO-', 13 | } 14 | line { 'startsnmpdyes': 15 | file => '/etc/hostconfig', 16 | line => 'SNMPSERVER=-YES-', 17 | notify => Exec['/sbin/SystemStarter start SNMP'], 18 | } 19 | exec{'/sbin/SystemStarter start SNMP': 20 | noop => false, 21 | } 22 | munin::register::snmp { $::fqdn: } 23 | } 24 | -------------------------------------------------------------------------------- /manifests/client/debian.pp: -------------------------------------------------------------------------------- 1 | # Install the munin client on debian 2 | class munin::client::debian inherits munin::client::base { 3 | # the plugin will need that 4 | ensure_packages(['iproute']) 5 | 6 | # workaround bug in munin_node_configure 7 | munin::plugin { 'postfix_mailvolume': ensure => absent } 8 | include munin::plugins::debian 9 | } 10 | -------------------------------------------------------------------------------- /manifests/client/gentoo.pp: -------------------------------------------------------------------------------- 1 | # install a munin client on gentoo 2 | class munin::client::gentoo inherits munin::client::base { 3 | 4 | Package['munin-node'] { 5 | name => 'net-analyzer/munin', 6 | } 7 | 8 | include munin::plugins::gentoo 9 | } 10 | -------------------------------------------------------------------------------- /manifests/client/openbsd.pp: -------------------------------------------------------------------------------- 1 | # generate a few missing things on openbsd 2 | class munin::client::openbsd inherits munin::client::base { 3 | file{ '/var/run/munin': 4 | ensure => directory, 5 | owner => '_munin-plugin', 6 | group => '_munin', 7 | mode => '0775', 8 | require => Package['munin-node'], 9 | } 10 | 11 | file{ '/var/log/munin-node': 12 | ensure => directory, 13 | owner => '_munin', 14 | group => '_munin', 15 | mode => '0755', 16 | require => Package['munin-node'], 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /manifests/client/params.pp: -------------------------------------------------------------------------------- 1 | # Set the parameters for the munin client 2 | class munin::client::params { 3 | $user = 'root' 4 | 5 | case $::osfamily { 6 | 'OpenBSD': { 7 | $group = 'wheel' 8 | $log_file = '/var/log/munin-node/munin-node.log' 9 | $service = 'munin_node' 10 | } 11 | 'Debian': { 12 | $group = 'root' 13 | $log_file = '/var/log/munin/munin-node.log' 14 | $service = 'munin-node' 15 | } 16 | default: { 17 | $group = 'root' 18 | $log_file = '/var/log/munin-node/munin-node.log' 19 | $service = 'munin-node' 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /manifests/host.pp: -------------------------------------------------------------------------------- 1 | # host.pp - the master host of the munin installation 2 | # Copyright (C) 2007 David Schmitt 3 | # See LICENSE for the full license granted to you. 4 | class munin::host ( 5 | $cgi_graphing = false, 6 | $use_firewall = false, 7 | ) { 8 | package { 'munin': 9 | ensure => installed, 10 | } -> file { 11 | '/etc/munin/munin-conf.d': 12 | ensure => directory, 13 | owner => root, 14 | group => 0, 15 | mode => '0644', 16 | purge => true, 17 | force => true, 18 | recurse => true; 19 | } 20 | File<<| tag == 'munin_client_register' |>> 21 | 22 | include munin::plugins::muninhost 23 | 24 | package { 'rrdtool': 25 | ensure => installed, 26 | } -> file { '/var/lib/munin/rrdcached-journal': 27 | ensure => directory, 28 | owner => munin, 29 | group => munin, 30 | mode => '0640', 31 | require => Package['munin']; 32 | } -> systemd::unit_file { 33 | 'munin-rrdcached.service': 34 | source => 'puppet:///modules/munin/config/host/rrdcached.service', 35 | enable => true, 36 | active => true, 37 | } -> file { 38 | '/etc/munin/munin-conf.d/01_rrdached.conf': 39 | content => "rrdcached_socket /run/munin/rrdcached.sock\n", 40 | owner => root, 41 | group => 0, 42 | mode => '0644'; 43 | } -> service { 'munin.timer': 44 | ensure => running, 45 | enable => true, 46 | } 47 | 48 | if $cgi_graphing { 49 | include munin::host::cgi 50 | } 51 | 52 | # from time to time we cleanup hanging munin-runs 53 | cron { 'munin_kill': 54 | command => 'if $(ps ax | grep -v grep | grep -q munin-run); then killall munin-run; fi', 55 | minute => ['4', '34'], 56 | user => 'root', 57 | } 58 | 59 | if $use_firewall { 60 | include firewall::rules::out::munin 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /manifests/host/cgi.pp: -------------------------------------------------------------------------------- 1 | # Set up a munin host using CGI rendering 2 | class munin::host::cgi { 3 | selboolean { 'nis_enabled': 4 | value => on, 5 | persistent => true, 6 | } -> file { 7 | '/etc/munin/munin-conf.d/01_cgi.conf': 8 | content => "graph_strategy cgi 9 | html_strategy cgi 10 | cgiurl_graph /munin/graph\n", 11 | owner => root, 12 | group => 0, 13 | mode => '0644', 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /manifests/plugin.pp: -------------------------------------------------------------------------------- 1 | # configure a specific munin plugin 2 | # 3 | # We only manage the plugin if it is not set to absent. 4 | # A plugin (or its config) that should be removed should 5 | # be purged by the recursively managed plugins- or 6 | # config-directory. So we can safe a few resources being 7 | # managed. 8 | define munin::plugin ( 9 | $ensure = 'present', 10 | $script_path_in = undef, 11 | $config = undef, 12 | ) { 13 | if $ensure != 'absent' { 14 | include munin::plugin::scriptpaths 15 | include munin::plugins::setup 16 | if $script_path_in { 17 | $real_script_path = $script_path_in 18 | } else { 19 | $real_script_path = $munin::plugin::scriptpaths::script_path 20 | } 21 | $plugin_src = $ensure ? { 22 | 'present' => $name, 23 | default => $ensure 24 | } 25 | 26 | file { "/etc/munin/plugins/${name}": 27 | ensure => link, 28 | target => "${real_script_path}/${plugin_src}", 29 | notify => Service['munin-node']; 30 | } 31 | if str2bool($facts['os']['selinux']['enabled']) and (($facts['os']['name'] != 'CentOS') or ($facts['os']['name'] == 'CentOS' and versioncmp($facts['os']['release']['major'],'5') > 0)) { 32 | File["/etc/munin/plugins/${name}"] { 33 | seltype => 'munin_etc_t', 34 | } 35 | } 36 | if $config { 37 | file { "/etc/munin/plugin-conf.d/${name}.conf": 38 | content => inline_template("[<%= @name %>]\n<%= Array(@config).join(\"\n\") %>\n"), 39 | owner => root, 40 | group => 0, 41 | mode => '0640', 42 | notify => Service['munin-node'], 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /manifests/plugin/deploy.pp: -------------------------------------------------------------------------------- 1 | # deploy and register a munin plugin 2 | define munin::plugin::deploy ( 3 | $ensure = 'present', 4 | $source = undef, 5 | $config = undef, 6 | $seltype = undef, 7 | $register = true, 8 | ) { 9 | if $seltype { 10 | $real_seltype = $seltype 11 | } else { 12 | $real_seltype = 'unconfined_munin_plugin_exec_t' 13 | } 14 | $plugin_src = $ensure ? { 15 | 'present' => $name, 16 | 'absent' => $name, 17 | default => $ensure 18 | } 19 | if $source { 20 | $real_source = $source 21 | } else { 22 | $real_source = "munin/plugins/${plugin_src}" 23 | } 24 | include munin::plugin::scriptpaths 25 | file { "munin_plugin_${name}": 26 | path => "${munin::plugin::scriptpaths::script_path}/${name}", 27 | source => "puppet:///modules/${real_source}", 28 | owner => root, 29 | group => 0, 30 | mode => '0755'; 31 | } 32 | 33 | File["munin_plugin_${name}"] { 34 | seltype => $real_seltype, 35 | } 36 | 37 | File["munin_plugin_${name}"] { 38 | require => Package['munin-node'] 39 | } 40 | 41 | # register the plugin if required 42 | if $register { 43 | munin::plugin { $name: 44 | ensure => $ensure, 45 | config => $config, 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /manifests/plugin/scriptpaths.pp: -------------------------------------------------------------------------------- 1 | # Determine the script path for each OS 2 | class munin::plugin::scriptpaths { 3 | case $facts['os']['name'] { 4 | 'gentoo': { $script_path = '/usr/libexec/munin/plugins' } 5 | 'debian': { $script_path = '/usr/share/munin/plugins' } 6 | 'centos': { $script_path = '/usr/share/munin/plugins' } 7 | 'openbsd': { $script_path = '/usr/local/libexec/munin/plugins/' } 8 | default: { $script_path = '/usr/share/munin/plugins' } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /manifests/plugins/base.pp: -------------------------------------------------------------------------------- 1 | # A basic set of plugins 2 | class munin::plugins::base( 3 | $df_as_root = false 4 | ) { 5 | ensure_packages(['net-tools']) 6 | # setup basic plugins 7 | munin::plugin { 8 | [ 'df', 'cpu', 'interrupts', 'load', 'memory', 'netstat', 'open_files', 9 | 'processes', 'swap', 'uptime', 'users', 'vmstat' ]: 10 | ensure => present, 11 | } 12 | Package['net-tools'] -> Munin::Plugin['netstat'] 13 | if $df_as_root { 14 | $df_opt = "user root\n" 15 | } else { 16 | $df_opt = undef 17 | } 18 | file{'/etc/munin/plugin-conf.d/df': 19 | content => "[df*]\n${df_opt}env.exclude none unknown iso9660 squashfs udf \ 20 | romfs ramfs debugfs binfmt_misc rpc_pipefs fuse.gvfs-fuse-daemon\n", 21 | require => Munin::Plugin['df'], 22 | owner => 'root', 23 | group => 0, 24 | mode => '0644', 25 | } 26 | include munin::plugins::interfaces 27 | 28 | case $facts['kernel'] { 29 | 'openbsd': { include munin::plugins::openbsd } 30 | 'linux': { include munin::plugins::linux } 31 | } 32 | 33 | case $facts['virtual'] { 34 | 'physical': { include munin::plugins::physical } 35 | 'xen0': { include munin::plugins::dom0 } 36 | default: { } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /manifests/plugins/debian.pp: -------------------------------------------------------------------------------- 1 | # Debian specific plugins 2 | class munin::plugins::debian { } 3 | -------------------------------------------------------------------------------- /manifests/plugins/djbdns.pp: -------------------------------------------------------------------------------- 1 | # Set up the djbdns plugin 2 | class munin::plugins::djbdns { 3 | munin::plugin::deploy { 'tinydns': } 4 | } 5 | -------------------------------------------------------------------------------- /manifests/plugins/dom0.pp: -------------------------------------------------------------------------------- 1 | # Set up plugins for a Xen dom0 host 2 | class munin::plugins::dom0 { 3 | munin::plugin::deploy { 4 | [ 'xen', 'xen_cpu', 'xen_memory', 'xen_mem', 5 | 'xen_vm', 'xen_vbd', 'xen_traffic_all' ]: 6 | config => 'user root'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /manifests/plugins/gentoo.pp: -------------------------------------------------------------------------------- 1 | # Set up the plugins for a gentoo host 2 | class munin::plugins::gentoo { 3 | munin::plugin::deploy { 'gentoo_lastupdated': 4 | config => "user portage\nenv.logfile /var/log/emerge.log\nenv.tail /usr/bin/tail\nenv.grep /bin/grep" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /manifests/plugins/interfaces.pp: -------------------------------------------------------------------------------- 1 | # handle if_ and if_err_ plugins 2 | class munin::plugins::interfaces { 3 | if 'legacy_interfaces' in $facts { 4 | # filter out many of the useless interfaces that show up 5 | $real_ifs = reject(split($facts['legacy_interfaces'], ','), 'eth\d+:\d+|eth\d+_\d+|sit0|virbr\d+_nic|vif\d+_\d+|veth(\w+)?\d+|__tmp\d+') 6 | 7 | $ifs = prefix($real_ifs, 'if_') 8 | $if_errs = prefix($real_ifs, 'if_err_') 9 | 10 | munin::plugin { 11 | $ifs: 12 | ensure => 'if_'; 13 | $if_errs: 14 | ensure => 'if_err_'; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /manifests/plugins/kvm.pp: -------------------------------------------------------------------------------- 1 | # Set up munin plugins for a KVM host 2 | class munin::plugins::kvm { 3 | munin::plugin::deploy { 4 | ['kvm_cpu', 'kvm_mem', 'kvm_net']:; 5 | 'kvm_io': 6 | config => 'user root'; 7 | } 8 | if versioncmp($facts['os']['release']['major'],'8') < 0 { 9 | ['kvm_cpu', 'kvm_mem', 'kvm_net', 'kvm_io'].each |$p| { 10 | Munin::Plugin::Deploy[$p] { 11 | source => "munin/plugins/${p}.CentOS.${facts['os']['release']['major']}", 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /manifests/plugins/linux.pp: -------------------------------------------------------------------------------- 1 | # Set up plugins for a linux host 2 | class munin::plugins::linux { 3 | munin::plugin { 4 | [ 'df_abs', 'forks', 'df_inode', 'irqstats', 'entropy', 'open_inodes', 5 | 'diskstats', 'proc_pri', 'threads', ]: 6 | ensure => present; 7 | 'acpi': 8 | ensure => $::acpi_available; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /manifests/plugins/muninhost.pp: -------------------------------------------------------------------------------- 1 | # Set up the plugins for a munin host 2 | class munin::plugins::muninhost { 3 | munin::plugin { ['munin_update', 'munin_graph', 'rrdcached']: } 4 | } 5 | -------------------------------------------------------------------------------- /manifests/plugins/openbsd.pp: -------------------------------------------------------------------------------- 1 | # Set up the plugins for an openbsd host 2 | class munin::plugins::openbsd { 3 | munin::plugin { 4 | [ 'memory_pools', 'memory_types' ]: 5 | ensure => present, 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /manifests/plugins/physical.pp: -------------------------------------------------------------------------------- 1 | # Set up the plugins for a physical machine 2 | class munin::plugins::physical { 3 | case $::kernel { 4 | linux: { munin::plugin { 'iostat': } } 5 | default: {} 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /manifests/plugins/selinux.pp: -------------------------------------------------------------------------------- 1 | # SELinux specific plugins 2 | class munin::plugins::selinux { 3 | munin::plugin{ [ 'selinux_avcstat' ]: } 4 | } 5 | -------------------------------------------------------------------------------- /manifests/plugins/setup.pp: -------------------------------------------------------------------------------- 1 | # Set up the munin plugins for a node 2 | class munin::plugins::setup { 3 | 4 | file { 5 | [ '/etc/munin/plugins', '/etc/munin/plugin-conf.d' ]: 6 | ensure => directory, 7 | require => Package['munin-node'], 8 | ignore => 'snmp_*', 9 | checksum => mtime, 10 | recurse => true, 11 | purge => true, 12 | force => true, 13 | notify => Service['munin-node'], 14 | owner => root, 15 | group => 0, 16 | mode => '0755'; 17 | '/etc/munin/plugin-conf.d/munin-node': 18 | ensure => present, 19 | notify => Service['munin-node'], 20 | owner => root, 21 | group => 0, 22 | mode => '0640'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /manifests/plugins/vserver.pp: -------------------------------------------------------------------------------- 1 | # vserver specific plugins 2 | class munin::plugins::vserver { 3 | munin::plugin { 4 | [ 'netstat', 'processes' ]: 5 | ensure => present; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /manifests/register.pp: -------------------------------------------------------------------------------- 1 | # register a client 2 | define munin::register ( 3 | $host = $facts['networking']['fqdn'], 4 | $port = '4949', 5 | $use_ssh = false, 6 | $description = 'absent', 7 | $config = [], 8 | $group = 'absent', 9 | ) { 10 | $fhost = $name 11 | $client_type = 'client' 12 | if $host =~ Stdlib::IP::Address::V6::Nosubnet { 13 | $host_str = "[${host}]" 14 | } else { 15 | $host_str = $host 16 | } 17 | @@file { 18 | "/etc/munin/munin-conf.d/10_${fhost}_${port}.conf": 19 | content => template('munin/client.erb'), 20 | owner => root, 21 | group => 0, 22 | mode => '0644', 23 | tag => 'munin_client_register', 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /manifests/register/snmp.pp: -------------------------------------------------------------------------------- 1 | # Register a munin node with snmp enabled 2 | define munin::register::snmp ( 3 | $community = 'public', 4 | $description = 'absent', 5 | $port = '4949', 6 | $host = $::fqdn, 7 | $group = 'absent', 8 | $version = '2', 9 | ) { 10 | $fhost = $name 11 | $client_type = 'snmp' 12 | $config = [ 'use_node_name no' ] 13 | 14 | exec { "munin_register_snmp_${fhost}": 15 | command => "munin-node-configure --snmp ${fhost} --snmpcommunity ${community} --snmpversion ${version} --shell | sh", 16 | unless => "ls /etc/munin/plugins/snmp_${fhost}_* &> /dev/null", 17 | } 18 | 19 | @@concat::fragment{ "munin_snmp_${fhost}": 20 | target => '/etc/munin/munin.conf', 21 | content => template('munin/client.erb'), 22 | tag => 'munin', 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /manifests/remoteplugin.pp: -------------------------------------------------------------------------------- 1 | # Configure a munin remote plugin 2 | define munin::remoteplugin( 3 | $source, 4 | $ensure = 'present', 5 | $config = undef, 6 | ) { 7 | case $ensure { 8 | 'absent': { munin::plugin{ $name: ensure => absent } } 9 | default: { 10 | file { 11 | "/var/lib/puppet/modules/munin/plugins/${name}": 12 | source => $source, 13 | mode => '0755', 14 | owner => root, 15 | group => 0, 16 | } 17 | munin::plugin { $name: 18 | ensure => $ensure, 19 | config => $config, 20 | script_path_in => '/var/lib/puppet/modules/munin/plugins', 21 | } 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /manifests/snmp_collector.pp: -------------------------------------------------------------------------------- 1 | # Set up munin as an SNMP collector 2 | class munin::snmp_collector{ 3 | file { 4 | '/var/lib/puppet/modules/munin/create_snmp_links': 5 | source => 'puppet:///modules/munin/create_snmp_links.sh', 6 | mode => '0755', 7 | owner => root, 8 | group => 0, 9 | } 10 | 11 | exec { 'create_snmp_links': 12 | command => '/var/lib/puppet/modules/munin/create_snmp_links /var/lib/puppet/modules/munin/nodes', 13 | require => File['snmp_links'], 14 | timeout => '2048', 15 | schedule => daily, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "duritong-munin", 3 | "version": "0.0.4", 4 | "author": "duritong", 5 | "summary": "Puppet module for Munin monitoring", 6 | "license": "Apache License, Version 2.0", 7 | "source": "git://github.com/duritong/puppet-munin.git", 8 | "project_page": "https://github.com/duritong/puppet-munin", 9 | "issues_url": "https://github.com/duritong/puppet-munin/issues", 10 | "description": "Munin is a performance monitoring system which creates nice RRD graphs and has a very easy plugin interface", 11 | "dependencies": [ 12 | {"name":"puppetlabs/concat","version_requirement":">= 1.1.0"}, 13 | {"name":"puppetlabs/stdlib","version_requirement":">= 3.2.0"}, 14 | {"name":"duritong/openbsd","version_requirement":">= 0.0.1"} 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /spec/classes/munin_client_base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'munin::client::base' do 4 | let :default_facts do 5 | { 6 | :fqdn => 'munin-node.example.org', 7 | :interfaces => 'eth0,eth1', 8 | :kernel => 'Linux', 9 | :virtual => false, 10 | :vserver => false, 11 | :selinux => true, 12 | :acpi_available => false, 13 | } 14 | end 15 | 16 | let :pre_condition do 17 | 'include munin::client' 18 | end 19 | 20 | context 'on Debian' do 21 | let :facts do 22 | { :osfamily => 'Debian', 23 | :operatingsystem => 'Debian' }.merge(default_facts) 24 | end 25 | 26 | it 'should compile' do 27 | should contain_class('munin::client::base') 28 | end 29 | 30 | it 'should set up munin-node' do 31 | should contain_service('munin-node').with({ 32 | :ensure => 'running', 33 | :enable => true, 34 | :hasstatus => true, 35 | :hasrestart => true, 36 | }) 37 | 38 | should contain_file('/etc/munin').with({ 39 | :ensure => 'directory', 40 | :mode => '0755', 41 | :owner => 'root', 42 | :group => 0, 43 | }) 44 | 45 | should contain_file('/etc/munin/munin-node.conf'). 46 | with_content(/^host_name munin-node.example.org$/). 47 | with_content(/^allow \^127\\\.0\\\.0\\\.1\$$/). 48 | with_content(/^host \*$/). 49 | with_content(/^port 4949$/) 50 | 51 | should contain_munin__register('munin-node.example.org').with({ 52 | :host => 'munin-node.example.org', 53 | :port => '4949', 54 | :use_ssh => false, 55 | :config => [ 'use_node_name yes', 'load.load.warning 5', 'load.load.critical 10'], 56 | :export_tag => 'munin', 57 | }) 58 | 59 | should contain_class('munin::plugins::base') 60 | end 61 | 62 | it 'should contain the Debian specific values' do 63 | should contain_file('/etc/munin/munin-node.conf'). 64 | with_content(/^log_file \/var\/log\/munin\/munin-node.log$/). 65 | with_content(/^group root$/) 66 | end 67 | end 68 | 69 | context 'on CentOS' do 70 | let :facts do 71 | { :osfamily => 'RedHat', 72 | :operatingsystemmajrelease => '7', 73 | :operatingsystem => 'CentOS' }.merge(default_facts) 74 | end 75 | 76 | it 'should contain the CentOS specific values' do 77 | should contain_file('/etc/munin/munin-node.conf'). 78 | with_content(/^log_file \/var\/log\/munin-node\/munin-node.log$/). 79 | with_content(/^group root$/) 80 | end 81 | end 82 | 83 | # Disabled because the required openbsd module is not in the requirements 84 | context 'on OpenBSD', :if => false do 85 | let :facts do 86 | { :osfamily => 'OpenBSD', 87 | :kernel => 'OpenBSD', 88 | :operatingsystem => 'OpenBSD', }.merge(default_facts) 89 | end 90 | 91 | it 'should contain the config OpenBSD specific values' do 92 | should contain_file('/etc/munin/munin-node.conf'). 93 | with_content(/^log_file \/var\/log\/munin-node\/munin-node.log$/). 94 | with_content(/^group 0$/) 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /spec/classes/munin_client_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'munin::client' do 4 | let(:default_facts){ 5 | { 6 | :interfaces => 'eth0,eth1', 7 | :vserver => false, 8 | :selinux => false, 9 | :acpi_available => false, 10 | :virtual => false, 11 | :kernel => 'Linux', 12 | } 13 | } 14 | shared_examples 'debian-client' do |os, codename| 15 | let(:facts) {{ 16 | :operatingsystem => os, 17 | :osfamily => 'Debian', 18 | :lsbdistcodename => codename, 19 | }.merge(default_facts)} 20 | it { should contain_package('munin-node') } 21 | it { should contain_package('iproute') } 22 | it { should contain_file('/etc/munin/munin-node.conf') } 23 | it { should contain_class('munin::client::debian') } 24 | end 25 | 26 | shared_examples 'redhat-client' do |os, codename| 27 | let(:facts) {{ 28 | :operatingsystem => os, 29 | :osfamily => 'RedHat', 30 | :serlinux => true, 31 | :lsbdistcodename => codename, 32 | }.merge(default_facts)} 33 | it { should contain_package('munin-node') } 34 | it { should contain_file('/etc/munin/munin-node.conf') } 35 | end 36 | 37 | context 'on debian-like system' do 38 | it_behaves_like 'debian-client', 'Debian', 'squeeze' 39 | it_behaves_like 'debian-client', 'Debian', 'wheezy' 40 | it_behaves_like 'debian-client', 'Ubuntu', 'precise' 41 | end 42 | 43 | context 'on redhat-like system' do 44 | it_behaves_like 'redhat-client', 'CentOS', '6' 45 | # not supported yet 46 | # it_behaves_like 'redhat', 'RedHat', '6' 47 | end 48 | 49 | context 'gentoo' do 50 | let(:facts) {{ 51 | :operatingsystem => 'Gentoo', 52 | :operatingsystemmajrelease => '12', 53 | :osfamily => 'Gentoo', 54 | :lsbdistcodename => '', 55 | :interfaces => 'lo,eth0', 56 | }.merge(default_facts)} 57 | it { should contain_package('munin-node') } 58 | it { should contain_file('/etc/munin/munin-node.conf') } 59 | it { should contain_class('munin::client::gentoo') } 60 | end 61 | 62 | end 63 | -------------------------------------------------------------------------------- /spec/classes/munin_host_cgi_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'munin::host::cgi' do 4 | let :pre_condition do 5 | 'include munin::host 6 | include munin::client' 7 | end 8 | 9 | context 'on Debian' do 10 | let(:facts) { 11 | { 12 | :os => { 13 | :name => os, 14 | :release => { :major => release, }, 15 | :selinux => { :enabled => true }, 16 | }, 17 | } 18 | } 19 | 20 | it 'should compile' do 21 | should contain_class('munin::host::cgi') 22 | end 23 | 24 | it 'should exec set_modes_for_cgi' do 25 | should contain_exec('set_modes_for_cgi').with({ 26 | :command => 'chgrp www-data /var/log/munin /var/log/munin/munin-graph.log && chmod g+w /var/log/munin /var/log/munin/munin-graph.log && find /var/www/munin/* -maxdepth 1 -type d -exec chgrp -R www-data {} \; && find /var/www/munin/* -maxdepth 1 -type d -exec chmod -R g+w {} \;', 27 | :refreshonly => true, 28 | :subscribe => 'Concat::Fragment[munin.conf.header]', 29 | }) 30 | end 31 | 32 | it 'should contain logrotate.conf' do 33 | should contain_file('/etc/logrotate.d/munin').with({ 34 | :content => /^ create 660 munin www-data$/, 35 | :group => 0, 36 | :mode => '0644', 37 | :owner => 'root', 38 | }) 39 | end 40 | end 41 | 42 | context 'on CentOS' do 43 | let :facts do 44 | { :operatingsystem => 'CentOS', 45 | :operatingsystemmajrelease => '7', 46 | :osfamily => 'RedHat', 47 | :kernel => 'Linux', 48 | :vserver => false, 49 | :interfaces => 'eth0', 50 | :acpi_available => false, 51 | :virtual => false, 52 | :selinux => true, 53 | } 54 | end 55 | 56 | it 'should exec set_modes_for_cgi' do 57 | should contain_exec('set_modes_for_cgi').with({ 58 | :command => 'chgrp apache /var/log/munin /var/log/munin/munin-graph.log && chmod g+w /var/log/munin /var/log/munin/munin-graph.log && find /var/www/html/munin/* -maxdepth 1 -type d -exec chgrp -R apache {} \; && find /var/www/html/munin/* -maxdepth 1 -type d -exec chmod -R g+w {} \;', 59 | :refreshonly => true, 60 | :subscribe => 'Concat::Fragment[munin.conf.header]', 61 | }) 62 | end 63 | 64 | it 'should contain logrotate.conf' do 65 | should contain_file('/etc/logrotate.d/munin').with({ 66 | :content => /^ create 660 munin apache$/, 67 | :group => 0, 68 | :mode => '0644', 69 | :owner => 'root', 70 | }) 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /spec/classes/munin_host_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'munin::host' do 4 | let(:pre_condition){ 'package{"munin-node": } 5 | service{"munin-node": }' } 6 | shared_examples 'redhat-host' do |os, release| 7 | let(:facts) { 8 | { 9 | :os => { 10 | :name => os, 11 | :release => { :major => release, }, 12 | :selinux => { :enabled => true }, 13 | }, 14 | } 15 | } 16 | it { should contain_package('munin') } 17 | it { should contain_concat('/etc/munin/munin.conf') } 18 | it { should contain_class('munin::host') } 19 | end 20 | 21 | context 'on redhat-like system' do 22 | it_behaves_like 'redhat-host', 'CentOS', '7' 23 | it_behaves_like 'redhat-host', 'CentOS', '8' 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/classes/munin_plugins_interfaces_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'munin::plugins::interfaces' do 4 | let(:pre_condition){ 'package{"munin-node": } 5 | service{"munin-node": }' } 6 | context 'on CentOS' do 7 | let :facts do 8 | { 9 | :legacy_interfaces => 'lo,eth0,sit0', 10 | :os => { 11 | :name => 'CentOS', 12 | :release => { :major => '7', }, 13 | :selinux => { :enabled => true }, 14 | }, 15 | } 16 | end 17 | 18 | it 'should compile' do 19 | should contain_class('munin::plugins::interfaces') 20 | end 21 | 22 | it 'should create plugins for each interface' do 23 | # lo 24 | should contain_munin__plugin('if_lo').with_ensure('if_') 25 | should contain_munin__plugin('if_err_lo').with_ensure('if_err_') 26 | 27 | # eth0 28 | should contain_munin__plugin('if_eth0').with_ensure('if_') 29 | should contain_munin__plugin('if_err_eth0').with_ensure('if_err_') 30 | end 31 | 32 | it 'should not create plugins for sit0' do 33 | should_not contain_munin__plugin('if_sit0') 34 | should_not contain_munin__plugin('if_err_sit0') 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/defines/munin_plugin_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'munin::plugin' do 4 | let(:title) { 'users' } 5 | let(:facts) do 6 | { 7 | :os => { 8 | :name => 'CentOS', 9 | :release => { :major => '7', }, 10 | :selinux => { :enabled => true }, 11 | }, 12 | } 13 | end 14 | let(:pre_condition){ 'package{"munin-node": } 15 | service{"munin-node": }' } 16 | context 'present' do 17 | it { should contain_file('/etc/munin/plugins/users').with( 18 | :ensure => 'link', 19 | :target => '/usr/share/munin/plugins/users' 20 | ) } 21 | it { should_not contain_file('/etc/munin/plugin-conf.d/users.conf') } 22 | end 23 | 24 | context 'present and config' do 25 | let(:params) do 26 | { :config => 'env.user root' } 27 | end 28 | it { should contain_file('/etc/munin/plugins/users').with( 29 | :ensure => 'link', 30 | :target => '/usr/share/munin/plugins/users', 31 | :notify => 'Service[munin-node]' 32 | ) } 33 | it { should contain_file('/etc/munin/plugin-conf.d/users.conf').with( 34 | :content => "[users]\nenv.user root\n", 35 | :owner => 'root', 36 | :group => 0, 37 | :mode => '0640', 38 | :notify => 'Service[munin-node]' 39 | ) } 40 | end 41 | 42 | context 'present and config as an array' do 43 | let(:params) do 44 | { :config => [ 'env.user root', 'env.group root' ] } 45 | end 46 | it { should contain_file('/etc/munin/plugins/users').with( 47 | :ensure => 'link', 48 | :target => '/usr/share/munin/plugins/users', 49 | :notify => 'Service[munin-node]' 50 | ) } 51 | it { should contain_file('/etc/munin/plugin-conf.d/users.conf').with( 52 | :content => "[users]\nenv.user root\nenv.group root\n", 53 | :owner => 'root', 54 | :group => 0, 55 | :mode => '0640', 56 | :notify => 'Service[munin-node]' 57 | ) } 58 | end 59 | 60 | context 'absent' do 61 | let(:params) do 62 | { :ensure => 'absent' } 63 | end 64 | it { should_not contain_file('/etc/munin/plugins/users') } 65 | it { should_not contain_file('/etc/munin/plugin-conf.d/users.conf') } 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'puppetlabs_spec_helper/module_spec_helper' 2 | 3 | fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures')) 4 | 5 | RSpec.configure do |c| 6 | c.module_path = File.join(fixture_path, 'modules') 7 | c.manifest_dir = File.join(fixture_path, 'manifests') 8 | end 9 | 10 | Puppet::Util::Log.level = :warning 11 | Puppet::Util::Log.newdestination(:console) 12 | -------------------------------------------------------------------------------- /spec/spec_helper_system.rb: -------------------------------------------------------------------------------- 1 | require 'rspec-system/spec_helper' 2 | require 'rspec-system-puppet/helpers' 3 | require 'rspec-system-serverspec/helpers' 4 | include Serverspec::Helper::RSpecSystem 5 | include Serverspec::Helper::DetectOS 6 | include RSpecSystemPuppet::Helpers 7 | 8 | RSpec.configure do |c| 9 | # Project root 10 | proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) 11 | 12 | # Enable colour 13 | c.tty = true 14 | 15 | c.include RSpecSystemPuppet::Helpers 16 | 17 | # This is where we 'setup' the nodes before running our tests 18 | c.before :suite do 19 | # Install puppet 20 | puppet_install 21 | 22 | # Install modules and dependencies 23 | puppet_module_install(:source => proj_root, :module_name => 'munin') 24 | shell('puppet module install puppetlabs-stdlib') 25 | shell('puppet module install puppetlabs-concat') 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /templates/client.erb: -------------------------------------------------------------------------------- 1 | <% 2 | # Downcase all information 3 | dom = scope['facts']['networking']['domain'].downcase 4 | h = scope['facts']['networking']['hostname'].downcase 5 | %> 6 | 7 | ### Munin client from Puppet template 8 | # Domain: <%= dom %> 9 | # Registered on: <%= h %> 10 | # Type: <%= @client_type %> 11 | <% if @description != 'absent' -%> 12 | # Description: <%= @description.gsub(/\n/, ' ') %> 13 | <% end -%> 14 | [<% if @group != 'absent' -%><%= @group %>;<% end -%><%= @fhost.downcase %>] 15 | <% if @use_ssh -%> 16 | address ssh://<%= @host_str %>/bin/nc localhost <%= @port %> 17 | <% else -%> 18 | address <%= @host_str %> 19 | port <%= @port %> 20 | <% end -%> 21 | <% if @config -%><% @config.each do |val| -%> 22 | <%= @val -%> 23 | <% end -%><% end -%> 24 | 25 | -------------------------------------------------------------------------------- /templates/munin-node.conf.erb: -------------------------------------------------------------------------------- 1 | ########## 2 | ########## Managed by puppet 3 | ########## 4 | # 5 | # Example config file for munin-node. You don't have to edit anything in 6 | # this file if you are using munin-asyncd. 7 | # 8 | 9 | log_level 4 10 | log_file <%= scope['munin::client::params::log_file'] %> 11 | pid_file /var/run/munin/munin-node.pid 12 | 13 | background 1 14 | setsid 1 15 | 16 | user <%= scope['munin::client::params::user'] %> 17 | group <%= scope['munin::client::params::group'] %> 18 | 19 | # This is the timeout for the whole transaction. 20 | # Units are in sec. Default is 15 min 21 | # 22 | # global_timeout 900 23 | 24 | # This is the timeout for each plugin. 25 | # Units are in sec. Default is 1 min 26 | # 27 | # timeout 60 28 | 29 | # Regexps for files to ignore 30 | #ignore_file [\#~]$ 31 | ignore_file DEADJOE$ 32 | ignore_file \.bak$ 33 | ignore_file %$ 34 | ignore_file \.dpkg-(tmp|new|old|dist)$ 35 | ignore_file \.rpm(save|new|orig)$ 36 | ignore_file \.pod$ 37 | 38 | # Set this if the client doesn't report the correct hostname when 39 | # telnetting to localhost, port 4949 40 | # 41 | host_name <%= scope['munin::client::host_name'] %> 42 | 43 | # A list of addresses that are allowed to connect. This must be a 44 | # regular expression, since Net::Server does not understand CIDR-style 45 | # network notation unless the perl module Net::CIDR is installed. You 46 | # may repeat the allow line as many times as you'd like 47 | 48 | <% scope['munin::client::allow'].each do |allow| -%> 49 | allow <%= "^#{Regexp.escape(allow)}$" %> 50 | <% end -%> 51 | <% scope['munin::client::allow6'].each do |allow| -%> 52 | allow <%= allow %> 53 | <% end -%> 54 | 55 | # If you have installed the Net::CIDR perl module, you can use one or more 56 | # cidr_allow and cidr_deny address/mask patterns. A connecting client must 57 | # match any cidr_allow, and not match any cidr_deny. Note that a netmask 58 | # *must* be provided, even if it's /32 59 | # 60 | # Example: 61 | # 62 | #cidr_allow 127.0.0.1/32 63 | #cidr_allow 192.0.2.0/24 64 | #cidr_deny 192.0.2.42/32 65 | 66 | # Which address to bind to; 67 | host <%= scope['munin::client::host'].empty? ? '*' : scope['munin::client::host'] %> 68 | #host 127.0.0.1 69 | 70 | # And which port 71 | port <%= scope['munin::client::port'] %> 72 | 73 | --------------------------------------------------------------------------------