diff --git a/.fixtures.yml b/.fixtures.yml index 926942f..670c58e 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -1,5 +1,5 @@ fixtures: - repositories: - stdlib: git://github.com/puppetlabs/puppetlabs-stdlib.git + forge_modules: + stdlib: "puppetlabs/stdlib" symlinks: munin: "#{source_dir}" diff --git a/.gitignore b/.gitignore index 73da533..6dfe023 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,12 @@ -spec/fixtures -vendor -.ruby-version -.bundle -Gemfile.lock +.*.sw? +/pkg +/spec/fixtures +/.rspec_system +/.vagrant +/.bundle +/vendor +/Gemfile.lock +/junit +/log +.yardoc +coverage diff --git a/.pmtignore b/.pmtignore new file mode 100644 index 0000000..e4e6ec9 --- /dev/null +++ b/.pmtignore @@ -0,0 +1,3 @@ +vendor/ +log/ +junit/ diff --git a/.rspec b/.rspec index 8c18f1a..4cd92bf 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ --format documentation --color +--fail-fast diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..daa9538 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,486 @@ +AllCops: + Exclude: + # Ignore HTML related things + - '**/*.erb' + # Ignore vendored gems + - 'vendor/**/*' + # Ignore code from test fixtures + - 'spec/fixtures/**/*' + +Lint/ConditionPosition: + Enabled: true + +Lint/ElseLayout: + Enabled: true + +Lint/UnreachableCode: + Enabled: true + +Lint/UselessComparison: + Enabled: true + +Lint/EnsureReturn: + Enabled: true + +Lint/HandleExceptions: + Enabled: true + +Lint/LiteralInCondition: + Enabled: true + +Lint/ShadowingOuterLocalVariable: + Enabled: true + +Lint/LiteralInInterpolation: + Enabled: true + +Style/RedundantReturn: + Enabled: true + +Lint/AmbiguousOperator: + Enabled: true + +Lint/AssignmentInCondition: + Enabled: true + +Style/SpaceBeforeComment: + Enabled: true + +# DISABLED - not useful +Style/HashSyntax: + Enabled: false + +# USES: as shortcut for non nil&valid checking a = x() and a.empty? +# DISABLED - not useful +Style/AndOr: + Enabled: false + +# DISABLED - not useful +Style/RedundantSelf: + Enabled: false + +# DISABLED - not useful +Metrics/MethodLength: + Enabled: false + +# DISABLED - not useful +Style/WhileUntilModifier: + Enabled: false + +# DISABLED - the offender is just haskell envy +Lint/AmbiguousRegexpLiteral: + Enabled: false + +# DISABLED +Lint/Eval: + Enabled: false + +# DISABLED +Lint/BlockAlignment: + Enabled: false + +# DISABLED +Lint/DefEndAlignment: + Enabled: false + +# DISABLED +Lint/EndAlignment: + Enabled: false + +# DISABLED +Lint/DeprecatedClassMethods: + Enabled: false + +# DISABLED +Lint/Loop: + Enabled: false + +# DISABLED +Lint/ParenthesesAsGroupedExpression: + Enabled: false + +Lint/RescueException: + Enabled: false + +Lint/StringConversionInInterpolation: + Enabled: false + +Lint/UnusedBlockArgument: + Enabled: false + +Lint/UnusedMethodArgument: + Enabled: false + +Lint/UselessAccessModifier: + Enabled: true + +Lint/UselessAssignment: + Enabled: true + +Lint/Void: + Enabled: true + +Style/AccessModifierIndentation: + Enabled: false + +Style/AccessorMethodName: + Enabled: false + +Style/Alias: + Enabled: false + +Style/AlignArray: + Enabled: false + +Style/AlignHash: + Enabled: false + +Style/AlignParameters: + Enabled: false + +Metrics/BlockNesting: + Enabled: false + +Style/AsciiComments: + Enabled: false + +Style/Attr: + Enabled: false + +Style/BracesAroundHashParameters: + Enabled: false + +Style/CaseEquality: + Enabled: false + +Style/CaseIndentation: + Enabled: false + +Style/CharacterLiteral: + Enabled: false + +Style/ClassAndModuleCamelCase: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false + +Style/ClassCheck: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +Style/ClassMethods: + Enabled: false + +Style/ClassVars: + Enabled: false + +Style/WhenThen: + Enabled: false + +# DISABLED - not useful +Style/WordArray: + Enabled: false + +Style/UnneededPercentQ: + Enabled: false + +Style/Tab: + Enabled: false + +Style/SpaceBeforeSemicolon: + Enabled: false + +Style/TrailingBlankLines: + Enabled: false + +Style/SpaceInsideBlockBraces: + Enabled: false + +Style/SpaceInsideBrackets: + Enabled: false + +Style/SpaceInsideHashLiteralBraces: + Enabled: false + +Style/SpaceInsideParens: + Enabled: false + +Style/LeadingCommentSpace: + Enabled: false + +Style/SingleSpaceBeforeFirstArg: + Enabled: false + +Style/SpaceAfterColon: + Enabled: false + +Style/SpaceAfterComma: + Enabled: false + +Style/SpaceAfterControlKeyword: + Enabled: false + +Style/SpaceAfterMethodName: + Enabled: false + +Style/SpaceAfterNot: + Enabled: false + +Style/SpaceAfterSemicolon: + Enabled: false + +Style/SpaceAroundEqualsInParameterDefault: + Enabled: false + +Style/SpaceAroundOperators: + Enabled: false + +Style/SpaceBeforeBlockBraces: + Enabled: false + +Style/SpaceBeforeComma: + Enabled: false + +Style/CollectionMethods: + Enabled: false + +Style/CommentIndentation: + Enabled: false + +Style/ColonMethodCall: + Enabled: false + +Style/CommentAnnotation: + Enabled: false + +Metrics/CyclomaticComplexity: + Enabled: false + +Style/ConstantName: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/DefWithParentheses: + Enabled: false + +Style/DeprecatedHashMethods: + Enabled: false + +Style/DotPosition: + Enabled: false + +# DISABLED - used for converting to bool +Style/DoubleNegation: + Enabled: false + +Style/EachWithObject: + Enabled: false + +Style/EmptyLineBetweenDefs: + Enabled: false + +Style/IndentArray: + Enabled: false + +Style/IndentHash: + Enabled: false + +Style/IndentationConsistency: + Enabled: false + +Style/IndentationWidth: + Enabled: false + +Style/EmptyLines: + Enabled: false + +Style/EmptyLinesAroundAccessModifier: + Enabled: false + +Style/EmptyLinesAroundBlockBody: + Enabled: false + +Style/EmptyLiteral: + Enabled: false + +Metrics/LineLength: + Enabled: false + +Style/MethodCallParentheses: + Enabled: false + +Style/MethodDefParentheses: + Enabled: false + +Style/LineEndConcatenation: + Enabled: false + +Style/TrailingWhitespace: + Enabled: false + +Style/StringLiterals: + Enabled: false + +Style/TrailingComma: + Enabled: false + +Style/GlobalVars: + Enabled: false + +Style/GuardClause: + Enabled: false + +Style/IfUnlessModifier: + Enabled: false + +Style/MultilineIfThen: + Enabled: false + +Style/MultilineOperationIndentation: + Enabled: false + +Style/NegatedIf: + Enabled: false + +Style/NegatedWhile: + Enabled: false + +Style/Next: + Enabled: false + +Style/SingleLineBlockParams: + Enabled: false + +Style/SingleLineMethods: + Enabled: false + +Style/SpecialGlobalVars: + Enabled: false + +Style/TrivialAccessors: + Enabled: false + +Style/UnlessElse: + Enabled: false + +Style/VariableInterpolation: + Enabled: false + +Style/VariableName: + Enabled: false + +Style/WhileUntilDo: + Enabled: false + +Style/EvenOdd: + Enabled: false + +Style/FileName: + Enabled: false + +Style/For: + Enabled: false + +Style/Lambda: + Enabled: false + +Style/MethodName: + Enabled: false + +Style/MultilineTernaryOperator: + Enabled: false + +Style/NestedTernaryOperator: + Enabled: false + +Style/NilComparison: + Enabled: false + +Style/FormatString: + Enabled: false + +Style/MultilineBlockChain: + Enabled: false + +Style/Semicolon: + Enabled: false + +Style/SignalException: + Enabled: false + +Style/NonNilCheck: + Enabled: false + +Style/Not: + Enabled: false + +Style/NumericLiterals: + Enabled: false + +Style/OneLineConditional: + Enabled: false + +Style/OpMethod: + Enabled: false + +Style/ParenthesesAroundCondition: + Enabled: false + +Style/PercentLiteralDelimiters: + Enabled: false + +Style/PerlBackrefs: + Enabled: false + +Style/PredicateName: + Enabled: false + +Style/RedundantException: + Enabled: false + +Style/SelfAssignment: + Enabled: false + +Style/Proc: + Enabled: false + +Style/RaiseArgs: + Enabled: false + +Style/RedundantBegin: + Enabled: false + +Style/RescueModifier: + Enabled: false + +Style/RegexpLiteral: + Enabled: false + +Lint/UnderscorePrefixedVariableName: + Enabled: false + +Metrics/ParameterLists: + Enabled: false + +Lint/RequireParentheses: + Enabled: false + +Lint/SpaceBeforeFirstArg: + Enabled: false + +Style/ModuleFunction: + Enabled: false + +Lint/Debugger: + Enabled: false + +Style/IfWithSemicolon: + Enabled: false + +Style/Encoding: + Enabled: false diff --git a/.travis.yml b/.travis.yml index e5cff13..8d0faa7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,38 @@ --- -sudo: false language: ruby -cache: bundler -bundler_args: --without development +bundler_args: --without development system_tests +before_install: rm Gemfile.lock || true rvm: + - 1.8.7 - 1.9.3 - - 2.1.6 - - 2.2.2 + - 2.0.0 + - 2.1.0 +script: bundle exec rake test env: - - PUPPET_VERSION="~> 3.0" - - PUPPET_VERSION="~> 4.0" + - PUPPET_GEM_VERSION="~> 2.7.0" + - PUPPET_GEM_VERSION="~> 3.2.0" + - PUPPET_GEM_VERSION="~> 3.3.0" + - PUPPET_GEM_VERSION="~> 3.4.0" + - PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES=yes + - PUPPET_GEM_VERSION="~> 3.6.0" STRICT_VARIABLES=yes + - PUPPET_GEM_VERSION="~> 3.7.0" STRICT_VARIABLES=yes + - PUPPET_GEM_VERSION="~> 3.7.0" STRICT_VARIABLES=yes FUTURE_PARSER=yes matrix: exclude: - - rvm: 2.2.2 - env: PUPPET_VERSION="~> 3.0" -script: bundle exec rake spec + # Ruby 1.9.3 + - rvm: 1.9.3 + env: PUPPET_GEM_VERSION="~> 2.7.0" + + # Ruby 2.0.0 + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 2.7.0" + + # Ruby 2.1.0 + - rvm: 2.1.0 + env: PUPPET_GEM_VERSION="~> 2.7.0" + - rvm: 2.1.0 + env: PUPPET_GEM_VERSION="~> 3.2.0" + - rvm: 2.1.0 + env: PUPPET_GEM_VERSION="~> 3.3.0" + - rvm: 2.1.0 + env: PUPPET_GEM_VERSION="~> 3.4.0" diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..29c933b --- /dev/null +++ b/.yardopts @@ -0,0 +1 @@ +--markup markdown diff --git a/CHANGELOG.md b/CHANGELOG.md index f337dc7..9c56485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,168 +1,189 @@ # Changelog +## 0.1.0 - 2015-12-12 + +* Added support for Archlinux + ([#40](https://github.com/ssm/ssm-munin/issues/40)) +* Added acceptance tests +* Added CONTRIBUTING.md for how to contribute to the module + ([#41](https://github.com/ssm/ssm-munin/issues/41)) +* Document all parameters in README.md + +### munin::node + +* Two new parameters: **bind\_address** and **bind\_port** + ([#37](https://github.com/ssm/ssm-munin/pull/37)) +* Bugfix: Rescue InvalidAddressError only if ruby is capable + ([#38](https://github.com/ssm/ssm-munin/pull/38)) + +### contributors + +Contributors to this release: David Hayes, Julien Pivotto, Stig +Sandbeck Mathisen, Victor Engmark + ## 0.0.10 - 2015-08-01 * Bugfix: Add missing dependency for the "munin-node" package when $munin::node::purge_configs is true. ([#34](https://github.com/ssm/ssm-munin/pull/34)) Contributors to this release: Martin Meinhold ## 0.0.9 - 2015-07-29 * Bugfix: The mastergroup, if used in the node's FQN (Fully Qualified Name), should no longer be empty on Puppet 4.0. ([#27](https://github.com/ssm/ssm-munin/pull/27)) * Bugfix: Using munin::master and munin::node with export and collect disabled should no longer trigger warnings about missing storeconfigs. ([#30](https://github.com/ssm/ssm-munin/issues/30), [#33](https://github.com/ssm/ssm-munin/pull/33)) ### munin::master * Add FreeBSD support. ### munin::node * New feature: Log to syslog with the "log\_destination" and "syslog\_facility" parameters. ([#23](https://github.com/ssm/ssm-munin/issues/23), [#24](https://github.com/ssm/ssm-munin/pull/24), [#25](https://github.com/ssm/ssm-munin/pull/25)) * New feature: Set the plugin runtime timeout with the "timeout" parameter. ([#29](https://github.com/ssm/ssm-munin/issues/29), [#32](https://github.com/ssm/ssm-munin/pull/32)) * New feature: Purge unmanaged plugins and plugin configuration with the "purge_configs" parameter. ([#28](https://github.com/ssm/ssm-munin/issues/28), [#31](https://github.com/ssm/ssm-munin/pull/31)) ## 0.0.8 - 2015-02-06 Support the future parser. Contributors to this release: Rike-Benjamin Schuppner, Stig Sandbeck Mathisen ## 0.0.7 - 2014-12-05 This release adds support for DragonFly BSD, FreeBSD, OpenBSD. Other changes listed below, per component. Contributors to this release: Alex Hornung, Chris Roddy, Frank Groeneveld, Fredrik Thulin, Julien Pivotto, Martin Jackson, Sebastian Wiesinger, Stig Sandbeck Mathisen ### munin::node * Add "host_name" parameter to override the host name of the munin node. * Add "file_group" parameter, used for configuration and log files. * Add "log_dir" parameter. * Improved handling of "allow" ACL parameter. ### munin::master * Improved collection logic. Set "collect_nodes" to "mine" to collect nodes which are targeted for this master, or "unclaimed" to pick up nodes not aimed a specific master. * Add global tls_* parameters for connecting to nodes. * Add "dbdir", "htmldir", "rundir" parameters. * Add "extra_config" parameter, which takes an array of extra configuration lines for munin.conf. ### munin::plugin * Support absolute paths as target for a plugin. ## 0.0.6 - 2014-12-05 * Retracted, had a breaking bug on older (3.4.x) puppet versions. ## 0.0.5 - 2014-03-19 * Support multiple masters with different nodes (Thanks: Cristian Gae) * Support older (1.4.6) munin versions (Thanks: Sergio Oliveira) * Update for compatibility with puppet 3.4 (Thanks: Harald Skoglund) * Easier configuration with more parameters. All parameters have trivial validation. ### munin::master - new parameter "config_root". Defaults should match supported operating systems. ### munin::plugin - new parameter "config_root". Defaults should match supported operating systems. ### munin::node - new parameter "address". Default is $::fqdn. This will be used as the "address" when registering with the munin master. - new parameter "config_root". Defaults should match supported operating systems. - new parameter "package_name". Default should match supported operating systems. - new parameter "service_name". Default should match supported operating systems. - new parameter "service_ensure". Default is "". Possible values: "", "running" or "stopped". ### munin::params - new class ## 0.0.4 - 2013-08-13 Bugfix for the munin::plugin define. - Bugfix: Ensure that we can run tests on ruby 1.8. - Bugfix: No longer requires the class `Munin::Plugins`, which does not exist in this module. ([#3](https://github.com/ssm/ssm-munin/issues/3)) - The `ensure` attribute no longer defaults to "link". If not set, a potentially existing plugin with the same name is not touched. - Plugin and configuration directories are now configurable. - Improved rspec tests, which now actually match the documentation. ## 0.0.2 - 2013-06-31 A few pull requests - Bugfix: Install munin package before creating munin-conf.d directory ([#1](https://github.com/ssm/ssm-munin/pull/1)) - Make graph strategy configurable ([#2](https://github.com/ssm/ssm-munin/pull/2)) - Improve documentation ## 0.0.1 - 2013-06-02 Initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..36d07a8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,92 @@ +This module has grown over time based on a range of contributions from +people using it. If you follow these contributing guidelines your patch +will likely make it into a release a little quicker. + + +## Contributing + +1. Fork the repo. + +2. Run the tests. We only take pull requests with passing tests, and + it's great to know that you have a clean slate. + +3. Add a test for your change. Only refactoring and documentation + changes require no new tests. If you are adding functionality + or fixing a bug, please add a test. + +4. Make the test pass. + +5. Push to your fork and submit a pull request. + + +## Dependencies + +The testing and development tools have a bunch of dependencies, +all managed by [Bundler](http://bundler.io/) according to the +[Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions). + +By default the tests use a baseline version of Puppet. + +If you have Ruby 2.x or want a specific version of Puppet, +you must set an environment variable such as: + + export PUPPET_VERSION="~> 3.2.0" + +Install the dependencies like so... + + bundle install + +## Syntax and style + +The test suite will run [Puppet Lint](http://puppet-lint.com/) and +[Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to +check various syntax and style things. You can run these locally with: + + bundle exec rake lint + bundle exec rake syntax + +## Running the unit tests + +The unit test suite covers most of the code, as mentioned above please +add tests if you're adding new functionality. If you've not used +[rspec-puppet](http://rspec-puppet.com/) before then feel free to ask +about how best to test your new feature. Running the test suite is done +with: + + bundle exec rake spec + +Note also you can run the syntax, style and unit tests in one go with: + + bundle exec rake test + +### Automatically run the tests + +During development of your puppet module you might want to run your unit +tests a couple of times. You can use the following command to automate +running the unit tests on every change made in the manifests folder. + + bundle exec guard + +## Integration tests + +The unit tests just check the code runs, not that it does exactly what +we want on a real machine. For that we're using +[Beaker](https://github.com/puppetlabs/beaker). + +Beaker fires up a new virtual machine (using Vagrant) and runs a series of +simple tests against it after applying the module. You can run our +Beaker tests with: + + bundle exec rake acceptance + +This will use the host described in `spec/acceptance/nodeset/default.yml` +by default. To run against another host, set the `BEAKER_set` environment +variable to the name of a host described by a `.yml` file in the +`nodeset` directory. For example, to run against CentOS 6.4: + + BEAKER_set=centos-64-x64 bundle exec rake acceptance + +If you don't want to have to recreate the virtual machine every time you +can use `BEAKER_destroy=no` and `BEAKER_provision=no`. On the first run you will +at least need `BEAKER_provision` set to yes (the default). The Vagrantfile +for the created virtual machines will be in `.vagrant/beaker_vagrant_files`. diff --git a/Gemfile b/Gemfile index 8baf230..ca3fd4e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,16 +1,33 @@ -source 'https://rubygems.org' +source "https://rubygems.org" group :test do - gem 'rake' - gem 'puppet', ENV['PUPPET_VERSION'] || '~> 4.0' - gem 'rspec-puppet' - gem 'rspec-puppet-facts', :require => false - gem 'puppetlabs_spec_helper', '~> 0.10.2' - gem 'metadata-json-lint' + gem "rake" + gem "puppet", ENV['PUPPET_GEM_VERSION'] || '~> 3.8.0' + gem "rspec", '< 3.2.0' + gem "rspec-puppet" + gem "puppetlabs_spec_helper" + gem "metadata-json-lint" + gem "rspec-puppet-facts" + gem 'rubocop', '0.33.0' + gem 'simplecov', '>= 0.11.0' + gem 'simplecov-console' + + gem "puppet-lint-absolute_classname-check" + gem "puppet-lint-leading_zero-check" + gem "puppet-lint-trailing_comma-check" + gem "puppet-lint-version_comparison-check" + gem "puppet-lint-classes_and_types_beginning_with_digits-check" + gem "puppet-lint-unquoted_string-check" end group :development do - gem 'travis' - gem 'vagrant-wrapper' - gem 'guard-rake' + gem "travis" + gem "travis-lint" + gem "guard-rake" +end + +group :system_tests do + gem "beaker" + gem "beaker-rspec" + gem "beaker-puppet_install_helper" end diff --git a/Guardfile b/Guardfile index f84d6e4..fd50602 100644 --- a/Guardfile +++ b/Guardfile @@ -1,13 +1,5 @@ notification :off -directories %w(manifests templates spec/classes spec/defines) - guard 'rake', :task => 'test' do watch(%r{^manifests\/(.+)\.pp$}) - watch(%r{^templates\/(.+)\.erb$}) - watch(%r{^spec/.*_spec.rb}) -end - -guard 'rake', :task => 'metadata' do - watch('metadata.json') end diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9f71055 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/README.md b/README.md index 9779528..cde6b12 100644 --- a/README.md +++ b/README.md @@ -1,224 +1,457 @@ -# Puppet munin module +# Puppet module ssm-munin # [![Puppet Forge](http://img.shields.io/puppetforge/v/ssm/munin.svg)](https://forge.puppetlabs.com/ssm/munin) [![Build Status](https://travis-ci.org/ssm/ssm-munin.png?branch=master)](https://travis-ci.org/ssm/ssm-munin) -# Table of contents + +**Table of Contents** -1. [Overview](#overview) -2. [Munin Master](#munin-master) -3. [Munin Node](#munin-node) -4. [Munin Plugins](#munin-plugins) +- [Puppet module ssm-munin](#puppet-module-ssm-munin) +- [Overview](#overview) +- [Module Description](#module-description) +- [Setup](#setup) + - [Setup requirements](#setup-requirements) +- [Usage](#usage) + - [munin::node](#muninnode) + - [munin::master](#muninmaster) + - [munin::master::node_definition](#muninmasternodedefinition) + - [munin::plugin](#muninplugin) +- [Examples](#examples) + - [munin::master::node_definition](#muninmasternodedefinition) + - [Static node definitions](#static-node-definitions) + - [node definitions as class parameter](#node-definitions-as-class-parameter) + - [node definitions with hiera](#node-definitions-with-hiera) + - [munin::node](#muninnode) + - [Allow remote masters to connect](#allow-remote-masters-to-connect) + - [munin::plugin](#muninplugin) + - [Activate a plugin](#activate-a-plugin) + - [Install and activate a plugin](#install-and-activate-a-plugin) + - [Activate wildcard plugin](#activate-wildcard-plugin) + - [Plugin with configuration](#plugin-with-configuration) + - [A plugin configuration file](#a-plugin-configuration-file) -# Overview + -Control munin master, munin node, and munin plugins. +# Overview # -Munin nodes are automatically configured on the master. (Requires -puppetdb) +Configure munin master, node and plugins. -# Munin master + +# Module Description # + +This module installs the munin master using the **munin::master** +class, munin node using the **munin::node** class, and can install, +configure and manage munin plugins using the **munin::plugin** defined +type. + +Munin nodes are automatically exported by the munin nodes, and +collected on the munin master. (Requires puppetdb) + +# Setup # + +Classify all nodes with **munin::node**, and classify at least one +node with **munin::master**. Use the **munin::plugin** defined type to +control plugin installation and configuration. + + +## Setup requirements ## + +Munin should be available in most distributions. For RedHat OS +Family, you need to install the EPEL source. + +The **munin::master** class does not manage any web server +configuration. The munin package installed might add some. + + +# Usage # + +## munin::node ## + +Typical usage + + include munin::node + +Installs a munin node. + +By default, **munin::node** exports a munin node definition so a node +classified with the **munin::master** class can collect it. + +Parameters for exporting a munin node definition + +* **address**: The address used in the munin master node definition. + +* **export_node**: "enabled" or "disabled". Defaults to "enabled". + Causes the node config to be exported to puppetmaster. + +* **masterconfig**: List of configuration lines to append to the munin + master node definitinon + +* **mastername**: The name of the munin master server which will + collect the node definition. + +* **mastergroup**: The group used on the master to construct a FQN for + this node. Defaults to "", which in turn makes munin master use the + domain. Note: changing this for a node also means you need to move + rrd files on the master, or graph history will be lost. + +Parameters for the munin node service and configuration + +* **allow**: List of IPv4 and IPv6 addresses and networks to allow to + connect. + +* **bind_address**: The IP address the munin-node process listens + on. Defaults: *. + +* **bind_port**: The port number the munin-node process listens on. + +* **config_root**: Root directory for munin configuration. + +* **host_name**: The host name munin node identifies as. Defaults to + the $::fqdn fact. + +* **log_dir**: The log directory for the munin node process. Defaults + change according to osfamily, see munin::params::node for details. + +* **log_file**: Appended to "log_dir". Defaults to "munin-node.log". + +* **log_destination**: "file" or "syslog". Defaults to "file". If + log_destination is "syslog", the "log_file" and "log_dir" parameters + are ignored, and the "syslog_*" parameters are used if set. + +* **purge_configs**: Removes all other munin plugins and munin plugin + configuration files. Boolean, defaults to false. + +* **syslog_facility**: Defaults to undef, which makes munin-node use + the perl Net::Server module default of "daemon". Possible values are + any syslog facility by number, or lowercase name. + +* **plugins**: A hash used by create_resources to create munin::plugin + instances. + +* **package_name**: The name of the munin node package to install. + +* **service_name**: The name of the munin node service. + +* **service_ensure**: Defaults to "". If set to "running" or + "stopped", it is used as parameter "ensure" for the munin node + service. + +* **file_group**: The UNIX group name owning the configuration files, + log files, etc. + +* **timeout**: Used to set the global plugin runtime timeout for this + node. Integer. (optional, no default) + +* **nodeconfig**: Array of extra configuration lines to append to the + munin node configuration. (optional, no default) + + +## munin::master ## Typical usage: include munin::master -Installs a munin master, and automatically collects configuration from -all munin nodes configured with munin::node. +Installs a munin master. + +By default, **munin::master** collects all munin node definitions +exported by nodes classified with **munin::node**/ + +Parameters for collecting and defining munin nodes + +* **collect_nodes**: 'enabled' (default), 'disabled', 'mine' or +'unclaimed'. 'enabled' makes the munin master collect all exported +node\_definitions. 'disabled' disables it. 'mine' makes the munin +master collect nodes matching **$munin::master::host_name**, while +'unclaimed' makes the munin master collect nodes not tagged with a +host name. + +* **host_name**: A host name for this munin master, matched with +munin::node::mastername for collecting nodes. Defaults to $::fqdn + +* **node_definitions**: A hash of node definitions used by +create_resources (optional, default: {}) + +Parameters for the munin master configuration + +* **config_root**: the root directory of the munin master +configuration. (Default is "/etc/munin" on most platforms). + +* **dbdir**: Path to the munin dbdir, where munin stores everything + +* **graph_strategy**: 'cgi' (default) or 'cron' Controls if +munin-graph graphs all services ('cron') or if graphing is done by +munin-cgi-graph (which must configured seperatly) -# Munin node definition +* **htmldir**: Path to where munin will generate HTML documents and +graphs, used if graph_strategy is cron. + +* **html_strategy**: 'cgi' (default) or 'cron' Controls if munin-html +will recreate all html pages every run interval ('cron') or if html +pages are generated by munin-cgi-graph (which must configured +seperatly) + +* **rundir**: Path to directory munin uses for pid and lock files. + +* **tls**: 'enabled' or 'disabled' (default). Controls the use of TLS +globally for master to node communications. + +* **tls_certificate**: Path to a file containing a TLS certificate. No +default. Required if tls is enabled. + +* **tls_private_key**: Path to a file containing a TLS key. No +default. Required if tls is enabled. + +* **tls_verify_certificate**: 'yes' (default) or 'no'. + +* **extra_config**: Extra lines of config to put in munin.conf. + +## munin::master::node_definition ## + +Typical usage: munin::master::node_definition { 'fqn': address => $address, config => ['additional', 'configuration' 'lines'], } +This will add configuration for the munin master to connect to a munin +node, and ask for data from its munin plugins. + +Note: By default, the node classified with **munin::master** will +collect all all exported instances of this type from hosts classified +with **munin::node**. + The resource title is used as the munin FQN, or "fully qualified name". This defines the node name and group. It is common to use the host's fully qualified domain name, where the domain name will be implicitly used as the node group. -The address is the host name, ip address, or alternate transport used -to contact the node. +Parameters + +* **address**: The address of the munin node. A hostname, an IP +address, or a ssh:// uri for munin-async node. (**required**, no +default) -To add more configuration, specify it as an array for the "config" -attribute. +* **mastername**: The name of the munin master server which will +collect the node definition. (**optional**, no default) + +* **config**: An array of configuration lines to be added to the node +definition. (**optional**, no default) For more information about configuring a munin node definition, see http://munin.readthedocs.org/en/latest/reference/munin.conf.html#node-definitions -If you have multiple munin master servers in your infrastructure and want to assign different nodes to different masters, you can specify the master's fully qualified domain name on the node's definition: +If you have multiple munin master servers in your infrastructure and +want to assign different nodes to different masters, you can specify +the master's fully qualified domain name on the node's definition: munin::master::node_definition { 'fqn': address => $address, mastername => 'munin.example.com', } -## Static node definitions + +## munin::plugin ## + +The defined type munin::plugin is used to control the munin plugins +used on a munin node. + +Typical usage: + + munin::plugin { 'cpu': + ensure => link, + } + +Parameters: + +* **ensure**: "link", "present", "absent" or "". (optional, default is +""). The ensure parameter is mandatory for installing a plugin, and +interacts with the **source** and **target** parameters (see below). + +* **source**: when ensure => present, source file. (optional) + +* **target**: when ensure => link, link target. If target is an +absolute path (starts with "/") it is used directly. If target is a +relative path, $munin::node::plugin_share_dir is prepended. (optional) + +* **config**: array of lines for munin plugin config + +* **config_label**: label for munin plugin config + +When using "**ensure** => link", a symlink is created from +/etc/munin/plugins/$title to what the optional **target** parameter +contains, or to /usr/share/munin/plugins/$title if that is not set. + +When using "**ensure** => present", you need to provide the **source** +parameter as well. + +When **ensure** is not set, a plugin will not be installed, but extra +plugin configuration can be managed with the **config** and +**config_label** parameters. + +# Examples # + +## munin::master::node_definition ## + + +### Static node definitions ### The munin master class will collect all "munin::master::node_definition" exported by "munin::node". For extra nodes, you can define them in hiera, and munin::master will create them. Example: munin::master::node_definition { 'foo.example.com': address => '192.0.2.1' } munin::master::node_definition { 'bar.example.com': address => '192.0.2.1', config => [ 'load.graph_future 30', 'load.load.trend yes', 'load.load.predict 86400,12' ], } -### node definitions as class parameter + +### node definitions as class parameter ### If you define your nodes as a data structure in a puppet manifest, or from the puppet External Node Classifier, you can use a class parameter: $nodes = { ... } class { 'puppet::master': node_definitions => $nodes, } -### node definitions with hiera + +### node definitions with hiera ### A JSON definition. { "munin::master::node_definitions" : { "foo.example.com" : { "address" : "192.0.2.1" }, "bar.example.com" : { "address" : "192.0.2.2", "config" : [ "load.graph_future 30", "load.load.trend yes", "load.load.predict 86400,12" ] } } } A YAML definition --- munin::master::node_definitions: foo.example.com: address: 192.0.2.1 bar.example.com: address: 192.0.2.2 config: - load.graph_future 30 - load.load.trend yes - load.load.predict 86400,12 -# Munin node +## munin::node ## -Typical usage: +### Allow remote masters to connect ### + +The **allow** parameter enables the munin master to connect. By +default, the munin node only permits connections from localhost. class { 'munin::node': allow => [ '192.0.2.0/24', '2001:db8::/64' ] } or in hiera: --- munin::node::allow: - 192.0.2.0/24 - 2001:db8::/64 Installs munin-node, and exports a munin::master::node_definition which munin::master will collect, and allows munin masters on specified networks to connect. -The munin::node class does take more parameters, see the -'manifests/node.pp' file for complete documentation. - -# Munin plugins - -The defined type munin::plugin is used to control the munin plugins -used on a munin node. - -Typical usage: - - munin::plugin { 'cpu': - ensure => link, - } -## Examples +## munin::plugin ## -### Activate a plugin +### Activate a plugin ### Here, we activate an already installed plugin. The use of "ensure => link" creates an implicit "target => /usr/share/munin/plugins/$title". The "target" parameter can be set to an absolute path (starting with a "/"), or a relative path (anything else). If relative, $munin::params::node::plugin_share_dir is prepended to the path. munin::plugin { 'apt': ensure => link; 'something': ensure => link, target => '/usr/local/share/munin/plugins/something'; 'ip_eth0': ensure => link, target => 'ip_'; # becomes $munin::params::node::plugin_share_dir/ip_ } -### Install and activate a plugin +### Install and activate a plugin ### The use of "ensure => present" creates a file in /etc/munin/plugins munin::plugin { 'somedaemon': ensure => present, source => 'puppet:///modules/munin/plugins/somedaemon', } -### Activate wildcard plugin +### Activate wildcard plugin ### A pair of plugins we provide, with a _name symlink (This is also known as "wildcard" plugins) munin::plugin { 'foo_bar': ensure => present, target => 'foo_', source => 'puppet:///modules/munin/plugins/foo_'; 'foo_baz': ensure => present, target => 'foo_', source => 'puppet:///modules/munin/plugins/foo_'; } -### Plugin with configuration +### Plugin with configuration ### This creates an additional "/etc/munin/plugin-conf.d/${title}.conf" munin::plugin { 'bletch': ensure => link, config => 'env.database flumpelump'; 'thud': ensure => present, source => 'puppet:///modules/munin/plugins/thud', config => ['env.database zotto', 'user root']; } -### A plugin configuration file +### A plugin configuration file ### This only adds a plugin configuration file. munin::plugin { 'slapd': config => ['env.rootdn cn=admin,dc=example,dc=org'], config_label => 'slapd_*', } diff --git a/Rakefile b/Rakefile index 0db5abd..8ac719e 100644 --- a/Rakefile +++ b/Rakefile @@ -1,37 +1,62 @@ +require 'rubygems' +require 'bundler/setup' + require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet/version' +require 'puppet/vendor/semantic/lib/semantic' unless Puppet.version.to_f < 3.6 require 'puppet-lint/tasks/puppet-lint' require 'puppet-syntax/tasks/puppet-syntax' +require 'metadata-json-lint/rake_task' +require 'rubocop/rake_task' -# Optional gems, used for development +# These gems aren't always present, for instance +# on Travis with --without development begin - require 'puppet_blacksmith/rake_tasks' -rescue LoadError +rescue LoadError # rubocop:disable Lint/HandleExceptions end -# workaround for https://github.com/rodjek/puppet-lint/issues/331 +RuboCop::RakeTask.new + +exclude_paths = [ + "bundle/**/*", + "pkg/**/*", + "vendor/**/*", + "spec/**/*", +] + +# Coverage from puppetlabs-spec-helper requires rcov which +# doesn't work in anything since 1.8.7 +Rake::Task[:coverage].clear + Rake::Task[:lint].clear PuppetLint.configuration.relative = true -PuppetLint.configuration.send("disable_80chars") -PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}" +PuppetLint.configuration.disable_80chars +PuppetLint.configuration.disable_class_inherits_from_params_class +PuppetLint.configuration.disable_class_parameter_defaults PuppetLint.configuration.fail_on_warnings = true -exclude_paths = [ - 'pkg/**/*', - 'vendor/**/*', - 'spec/**/*', -] -PuppetLint.configuration.ignore_paths = exclude_paths +PuppetLint::RakeTask.new :lint do |config| + config.ignore_paths = exclude_paths +end + PuppetSyntax.exclude_paths = exclude_paths -task :metadata do - sh 'metadata-json-lint metadata.json' +desc "Run acceptance tests" +RSpec::Core::RakeTask.new(:acceptance) do |t| + t.pattern = 'spec/acceptance' +end + +desc "Populate CONTRIBUTORS file" +task :contributors do + system("git log --format='%aN' | sort -u > CONTRIBUTORS") end -desc 'Run syntax, lint, and spec tests.' +desc "Run syntax, lint, and spec tests." task :test => [ + :metadata_lint, :syntax, :lint, + :rubocop, :spec, - :metadata, ] diff --git a/manifests/master.pp b/manifests/master.pp index e1aeeca..734228c 100644 --- a/manifests/master.pp +++ b/manifests/master.pp @@ -1,135 +1,135 @@ # munin::master - Define a munin master # # The munin master will install munin, and collect all exported munin # node definitions as files into /etc/munin/munin-conf.d/. # # Parameters: # # - node_definitions: A hash of node definitions used by # create_resources to make static node definitions. # # - host_name: A host name for this munin master, matched with # munin::node::mastername for collecting nodes. Defaults to $::fqdn # # - graph_strategy: 'cgi' (default) or 'cron' # Controls if munin-graph graphs all services ('cron') or if graphing is done # by munin-cgi-graph (which must configured seperatly) # # - html_strategy: 'cgi' (default) or 'cron' # Controls if munin-html will recreate all html pages every run interval # ('cron') or if html pages are generated by munin-cgi-graph (which must # configured seperatly) # # - config_root: the root directory of the munin master configuration. # Default: /etc/munin on most platforms. # # - collect_nodes: 'enabled' (default), 'disabled', 'mine' or # 'unclaimed'. 'enabled' makes the munin master collect all exported # node_definitions. 'disabled' disables it. 'mine' makes the munin # master collect nodes matching $munin::master::host_name, while # 'unclaimed' makes the munin master collect nodes not tagged with a # host name. # # - dbdir: Path to the munin dbdir, where munin stores everything # # - htmldir: Path to where munin will generate HTML documents and # graphs, used if graph_strategy is cron. # # - rundir: Path to directory munin uses for pid and lock files. # # - tls: 'enabled' or 'disabled' (default). Controls the use of TLS # globally for master to node communications. # # - tls_certificate: Path to a file containing a TLS certificate. No # default. Required if tls is enabled. # # - tls_private_key: Path to a file containing a TLS key. No default. # Required if tls is enabled. # # - tls_verify_certificate: 'yes' (default) or 'no'. # # - extra_config: Extra lines of config to put in munin.conf. class munin::master ( $node_definitions = $munin::params::master::node_defintions, $graph_strategy = $munin::params::master::graph_strategy, $html_strategy = $munin::params::master::html_strategy, $config_root = $munin::params::master::config_root, $collect_nodes = $munin::params::master::collect_nodes, $dbdir = $munin::params::master::dbdir, $htmldir = $munin::params::master::htmldir, $logdir = $munin::params::master::logdir, $rundir = $munin::params::master::rundir, $tls = $munin::params::master::tls, $tls_certificate = $munin::params::master::tls_certificate, $tls_private_key = $munin::params::master::tls_private_key, $tls_verify_certificate = $munin::params::master::tls_verify_certificate, $host_name = $munin::params::master::host_name, $extra_config = $munin::params::master::extra_config, ) inherits munin::params::master { if $node_definitions { validate_hash($node_definitions) } if $graph_strategy { validate_re($graph_strategy, [ '^cgi$', '^cron$' ]) } if $html_strategy { validate_re($html_strategy, [ '^cgi$', '^cron$' ]) } validate_re($collect_nodes, [ '^enabled$', '^disabled$', '^mine$', '^unclaimed$' ]) validate_absolute_path($config_root) validate_re($tls, [ '^enabled$', '^disabled$' ]) if $tls == 'enabled' { validate_re($tls_verify_certificate, [ '^yes$', '^no$' ]) validate_absolute_path($tls_private_key) validate_absolute_path($tls_certificate) } if $host_name { validate_string($host_name) - if ! is_domain_name("${host_name}") { + if ! is_domain_name($host_name) { fail('host_name should be a valid domain name') } } validate_array($extra_config) # The munin package and configuration package { 'munin': ensure => latest, } File { owner => 'root', group => 'root', mode => '0644', require => Package['munin'], } file { "${config_root}/munin.conf": content => template('munin/munin.conf.erb'), } file { "${config_root}/munin-conf.d": ensure => directory, recurse => true, purge => true, force => true, } if $collect_nodes != 'disabled' { - class { 'munin::master::collect': + class { '::munin::master::collect': collect_nodes => $collect_nodes, host_name => $host_name, } } # Create static node definitions if $node_definitions { create_resources(munin::master::node_definition, $node_definitions, {}) } } diff --git a/manifests/master/node_definition.pp b/manifests/master/node_definition.pp index dbf4755..cc1d582 100644 --- a/manifests/master/node_definition.pp +++ b/manifests/master/node_definition.pp @@ -1,35 +1,35 @@ # munin::master::node_definition - A node definition for the munin # master. # # - title: The title of the defined resource should be a munin FQN, # ('hostname', 'group;hostname', 'group;subgroup;hostname'). If a # group is not set, munin will by default use the domain of the node # as a group. # # Parameters # # - address: The address of the munin node. A hostname, an IP address, # or a ssh:// uri for munin-async node. Required. # # - mastername: The name of the munin master server which will collect # the node definition. # # - config: An array of configuration lines to be added to the node # definition. Default is an empty array. # define munin::master::node_definition ( $address, $mastername='', $config=[], ) { validate_string($address) validate_array($config) $filename=sprintf('/etc/munin/munin-conf.d/node.%s.conf', regsubst($name, '[^[:alnum:]\.]', '_', 'IG')) file { $filename: - content => template('munin/master/node.definition.conf.erb') + content => template('munin/master/node.definition.conf.erb'), } } diff --git a/manifests/node.pp b/manifests/node.pp index cd929f4..423d5b9 100644 --- a/manifests/node.pp +++ b/manifests/node.pp @@ -1,184 +1,190 @@ # munin::node - Configure a munin node, and export configuration a # munin master can collect. # # Parameters: # # allow: List of IPv4 and IPv6 addresses and networks to allow to connect. # # config_root: Root directory for munin configuration. # # nodeconfig: List of lines to append to the munin node configuration. # # host_name: The host name munin node identifies as. Defaults to # the $::fqdn fact. # # log_dir: The log directory for the munin node process. Defaults # change according to osfamily, see munin::params::node for details. # # log_file: Appended to "log_dir". Defaults to "munin-node.log". # # log_destination: "file" or "syslog". Defaults to "file". If log_destination # is "syslog", the "log_file" and "log_dir" parameters are ignored, and the # "syslog_*" parameters are used if set. # # purge_configs: Removes all other munin plugins and munin plugin # configuration files. Boolean, defaults to false. # # syslog_facility: Defaults to undef, which makes munin-node use the # perl Net::Server module default of "daemon". Possible values are any # syslog facility by number, or lowercase name. # # masterconfig: List of configuration lines to append to the munin # master node definitinon # # mastername: The name of the munin master server which will collect # the node definition. # # mastergroup: The group used on the master to construct a FQN for # this node. Defaults to "", which in turn makes munin master use the # domain. Note: changing this for a node also means you need to move # rrd files on the master, or graph history will be lost. # # plugins: A hash used by create_resources to create munin::plugin # instances. # # address: The address used in the munin master node definition. # +# bind_address: The IP address the munin-node process listens on. Defaults: *. +# +# bind_port: The port number the munin-node process listens on. +# # package_name: The name of the munin node package to install. # # service_name: The name of the munin node service. # # service_ensure: Defaults to "". If set to "running" or "stopped", it # is used as parameter "ensure" for the munin node service. # # export_node: "enabled" or "disabled". Defaults to "enabled". # Causes the node config to be exported to puppetmaster. # # file_group: The UNIX group name owning the configuration files, # log files, etc. # # timeout: Used to set the global plugin runtime timeout for this # node. Integer. Defaults to undef, which lets munin-node use its # default of 10 seconds. class munin::node ( $address = $munin::params::node::address, $allow = $munin::params::node::allow, + $bind_address = $munin::params::node::bind_address, + $bind_port = $munin::params::node::bind_port, $config_root = $munin::params::node::config_root, $host_name = $munin::params::node::host_name, $log_dir = $munin::params::node::log_dir, $log_file = $munin::params::node::log_file, $masterconfig = $munin::params::node::masterconfig, $mastergroup = $munin::params::node::mastergroup, $mastername = $munin::params::node::mastername, $nodeconfig = $munin::params::node::nodeconfig, $package_name = $munin::params::node::package_name, $plugins = $munin::params::node::plugins, $purge_configs = $munin::params::node::purge_configs, $service_ensure = $munin::params::node::service_ensure, $service_name = $munin::params::node::service_name, $export_node = $munin::params::node::export_node, $file_group = $munin::params::node::file_group, $log_destination = $munin::params::node::log_destination, $syslog_facility = $munin::params::node::syslog_facility, $timeout = $munin::params::node::timeout, ) inherits munin::params::node { validate_array($allow) validate_array($nodeconfig) validate_array($masterconfig) if $mastergroup { validate_string($mastergroup) } if $mastername { validate_string($mastername) } validate_hash($plugins) validate_string($address) validate_absolute_path($config_root) validate_string($package_name) validate_string($service_name) if $service_ensure { validate_re($service_ensure, '^(running|stopped)$') } validate_re($export_node, '^(enabled|disabled)$') validate_absolute_path($log_dir) validate_re($log_destination, '^(?:file|syslog)$') validate_string($log_file) validate_string($file_group) validate_bool($purge_configs) if $timeout { validate_integer($timeout) } case $log_destination { 'file': { $_log_file = "${log_dir}/${log_file}" validate_absolute_path($_log_file) } 'syslog': { $_log_file = 'Sys::Syslog' if $syslog_facility { validate_string($syslog_facility) validate_re($syslog_facility, '^(?:\d+|(?:kern|user|mail|daemon|auth|syslog|lpr|news|uucp|authpriv|ftp|cron|local[0-7]))$') } } default: { fail('log_destination is not set') } } if $mastergroup { $fqn = "${mastergroup};${host_name}" } else { $fqn = $host_name } if $service_ensure { $_service_ensure = $service_ensure } else { $_service_ensure = undef } # Defaults File { ensure => present, owner => 'root', group => $file_group, mode => '0444', } package { $package_name: ensure => installed, } service { $service_name: ensure => $_service_ensure, enable => true, require => Package[$package_name], } file { "${config_root}/munin-node.conf": content => template('munin/munin-node.conf.erb'), require => Package[$package_name], notify => Service[$service_name], } # Export a node definition to be collected by the munin master. # (Separated into its own class to prevent warnings about "missing # storeconfigs", even if $export_node is not enabled) if $export_node == 'enabled' { - class { 'munin::node::export': + class { '::munin::node::export': address => $address, fqn => $fqn, mastername => $mastername, masterconfig => $masterconfig, } } # Generate plugin resources from hiera or class parameter. create_resources(munin::plugin, $plugins, {}) # Purge unmanaged plugins and plugin configuration files. if $purge_configs { file { ["${config_root}/plugins", "${config_root}/plugin-conf.d" ]: ensure => directory, recurse => true, purge => true, require => Package[$package_name], notify => Service[$service_name], } } } diff --git a/manifests/params/master.pp b/manifests/params/master.pp index b745b6a..ab5322b 100644 --- a/manifests/params/master.pp +++ b/manifests/params/master.pp @@ -1,34 +1,37 @@ +# Parameters for the munin::master class. Add support for new OS +# families here. class munin::params::master { $message = "Unsupported osfamily ${::osfamily}" $graph_strategy = 'cgi' $html_strategy = 'cgi' $node_definitions = '' $collect_nodes = 'enabled' $dbdir = undef $htmldir = undef $logdir = undef $rundir = undef $tls = 'disabled' $tls_certificate = undef $tls_private_key = undef $tls_verify_certificate = 'yes' $extra_config = [] $host_name = $::fqdn case $::osfamily { + 'Archlinux', 'Debian', 'RedHat': { $config_root = '/etc/munin' } 'Solaris': { $config_root = '/opt/local/etc/munin' } 'FreeBSD': { $config_root = '/usr/local/etc/munin' } default: { fail($message) } } } diff --git a/manifests/params/node.pp b/manifests/params/node.pp index f2ae4ca..729ad97 100644 --- a/manifests/params/node.pp +++ b/manifests/params/node.pp @@ -1,75 +1,80 @@ +# Parameters for the munin::node class. Add support for new OS +# families here. class munin::params::node { $message = "Unsupported osfamily: ${::osfamily}" $address = $::fqdn $host_name = $::fqdn + $bind_address = '*' + $bind_port = 4949 $allow = [] $masterconfig = [] $mastergroup = undef $mastername = undef $nodeconfig = [] $plugins = {} $service_ensure = undef $export_node = 'enabled' $log_file = 'munin-node.log' $log_destination = 'file' $syslog_facility = undef $purge_configs = false $timeout = undef case $::osfamily { + 'Archlinux', 'RedHat': { $config_root = '/etc/munin' $log_dir = '/var/log/munin-node' $service_name = 'munin-node' $package_name = 'munin-node' $plugin_share_dir = '/usr/share/munin/plugins' $file_group = 'root' } 'Debian': { $config_root = '/etc/munin' $log_dir = '/var/log/munin' $service_name = 'munin-node' $package_name = 'munin-node' $plugin_share_dir = '/usr/share/munin/plugins' $file_group = 'root' } 'Solaris': { case $::operatingsystem { 'SmartOS': { $config_root = '/opt/local/etc/munin' $log_dir = '/var/opt/log/munin' $service_name = 'smf:/munin-node' $package_name = 'munin-node' $plugin_share_dir = '/opt/local/share/munin/plugins' $file_group = 'root' } default: { fail("Unsupported operatingsystem ${::operatingsystem} for osfamily ${::osfamily}") } } } 'FreeBSD', 'DragonFly': { $config_root = '/usr/local/etc/munin' $log_dir = '/var/log/munin' $service_name = 'munin-node' $package_name = 'munin-node' $plugin_share_dir = '/usr/local/share/munin/plugins' $file_group = 'wheel' } 'OpenBSD': { $config_root = '/etc/munin' $log_dir = '/var/log/munin' $service_name = 'munin_node' $package_name = 'munin-node' $plugin_share_dir = '/usr/local/libexec/munin/plugins' $file_group = 'wheel' } default: { fail($message) } } } diff --git a/manifests/plugin.pp b/manifests/plugin.pp index 9d8a90b..1b5b66e 100644 --- a/manifests/plugin.pp +++ b/manifests/plugin.pp @@ -1,92 +1,92 @@ # munin::plugin # # Parameters: # # - ensure: "link", "present", "absent" or "". Default is "". The # ensure parameter is mandatory for installing a plugin. # - source: when ensure => present, source file # - target: when ensure => link, link target. If target is an # absolute path (starts with "/") it is used directly. If target is # a relative path, $munin::node::plugin_share_dir is prepended. # - config: array of lines for munin plugin config # - config_label: label for munin plugin config define munin::plugin ( $ensure='', $source=undef, $target='', $config=undef, $config_label=undef, ) { - include munin::node + include ::munin::node $plugin_share_dir=$munin::node::plugin_share_dir validate_absolute_path($plugin_share_dir) File { require => Package[$munin::node::package_name], notify => Service[$munin::node::service_name], } validate_re($ensure, '^(|link|present|absent)$') case $ensure { 'present': { $handle_plugin = true $plugin_ensure = 'present' } 'absent': { $handle_plugin = true $plugin_ensure = 'absent' } 'link': { $handle_plugin = true $plugin_ensure = 'link' case $target { '': { $plugin_target = "${munin::node::plugin_share_dir}/${title}" } /^\//: { $plugin_target = $target } default: { $plugin_target = "${munin::node::plugin_share_dir}/${target}" } } validate_absolute_path($plugin_target) } default: { $handle_plugin = false } } if $config { $config_ensure = $ensure ? { - absent => absent, + 'absent'=> absent, default => present, } } else { $config_ensure = absent } if $handle_plugin { # Install the plugin file {"${munin::node::config_root}/plugins/${name}": ensure => $plugin_ensure, source => $source, target => $plugin_target, mode => '0755', } } # Config file{ "${munin::node::config_root}/plugin-conf.d/${name}.conf": ensure => $config_ensure, content => template('munin/plugin_conf.erb'), } } diff --git a/metadata.json b/metadata.json index 9db9c64..260186a 100644 --- a/metadata.json +++ b/metadata.json @@ -1,62 +1,66 @@ { - "name": "ssm/munin", - "version": "0.0.10", + "name": "ssm-munin", + "version": "0.1.0", "author": "ssm", "license": "Apache-2.0", "summary": "Configure munin master, node and plugins", "source": "https://github.com/ssm/ssm-munin", "dependencies": [ { "name": "puppetlabs/stdlib", "version_requirement": ">= 2.3.0" } ], "project_page": "https://github.com/ssm/ssm-munin", "issues_url": "https://github.com/ssm/ssm-munin/issues", "operatingsystem_support": [ + { + "operatingsystem": "Archlinux", + "operatingsystemrelease": [ "4" ] + }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "6", "7", "8" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "RedHat", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "Scientific", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "SmartOS" }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "10.04", "12.04", "14.04" ] }, { "operatingsystem": "FreeBSD", "operatingsystemrelease": [ "9", "10" ] }, { "operatingsystem": "DragonFly" }, { "operatingsystem": "OpenBSD" } ], "tags": [ "munin", "monitoring", "graphing", "performance", "trending" ] } diff --git a/spec/acceptance/class_spec.rb b/spec/acceptance/class_spec.rb new file mode 100644 index 0000000..7cd8cdf --- /dev/null +++ b/spec/acceptance/class_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper_acceptance' + +describe 'munin and munin-node' do + context 'default parameters' do + # Using puppet_apply as a helper + it 'should work idempotently with no errors' do + pp = <<-EOS + class { 'munin::master': } + class { 'munin::node': } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe package('munin') do + it { is_expected.to be_installed } + end + + describe package('munin-node') do + it { is_expected.to be_installed } + end + + describe service('munin-node') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + end +end diff --git a/spec/acceptance/munin__master_spec.rb b/spec/acceptance/munin__master_spec.rb new file mode 100644 index 0000000..4e045f7 --- /dev/null +++ b/spec/acceptance/munin__master_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper_acceptance' + +describe 'munin::master class' do + context 'default parameters' do + # Using puppet_apply as a helper + it 'should work idempotently with no errors' do + pp = <<-EOS + class { 'munin::master': } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe package('munin') do + it { is_expected.to be_installed } + end + end +end diff --git a/spec/acceptance/munin__node_spec.rb b/spec/acceptance/munin__node_spec.rb new file mode 100644 index 0000000..a338a40 --- /dev/null +++ b/spec/acceptance/munin__node_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper_acceptance' + +describe 'munin::node class' do + context 'default parameters' do + # Using puppet_apply as a helper + it 'should work idempotently with no errors' do + pp = <<-EOS + class { 'munin::node': } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe package('munin-node') do + it { is_expected.to be_installed } + end + + describe service('munin-node') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + end +end diff --git a/spec/acceptance/nodesets/centos-511-x64.yml b/spec/acceptance/nodesets/centos-511-x64.yml new file mode 100644 index 0000000..155926d --- /dev/null +++ b/spec/acceptance/nodesets/centos-511-x64.yml @@ -0,0 +1,12 @@ +HOSTS: + centos-511-x64: + roles: + - master + platform: el-5-x86_64 + box: puppetlabs/centos-5.11-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/centos-5.11-64-nocm + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/centos-66-x64.yml b/spec/acceptance/nodesets/centos-66-x64.yml new file mode 100644 index 0000000..07843d5 --- /dev/null +++ b/spec/acceptance/nodesets/centos-66-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-66-x64: + roles: + - master + platform: el-6-x86_64 + box: puppetlabs/centos-6.6-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/centos-6.6-64-nocm + hypervisor: vagrant +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/centos-7-x64.yml b/spec/acceptance/nodesets/centos-7-x64.yml new file mode 100644 index 0000000..028a1b5 --- /dev/null +++ b/spec/acceptance/nodesets/centos-7-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-7-x64: + roles: + - master + platform: el-7-x86_64 + box: puppetlabs/centos-7.0-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/centos-7.0-64-nocm + hypervisor: vagrant +CONFIG: + log_level: verbose + type: foss \ No newline at end of file diff --git a/spec/acceptance/nodesets/debian-609-x64.yml b/spec/acceptance/nodesets/debian-609-x64.yml new file mode 100644 index 0000000..e2451ea --- /dev/null +++ b/spec/acceptance/nodesets/debian-609-x64.yml @@ -0,0 +1,12 @@ +HOSTS: + debian-609-x64: + roles: + - master + platform: debian-6-amd64 + box: puppetlabs/debian-6.0.9-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/debian-6.0.9-64-nocm + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/debian-78-x64.yml b/spec/acceptance/nodesets/debian-78-x64.yml new file mode 100644 index 0000000..c4062fd --- /dev/null +++ b/spec/acceptance/nodesets/debian-78-x64.yml @@ -0,0 +1,12 @@ +HOSTS: + debian-78-x64: + roles: + - master + platform: debian-7-amd64 + box: puppetlabs/debian-7.8-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/debian-7.8-64-nocm + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/debian-8-x64.yml b/spec/acceptance/nodesets/debian-8-x64.yml new file mode 100644 index 0000000..845be5a --- /dev/null +++ b/spec/acceptance/nodesets/debian-8-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-8-amd64: + roles: + - master + platform: debian-8-amd64 + box: debian/jessie64 + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/default.yml b/spec/acceptance/nodesets/default.yml new file mode 100644 index 0000000..c4062fd --- /dev/null +++ b/spec/acceptance/nodesets/default.yml @@ -0,0 +1,12 @@ +HOSTS: + debian-78-x64: + roles: + - master + platform: debian-7-amd64 + box: puppetlabs/debian-7.8-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/debian-7.8-64-nocm + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/fedora-20-x64.yml b/spec/acceptance/nodesets/fedora-20-x64.yml new file mode 100644 index 0000000..138341f --- /dev/null +++ b/spec/acceptance/nodesets/fedora-20-x64.yml @@ -0,0 +1,12 @@ +HOSTS: + fedora-20-x64: + roles: + - master + platform: el-7-x86_64 + box: chef/fedora-20 + box_url: https://vagrantcloud.com/chef/boxes/fedora-20 + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/acceptance/nodesets/ubuntu-1204-x64.yml b/spec/acceptance/nodesets/ubuntu-1204-x64.yml new file mode 100644 index 0000000..b4e7d55 --- /dev/null +++ b/spec/acceptance/nodesets/ubuntu-1204-x64.yml @@ -0,0 +1,13 @@ +HOSTS: + ubuntu-1204-x64: + roles: + - master + platform: ubuntu-1204-amd64 + box: puppetlabs/ubuntu-12.04-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/ubuntu-12.04-64-nocm + hypervisor: vagrant + +CONFIG: + log_level: verbose + color: false + type: foss diff --git a/spec/acceptance/nodesets/ubuntu-1404-x64.yml b/spec/acceptance/nodesets/ubuntu-1404-x64.yml new file mode 100644 index 0000000..edc1d12 --- /dev/null +++ b/spec/acceptance/nodesets/ubuntu-1404-x64.yml @@ -0,0 +1,12 @@ +HOSTS: + ubuntu-1404-x64: + roles: + - master + platform: ubuntu-1404-amd64 + box: puppetlabs/ubuntu-14.04-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/boxes/ubuntu-14.04-64-nocm + hypervisor: vagrant + +CONFIG: + log_level: verbose + type: foss diff --git a/spec/classes/coverage_spec.rb b/spec/classes/coverage_spec.rb new file mode 100644 index 0000000..12513b8 --- /dev/null +++ b/spec/classes/coverage_spec.rb @@ -0,0 +1 @@ +at_exit { RSpec::Puppet::Coverage.report! } diff --git a/spec/classes/munin_master_spec.rb b/spec/classes/munin_master_spec.rb index a56cb64..0436f4e 100644 --- a/spec/classes/munin_master_spec.rb +++ b/spec/classes/munin_master_spec.rb @@ -1,167 +1,167 @@ require 'spec_helper' _conf_dir = {} _conf_dir.default = '/etc/munin' _conf_dir['Solaris'] = '/opt/local/etc/munin' _conf_dir['FreeBSD'] = '/usr/local/etc/munin' describe 'munin::master' do on_supported_os.each do |os, facts| # Avoid testing on distributions similar to RedHat and Debian next if /^(ubuntu|centos|scientific|oraclelinux)-/.match(os) # No need to test all os versions as long as os version is not # used in the params class next if /^(debian-[67]|redhat-[56]|freebsd-9)-/.match(os) context "on #{os}" do let(:facts) do facts end conf_dir = _conf_dir[facts[:osfamily]] it { should compile.with_all_deps } it { should contain_package('munin') } context 'with default params' do it do should contain_file("#{conf_dir}/munin.conf") .with_content(/graph_strategy\s+cgi/) .with_content(/html_strategy\s+cgi/) end it do should contain_file("#{conf_dir}/munin-conf.d") .with_ensure('directory') end end context 'with html_strategy => cron' do let (:params) { { :html_strategy => 'cron' } } it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/html_strategy\s+cron/) - } + end end context 'with graph_strategy => cron' do let (:params) { { :graph_strategy => 'cron' } } it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/graph_strategy\s+cron/) - } + end end context 'with dbdir => /var/lib/munin' do let (:params) { { :dbdir => '/var/lib/munin' } } it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/dbdir\s+\/var\/lib\/munin/) - } + end end context 'with htmldir => /var/www/munin' do let (:params) { { :htmldir => '/var/www/munin' } } it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/htmldir\s+\/var\/www\/munin/) - } + end end context 'with logdir => /var/log/munin' do let (:params) { { :dbdir => '/var/log/munin' } } it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/dbdir\s+\/var\/log\/munin/) - } + end end context 'with rundir => /var/run/munin' do let (:params) { { :dbdir => '/var/run/munin' } } it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/dbdir\s+\/var\/run\/munin/) - } + end end context 'with tls => enabled' do - let(:params) { + let(:params) do { :tls => 'enabled', :tls_certificate => '/path/to/certificate.pem', :tls_private_key => '/path/to/key.pem', :tls_verify_certificate => 'yes', } - } + end it { should compile.with_all_deps } - it { + it do should contain_file("#{conf_dir}/munin.conf") .with_content(/tls = enabled/) .with_content(/tls_certificate = \/path\/to\/certificate\.pem/) .with_content(/tls_private_key = \/path\/to\/key\.pem/) .with_content(/tls_verify_certificate = yes/) - } + end end context 'with extra_config' do token = '1b7febce-bb2d-4c18-b889-84c73538a900' let(:params) do { :extra_config => [ token ] } end it { should compile.with_all_deps } it do should contain_file("#{conf_dir}/munin.conf") .with_content(/#{token}/) end end context 'with extra_config set to a string' do token = '1b7febce-bb2d-4c18-b889-84c73538a900' let(:params) do { :extra_config => token } end it { should raise_error(Puppet::Error, /is not an Array/) } end ['test.example.com', 'invalid/hostname.example.com'].each do |param| context "with host_name => #{param}" do let(:params) do { :host_name => param } end if param =~ /invalid/ it { should raise_error(Puppet::Error, /valid domain name/) } else it { should compile.with_all_deps } end end end %w( enabled disabled mine unclaimed invalid ).each do |param| context "with collect_nodes => #{param}" do let(:params) do { :collect_nodes => param } end if param == 'invalid' it { should raise_error(Puppet::Error, /validate_re/) } else it { should compile.with_all_deps } end end end end # on os end end diff --git a/spec/classes/munin_node_spec.rb b/spec/classes/munin_node_spec.rb index 2fbac6f..a95669a 100644 --- a/spec/classes/munin_node_spec.rb +++ b/spec/classes/munin_node_spec.rb @@ -1,195 +1,199 @@ require 'spec_helper' _conf_dir = {} _conf_dir.default = '/etc/munin' _conf_dir['DragonFly'] = '/usr/local/etc/munin' _conf_dir['FreeBSD'] = '/usr/local/etc/munin' _conf_dir['Solaris'] = '/opt/local/etc/munin' describe 'munin::node' do on_supported_os.each do |os, facts| # Avoid testing on distributions similar to RedHat and Debian next if /^(ubuntu|centos|scientific|oraclelinux)-/.match(os) # No need to test all os versions as long as os version is not # used in the params class next if /^(debian-[67]|redhat-[56]|freebsd-9)-/.match(os) context "on #{os}" do let(:facts) do facts end it { should compile.with_all_deps } it { should contain_package('munin-node') } munin_confdir = _conf_dir[facts[:osfamily]] munin_node_conf = "#{munin_confdir}/munin-node.conf" munin_plugin_dir = "#{munin_confdir}/plugins" munin_plugin_conf_dir = "#{munin_confdir}/plugin-conf.d" case facts[:osfamily] when 'Solaris' munin_node_service = 'smf:/munin-node' else munin_node_service = 'munin-node' end case facts[:osfamily] when 'Solaris' log_dir = '/var/opt/log/munin' when 'RedHat' log_dir = '/var/log/munin-node' else log_dir = '/var/log/munin' end it { should contain_service(munin_node_service) } it { should contain_file(munin_node_conf) } context 'with no parameters' do it { should compile.with_all_deps } it do should contain_service(munin_node_service) .without_ensure() end it do should contain_file(munin_node_conf) .with_content(/host_name\s+foo.example.com/) .with_content(/log_file\s+#{log_dir}\/munin-node.log/) end end context 'with parameter allow' do let(:params) do { allow: ['2001:db8:1::', '2001:db8:2::/64', '192.0.2.129', '192.0.2.0/25', '192\.0\.2'] } end it { should compile.with_all_deps } it do should contain_file(munin_node_conf) .with_content(/^cidr_allow 192.0.2.0\/25$/) .with_content(/^cidr_allow 2001:db8:2::\/64$/) .with_content(/^allow \^192\\.0\\.2\\.129\$$/) .with_content(/^allow 192\\.0\\.2$/) .with_content(/^allow \^2001:db8:1::\$$/) end end context 'with parameter host_name' do let(:params) do { host_name: 'something.example.com' } end it { should compile.with_all_deps } it do should contain_file(munin_node_conf) .with_content(/host_name\s+something.example.com/) end end context 'with parameter service_ensure' do let(:params) do { service_ensure: 'running' } end it { should compile.with_all_deps } it do should contain_service('munin-node') .with_ensure('running') end end context 'logging to syslog' do context 'defaults' do let(:params) do { log_destination: 'syslog' } end it{ should compile.with_all_deps } it do should contain_file(munin_node_conf) .with_content(/log_file\s+Sys::Syslog/) end end context 'with syslog options' do let(:params) do { log_destination: 'syslog', syslog_facility: 'local1', } end it{ should compile.with_all_deps } it do should contain_file(munin_node_conf) .with_content(/log_file\s+Sys::Syslog/) .with_content(/syslog_facility\s+local1/) end end context 'with syslog_facility set to wrong value ' do let(:params) do { log_destination: 'syslog', syslog_facility: 'wrong', } end it { expect { should compile.with_all_deps }.to raise_error(/validate_re/) } end end context 'purge_configs' do context 'set' do let(:params) { { purge_configs: true } } it { should compile.with_all_deps } - it do should contain_file(munin_plugin_dir) - .with_ensure('directory') - .with_recurse(true) - .with_purge(true) + it do + should contain_file(munin_plugin_dir) + .with_ensure('directory') + .with_recurse(true) + .with_purge(true) end - it do should contain_file(munin_plugin_conf_dir) - .with_ensure('directory') - .with_recurse(true) - .with_purge(true) + it do + should contain_file(munin_plugin_conf_dir) + .with_ensure('directory') + .with_recurse(true) + .with_purge(true) end end context 'unset' do it { should compile.with_all_deps } it { should_not contain_file(munin_plugin_dir) } it { should_not contain_file(munin_plugin_conf_dir) } end end context 'timeout' do context 'set' do let(:params) { { timeout: 123 } } it { should compile.with_all_deps } - it do should contain_file(munin_node_conf) - .with_content(/^timeout 123/) + it do + should contain_file(munin_node_conf) + .with_content(/^timeout 123/) end end context 'unset' do it { should compile.with_all_deps } - it do should contain_file(munin_node_conf) - .without_content(/^timeout/) + it do + should contain_file(munin_node_conf) + .without_content(/^timeout/) end end end end end context 'unsupported' do include_context :unsupported - it { - expect { + it do + expect do should contain_class('munin::node') - }.to raise_error(Puppet::Error, /Unsupported osfamily/) - } + end.to raise_error(Puppet::Error, /Unsupported osfamily/) + end end end diff --git a/spec/defines/munin_plugin_spec.rb b/spec/defines/munin_plugin_spec.rb index dbf36da..f38ce96 100644 --- a/spec/defines/munin_plugin_spec.rb +++ b/spec/defines/munin_plugin_spec.rb @@ -1,143 +1,143 @@ require 'spec_helper' _conf_dir = {} _conf_dir.default = '/etc/munin' _conf_dir['Solaris'] = '/opt/local/etc/munin' _conf_dir['FreeBSD'] = '/usr/local/etc/munin' _share_dir = {} _share_dir.default = '/usr/share/munin' _share_dir['Solaris'] = '/opt/local/share/munin' _share_dir['FreeBSD'] = '/usr/local/share/munin' describe 'munin::plugin', :type => 'define' do let(:title) { 'testplugin' } on_supported_os.each do |os, facts| # Avoid testing on distributions similar to RedHat and Debian next if /^(ubuntu|centos|scientific|oraclelinux)-/.match(os) # No need to test all os versions as long as os version is not # used in the params class next if /^(debian-[67]|redhat-[56]|freebsd-9)-/.match(os) context "on #{os}" do let(:facts) do facts end conf_dir = _conf_dir[facts[:osfamily]] plugin_share_dir = "#{_share_dir[facts[:osfamily]]}/plugins" context 'with no parameters' do it do expect { should contain_file("#{conf_dir}/plugins/testplugin") } .to raise_error("expected that the catalogue would contain File[#{conf_dir}/plugins/testplugin]") end it do should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") .with_ensure('absent') end end context 'with ensure=link parameter' do let(:params) { { :ensure => 'link' } } it do should contain_file("#{conf_dir}/plugins/testplugin") .with_ensure('link') .with_target("#{plugin_share_dir}/testplugin") end it do should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") .with_ensure('absent') end end context 'with ensure=link and target parameters' do - let (:title) { 'test_foo' } - let (:params) do + let(:title) { 'test_foo' } + let(:params) do { :ensure => 'link', :target => 'test_' } end it do should contain_file("#{conf_dir}/plugins/test_foo") .with_ensure('link') .with_target("#{plugin_share_dir}/test_") end it do should contain_file("#{conf_dir}/plugin-conf.d/test_foo.conf") .with_ensure('absent') end end context 'with ensure=present and source parameters' do let(:params) do { :ensure => 'present', :source => 'puppet:///modules/munin/plugins/testplugin' } end it do should contain_file("#{conf_dir}/plugins/testplugin") .with_ensure('present') .with_source('puppet:///modules/munin/plugins/testplugin') end it do should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") .with_ensure('absent') end end context 'with ensure=present, source and config parameters' do let(:params) do { :ensure => 'present', :source => 'puppet:///modules/munin/plugins/testplugin', :config => [ 'something wonderful' ], } end it do should contain_file("#{conf_dir}/plugins/testplugin") .with_ensure('present') .with_source('puppet:///modules/munin/plugins/testplugin') end it do should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") .with_ensure('present') .with_content(/something wonderful/) end end context 'only configuration' do - let (:params) do + let(:params) do { :config => ['env.rootdn cn=admin,dc=example,dc=org'], :config_label => 'slapd_*', } end it do should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") .with_ensure('present') .with_content(/env.rootdn/) end it do expect { should contain_file("#{conf_dir}/plugins/testplugin") } .to raise_error("expected that the catalogue would contain File[#{conf_dir}/plugins/testplugin]") end end context 'with absolute target' do let(:params) do { ensure: 'link', target: '/full/path/to/testplugin' } end it do should contain_file("#{conf_dir}/plugins/testplugin") .with_ensure('link') .with_target('/full/path/to/testplugin') end end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index bc2982e..23d3e29 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,11 +1,20 @@ require 'puppetlabs_spec_helper/module_spec_helper' require 'rspec-puppet-facts' + include RspecPuppetFacts -RSpec.configure do |c| - c.fail_fast = true +require 'simplecov' +require 'simplecov-console' + +SimpleCov.start do + add_filter '/spec' + add_filter '/vendor' + formatter SimpleCov::Formatter::MultiFormatter.new([ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::Console + ]) end shared_context :unsupported do let(:facts) { { osfamily: 'Unsupported' } } end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb new file mode 100644 index 0000000..538b7a3 --- /dev/null +++ b/spec/spec_helper_acceptance.rb @@ -0,0 +1,22 @@ +require 'beaker-rspec/spec_helper' +require 'beaker-rspec/helpers/serverspec' +require 'beaker/puppet_install_helper' + +run_puppet_install_helper unless ENV['BEAKER_provision'] == 'no' + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Readable test descriptions + c.formatter = :documentation + + # Configure all nodes in nodeset + c.before :suite do + # Install module and dependencies + puppet_module_install(:source => proj_root, :module_name => 'munin') + hosts.each do |host| + on host, puppet('module', 'install', 'puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] } + end + end +end diff --git a/templates/munin-node.conf.erb b/templates/munin-node.conf.erb index 3e076b4..d059b38 100644 --- a/templates/munin-node.conf.erb +++ b/templates/munin-node.conf.erb @@ -1,69 +1,77 @@ # /etc/munin/munin-node.conf - config-file for munin-node # # This file is handled by puppet, any local changes will be lost # <% require 'ipaddr' addresses = [] unrecognized = [] + rescuable_exceptions = [ ArgumentError ] + + if defined?(IPAddr::InvalidAddressError) + rescuable_exceptions << IPAddr::InvalidAddressError + end + Array(@allow).flatten.each do |line| begin a = IPAddr.new(line) if a.ipv4? or a.ipv6? addresses << line end - rescue ArgumentError, IPAddr::InvalidAddressError + rescue *rescuable_exceptions # Treat invalid addresses as "allow" arguments, as they can be # regular expressions. unrecognized << line end end -%> host_name <%= @host_name %> log_level 4 log_file <%= @_log_file %> <% if @log_destination == 'syslog' -%> <% if @syslog_facility -%> syslog_facility <%= @syslog_facility %> <% end -%> <% end -%> -port 4949 pid_file /var/run/munin/munin-node.pid background 1 setsid 1 -# Which port to bind to; +# Which port and address to bind to; +host <%= @bind_address %> +port <%= @bind_port %> + user root group <%= @file_group %> # Regexps for files to ignore ignore_file ~$ ignore_file \.bak$ ignore_file %$ ignore_file \.dpkg-(tmp|new|old|dist)$ ignore_file \.rpm(save|new)$ ignore_file \.puppet-bak$ # Hosts to allow <% addresses.each do |line| -%> <% if line.match(/\//) -%> cidr_allow <%= line %> <% else -%> allow ^<%= Regexp.quote(line) %>$ <% end -%> <% end -%> <% unrecognized.each do |line| -%> allow <%= line %> <% end -%> <% if @timeout -%> timeout <%= @timeout %> <% end -%> <% Array(@nodeconfig).each do |line| -%> <%= line %> <% end -%>