diff --git a/README.md b/README.md index d5bb91c31..d540a6acc 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,11 @@ documentation for each plugin for configurable attributes. * `entropy` (see [collectd::plugin::entropy](#class-collectdpluginentropy) below) * `exec` (see [collectd::plugin::exec](#class-collectdpluginexec) below) * `filecount` (see [collectd::plugin::filecount](#class-collectdpluginfilecount) below) +* `genericjmx` (see [collectd::plugin::genericjmx](#class-collectdplugingenericjmx) below) * `interface` (see [collectd::plugin::interface](#class-collectdplugininterface) below) * `iptables` (see [collectd::plugin::iptables](#class-collectdpluginiptables) below) * `irq` (see [collectd::plugin::irq](#class-collectdpluginirq) below) +* `java` (see [collectd::plugin::java](#class-collectdpluginjava) below) * `load` (see [collectd::plugin::load](#class-collectdpluginload) below) * `logfile` (see [collectd::plugin::logfile](#class-collectdpluginlogfile) below) * `libvirt` (see [collectd::plugin::libvirt](#class-collectdpluginlibvirt) below) @@ -303,6 +305,41 @@ class { 'collectd::plugin::filecount': }, } ``` + +####Class: `collectd::plugin::genericjmx` + +```puppet +include collectd::plugin::genericjmx + +collectd::plugin::genericjmx::mbean { + 'garbage_collector': + object_name => 'java.lang:type=GarbageCollector,*', + instance_prefix => 'gc-', + instance_from => 'name', + values => [ + { + type => 'invocations', + table => false, + attribute => 'CollectionCount', + }, + { + type => 'total_time_in_ms', + instance_prefix => 'collection_time', + table => false, + attribute => 'CollectionTime', + }, + ]; +} + +collectd::plugin::genericjmx::connection { + 'java_app': + host => $fqdn, + service_url => 'service:jmx:rmi:///jndi/rmi://localhost:3637/jmxrmi', + collect => [ 'memory-heap', 'memory-nonheap','garbage_collector' ], +} + +``` + ####Class: `collectd::plugin::interface` ```puppet @@ -332,6 +369,12 @@ class { 'collectd::plugin::iptables': } ``` +####Class: `collectd::plugin::java` + +```puppet +class { 'collectd::plugin::java': } +``` + ####Class: `collectd::plugin::load` ```puppet diff --git a/manifests/params.pp b/manifests/params.pp index f2ce6c92b..0960c6ee6 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -10,6 +10,7 @@ $service_name = 'collectd' $config_file = "${collectd_dir}/collectd.conf" $root_group = 'root' + $java_dir = '/usr/share/collectd/java' } 'Solaris': { $package = 'CSWcollectd' @@ -19,6 +20,7 @@ $service_name = 'collectd' $config_file = "${collectd_dir}/collectd.conf" $root_group = 'root' + $java_dir = undef } 'Redhat': { $package = 'collectd' @@ -28,6 +30,7 @@ $service_name = 'collectd' $config_file = '/etc/collectd.conf' $root_group = 'root' + $java_dir = '/usr/share/collectd/java' } 'Suse': { $package = 'collectd' @@ -37,6 +40,7 @@ $service_name = 'collectd' $config_file = '/etc/collectd.conf' $root_group = 'root' + $java_dir = undef } 'FreeBSD': { $package = 'collectd5' @@ -46,6 +50,7 @@ $service_name = 'collectd' $config_file = '/usr/local/etc/collectd.conf' $root_group = 'wheel' + $java_dir = undef } 'Archlinux': { $package = 'collectd' @@ -55,6 +60,7 @@ $service_name = 'collectd' $config_file = '/etc/collectd.conf' $root_group = 'wheel' + $java_dir = undef } 'Gentoo': { $package = 'app-admin/collectd' @@ -64,6 +70,7 @@ $service_name = 'collectd' $config_file = '/etc/collectd.conf' $root_group = 'collectd' + $java_dir = undef } default: { diff --git a/manifests/plugin/genericjmx.pp b/manifests/plugin/genericjmx.pp new file mode 100644 index 000000000..5db8e89db --- /dev/null +++ b/manifests/plugin/genericjmx.pp @@ -0,0 +1,29 @@ +# https://collectd.org/wiki/index.php/Plugin:GenericJMX +class collectd::plugin::genericjmx ( + $jvmarg = [], +) { + include collectd + include collectd::params + include collectd::plugin::java + $class_path = "${collectd::params::java_dir}/collectd-api.jar:${collectd::params::java_dir}/generic-jmx.jar" + $config_file = "${collectd::params::plugin_conf_dir}/15-genericjmx.conf" + + concat { $config_file: + mode => '0640', + owner => 'root', + group => $collectd::params::root_group, + notify => Service['collectd'], + ensure_newline => true, + } + concat::fragment { + 'collectd_plugin_genericjmx_conf_header': + order => '00', + content => template('collectd/plugin/genericjmx.conf.header.erb'), + target => $config_file; + 'collectd_plugin_genericjmx_conf_footer': + order => '99', + content => " \n\n", + target => $config_file; + } + +} diff --git a/manifests/plugin/genericjmx/connection.pp b/manifests/plugin/genericjmx/connection.pp new file mode 100644 index 000000000..23d475acb --- /dev/null +++ b/manifests/plugin/genericjmx/connection.pp @@ -0,0 +1,16 @@ +# https://collectd.org/wiki/index.php/Plugin:GenericJMX +define collectd::plugin::genericjmx::connection ( + $host = $name, + $service_url, + $user = undef, + $password = undef, + $instance_prefix = undef, + $collect, +) { + include collectd::plugin::genericjmx + concat::fragment { "collectd_plugin_genericjmx_conf_${name}": + order => 20, + content => template('collectd/plugin/genericjmx/connection.conf.erb'), + target => $collectd::plugin::genericjmx::config_file; + } +} diff --git a/manifests/plugin/genericjmx/mbean.pp b/manifests/plugin/genericjmx/mbean.pp new file mode 100644 index 000000000..68f0e1435 --- /dev/null +++ b/manifests/plugin/genericjmx/mbean.pp @@ -0,0 +1,17 @@ +# https://collectd.org/wiki/index.php/Plugin:GenericJMX +define collectd::plugin::genericjmx::mbean ( + $object_name, + $instance_prefix = undef, + $instance_from = undef, + $values, +) { + include collectd::plugin::genericjmx + validate_array($values) + + concat::fragment { + "collectd_plugin_genericjmx_conf_${name}": + order => '10', + content => template('collectd/plugin/genericjmx/mbean.conf.erb'), + target => $collectd::plugin::genericjmx::config_file; + } +} diff --git a/manifests/plugin/java.pp b/manifests/plugin/java.pp new file mode 100644 index 000000000..1ef6960ca --- /dev/null +++ b/manifests/plugin/java.pp @@ -0,0 +1,12 @@ +# https://collectd.org/wiki/index.php/Plugin:Java +class collectd::plugin::java ( + $ensure = present, + $jvmarg = [], + $interval = undef, +) { + collectd::plugin { 'java': + ensure => $ensure, + content => template('collectd/plugin/java.conf.erb'), + interval => $interval, + } +} diff --git a/spec/classes/collectd_plugin_genericjmx_spec.rb b/spec/classes/collectd_plugin_genericjmx_spec.rb new file mode 100644 index 000000000..2393e3544 --- /dev/null +++ b/spec/classes/collectd_plugin_genericjmx_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe 'collectd::plugin::genericjmx', :type => :class do + let (:facts) {{ + :osfamily => 'Debian', + :id => 'root', + :concat_basedir => tmpfilename('collectd-genericjmx'), + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + }} + + let (:config_filename) { '/etc/collectd/conf.d/15-genericjmx.conf' } + + context 'defaults' do + it 'will include the java plugin' do + should contain_class('collectd::plugin::java') + end + + it 'will load the genericjmx plugin' do + should contain_concat(config_filename).with({ + :ensure => 'present', + :mode => '0640', + :owner => 'root', + :group => 'root', + :ensure_newline => true + }) + end + + it { should contain_concat(config_filename).that_notifies('Service[collectd]') } + + it do + should contain_concat__fragment('collectd_plugin_genericjmx_conf_header').with({ + :order => '00', + :target => config_filename, + :content => /.+LoadPlugin "org\.collectd\.java\.GenericJMX".+/m + }) + end + + it do + should contain_concat__fragment('collectd_plugin_genericjmx_conf_footer').with({ + :order => '99', + :target => config_filename, + :content => %r{.+}m, + }) + end + + end + + context 'jvmarg parameter array' do + let (:params) {{ :jvmarg => %w{ foo bar baz } }} + it 'should have multiple jvmarg parameters' do + should contain_concat__fragment('collectd_plugin_genericjmx_conf_header').with_content(/JVMArg "foo".*JVMArg "bar".*JVMArg "baz"/m) + end + end + + context 'jvmarg parameter string' do + let (:params) {{ :jvmarg => "bat" }} + it 'should have one jvmarg parameter' do + should contain_concat__fragment('collectd_plugin_genericjmx_conf_header').with_content(/JVMArg "bat"/) + end + it 'should have ONLY one jvmarg parameter other than classpath' do + should contain_concat__fragment('collectd_plugin_genericjmx_conf_header').without_content(/(.*JVMArg.*){3,}/m) + end + end + + context 'jvmarg parameter empty' do + let (:params) {{ :jvmarg => [] }} + it 'should not have any jvmarg parameters other than classpath' do + should contain_concat__fragment('collectd_plugin_genericjmx_conf_header').without_content(/(.*JVMArg.*){2,}/m) + end + end +end + diff --git a/spec/classes/collectd_plugin_java_spec.rb b/spec/classes/collectd_plugin_java_spec.rb new file mode 100644 index 000000000..ad5bb2fa7 --- /dev/null +++ b/spec/classes/collectd_plugin_java_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe 'collectd::plugin::java', :type => :class do + let :facts do + {:osfamily => 'RedHat'} + end + + context ':ensure => present, defaults' do + it 'Will load the plugin' do + should contain_collectd__plugin('java').with({ + :ensure => 'present', + }) + end + end + + context ':ensure => absent' do + let (:params) {{ + :ensure => 'absent', + }} + + it 'will not load the plugin' do + should contain_collectd__plugin('java').with({ + :ensure => 'absent' + }) + end + end + + context 'jvmarg parameter array' do + let (:params) {{ + :jvmarg => %w{ foo bar baz } + }} + + it 'will have multiple jvmarg parameters' do + should contain_collectd__plugin('java').with_content(/JVMArg "foo".+JVMArg "bar".+JVMArg "baz"/m) + end + end + + context 'jvmarg parameter string' do + let (:params) {{ + :jvmarg => 'bat' + }} + + it 'will have a JVMArg parameter' do + should contain_collectd__plugin('java').with_content(/JVMArg "bat"/) + end + + it 'will only have one JVMArg parameter' do + should contain_collectd__plugin('java').without_content(/(.*JVMArg.*){2,}/m) + end + end + + context 'jvmarg parameter empty' do + let (:params) {{ + :jvmarg => [], + }} + + it 'will not have a stanza' do + should contain_collectd__plugin('java').without_content(//) + end + it 'will not have any jvmarg parameters' do + should contain_collectd__plugin('java').without_content(/JVMArg/) + end + end +end diff --git a/spec/defines/collectd_plugin_genericjmx_connection_spec.rb b/spec/defines/collectd_plugin_genericjmx_connection_spec.rb new file mode 100644 index 000000000..105887c2d --- /dev/null +++ b/spec/defines/collectd_plugin_genericjmx_connection_spec.rb @@ -0,0 +1,105 @@ +require 'spec_helper' +describe 'collectd::plugin::genericjmx::connection', :type => :define do + + let (:facts) {{ + :osfamily => 'Debian', + :id => 'root', + :concat_basedir => tmpfilename('collectd-genericjmx-connection'), + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + }} + + let (:config_filename) { '/etc/collectd/conf.d/15-genericjmx.conf' } + + let (:default_params) {{ + :service_url => 'foo:bar:baz', + }} + + let (:title) { 'foo.example.com' } + let (:concat_fragment_name) { 'collectd_plugin_genericjmx_conf_foo.example.com' } + + context 'required params' do + let (:params) { + default_params.merge({ + :collect => [], + }) + } + + it 'provides a Connection concat fragment' do + should contain_concat__fragment(concat_fragment_name).with({ + :target => config_filename, + :order => '20', + }) + end + + it { should contain_concat__fragment(concat_fragment_name).with_content(%r{.*}m) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/Host "foo\.example\.com"/) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/ServiceURL "foo:bar:baz"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/User/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/Password/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstancePrefix/) } + end + + context 'hostname override' do + let (:params) { + default_params.merge({ + :host => 'bar.example.com', + :collect => [], + }) + } + + it 'provides a Connection concat fragment' do + should contain_concat__fragment(concat_fragment_name).with({ + :target => config_filename, + :order => '20', + }) + end + + it { should contain_concat__fragment(concat_fragment_name).with_content(/Host "bar\.example\.com"/) } + end + + context 'collect array' do + let (:params) { + default_params.merge({ + :collect => %w{ foo bar baz } + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/Collect "foo".*Collect "bar".*Collect "baz"/m) } + end + + context 'collect string' do + let (:params) { + default_params.merge({ + :collect => 'bat' + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/Collect "bat"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/(.*Collect.*){2,}/m) } + end + + context 'username and password' do + let (:params) { + default_params.merge({ + :user => 'alice', + :password => 'aoeuhtns', + :collect => [], + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/User "alice"/) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/Password "aoeuhtns"/) } + end + + context 'instance_prefix 'do + let (:params) { + default_params.merge({ + :instance_prefix => 'bat', + :collect => [], + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstancePrefix "bat"/) } + end + +end diff --git a/spec/defines/collectd_plugin_genericjmx_mbean_spec.rb b/spec/defines/collectd_plugin_genericjmx_mbean_spec.rb new file mode 100644 index 000000000..de8f961cc --- /dev/null +++ b/spec/defines/collectd_plugin_genericjmx_mbean_spec.rb @@ -0,0 +1,177 @@ +require 'spec_helper' + +describe 'collectd::plugin::genericjmx::mbean', :type => :define do + + let (:facts) {{ + :osfamily => 'Debian', + :id => 'root', + :concat_basedir => tmpfilename('collectd-genericjmx-mbean'), + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + }} + + let (:config_filename) { '/etc/collectd/conf.d/15-genericjmx.conf' } + + let (:default_params) {{ + :object_name => 'bar', + :values => [], + }} + + let (:title) { 'foo' } + let (:concat_fragment_name) { 'collectd_plugin_genericjmx_conf_foo' } + + # empty values array is technically not valid, but we'll test those cases later + context 'defaults' do + let (:params) { default_params } + it 'provides an MBean stanza concat fragment' do + should contain_concat__fragment(concat_fragment_name).with({ + :target => config_filename, + :order => '10', + }) + end + + it { should contain_concat__fragment(concat_fragment_name).with_content(%r{\s+ObjectName "bar".+}m) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstancePrefix/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstanceFrom/) } + end + + context 'instance_prefix set' do + let (:params) { + default_params.merge({ + :instance_prefix => 'baz' + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstancePrefix "baz"/) } + end + + context 'instance_from array' do + let (:params) { + default_params.merge({ + :instance_from => %w{ foo bar baz } + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstanceFrom "foo"\s+InstanceFrom "bar"\s+InstanceFrom "baz"/) } + end + + context 'instance_from string' do + let (:params) { + default_params.merge({ + :instance_from => 'bat' + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstanceFrom "bat"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/(.*InstanceFrom.*){2,}/) } + end + + let (:default_values_args) {{ + 'type' => 'foo', + 'attribute' => 'bar' + }} + + + # testing the Value template section is going to be messy + context 'value section defaults' do + let (:params) { + default_params.merge({ + :values => [default_values_args] + }) + } + + it 'should have a value stanza' do + should contain_concat__fragment(concat_fragment_name).with_content(%r{.*}m) + end + + it 'should have only one value stanza' do + should contain_concat__fragment(concat_fragment_name).without_content(%r{(.*.*){2,}}) + end + + it { should contain_concat__fragment(concat_fragment_name).with_content(/Type "foo"/) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/Table false/) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/Attribute "bar"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstancePrefix/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstanceFrom/) } + end + + context 'value section instance_prefix set' do + let (:params) { + default_params.merge({ + :values => [default_values_args.merge({ + 'instance_prefix' => 'baz', + })] + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstancePrefix "baz"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstanceFrom/) } + end + + context 'value section instance_from array' do + let (:params) { + default_params.merge({ + :values => [default_values_args.merge({ + 'instance_from' => %w{ alice bob carol } + })] + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstanceFrom "alice"/) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstanceFrom "bob"/) } + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstanceFrom "carol"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstancePrefix/) } + end + + context 'value section instance_from string' do + let (:params) { + default_params.merge({ + :values => [default_values_args.merge({ + 'instance_from' => 'dave', + })] + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/InstanceFrom "dave"/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/(.*InstancePrefix.*){2,}/) } + it { should contain_concat__fragment(concat_fragment_name).without_content(/InstancePrefix/) } + end + + context 'value section table true-like' do + ['true', true].each do |truthy| + let (:params) { + default_params.merge({ + :values => [default_values_args.merge({ + 'table' => truthy + })] + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/Table true/) } + end + end + + context 'value section table false-like' do + ['false', false].each do |truthy| + let (:params) { + default_params.merge({ + :values => [default_values_args.merge({ + 'table' => truthy + })] + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(/Table false/) } + end + end + + context 'multiple values' do + let (:params) { + default_params.merge({ + :values => [default_values_args,default_values_args] + }) + } + + it { should contain_concat__fragment(concat_fragment_name).with_content(%r{(.*.*.*){2}}m) } + end + +end diff --git a/templates/plugin/genericjmx.conf.header.erb b/templates/plugin/genericjmx.conf.header.erb new file mode 100644 index 000000000..1a8ec7fc9 --- /dev/null +++ b/templates/plugin/genericjmx.conf.header.erb @@ -0,0 +1,8 @@ + + JVMArg "-Djava.class.path=<%= @class_path %>" +<% Array(@jvmarg).each do |jvmarg| -%> + JVMArg "<%= jvmarg %>" +<% end -%> + + LoadPlugin "org.collectd.java.GenericJMX" + diff --git a/templates/plugin/genericjmx/connection.conf.erb b/templates/plugin/genericjmx/connection.conf.erb new file mode 100644 index 000000000..ea32ce9df --- /dev/null +++ b/templates/plugin/genericjmx/connection.conf.erb @@ -0,0 +1,16 @@ + + Host "<%= @host %>" + ServiceURL "<%= @service_url %>" + <% Array(@collect).each do |collect| -%> + Collect "<%= collect %>" + <% end -%> + <% if @user -%> + User "<%= @user %>" + <% end -%> + <% if @password -%> + Password "<%= @password %>" + <% end -%> + <% if @instance_prefix -%> + InstancePrefix "<%= @instance_prefix %>" + <% end -%> + diff --git a/templates/plugin/genericjmx/mbean.conf.erb b/templates/plugin/genericjmx/mbean.conf.erb new file mode 100644 index 000000000..cced7724a --- /dev/null +++ b/templates/plugin/genericjmx/mbean.conf.erb @@ -0,0 +1,27 @@ +"> + ObjectName "<%= @object_name %>" + <% if @instance_prefix -%> + InstancePrefix "<%= @instance_prefix %>" + <% end -%> + <% if @instance_from -%> + <% Array(@instance_from).each do |instance_from_item| -%> + InstanceFrom "<%= instance_from_item %>" + <% end -%> + <% end -%> + + <% @values.each do |value| -%> + + Type "<%= value['type'] %>" + <% if value['instance_prefix'] -%> + InstancePrefix "<%= value['instance_prefix'] %>" + <% end -%> + <% if value['instance_from'] -%> + <% Array(value['instance_from']).each do |instance_from_item| -%> + InstanceFrom "<%= instance_from_item %>" + <% end -%> + <% end -%> + Table <%= scope.function_str2bool([value['table'] || false ]) ? 'true' : 'false' %> + Attribute "<%= value['attribute'] %>" + + <% end -%> + diff --git a/templates/plugin/java.conf.erb b/templates/plugin/java.conf.erb new file mode 100644 index 000000000..0ab321810 --- /dev/null +++ b/templates/plugin/java.conf.erb @@ -0,0 +1,7 @@ +<% if !Array(@jvmarg).empty? -%> + + <% Array(@jvmarg).each do |arg| -%> + JVMArg "<%= arg %>" + <% end -%> + +<% end -%>