diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d77700e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org + +# MANAGED BY MODULESYNC + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +tab_width = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2b1904f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + - pull_request + - push + +jobs: + setup_matrix: + name: 'Setup Test Matrix' + runs-on: ubuntu-latest + timeout-minutes: 40 + outputs: + beaker_setfiles: ${{ steps.get-outputs.outputs.beaker_setfiles }} + puppet_major_versions: ${{ steps.get-outputs.outputs.puppet_major_versions }} + puppet_unit_test_matrix: ${{ steps.get-outputs.outputs.puppet_unit_test_matrix }} + env: + BUNDLE_WITHOUT: development:release + steps: + - uses: actions/checkout@v2 + - name: Setup ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '2.7' + bundler-cache: true + - name: Run rake validate + run: bundle exec rake validate + - name: Run rake rubocop + run: bundle exec rake rubocop + - name: Setup Test Matrix + id: get-outputs + run: bundle exec metadata2gha --use-fqdn --pidfile-workaround false + + unit: + needs: setup_matrix + runs-on: ubuntu-latest + timeout-minutes: 40 + strategy: + fail-fast: false + matrix: + include: ${{fromJson(needs.setup_matrix.outputs.puppet_unit_test_matrix)}} + env: + BUNDLE_WITHOUT: development:system_tests:release + PUPPET_VERSION: "~> ${{ matrix.puppet }}.0" + name: Puppet ${{ matrix.puppet }} (Ruby ${{ matrix.ruby }}) + steps: + - uses: actions/checkout@v2 + - name: Setup ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run tests + run: bundle exec rake diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..68b8528 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: Release + +on: + push: + tags: + - '*' + +env: + BUNDLE_WITHOUT: development:test:system_tests + +jobs: + deploy: + name: 'deploy to forge' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '2.7' + bundler-cache: true + - name: Build and Deploy + env: + # Configure secrets here: + # https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets + BLACKSMITH_FORGE_USERNAME: '${{ secrets.PUPPET_FORGE_USERNAME }}' + BLACKSMITH_FORGE_API_KEY: '${{ secrets.PUPPET_FORGE_API_KEY }}' + run: bundle exec rake module:push diff --git a/.gitignore b/.gitignore index 1d548c5..e9b3cf4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,20 @@ pkg/ -*.swp -.DS_Store Gemfile.lock +Gemfile.local vendor/ .vendor/ +spec/fixtures/manifests/ +spec/fixtures/modules/ +.vagrant/ .bundle/ +.ruby-version +coverage/ +log/ +.idea/ +.dependencies/ +.librarian/ +Puppetfile.lock +*.iml +.*.sw? +.yardoc/ +Guardfile diff --git a/.msync.yml b/.msync.yml new file mode 100644 index 0000000..57ff503 --- /dev/null +++ b/.msync.yml @@ -0,0 +1,2 @@ +--- +modulesync_config_version: '4.1.0' diff --git a/.overcommit.yml b/.overcommit.yml new file mode 100644 index 0000000..0af0fdc --- /dev/null +++ b/.overcommit.yml @@ -0,0 +1,64 @@ +# Managed by https://github.com/voxpupuli/modulesync_configs +# +# Hooks are only enabled if you take action. +# +# To enable the hooks run: +# +# ``` +# bundle exec overcommit --install +# # ensure .overcommit.yml does not harm to you and then +# bundle exec overcommit --sign +# ``` +# +# (it will manage the .git/hooks directory): +# +# Examples howto skip a test for a commit or push: +# +# ``` +# SKIP=RuboCop git commit +# SKIP=PuppetLint git commit +# SKIP=RakeTask git push +# ``` +# +# Don't invoke overcommit at all: +# +# ``` +# OVERCOMMIT_DISABLE=1 git commit +# ``` +# +# Read more about overcommit: https://github.com/brigade/overcommit +# +# To manage this config yourself in your module add +# +# ``` +# .overcommit.yml: +# unmanaged: true +# ``` +# +# to your modules .sync.yml config +--- +PreCommit: + RuboCop: + enabled: true + description: 'Runs rubocop on modified files only' + command: ['bundle', 'exec', 'rubocop'] + PuppetLint: + enabled: true + description: 'Runs puppet-lint on modified files only' + command: ['bundle', 'exec', 'puppet-lint'] + YamlSyntax: + enabled: true + JsonSyntax: + enabled: true + TrailingWhitespace: + enabled: true + +PrePush: + RakeTarget: + enabled: true + description: 'Run rake targets' + targets: + - 'validate' + - 'test' + - 'rubocop' + command: ['bundle', 'exec', 'rake'] diff --git a/.pmtignore b/.pmtignore index fb58957..33a8c65 100644 --- a/.pmtignore +++ b/.pmtignore @@ -1,20 +1,34 @@ docs/ pkg/ +Gemfile Gemfile.lock Gemfile.local vendor/ .vendor/ -spec/fixtures/manifests/ -spec/fixtures/modules/ +spec/ +Rakefile .vagrant/ .bundle/ .ruby-version coverage/ log/ .idea/ .dependencies/ +.github/ .librarian/ Puppetfile.lock *.iml +.editorconfig +.fixtures.yml +.gitignore +.msync.yml +.overcommit.yml +.pmtignore +.rspec +.rspec_parallel +.rubocop.yml +.sync.yml .*.sw? .yardoc/ +.yardopts +Dockerfile diff --git a/.rspec b/.rspec index 49d5710..8c18f1a 100644 --- a/.rspec +++ b/.rspec @@ -1 +1,2 @@ --format documentation +--color diff --git a/.rspec_parallel b/.rspec_parallel new file mode 100644 index 0000000..e4d136b --- /dev/null +++ b/.rspec_parallel @@ -0,0 +1 @@ +--format progress diff --git a/.rubocop.yml b/.rubocop.yml index f635313..198a359 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,508 +1,3 @@ -require: rubocop-rspec -AllCops: - TargetRubyVersion: 2.2 - Include: - - ./**/*.rb - Exclude: - - files/**/* - - vendor/**/* - - Gemfile - - Rakefile - - .vendor/**/* - - pkg/**/* - - spec/fixtures/**/* - - Gemfile - - Rakefile -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/ShadowingOuterLocalVariable: - Enabled: true - -Lint/LiteralInInterpolation: - Enabled: true - -Style/HashSyntax: - Enabled: true - -Style/RedundantReturn: - Enabled: true - -Lint/AmbiguousOperator: - Enabled: true - -Lint/AssignmentInCondition: - Enabled: true - -Layout/SpaceBeforeComment: - Enabled: true - -Style/AndOr: - Enabled: true - -Style/RedundantSelf: - Enabled: true - -# Method length is not necessarily an indicator of code quality -Metrics/MethodLength: - Enabled: false - -# Module length is not necessarily an indicator of code quality -Metrics/ModuleLength: - Enabled: false - -Style/WhileUntilModifier: - Enabled: true - -Lint/AmbiguousRegexpLiteral: - Enabled: true - -Security/Eval: - Enabled: true - -Lint/BlockAlignment: - Enabled: true - -Lint/DefEndAlignment: - Enabled: true - -Lint/EndAlignment: - Enabled: true - -Lint/DeprecatedClassMethods: - Enabled: true - -Lint/Loop: - Enabled: true - -Lint/ParenthesesAsGroupedExpression: - Enabled: true - -Lint/RescueException: - Enabled: true - -Lint/StringConversionInInterpolation: - Enabled: true - -Lint/UnusedBlockArgument: - Enabled: true - -Lint/UnusedMethodArgument: - Enabled: true - -Lint/UselessAccessModifier: - Enabled: true - -Lint/UselessAssignment: - Enabled: true - -Lint/Void: - Enabled: true - -Layout/AccessModifierIndentation: - Enabled: true - -Style/AccessorMethodName: - Enabled: true - -Style/Alias: - Enabled: true - -Layout/AlignArray: - Enabled: true - -Layout/AlignHash: - Enabled: true - -Layout/AlignParameters: - Enabled: true - -Metrics/BlockNesting: - Enabled: true - -Style/AsciiComments: - Enabled: true - -Style/Attr: - Enabled: true - -Style/BracesAroundHashParameters: - Enabled: true - -Style/CaseEquality: - Enabled: true - -Layout/CaseIndentation: - Enabled: true - -Style/CharacterLiteral: - Enabled: true - -Style/ClassAndModuleCamelCase: - Enabled: true - -Style/ClassAndModuleChildren: - Enabled: false - -Style/ClassCheck: - Enabled: true - -# Class length is not necessarily an indicator of code quality -Metrics/ClassLength: - Enabled: false - -Style/ClassMethods: - Enabled: true - -Style/ClassVars: - Enabled: true - -Style/WhenThen: - Enabled: true - -Style/WordArray: - Enabled: true - -Style/UnneededPercentQ: - Enabled: true - -Layout/Tab: - Enabled: true - -Layout/SpaceBeforeSemicolon: - Enabled: true - -Layout/TrailingBlankLines: - Enabled: true - -Layout/SpaceInsideBlockBraces: - Enabled: true - -Layout/SpaceInsideHashLiteralBraces: - Enabled: true - -Layout/SpaceInsideParens: - Enabled: true - -Layout/LeadingCommentSpace: - Enabled: true - -Layout/SpaceBeforeFirstArg: - Enabled: true - -Layout/SpaceAfterColon: - Enabled: true - -Layout/SpaceAfterComma: - Enabled: true - -Layout/SpaceAfterMethodName: - Enabled: true - -Layout/SpaceAfterNot: - Enabled: true - -Layout/SpaceAfterSemicolon: - Enabled: true - -Layout/SpaceAroundEqualsInParameterDefault: - Enabled: true - -Layout/SpaceAroundOperators: - Enabled: true - -Layout/SpaceBeforeBlockBraces: - Enabled: true - -Layout/SpaceBeforeComma: - Enabled: true - -Style/CollectionMethods: - Enabled: true - -Layout/CommentIndentation: - Enabled: true - -Style/ColonMethodCall: - Enabled: true - -Style/CommentAnnotation: - Enabled: true - -# 'Complexity' is very relative -Metrics/CyclomaticComplexity: - Enabled: false - -Style/ConstantName: - Enabled: true - -Style/Documentation: - Enabled: false - -Style/DefWithParentheses: - Enabled: true - -Style/PreferredHashMethods: - Enabled: true - -Layout/DotPosition: - EnforcedStyle: trailing - -Style/DoubleNegation: - Enabled: true - -Style/EachWithObject: - Enabled: true - -Layout/EmptyLineBetweenDefs: - Enabled: true - -Layout/IndentArray: - Enabled: true - -Layout/IndentHash: - Enabled: true - -Layout/IndentationConsistency: - Enabled: true - -Layout/IndentationWidth: - Enabled: true - -Layout/EmptyLines: - Enabled: true - -Layout/EmptyLinesAroundAccessModifier: - Enabled: true - -Style/EmptyLiteral: - Enabled: true - -# Configuration parameters: AllowURI, URISchemes. -Metrics/LineLength: - Enabled: false - -Style/MethodCallWithoutArgsParentheses: - Enabled: true - -Style/MethodDefParentheses: - Enabled: true - -Style/LineEndConcatenation: - Enabled: true - -Layout/TrailingWhitespace: - Enabled: true - -Style/StringLiterals: - Enabled: true - -Style/TrailingCommaInArguments: - Enabled: true - -Style/GlobalVars: - Enabled: true - -Style/GuardClause: - Enabled: true - -Style/IfUnlessModifier: - Enabled: true - -Style/MultilineIfThen: - Enabled: true - -Style/NegatedIf: - Enabled: true - -Style/NegatedWhile: - Enabled: true - -Style/Next: - Enabled: true - -Style/SingleLineBlockParams: - Enabled: true - -Style/SingleLineMethods: - Enabled: true - -Style/SpecialGlobalVars: - Enabled: true - -Style/TrivialAccessors: - Enabled: true - -Style/UnlessElse: - Enabled: true - -Style/VariableInterpolation: - Enabled: true - -Style/VariableName: - Enabled: true - -Style/WhileUntilDo: - Enabled: true - -Style/EvenOdd: - Enabled: true - -Style/FileName: - Enabled: true - -Style/For: - Enabled: true - -Style/Lambda: - Enabled: true - -Style/MethodName: - Enabled: true - -Style/MultilineTernaryOperator: - Enabled: true - -Style/NestedTernaryOperator: - Enabled: true - -Style/NilComparison: - Enabled: true - -Style/FormatString: - Enabled: true - -Style/MultilineBlockChain: - Enabled: true - -Style/Semicolon: - Enabled: true - -Style/SignalException: - Enabled: true - -Style/NonNilCheck: - Enabled: true - -Style/Not: - Enabled: true - -Style/NumericLiterals: - Enabled: true - -Style/OneLineConditional: - Enabled: true - -Style/ParenthesesAroundCondition: - Enabled: true - -Style/PercentLiteralDelimiters: - Enabled: true - -Style/PerlBackrefs: - Enabled: true - -Style/PredicateName: - Enabled: true - -Style/RedundantException: - Enabled: true - -Style/SelfAssignment: - Enabled: true - -Style/Proc: - Enabled: true - -Style/RaiseArgs: - Enabled: true - -Style/RedundantBegin: - Enabled: true - -Style/RescueModifier: - Enabled: true - -# based on https://github.com/voxpupuli/modulesync_config/issues/168 -Style/RegexpLiteral: - EnforcedStyle: percent_r - Enabled: true - -Lint/UnderscorePrefixedVariableName: - Enabled: true - -Metrics/ParameterLists: - Enabled: false - -Lint/RequireParentheses: - Enabled: true - -Layout/SpaceBeforeFirstArg: - Enabled: true - -Style/ModuleFunction: - Enabled: true - -Lint/Debugger: - Enabled: true - -Style/IfWithSemicolon: - Enabled: true - -Style/Encoding: - Enabled: true - -Style/BlockDelimiters: - Enabled: true - -Style/FormatStringToken: - Enabled: false - -Layout/MultilineBlockLayout: - Enabled: true - -# 'Complexity' is very relative -Metrics/AbcSize: - Enabled: False - -Metrics/BlockLength: - Enabled: False - -# 'Complexity' is very relative -Metrics/PerceivedComplexity: - Enabled: False - -Lint/UselessAssignment: - Enabled: true - -Layout/ClosingParenthesisIndentation: - Enabled: false - -# RSpec - -# We don't use rspec in this way -RSpec/DescribeClass: - Enabled: False - -# Example length is not necessarily an indicator of code quality -RSpec/ExampleLength: - Enabled: False -RSpec/NestedGroups: - Max: 5 -RSpec/MultipleExpectations: - Max: 3 +--- +inherit_gem: + voxpupuli-test: rubocop.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a9722d4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -sudo: false -language: ruby -cache: bundler -bundler_args: "--without system_tests development" -before_install: -- bundle -v -- rm Gemfile.lock || true -- gem update --system -- gem update bundler -- gem --version -- bundle -v -script: -- bundle exec rake $CHECK -matrix: - fast_finish: true - include: - - rvm: 2.3.1 - env: PUPPET_VERSION="~> 4.0" STRICT_VARIABLES="yes" CHECK=test - - rvm: 2.3.1 - env: PUPPET_VERSION="~> 4.0" STRICT_VARIABLES="yes" CHECK=rubocop - - rvm: 2.3.1 - env: PUPPET_VERSION="~> 4.0" STRICT_VARIABLES="yes" CHECK=build FORGEDEPLOY=true - - rvm: 2.3.1 - env: PUPPET_VERSION="~> 5.0" STRICT_VARIABLES="yes" CHECK=test - - rvm: 2.3.1 - env: PUPPET_VERSION="~> 5.0" STRICT_VARIABLES="yes" CHECK=rubocop - - rvm: 2.5.3 - env: PUPPET_VERSION="~> 6.1" STRICT_VARIABLES="yes" CHECK=test - - rvm: 2.5.3 - env: PUPPET_VERSION="~> 6.1" STRICT_VARIABLES="yes" CHECK=rubocop -notifications: - email: false -deploy: - provider: puppetforge - user: saz - password: - secure: HOEacsz4i4p5Bagrotnyrst0TPMsbqlpfK8X2j/7ieGRqTJPuLx2yarz2ILHsEUnVPqlSJd4mDXabMZbPcpJlD/tJfNeoU1nVGUH+RX1BcXpakDeZrkraImDLjpnuw3ANtGgUpCFJlQLbYylHBA84RH/mZuroNhW5zi0polPz5M= - on: - tags: true - all_branches: true - rvm: 2.3.1 - condition: "$FORGEDEPLOY = true" diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..3687f51 --- /dev/null +++ b/.yardopts @@ -0,0 +1,2 @@ +--markup markdown +--output-dir docs/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ea331..090629f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,31 +1,31 @@ # Changelog All notable changes to this project will be documented in this file. 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). ## [6.2.0] ### Changed - support older facter versions (#293) ## [6.1.0] ### Fixed -- Fix absolute class name includes +- Fix absolute class name includes - Use gid 0 instead of group name for $host_priv_key_group (#289) - Sort hostkeys (#288) - Do not show diff when installing a ssh private host key (#283) - Don't populate options which have a value of `undef` (#281) ### Added - document exclusion of interfaces and ipaddresses within hostkeys.pp (#267) - add parameter to use trusted facts to hostkeys.pp (#226) ## [6.0.0] ### Fixed - don't fail at deep_merge if hiera data not available, see #272 - Fix typo in match_block example in README, see #271, #273 ### Added - Add CHANGELOG (starting with this release), see #222 - Test module with Puppet 6.1, see #269 ### Changed - Convert `ipaddresses` to 4x API namespaced function, see #270 - Allow `puppetlabs` `stdlib` and `concat` 6.x, see #280 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a51c641 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM ruby:2.7 + +WORKDIR /opt/puppet + +# https://github.com/puppetlabs/puppet/blob/06ad255754a38f22fb3a22c7c4f1e2ce453d01cb/lib/puppet/provider/service/runit.rb#L39 +RUN mkdir -p /etc/sv + +ARG PUPPET_VERSION="~> 6.0" +ARG PARALLEL_TEST_PROCESSORS=4 + +# Cache gems +COPY Gemfile . +RUN bundle install --without system_tests development release --path=${BUNDLE_PATH:-vendor/bundle} + +COPY . . + +RUN bundle install +RUN bundle exec rake release_checks + +# Container should not saved +RUN exit 1 diff --git a/Gemfile b/Gemfile index 577f487..f4855f6 100644 --- a/Gemfile +++ b/Gemfile @@ -1,63 +1,33 @@ -source ENV['GEM_SOURCE'] || 'https://rubygems.org' - -def location_for(place, fake_version = nil) - if place =~ /^(git[:@][^#]*)#(.*)/ - [fake_version, { git: $1, branch: $2, require: false }].compact - elsif place =~ /^file:\/\/(.*)/ - ['>= 0', { path: File.expand_path($1), require: false }] - else - [place, { require: false }] - end -end +source ENV['GEM_SOURCE'] || "https://rubygems.org" group :test do - gem 'puppetlabs_spec_helper', '>= 2.11.0', require: false - gem 'rspec-puppet', require: false - gem 'rspec-puppet-facts', require: false - gem 'rspec-puppet-utils', require: false - gem 'puppet-lint-absolute_classname-check', require: false - gem 'puppet-lint-leading_zero-check', require: false - gem 'puppet-lint-trailing_comma-check', require: false - gem 'puppet-lint-version_comparison-check', require: false - gem 'puppet-lint-classes_and_types_beginning_with_digits-check', require: false - gem 'puppet-lint-unquoted_string-check', require: false - gem 'puppet-lint-variable_contains_upcase', require: false - gem 'metadata-json-lint', require: false - gem 'puppet-blacksmith', require: false - gem 'voxpupuli-release', require: false, git: 'https://github.com/voxpupuli/voxpupuli-release-gem.git' - gem 'puppet-strings', '~> 1.0', require: false - gem 'rubocop', '~> 0.49.1', require: false - gem 'rubocop-rspec', require: false - gem 'rspec-its', require: false + gem 'voxpupuli-test', '~> 2.1', :require => false + gem 'coveralls', :require => false + gem 'simplecov-console', :require => false end group :development do - gem 'travis', require: false - gem 'travis-lint', require: false - gem 'guard-rake', require: false + gem 'guard-rake', :require => false + gem 'overcommit', '>= 0.39.1', :require => false end group :system_tests do - if (beaker_version = ENV['BEAKER_VERSION']) - gem 'beaker', *location_for(beaker_version) - end - if (beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION']) - gem 'beaker-rspec', *location_for(beaker_rspec_version) - else - gem 'beaker-rspec', require: false - end - gem 'beaker-puppet_install_helper', require: false + gem 'puppet_metadata', '~> 0.3.0', :require => false + gem 'voxpupuli-acceptance', :require => false end - - -if (facterversion = ENV['FACTER_GEM_VERSION']) - gem 'facter', facterversion.to_s, require: false, groups: [:test] -else - gem 'facter', require: false, groups: [:test] +group :release do + gem 'github_changelog_generator', '>= 1.16.1', :require => false + gem 'puppet-blacksmith', :require => false + gem 'voxpupuli-release', :require => false + gem 'puppet-strings', '>= 2.2', :require => false end -ENV['PUPPET_VERSION'].nil? ? puppetversion = '~> 4.0' : puppetversion = ENV['PUPPET_VERSION'].to_s -gem 'puppet', puppetversion, require: false, groups: [:test] +gem 'puppetlabs_spec_helper', '~> 2.0', :require => false +gem 'rake', :require => false +gem 'facter', ENV['FACTER_GEM_VERSION'], :require => false, :groups => [:test] + +puppetversion = ENV['PUPPET_VERSION'] || '~> 6.0' +gem 'puppet', puppetversion, :require => false, :groups => [:test] # vim: syntax=ruby diff --git a/Rakefile b/Rakefile index 5c10c3f..1e8a898 100644 --- a/Rakefile +++ b/Rakefile @@ -1,42 +1,61 @@ -require 'puppetlabs_spec_helper/rake_tasks' -require 'puppet_blacksmith/rake_tasks' -require 'voxpupuli/release/rake_tasks' +# Attempt to load voxupuli-test (which pulls in puppetlabs_spec_helper), +# otherwise attempt to load it directly. +begin + require 'voxpupuli/test/rake' +rescue LoadError + require 'puppetlabs_spec_helper/rake_tasks' +end -if RUBY_VERSION >= '2.2.0' - require 'rubocop/rake_task' +# load optional tasks for releases +# only available if gem group releases is installed +begin + require 'voxpupuli/release/rake_tasks' +rescue LoadError +end - RuboCop::RakeTask.new(:rubocop) do |task| - # These make the rubocop experience maybe slightly less terrible - task.options = ['-D', '-S', '-E'] +desc "Run main 'test' task and report merged results to coveralls" +task test_with_coveralls: [:test] do + if Dir.exist?(File.expand_path('../lib', __FILE__)) + require 'coveralls/rake/task' + Coveralls::RakeTask.new + Rake::Task['coveralls:push'].invoke + else + puts 'Skipping reporting to coveralls. Module has no lib dir' end end -PuppetLint.configuration.fail_on_warnings = true -PuppetLint.configuration.send('relative') -PuppetLint.configuration.send('disable_140chars') -PuppetLint.configuration.send('disable_class_inherits_from_params_class') -PuppetLint.configuration.send('disable_documentation') -PuppetLint.configuration.send('disable_single_quote_string_with_variables') +desc 'Generate REFERENCE.md' +task :reference, [:debug, :backtrace] do |t, args| + patterns = '' + Rake::Task['strings:generate:reference'].invoke(patterns, args[:debug], args[:backtrace]) +end -exclude_paths = %w( - pkg/**/* - vendor/**/* - .vendor/**/* - spec/**/* -) -PuppetLint.configuration.ignore_paths = exclude_paths -PuppetSyntax.exclude_paths = exclude_paths +begin + require 'github_changelog_generator/task' + require 'puppet_blacksmith' + GitHubChangelogGenerator::RakeTask.new :changelog do |config| + version = (Blacksmith::Modulefile.new).version + config.future_release = "v#{version}" if version =~ /^\d+\.\d+.\d+$/ + config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\nEach new release typically also includes the latest modulesync defaults.\nThese should not affect the functionality of the module." + config.exclude_labels = %w{duplicate question invalid wontfix wont-fix modulesync skip-changelog} + config.user = 'saz' + metadata_json = File.join(File.dirname(__FILE__), 'metadata.json') + metadata = JSON.load(File.read(metadata_json)) + config.project = metadata['name'] + end -desc 'Run acceptance tests' -RSpec::Core::RakeTask.new(:acceptance) do |t| - t.pattern = 'spec/acceptance' -end + # Workaround for https://github.com/github-changelog-generator/github-changelog-generator/issues/715 + require 'rbconfig' + if RbConfig::CONFIG['host_os'] =~ /linux/ + task :changelog do + puts 'Fixing line endings...' + changelog_file = File.join(__dir__, 'CHANGELOG.md') + changelog_txt = File.read(changelog_file) + new_contents = changelog_txt.gsub(%r{\r\n}, "\n") + File.open(changelog_file, "w") {|file| file.puts new_contents } + end + end -desc 'Run tests metadata_lint, lint, syntax, spec' -task test: [ - :metadata_lint, - :lint, - :syntax, - :spec, -] +rescue LoadError +end # vim: syntax=ruby diff --git a/manifests/client.pp b/manifests/client.pp index 080b90f..edf6c1f 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -1,64 +1,56 @@ # @summary # This class add ssh client management # # @example Puppet usage # class { 'ssh::client': # ensure => present, # storeconfigs_enabled => true, # use_augeas => false, # } # # @param ensure # Ensurable param to ssh client # # @param storeconfigs_enabled # Collected host keys from servers will be written to known_hosts unless storeconfigs_enabled is false # # @param options # Dynamic hash for openssh client options # # @param options_absent # Remove options (with augeas style) # -class ssh::client( +class ssh::client ( String $ensure = present, Boolean $storeconfigs_enabled = true, Hash $options = {}, Boolean $use_augeas = false, Array $options_absent = [], ) inherits ssh::params { - # Merge hashes from multiple layer of hierarchy in hiera $hiera_options = lookup("${module_name}::client::options", Optional[Hash], 'deep', {}) $fin_options = deep_merge($hiera_options, $options) if $use_augeas { $merged_options = sshclient_options_to_augeas_ssh_config($fin_options, $options_absent, { 'target' => $ssh::params::ssh_config }) } else { $merged_options = merge($fin_options, delete($ssh::params::ssh_default_options, keys($fin_options))) } include ssh::client::install include ssh::client::config - anchor { 'ssh::client::start': } - anchor { 'ssh::client::end': } - # Provide option to *not* use storeconfigs/puppetdb, which means not managing # hostkeys and knownhosts if ($storeconfigs_enabled) { include ssh::knownhosts - Anchor['ssh::client::start'] - -> Class['ssh::client::install'] + Class['ssh::client::install'] -> Class['ssh::client::config'] -> Class['ssh::knownhosts'] - -> Anchor['ssh::client::end'] } else { - Anchor['ssh::client::start'] - -> Class['ssh::client::install'] + Class['ssh::client::install'] -> Class['ssh::client::config'] - -> Anchor['ssh::client::end'] } } diff --git a/manifests/client/config.pp b/manifests/client/config.pp index 68885c8..e8a99a5 100644 --- a/manifests/client/config.pp +++ b/manifests/client/config.pp @@ -1,18 +1,17 @@ -class ssh::client::config -{ +class ssh::client::config { $options = $ssh::client::merged_options $use_augeas = $ssh::client::use_augeas if $use_augeas { create_resources('ssh_config', $options) } else { file { $ssh::params::ssh_config: - ensure => present, + ensure => file, owner => '0', group => '0', mode => '0644', content => template("${module_name}/ssh_config.erb"), require => Class['ssh::client::install'], } } } diff --git a/manifests/client/config/user.pp b/manifests/client/config/user.pp index 35ec937..d2f8150 100644 --- a/manifests/client/config/user.pp +++ b/manifests/client/config/user.pp @@ -1,56 +1,56 @@ # # Copyright (c) IN2P3 Computing Centre, IN2P3, CNRS # Contributor: Remi Ferrand (2015) # Contributor: Tim Meusel (2017) # -define ssh::client::config::user( +define ssh::client::config::user ( Enum['present', 'absent'] $ensure = present, Optional[Stdlib::Absolutepath] $target = undef, Optional[Stdlib::Absolutepath] $user_home_dir = undef, Boolean $manage_user_ssh_dir = true, Hash $options = {}, String[1] $user = $name, ) { include ssh::params # If a specific target file was specified, # it must have higher priority than any # other parameter. if ($target != undef) { $_target = $target } else { if ($user_home_dir == undef) { $_user_home_dir = "/home/${user}" } else { $_user_home_dir = $user_home_dir } $user_ssh_dir = "${_user_home_dir}/.ssh" $_target = "${user_ssh_dir}/config" if ($manage_user_ssh_dir == true) { unless defined(File[$user_ssh_dir]) { file { $user_ssh_dir: ensure => directory, owner => $user, mode => $ssh::params::user_ssh_directory_default_mode, before => Concat_file[$_target], } } } } unless defined(Concat_file[$_target]) { concat_file { $_target: ensure => $ensure, owner => $user, mode => $ssh::params::user_ssh_config_default_mode, tag => $name, } } concat_fragment { $name: tag => $name, content => template("${module_name}/ssh_config.erb"), target => $_target, } } diff --git a/manifests/client/install.pp b/manifests/client/install.pp index 11f0d2b..d3489ec 100644 --- a/manifests/client/install.pp +++ b/manifests/client/install.pp @@ -1,5 +1,9 @@ class ssh::client::install { if $ssh::params::client_package_name { - ensure_packages([$ssh::params::client_package_name], {'ensure' => $ssh::client::ensure}) + ensure_packages([ + $ssh::params::client_package_name, + ], { + 'ensure' => $ssh::client::ensure, + }) } } diff --git a/manifests/hostkeys.pp b/manifests/hostkeys.pp index 697b9f6..b5e45f6 100644 --- a/manifests/hostkeys.pp +++ b/manifests/hostkeys.pp @@ -1,59 +1,58 @@ # @summary # This class manages hostkeys # # @api private # -class ssh::hostkeys( +class ssh::hostkeys ( Boolean $export_ipaddresses = true, Optional[String] $storeconfigs_group = undef, Array $extra_aliases = [], Array $exclude_interfaces = [], Array $exclude_ipaddresses = [], Boolean $use_trusted_facts = false, ) { - if $use_trusted_facts { $fqdn_real = $trusted['certname'] $hostname_real = $trusted['hostname'] } else { # stick to legacy facts for older versions of facter - $fqdn_real = $facts['fqdn'] - $hostname_real = $facts['hostname'] + $fqdn_real = $facts['networking']['fqdn'] + $hostname_real = $facts['networking']['hostname'] } if $export_ipaddresses == true { $ipaddresses = ssh::ipaddresses($exclude_interfaces) $ipaddresses_real = $ipaddresses - $exclude_ipaddresses - $host_aliases = sort(unique(flatten([ $fqdn_real, $hostname_real, $extra_aliases, $ipaddresses_real ]))) + $host_aliases = sort(unique(flatten([$fqdn_real, $hostname_real, $extra_aliases, $ipaddresses_real]))) } else { - $host_aliases = sort(unique(flatten([ $fqdn_real, $hostname_real, $extra_aliases ]))) + $host_aliases = sort(unique(flatten([$fqdn_real, $hostname_real, $extra_aliases]))) } if $storeconfigs_group { tag 'hostkey_all', "hostkey_${storeconfigs_group}" } ['dsa', 'rsa', 'ecdsa', 'ed25519'].each |String $key_type| { # can be removed as soon as we drop support for puppet 4 # see https://tickets.puppetlabs.com/browse/FACT-1377?jql=project%20%3D%20FACT%20AND%20fixVersion%20%3D%20%22FACT%203.12.0%22 if $key_type == 'ecdsa' { $key_type_real = 'ecdsa-sha2-nistp256' } else { $key_type_real = $key_type } if $key_type in $facts['ssh'] { @@sshkey { "${fqdn_real}_${key_type}": ensure => present, host_aliases => $host_aliases, type => $key_type_real, key => $facts['ssh'][$key_type]['key'], } } else { @@sshkey { "${fqdn_real}_${key_type}": ensure => absent, type => $key_type_real, } } } } diff --git a/manifests/init.pp b/manifests/init.pp index 1f833e3..ca98a1a 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,153 +1,152 @@ # @summary # This class manages ssh client and server # # @example Puppet usage # class { 'ssh': # storeconfigs_enabled => false, # server_options => { # 'Match User www-data' => { # 'ChrootDirectory' => '%h', # 'ForceCommand' => 'internal-sftp', # 'PasswordAuthentication' => 'yes', # 'AllowTcpForwarding' => 'no', # 'X11Forwarding' => 'no', # }, # 'Port' => [22, 2222, 2288], # }, # client_options => { # 'Host *.amazonaws.com' => { # 'User' => 'ec2-user', # }, # }, # users_client_options => { # 'bob' => { # options => { # 'Host *.alice.fr' => { # 'User' => 'alice', # }, # }, # }, # }, # } # # @example hiera usage # ssh::storeconfigs_enabled: true # # ssh::server_options: # Protocol: '2' # ListenAddress: # - '127.0.0.0' # - '%{::hostname}' # PasswordAuthentication: 'yes' # SyslogFacility: 'AUTHPRIV' # UsePAM: 'yes' # X11Forwarding: 'yes' # # ssh::server::match_block: # filetransfer: # type: group # options: # ChrootDirectory: /home/sftp # ForceCommand: internal-sftp # # ssh::client_options: # 'Host *': # SendEnv: 'LANG LC_*' # ForwardX11Trusted: 'yes' # ServerAliveInterval: '10' # # ssh::users_client_options: # 'bob': # 'options': # 'Host *.alice.fr': # 'User': 'alice' # 'PasswordAuthentication': 'no' # # # @param server_options # Add dynamic options for ssh server config # # @param server_match_block # Add match block for ssh server config # # @param client_options # Add dynamic options for ssh client config # # @param users_client_options # Add users options for ssh client config # # @param version # Define package version (pacakge ressource) # # @param storeconfigs_enabled # Default value for storeconfigs_enabled (client and server) # # @param validate_sshd_file # Default value for validate_sshd_file (server) # # @param use_augeas # Default value to use augeas (client and server) # # @param server_options_absent # List of options to remove for server config (augeas only) # # @param client_options_absent # List of options to remove for client config (augeas only) # # @param use_issue_net # Use issue_net header # class ssh ( Hash $server_options = {}, Hash $server_match_block = {}, Hash $client_options = {}, Hash $users_client_options = {}, String $version = 'present', Boolean $storeconfigs_enabled = true, Boolean $validate_sshd_file = $ssh::params::validate_sshd_file, Boolean $use_augeas = false, Array $server_options_absent = [], Array $client_options_absent = [], Boolean $use_issue_net = false, Boolean $purge_unmanaged_sshkeys = true, ) inherits ssh::params { - # Merge hashes from multiple layer of hierarchy in hiera $hiera_server_options = lookup("${module_name}::server_options", Optional[Hash], 'deep', {}) $hiera_server_match_block = lookup("${module_name}::server_match_block", Optional[Hash], 'deep', {}) $hiera_client_options = lookup("${module_name}::client_options", Optional[Hash], 'deep', {}) $hiera_users_client_options = lookup("${module_name}::users_client_options", Optional[Hash], 'deep', {}) $fin_server_options = deep_merge($hiera_server_options, $server_options) $fin_server_match_block = deep_merge($hiera_server_match_block, $server_match_block) $fin_client_options = deep_merge($hiera_client_options, $client_options) $fin_users_client_options = deep_merge($hiera_users_client_options, $users_client_options) class { 'ssh::server': ensure => $version, storeconfigs_enabled => $storeconfigs_enabled, options => $fin_server_options, validate_sshd_file => $validate_sshd_file, use_augeas => $use_augeas, options_absent => $server_options_absent, use_issue_net => $use_issue_net, } class { 'ssh::client': ensure => $version, storeconfigs_enabled => $storeconfigs_enabled, options => $fin_client_options, use_augeas => $use_augeas, options_absent => $client_options_absent, } # If host keys are being managed, optionally purge unmanaged ones as well. if ($storeconfigs_enabled and $purge_unmanaged_sshkeys) { resources { 'sshkey': purge => true, } } create_resources('ssh::client::config::user', $fin_users_client_options) create_resources('ssh::server::match_block', $fin_server_match_block) } diff --git a/manifests/knownhosts.pp b/manifests/knownhosts.pp index 405a182..bd6b9d2 100644 --- a/manifests/knownhosts.pp +++ b/manifests/knownhosts.pp @@ -1,21 +1,21 @@ # @summary # This class manages knownhosts if collection is enabled. # # @param collect_enabled # Enable collection # # @param storeconfigs_group # Define the hostkeys group storage # -class ssh::knownhosts( +class ssh::knownhosts ( Boolean $collect_enabled = $ssh::params::collect_enabled, Optional[String] $storeconfigs_group = undef, ) inherits ssh::params { if ($collect_enabled) { if $storeconfigs_group { Sshkey <<| tag == "hostkey_${storeconfigs_group}" |>> } else { Sshkey <<| |>> } } } diff --git a/manifests/params.pp b/manifests/params.pp index 5b4b6c1..6925cfe 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,238 +1,238 @@ # @summary # Params class # # @api private # class ssh::params { - case $::osfamily { + case $facts['os']['family'] { 'Debian': { $server_package_name = 'openssh-server' $client_package_name = 'openssh-client' $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'ssh' $sftp_server_path = '/usr/lib/openssh/sftp-server' $host_priv_key_group = 0 } 'RedHat': { $server_package_name = 'openssh-server' $client_package_name = 'openssh-clients' $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' $sftp_server_path = '/usr/libexec/openssh/sftp-server' - if versioncmp($::operatingsystemmajrelease, '7') >= 0 { + if versioncmp($facts['os']['release']['major'], '7') >= 0 { $host_priv_key_group = 'ssh_keys' } else { $host_priv_key_group = 0 } } 'FreeBSD', 'DragonFly': { $server_package_name = undef $client_package_name = undef $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' $sftp_server_path = '/usr/libexec/sftp-server' $host_priv_key_group = 0 } 'OpenBSD': { $server_package_name = undef $client_package_name = undef $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' $sftp_server_path = '/usr/libexec/sftp-server' $host_priv_key_group = 0 } 'Darwin': { $server_package_name = undef $client_package_name = undef $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'com.openssh.sshd' $sftp_server_path = '/usr/libexec/sftp-server' $host_priv_key_group = 0 } 'ArchLinux': { $server_package_name = 'openssh' $client_package_name = 'openssh' $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd.service' $sftp_server_path = '/usr/lib/ssh/sftp-server' $host_priv_key_group = 0 } 'Suse': { $server_package_name = 'openssh' $client_package_name = 'openssh' $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $host_priv_key_group = 0 - case $::operatingsystem { + case $facts['os']['name'] { 'SLES': { $service_name = 'sshd' - # $::operatingsystemmajrelease isn't available on e.g. SLES 10 - case $::operatingsystemrelease { + case $facts['os']['release']['full'] { /^10\./, /^11\./: { - if ($::architecture == 'x86_64') { + if ($facts['os']['architecture'] == 'x86_64') { $sftp_server_path = '/usr/lib64/ssh/sftp-server' } else { $sftp_server_path = '/usr/lib/ssh/sftp-server' } } default: { $sftp_server_path = '/usr/lib/ssh/sftp-server' } } } 'OpenSuse': { $service_name = 'sshd' $sftp_server_path = '/usr/lib/ssh/sftp-server' } default: { - fail("Unsupported platform: ${::osfamily}/${::operatingsystem}") + fail("Unsupported platform: ${facts['os']['family']}/${facts['os']['name']}") } } } 'Solaris': { - case $::operatingsystem { + case $facts['os']['name'] { 'SmartOS': { $server_package_name = undef $client_package_name = undef $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'svc:/network/ssh:default' $sftp_server_path = 'internal-sftp' $host_priv_key_group = 0 } default: { $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'svc:/network/ssh:default' $sftp_server_path = 'internal-sftp' $host_priv_key_group = 0 - case versioncmp($::kernelrelease, '5.10') { + case versioncmp($facts['kernelrelease'], '5.10') { 1: { # Solaris 11 and later $server_package_name = '/service/network/ssh' $client_package_name = '/network/ssh' } 0: { # Solaris 10 $server_package_name = 'SUNWsshdu' $client_package_name = 'SUNWsshu' } default: { # Solaris 9 and earlier not supported - fail("Unsupported platform: ${::osfamily}/${::kernelrelease}") + fail("Unsupported platform: ${facts['os']['family']}/${facts['kernelrelease']}") } } } } } default: { - case $::operatingsystem { + case $facts['os']['name'] { 'Gentoo': { $server_package_name = 'openssh' $client_package_name = 'openssh' $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' $sftp_server_path = '/usr/lib/misc/sftp-server' $host_priv_key_group = 0 } 'Amazon': { $server_package_name = 'openssh-server' $client_package_name = 'openssh-clients' $sshd_dir = '/etc/ssh' $sshd_config = '/etc/ssh/sshd_config' $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' $sftp_server_path = '/usr/libexec/openssh/sftp-server' $host_priv_key_group = 0 } default: { - fail("Unsupported platform: ${::osfamily}/${::operatingsystem}") + fail("Unsupported platform: ${facts['os']['family']}/${facts['os']['name']}") } } } } # ssh & sshd default options: # - OpenBSD doesn't know about UsePAM # - Sun_SSH doesn't know about UsePAM & AcceptEnv; SendEnv & HashKnownHosts - case $::osfamily { + case $facts['os']['family'] { 'OpenBSD': { $sshd_default_options = { 'ChallengeResponseAuthentication' => 'no', 'X11Forwarding' => 'yes', 'PrintMotd' => 'no', 'AcceptEnv' => 'LANG LC_*', 'Subsystem' => "sftp ${sftp_server_path}", } $ssh_default_options = { 'Host *' => { 'SendEnv' => 'LANG LC_*', 'HashKnownHosts' => 'yes', }, } } 'Solaris': { $sshd_default_options = { 'ChallengeResponseAuthentication' => 'no', 'X11Forwarding' => 'yes', 'PrintMotd' => 'no', 'Subsystem' => "sftp ${sftp_server_path}", 'HostKey' => [ "${sshd_dir}/ssh_host_rsa_key", "${sshd_dir}/ssh_host_dsa_key", ], } - $ssh_default_options = { } + $ssh_default_options = { + } } default: { $sshd_default_options = { 'ChallengeResponseAuthentication' => 'no', 'X11Forwarding' => 'yes', 'PrintMotd' => 'no', 'AcceptEnv' => 'LANG LC_*', 'Subsystem' => "sftp ${sftp_server_path}", 'UsePAM' => 'yes', } $ssh_default_options = { 'Host *' => { 'SendEnv' => 'LANG LC_*', 'HashKnownHosts' => 'yes', }, } } } $validate_sshd_file = false $user_ssh_directory_default_mode = '0700' $user_ssh_config_default_mode = '0600' $collect_enabled = true # Collect sshkey resources $issue_net = '/etc/issue.net' } diff --git a/manifests/server.pp b/manifests/server.pp index 7b3d89b..e30a631 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,88 +1,80 @@ # @summary # This class managed ssh server # # @example Puppet usage # class { 'ssh::server': # ensure => present, # storeconfigs_enabled => true, # use_issue_net => false, # } # # @param ensure # Ensurable param to ssh server # # @param storeconfigs_enabled # Host keys will be collected and distributed unless storeconfigs_enabled is false. # # @param options # Dynamic hash for openssh server option # # @param validate_sshd_file # Add sshd file validate cmd # # @param use_augeas # Use augeas for configuration (default concat) # # @param options_absent # Remove options (with augeas style) # # @param match_block # Add sshd match_block (with concat) # # @use_issue_net # Add issue_net banner # -class ssh::server( +class ssh::server ( String $ensure = present, Boolean $storeconfigs_enabled = true, Hash $options = {}, Boolean $validate_sshd_file = false, Boolean $use_augeas = false, Array $options_absent = [], Hash $match_block = {}, Boolean $use_issue_net = false ) inherits ssh::params { - # Merge hashes from multiple layer of hierarchy in hiera $hiera_options = lookup("${module_name}::server::options", Optional[Hash], 'deep', {}) $hiera_match_block = lookup("${module_name}::server::match_block", Optional[Hash], 'deep', {}) $fin_options = deep_merge($hiera_options, $options) $fin_match_block = deep_merge($hiera_match_block, $match_block) if $use_augeas { $merged_options = sshserver_options_to_augeas_sshd_config($fin_options, $options_absent, { 'target' => $ssh::params::sshd_config }) } else { $merged_options = deep_merge($ssh::params::sshd_default_options, $fin_options) } include ssh::server::install include ssh::server::config include ssh::server::service - anchor { 'ssh::server::start': } - anchor { 'ssh::server::end': } - # Provide option to *not* use storeconfigs/puppetdb, which means not managing # hostkeys and knownhosts if ($storeconfigs_enabled) { include ssh::hostkeys include ssh::knownhosts - Anchor['ssh::server::start'] - -> Class['ssh::server::install'] + Class['ssh::server::install'] -> Class['ssh::server::config'] ~> Class['ssh::server::service'] -> Class['ssh::hostkeys'] -> Class['ssh::knownhosts'] - -> Anchor['ssh::server::end'] } else { - Anchor['ssh::server::start'] - -> Class['ssh::server::install'] + Class['ssh::server::install'] -> Class['ssh::server::config'] ~> Class['ssh::server::service'] - -> Anchor['ssh::server::end'] } create_resources('ssh::server::match_block', $fin_match_block) } diff --git a/manifests/server/config.pp b/manifests/server/config.pp index e539a95..ce1fa12 100644 --- a/manifests/server/config.pp +++ b/manifests/server/config.pp @@ -1,53 +1,53 @@ # @summary # Managed ssh server configuration # # @api private # class ssh::server::config { $options = $ssh::server::merged_options case $ssh::server::validate_sshd_file { true: { $sshd_validate_cmd = '/usr/sbin/sshd -tf %' } default: { $sshd_validate_cmd = undef } } if $ssh::server::use_augeas { create_resources('sshd_config', $options) } else { concat { $ssh::params::sshd_config: ensure => present, owner => 0, group => 0, mode => '0600', validate_cmd => $sshd_validate_cmd, notify => Service[$ssh::params::service_name], } concat::fragment { 'global config': target => $ssh::params::sshd_config, content => template("${module_name}/sshd_config.erb"), order => '00', } } if $ssh::server::use_issue_net { file { $ssh::params::issue_net: - ensure => present, + ensure => file, owner => 0, group => 0, mode => '0644', content => template("${module_name}/issue.net.erb"), notify => Service[$ssh::params::service_name], } concat::fragment { 'banner file': target => $ssh::params::sshd_config, content => "Banner ${ssh::params::issue_net}\n", order => '01', } } } diff --git a/manifests/server/config/setting.pp b/manifests/server/config/setting.pp index 912806b..20dafc6 100644 --- a/manifests/server/config/setting.pp +++ b/manifests/server/config/setting.pp @@ -1,33 +1,32 @@ # @summary # Internal define to managed ssh server param # # @api private # define ssh::server::config::setting ( $key, $value, $order = '10' ) { include ssh::params if is_bool($value) { $real_value = $value ? { true => 'yes', false => 'no', default => undef } } elsif is_array($value) { $real_value = join($value, ' ') } elsif is_hash($value) { fail('Hash values are not supported') } else { $real_value = $value } concat::fragment { "ssh_setting_${name}_${key}": target => $ssh::params::sshd_config, content => "\n# added by Ssh::Server::Config::Setting[${name}]\n${key} ${real_value}\n", order => $order, } - } diff --git a/manifests/server/host_key.pp b/manifests/server/host_key.pp index 65e8768..209f057 100644 --- a/manifests/server/host_key.pp +++ b/manifests/server/host_key.pp @@ -1,153 +1,152 @@ # == Define: ssh::server::host_key # # This module install a ssh host key in the server (basically, it is # a file resource but it also notifies to the ssh service) # # Important! This define does not modify any option in sshd_config, so # you have to manually define the HostKey option in the server options # if you haven't done yet. # # == Parameters # # [*ensure*] # Set to 'absent' to remove host_key files # # [*public_key_source*] # Sets the content of the source parameter for the public key file # Note public_key_source and public_key_content are mutually exclusive. # # [*public_key_content*] # Sets the content for the public key file. # Note public_key_source and public_key_content are mutually exclusive. # # [*private_key_source*] # Sets the content of the source parameter for the private key file # Note private_key_source and private_key_content are mutually exclusive. # # [*private_key_content*] # Sets the content for the private key file. # Note private_key_source and private_key_content are mutually exclusive. # # [*certificate_source*] # Sets the content of the source parameter for the host key certificate. # Note certificate_source and certificate_content are mutually exclusive. # # [*certificate_content*] # Sets the content for the host key certificate. # Note certificate_source and certificate_content are mutually exclusive. # define ssh::server::host_key ( $ensure = 'present', $public_key_source = '', $public_key_content = '', $private_key_source = '', $private_key_content = '', $certificate_source = '', $certificate_content = '', ) { - # Ensure the ssh::server class is included in the manifest include ssh::server if $public_key_source == '' and $public_key_content == '' and $ensure == 'present' { fail('You must provide either public_key_source or public_key_content parameter') } if $private_key_source == '' and $private_key_content == '' and $ensure == 'present' { fail('You must provide either private_key_source or private_key_content parameter') } $manage_pub_key_content = $public_key_source ? { '' => $public_key_content, default => undef, } $manage_pub_key_source = $public_key_source ? { '' => undef, default => $public_key_source, } $manage_priv_key_content = $private_key_source ? { '' => $private_key_content, default => undef, } $manage_priv_key_source = $private_key_source ? { '' => undef, default => $private_key_source, } $manage_cert_content = $certificate_source ? { '' => $certificate_content, default => undef, } $manage_cert_source = $certificate_source ? { '' => undef, default => $certificate_source, } if $ensure == 'present' { - file {"${name}_pub": + file { "${name}_pub": ensure => $ensure, owner => 0, group => 0, mode => '0644', path => "${ssh::params::sshd_dir}/${name}.pub", source => $manage_pub_key_source, content => $manage_pub_key_content, notify => Class['ssh::server::service'], } - file {"${name}_priv": + file { "${name}_priv": ensure => $ensure, owner => 0, group => $ssh::params::host_priv_key_group, mode => '0600', path => "${ssh::params::sshd_dir}/${name}", source => $manage_priv_key_source, content => $manage_priv_key_content, show_diff => false, notify => Class['ssh::server::service'], } } else { - file {"${name}_pub": + file { "${name}_pub": ensure => $ensure, owner => 0, group => 0, mode => '0644', path => "${ssh::params::sshd_dir}/${name}.pub", notify => Class['ssh::server::service'], } - file {"${name}_priv": + file { "${name}_priv": ensure => $ensure, owner => 0, group => $ssh::params::host_priv_key_group, mode => '0600', path => "${ssh::params::sshd_dir}/${name}", show_diff => false, notify => Class['ssh::server::service'], } } if !empty($certificate_source) or !empty($certificate_content) { if $ensure == 'present' { - file {"${name}_cert": + file { "${name}_cert": ensure => $ensure, owner => 0, group => 0, mode => '0644', path => "${ssh::params::sshd_dir}/${name}-cert.pub", source => $manage_cert_source, content => $manage_cert_content, notify => Class['ssh::server::service'], } } else { - file {"${name}_cert": + file { "${name}_cert": ensure => $ensure, owner => 0, group => 0, mode => '0644', path => "${ssh::params::sshd_dir}/${name}-cert.pub", notify => Class['ssh::server::service'], } } } } diff --git a/manifests/server/install.pp b/manifests/server/install.pp index 70b22aa..d6a4a46 100644 --- a/manifests/server/install.pp +++ b/manifests/server/install.pp @@ -1,14 +1,15 @@ # @summary # Install ssh server package # # @api private # class ssh::server::install { include ssh::params if $ssh::params::server_package_name { - ensure_packages( - [$ssh::params::server_package_name], - { 'ensure' => $ssh::server::ensure } - ) + ensure_packages ([ + $ssh::params::server_package_name, + ], { + 'ensure' => $ssh::server::ensure, + }) } } diff --git a/manifests/server/service.pp b/manifests/server/service.pp index ee80a6c..1aa0757 100644 --- a/manifests/server/service.pp +++ b/manifests/server/service.pp @@ -1,24 +1,24 @@ # @summary # This class managed ssh server service # # @param ensure # Ensurable service param # # @param enable # Define if service is enable # class ssh::server::service ( String $ensure = 'running', Boolean $enable = true -){ +) { include ssh::params include ssh::server service { $ssh::params::service_name: ensure => $ssh::server::service::ensure, hasstatus => true, hasrestart => true, enable => $ssh::server::service::enable, require => Class['ssh::server::config'], } } diff --git a/metadata.json b/metadata.json index cba5d51..1846f6d 100644 --- a/metadata.json +++ b/metadata.json @@ -1,64 +1,64 @@ { "name": "saz-ssh", "version": "6.2.0", "author": "saz", "summary": "Manage SSH client and server via Puppet.", "description": "Manage SSH client and server via puppet", "license": "Apache-2.0", "source": "git://github.com/saz/puppet-ssh.git", "project_page": "https://github.com/saz/puppet-ssh", "dependencies": [ { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.25.0 < 8.0.0" }, { "name": "puppetlabs/concat", "version_requirement": ">= 2.2.0 < 8.0.0" } ], "operatingsystem_support": [ { "operatingsystem": "RedHat" }, { "operatingsystem": "CentOS" }, { "operatingsystem": "OracleLinux" }, { "operatingsystem": "Scientific" }, { "operatingsystem": "Debian" }, { "operatingsystem": "Ubuntu" }, { "operatingsystem": "FreeBSD" }, { "operatingsystem": "DragonFly" }, { "operatingsystem": "OpenBSD" }, { "operatingsystem": "Gentoo" }, { "operatingsystem": "Solaris" }, { "operatingsystem": "ArchLinux" } ], "requirements": [ { "name": "puppet", - "version_requirement": ">= 4.10.10 < 7.0.0" + "version_requirement": ">= 6.1.0 < 8.0.0" } ] } diff --git a/spec/classes/client_spec.rb b/spec/classes/client_spec.rb index 6dd1433..80115b3 100644 --- a/spec/classes/client_spec.rb +++ b/spec/classes/client_spec.rb @@ -1,31 +1,55 @@ require 'spec_helper' describe 'ssh::client', type: 'class' do context 'when on Debian with no other parameters' do let :facts do { - osfamily: 'Debian' + :os => { + 'family' => 'Debian' + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end it do is_expected.to contain_package('openssh-client').with(ensure: 'present') end end context 'when on Debian with custom ensure' do let :facts do { - osfamily: 'Debian' + :os => { + 'family' => 'Debian' + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end let :params do { ensure: 'latest' } end it do is_expected.to contain_package('openssh-client').with(ensure: 'latest') end end end diff --git a/spec/classes/coverage_spec.rb b/spec/classes/coverage_spec.rb deleted file mode 100644 index de44654..0000000 --- a/spec/classes/coverage_spec.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'rspec-puppet' - -at_exit { RSpec::Puppet::Coverage.report! } -# vim: syntax=ruby diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index e2a36b5..09e1df8 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -1,62 +1,98 @@ require 'spec_helper' describe 'ssh', type: 'class' do context 'when on Debian with no other parameters' do let :facts do { - osfamily: 'Debian' + :os => { + 'family' => 'Debian' + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end it do is_expected.to contain_class('ssh::client') end it do is_expected.to contain_class('ssh::server') end it do is_expected.to contain_concat('/etc/ssh/sshd_config').with_validate_cmd(nil) end it do is_expected.to contain_resources('sshkey').with_purge(true) end context 'when on Debian with the validate_sshd_file setting' do let :facts do { - osfamily: 'Debian' + :os => { + 'family' => 'Debian' + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end let :params do { validate_sshd_file: true } end it do is_expected.to contain_class('ssh::client') end it do is_expected.to contain_concat('/etc/ssh/sshd_config').with_validate_cmd('/usr/sbin/sshd -tf %') end end end standard_facts = { - osfamily: 'Debian' + :os => { + 'family' => 'Debian' + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } context 'When on Debian without resource purging' do let :facts do standard_facts end let :params do { 'purge_unmanaged_sshkeys' => false } end it do is_expected.not_to contain_resources('sshkey') end end end diff --git a/spec/classes/server_spec.rb b/spec/classes/server_spec.rb index 09cae7b..54d977e 100644 --- a/spec/classes/server_spec.rb +++ b/spec/classes/server_spec.rb @@ -1,145 +1,181 @@ require 'spec_helper' describe 'ssh::server' do let :default_params do { ensure: 'present', storeconfigs_enabled: true } end describe 'providing options' do let :params do { options: { 'TestString' => '/usr/bin', 'TestBoolean' => true } } end let :facts do { - osfamily: 'RedHat', - operatingsystemmajrelease: '6' + :os => { + 'family' => 'RedHat', + 'release' => { + 'major' => '6' + } + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end it do is_expected.to contain_concat__fragment('global config').with( target: '/etc/ssh/sshd_config', content: '# File is managed by Puppet AcceptEnv LANG LC_* ChallengeResponseAuthentication no PrintMotd no Subsystem sftp /usr/libexec/openssh/sftp-server TestBoolean yes TestString /usr/bin UsePAM yes X11Forwarding yes ' # rubocop:enable EmptyLinesAroundArguments ) end end [{}, { ensure: 'latest', storeconfigs_enabled: true }, { ensure: 'present', storeconfigs_enabled: false }].each do |param_set| describe "when #{param_set == {} ? 'using default' : 'specifying'} class parameters" do let :param_hash do default_params.merge(param_set) end let :params do param_set end ['Debian'].each do |osfamily| let :facts do { - osfamily: osfamily + :os => { + 'family' => osfamily + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end describe "on supported osfamily: #{osfamily}" do it { is_expected.to contain_class('ssh::params') } it { is_expected.to contain_package('openssh-server').with_ensure(param_hash[:ensure]) } it do is_expected.to contain_service('ssh').with( 'ensure' => 'running', 'enable' => true, 'hasrestart' => true, 'hasstatus' => true ) end it { is_expected.to contain_concat('/etc/ssh/sshd_config') } it do is_expected.to contain_concat__fragment('global config').with( target: '/etc/ssh/sshd_config', content: '# File is managed by Puppet AcceptEnv LANG LC_* ChallengeResponseAuthentication no PrintMotd no Subsystem sftp /usr/lib/openssh/sftp-server UsePAM yes X11Forwarding yes ' ) end end describe 'on Arch' do let :facts do { - osfamily: 'Archlinux', - lsbdistdescription: 'Arch Linux', - lsbdistid: 'Arch' + :os => { + 'family' => 'Archlinux' + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end it { is_expected.to contain_class('ssh::params') } it do is_expected.to contain_package('openssh').with( ensure: param_hash[:ensure], name: 'openssh' ) end it do is_expected.to contain_service('sshd.service').with( 'ensure' => 'running', 'enable' => true, 'hasrestart' => true, 'hasstatus' => true ) end it { is_expected.to contain_concat('/etc/ssh/sshd_config') } it do is_expected.to contain_concat__fragment('global config').with( target: '/etc/ssh/sshd_config', content: '# File is managed by Puppet AcceptEnv LANG LC_* ChallengeResponseAuthentication no PrintMotd no Subsystem sftp /usr/lib/ssh/sftp-server UsePAM yes X11Forwarding yes ' ) end end end end end end diff --git a/spec/defines/client/config/user_spec.rb b/spec/defines/client/config/user_spec.rb index 47a2f8e..e0f1034 100644 --- a/spec/defines/client/config/user_spec.rb +++ b/spec/defines/client/config/user_spec.rb @@ -1,170 +1,184 @@ require 'spec_helper' describe 'ssh::client::config::user', type: :define do let :title do 'riton' end let :ssh_options do { 'HashKnownHosts' => 'yes', 'Host *.in2p3.fr' => { 'User' => 'riton', 'GSSAPIAuthentication' => 'no' } } end let :facts do { - osfamily: 'RedHat', - operatingsystemmajrelease: '6' + :os => { + 'family' => 'RedHat', + 'release' => { + 'major' => '6' + } + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end describe 'with invalid parameters' do params = { ensure: ['somestate', 'expects a match for Enum'], target: ['./somedir', 'Pattern'], user_home_dir: ['./somedir', 'Pattern'], manage_user_ssh_dir: ['maybe', 'expects a Boolean'], options: ['the_options', 'Hash value'] } params.each do |param, value| context "with invalid value for #{param}" do let :params do { param => value[0] } end it { is_expected.not_to compile } end end end # describe 'with invalid parameters' describe 'with correct values' do describe 'with a user provided target' do let :target do '/root/.ssh/config' end let :params do { target: target } end it do is_expected.to contain_concat_file(target).with( ensure: 'present', tag: title ) is_expected.to contain_concat_fragment(title).with( tag: title, target: target ) end end # describe 'with a user provided target' describe 'user_home_dir behavior' do context 'with a user provided user_home_dir' do let :user_home_dir do '/path/to/home' end context 'with manage_user_ssh_dir default value' do let :params do { user_home_dir: user_home_dir } end it 'contains ssh directory and ssh config' do is_expected.to contain_file("#{user_home_dir}/.ssh").with( ensure: 'directory', owner: title, mode: '0700' ).that_comes_before("Concat_file[#{user_home_dir}/.ssh/config]") is_expected.to contain_concat_file("#{user_home_dir}/.ssh/config").with( ensure: 'present', owner: title, mode: '0600' ) end end # context 'with manage_user_ssh_dir default value' context 'with manage_user_ssh_dir set to false' do let :params do { user_home_dir: user_home_dir, manage_user_ssh_dir: false } end it do is_expected.not_to contain_file("#{user_home_dir}/.ssh") end end # context 'with manage_user_ssh_dir set to false' end # context 'with a user provided user_home_dir' context 'with no user provided user_home_dir' do it 'with manage_user_ssh_dir default value' do is_expected.to contain_file("/home/#{title}/.ssh").that_comes_before("Concat_file[/home/#{title}/.ssh/config]") is_expected.to contain_concat_file("/home/#{title}/.ssh/config") end context 'with manage_user_ssh_dir set to false' do let :params do { manage_user_ssh_dir: false } end it do is_expected.not_to contain_file("/home/#{title}/.ssh") end it do is_expected.to contain_concat_file("/home/#{title}/.ssh/config") end end # context 'with manage_user_ssh_dir set to false' end # context 'with no user provided user_home_dir' end # describe 'user_home_dir behavior' describe 'ssh configuration content' do let :params do { options: ssh_options } end it 'has single value' do is_expected.to contain_concat_fragment(title).with( content: %r{HashKnownHosts\s+yes}, target: "/home/#{title}/.ssh/config" ) end it 'has Hash value' do is_expected.to contain_concat_fragment(title).with( content: %r{Host \*\.in2p3\.fr\s*\n\s+GSSAPIAuthentication\s+no\s*\n\s+User\s+riton}, target: "/home/#{title}/.ssh/config" ) end end end # describe 'with correct values' end # vim: tabstop=2 shiftwidth=2 softtabstop=2 diff --git a/spec/defines/server/config/setting_spec.rb b/spec/defines/server/config/setting_spec.rb index 4d95a29..cc4ebf8 100644 --- a/spec/defines/server/config/setting_spec.rb +++ b/spec/defines/server/config/setting_spec.rb @@ -1,72 +1,86 @@ require 'spec_helper' describe 'ssh::server::config::setting', type: :define do let :title do 'something' end let :facts do { - osfamily: 'RedHat', - operatingsystemmajrelease: '6' + :os => { + 'family' => 'RedHat', + 'release' => { + 'major' => '6' + }, + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end describe 'with key => "AllowGroups", value => "group1 group2"' do let :params do { key: 'AllowGroups', value: 'group1 group2' } end it do is_expected.to contain_concat__fragment('ssh_setting_something_AllowGroups').with_content(%r{\nAllowGroups group1 group2\n}) end end describe 'with key => "Somesetting", value => true' do let :params do { key: 'Somesetting', value: true } end it do is_expected.to contain_concat__fragment('ssh_setting_something_Somesetting').with_content(%r{\nSomesetting yes\n}) end end describe 'with key => "Foo", value => [1, 2]' do let :params do { key: 'Foo', value: [1, 2] } end it do is_expected.to contain_concat__fragment('ssh_setting_something_Foo').with_content(%r{\nFoo 1 2\n}) end end describe 'with key => "Bar", value => {"a" => "b"}' do let :params do { key: 'Bar', value: { 'a' => 'b' } } end it 'fails' do expect do is_expected.to compile end.to raise_error(%r{Hash values are not supported}) end end end # vim: tabstop=2 shiftwidth=2 softtabstop=2 diff --git a/spec/defines/server/host_key_spec.rb b/spec/defines/server/host_key_spec.rb index a009c53..3be4d31 100644 --- a/spec/defines/server/host_key_spec.rb +++ b/spec/defines/server/host_key_spec.rb @@ -1,166 +1,180 @@ require 'spec_helper' describe 'ssh::server::host_key', type: :define do let :title do 'something' end let(:pre_condition) { 'class {"::ssh::params": }' } let :facts do { - osfamily: 'RedHat', - operatingsystemmajrelease: '6' + :os => { + 'family' => 'RedHat', + 'release' => { + 'major' => '6' + }, + }, + 'networking' => { + 'interfaces' => { + 'eth0' => { + 'ip' => '10.0.0.1' + }, + 'eth1' => { + 'ip' => '10.0.1.1' + }, + } + } } end describe 'with public_key_content, private_key_content and certificate_content' do let :params do { public_key_content: 'abc', private_key_content: 'bcd', certificate_content: 'cde' } end it do is_expected.to contain_file('something_pub'). with_content('abc'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0644'). with_path('/etc/ssh/something.pub') is_expected.to contain_file('something_priv'). with_content('bcd'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0600'). with_path('/etc/ssh/something') is_expected.to contain_file('something_cert'). with_content('cde'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0644'). with_path('/etc/ssh/something-cert.pub') end end describe 'with public_key_content and private_key_content' do let :params do { public_key_content: 'abc', private_key_content: 'bcd' } end it do is_expected.to contain_file('something_pub'). with_content('abc'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0644'). with_path('/etc/ssh/something.pub') is_expected.to contain_file('something_priv'). with_content('bcd'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0600'). with_path('/etc/ssh/something') is_expected.not_to contain_file('something_cert') end end describe 'with *_key_content and *_key_source, *_key_source takes precedence' do let :params do { public_key_content: 'abc', public_key_source: 'a', private_key_content: 'bcd', private_key_source: 'b' } end it do is_expected.to contain_file('something_pub'). without_content. with_source('a'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0644'). with_path('/etc/ssh/something.pub') is_expected.to contain_file('something_priv'). without_content. with_source('b'). with_ensure('present'). with_owner(0). with_group(0). with_mode('0600'). with_path('/etc/ssh/something') is_expected.not_to contain_file('something_cert') end end describe 'with private_key_content and no public_key_content' do let :params do { private_key_content: 'bcd' } end it 'fails' do expect do is_expected.to compile end.to raise_error(%r{You must provide either public_key_source or public_key_content parameter}) end end describe 'with public_key_content and no private_key_content' do let :params do { public_key_content: 'abc' } end it 'fails' do expect do is_expected.to compile end.to raise_error(%r{You must provide either private_key_source or private_key_content parameter}) end end describe 'with private_key_source and no public_key_source' do let :params do { private_key_source: 'bcd' } end it 'fails' do expect do is_expected.to compile end.to raise_error(%r{You must provide either public_key_source or public_key_content parameter}) end end describe 'with public_key_source and no private_key_source' do let :params do { public_key_source: 'abc' } end it 'fails' do expect do is_expected.to compile end.to raise_error(%r{You must provide either private_key_source or private_key_content parameter}) end end end # vim: tabstop=2 shiftwidth=2 softtabstop=2 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fef3ee9..d266f6b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,32 +1,18 @@ -require 'rspec-puppet' -require 'puppetlabs_spec_helper/module_spec_helper' +# This file is managed via modulesync +# https://github.com/voxpupuli/modulesync +# https://github.com/voxpupuli/modulesync_config -RSpec.configure do |c| - c.default_facts = { - 'networking' => { - 'interfaces' => { - 'eth0' => { - 'bindings' => [ - { - 'address' => '192.168.1.1' - } - ], - 'bindings6' => [ - { - 'address' => '::1' - } - ] - } - } - }, - concat_basedir: '/tmp', - puppetversion: '3.7.0', - sshdsakey: 'AAAAB3NzaC1kc3MAAACBAODCvvUUnv2imW4cfuLBWVJTLMzds89MtCUXGl3+7Gza5QYJmp7GSkKBnV8+7XI+JAmjv0RKQM1RAn7mV5UplRTtg3CYbeNkX4IakZmNJLTdL4vUyIehhaxBobpOtBaJfFewCJE1plIaWvoWfEDrShcjIUbUbJMfR8YWweIIqp9bAAAAFQCr8+KRfOUZbS9Dz1t15A/Owl61VQAAAIBr/7hNPCvjzAl5+rde6jUR5k20pxAE+z2wsaZxlhrs6ZhhplyCKIXKq4rCx4QuFVPh/c+WJRPO56iH/rSh5Y5cpT1LUk66wNJcOBPprjvDEHfQUHUmfYXzNJ2BHkRL78lfzQr52YyowV6dHfktv0VsIctm13KcMr2KQygZtV6EqgAAAIEAjNC4PRdzYpWfxu268CJDpexlhBwIkIx+ovEibtYeke55qAQcF9UWko4A1c8Wf4nLLxlQYCf501Bt5lb6GmZd0xfpg27fPIfzZPL8o+E756D3ZcNXUaLj4HPRKnwNcdAtChL2jESH3fm8PyNwBI7tV6IOjmOGpyQKtmJq3IyNgms=', - sshrsakey: 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDzA57hAMwz6pywCgxNUcloWeNMvBo2PDPxK2RCegst+9tYaf4S3shnM9a1j2PGBoeRXTuUG6mYB32fJm6/37UUUJA4lT+8CZ3hNnDZU9aitpukkKon7RIlvY1PWO8wT4A5mEa0hfdQg6Um8KZZUs+jrB+8zMJO/X0fmleY54r/JKrP3hNcpaJpTUVQEvMmKacW7nYez/PvWKAz8d02uAOXuauGKhZ9K2AHYKlQFqJ4S1jLiduoGFWxFQ2vQybbN/O0PQQU7EZlHIjSzwoowZLzlxCKCZcKnoDsbGCtYHArbjxTb+m5e7nvsamz7TXLoY90Srmc5QGMxrLUlSvkYsm5', - sshecdsakey: 'AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFDrof0LPA0hGuwODy+5uTynV7rgPJspvZo2TzykBu5mSANJvdL1z5/JS3x16/c/cDjx2lfEkRoVDnon4/NjKEM=', - sshed25519key: '', - id: 'root', - is_pe: false, - path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games' - } +# puppetlabs_spec_helper will set up coverage if the env variable is set. +# We want to do this if lib exists and it hasn't been explicitly set. +ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../../lib', __FILE__)) + +require 'voxpupuli/test/spec_helper' + +if File.exist?(File.join(__dir__, 'default_module_facts.yml')) + facts = YAML.safe_load(File.read(File.join(__dir__, 'default_module_facts.yml'))) + if facts + facts.each do |name, value| + add_custom_fact name.to_sym, value + end + end end diff --git a/spec/unit/facter/util/fact_ssh_client_version_spec.rb b/spec/unit/facter/util/fact_ssh_client_version_spec.rb index 76f2c55..877419f 100644 --- a/spec/unit/facter/util/fact_ssh_client_version_spec.rb +++ b/spec/unit/facter/util/fact_ssh_client_version_spec.rb @@ -1,26 +1,27 @@ require 'spec_helper' describe 'ssh_client_version_full' do + before { Facter.clear } + after { Facter.clear } + context 'when on a Linux host' do before do - Facter.clear - Facter.fact(:kernel).stubs(:value).returns('linux') - Facter::Util::Resolution.stubs(:which).with('ssh').returns('/usr/bin/ssh') - Facter::Util::Resolution.stubs(:exec).with('ssh -V 2>&1').returns('OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.8, OpenSSL 1.0.1f 6 Jan 2014') + allow(Facter.fact(:kernel)).to receive(:value).and_return('linux') + allow(Facter::Util::Resolution).to receive(:which).with('ssh').and_return('/usr/bin/ssh') + allow(Facter::Util::Resolution).to receive(:exec).with('ssh -V 2>&1').and_return('OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.8, OpenSSL 1.0.1f 6 Jan 2014') end it 'execs ssh -V and returns full version number' do expect(Facter.fact(:ssh_client_version_full).value).to eq('6.6.1p1') end end context 'when on a SunOS host' do before do - Facter.clear - Facter.fact(:kernel).stubs(:value).returns('SunOS') - Facter::Util::Resolution.stubs(:which).with('ssh').returns('/usr/bin/ssh') - Facter::Util::Resolution.stubs(:exec).with('ssh -V 2>&1').returns('Sun_SSH_2.4, SSH protocols 1.5/2.0, OpenSSL 0x100020bf') + allow(Facter.fact(:kernel)).to receive(:value).and_return('SunOS') + allow(Facter::Util::Resolution).to receive(:which).with('ssh').and_return('/usr/bin/ssh') + allow(Facter::Util::Resolution).to receive(:exec).with('ssh -V 2>&1').and_return('Sun_SSH_2.4, SSH protocols 1.5/2.0, OpenSSL 0x100020bf') end it 'execs ssh -V and returns full version number' do expect(Facter.fact(:ssh_client_version_full).value).to eq('2.4') end end end diff --git a/spec/unit/facter/util/fact_ssh_server_version_major_spec.rb b/spec/unit/facter/util/fact_ssh_server_version_major_spec.rb index 55e91be..d2f18f5 100644 --- a/spec/unit/facter/util/fact_ssh_server_version_major_spec.rb +++ b/spec/unit/facter/util/fact_ssh_server_version_major_spec.rb @@ -1,41 +1,41 @@ require 'spec_helper' describe Facter::Util::Fact do before do Facter.clear - Facter.fact(:kernel).stubs(:value).returns('linux') + allow(Facter.fact(:kernel)).to receive(:value).and_return('linux') end describe 'ssh_server_version_major' do context 'with 3 point semver syntax (6.6.1p1)' do context 'with ssh_server_version_full fact present returns major version' do before do - Facter.fact(:ssh_server_version_full).stubs(:value).returns('6.6.1p1') + allow(Facter.fact(:ssh_server_version_full)).to receive(:value).and_return('6.6.1p1') end it do expect(Facter.fact(:ssh_server_version_major).value).to eq('6') end end end context 'with 2 point semver syntax (7.2p2)' do context 'with ssh_server_version_full fact present returns major version' do before do - Facter.fact(:ssh_server_version_full).stubs(:value).returns('7.2p2') + allow(Facter.fact(:ssh_server_version_full)).to receive(:value).and_return('7.2p2') end it do expect(Facter.fact(:ssh_server_version_major).value).to eq('7') end end end context 'without ssh_server_version_full fact present returns nil' do before do - Facter.fact(:ssh_server_version_full).stubs(:value).returns(nil) + allow(Facter.fact(:ssh_server_version_full)).to receive(:value).and_return(nil) end it do expect(Facter.fact(:ssh_server_version_major).value).to be_nil end end end end diff --git a/spec/unit/facter/util/fact_ssh_server_version_spec.rb b/spec/unit/facter/util/fact_ssh_server_version_spec.rb index d4030b3..96d9bab 100644 --- a/spec/unit/facter/util/fact_ssh_server_version_spec.rb +++ b/spec/unit/facter/util/fact_ssh_server_version_spec.rb @@ -1,26 +1,27 @@ require 'spec_helper' describe 'ssh_server_version_full' do + before { Facter.clear } + after { Facter.clear } + context 'when on a Linux host' do before do - Facter.clear - Facter.fact(:kernel).stubs(:value).returns('linux') - Facter::Util::Resolution.stubs(:which).with('sshd').returns('/usr/sbin/sshd') - Facter::Util::Resolution.stubs(:exec).with('sshd -V 2>&1').returns('OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.8, OpenSSL 1.0.1f 6 Jan 2014') + allow(Facter.fact(:kernel)).to receive(:value).and_return('linux') + allow(Facter::Util::Resolution).to receive(:which).with('sshd').and_return('/usr/bin/sshd') + allow(Facter::Util::Resolution).to receive(:exec).with('sshd -V 2>&1').and_return('OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.8, OpenSSL 1.0.1f 6 Jan 2014') end it 'execs sshd -V and returns full version number' do expect(Facter.fact(:ssh_server_version_full).value).to eq('6.6.1p1') end end context 'when on a SunOS host' do before do - Facter.clear - Facter.fact(:kernel).stubs(:value).returns('SunOS') - Facter::Util::Resolution.stubs(:which).with('sshd').returns('/usr/bin/sshd') - Facter::Util::Resolution.stubs(:exec).with('sshd -V 2>&1').returns('Sun_SSH_2.4, SSH protocols 1.5/2.0, OpenSSL 0x100020bf') + allow(Facter.fact(:kernel)).to receive(:value).and_return('SunOS') + allow(Facter::Util::Resolution).to receive(:which).with('sshd').and_return('/usr/bin/sshd') + allow(Facter::Util::Resolution).to receive(:exec).with('sshd -V 2>&1').and_return('Sun_SSH_2.4, SSH protocols 1.5/2.0, OpenSSL 0x100020bf') end it 'execs sshd -V and returns full version number' do expect(Facter.fact(:ssh_server_version_full).value).to eq('2.4') end end end diff --git a/tests/init.pp b/tests/init.pp deleted file mode 100644 index 6687c2c..0000000 --- a/tests/init.pp +++ /dev/null @@ -1 +0,0 @@ -class { '::ssh::server': } diff --git a/tests/server.pp b/tests/server.pp deleted file mode 100644 index 93a2381..0000000 --- a/tests/server.pp +++ /dev/null @@ -1 +0,0 @@ -include ::ssh::server