diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9032a01 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +*.rb eol=lf +*.erb eol=lf +*.pp eol=lf +*.sh eol=lf +*.epp eol=lf diff --git a/.gitignore b/.gitignore index 6dfe023..650022e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,24 @@ -.*.sw? -/pkg -/spec/fixtures -/.rspec_system -/.vagrant -/.bundle -/vendor -/Gemfile.lock -/junit -/log +.git/ +.*.sw[op] +.metadata .yardoc -coverage +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +/update_report.txt +.DS_Store diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..ea59806 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,42 @@ +--- +stages: + - syntax + - unit + +cache: + paths: + - vendor/bundle + +before_script: + - bundle -v + - rm Gemfile.lock || true + - gem update --system $RUBYGEMS_VERSION + - gem --version + - bundle -v + - bundle install --without system_tests --path vendor/bundle --jobs $(nproc) + +parallel_spec-Ruby 2.1.9-Puppet ~> 4.0: + stage: unit + image: ruby:2.1.9 + script: + - bundle exec rake parallel_spec + variables: + PUPPET_GEM_VERSION: '~> 4.0' + RUBYGEMS_VERSION: '2.7.8' + +syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop-Ruby 2.4.4-Puppet ~> 5.5: + stage: syntax + image: ruby:2.4.4 + script: + - bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop + variables: + PUPPET_GEM_VERSION: '~> 5.5' + +parallel_spec-Ruby 2.4.4-Puppet ~> 5.5: + stage: unit + image: ruby:2.4.4 + script: + - bundle exec rake parallel_spec + variables: + PUPPET_GEM_VERSION: '~> 5.5' + diff --git a/.pdkignore b/.pdkignore new file mode 100644 index 0000000..b713b3b --- /dev/null +++ b/.pdkignore @@ -0,0 +1,37 @@ +.git/ +.*.sw[op] +.metadata +.yardoc +.yardwarns +*.iml +/.bundle/ +/.idea/ +/.vagrant/ +/coverage/ +/bin/ +/doc/ +/Gemfile.local +/Gemfile.lock +/junit/ +/log/ +/pkg/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/tmp/ +/vendor/ +/convert_report.txt +/update_report.txt +.DS_Store +/appveyor.yml +/.fixtures.yml +/Gemfile +/.gitattributes +/.gitignore +/.gitlab-ci.yml +/.pdkignore +/Rakefile +/.rspec +/.rubocop.yml +/.travis.yml +/.yardopts +/spec/ diff --git a/.puppet-lint.rc b/.puppet-lint.rc new file mode 100644 index 0000000..cc96ece --- /dev/null +++ b/.puppet-lint.rc @@ -0,0 +1 @@ +--relative diff --git a/.rspec b/.rspec index 4cd92bf..16f9cdb 100644 --- a/.rspec +++ b/.rspec @@ -1,3 +1,2 @@ ---format documentation --color ---fail-fast +--format documentation diff --git a/.rubocop.yml b/.rubocop.yml index daa9538..f5a6c2a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,486 +1,122 @@ +--- +require: rubocop-rspec AllCops: + DisplayCopNames: true + TargetRubyVersion: '2.1' + Include: + - "./**/*.rb" 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: + - bin/* + - ".vendor/**/*" + - "**/Gemfile" + - "**/Rakefile" + - pkg/**/* + - spec/fixtures/**/* + - vendor/**/* + - "**/Puppetfile" + - "**/Vagrantfile" + - "**/Guardfile" +Metrics/LineLength: + Description: People have wide screens, use them. + Max: 200 +GetText/DecorateString: + Description: We don't want to decorate test output. + Exclude: + - spec/* +RSpec/BeforeAfterAll: + Description: Beware of using after(:all) as it may cause state to leak between tests. + A necessary evil in acceptance testing. + Exclude: + - spec/acceptance/**/*.rb +RSpec/HookArgument: + Description: Prefer explicit :each argument, matching existing module's style + EnforcedStyle: each +Style/BlockDelimiters: + Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to + be consistent then. + EnforcedStyle: braces_for_chaining +Style/ClassAndModuleChildren: + Description: Compact style reduces the required amount of indentation. + EnforcedStyle: compact +Style/EmptyElse: + Description: Enforce against empty else clauses, but allow `nil` for clarity. + EnforcedStyle: empty +Style/FormatString: + Description: Following the main puppet project's style, prefer the % format format. + EnforcedStyle: percent +Style/FormatStringToken: + Description: Following the main puppet project's style, prefer the simpler template + tokens over annotated ones. + EnforcedStyle: template +Style/Lambda: + Description: Prefer the keyword for easier discoverability. + EnforcedStyle: literal +Style/RegexpLiteral: + Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 + EnforcedStyle: percent_r +Style/TernaryParentheses: + Description: Checks for use of parentheses around ternary conditions. Enforce parentheses + on complex expressions for better readability, but seriously consider breaking + it up. + EnforcedStyle: require_parentheses_when_complex +Style/TrailingCommaInArguments: + Description: Prefer always trailing comma on multiline argument lists. This makes + diffs, and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/TrailingCommaInLiteral: + Description: Prefer always trailing comma on multiline literals. This makes diffs, + and re-ordering nicer. + EnforcedStyleForMultiline: comma +Style/SymbolArray: + Description: Using percent style obscures symbolic intent of array's contents. + EnforcedStyle: brackets +RSpec/MessageSpies: + EnforcedStyle: receive +Style/Documentation: + Exclude: + - lib/puppet/parser/functions/**/* + - spec/**/* +Style/WordArray: + EnforcedStyle: brackets +Style/CollectionMethods: Enabled: true - -Lint/UselessAssignment: +Style/MethodCalledOnDoEndBlock: Enabled: true - -Lint/Void: +Style/StringMethods: 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: +Layout/EndOfLine: Enabled: false - -Style/Attr: +Layout/IndentHeredoc: Enabled: false - -Style/BracesAroundHashParameters: +Metrics/AbcSize: Enabled: false - -Style/CaseEquality: +Metrics/BlockLength: 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: +Metrics/MethodLength: Enabled: false - -Metrics/LineLength: +Metrics/ModuleLength: Enabled: false - -Style/MethodCallParentheses: +Metrics/ParameterLists: Enabled: false - -Style/MethodDefParentheses: +Metrics/PerceivedComplexity: Enabled: false - -Style/LineEndConcatenation: +RSpec/DescribeClass: Enabled: false - -Style/TrailingWhitespace: +RSpec/ExampleLength: Enabled: false - -Style/StringLiterals: +RSpec/MessageExpectation: Enabled: false - -Style/TrailingComma: +RSpec/MultipleExpectations: Enabled: false - -Style/GlobalVars: +RSpec/NestedGroups: Enabled: false - -Style/GuardClause: +Style/AsciiComments: 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: +Style/SymbolProc: Enabled: false diff --git a/.travis.yml b/.travis.yml index 8d0faa7..521510d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,38 +1,43 @@ --- +dist: trusty language: ruby -bundler_args: --without development system_tests -before_install: rm Gemfile.lock || true +cache: bundler +before_install: + - bundle -v + - rm -f Gemfile.lock + - gem update --system $RUBYGEMS_VERSION + - gem --version + - bundle -v +script: + - 'bundle exec rake $CHECK' +bundler_args: --without system_tests rvm: - - 1.8.7 - - 1.9.3 - - 2.0.0 - - 2.1.0 -script: bundle exec rake test + - 2.5.1 env: - - 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 + global: + - BEAKER_PUPPET_COLLECTION=puppet6 PUPPET_GEM_VERSION="~> 6.0" matrix: - exclude: - # 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" + fast_finish: true + include: + - + env: CHECK="syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop" + - + env: CHECK=parallel_spec + - + env: PUPPET_GEM_VERSION="~> 5.0" CHECK=parallel_spec + rvm: 2.4.4 +branches: + only: + - master + - /^v\d/ +notifications: + email: false +deploy: + provider: puppetforge + user: puppet + password: + secure: "" + on: + tags: true + all_branches: true + condition: "$DEPLOY_TO_FORGE = yes" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c56485..aa6e5a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,189 +1,215 @@ # Changelog +All notable changes to this project will be documented in this file. -## 0.1.0 - 2015-12-12 +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Added +- Support for DragonFly BSD (Thanks: Zach Crownover) +- Support for FreeBSD as master (Thanks: Zach Crownover) +- Export additional nodes with `munin::node::export::node_definitions` + if `munin::node::export_node` is enabled. (Thanks: Kjetil Torgrim Homme) +- New parameter `munin::master::package_name` +- New parameter `munin::master::file_group` +- New parameter `munin::master::config_root` + +### Changed +- Support puppet 4. (Thanks: Kjetil Torgrim Homme) +- Scaffolding updated with PDK 1.9.0 + +### Fixed +- Support for Arch Linux (Thanks: Kjetil Torgrim Homme) +- Fixed bug with parameter `munin::master::node_definitions` + +### Deprecated +- Module is no longer tested with Puppet 3.x and 2.x +- Module is no longer tested on Ruby < 2.1.9 + +## [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 +## [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 +## [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 +## [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 +## [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 +## [0.0.6] - 2014-12-05 * Retracted, had a breaking bug on older (3.4.x) puppet versions. -## 0.0.5 - 2014-03-19 +## [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 +## [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 +## [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 +## [0.0.1] - 2013-06-02 Initial release diff --git a/Gemfile b/Gemfile index ca3fd4e..cf2c387 100644 --- a/Gemfile +++ b/Gemfile @@ -1,33 +1,71 @@ -source "https://rubygems.org" - -group :test do - 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" +source ENV['GEM_SOURCE'] || 'https://rubygems.org' + +def location_for(place_or_version, fake_version = nil) + git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} + file_url_regex = %r{\Afile:\/\/(?.*)} + + if place_or_version && (git_url = place_or_version.match(git_url_regex)) + [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact + elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) + ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] + else + [place_or_version, { require: false }] + end end +ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments +minor_version = ruby_version_segments[0..1].join('.') + group :development do - gem "travis" - gem "travis-lint" - gem "guard-rake" + gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') + gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') + gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') + gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "puppet-module-posix-default-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-posix-dev-r#{minor_version}", require: false, platforms: [:ruby] + gem "puppet-module-win-default-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-win-dev-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] end -group :system_tests do - gem "beaker" - gem "beaker-rspec" - gem "beaker-puppet_install_helper" +puppet_version = ENV['PUPPET_GEM_VERSION'] +facter_version = ENV['FACTER_GEM_VERSION'] +hiera_version = ENV['HIERA_GEM_VERSION'] + +gems = {} + +gems['puppet'] = location_for(puppet_version) + +# If facter or hiera versions have been specified via the environment +# variables + +gems['facter'] = location_for(facter_version) if facter_version +gems['hiera'] = location_for(hiera_version) if hiera_version + +if Gem.win_platform? && puppet_version =~ %r{^(file:///|git://)} + # If we're using a Puppet gem on Windows which handles its own win32-xxx gem + # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). + gems['win32-dir'] = ['<= 0.4.9', require: false] + gems['win32-eventlog'] = ['<= 0.6.5', require: false] + gems['win32-process'] = ['<= 0.7.5', require: false] + gems['win32-security'] = ['<= 0.2.5', require: false] + gems['win32-service'] = ['0.8.8', require: false] +end + +gems.each do |gem_name, gem_params| + gem gem_name, *gem_params +end + +# Evaluate Gemfile.local and ~/.gemfile if they exist +extra_gemfiles = [ + "#{__FILE__}.local", + File.join(Dir.home, '.gemfile'), +] + +extra_gemfiles.each do |gemfile| + if File.file?(gemfile) && File.readable?(gemfile) + eval(File.read(gemfile), binding) + end end +# vim: syntax=ruby diff --git a/Guardfile b/Guardfile deleted file mode 100644 index fd50602..0000000 --- a/Guardfile +++ /dev/null @@ -1,5 +0,0 @@ -notification :off - -guard 'rake', :task => 'test' do - watch(%r{^manifests\/(.+)\.pp$}) -end diff --git a/README.md b/README.md index cde6b12..81c6b84 100644 --- a/README.md +++ b/README.md @@ -1,457 +1,466 @@ # 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** - [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 # Configure munin master, node and plugins. # 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. + Defaults to the $::fqdn fact. * **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) +### Export extra nodes ### + +If **munin::node::export_node** is enabled, you may export additional +nodes with the **munin::node::export::node_definitions** hash. These +are exported as **munin::master::node_definition** resources. They will +be associated with the same mastername as the node itself. ## munin::master ## Typical usage: include munin::master 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) * **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. Parameters -* **address**: The address of the munin node. A hostname, an IP -address, or a ssh:// uri for munin-async node. (**required**, no -default) +* **address**: The address of the munin node. A hostname, an IPv4 +address, an IPv6 address in brackets, or a ssh:// uri for munin-async +node. (**required**, no default) * **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: munin::master::node_definition { 'fqn': address => $address, mastername => 'munin.example.com', } ## 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: +For extra nodes, you can define them in hiera data for the master +server, 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' ], } +See also **munin::node::export::node_definitions** for extra nodes +declared on the clients. ### 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 ### 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 ## ### 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. ## munin::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 ### 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 ### 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 ### 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 ### 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 8ac719e..a6b14c5 100644 --- a/Rakefile +++ b/Rakefile @@ -1,62 +1,76 @@ -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' +require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any? +require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any? +require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any? -# These gems aren't always present, for instance -# on Travis with --without development -begin -rescue LoadError # rubocop:disable Lint/HandleExceptions +def changelog_user + return unless Rake.application.top_level_tasks.include? "changelog" + returnVal = nil || JSON.load(File.read('metadata.json'))['author'] + raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil? + puts "GitHubChangelogGenerator user:#{returnVal}" + returnVal end -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.disable_80chars -PuppetLint.configuration.disable_class_inherits_from_params_class -PuppetLint.configuration.disable_class_parameter_defaults -PuppetLint.configuration.fail_on_warnings = true - -PuppetLint::RakeTask.new :lint do |config| - config.ignore_paths = exclude_paths +def changelog_project + return unless Rake.application.top_level_tasks.include? "changelog" + returnVal = nil || JSON.load(File.read('metadata.json'))['name'] + raise "unable to find the changelog_project in .sync.yml or the name in metadata.json" if returnVal.nil? + puts "GitHubChangelogGenerator project:#{returnVal}" + returnVal end -PuppetSyntax.exclude_paths = exclude_paths - -desc "Run acceptance tests" -RSpec::Core::RakeTask.new(:acceptance) do |t| - t.pattern = 'spec/acceptance' +def changelog_future_release + return unless Rake.application.top_level_tasks.include? "changelog" + returnVal = JSON.load(File.read('metadata.json'))['version'] + raise "unable to find the future_release (version) in metadata.json" if returnVal.nil? + puts "GitHubChangelogGenerator future_release:#{returnVal}" + returnVal end -desc "Populate CONTRIBUTORS file" -task :contributors do - system("git log --format='%aN' | sort -u > CONTRIBUTORS") +PuppetLint.configuration.send('disable_relative') + +if Bundler.rubygems.find_name('github_changelog_generator').any? + GitHubChangelogGenerator::RakeTask.new :changelog do |config| + raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil? + config.user = "#{changelog_user}" + config.project = "#{changelog_project}" + config.future_release = "#{changelog_future_release}" + config.exclude_labels = ['maintenance'] + config.header = "# Change log\n\nAll notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org)." + config.add_pr_wo_labels = true + config.issues = false + config.merge_prefix = "### UNCATEGORIZED PRS; GO LABEL THEM" + config.configure_sections = { + "Changed" => { + "prefix" => "### Changed", + "labels" => ["backwards-incompatible"], + }, + "Added" => { + "prefix" => "### Added", + "labels" => ["feature", "enhancement"], + }, + "Fixed" => { + "prefix" => "### Fixed", + "labels" => ["bugfix"], + }, + } + end +else + desc 'Generate a Changelog from GitHub' + task :changelog do + raise <= Gem::Version.new('2.2.2')" +EOM + end end -desc "Run syntax, lint, and spec tests." -task :test => [ - :metadata_lint, - :syntax, - :lint, - :rubocop, - :spec, -] diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..e10ba3b --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,55 @@ +--- +version: 1.1.x.{build} +branches: + only: + - master +skip_commits: + message: /^\(?doc\)?.*/ +clone_depth: 10 +init: + - SET + - 'mkdir C:\ProgramData\PuppetLabs\code && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\facter && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\hiera && exit 0' + - 'mkdir C:\ProgramData\PuppetLabs\puppet\var && exit 0' +environment: + matrix: + - + RUBY_VERSION: 24-x64 + CHECK: syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop + - + PUPPET_GEM_VERSION: ~> 5.0 + RUBY_VERSION: 24 + CHECK: parallel_spec + - + PUPPET_GEM_VERSION: ~> 5.0 + RUBY_VERSION: 24-x64 + CHECK: parallel_spec + - + PUPPET_GEM_VERSION: ~> 6.0 + RUBY_VERSION: 25 + CHECK: parallel_spec + - + PUPPET_GEM_VERSION: ~> 6.0 + RUBY_VERSION: 25-x64 + CHECK: parallel_spec +matrix: + fast_finish: true +install: + - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% + - bundle install --jobs 4 --retry 2 --without system_tests + - type Gemfile.lock +build: off +test_script: + - bundle exec puppet -V + - ruby -v + - gem -v + - bundle -v + - bundle exec rake %CHECK% +notifications: + - provider: Email + to: + - nobody@nowhere.com + on_build_success: false + on_build_failure: false + on_build_status_changed: false diff --git a/manifests/master.pp b/manifests/master.pp index 734228c..d8cd02c 100644 --- a/manifests/master.pp +++ b/manifests/master.pp @@ -1,135 +1,141 @@ # 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, + $node_definitions = $munin::params::master::node_definitions, $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, + $file_group = $munin::params::master::file_group, + $package_name = $munin::params::master::package_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) { fail('host_name should be a valid domain name') } } + validate_string($file_group) + + validate_string($package_name) + validate_array($extra_config) # The munin package and configuration - package { 'munin': + package { $package_name: ensure => latest, } File { owner => 'root', - group => 'root', + group => $file_group, mode => '0644', - require => Package['munin'], + require => Package[$package_name], } 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': 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 cc1d582..088fa0f 100644 --- a/manifests/master/node_definition.pp +++ b/manifests/master/node_definition.pp @@ -1,35 +1,42 @@ # 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=[], ) { + + include ::munin::params::master + + $config_root = $munin::params::master::config_root + validate_string($address) validate_array($config) + validate_string($config_root) - $filename=sprintf('/etc/munin/munin-conf.d/node.%s.conf', + $filename=sprintf('%s/munin-conf.d/node.%s.conf', + $config_root, regsubst($name, '[^[:alnum:]\.]', '_', 'IG')) file { $filename: content => template('munin/master/node.definition.conf.erb'), } } diff --git a/manifests/node/export.pp b/manifests/node/export.pp index 49130fa..f0c7ce0 100644 --- a/manifests/node/export.pp +++ b/manifests/node/export.pp @@ -1,19 +1,25 @@ # Class to export the munin node. # # This is separated into its own class to avoid warnings about missing # storeconfigs. # class munin::node::export ( $address, $fqn, $masterconfig, $mastername, + $node_definitions = {}, ) { - @@munin::master::node_definition{ $fqn: - address => $address, + Munin::Master::Node_definition { mastername => $mastername, - config => $masterconfig, - tag => [ "munin::master::${mastername}" ], + tag => "munin::master::${mastername}", + } + @@munin::master::node_definition{ $fqn: + address => $address, + config => $masterconfig, + } + if ! empty($node_definitions) { + create_resources('@@munin::master::node_definition', $node_definitions) } } diff --git a/manifests/params/master.pp b/manifests/params/master.pp index ab5322b..747f55b 100644 --- a/manifests/params/master.pp +++ b/manifests/params/master.pp @@ -1,37 +1,43 @@ # 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 = '' + $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' + $config_root = '/etc/munin' + $file_group = 'root' + $package_name = 'munin' } 'Solaris': { - $config_root = '/opt/local/etc/munin' + $config_root = '/opt/local/etc/munin' + $file_group = 'root' + $package_name = 'munin' } - 'FreeBSD': { - $config_root = '/usr/local/etc/munin' + 'DragonFly', 'FreeBSD': { + $config_root = '/usr/local/etc/munin' + $file_group = 'wheel' + $package_name = 'munin-master' } default: { fail($message) } } } diff --git a/manifests/params/node.pp b/manifests/params/node.pp index 729ad97..b273409 100644 --- a/manifests/params/node.pp +++ b/manifests/params/node.pp @@ -1,80 +1,85 @@ # 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', + 'Archlinux': { + $config_root = '/etc/munin' + $log_dir = '/var/log/munin' + $service_name = 'munin-node' + $package_name = 'munin-node' + $plugin_share_dir = '/usr/lib/munin/plugins' + $file_group = 'root' + } '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 1b5b66e..091385e 100644 --- a/manifests/plugin.pp +++ b/manifests/plugin.pp @@ -1,92 +1,89 @@ # 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 $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': { + 'present', 'absent': { $handle_plugin = true - $plugin_ensure = 'present' - } - 'absent': { - $handle_plugin = true - $plugin_ensure = 'absent' + $plugin_ensure = $ensure + $plugin_target = undef } '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, 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 260186a..d17b365 100644 --- a/metadata.json +++ b/metadata.json @@ -1,66 +1,104 @@ { "name": "ssm-munin", "version": "0.1.0", "author": "ssm", - "license": "Apache-2.0", "summary": "Configure munin master, node and plugins", + "license": "Apache-2.0", "source": "https://github.com/ssm/ssm-munin", + "project_page": "https://github.com/ssm/ssm-munin", + "issues_url": "https://github.com/ssm/ssm-munin/issues", "dependencies": [ { "name": "puppetlabs/stdlib", - "version_requirement": ">= 2.3.0" + "version_requirement": ">= 2.3.0 < 6.0.0" } ], - "project_page": "https://github.com/ssm/ssm-munin", - "issues_url": "https://github.com/ssm/ssm-munin/issues", "operatingsystem_support": [ { "operatingsystem": "Archlinux", - "operatingsystemrelease": [ "4" ] + "operatingsystemrelease": [ + "4" + ] }, { "operatingsystem": "CentOS", - "operatingsystemrelease": [ "5", "6", "7" ] + "operatingsystemrelease": [ + "5", + "6", + "7" + ] }, { "operatingsystem": "Debian", - "operatingsystemrelease": [ "6", "7", "8" ] + "operatingsystemrelease": [ + "6", + "7", + "8" + ] }, { "operatingsystem": "OracleLinux", - "operatingsystemrelease": [ "5", "6", "7" ] + "operatingsystemrelease": [ + "5", + "6", + "7" + ] }, { "operatingsystem": "RedHat", - "operatingsystemrelease": [ "5", "6", "7" ] + "operatingsystemrelease": [ + "5", + "6", + "7" + ] }, { "operatingsystem": "Scientific", - "operatingsystemrelease": [ "5", "6", "7" ] + "operatingsystemrelease": [ + "5", + "6", + "7" + ] }, { "operatingsystem": "SmartOS" }, { "operatingsystem": "Ubuntu", - "operatingsystemrelease": [ "10.04", "12.04", "14.04" ] + "operatingsystemrelease": [ + "10.04", + "12.04", + "14.04" + ] }, { "operatingsystem": "FreeBSD", - "operatingsystemrelease": [ "9", "10" ] + "operatingsystemrelease": [ + "9", + "10" + ] }, { "operatingsystem": "DragonFly" }, { "operatingsystem": "OpenBSD" } ], + "requirements": [ + { + "name": "puppet", + "version_requirement": ">= 4.7.0 < 6.0.0" + } + ], "tags": [ "munin", "monitoring", "graphing", "performance", "trending" - ] -} + ], + "pdk-version": "1.9.0", + "template-url": "file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git", + "template-ref": "1.9.0-0-g7281db5" +} \ No newline at end of file diff --git a/spec/acceptance/class_spec.rb b/spec/acceptance/class_spec.rb index 7cd8cdf..0ef9c4c 100644 --- a/spec/acceptance/class_spec.rb +++ b/spec/acceptance/class_spec.rb @@ -1,30 +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 + it 'works idempotently with no errors' do + pp = <<-PUPPET_CODE class { 'munin::master': } class { 'munin::node': } - EOS + PUPPET_CODE # Run it twice and test for idempotency - apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) + 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 index 4e045f7..082abf4 100644 --- a/spec/acceptance/munin__master_spec.rb +++ b/spec/acceptance/munin__master_spec.rb @@ -1,20 +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 + it 'works idempotently with no errors' do + pp = <<-PUPPET_CODE class { 'munin::master': } - EOS + PUPPET_CODE # Run it twice and test for idempotency - apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) + 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 index a338a40..5cab9b2 100644 --- a/spec/acceptance/munin__node_spec.rb +++ b/spec/acceptance/munin__node_spec.rb @@ -1,25 +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 + it 'works idempotently with no errors' do + pp = <<-PUPPET_CODE class { 'munin::node': } - EOS + PUPPET_CODE # Run it twice and test for idempotency - apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) + 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/classes/munin_master_spec.rb b/spec/classes/munin_master_spec.rb index 0436f4e..fc892a0 100644 --- a/spec/classes/munin_master_spec.rb +++ b/spec/classes/munin_master_spec.rb @@ -1,167 +1,196 @@ require 'spec_helper' -_conf_dir = {} -_conf_dir.default = '/etc/munin' -_conf_dir['Solaris'] = '/opt/local/etc/munin' -_conf_dir['FreeBSD'] = '/usr/local/etc/munin' +t_conf_dir = {} +t_conf_dir.default = '/etc/munin' +t_conf_dir['Solaris'] = '/opt/local/etc/munin' +t_conf_dir['FreeBSD'] = '/usr/local/etc/munin' -describe 'munin::master' do +t_package = {} +t_package.default = 'munin' +t_package['FreeBSD'] = 'munin-master' +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) + next if os =~ %r{^(ubuntu|centos|scientific|oraclelinux)-} # 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) + next if os =~ %r{^(debian-[67]|redhat-[56]|freebsd-9)-} context "on #{os}" do let(:facts) do facts end - conf_dir = _conf_dir[facts[:osfamily]] + conf_dir = t_conf_dir[facts[:osfamily]] + package = t_package[facts[:osfamily]] - it { should compile.with_all_deps } + it { is_expected.to compile.with_all_deps } - it { should contain_package('munin') } + it { is_expected.to contain_package(package) } 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/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{graph_strategy\s+cgi}) + .with_content(%r{html_strategy\s+cgi}) end it do - should contain_file("#{conf_dir}/munin-conf.d") - .with_ensure('directory') + is_expected.to 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 } + let(:params) { { html_strategy: 'cron' } } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/html_strategy\s+cron/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{html_strategy\s+cron}) end end context 'with graph_strategy => cron' do - let (:params) { { :graph_strategy => 'cron' } } - it { should compile.with_all_deps } + let(:params) { { graph_strategy: 'cron' } } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/graph_strategy\s+cron/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{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 } + let(:params) { { dbdir: '/var/lib/munin' } } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/dbdir\s+\/var\/lib\/munin/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{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 } + let(:params) { { htmldir: '/var/www/munin' } } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/htmldir\s+\/var\/www\/munin/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{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 } + let(:params) { { dbdir: '/var/log/munin' } } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/dbdir\s+\/var\/log\/munin/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{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 } + let(:params) { { dbdir: '/var/run/munin' } } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/dbdir\s+\/var\/run\/munin/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{dbdir\s+/var/run/munin}) end end context 'with tls => enabled' do let(:params) do { - :tls => 'enabled', - :tls_certificate => '/path/to/certificate.pem', - :tls_private_key => '/path/to/key.pem', - :tls_verify_certificate => 'yes', + 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 { is_expected.to compile.with_all_deps } 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/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{tls = enabled}) + .with_content(%r{tls_certificate = /path/to/certificate\.pem}) + .with_content(%r{tls_private_key = /path/to/key\.pem}) + .with_content(%r{tls_verify_certificate = yes}) end end + context 'with node_definitions' do + let(:params) do + { + node_definitions: { + 'node-a' => { + 'address' => 'munin://node-a.example.com', + }, + 'node-b' => { + 'address' => 'munin://node-b.example.com', + }, + }, + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_munin__master__node_definition('node-a') } + it { is_expected.to contain_munin__master__node_definition('node-b') } + end context 'with extra_config' do token = '1b7febce-bb2d-4c18-b889-84c73538a900' let(:params) do - { :extra_config => [ token ] } + { extra_config: [token] } end - it { should compile.with_all_deps } + + it { is_expected.to compile.with_all_deps } it do - should contain_file("#{conf_dir}/munin.conf") - .with_content(/#{token}/) + is_expected.to contain_file("#{conf_dir}/munin.conf") + .with_content(%r{#{token}}) end end context 'with extra_config set to a string' do token = '1b7febce-bb2d-4c18-b889-84c73538a900' let(:params) do - { :extra_config => token } + { extra_config: token } end - it { should raise_error(Puppet::Error, /is not an Array/) } + + it { is_expected.to raise_error(Puppet::Error, %r{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 } + { host_name: param } end - if param =~ /invalid/ - it { should raise_error(Puppet::Error, /valid domain name/) } + + if param =~ %r{invalid} + it { is_expected.to raise_error(Puppet::Error, %r{valid domain name}) } else - it { should compile.with_all_deps } + it { is_expected.to compile.with_all_deps } end end end - %w( enabled disabled mine unclaimed invalid ).each do |param| + ['enabled', 'disabled', 'mine', 'unclaimed', 'invalid'].each do |param| context "with collect_nodes => #{param}" do let(:params) do - { :collect_nodes => param } + { collect_nodes: param } end + if param == 'invalid' - it { should raise_error(Puppet::Error, /validate_re/) } + it { is_expected.to raise_error(Puppet::Error, %r{validate_re}) } else - it { should compile.with_all_deps } + it { is_expected.to compile.with_all_deps } end end end - - end # on os + end end - end diff --git a/spec/classes/munin_node_export_spec.rb b/spec/classes/munin_node_export_spec.rb new file mode 100644 index 0000000..bb3264e --- /dev/null +++ b/spec/classes/munin_node_export_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +t_params = { + address: '127.0.0.2', + fqn: 'example;foo.example.com', + masterconfig: [], + mastername: 'munin.example.com', +} +t_extra_nodes = { + 'example;svc10.example.com' => { + 'address' => '127.0.0.10', + 'config' => [], + }, + 'example;svc11.example.com' => { + 'address' => '127.0.0.11', + 'config' => ['env foo.warn 12'], + }, +} + +describe 'munin::node::export' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) { facts } + let(:params) { t_params } + + it { is_expected.to compile.with_all_deps } + + it do + expect(exported_resources).to have_munin__master__node_definition_resource_count(1) + end + it do + expect(exported_resources).to contain_munin__master__node_definition(t_params[:fqn]) + .with_address(t_params[:address]) + .with_mastername(t_params[:mastername]) + .with_tag(["munin::master::#{t_params[:mastername]}"]) + end + end + + context "on #{os} with extra nodes" do + let(:facts) { facts } + let(:params) { t_params.merge(node_definitions: t_extra_nodes) } + + it { is_expected.to compile.with_all_deps } + + it do + expect(exported_resources).to have_munin__master__node_definition_resource_count(3) + end + it do + expect(exported_resources).to contain_munin__master__node_definition(t_params[:fqn]) + .with_address(t_params[:address]) + .with_mastername(t_params[:mastername]) + .with_tag("munin::master::#{t_params[:mastername]}") + end + t_extra_nodes.each_key do |n| + it do + expect(exported_resources).to contain_munin__master__node_definition(n) + .with_address(t_extra_nodes[n]['address']) + .with_mastername(t_params[:mastername]) + .with_config(t_extra_nodes[n]['config']) + .with_tag("munin::master::#{t_params[:mastername]}") + end + end + end + end +end diff --git a/spec/classes/munin_node_spec.rb b/spec/classes/munin_node_spec.rb index a95669a..65fff6d 100644 --- a/spec/classes/munin_node_spec.rb +++ b/spec/classes/munin_node_spec.rb @@ -1,199 +1,186 @@ 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' +t_conf_dir = {} +t_conf_dir.default = '/etc/munin' +t_conf_dir['DragonFly'] = '/usr/local/etc/munin' +t_conf_dir['FreeBSD'] = '/usr/local/etc/munin' +t_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) + next if os =~ %r{^(ubuntu|centos|scientific|oraclelinux)-} # 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) + next if os =~ %r{^(debian-[67]|redhat-[56]|freebsd-9)-} context "on #{os}" do - let(:facts) do - facts - end + let(:facts) { facts } - it { should compile.with_all_deps } + it { is_expected.to compile.with_all_deps } - it { should contain_package('munin-node') } + it { is_expected.to contain_package('munin-node') } - munin_confdir = _conf_dir[facts[:osfamily]] + munin_confdir = t_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 + munin_node_service = + case facts[:osfamily] + when 'Solaris' then 'smf:/munin-node' + else '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 + log_dir = + case facts[:osfamily] + when 'Solaris' then '/var/opt/log/munin' + when 'RedHat' then '/var/log/munin-node' + else '/var/log/munin' + end - it { should contain_service(munin_node_service) } - it { should contain_file(munin_node_conf) } + it { is_expected.to contain_service(munin_node_service) } + it { is_expected.to contain_file(munin_node_conf) } context 'with no parameters' do - it { should compile.with_all_deps } + it { is_expected.to compile.with_all_deps } it do - should contain_service(munin_node_service) - .without_ensure() + is_expected.to 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/) + is_expected.to contain_file(munin_node_conf) + .with_content(%r{host_name\s+foo.example.com}) + .with_content(%r{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'] - } + '192\.0\.2'] } end - it { should compile.with_all_deps } + + it { is_expected.to 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::\$$/) + is_expected.to contain_file(munin_node_conf) + .with_content(%r{^cidr_allow 192\.0\.2\.0/25$}) + .with_content(%r{^cidr_allow 2001:db8:2::/64$}) + .with_content(%r{^allow \^192\\\.0\\\.2\\\.129\$$}) + .with_content(%r{^allow 192\\.0\\.2$}) + .with_content(%r{^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 { is_expected.to compile.with_all_deps } it do - should contain_file(munin_node_conf) - .with_content(/host_name\s+something.example.com/) + is_expected.to contain_file(munin_node_conf) + .with_content(%r{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 { is_expected.to compile.with_all_deps } it do - should contain_service('munin-node') + is_expected.to 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 { is_expected.to compile.with_all_deps } it do - should contain_file(munin_node_conf) - .with_content(/log_file\s+Sys::Syslog/) + is_expected.to contain_file(munin_node_conf) + .with_content(%r{log_file\s+Sys::Syslog}) end end context 'with syslog options' do let(:params) do { log_destination: 'syslog', - syslog_facility: 'local1', - } + syslog_facility: 'local1' } end - it{ should compile.with_all_deps } + + it { is_expected.to 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/) + is_expected.to contain_file(munin_node_conf) + .with_content(%r{log_file\s+Sys::Syslog}) + .with_content(%r{syslog_facility\s+local1}) end end context 'with syslog_facility set to wrong value ' do let(:params) do { log_destination: 'syslog', - syslog_facility: 'wrong', - } + syslog_facility: 'wrong' } end - it { expect { should compile.with_all_deps }.to raise_error(/validate_re/) } + + it { expect { is_expected.to compile.with_all_deps }.to raise_error(%r{validate_re}) } end end context 'purge_configs' do context 'set' do let(:params) { { purge_configs: true } } - it { should compile.with_all_deps } + + it { is_expected.to compile.with_all_deps } it do - should contain_file(munin_plugin_dir) - .with_ensure('directory') - .with_recurse(true) - .with_purge(true) + is_expected.to 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) + is_expected.to 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) } + it { is_expected.to compile.with_all_deps } + it { is_expected.not_to contain_file(munin_plugin_dir) } + it { is_expected.not_to 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 { is_expected.to compile.with_all_deps } it do - should contain_file(munin_node_conf) - .with_content(/^timeout 123/) + is_expected.to contain_file(munin_node_conf) + .with_content(%r{^timeout 123}) end end context 'unset' do - it { should compile.with_all_deps } + it { is_expected.to compile.with_all_deps } it do - should contain_file(munin_node_conf) - .without_content(/^timeout/) + is_expected.to contain_file(munin_node_conf) + .without_content(%r{^timeout}) end end end - end end - - context 'unsupported' do - include_context :unsupported - it do - expect do - should contain_class('munin::node') - end.to raise_error(Puppet::Error, /Unsupported osfamily/) - end - end - end diff --git a/spec/default_facts.yml b/spec/default_facts.yml new file mode 100644 index 0000000..ea1e480 --- /dev/null +++ b/spec/default_facts.yml @@ -0,0 +1,7 @@ +# Use default_module_facts.yml for module specific facts. +# +# Facts specified here will override the values provided by rspec-puppet-facts. +--- +ipaddress: "172.16.254.254" +is_pe: false +macaddress: "AA:AA:AA:AA:AA:AA" diff --git a/spec/defines/munin_plugin_spec.rb b/spec/defines/munin_plugin_spec.rb index f38ce96..a4fb37b 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 - +t_conf_dir = {} +t_conf_dir.default = '/etc/munin' +t_conf_dir['Solaris'] = '/opt/local/etc/munin' +t_conf_dir['FreeBSD'] = '/usr/local/etc/munin' + +t_share_dir = {} +t_share_dir.default = '/usr/share/munin' +t_share_dir['Solaris'] = '/opt/local/share/munin' +t_share_dir['FreeBSD'] = '/usr/local/share/munin' +t_share_dir['Archlinux'] = '/usr/lib/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) + next if os =~ %r{^(ubuntu|centos|scientific|oraclelinux)-} # 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) + next if os =~ %r{^(debian-[67]|redhat-[56]|freebsd-9)-} context "on #{os}" do let(:facts) do facts end - conf_dir = _conf_dir[facts[:osfamily]] - plugin_share_dir = "#{_share_dir[facts[:osfamily]]}/plugins" + conf_dir = t_conf_dir[facts[:osfamily]] + plugin_share_dir = "#{t_share_dir[facts[:osfamily]]}/plugins" context 'with no parameters' do it do - expect { should contain_file("#{conf_dir}/plugins/testplugin") } + expect { is_expected.to 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') + is_expected.to contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") + .with_ensure('absent') end end context 'with ensure=link parameter' do - let(:params) { { :ensure => 'link' } } + let(:params) { { ensure: 'link' } } + it do - should contain_file("#{conf_dir}/plugins/testplugin") - .with_ensure('link') - .with_target("#{plugin_share_dir}/testplugin") + is_expected.to 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') + is_expected.to 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 - { :ensure => 'link', - :target => 'test_' } + { ensure: 'link', + target: 'test_' } end + it do - should contain_file("#{conf_dir}/plugins/test_foo") - .with_ensure('link') - .with_target("#{plugin_share_dir}/test_") + is_expected.to 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') + is_expected.to 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' } + { 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') + is_expected.to 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') + is_expected.to 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' ], - } + { 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') + is_expected.to 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/) + is_expected.to contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") + .with_ensure('present') + .with_content(%r{something wonderful}) end end context 'only configuration' do let(:params) do - { :config => ['env.rootdn cn=admin,dc=example,dc=org'], - :config_label => 'slapd_*', - } + { 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/) + it do + is_expected.to contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") + .with_ensure('present') + .with_content(%r{env.rootdn}) end it do - expect { should contain_file("#{conf_dir}/plugins/testplugin") } + expect { is_expected.to 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') + is_expected.to contain_file("#{conf_dir}/plugins/testplugin") + .with_ensure('link') + .with_target('/full/path/to/testplugin') end end - end end - end diff --git a/spec/defines/regression_13_munin_plugin_config_name_spec.rb b/spec/defines/regression_13_munin_plugin_config_name_spec.rb index 862327c..53a5092 100644 --- a/spec/defines/regression_13_munin_plugin_config_name_spec.rb +++ b/spec/defines/regression_13_munin_plugin_config_name_spec.rb @@ -1,52 +1,47 @@ require 'spec_helper' -_conf_dir = {} -_conf_dir.default = '/etc/munin' -_conf_dir['Solaris'] = '/opt/local/etc/munin' -_conf_dir['FreeBSD'] = '/usr/local/etc/munin' +t_conf_dir = {} +t_conf_dir.default = '/etc/munin' +t_conf_dir['Solaris'] = '/opt/local/etc/munin' +t_conf_dir['FreeBSD'] = '/usr/local/etc/munin' describe 'munin::plugin' 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) + next if os =~ %r{^(ubuntu|centos|scientific|oraclelinux)-} # 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) + next if os =~ %r{^(debian-[67]|redhat-[56]|freebsd-9)-} context "on #{os}" do - let(:facts) do - facts - end + let(:facts) { facts } - conf_dir = _conf_dir[facts[:osfamily]] + conf_dir = t_conf_dir[facts[:osfamily]] context 'with config_label unset, label should be set to title' do let(:params) do { config: ['env.foo bar'] } end it do - should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") - .with_content(/^\[testplugin\]$/) + is_expected.to contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") + .with_content(%r{^\[testplugin\]$}) end end context 'with config_label set, label should be set to config_label' do let(:params) do - { config: ['env.foo bar'], - config_label: 'foo_' } + { config: ['env.foo bar'], config_label: 'foo_' } end + it do - should contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") - .with_content(/^\[foo_\]$/) + is_expected.to contain_file("#{conf_dir}/plugin-conf.d/testplugin.conf") + .with_content(%r{^\[foo_\]$}) end end - - end # on os + end end - end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 23d3e29..0d5efc0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,20 +1,47 @@ require 'puppetlabs_spec_helper/module_spec_helper' require 'rspec-puppet-facts' +require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) + include RspecPuppetFacts -require 'simplecov' -require 'simplecov-console' +default_facts = { + puppetversion: Puppet.version, + facterversion: Facter.version, +} + +default_fact_files = [ + File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), + File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), +] + +default_fact_files.each do |f| + next unless File.exist?(f) && File.readable?(f) && File.size?(f) -SimpleCov.start do - add_filter '/spec' - add_filter '/vendor' - formatter SimpleCov::Formatter::MultiFormatter.new([ - SimpleCov::Formatter::HTMLFormatter, - SimpleCov::Formatter::Console - ]) + begin + default_facts.merge!(YAML.safe_load(File.read(f))) + rescue => e + RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" + end end -shared_context :unsupported do - let(:facts) { { osfamily: 'Unsupported' } } +RSpec.configure do |c| + c.default_facts = default_facts + c.before :each do + # set to strictest setting for testing + # by default Puppet runs at warning level + Puppet.settings[:strict] = :warning + end + c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] + c.after(:suite) do + end end + +def ensure_module_defined(module_name) + module_name.split('::').reduce(Object) do |last_module, next_module| + last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) + last_module.const_get(next_module, false) + end +end + +# 'spec_overrides' from sync.yml will appear below this line diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index 538b7a3..9740985 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,22 +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') + 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] } + on host, puppet('module', 'install', 'puppetlabs-stdlib'), acceptable_exit_codes: [0, 1] end end end diff --git a/templates/munin.conf.erb b/templates/munin.conf.erb index 29f47de..2ae7ff2 100644 --- a/templates/munin.conf.erb +++ b/templates/munin.conf.erb @@ -1,37 +1,37 @@ # /etc/munin/munin.conf - Configuration file for the munin master # # This file is handled by puppet, all local modifications will be lost <% if @dbdir -%> dbdir <%= @dbdir %> <% end -%> <% if @htmldir -%> htmldir <%= @htmldir %> <% end -%> <% if @logdir -%> logdir <%= @logdir %> <% end -%> <% if @rundir -%> rundir <%= @rundir %> <% end -%> <% if @html_strategy -%> html_strategy <%= @html_strategy %> <% end -%> <% if @graph_strategy -%> graph_strategy <%= @graph_strategy %> <% end -%> <% if @tls == 'enabled' -%> tls = <%= @tls %> tls_certificate = <%= @tls_certificate %> tls_private_key = <%= @tls_private_key %> tls_verify_certificate = <%= @tls_verify_certificate %> <% end -%> <% if @extra_config -%> <% @extra_config.each do |this| -%> <%= this %> <% end -%> <% end -%> # Where to look for puppet generated munin master configuration. -includedir /etc/munin/munin-conf.d +includedir <%= @config_root -%>/munin-conf.d