diff --git a/.fixtures.yml b/.fixtures.yml index d9d05bff..adba068b 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -1,6 +1,6 @@ fixtures: repositories: - epel: 'https://github.com/stahnma/puppet-module-epel.git' + epel: 'https://github.com/voxpupuli/puppet-epel.git' inifile: 'https://github.com/puppetlabs/puppetlabs-inifile.git' stdlib: 'https://github.com/puppetlabs/puppetlabs-stdlib.git' vcsrepo: 'https://github.com/puppetlabs/puppetlabs-vcsrepo.git' diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 38cacd4e..cace33e6 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,3 +1,18 @@ +# Contribution guidelines + +## Table of contents + +* [Contributing](#contributing) +* [Writing proper commits - short version](#writing-proper-commits-short-version) +* [Writing proper commits - long version](#writing-proper-commits-long-version) +* [Dependencies](#dependencies) + * [Note for OS X users](#note-for-os-x-users) +* [The test matrix](#the-test-matrix) +* [Syntax and style](#syntax-and-style) +* [Running the unit tests](#running-the-unit-tests) +* [Unit tests in docker](#unit-tests-in-docker) +* [Integration tests](#integration-tests) + This module has grown over time based on a range of contributions from people using it. If you follow these contributing guidelines your patch will likely make it into a release a little more quickly. @@ -8,29 +23,94 @@ Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. [Contributor Code of Conduct](https://voxpupuli.org/coc/). -1. Fork the repo. - -1. Create a separate branch for your change. - -1. We only take pull requests with passing tests, and documentation. [travis-ci](http://travis-ci.org) - runs the tests for us. You can also execute them locally. This is explained - in a later section. - -1. Checkout [our docs](https://voxpupuli.org/docs/#reviewing-a-module-pr) we - use to review a module and the [official styleguide](https://puppet.com/docs/puppet/6.0/style_guide.html). - They provide some guidance for new code that might help you before you submit a pull request. - -1. Add a test for your change. Only refactoring and documentation - changes require no new tests. If you are adding functionality - or fixing a bug, please add a test. - -1. Squash your commits down into logical components. Make sure to rebase - against our current master. - -1. Push the branch to your fork and submit a pull request. - -Please be prepared to repeat some of these steps as our contributors review -your code. +* Fork the repo. +* Create a separate branch for your change. +* We only take pull requests with passing tests, and documentation. [travis-ci](http://travis-ci.org) runs the tests for us. You can also execute them locally. This is explained [in a later section](#the-test-matrix). +* Checkout [our docs](https://voxpupuli.org/docs/reviewing_pr/) we use to review a module and the [official styleguide](https://puppet.com/docs/puppet/6.0/style_guide.html). They provide some guidance for new code that might help you before you submit a pull request. +* Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, please add a test. +* Squash your commits down into logical components. Make sure to rebase against our current master. +* Push the branch to your fork and submit a pull request. + +Please be prepared to repeat some of these steps as our contributors review your code. + +Also consider sending in your profile code that calls this component module as an acceptance test or provide it via an issue. This helps reviewers a lot to test your use case and prevents future regressions! + +## Writing proper commits - short version + +* Make commits of logical units. +* Check for unnecessary whitespace with "git diff --check" before committing. +* Commit using Unix line endings (check the settings around "crlf" in git-config(1)). +* Do not check in commented out code or unneeded files. +* The first line of the commit message should be a short description (50 characters is the soft limit, excluding ticket number(s)), and should skip the full stop. +* Associate the issue in the message. The first line should include the issue number in the form "(#XXXX) Rest of message". +* The body should provide a meaningful commit message, which: + *uses the imperative, present tense: `change`, not `changed` or `changes`. + * includes motivation for the change, and contrasts its implementation with the previous behavior. + * Make sure that you have tests for the bug you are fixing, or feature you are adding. + * Make sure the test suites passes after your commit: + * When introducing a new feature, make sure it is properly documented in the README.md + +## Writing proper commits - long version + + 1. Make separate commits for logically separate changes. + + Please break your commits down into logically consistent units + which include new or changed tests relevant to the rest of the + change. The goal of doing this is to make the diff easier to + read for whoever is reviewing your code. In general, the easier + your diff is to read, the more likely someone will be happy to + review it and get it into the code base. + + If you are going to refactor a piece of code, please do so as a + separate commit from your feature or bug fix changes. + + We also really appreciate changes that include tests to make + sure the bug is not re-introduced, and that the feature is not + accidentally broken. + + Describe the technical detail of the change(s). If your + description starts to get too long, that is a good sign that you + probably need to split up your commit into more finely grained + pieces. + + Commits which plainly describe the things which help + reviewers check the patch and future developers understand the + code are much more likely to be merged in with a minimum of + bike-shedding or requested changes. Ideally, the commit message + would include information, and be in a form suitable for + inclusion in the release notes for the version of Puppet that + includes them. + + Please also check that you are not introducing any trailing + whitespace or other "whitespace errors". You can do this by + running "git diff --check" on your changes before you commit. + + 2. Sending your patches + + To submit your changes via a GitHub pull request, we _highly_ + recommend that you have them on a topic branch, instead of + directly on `master`. + It makes things much easier to keep track of, especially if + you decide to work on another thing before your first change + is merged in. + + GitHub has some pretty good + [general documentation](http://help.github.com/) on using + their site. They also have documentation on + [creating pull requests](http://help.github.com/send-pull-requests/). + + In general, after pushing your topic branch up to your + repository on GitHub, you can switch to the branch in the + GitHub UI and click "Pull Request" towards the top of the page + in order to open a pull request. + + + 3. Update the related GitHub issue. + + If there is a GitHub issue associated with the change you + submitted, then you should update the ticket to include the + location of your branch, along with any other commentary you + may wish to make. ## Dependencies @@ -75,13 +155,15 @@ BUNDLE_JOBS="$(nproc)" ### Note for OS X users -`nproc` isn't a valid command unter OS x. As an alternative, you can do: +`nproc` isn't a valid command under OS x. As an alternative, you can do: ```sh --jobs "$(sysctl -n hw.ncpu)" ``` -## Syntax and style +## The test matrix + +### Syntax and style The test suite will run [Puppet Lint](http://puppet-lint.com/) and [Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to @@ -99,7 +181,7 @@ against it. You can run those locally ahead of time with: bundle exec rake rubocop ``` -## Running the unit tests +### Running the unit tests The unit test suite covers most of the code, as mentioned above please add tests if you're adding new functionality. If you've not used @@ -124,7 +206,7 @@ To run a specific spec test set the `SPEC` variable: bundle exec rake spec SPEC=spec/foo_spec.rb ``` -### Unit tests in docker +#### Unit tests in docker Some people don't want to run the dependencies locally or don't want to install ruby. We ship a Dockerfile that enables you to run all unit tests and linting. @@ -139,7 +221,7 @@ permission to talk to it. You can specify a remote docker host by setting the `DOCKER_HOST` environment variable. it will copy the content of the module into the docker image. So it will not work if a Gemfile.lock exists. -## Integration tests +### Integration tests The unit tests just check the code runs, not that it does exactly what we want on a real machine. For that we're using @@ -176,18 +258,20 @@ Beaker also supports docker containers. We also use that in our automated CI pipeline at [travis-ci](http://travis-ci.org). To use that instead of Vagrant: ```sh -PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=debian9-64{hypervisor=docker} BEAKER_destroy=yes bundle exec rake beaker +PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian10-64{hypervisor=docker} BEAKER_destroy=yes bundle exec rake beaker ``` -You can replace the string `debian9` with any common operating system. +You can replace the string `debian10` with any common operating system. The following strings are known to work: * ubuntu1604 * ubuntu1804 -* debian8 +* ubuntu2004 * debian9 +* debian10 * centos6 * centos7 +* centos8 The easiest way to debug in a docker container is to open a shell: diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..cacadf22 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,3 @@ +# Vox Pupuli Security Policy + +Our vulnerabilities reporting process is at https://voxpupuli.org/security/ diff --git a/.msync.yml b/.msync.yml index 23dfa32f..5758aced 100644 --- a/.msync.yml +++ b/.msync.yml @@ -1 +1,2 @@ -modulesync_config_version: '2.8.0' +--- +modulesync_config_version: '3.1.0' diff --git a/.overcommit.yml b/.overcommit.yml index 1b03fad7..0af0fdc0 100644 --- a/.overcommit.yml +++ b/.overcommit.yml @@ -61,4 +61,4 @@ PrePush: - 'validate' - 'test' - 'rubocop' - command: [ 'bundle', 'exec', 'rake' ] + command: ['bundle', 'exec', 'rake'] diff --git a/.rubocop.yml b/.rubocop.yml index 099a11c5..198a3599 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,545 +1,3 @@ -require: rubocop-rspec -AllCops: - TargetRubyVersion: 1.9 - Include: - - ./**/*.rb - Exclude: - - files/**/* - - vendor/**/* - - .vendor/**/* - - pkg/**/* - - spec/fixtures/**/* - - Gemfile - - Rakefile - - Guardfile - - Vagrantfile -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/HashSyntax: - Enabled: True - -Style/RedundantReturn: - Enabled: True - -Layout/EndOfLine: - Enabled: False - -Lint/AmbiguousOperator: - Enabled: True - -Lint/AssignmentInCondition: - Enabled: True - -Layout/SpaceBeforeComment: - Enabled: True - -Style/AndOr: - Enabled: True - -Style/RedundantSelf: - Enabled: True - -Metrics/BlockLength: - Enabled: False - -# 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/SpaceInsideBrackets: - 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/TrailingCommaInLiteral: - 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/OpMethod: - 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 - -Style/ModuleFunction: - Enabled: True - -Lint/Debugger: - Enabled: True - -Style/IfWithSemicolon: - Enabled: True - -Style/Encoding: - Enabled: True - -Style/BlockDelimiters: - Enabled: True - -Layout/MultilineBlockLayout: - Enabled: True - -# 'Complexity' is very relative -Metrics/AbcSize: - Enabled: False - -# 'Complexity' is very relative -Metrics/PerceivedComplexity: - Enabled: False - -Lint/UselessAssignment: - Enabled: True - -Layout/ClosingParenthesisIndentation: - Enabled: True - -# RSpec - -RSpec/BeforeAfterAll: - Exclude: - - spec/acceptance/**/* - -# 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/NamedSubject: - Enabled: False - -# disabled for now since they cause a lot of issues -# these issues aren't easy to fix -RSpec/RepeatedDescription: - Enabled: False - -RSpec/NestedGroups: - Enabled: False - -# this is broken on ruby1.9 -Layout/IndentHeredoc: - Enabled: False - -# disable Yaml safe_load. This is needed to support ruby2.0.0 development envs -Security/YAMLLoad: - Enabled: false - -# This affects hiera interpolation, as well as some configs that we push. -Style/FormatStringToken: - Enabled: false - -# This is useful, but sometimes a little too picky about where unit tests files -# are located. -RSpec/FilePath: - Enabled: false +--- +inherit_gem: + voxpupuli-test: rubocop.yml diff --git a/.sync.yml b/.sync.yml index f779bab4..6150f683 100644 --- a/.sync.yml +++ b/.sync.yml @@ -3,8 +3,9 @@ docker_sets: - set: centos7-64 - set: debian9-64 - - set: fedora29-64 + - set: debian10-64 - set: fedora30-64 + - set: fedora31-64 - set: ubuntu1604-64 - set: ubuntu1804-64 secure: "n/CVUS2upgv5DifCm/YsjBxR/11bdTRDYi1x9QK6ILa32+6ngVV2RQaIMXXJfJKYIPT8/O21tpc9C7fOBRGhRpNbl0usfvqsZS0C9UkpEx6AqT7lcRzj6pLrNn3IuChhZ0tQjNiKp9LxVTzltxr5uTFwKKCE4o534v/DLAzkzq5EAZuBWpRS1rcVHQA3o0767Gu3601yyYkZj9ySDH5RpbSdTCcNkTzwtFhr2NEvVb+2FI0RhchDSqPBfNWHV4Hn3dKuL42MNC2zjd2FYFpC8F27OXk/erUZIOZFfpZuIWypjSimfVC95a2Nb8kfQotTvQxUI1fwiB01ibUQGGkJj+mh7Utg/byBrbijpJnWRR7TT6oQ1NbIUHVXcqE1tfpbCBZ4Ws2Hqji0QoGc0fMrkt1NVlZlgbVrb9t+ctb1QcLaEPI+1Zf2a3AZhXOKA1EGx2W5DTQSWSPv57BUtFPICZENQi/ats30h+0FwtN7rjfx8Q6BIGO2D5JODI6eJC0nLNaL5UaPA0pjGRsNlZWoUzieuKG08G/rQtj/8jLq/3eLICv1cbfvj7lDPc0thPwXdrPIC9nLSisb/wdLufpqXsFku9TeBqrRHfQWImybcv7JRAeZZeHEo+tvFvZg5MSAEiPmz8zIOJOKhuMKEXlOmALmSjEhW6Ca5r7xuQ5Qwm0=" diff --git a/.travis.yml b/.travis.yml index eaf2b867..ca73a2d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,82 +1,92 @@ --- -dist: xenial +# yamllint disable rule:line-length rule:truthy +os: linux +dist: focal language: ruby cache: bundler before_install: - - gem update --system - - gem update bundler + - yes | gem update --system - bundle --version script: - 'bundle exec rake $CHECK' -matrix: +jobs: fast_finish: true include: - - rvm: 2.4.4 - bundler_args: --without system_tests development release - env: PUPPET_VERSION="~> 5.0" CHECK=test - - rvm: 2.5.3 - bundler_args: --without system_tests development release - env: PUPPET_VERSION="~> 6.0" CHECK=test_with_coveralls - - rvm: 2.5.3 - bundler_args: --without system_tests development release - env: PUPPET_VERSION="~> 6.0" CHECK=rubocop - - rvm: 2.4.4 - bundler_args: --without system_tests development release - env: PUPPET_VERSION="~> 5.0" CHECK=build DEPLOY_TO_FORGE=yes - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=debian9-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=debian9-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=fedora29-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=fedora29-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=fedora30-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=fedora30-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=ubuntu1604-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=ubuntu1604-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_debug=true BEAKER_setfile=ubuntu1804-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker - - rvm: 2.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_debug=true BEAKER_setfile=ubuntu1804-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker + - rvm: 2.4.4 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 5.0" CHECK=test + - rvm: 2.5.3 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 6.0" CHECK=test_with_coveralls + - rvm: 2.5.3 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 6.0" CHECK=rubocop + - rvm: 2.4.4 + bundler_args: --without system_tests development release + env: PUPPET_VERSION="~> 5.0" CHECK=build DEPLOY_TO_FORGE=yes + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=centos7-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=centos7-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=debian9-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=debian9-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=debian10-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=debian10-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=fedora30-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=fedora30-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=fedora31-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=fedora31-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=ubuntu1604-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=ubuntu1604-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet5 BEAKER_setfile=ubuntu1804-64 CHECK=beaker + services: docker + - rvm: 2.5.3 + bundler_args: --without development release + env: BEAKER_PUPPET_COLLECTION=puppet6 BEAKER_setfile=ubuntu1804-64 CHECK=beaker + services: docker branches: only: - - master - - /^v\d/ + - master + - /^v\d/ notifications: email: false + webhooks: https://voxpupu.li/incoming/travis irc: on_success: always on_failure: always @@ -84,7 +94,7 @@ notifications: - "chat.freenode.org#voxpupuli-notifications" deploy: provider: puppetforge - user: puppet + username: puppet password: secure: "n/CVUS2upgv5DifCm/YsjBxR/11bdTRDYi1x9QK6ILa32+6ngVV2RQaIMXXJfJKYIPT8/O21tpc9C7fOBRGhRpNbl0usfvqsZS0C9UkpEx6AqT7lcRzj6pLrNn3IuChhZ0tQjNiKp9LxVTzltxr5uTFwKKCE4o534v/DLAzkzq5EAZuBWpRS1rcVHQA3o0767Gu3601yyYkZj9ySDH5RpbSdTCcNkTzwtFhr2NEvVb+2FI0RhchDSqPBfNWHV4Hn3dKuL42MNC2zjd2FYFpC8F27OXk/erUZIOZFfpZuIWypjSimfVC95a2Nb8kfQotTvQxUI1fwiB01ibUQGGkJj+mh7Utg/byBrbijpJnWRR7TT6oQ1NbIUHVXcqE1tfpbCBZ4Ws2Hqji0QoGc0fMrkt1NVlZlgbVrb9t+ctb1QcLaEPI+1Zf2a3AZhXOKA1EGx2W5DTQSWSPv57BUtFPICZENQi/ats30h+0FwtN7rjfx8Q6BIGO2D5JODI6eJC0nLNaL5UaPA0pjGRsNlZWoUzieuKG08G/rQtj/8jLq/3eLICv1cbfvj7lDPc0thPwXdrPIC9nLSisb/wdLufpqXsFku9TeBqrRHfQWImybcv7JRAeZZeHEo+tvFvZg5MSAEiPmz8zIOJOKhuMKEXlOmALmSjEhW6Ca5r7xuQ5Qwm0=" on: diff --git a/.travis/setup.sh b/.travis/setup.sh deleted file mode 100644 index ae1a0438..00000000 --- a/.travis/setup.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# THIS FILE IS MANAGED BY MODULESYNC - -rm -f Gemfile.lock -if [ "${PUPPET_VERSION}" = '~> 4.0' ]; then - gem install bundler -v '< 2' --no-rdoc --no-ri; -else - gem update --system; - gem update bundler; - bundle --version; -fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 435e59bf..0190af32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,72 @@ All notable changes to this project will be documented in this file. Each new release typically also includes the latest modulesync defaults. These should not affect the functionality of the module. -## [v4.0.0](https://github.com/voxpupuli/puppet-letsencrypt/tree/v4.0.0) (2019-03-27) +## [v6.0.0](https://github.com/voxpupuli/puppet-letsencrypt/tree/v6.0.0) (2020-09-11) + +[Full Changelog](https://github.com/voxpupuli/puppet-letsencrypt/compare/v5.0.0...v6.0.0) + +**Breaking changes:** + +- modulesync 2.10.0 / Drop FreeBSD 10 / Add FreeBSD 12 [\#213](https://github.com/voxpupuli/puppet-letsencrypt/pull/213) ([dhoppe](https://github.com/dhoppe)) + +**Implemented enhancements:** + +- add manifest to install dns-route53 plugin, along with tests [\#225](https://github.com/voxpupuli/puppet-letsencrypt/pull/225) ([aripringle](https://github.com/aripringle)) +- Add `cert_name` parameter to `letsencrypt::certonly` [\#219](https://github.com/voxpupuli/puppet-letsencrypt/pull/219) ([saimonn](https://github.com/saimonn)) + +**Closed issues:** + +- typo in example [\#227](https://github.com/voxpupuli/puppet-letsencrypt/issues/227) +- update metadata.json [\#218](https://github.com/voxpupuli/puppet-letsencrypt/issues/218) + +**Merged pull requests:** + +- modulesync 3.0.0 & puppet-lint updates [\#229](https://github.com/voxpupuli/puppet-letsencrypt/pull/229) ([bastelfreak](https://github.com/bastelfreak)) +- fix typo in renew example [\#228](https://github.com/voxpupuli/puppet-letsencrypt/pull/228) ([milesstoetzner](https://github.com/milesstoetzner)) +- Use voxpupuli-acceptance [\#224](https://github.com/voxpupuli/puppet-letsencrypt/pull/224) ([ekohl](https://github.com/ekohl)) +- Ensure EPEL is configured before installing plugin [\#222](https://github.com/voxpupuli/puppet-letsencrypt/pull/222) ([alexjfisher](https://github.com/alexjfisher)) +- \#218 Switch to puppet-epel [\#221](https://github.com/voxpupuli/puppet-letsencrypt/pull/221) ([kallies](https://github.com/kallies)) +- Add Fedora 31, drop Fedora 29 [\#216](https://github.com/voxpupuli/puppet-letsencrypt/pull/216) ([ekohl](https://github.com/ekohl)) +- delete legacy travis directory [\#214](https://github.com/voxpupuli/puppet-letsencrypt/pull/214) ([bastelfreak](https://github.com/bastelfreak)) +- add --keep-until-expiring closer to letsencrypt command in cron [\#211](https://github.com/voxpupuli/puppet-letsencrypt/pull/211) ([pulecp](https://github.com/pulecp)) +- allow puppetlabs/inifile 4.x [\#210](https://github.com/voxpupuli/puppet-letsencrypt/pull/210) ([bastelfreak](https://github.com/bastelfreak)) + +## [v5.0.0](https://github.com/voxpupuli/puppet-letsencrypt/tree/v5.0.0) (2019-10-09) + +[Full Changelog](https://github.com/voxpupuli/puppet-letsencrypt/compare/v4.0.0...v5.0.0) + +**Breaking changes:** + +- remove params.pp and change some defaults values [\#205](https://github.com/voxpupuli/puppet-letsencrypt/pull/205) ([Dan33l](https://github.com/Dan33l)) +- Drop Ubuntu 14.04 & add Debian 9/10 / Fedora 29/30 support [\#193](https://github.com/voxpupuli/puppet-letsencrypt/pull/193) ([ekohl](https://github.com/ekohl)) + +**Implemented enhancements:** + +- replace server urls with v2 urls [\#196](https://github.com/voxpupuli/puppet-letsencrypt/issues/196) +- Option to clean up cronjobs for removed domains [\#175](https://github.com/voxpupuli/puppet-letsencrypt/issues/175) +- update version shiped with vcs method to 0.39.0 [\#207](https://github.com/voxpupuli/puppet-letsencrypt/pull/207) ([Dan33l](https://github.com/Dan33l)) +- use ACME API v2 [\#206](https://github.com/voxpupuli/puppet-letsencrypt/pull/206) ([Dan33l](https://github.com/Dan33l)) +- feat\(facts\): add facts about certificates [\#187](https://github.com/voxpupuli/puppet-letsencrypt/pull/187) ([minorOffense](https://github.com/minorOffense)) + +**Fixed bugs:** + +- fix modulesync config file [\#201](https://github.com/voxpupuli/puppet-letsencrypt/pull/201) ([bastelfreak](https://github.com/bastelfreak)) + +**Closed issues:** + +- python2-certbot-dns-rfc2136 doesn't exist in debian buster [\#191](https://github.com/voxpupuli/puppet-letsencrypt/issues/191) +- letsencrypt failed to generate certificate [\#184](https://github.com/voxpupuli/puppet-letsencrypt/issues/184) +- `$letsencrypt::venv_path` is undocumented [\#21](https://github.com/voxpupuli/puppet-letsencrypt/issues/21) + +**Merged pull requests:** + +- release 5.0.0 [\#208](https://github.com/voxpupuli/puppet-letsencrypt/pull/208) ([Dan33l](https://github.com/Dan33l)) +- use puppet strings [\#204](https://github.com/voxpupuli/puppet-letsencrypt/pull/204) ([Dan33l](https://github.com/Dan33l)) +- Raise upper bound version of stdlib & vcsrepo [\#202](https://github.com/voxpupuli/puppet-letsencrypt/pull/202) ([mfaure](https://github.com/mfaure)) +- Fix type in readme: deploy\_hooks\_commands -\> deploy\_hook\_commands [\#188](https://github.com/voxpupuli/puppet-letsencrypt/pull/188) ([2ZZ](https://github.com/2ZZ)) +- Allow puppetlabs/inifile 3.x [\#186](https://github.com/voxpupuli/puppet-letsencrypt/pull/186) ([dhoppe](https://github.com/dhoppe)) + +## [v4.0.0](https://github.com/voxpupuli/puppet-letsencrypt/tree/v4.0.0) (2019-03-29) [Full Changelog](https://github.com/voxpupuli/puppet-letsencrypt/compare/v3.0.0...v4.0.0) diff --git a/Dockerfile b/Dockerfile index 67048bb4..6fd63422 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN bundle install --without system_tests development release --path=${BUNDLE_PA COPY . . RUN bundle install -RUN bundle exec release_checks +RUN bundle exec rake release_checks # Container should not saved RUN exit 1 diff --git a/Gemfile b/Gemfile index 9571ef3c..2fce93ce 100644 --- a/Gemfile +++ b/Gemfile @@ -11,25 +11,9 @@ def location_for(place, fake_version = nil) end group :test do - gem 'puppetlabs_spec_helper', '>= 2.14.0', :require => false - gem 'rspec-puppet-facts', '>= 1.8.0', :require => false - gem 'rspec-puppet-utils', :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 'puppet-lint-absolute_classname-check', :require => false - gem 'puppet-lint-topscope-variable-check', :require => false - gem 'metadata-json-lint', :require => false - gem 'redcarpet', :require => false - gem 'rubocop', '~> 0.49.1', :require => false - gem 'rubocop-rspec', '~> 1.15.0', :require => false - gem 'mocha', '~> 1.4.0', :require => false - gem 'coveralls', :require => false - gem 'simplecov-console', :require => false - gem 'parallel_tests', :require => false + gem 'voxpupuli-test', '~> 2.1', :require => false + gem 'coveralls', :require => false + gem 'simplecov-console', :require => false end group :development do @@ -40,32 +24,13 @@ group :development do end group :system_tests do - gem 'winrm', :require => false - if beaker_version = ENV['BEAKER_VERSION'] - gem 'beaker', *location_for(beaker_version) - else - gem 'beaker', '>= 4.2.0', :require => false - 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 'serverspec', :require => false - gem 'beaker-hostgenerator', '>= 1.1.22', :require => false - gem 'beaker-docker', :require => false - gem 'beaker-puppet', :require => false - gem 'beaker-puppet_install_helper', :require => false - gem 'beaker-module_install_helper', :require => false - gem 'rbnacl', '>= 4', :require => false - gem 'rbnacl-libsodium', :require => false - gem 'bcrypt_pbkdf', :require => false + gem 'voxpupuli-acceptance', :require => false end group :release do - gem 'github_changelog_generator', :require => false, :git => 'https://github.com/github-changelog-generator/github-changelog-generator' + gem 'github_changelog_generator', :require => false, :git => 'https://github.com/voxpupuli/github-changelog-generator', :branch => 'voxpupuli_essential_fixes' gem 'puppet-blacksmith', :require => false - gem 'voxpupuli-release', :require => false, :git => 'https://github.com/voxpupuli/voxpupuli-release-gem' + gem 'voxpupuli-release', :require => false gem 'puppet-strings', '>= 2.2', :require => false end diff --git a/README.md b/README.md index 1d9b4a7c..dfe2141a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ versions are defined in the [metadata.json](metadata.json) On EL (Red Hat, CentOS etc.) systems, the EPEL repository needs to be enabled for the Let's Encrypt client package. -The module can integrate with [stahnma/epel](https://forge.puppetlabs.com/stahnma/epel) +The module can integrate with [puppet/epel](https://forge.puppetlabs.com/puppet/epel) to set up the repo by setting the `configure_epel` parameter to `true` (the default for RedHat) and installing the module. @@ -166,6 +166,39 @@ letsencrypt::certonly { 'foo': plugin => 'dns-rfc2136', } ``` +#### dns-ovh plugin + +To request a certificate using the `dns-ovh` plugin, you will at a minimum +need to pass `endpoint`, `application_key`, `application_secret` and +`consumer_key`to the class `letsencrypt::plugin::dns_ovh`. +Ideally keys and secret should be encrypted, eg. with eyaml if using Hiera. + +Plugin documentation and it's parameters can be found here: +https://certbot-dns-ovh.readthedocs.io + +Note: + +For Debian based OS, this plugin is compatible from Debian 10 +and Ubuntu 19. Older OS are not supported. + +Parameter defaults: + +- `propagation_seconds` 30 (the plugin defaults to 30) + +Example: + +```puppet +class { 'letsencrypt::plugin::dns_ovh': + endpoint => 'ovh-eu', + application_key => 'MDAwMDAwMDAwMDAw', + application_secret => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', + consumer_key => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', +} +letsencrypt::certonly { 'foo': + domains => ['foo.example.com', 'bar.example.com'], + plugin => 'dns-ovh', +} +``` #### Additional arguments @@ -201,7 +234,7 @@ class { 'letsencrypt': email => 'foo@example.com', server => 'https://acme-v01.api.letsencrypt.org/directory', }, - renew_cron_ensure: 'present', + renew_cron_ensure => 'present', } ``` diff --git a/REFERENCE.md b/REFERENCE.md new file mode 100644 index 00000000..c3459d5d --- /dev/null +++ b/REFERENCE.md @@ -0,0 +1,811 @@ +# Reference + + +## Table of Contents + +**Classes** + +_Public Classes_ + +* [`letsencrypt`](#letsencrypt): Install and configure Certbot, the LetsEncrypt client +* [`letsencrypt::install`](#letsencryptinstall): Installs the Let's Encrypt client. +* [`letsencrypt::plugin::dns_rfc2136`](#letsencryptplugindns_rfc2136): Installs and configures the dns-rfc2136 plugin +* [`letsencrypt::renew`](#letsencryptrenew): Configures renewal of Let's Encrypt certificates using Certbot + +_Private Classes_ + +* `letsencrypt::config`: Configures the Let's Encrypt client. + +**Defined types** + +* [`letsencrypt::certonly`](#letsencryptcertonly): Request a certificate using the `certonly` installer +* [`letsencrypt::hook`](#letsencrypthook): Creates hook scripts. + +**Functions** + +* [`letsencrypt::letsencrypt_lookup`](#letsencryptletsencrypt_lookup): + +**Data types** + +* [`Letsencrypt::Cron::Hour`](#letsencryptcronhour): mimic hour setting in cron as defined in man 5 crontab +* [`Letsencrypt::Cron::Minute`](#letsencryptcronminute): mimic minute setting in cron as defined in man 5 crontab +* [`Letsencrypt::Cron::Monthday`](#letsencryptcronmonthday): mimic monthday setting in cron as defined in man 5 crontab +* [`Letsencrypt::Plugin`](#letsencryptplugin): List of accepted plugins + +## Classes + +### letsencrypt + +Install and configure Certbot, the LetsEncrypt client + +#### Examples + +```puppet +class { 'letsencrypt' : + email => 'letsregister@example.com', + config => { + 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', + }, +} +``` + +#### Parameters + +The following parameters are available in the `letsencrypt` class. + +##### `email` + +Data type: `Optional[String]` + +The email address to use to register with Let's Encrypt. This takes +precedence over an 'email' setting defined in $config. + +Default value: `undef` + +##### `path` + +Data type: `String` + +The path to the letsencrypt installation. + +Default value: '/opt/letsencrypt' + +##### `venv_path` + +Data type: `Any` + +virtualenv path for vcs-installed Certbot + +Default value: '/opt/letsencrypt/.venv' + +##### `environment` + +Data type: `Array` + +An optional array of environment variables (in addition to VENV_PATH) + +Default value: [] + +##### `repo` + +Data type: `String` + +A Git URL to install the Let's encrypt client from. + +Default value: 'https://github.com/certbot/certbot.git' + +##### `version` + +Data type: `String` + +The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. + +Default value: 'v0.39.0' + +##### `package_name` + +Data type: `String` + +Name of package and command to use when installing the client with the `package` method. + +Default value: 'certbot' + +##### `package_ensure` + +Data type: `Any` + +The value passed to `ensure` when installing the client with the `package` method. + +Default value: 'installed' + +##### `package_command` + +Data type: `String` + +Path or name for letsencrypt executable when installing the client with the `package` method. + +Default value: 'certbot' + +##### `config_file` + +Data type: `String` + +The path to the configuration file for the letsencrypt cli. + +Default value: "${config_dir}/cli.ini" + +##### `config` + +Data type: `Hash` + +A hash representation of the letsencrypt configuration file. + +Default value: {'server' => 'https://acme-v02.api.letsencrypt.org/directory'} + +##### `cron_scripts_path` + +Data type: `String` + +The path for renewal scripts called by cron + +Default value: "${facts['puppet_vardir']}/letsencrypt" + +##### `cron_owner_group` + +Data type: `String` + +Group owner of cron renew scripts. + +Default value: 'root' + +##### `manage_config` + +Data type: `Boolean` + +A feature flag to toggle the management of the letsencrypt configuration file. + +Default value: `true` + +##### `manage_install` + +Data type: `Boolean` + +A feature flag to toggle the management of the letsencrypt client installation. + +Default value: `true` + +##### `manage_dependencies` + +Data type: `Boolean` + +A feature flag to toggle the management of the letsencrypt dependencies. + +Default value: `true` + +##### `configure_epel` + +Data type: `Boolean` + +A feature flag to include the 'epel' class and depend on it for package installation. + +##### `install_method` + +Data type: `Enum['package', 'vcs']` + +Method to install the letsencrypt client, either package or vcs. + +Default value: 'package' + +##### `agree_tos` + +Data type: `Boolean` + +A flag to agree to the Let's Encrypt Terms of Service. + +Default value: `true` + +##### `unsafe_registration` + +Data type: `Boolean` + +A flag to allow using the 'register-unsafely-without-email' flag. + +Default value: `false` + +##### `config_dir` + +Data type: `Stdlib::Unixpath` + +The path to the configuration directory. + +Default value: '/etc/letsencrypt' + +##### `key_size` + +Data type: `Integer[2048]` + +Size for the RSA public key + +Default value: 4096 + +##### `renew_pre_hook_commands` + +Data type: `Any` + +Array of commands to run in a shell before obtaining/renewing any certificates. + +Default value: [] + +##### `renew_post_hook_commands` + +Data type: `Any` + +Array of commands to run in a shell after attempting to obtain/renew certificates. + +Default value: [] + +##### `renew_deploy_hook_commands` + +Data type: `Any` + +Array of commands to run in a shell once for each successfully issued/renewed +certificate. Two environmental variables are supplied by certbot: +- $RENEWED_LINEAGE: Points to the live directory with the cert files and key. + Example: /etc/letsencrypt/live/example.com +- $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. + Example: "example.com www.example.com" + +Default value: [] + +##### `renew_additional_args` + +Data type: `Any` + +Array of additional command line arguments to pass to 'certbot renew'. + +Default value: [] + +##### `renew_cron_ensure` + +Data type: `Any` + +Intended state of the cron resource running certbot renew. + +Default value: 'absent' + +##### `renew_cron_hour` + +Data type: `Any` + +Optional string, integer or array of hour(s) the renewal command should run. +E.g. '[0,12]' to execute at midnight and midday. +hour. + +Default value: fqdn_rand(24) + +##### `renew_cron_minute` + +Data type: `Any` + +Optional string, integer or array of minute(s) the renewal command should +run. E.g. 0 or '00' or [0,30]. + +Default value: fqdn_rand(60, fqdn_rand_string(10)) + +##### `renew_cron_monthday` + +Data type: `Any` + +Optional string, integer or array of monthday(s) the renewal command should +run. E.g. '2-30/2' to run on even days. + +Default value: '*' + +### letsencrypt::install + +Installs the Let's Encrypt client. + +#### Parameters + +The following parameters are available in the `letsencrypt::install` class. + +##### `manage_install` + +Data type: `Boolean` + +A feature flag to toggle the management of the letsencrypt client installation. + +Default value: $letsencrypt::manage_install + +##### `manage_dependencies` + +Data type: `Boolean` + +A feature flag to toggle the management of the letsencrypt dependencies. + +Default value: $letsencrypt::manage_dependencies + +##### `configure_epel` + +Data type: `Boolean` + +A feature flag to include the 'epel' class and depend on it for package installation. + +Default value: $letsencrypt::configure_epel + +##### `install_method` + +Data type: `Enum['package', 'vcs']` + +Method to install the letsencrypt client + +Default value: $letsencrypt::install_method + +##### `path` + +Data type: `String` + +The path to the letsencrypt installation. + +Default value: $letsencrypt::path + +##### `repo` + +Data type: `String` + +A Git URL to install the Let's encrypt client from. + +Default value: $letsencrypt::repo + +##### `version` + +Data type: `String` + +The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. + +Default value: $letsencrypt::version + +##### `package_ensure` + +Data type: `String` + +The value passed to `ensure` when installing the client with the `package` method. + +Default value: $letsencrypt::package_ensure + +##### `package_name` + +Data type: `String` + +Name of package to use when installing the client with the `package` method. + +Default value: $letsencrypt::package_name + +### letsencrypt::plugin::dns_rfc2136 + +This class installs and configures the Let's Encrypt dns-rfc2136 plugin. +https://certbot-dns-rfc2136.readthedocs.io + +#### Parameters + +The following parameters are available in the `letsencrypt::plugin::dns_rfc2136` class. + +##### `server` + +Data type: `Stdlib::Host` + +Target DNS server. + +##### `key_name` + +Data type: `String[1]` + +TSIG key name. + +##### `key_secret` + +Data type: `String[1]` + +TSIG key secret. + +##### `key_algorithm` + +Data type: `String[1]` + +TSIG key algorithm. + +Default value: 'HMAC-SHA512' + +##### `port` + +Data type: `Stdlib::Port` + +Target DNS port. + +Default value: 53 + +##### `propagation_seconds` + +Data type: `Integer` + +Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. + +Default value: 10 + +##### `manage_package` + +Data type: `Boolean` + +Manage the plugin package. + +Default value: `true` + +##### `package_name` + +Data type: `String[1]` + +The name of the package to install when $manage_package is true. + +##### `config_dir` + +Data type: `Stdlib::Absolutepath` + +The path to the configuration directory. + +Default value: $letsencrypt::config_dir + +### letsencrypt::renew + +Configures renewal of Let's Encrypt certificates using the certbot renew command. + +Note: Hooks set here will run before/after/for ALL certificates, including +any not managed by Puppet. If you want to create hooks for specific +certificates only, create them using letsencrypt::certonly. + +#### Parameters + +The following parameters are available in the `letsencrypt::renew` class. + +##### `pre_hook_commands` + +Data type: `Variant[String[1], Array[String[1]]]` + +Array of commands to run in a shell before obtaining/renewing any certificates. + +Default value: $letsencrypt::renew_pre_hook_commands + +##### `post_hook_commands` + +Data type: `Variant[String[1], Array[String[1]]]` + +Array of commands to run in a shell after attempting to obtain/renew certificates. + +Default value: $letsencrypt::renew_post_hook_commands + +##### `deploy_hook_commands` + +Data type: `Variant[String[1], Array[String[1]]]` + +Array of commands to run in a shell once for each successfully issued/renewed +certificate. Two environmental variables are supplied by certbot: +- $RENEWED_LINEAGE: Points to the live directory with the cert files and key. + Example: /etc/letsencrypt/live/example.com +- $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. + Example: "example.com www.example.com" + +Default value: $letsencrypt::renew_deploy_hook_commands + +##### `additional_args` + +Data type: `Array[String[1]]` + +Array of additional command line arguments to pass to 'certbot renew'. + +Default value: $letsencrypt::renew_additional_args + +##### `cron_ensure` + +Data type: `Enum['present', 'absent']` + +Intended state of the cron resource running certbot renew + +Default value: $letsencrypt::renew_cron_ensure + +##### `cron_hour` + +Data type: `Letsencrypt::Cron::Hour` + +Optional string, integer or array of hour(s) the renewal command should run. +E.g. '[0,12]' to execute at midnight and midday. Default: fqdn-seeded random hour. + +Default value: $letsencrypt::renew_cron_hour + +##### `cron_minute` + +Data type: `Letsencrypt::Cron::Minute` + +Optional string, integer or array of minute(s) the renewal command should +run. E.g. 0 or '00' or [0,30]. Default: fqdn-seeded random minute. + +Default value: $letsencrypt::renew_cron_minute + +##### `cron_monthday` + +Data type: `Letsencrypt::Cron::Monthday` + +Optional string, integer or array of monthday(s) the renewal command should +run. E.g. '2-30/2' to run on even days. Default: Every day. + +Default value: $letsencrypt::renew_cron_monthday + +## Defined types + +### letsencrypt::certonly + +This type can be used to request a certificate using the `certonly` installer. + +#### Parameters + +The following parameters are available in the `letsencrypt::certonly` defined type. + +##### `ensure` + +Data type: `Enum['present','absent']` + +Intended state of the resource +Will remove certificates for specified domains if set to 'absent'. Will +also remove cronjobs and renewal scripts if `manage_cron` is set to 'true'. + +Default value: 'present' + +##### `domains` + +Data type: `Array[String[1]]` + +An array of domains to include in the CSR. + +Default value: [$title] + +##### `custom_plugin` + +Data type: `Boolean` + +Whether to use a custom plugin in additional_args and disable -a flag. + +Default value: `false` + +##### `plugin` + +Data type: `Letsencrypt::Plugin` + +The authenticator plugin to use when requesting the certificate. + +Default value: 'standalone' + +##### `webroot_paths` + +Data type: `Array[Stdlib::Unixpath]` + +An array of webroot paths for the domains in `domains`. +Required if using `plugin => 'webroot'`. If `domains` and +`webroot_paths` are not the same length, the last `webroot_paths` +element will be used for all subsequent domains. + +Default value: [] + +##### `letsencrypt_command` + +Data type: `String[1]` + +Command to run letsencrypt + +Default value: $letsencrypt::command + +##### `additional_args` + +Data type: `Array[String[1]]` + +An array of additional command line arguments to pass to the `letsencrypt-auto` command. + +Default value: [] + +##### `environment` + +Data type: `Array[String[1]]` + +An optional array of environment variables (in addition to VENV_PATH). + +Default value: [] + +##### `key_size` + +Data type: `Integer[2048]` + +Size for the RSA public key + +Default value: $letsencrypt::key_size + +##### `manage_cron` + +Data type: `Boolean` + +Indicating whether or not to schedule cron job for renewal. +Runs daily but only renews if near expiration, e.g. within 10 days. + +Default value: `false` + +##### `suppress_cron_output` + +Data type: `Boolean` + +Redirect cron output to devnull + +Default value: `false` + +##### `cron_before_command` + +Data type: `Optional[String[1]]` + +Representation of a command that should be run before renewal command + +Default value: `undef` + +##### `cron_success_command` + +Data type: `Optional[String[1]]` + +Representation of a command that should be run if the renewal command succeeds. + +Default value: `undef` + +##### `cron_hour` + +Data type: `Variant[Integer[0,23], String, Array]` + +Optional hour(s) that the renewal command should execute. +e.g. '[0,12]' execute at midnight and midday. Default - seeded random hour. + +Default value: fqdn_rand(24, $title) + +##### `cron_minute` + +Data type: `Variant[Integer[0,59], String, Array]` + +Optional minute(s) that the renewal command should execute. +e.g. 0 or '00' or [0,30]. Default - seeded random minute. + +Default value: fqdn_rand(60, fqdn_rand_string(10, $title)) + +##### `cron_monthday` + +Data type: `Array[Variant[Integer[0, 59], String[1]]]` + +Optional string, integer or array of monthday(s) the renewal command should +run. E.g. '2-30/2' to run on even days. Default: Every day. + +Default value: ['*'] + +##### `config_dir` + +Data type: `Stdlib::Unixpath` + +The path to the configuration directory. + +Default value: $letsencrypt::config_dir + +##### `pre_hook_commands` + +Data type: `Variant[String[1], Array[String[1]]]` + +Array of commands to run in a shell before attempting to obtain/renew the certificate. + +Default value: [] + +##### `post_hook_commands` + +Data type: `Variant[String[1], Array[String[1]]]` + +Array of command(s) to run in a shell after attempting to obtain/renew the certificate. + +Default value: [] + +##### `deploy_hook_commands` + +Data type: `Variant[String[1], Array[String[1]]]` + +Array of command(s) to run in a shell once if the certificate is successfully issued. +Two environmental variables are supplied by certbot: +- $RENEWED_LINEAGE: Points to the live directory with the cert files and key. + Example: /etc/letsencrypt/live/example.com +- $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. + Example: "example.com www.example.com" + +Default value: [] + +### letsencrypt::hook + +This type is used by letsencrypt::renew and letsencrypt::certonly to create hook scripts. + +#### Parameters + +The following parameters are available in the `letsencrypt::hook` defined type. + +##### `type` + +Data type: `Enum['pre', 'post', 'deploy']` + +Hook type. + +##### `hook_file` + +Data type: `String[1]` + +Path to deploy hook script. + +##### `commands` + +Data type: `Variant[String[1],Array[String[1]]]` + +Bash commands to execute when the hook is run by certbot. + +## Functions + +### letsencrypt::letsencrypt_lookup + +Type: Ruby 4.x API + +The letsencrypt::letsencrypt_lookup function. + +#### `letsencrypt::letsencrypt_lookup(Any $cn)` + +The letsencrypt::letsencrypt_lookup function. + +Returns: `Any` + +##### `cn` + +Data type: `Any` + + + +## Data types + +### Letsencrypt::Cron::Hour + +mimic hour setting in cron as defined in man 5 crontab + +Alias of `Variant[Integer[0,23], String[1], Array[ + Variant[ + Integer[0,23], + String[1], + ] + ]]` + +### Letsencrypt::Cron::Minute + +mimic minute setting in cron as defined in man 5 crontab + +Alias of `Variant[Integer[0,59], String[1], Array[ + Variant[ + Integer[0,59], + String[1], + ] + ]]` + +### Letsencrypt::Cron::Monthday + +mimic monthday setting in cron as defined in man 5 crontab + +Alias of `Variant[Integer[0,31], String[1], Array[ + Variant[ + Integer[0,31], + String[1], + ] + ]]` + +### Letsencrypt::Plugin + +List of accepted plugins + +Alias of `Enum['apache', 'standalone', 'webroot', 'nginx', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136']` + diff --git a/Rakefile b/Rakefile index 09701d0f..b450fe7b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,4 @@ -require 'puppetlabs_spec_helper/rake_tasks' +require 'voxpupuli/test/rake' # load optional tasks for releases # only available if gem group releases is installed @@ -7,47 +7,6 @@ begin rescue LoadError end -PuppetLint.configuration.log_format = '%{path}:%{line}:%{check}:%{KIND}:%{message}' -PuppetLint.configuration.absolute_classname_reverse = true - -exclude_paths = %w( - pkg/**/* - vendor/**/* - .vendor/**/* - spec/**/* -) -PuppetLint.configuration.ignore_paths = exclude_paths -PuppetSyntax.exclude_paths = exclude_paths - -desc 'Auto-correct puppet-lint offenses' -task 'lint:auto_correct' do - Rake::Task[:lint_fix].invoke -end - -desc 'Run acceptance tests' -RSpec::Core::RakeTask.new(:acceptance) do |t| - t.pattern = 'spec/acceptance' -end - -desc 'Run tests' -task test: [:release_checks] - -namespace :check do - desc 'Check for trailing whitespace' - task :trailing_whitespace do - Dir.glob('**/*.md', File::FNM_DOTMATCH).sort.each do |filename| - next if filename =~ %r{^((modules|acceptance|\.?vendor|spec/fixtures|pkg)/|REFERENCE.md)} - File.foreach(filename).each_with_index do |line, index| - if line =~ %r{\s\n$} - puts "#{filename} has trailing whitespace on line #{index + 1}" - exit 1 - end - end - end - end -end -Rake::Task[:release_checks].enhance ['check:trailing_whitespace'] - 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__)) @@ -77,6 +36,19 @@ begin metadata = JSON.load(File.read(metadata_json)) config.project = metadata['name'] 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 + rescue LoadError end # vim: syntax=ruby diff --git a/data/FreeBSD-family.yaml b/data/FreeBSD-family.yaml new file mode 100644 index 00000000..5e7cf810 --- /dev/null +++ b/data/FreeBSD-family.yaml @@ -0,0 +1,4 @@ +--- +letsencrypt::package_name: 'py27-certbot' +letsencrypt::config_dir: '/usr/local/etc/letsencrypt' +letsencrypt::cron_owner_group: 'wheel' diff --git a/data/OpenBSD-family.yaml b/data/OpenBSD-family.yaml new file mode 100644 index 00000000..be708595 --- /dev/null +++ b/data/OpenBSD-family.yaml @@ -0,0 +1,2 @@ +--- +letsencrypt::cron_owner_group: 'wheel' diff --git a/data/RedHat-family.yaml b/data/RedHat-family.yaml new file mode 100644 index 00000000..404b411c --- /dev/null +++ b/data/RedHat-family.yaml @@ -0,0 +1,4 @@ +--- +letsencrypt::configure_epel: true +letsencrypt::plugin::dns_rfc2136::package_name: 'python2-certbot-dns-rfc2136' +letsencrypt::plugin::dns_route53::package_name: 'python2-certbot-dns-route53' diff --git a/data/common.yaml b/data/common.yaml new file mode 100644 index 00000000..23925b49 --- /dev/null +++ b/data/common.yaml @@ -0,0 +1,2 @@ +--- +letsencrypt::configure_epel: false diff --git a/data/os/Debian/10.yaml b/data/os/Debian/10.yaml new file mode 100644 index 00000000..d0641b25 --- /dev/null +++ b/data/os/Debian/10.yaml @@ -0,0 +1,3 @@ +--- +letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136' +letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53' diff --git a/data/os/Fedora.yaml b/data/os/Fedora.yaml new file mode 100644 index 00000000..56c3cd56 --- /dev/null +++ b/data/os/Fedora.yaml @@ -0,0 +1,4 @@ +--- +letsencrypt::configure_epel: false +letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136' +letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53' diff --git a/data/os/Ubuntu/18.04.yaml b/data/os/Ubuntu/18.04.yaml new file mode 100644 index 00000000..d0641b25 --- /dev/null +++ b/data/os/Ubuntu/18.04.yaml @@ -0,0 +1,3 @@ +--- +letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136' +letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53' diff --git a/hiera.yaml b/hiera.yaml new file mode 100644 index 00000000..2058ed68 --- /dev/null +++ b/hiera.yaml @@ -0,0 +1,19 @@ +--- +version: 5 + +defaults: + datadir: 'data' + data_hash: 'yaml_data' + +hierarchy: + - name: 'Operating System Major Release' + path: 'os/%{facts.os.name}/%{facts.os.release.major}.yaml' + + - name: 'Operating System' + path: 'os/%{facts.os.name}.yaml' + + - name: 'Operating System Family' + path: '%{facts.os.family}-family.yaml' + + - name: 'common' + path: 'common.yaml' diff --git a/manifests/certonly.pp b/manifests/certonly.pp index 5eaacdd1..fa544578 100644 --- a/manifests/certonly.pp +++ b/manifests/certonly.pp @@ -1,52 +1,43 @@ -# == Defined Type: letsencrypt::certonly +# @summary Request a certificate using the `certonly` installer # -# This type can be used to request a certificate using the `certonly` -# installer. +# This type can be used to request a certificate using the `certonly` installer. # -# === Parameters: -# -# [*ensure*] -# Intended state of the resource. Accepts either 'present' or 'absent'. -# Default: 'present'. +# @param ensure +# Intended state of the resource # Will remove certificates for specified domains if set to 'absent'. Will # also remove cronjobs and renewal scripts if `manage_cron` is set to 'true'. -# [*domains*] -# Namevar. An array of domains to include in the CSR. -# [*custom_plugin*] -# Whether to use a custom plugin in additional_args and disable -a flag. -# [*plugin*] -# The authenticator plugin to use when requesting the certificate. -# [*webroot_paths*] +# @param domains +# An array of domains to include in the CSR. +# @param custom_plugin Whether to use a custom plugin in additional_args and disable -a flag. +# @param plugin The authenticator plugin to use when requesting the certificate. +# @param webroot_paths # An array of webroot paths for the domains in `domains`. # Required if using `plugin => 'webroot'`. If `domains` and # `webroot_paths` are not the same length, the last `webroot_paths` # element will be used for all subsequent domains. -# [*letsencrypt_command*] -# Command to run letsencrypt -# [*additional_args*] -# An array of additional command line arguments to pass to the -# `letsencrypt-auto` command. -# [*environment*] -# An optional array of environment variables (in addition to VENV_PATH). -# [*manage_cron*] -# Boolean indicating whether or not to schedule cron job for renewal. Default: 'false'. +# @param letsencrypt_command Command to run letsencrypt +# @param additional_args An array of additional command line arguments to pass to the `letsencrypt-auto` command. +# @param environment An optional array of environment variables (in addition to VENV_PATH). +# @param key_size Size for the RSA public key +# @param manage_cron +# Indicating whether or not to schedule cron job for renewal. # Runs daily but only renews if near expiration, e.g. within 10 days. -# [*cron_before_command*] -# String representation of a command that should be run before renewal command -# [*cron_success_command*] -# String representation of a command that should be run if the renewal command -# succeeds. -# [*cron_hour*] -# Optional string, integer or array, hour(s) that the renewal command should execute. +# @param suppress_cron_output Redirect cron output to devnull +# @param cron_before_command Representation of a command that should be run before renewal command +# @param cron_success_command Representation of a command that should be run if the renewal command succeeds. +# @param cron_hour +# Optional hour(s) that the renewal command should execute. # e.g. '[0,12]' execute at midnight and midday. Default - seeded random hour. -# [*cron_minute*] -# Optional string, integer or array, minute(s) that the renewal command should execute. +# @param cron_minute +# Optional minute(s) that the renewal command should execute. # e.g. 0 or '00' or [0,30]. Default - seeded random minute. -# [*pre_hook_commands*] -# Array of commands to run in a shell before attempting to obtain/renew the certificate. -# [*post_hook_commands*] -# Array of command(s) to run in a shell after attempting to obtain/renew the certificate. -# [*deploy_hook_commands*] +# @param cron_monthday +# Optional string, integer or array of monthday(s) the renewal command should +# run. E.g. '2-30/2' to run on even days. Default: Every day. +# @param config_dir The path to the configuration directory. +# @param pre_hook_commands Array of commands to run in a shell before attempting to obtain/renew the certificate. +# @param post_hook_commands Array of command(s) to run in a shell after attempting to obtain/renew the certificate. +# @param deploy_hook_commands # Array of command(s) to run in a shell once if the certificate is successfully issued. # Two environmental variables are supplied by certbot: # - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. @@ -57,6 +48,7 @@ define letsencrypt::certonly ( Enum['present','absent'] $ensure = 'present', Array[String[1]] $domains = [$title], + String[1] $cert_name = $title, Boolean $custom_plugin = false, Letsencrypt::Plugin $plugin = 'standalone', Array[Stdlib::Unixpath] $webroot_paths = [], @@ -76,7 +68,6 @@ Variant[String[1], Array[String[1]]] $post_hook_commands = [], Variant[String[1], Array[String[1]]] $deploy_hook_commands = [], ) { - if $plugin == 'webroot' and empty($webroot_paths) { fail("The 'webroot_paths' parameter must be specified when using the 'webroot' plugin") } @@ -95,7 +86,6 @@ } case $plugin { - 'webroot': { $_plugin_args = zip($domains, $webroot_paths).map |$domain| { if $domain[1] { @@ -104,26 +94,37 @@ "-d '${domain[0]}'" } } - $plugin_args = ["--cert-name '${title}'"] + $_plugin_args + $plugin_args = ["--cert-name '${cert_name}'"] + $_plugin_args } 'dns-rfc2136': { require letsencrypt::plugin::dns_rfc2136 $_domains = join($domains, '\' -d \'') $plugin_args = [ - "--cert-name '${title}' -d", + "--cert-name '${cert_name}' -d", "'${_domains}'", "--dns-rfc2136-credentials ${letsencrypt::plugin::dns_rfc2136::config_dir}/dns-rfc2136.ini", "--dns-rfc2136-propagation-seconds ${letsencrypt::plugin::dns_rfc2136::propagation_seconds}", ] } + 'dns-ovh': { + require letsencrypt::plugin::dns_ovh + $_domains = join($domains, '\' -d \'') + $plugin_args = [ + "--cert-name '${cert_name}' -d", + "'${_domains}'", + "--dns-ovh-credentials ${letsencrypt::plugin::dns_ovh::config_file}", + "--dns-ovh-propagation-seconds ${letsencrypt::plugin::dns_ovh::propagation_seconds}", + ] + } + default: { if $ensure == 'present' { $_domains = join($domains, '\' -d \'') - $plugin_args = "--cert-name '${title}' -d '${_domains}'" + $plugin_args = "--cert-name '${cert_name}' -d '${_domains}'" } else { - $plugin_args = "--cert-name '${title}'" + $plugin_args = "--cert-name '${cert_name}'" } } } @@ -146,19 +147,19 @@ } # certbot uses --cert-name to generate the file path - $live_path_certname = regsubst($title, '^\*\.', '') + $live_path_certname = regsubst($cert_name, '^\*\.', '') $live_path = "${config_dir}/live/${live_path_certname}/cert.pem" $_command = flatten([ - $letsencrypt_command, - $default_args, - $plugin_args, - $hook_args, - $additional_args, + $letsencrypt_command, + $default_args, + $plugin_args, + $hook_args, + $additional_args, ]).filter | $arg | { $arg =~ NotUndef and $arg != [] } $command = join($_command, ' ') - $execution_environment = [ "VENV_PATH=${letsencrypt::venv_path}", ] + $environment + $execution_environment = ["VENV_PATH=${letsencrypt::venv_path}",] + $environment $verify_domains = join(unique($domains), '\' \'') if $ensure == 'present' { @@ -180,7 +181,7 @@ } if $manage_cron { - $maincommand = join($_command + ['--keep-until-expiring'], ' ') + $maincommand = join(["${letsencrypt_command} --keep-until-expiring"] + $_command[1,-1], ' ') $cron_script_ensure = $ensure ? { 'present' => 'file', default => 'absent' } $cron_ensure = $ensure diff --git a/manifests/config.pp b/manifests/config.pp index 8a9a271e..1ad1a0b2 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -1,6 +1,6 @@ -# == Class: letsencrypt +# @summary Configures the Let's Encrypt client. # -# This class configures the Let's Encrypt client. This is a private class. +# @api private # class letsencrypt::config ( $config_dir = $letsencrypt::config_dir, @@ -10,7 +10,6 @@ $unsafe_registration = $letsencrypt::unsafe_registration, $agree_tos = $letsencrypt::agree_tos, ) { - assert_private() unless $agree_tos { @@ -25,7 +24,7 @@ } if $email { - $_config = merge($config, {'email' => $email}) + $_config = merge($config, { 'email' => $email }) } else { $_config = $config } diff --git a/manifests/hook.pp b/manifests/hook.pp index 99d89632..aa2ee2b2 100644 --- a/manifests/hook.pp +++ b/manifests/hook.pp @@ -1,24 +1,17 @@ -# == Defined Type: letsencrypt::hook +# @summary Creates hook scripts. # -# This type is used by letsencrypt::renew and letsencrypt::certonly to create -# hook scripts. +# This type is used by letsencrypt::renew and letsencrypt::certonly to create hook scripts. # -# === Parameters: -# -# [*type*] -# Hook type. Can be pre, post or deploy. -# [*hook_file*] -# Path to deploy hook script. -# [*commands*] -# String or array of bash commands to execute when the hook is run by certbot. +# @param type Hook type. +# @param hook_file Path to deploy hook script. +# @param commands Bash commands to execute when the hook is run by certbot. # define letsencrypt::hook ( Enum['pre', 'post', 'deploy'] $type, String[1] $hook_file, # hook.sh.epp will validate this - $commands, + Variant[String[1],Array[String[1]]] $commands, ) { - $validate_env = $type ? { 'deploy' => true, default => false, @@ -30,11 +23,10 @@ group => 'root', mode => '0755', content => epp('letsencrypt/hook.sh.epp', { - commands => $commands, - validate_env => $validate_env, + commands => $commands, + validate_env => $validate_env, }), # Defined in letsencrypt::config require => File['letsencrypt-renewal-hooks-puppet'], } - } diff --git a/manifests/init.pp b/manifests/init.pp index 9a62a640..d72707b2 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,89 +1,94 @@ -# == Class: letsencrypt +# @summary Install and configure Certbot, the LetsEncrypt client # -# This class installs and configures the Let's Encrypt client. +# Install and configure Certbot, the LetsEncrypt client # -# === Parameters: +# @example +# class { 'letsencrypt' : +# email => 'letsregister@example.com', +# config => { +# 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', +# }, +# } # -# [*email*] +# @param email # The email address to use to register with Let's Encrypt. This takes # precedence over an 'email' setting defined in $config. -# [*path*] -# The path to the letsencrypt installation. -# [*environment*] -# An optional array of environment variables (in addition to VENV_PATH) -# [*repo*] -# A Git URL to install the Let's encrypt client from. -# [*version*] -# The Git ref (tag, sha, branch) to check out when installing the client with -# the `vcs` method. -# [*package_ensure*] -# The value passed to `ensure` when installing the client with the `package` -# method. -# [*package_name*] -# Name of package and command to use when installing the client with the -# `package` method. -# [*package_command*] -# Path or name for letsencrypt executable when installing the client with -# the `package` method. -# [*config_dir*] -# The path to the configuration directory. -# [*config_file*] -# The path to the configuration file for the letsencrypt cli. -# [*config*] -# A hash representation of the letsencrypt configuration file. -# [*manage_config*] -# A feature flag to toggle the management of the letsencrypt configuration -# file. -# [*manage_install*] -# A feature flag to toggle the management of the letsencrypt client -# installation. -# [*manage_dependencies*] -# A feature flag to toggle the management of the letsencrypt dependencies. -# [*configure_epel*] -# A feature flag to include the 'epel' class and depend on it for package -# installation. -# [*install_method*] -# Method to install the letsencrypt client, either package or vcs. -# [*agree_tos*] -# A flag to agree to the Let's Encrypt Terms of Service. -# [*unsafe_registration*] -# A flag to allow using the 'register-unsafely-without-email' flag. -# [*cron_scripts_path*] -# The path to put the script we'll call with cron. Defaults to $puppet_vardir/letsencrypt. +# @param path The path to the letsencrypt installation. +# @param venv_path virtualenv path for vcs-installed Certbot +# @param environment An optional array of environment variables (in addition to VENV_PATH) +# @param repo A Git URL to install the Let's encrypt client from. +# @param version The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. +# @param package_name Name of package and command to use when installing the client with the `package` method. +# @param package_ensure The value passed to `ensure` when installing the client with the `package` method. +# @param package_command Path or name for letsencrypt executable when installing the client with the `package` method. +# @param config_file The path to the configuration file for the letsencrypt cli. +# @param config A hash representation of the letsencrypt configuration file. +# @param cron_scripts_path The path for renewal scripts called by cron +# @param cron_owner_group Group owner of cron renew scripts. +# @param manage_config A feature flag to toggle the management of the letsencrypt configuration file. +# @param manage_install A feature flag to toggle the management of the letsencrypt client installation. +# @param manage_dependencies A feature flag to toggle the management of the letsencrypt dependencies. +# @param configure_epel A feature flag to include the 'epel' class and depend on it for package installation. +# @param install_method Method to install the letsencrypt client, either package or vcs. +# @param agree_tos A flag to agree to the Let's Encrypt Terms of Service. +# @param unsafe_registration A flag to allow using the 'register-unsafely-without-email' flag. +# @param config_dir The path to the configuration directory. +# @param key_size Size for the RSA public key +# @param renew_pre_hook_commands Array of commands to run in a shell before obtaining/renewing any certificates. +# @param renew_post_hook_commands Array of commands to run in a shell after attempting to obtain/renew certificates. +# @param renew_deploy_hook_commands +# Array of commands to run in a shell once for each successfully issued/renewed +# certificate. Two environmental variables are supplied by certbot: +# - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. +# Example: /etc/letsencrypt/live/example.com +# - $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. +# Example: "example.com www.example.com" +# @param renew_additional_args Array of additional command line arguments to pass to 'certbot renew'. +# @param renew_cron_ensure Intended state of the cron resource running certbot renew. +# @param renew_cron_hour +# Optional string, integer or array of hour(s) the renewal command should run. +# E.g. '[0,12]' to execute at midnight and midday. +# hour. +# @param renew_cron_minute +# Optional string, integer or array of minute(s) the renewal command should +# run. E.g. 0 or '00' or [0,30]. +# @param renew_cron_monthday +# Optional string, integer or array of monthday(s) the renewal command should +# run. E.g. '2-30/2' to run on even days. # class letsencrypt ( + Boolean $configure_epel, Optional[String] $email = undef, - String $path = $letsencrypt::params::path, - $venv_path = $letsencrypt::params::venv_path, + String $path = '/opt/letsencrypt', + $venv_path = '/opt/letsencrypt/.venv', Array $environment = [], - String $repo = $letsencrypt::params::repo, - String $version = $letsencrypt::params::version, - String $package_name = $letsencrypt::params::package_name, - $package_ensure = $letsencrypt::params::package_ensure, - String $package_command = $letsencrypt::params::package_command, - String $config_file = $letsencrypt::params::config_file, - Hash $config = $letsencrypt::params::config, - String $cron_scripts_path = $letsencrypt::params::cron_scripts_path, - Boolean $manage_config = $letsencrypt::params::manage_config, - Boolean $manage_install = $letsencrypt::params::manage_install, - Boolean $manage_dependencies = $letsencrypt::params::manage_dependencies, - Boolean $configure_epel = $letsencrypt::params::configure_epel, - Enum['package', 'vcs'] $install_method = $letsencrypt::params::install_method, - Boolean $agree_tos = $letsencrypt::params::agree_tos, - Boolean $unsafe_registration = $letsencrypt::params::unsafe_registration, - Stdlib::Unixpath $config_dir = $letsencrypt::params::config_dir, + String $repo = 'https://github.com/certbot/certbot.git', + String $version = 'v0.39.0', + String $package_name = 'certbot', + $package_ensure = 'installed', + String $package_command = 'certbot', + Stdlib::Unixpath $config_dir = '/etc/letsencrypt', + String $config_file = "${config_dir}/cli.ini", + Hash $config = { 'server' => 'https://acme-v02.api.letsencrypt.org/directory' }, + String $cron_scripts_path = "${facts['puppet_vardir']}/letsencrypt", + String $cron_owner_group = 'root', + Boolean $manage_config = true, + Boolean $manage_install = true, + Boolean $manage_dependencies = true, + Enum['package', 'vcs'] $install_method = 'package', + Boolean $agree_tos = true, + Boolean $unsafe_registration = false, Integer[2048] $key_size = 4096, # $renew_* should only be used in letsencrypt::renew (blame rspec) - $renew_pre_hook_commands = $letsencrypt::params::renew_pre_hook_commands, - $renew_post_hook_commands = $letsencrypt::params::renew_post_hook_commands, - $renew_deploy_hook_commands = $letsencrypt::params::renew_deploy_hook_commands, - $renew_additional_args = $letsencrypt::params::renew_additional_args, - $renew_cron_ensure = $letsencrypt::params::renew_cron_ensure, - $renew_cron_hour = $letsencrypt::params::renew_cron_hour, - $renew_cron_minute = $letsencrypt::params::renew_cron_minute, - $renew_cron_monthday = $letsencrypt::params::renew_cron_monthday, -) inherits letsencrypt::params { - + $renew_pre_hook_commands = [], + $renew_post_hook_commands = [], + $renew_deploy_hook_commands = [], + $renew_additional_args = [], + $renew_cron_ensure = 'absent', + $renew_cron_hour = fqdn_rand(24), + $renew_cron_minute = fqdn_rand(60, fqdn_rand_string(10)), + $renew_cron_monthday = '*', +) { if $manage_install { contain letsencrypt::install # lint:ignore:relative_classname_inclusion Class['letsencrypt::install'] ~> Exec['initialize letsencrypt'] @@ -111,7 +116,7 @@ exec { 'initialize letsencrypt': command => "${command_init} -h", path => $facts['path'], - environment => concat([ "VENV_PATH=${venv_path}" ], $environment), + environment => concat(["VENV_PATH=${venv_path}"], $environment), refreshonly => true, } diff --git a/manifests/install.pp b/manifests/install.pp index d17ae6e2..0ba33134 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -1,32 +1,14 @@ -# == Class: letsencrypt::install +# @summary Installs the Let's Encrypt client. # -# This class installs the Let's Encrypt client. This is a private class. -# -# === Parameters: -# -# [*manage_install*] -# A feature flag to toggle the management of the letsencrypt client -# installation. -# [*manage_dependencies*] -# A feature flag to toggle the management of the letsencrypt dependencies. -# [*configure_epel*] -# A feature flag to include the 'epel' class and depend on it for package -# installation. -# [*install_method*] -# Method to install the letsencrypt client, either package or vcs. -# [*path*] -# The path to the letsencrypt installation. -# [*repo*] -# A Git URL to install the Let's encrypt client from. -# [*version*] -# The Git ref (tag, sha, branch) to check out when installing the client with -# the `vcs` method. -# [*package_ensure*] -# The value passed to `ensure` when installing the client with the `package` -# method. -# [*package_name*] -# Name of package to use when installing the client with the `package` -# method. +# @param manage_install A feature flag to toggle the management of the letsencrypt client installation. +# @param manage_dependencies A feature flag to toggle the management of the letsencrypt dependencies. +# @param configure_epel A feature flag to include the 'epel' class and depend on it for package installation. +# @param install_method Method to install the letsencrypt client +# @param path The path to the letsencrypt installation. +# @param repo A Git URL to install the Let's encrypt client from. +# @param version The Git ref (tag, sha, branch) to check out when installing the client with the `vcs` method. +# @param package_ensure The value passed to `ensure` when installing the client with the `package` method. +# @param package_name Name of package to use when installing the client with the `package` method. # class letsencrypt::install ( Boolean $manage_install = $letsencrypt::manage_install, @@ -39,7 +21,6 @@ String $repo = $letsencrypt::repo, String $version = $letsencrypt::version, ) { - if $install_method == 'vcs' { if $manage_dependencies { $dependencies = ['python', 'git'] diff --git a/manifests/params.pp b/manifests/params.pp deleted file mode 100644 index 6ed6409f..00000000 --- a/manifests/params.pp +++ /dev/null @@ -1,85 +0,0 @@ -# @summary Default parameters -# @api private -class letsencrypt::params { - $agree_tos = true - $unsafe_registration = false - $manage_config = true - $manage_install = true - $manage_dependencies = true - $package_ensure = 'installed' - $path = '/opt/letsencrypt' - $venv_path = '/opt/letsencrypt/.venv' # virtualenv path for vcs-installed letsencrypt - $repo = 'https://github.com/certbot/certbot.git' - $cron_scripts_path = "${facts['puppet_vardir']}/letsencrypt" # path for renewal scripts called by cron - $version = 'v0.30.2' - $config = { - 'server' => 'https://acme-v01.api.letsencrypt.org/directory', - } - - if $facts['osfamily'] == 'Debian' { - $install_method = 'package' - $package_name = 'certbot' - $package_command = 'certbot' - $config_dir = '/etc/letsencrypt' - $dns_rfc2136_package_name = 'python3-certbot-dns-rfc2136' - } elsif $facts['osfamily'] == 'RedHat' { - $install_method = 'package' - $package_name = 'certbot' - $package_command = 'certbot' - $config_dir = '/etc/letsencrypt' - if $facts['operatingsystemmajrelease'] == '7' { - $dns_rfc2136_package_name = 'python2-certbot-dns-rfc2136' - } else { - $dns_rfc2136_package_name = 'python3-certbot-dns-rfc2136' - } - } elsif $facts['osfamily'] == 'Gentoo' { - $install_method = 'package' - $package_name = 'app-crypt/certbot' - $package_command = 'certbot' - $config_dir = '/etc/letsencrypt' - $dns_rfc2136_package_name = undef - } elsif $facts['osfamily'] == 'OpenBSD' { - $install_method = 'package' - $package_name = 'certbot' - $package_command = 'certbot' - $config_dir = '/etc/letsencrypt' - $dns_rfc2136_package_name = undef - } elsif $facts['osfamily'] == 'FreeBSD' { - $install_method = 'package' - $package_name = 'py27-certbot' - $package_command = 'certbot' - $config_dir = '/usr/local/etc/letsencrypt' - $dns_rfc2136_package_name = undef - } else { - $install_method = 'vcs' - $package_name = 'letsencrypt' - $package_command = 'letsencrypt' - $config_dir = '/etc/letsencrypt' - $dns_rfc2136_package_name = undef - } - - $config_file = "${config_dir}/cli.ini" - - $configure_epel = $facts['osfamily'] == 'RedHat' and $facts['os']['name'] != 'Fedora' - - $cron_owner_group = $facts['osfamily'] ? { - 'OpenBSD' => 'wheel', - 'FreeBSD' => 'wheel', - default => 'root', - } - - $renew_pre_hook_commands = [] - $renew_post_hook_commands = [] - $renew_deploy_hook_commands = [] - $renew_additional_args = [] - $renew_cron_ensure = 'absent' - $renew_cron_hour = fqdn_rand(24) - $renew_cron_minute = fqdn_rand(60, fqdn_rand_string(10)) - $renew_cron_monthday = '*' - - $dns_rfc2136_manage_package = true - $dns_rfc2136_port = 53 - $dns_rfc2136_algorithm = 'HMAC-SHA512' - $dns_rfc2136_propagation_seconds = 10 - -} diff --git a/manifests/plugin/dns_ovh.pp b/manifests/plugin/dns_ovh.pp new file mode 100644 index 00000000..bc3f78fb --- /dev/null +++ b/manifests/plugin/dns_ovh.pp @@ -0,0 +1,76 @@ +# @summary Installs and configures the dns-ovh plugin +# +# @example Basic usage +# class { 'letsencrypt::plugin::dns_ovh': +# endpoint => 'ovh-eu', +# application_key => 'MDAwMDAwMDAwMDAw', +# application_secret => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', +# consumer_key => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', +# } +# letsencrypt::certonly { 'foo': +# domains => ['foo.example.com', 'bar.example.com'], +# plugin => 'dns-ovh', +# } +# +# @see https://certbot-dns-ovh.readthedocs.io +# +# @param endpoint Target OVH DNS endpoint. +# @param application_key OVH application key. +# @param application_secret OVH application secret. +# @param consumer_key OVH consumer key. +# @param propagation_seconds Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. +# @param manage_package Manage the plugin. +# @param package_name The name of the package to install when $manage_package is true. +# @param config_dir The path to the configuration directory. +# +class letsencrypt::plugin::dns_ovh ( + Enum['ovh-eu', 'ovh-ca'] $endpoint, + String[1] $application_key, + String[1] $application_secret, + String[1] $consumer_key, + Integer $propagation_seconds = $letsencrypt::plugin::dns_ovh_propagation_seconds, + Boolean $manage_package = $letsencrypt::plugin::dns_ovh_manage_package, + String $package_name = $letsencrypt::plugin::dns_ovh_package_name, + Stdlib::Absolutepath $config_file = "${letsencrypt::config_dir}/dns-ovh.ini", +) { + require letsencrypt + + case $::facts['os']['id'] { + 'Debian': { + if versioncmp($::facts['os']['release']['major'], '10') < 0 { + fail("The dns-ovh plugin is not compatible with ${$::facts['os']['id']} ${$::facts['os']['release']['major']}. See README.") + } + } + 'Ubuntu': { + if versioncmp($::facts['os']['release']['major'], '19') < 0 { + fail("The dns-ovh plugin is not compatible with ${$::facts['os']['id']} ${$::facts['os']['release']['major']}. See README.") + } + } + default: { + } + } + + if $manage_package { + package { $package_name: + ensure => installed, + } + } + + $ini_vars = { + dns_ovh_endpoint => $endpoint, + dns_ovh_application_key => $application_key, + dns_ovh_application_secret => $application_secret, + dns_ovh_consumer_key => $consumer_key, + dns_ovh_propagation_seconds => $propagation_seconds, + } + + file { $config_file: + ensure => file, + owner => 'root', + group => 'root', + mode => '0400', + content => epp('letsencrypt/ini.epp', { + vars => { '' => $ini_vars }, + }), + } +} diff --git a/manifests/plugin/dns_rfc2136.pp b/manifests/plugin/dns_rfc2136.pp index 1bcd5f14..ebe5fd3e 100644 --- a/manifests/plugin/dns_rfc2136.pp +++ b/manifests/plugin/dns_rfc2136.pp @@ -1,40 +1,30 @@ -# == Class: letsencrypt::plugin::dns_rfc2136 +# @summary Installs and configures the dns-rfc2136 plugin # -# This class installs and configures the Let's Encrypt dns-rfc2136 plugin. -# https://certbot-dns-rfc2136.readthedocs.io +# This class installs and configures the Let's Encrypt dns-rfc2136 plugin. +# https://certbot-dns-rfc2136.readthedocs.io # -# === Parameters: -# -# [*server*] -# Target DNS server. -# [*key_name*] -# TSIG key name. -# [*key_secret*] -# TSIG key secret. -# [*key_algorithm*] -# TSIG key algorithm. -# [*port*] -# Target DNS port. -# [*propagation_seconds*] -# Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. -# [*manage_package*] -# Manage the plugin package. -# [*package_name*] -# The name of the package to install when $manage_package is true. -# [*config_dir*] -# The path to the configuration directory. +# @param server Target DNS server. +# @param key_name TSIG key name. +# @param key_secret TSIG key secret. +# @param key_algorithm TSIG key algorithm. +# @param port Target DNS port. +# @param propagation_seconds Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. +# @param manage_package Manage the plugin package. +# @param package_name The name of the package to install when $manage_package is true. +# @param config_dir The path to the configuration directory. # class letsencrypt::plugin::dns_rfc2136 ( Stdlib::Host $server, String[1] $key_name, String[1] $key_secret, - String[1] $key_algorithm = $letsencrypt::dns_rfc2136_algorithm, - Stdlib::Port $port = $letsencrypt::dns_rfc2136_port, - Integer $propagation_seconds = $letsencrypt::dns_rfc2136_propagation_seconds, + String[1] $package_name, + String[1] $key_algorithm = 'HMAC-SHA512', + Stdlib::Port $port = 53, + Integer $propagation_seconds = 10, Stdlib::Absolutepath $config_dir = $letsencrypt::config_dir, - Boolean $manage_package = $letsencrypt::dns_rfc2136_manage_package, - String $package_name = $letsencrypt::dns_rfc2136_package_name, + Boolean $manage_package = true, ) { + require letsencrypt if $manage_package { package { $package_name: @@ -56,9 +46,7 @@ group => 'root', mode => '0400', content => epp('letsencrypt/ini.epp', { - vars => { '' => $ini_vars }, + vars => { '' => $ini_vars }, }), - require => Class['letsencrypt'], } - } diff --git a/manifests/plugin/dns_route53.pp b/manifests/plugin/dns_route53.pp new file mode 100644 index 00000000..3d3d27b3 --- /dev/null +++ b/manifests/plugin/dns_route53.pp @@ -0,0 +1,22 @@ +# @summary Installs and configures the dns-route53 plugin +# +# This class installs and configures the Let's Encrypt dns-route53 plugin. +# https://certbot-dns-route53.readthedocs.io +# +# @param propagation_seconds Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. +# @param manage_package Manage the plugin package. +# @param package_name The name of the package to install when $manage_package is true. +# +class letsencrypt::plugin::dns_route53 ( + String[1] $package_name, + Integer $propagation_seconds = 10, + Boolean $manage_package = true, +) { + require letsencrypt + + if $manage_package { + package { $package_name: + ensure => installed, + } + } +} diff --git a/manifests/renew.pp b/manifests/renew.pp index 18f8f880..350b9fff 100644 --- a/manifests/renew.pp +++ b/manifests/renew.pp @@ -1,38 +1,29 @@ -# == Class: letsencrypt::renew +# @summary Configures renewal of Let's Encrypt certificates using Certbot # -# This class configures renewal of Let's Encrypt certificates using the -# certbot renew command. +# Configures renewal of Let's Encrypt certificates using the certbot renew command. # -# Note: Hooks set here will run before/after/for ALL certificates, including -# any not managed by Puppet. If you want to create hooks for specific -# certificates only, create them using letsencrypt::certonly. +# Note: Hooks set here will run before/after/for ALL certificates, including +# any not managed by Puppet. If you want to create hooks for specific +# certificates only, create them using letsencrypt::certonly. # -# === Parameters: -# -# [*pre_hook_commands*] -# Array of commands to run in a shell before obtaining/renewing any certificates. -# [*post_hook_commands*] -# Array of commands to run in a shell after attempting to obtain/renew certificates. -# [*deploy_hook_commands*] +# @param pre_hook_commands Array of commands to run in a shell before obtaining/renewing any certificates. +# @param post_hook_commands Array of commands to run in a shell after attempting to obtain/renew certificates. +# @param deploy_hook_commands # Array of commands to run in a shell once for each successfully issued/renewed # certificate. Two environmental variables are supplied by certbot: # - $RENEWED_LINEAGE: Points to the live directory with the cert files and key. # Example: /etc/letsencrypt/live/example.com # - $RENEWED_DOMAINS: A space-delimited list of renewed certificate domains. # Example: "example.com www.example.com" -# [*additional_args*] -# Array of additional command line arguments to pass to 'certbot renew'. -# [*cron_ensure*] -# Intended state of the cron resource running certbot renew. Accepts 'present' -# or 'absent'. Default: 'absent' -# [*cron_hour*] +# @param additional_args Array of additional command line arguments to pass to 'certbot renew'. +# @param cron_ensure Intended state of the cron resource running certbot renew +# @param cron_hour # Optional string, integer or array of hour(s) the renewal command should run. -# E.g. '[0,12]' to execute at midnight and midday. Default: fqdn-seeded random -# hour. -# [*cron_minute*] +# E.g. '[0,12]' to execute at midnight and midday. Default: fqdn-seeded random hour. +# @param cron_minute # Optional string, integer or array of minute(s) the renewal command should # run. E.g. 0 or '00' or [0,30]. Default: fqdn-seeded random minute. -# [*cron_monthday*] +# @param cron_monthday # Optional string, integer or array of monthday(s) the renewal command should # run. E.g. '2-30/2' to run on even days. Default: Every day. # @@ -46,7 +37,6 @@ Letsencrypt::Cron::Minute $cron_minute = $letsencrypt::renew_cron_minute, Letsencrypt::Cron::Monthday $cron_monthday = $letsencrypt::renew_cron_monthday, ) { - # Directory used for Puppet-managed renewal hooks. Make sure old unmanaged # hooks in this directory are purged. Leave custom hooks in the default # renewal-hooks directory alone. @@ -79,10 +69,10 @@ } $_command = flatten([ - $letsencrypt::command, - $default_args, - $hook_args, - $additional_args, + $letsencrypt::command, + $default_args, + $hook_args, + $additional_args, ]).filter | $arg | { $arg =~ NotUndef and $arg != [] } $command = join($_command, ' ') @@ -94,5 +84,4 @@ minute => $cron_minute, monthday => $cron_monthday, } - } diff --git a/metadata.json b/metadata.json index 261238c3..2a00b231 100644 --- a/metadata.json +++ b/metadata.json @@ -1,6 +1,6 @@ { "name": "puppet-letsencrypt", - "version": "4.0.1-rc0", + "version": "6.0.1-rc0", "author": "Vox Pupuli", "summary": "Manages lets-encrypt and certbot + related certs", "license": "Apache-2.0", @@ -29,8 +29,8 @@ { "operatingsystem": "Fedora", "operatingsystemrelease": [ - "29", - "30" + "30", + "31" ] }, { @@ -56,8 +56,8 @@ { "operatingsystem": "FreeBSD", "operatingsystemrelease": [ - "10", - "11" + "11", + "12" ] } ], @@ -70,19 +70,19 @@ "dependencies": [ { "name": "puppetlabs/stdlib", - "version_requirement": ">= 4.13.1 < 6.0.0" + "version_requirement": ">= 4.13.1 < 7.0.0" }, { "name": "puppetlabs/inifile", - "version_requirement": ">= 2.0.0 < 4.0.0" + "version_requirement": ">= 2.0.0 < 5.0.0" }, { "name": "puppetlabs/vcsrepo", - "version_requirement": ">= 2.0.0 < 3.0.0" + "version_requirement": ">= 2.0.0 < 4.0.0" }, { - "name": "stahnma/epel", - "version_requirement": ">= 1.0.0 < 2.0.0" + "name": "puppet/epel", + "version_requirement": ">= 3.0.1 < 4.0.0" } ] } diff --git a/spec/acceptance/letsencrypt_plugin_dns_ovh_spec.rb b/spec/acceptance/letsencrypt_plugin_dns_ovh_spec.rb new file mode 100644 index 00000000..2cb98d5d --- /dev/null +++ b/spec/acceptance/letsencrypt_plugin_dns_ovh_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper_acceptance' + +describe 'letsencrypt::plugin::dns_ovh' do + supported = case fact('os.family') + when 'Debian' + # Debian started shipping in Buster, Ubuntu started shipping in Disco + fact('os.release.major') != '10' && fact('os.release.major') != '19.04' + when 'RedHat' + true + else + false + end + + context 'with defaults values' do + pp = <<-PUPPET + class { 'letsencrypt' : + email => 'letsregister@example.com', + config => { + 'server' => 'https://acme-staging.api.letsencrypt.org/directory', + }, + } + class { 'letsencrypt::plugin::dns_ovh': + endpoint => 'ovh-eu', + application_key => 'MDAwMDAwMDAwMDAw', + application_secret => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', + consumer_key => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', + } + PUPPET + + if supported + it 'installs letsencrypt and dns ovh plugin without error' do + apply_manifest(pp, catch_failures: true) + end + it 'installs letsencrypt and dns ovh idempotently' do + apply_manifest(pp, catch_changes: true) + end + + describe file('/etc/letsencrypt/dns-ovh.ini') do + it { is_expected.to be_file } + it { is_expected.to be_owned_by 'root' } + it { is_expected.to be_grouped_into 'root' } + it { is_expected.to be_mode 400 } + end + else + it 'fails to install' do + apply_manifest(pp, expect_failures: true) + end + end + end +end diff --git a/spec/acceptance/letsencrypt_plugin_dns_rfc2136_spec.rb b/spec/acceptance/letsencrypt_plugin_dns_rfc2136_spec.rb index 036f9550..32717744 100644 --- a/spec/acceptance/letsencrypt_plugin_dns_rfc2136_spec.rb +++ b/spec/acceptance/letsencrypt_plugin_dns_rfc2136_spec.rb @@ -16,7 +16,7 @@ class { 'letsencrypt' : email => 'letsregister@example.com', config => { - 'server' => 'https://acme-staging.api.letsencrypt.org/directory', + 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', }, } class { 'letsencrypt::plugin::dns_rfc2136': diff --git a/spec/acceptance/letsencrypt_plugin_dns_route53_spec.rb b/spec/acceptance/letsencrypt_plugin_dns_route53_spec.rb new file mode 100644 index 00000000..5b268827 --- /dev/null +++ b/spec/acceptance/letsencrypt_plugin_dns_route53_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper_acceptance' + +describe 'letsencrypt::plugin::dns_route53' do + supported = case fact('os.family') + when 'Debian' + # Debian 9 has it in backports, Ubuntu started shipping in Bionic + fact('os.release.major') != '9' && fact('os.release.major') != '16.04' + when 'RedHat' + true + else + false + end + + context 'with defaults values' do + pp = <<-PUPPET + class { 'letsencrypt' : + email => 'letsregister@example.com', + config => { + 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', + }, + } + class { 'letsencrypt::plugin::dns_route53': + } + PUPPET + + if supported + it 'installs letsencrypt and dns route53 plugin without error' do + apply_manifest(pp, catch_failures: true) + end + it 'installs letsencrypt and dns route53 idempotently' do + apply_manifest(pp, catch_changes: true) + end + + else + it 'fails to install' do + apply_manifest(pp, expect_failures: true) + end + end + end +end diff --git a/spec/acceptance/letsencrypt_spec.rb b/spec/acceptance/letsencrypt_spec.rb index a4350514..7c30e7b0 100644 --- a/spec/acceptance/letsencrypt_spec.rb +++ b/spec/acceptance/letsencrypt_spec.rb @@ -6,7 +6,7 @@ class { 'letsencrypt' : email => 'letsregister@example.com', config => { - 'server' => 'https://acme-staging.api.letsencrypt.org/directory', + 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', }, } ) @@ -23,7 +23,7 @@ class { 'letsencrypt' : it { is_expected.to be_owned_by 'root' } it { is_expected.to be_grouped_into 'root' } it { is_expected.to be_mode 644 } - its(:content) { is_expected.to match %r{server = https://acme-staging.api.letsencrypt.org/directory} } + its(:content) { is_expected.to match %r{server = https://acme-staging-v02.api.letsencrypt.org/directory} } its(:content) { is_expected.to match %r{email = letsregister@example.com} } end end @@ -34,7 +34,7 @@ class { 'letsencrypt' : install_method => 'vcs', email => 'letsregister@example.com', config => { - 'server' => 'https://acme-staging.api.letsencrypt.org/directory', + 'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory', }, } ) @@ -51,11 +51,11 @@ class { 'letsencrypt' : it { is_expected.to be_owned_by 'root' } it { is_expected.to be_grouped_into 'root' } it { is_expected.to be_mode 644 } - its(:content) { is_expected.to match %r{server = https://acme-staging.api.letsencrypt.org/directory} } + its(:content) { is_expected.to match %r{server = https://acme-staging-v02.api.letsencrypt.org/directory} } its(:content) { is_expected.to match %r{email = letsregister@example.com} } end - describe file('/opt/letsencrypt/.venv/bin/letsencrypt') do + describe file('/opt/letsencrypt/.venv/bin/certbot') do it { is_expected.to be_file } it { is_expected.to be_owned_by 'root' } it { is_expected.to be_grouped_into 'root' } diff --git a/spec/acceptance/nodesets/archlinux-2-x64.yml b/spec/acceptance/nodesets/archlinux-2-x64.yml deleted file mode 100644 index 89b63003..00000000 --- a/spec/acceptance/nodesets/archlinux-2-x64.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -HOSTS: - archlinux-2-x64: - roles: - - master - platform: archlinux-2-x64 - box: archlinux/archlinux - hypervisor: vagrant -CONFIG: - type: foss diff --git a/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml b/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml deleted file mode 100644 index 19dd43ed..00000000 --- a/spec/acceptance/nodesets/ec2/amazonlinux-2016091.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -# -# Additional ~/.fog config file with AWS EC2 credentials -# required. -# -# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md -# -# Amazon Linux is not a RHEL clone. -# -HOSTS: - amazonlinux-2016091-x64: - roles: - - master - platform: centos-6-x86_64 - hypervisor: ec2 - # refers to image_tempaltes.yaml AMI[vmname] entry: - vmname: amazonlinux-2016091-eu-central-1 - # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: - snapshot: aio - # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): - amisize: t2.micro - # required so that beaker sanitizes sshd_config and root authorized_keys: - user: ec2-user -CONFIG: - type: aio - :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml -... -# vim: syntax=yaml diff --git a/spec/acceptance/nodesets/ec2/image_templates.yaml b/spec/acceptance/nodesets/ec2/image_templates.yaml deleted file mode 100644 index e50593ee..00000000 --- a/spec/acceptance/nodesets/ec2/image_templates.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -# -# see also: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md -# -# Hint: image IDs (ami-*) for the same image are different per location. -# -AMI: - # Amazon Linux AMI 2016.09.1 (HVM), SSD Volume Type - amazonlinux-2016091-eu-central-1: - :image: - :aio: ami-af0fc0c0 - :region: eu-central-1 - # Red Hat Enterprise Linux 7.3 (HVM), SSD Volume Type - rhel-73-eu-central-1: - :image: - :aio: ami-e4c63e8b - :region: eu-central-1 - # SUSE Linux Enterprise Server 12 SP2 (HVM), SSD Volume Type - sles-12sp2-eu-central-1: - :image: - :aio: ami-c425e4ab - :region: eu-central-1 - # Ubuntu Server 16.04 LTS (HVM), SSD Volume Type - ubuntu-1604-eu-central-1: - :image: - :aio: ami-fe408091 - :region: eu-central-1 - # Microsoft Windows Server 2016 Base - windows-2016-base-eu-central-1: - :image: - :aio: ami-88ec20e7 - :region: eu-central-1 diff --git a/spec/acceptance/nodesets/ec2/rhel-73-x64.yml b/spec/acceptance/nodesets/ec2/rhel-73-x64.yml deleted file mode 100644 index 7fac8236..00000000 --- a/spec/acceptance/nodesets/ec2/rhel-73-x64.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -# -# Additional ~/.fog config file with AWS EC2 credentials -# required. -# -# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md -# -HOSTS: - rhel-73-x64: - roles: - - master - platform: el-7-x86_64 - hypervisor: ec2 - # refers to image_tempaltes.yaml AMI[vmname] entry: - vmname: rhel-73-eu-central-1 - # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: - snapshot: aio - # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): - amisize: t2.micro - # required so that beaker sanitizes sshd_config and root authorized_keys: - user: ec2-user -CONFIG: - type: aio - :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml -... -# vim: syntax=yaml diff --git a/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml b/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml deleted file mode 100644 index 8542154d..00000000 --- a/spec/acceptance/nodesets/ec2/sles-12sp2-x64.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -# -# Additional ~/.fog config file with AWS EC2 credentials -# required. -# -# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md -# -HOSTS: - sles-12sp2-x64: - roles: - - master - platform: sles-12-x86_64 - hypervisor: ec2 - # refers to image_tempaltes.yaml AMI[vmname] entry: - vmname: sles-12sp2-eu-central-1 - # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: - snapshot: aio - # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): - amisize: t2.micro - # required so that beaker sanitizes sshd_config and root authorized_keys: - user: ec2-user -CONFIG: - type: aio - :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml -... -# vim: syntax=yaml diff --git a/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml b/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml deleted file mode 100644 index 9cf59d59..00000000 --- a/spec/acceptance/nodesets/ec2/ubuntu-1604-x64.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -# -# Additional ~/.fog config file with AWS EC2 credentials -# required. -# -# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md -# -HOSTS: - ubuntu-1604-x64: - roles: - - master - platform: ubuntu-16.04-amd64 - hypervisor: ec2 - # refers to image_tempaltes.yaml AMI[vmname] entry: - vmname: ubuntu-1604-eu-central-1 - # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: - snapshot: aio - # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): - amisize: t2.micro - # required so that beaker sanitizes sshd_config and root authorized_keys: - user: ubuntu -CONFIG: - type: aio - :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml -... -# vim: syntax=yaml diff --git a/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml b/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml deleted file mode 100644 index 0932e29c..00000000 --- a/spec/acceptance/nodesets/ec2/windows-2016-base-x64.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -# -# Additional ~/.fog config file with AWS EC2 credentials -# required. -# -# see: https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/ec2.md -# -HOSTS: - windows-2016-base-x64: - roles: - - master - platform: windows-2016-64 - hypervisor: ec2 - # refers to image_tempaltes.yaml AMI[vmname] entry: - vmname: windows-2016-base-eu-central-1 - # refers to image_tempaltes.yaml entry inside AMI[vmname][:image]: - snapshot: aio - # t2.micro is free tier eligible (https://aws.amazon.com/en/free/): - amisize: t2.micro - # required so that beaker sanitizes sshd_config and root authorized_keys: - user: ec2-user -CONFIG: - type: aio - :ec2_yaml: spec/acceptance/nodesets/ec2/image_templates.yaml -... -# vim: syntax=yaml diff --git a/spec/classes/letsencrypt_spec.rb b/spec/classes/letsencrypt_spec.rb index 5bae52e7..1a5e6154 100644 --- a/spec/classes/letsencrypt_spec.rb +++ b/spec/classes/letsencrypt_spec.rb @@ -32,7 +32,7 @@ manage_install: true, manage_dependencies: true, repo: 'https://github.com/certbot/certbot.git', - version: 'v0.30.2'). + version: 'v0.39.0'). that_notifies('Exec[initialize letsencrypt]'). that_comes_before('Class[letsencrypt::renew]') is_expected.to contain_exec('initialize letsencrypt') @@ -48,7 +48,7 @@ if facts[:osfamily] == 'FreeBSD' is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') - is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v01.api.letsencrypt.org/directory') + is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') is_expected.to contain_file('letsencrypt-renewal-hooks-puppet'). with(ensure: 'directory', path: '/usr/local/etc/letsencrypt/renewal-hooks-puppet', @@ -59,7 +59,7 @@ purge: true) else is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini email foo@example.com') - is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini server https://acme-v01.api.letsencrypt.org/directory') + is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') is_expected.to contain_file('letsencrypt-renewal-hooks-puppet').with_path('/etc/letsencrypt/renewal-hooks-puppet') end @@ -132,7 +132,7 @@ describe 'with custom config file' do let(:additional_params) { { config_file: '/etc/letsencrypt/custom_config.ini' } } - it { is_expected.to contain_ini_setting('/etc/letsencrypt/custom_config.ini server https://acme-v01.api.letsencrypt.org/directory') } + it { is_expected.to contain_ini_setting('/etc/letsencrypt/custom_config.ini server https://acme-v02.api.letsencrypt.org/directory') } end describe 'with custom config' do diff --git a/spec/classes/plugin/dns_ovh_spec.rb b/spec/classes/plugin/dns_ovh_spec.rb new file mode 100644 index 00000000..56343ec3 --- /dev/null +++ b/spec/classes/plugin/dns_ovh_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe 'letsencrypt::plugin::dns_ovh' do + on_supported_os.each do |os, facts| + context "on #{os} based operating systems" do + let(:facts) { facts } + let(:params) { {} } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + } + PUPPET + end + let(:package_name) do + case facts[:osfamily] + when 'Debian' + 'python3-certbot-dns-ovh' + when 'RedHat' + facts[:operatingsystem] == 'Fedora' ? 'python3-certbot-dns-ovh' : 'python2-certbot-dns-ovh' + end + end + + context 'without required parameters' do + it { is_expected.not_to compile } + end + + context 'with required parameters' do + let(:params) do + super().merge( + endpoint: 'ovh-eu', + application_key: 'MDAwMDAwMDAwMDAw', + application_secret: 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', + consumer_key: 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw' + ) + end + + it do + if package_name.nil? + is_expected.not_to compile + else + is_expected.to compile.with_all_deps + + is_expected.to contain_file('/etc/letsencrypt/dns-ovh.ini'). + with_ensure('file'). + with_owner('root'). + with_group('root'). + with_mode('0400'). + with_content(%r{^.*dns_ovh_endpoint.*$}) + end + end + + describe 'with manage_package => true' do + let(:params) { super().merge(manage_package: true) } + + it do + if package_name.nil? + is_expected.not_to compile + else + is_expected.to contain_class('letsencrypt::plugin::dns_ovh').with_package_name(package_name) + is_expected.to contain_package(package_name).with_ensure('installed') + end + end + end + + describe 'with manage_package => false' do + let(:params) { super().merge(manage_package: false, package_name: 'dns-ovh-package') } + + it { is_expected.not_to contain_package('dns-ovh-package') } + end + end + end + end +end diff --git a/spec/classes/plugin/dns_rfc2136_spec.rb b/spec/classes/plugin/dns_rfc2136_spec.rb index bea4d75c..5b3ebbae 100644 --- a/spec/classes/plugin/dns_rfc2136_spec.rb +++ b/spec/classes/plugin/dns_rfc2136_spec.rb @@ -13,11 +13,14 @@ class { 'letsencrypt': PUPPET end let(:package_name) do - case facts[:osfamily] - when 'Debian' + osname = facts[:os]['name'] + osrelease = facts[:os]['release']['major'] + osfull = "#{osname}-#{osrelease}" + case osfull + when 'Debian-10', 'Ubuntu-18.04', 'Fedora-30', 'Fedora-31' 'python3-certbot-dns-rfc2136' - when 'RedHat' - facts[:operatingsystem] == 'Fedora' ? 'python3-certbot-dns-rfc2136' : 'python2-certbot-dns-rfc2136' + when 'RedHat-7', 'CentOS-7' + 'python2-certbot-dns-rfc2136' end end diff --git a/spec/classes/plugin/dns_route53_spec.rb b/spec/classes/plugin/dns_route53_spec.rb new file mode 100644 index 00000000..631fc5ad --- /dev/null +++ b/spec/classes/plugin/dns_route53_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe 'letsencrypt::plugin::dns_route53' do + on_supported_os.each do |os, facts| + context "on #{os} based operating systems" do + let(:facts) { facts } + let(:params) { {} } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + } + PUPPET + end + let(:package_name) do + osname = facts[:os]['name'] + osrelease = facts[:os]['release']['major'] + osfull = "#{osname}-#{osrelease}" + case osfull + when 'Debian-10', 'Ubuntu-18.04', 'Fedora-30', 'Fedora-31' + 'python3-certbot-dns-route53' + when 'RedHat-7', 'CentOS-7' + 'python2-certbot-dns-route53' + end + end + + context 'with required parameters' do + it do + if package_name.nil? + is_expected.not_to compile + else + is_expected.to compile.with_all_deps + end + end + + describe 'with manage_package => true' do + let(:params) { super().merge(manage_package: true) } + + it do + if package_name.nil? + is_expected.not_to compile + else + is_expected.to contain_class('letsencrypt::plugin::dns_route53').with_package_name(package_name) + is_expected.to contain_package(package_name).with_ensure('installed') + end + end + end + + describe 'with manage_package => false' do + let(:params) { super().merge(manage_package: false, package_name: 'dns-route53-package') } + + it { is_expected.not_to contain_package('dns-route53-package') } + end + end + end + end +end diff --git a/spec/defines/letsencrypt_certonly_spec.rb b/spec/defines/letsencrypt_certonly_spec.rb index 7b5b17a2..5b7fd4cb 100644 --- a/spec/defines/letsencrypt_certonly_spec.rb +++ b/spec/defines/letsencrypt_certonly_spec.rb @@ -18,17 +18,16 @@ it { is_expected.to compile.with_all_deps } it { is_expected.to contain_class('Letsencrypt::Install') } it { is_expected.to contain_class('Letsencrypt::Config') } - it { is_expected.to contain_class('Letsencrypt::Params') } if facts[:osfamily] == 'FreeBSD' it { is_expected.to contain_file('/usr/local/etc/letsencrypt') } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') } - it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v01.api.letsencrypt.org/directory') } + it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') } else it { is_expected.to contain_file('/etc/letsencrypt') } - it { is_expected.to contain_package('letsencrypt') } unless facts[:os]['release']['full'] == '14.04' + it { is_expected.to contain_package('letsencrypt') } it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini email foo@example.com') } - it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini server https://acme-v01.api.letsencrypt.org/directory') } + it { is_expected.to contain_ini_setting('/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') } end it { is_expected.to contain_exec('initialize letsencrypt') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com') } @@ -52,6 +51,14 @@ it { is_expected.to contain_exec('letsencrypt certonly foo').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo' -d 'foo.example.com' -d 'bar.example.com' -d '*.example.com'" } end + context 'with custom cert-name' do + let(:title) { 'foo' } + let(:params) { { cert_name: 'bar.example.com' } } + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_exec('letsencrypt certonly foo').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'bar.example.com' -d 'foo'" } + end + context 'with custom command' do let(:title) { 'foo.example.com' } let(:params) { { letsencrypt_command: '/usr/lib/letsencrypt/letsencrypt-auto' } } @@ -126,6 +133,50 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a dns-rfc2136 --cert-name 'foo.example.com' -d 'foo.example.com' --dns-rfc2136-credentials /etc/letsencrypt/dns-rfc2136.ini --dns-rfc2136-propagation-seconds 10" } end + context 'with dns-ovh plugin' do + let(:title) { 'foo.example.com' } + let(:params) { { plugin: 'dns-ovh', letsencrypt_command: 'letsencrypt' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + config_dir => '/etc/letsencrypt', + } + class { 'letsencrypt::plugin::dns_ovh': + endpoint => 'ovh-eu', + application_key => 'MDAwMDAwMDAwMDAw', + application_secret => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', + consumer_key => 'MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw', + package_name => 'irrelevant', + } + PUPPET + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('letsencrypt::plugin::dns_ovh') } + it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a dns-ovh --cert-name 'foo.example.com' -d 'foo.example.com' --dns-ovh-credentials /etc/letsencrypt/dns-ovh.ini --dns-ovh-propagation-seconds 30" } + end + + context 'with dns-route53 plugin' do + let(:title) { 'foo.example.com' } + let(:params) { { plugin: 'dns-route53', letsencrypt_command: 'letsencrypt' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + config_dir => '/etc/letsencrypt', + } + class { 'letsencrypt::plugin::dns_route53': + package_name => 'irrelevant', + } + PUPPET + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('letsencrypt::plugin::dns_route53') } + it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a dns-route53 --cert-name 'foo.example.com' -d 'foo.example.com' --dns-route53-propagation-seconds 10" } + end + context 'with custom plugin' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'apache' } } @@ -145,7 +196,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command('"/var/lib/puppet/letsencrypt/renew-foo.example.com.sh"').with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with hook' do @@ -201,7 +252,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_hour(13).with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and out of range defined cron_hour (integer)' do @@ -228,7 +279,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_hour('00').with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and defined cron_hour (array)' do @@ -242,7 +293,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_hour([1, 13]).with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and defined cron_minute (integer)' do @@ -256,7 +307,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_minute(15).with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and out of range defined cron_hour (integer)' do @@ -283,7 +334,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_minute('15').with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and defined cron_minute (array)' do @@ -297,7 +348,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_minute([0, 30]).with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with manage_cron and ensure absent' do @@ -327,7 +378,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_file('/tmp/custom_vardir/letsencrypt').with_ensure('directory') } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command '"/tmp/custom_vardir/letsencrypt/renew-foo.example.com.sh"' } - it { is_expected.to contain_file('/tmp/custom_vardir/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/tmp/custom_vardir/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with custom plugin and manage cron and cron_success_command' do @@ -343,7 +394,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command '"/var/lib/puppet/letsencrypt/renew-foo.example.com.sh"' } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\n(echo before) && letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring && (echo success)\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\n(echo before) && letsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a apache --cert-name 'foo.example.com' -d 'foo.example.com' && (echo success)\n") } end context 'without plugin' do @@ -382,7 +433,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': let(:params) { { environment: ['FOO=bar', 'FIZZ=buzz'], manage_cron: true } } it { is_expected.to compile.with_all_deps } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_content "#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nexport FOO=bar\nexport FIZZ=buzz\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n" } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_content "#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nexport FOO=bar\nexport FIZZ=buzz\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n" } end context 'with manage cron and suppress_cron_output' do\ @@ -394,7 +445,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with_command('"/var/lib/puppet/letsencrypt/renew-foo.example.com.sh"').with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring > /dev/null 2>&1\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' > /dev/null 2>&1\n") } end context 'with manage cron and custom day of month' do @@ -406,7 +457,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_cron('letsencrypt renew cron foo.example.com').with(monthday: [1, 15]).with_ensure('present') } - it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com' --keep-until-expiring\n") } + it { is_expected.to contain_file('/var/lib/puppet/letsencrypt/renew-foo.example.com.sh').with_ensure('file').with_content("#!/bin/sh\nexport VENV_PATH=/opt/letsencrypt/.venv\nletsencrypt --keep-until-expiring --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a standalone --cert-name 'foo.example.com' -d 'foo.example.com'\n") } end context 'with custom config_dir' do @@ -425,7 +476,7 @@ class { 'letsencrypt::plugin::dns_rfc2136': it { is_expected.to compile.with_all_deps } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command %r{^certbot} } it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini email foo@example.com') } - it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v01.api.letsencrypt.org/directory') } + it { is_expected.to contain_ini_setting('/usr/local/etc/letsencrypt/cli.ini server https://acme-v02.api.letsencrypt.org/directory') } it { is_expected.to contain_file('/usr/local/etc/letsencrypt').with_ensure('directory') } it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_unless '/usr/local/sbin/letsencrypt-domain-validation /usr/local/etc/letsencrypt/live/foo.example.com/cert.pem \'foo.example.com\'' } end diff --git a/spec/defines/letsencrypt_hook_spec.rb b/spec/defines/letsencrypt_hook_spec.rb index 936d7525..7ac1b4e7 100644 --- a/spec/defines/letsencrypt_hook_spec.rb +++ b/spec/defines/letsencrypt_hook_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'letsencrypt::hook' do - on_supported_os.each do |os, _facts| + on_supported_os.each do |os, facts| let(:title) { 'foo.example.com' } let(:pre_condition) { ["class { letsencrypt: email => 'foo@example.com', package_command => 'letsencrypt' }"] } @@ -10,6 +10,10 @@ let(:required_params) { {} } let(:additional_params) { {} } + let :facts do + facts + end + context 'without required parameters' do it { is_expected.not_to compile } end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f16fb152..d266f6b4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,44 +1,18 @@ # This file is managed via modulesync # https://github.com/voxpupuli/modulesync # https://github.com/voxpupuli/modulesync_config -RSpec.configure do |c| - c.mock_with :rspec -end -require 'puppetlabs_spec_helper/module_spec_helper' -require 'rspec-puppet-facts' -require 'bundler' -include RspecPuppetFacts +# 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.load(File.read(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 - -if Dir.exist?(File.expand_path('../../lib', __FILE__)) - require 'coveralls' - require 'simplecov' - require 'simplecov-console' - SimpleCov.formatters = [ - SimpleCov::Formatter::HTMLFormatter, - SimpleCov::Formatter::Console - ] - SimpleCov.start do - track_files 'lib/**/*.rb' - add_filter '/spec' - add_filter '/vendor' - add_filter '/.vendor' - add_filter Bundler.configured_bundle_path.path - end -end - -RSpec.configure do |c| - # Coverage generation - c.after(:suite) do - RSpec::Puppet::Coverage.report! - end -end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index d2de0ebc..3a33745b 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,23 +1,11 @@ -require 'beaker-rspec' -require 'beaker-puppet' -require 'beaker/puppet_install_helper' -require 'beaker/module_install_helper' +require 'voxpupuli/acceptance/spec_helper_acceptance' -run_puppet_install_helper unless ENV['BEAKER_provision'] == 'no' -install_module -install_module_dependencies - -RSpec.configure do |c| - # Configure all nodes in nodeset - c.before :suite do - hosts.each do |host| - # docker image does not provide cron in all cases - case fact('os.family') - when 'Debian' - host.install_package('cron') - when 'RedHat' - host.install_package('crontabs') - end - end +configure_beaker do |host| + # docker image does not provide cron in all cases + case fact_on(host, 'os.family') + when 'Debian' + host.install_package('cron') + when 'RedHat' + host.install_package('crontabs') end end diff --git a/spec/type_aliases/plugin_spec.rb b/spec/type_aliases/plugin_spec.rb index 2a634fbe..edf3e456 100644 --- a/spec/type_aliases/plugin_spec.rb +++ b/spec/type_aliases/plugin_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Letsencrypt::Plugin' do - it { is_expected.to allow_values('apache', 'standalone', 'webroot', 'nginx', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136') } + it { is_expected.to allow_values('apache', 'standalone', 'webroot', 'nginx', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136', 'dns-ovh') } it { is_expected.not_to allow_value(nil) } it { is_expected.not_to allow_value('foo') } it { is_expected.not_to allow_value('custom') } diff --git a/types/cron/hour.pp b/types/cron/hour.pp index 686133f1..f1034034 100644 --- a/types/cron/hour.pp +++ b/types/cron/hour.pp @@ -1 +1,11 @@ -type Letsencrypt::Cron::Hour = Variant[Integer[0,23], String[1], Array[Variant[Integer[0,23], String[1]]]] +# @summary mimic hour setting in cron as defined in man 5 crontab +type Letsencrypt::Cron::Hour = Variant[ + Integer[0,23], + String[1], + Array[ + Variant[ + Integer[0,23], + String[1], + ] + ] +] diff --git a/types/cron/minute.pp b/types/cron/minute.pp index ab65af6f..0c52dace 100644 --- a/types/cron/minute.pp +++ b/types/cron/minute.pp @@ -1 +1,11 @@ -type Letsencrypt::Cron::Minute = Variant[Integer[0,59], String[1], Array[Variant[Integer[0,59], String[1]]]] +# @summary mimic minute setting in cron as defined in man 5 crontab +type Letsencrypt::Cron::Minute = Variant[ + Integer[0,59], + String[1], + Array[ + Variant[ + Integer[0,59], + String[1], + ] + ] +] diff --git a/types/cron/monthday.pp b/types/cron/monthday.pp index 7ded7f32..8831d1b0 100644 --- a/types/cron/monthday.pp +++ b/types/cron/monthday.pp @@ -1 +1,11 @@ -type Letsencrypt::Cron::Monthday = Variant[Integer[0,31], String[1], Array[Variant[Integer[0,31], String[1]]]] +# @summary mimic monthday setting in cron as defined in man 5 crontab +type Letsencrypt::Cron::Monthday = Variant[ + Integer[0,31], + String[1], + Array[ + Variant[ + Integer[0,31], + String[1], + ] + ] +] diff --git a/types/plugin.pp b/types/plugin.pp index d24eb26b..f3afe835 100644 --- a/types/plugin.pp +++ b/types/plugin.pp @@ -1 +1,12 @@ -type Letsencrypt::Plugin = Enum['apache', 'standalone', 'webroot', 'nginx', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136'] +# @summary List of accepted plugins +type Letsencrypt::Plugin = Enum[ + 'apache', + 'standalone', + 'webroot', + 'nginx', + 'dns-route53', + 'dns-google', + 'dns-cloudflare', + 'dns-rfc2136', + 'dns-ovh', +]