diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..08c6abf9 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,4 @@ +{ + "name": "VoxBox", + "image": "ghcr.io/voxpupuli/voxbox:latest" +} diff --git a/.editorconfig b/.editorconfig index d77700e3..ecb10a80 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,7 @@ # editorconfig.org -# MANAGED BY MODULESYNC +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ root = true diff --git a/.fixtures.yml b/.fixtures.yml index 1cf7a43a..4a4f5b85 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -1,7 +1,6 @@ +--- fixtures: repositories: - stdlib: 'https://github.com/puppetlabs/puppetlabs-stdlib.git' - epel: 'https://github.com/stahnma/puppet-module-epel.git' - yumrepo_core: - repo: https://github.com/puppetlabs/puppetlabs-yumrepo_core.git - puppet_version: ">= 6.0.0" + epel: https://github.com/voxpupuli/puppet-epel.git + stdlib: https://github.com/puppetlabs/puppetlabs-stdlib.git + yumrepo_core: https://github.com/puppetlabs/puppetlabs-yumrepo_core.git diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 5d047472..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,184 +0,0 @@ -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. - -## Contributing - -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. - -## Dependencies - -The testing and development tools have a bunch of dependencies, -all managed by [bundler](http://bundler.io/) according to the -[Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions). - -By default the tests use a baseline version of Puppet. - -If you have Ruby 2.x or want a specific version of Puppet, -you must set an environment variable such as: - -```sh -export PUPPET_VERSION="~> 5.5.6" -``` - -You can install all needed gems for spec tests into the modules directory by -running: - -```sh -bundle install --path .vendor/ --without development system_tests release -``` - -If you also want to run acceptance tests: - -```sh -bundle install --path .vendor/ --with system_tests --without development release -``` - -Our all in one solution if you don't know if you need to install or update gems: - -```sh -bundle install --path .vendor/ --with system_tests --without development release; bundle update; bundle clean -``` - -## Syntax and style - -The test suite will run [Puppet Lint](http://puppet-lint.com/) and -[Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to -check various syntax and style things. You can run these locally with: - -```sh -bundle exec rake lint -bundle exec rake validate -``` - -It will also run some [Rubocop](http://batsov.com/rubocop/) tests -against it. You can run those locally ahead of time with: - -```sh -bundle exec rake rubocop -``` - -## Running the unit tests - -The unit test suite covers most of the code, as mentioned above please -add tests if you're adding new functionality. If you've not used -[rspec-puppet](http://rspec-puppet.com/) before then feel free to ask -about how best to test your new feature. - -To run the linter, the syntax checker and the unit tests: - -```sh -bundle exec rake test -``` - -To run your all the unit tests - -```sh -bundle exec rake spec -``` - -To run a specific spec test set the `SPEC` variable: - -```sh -bundle exec rake spec SPEC=spec/foo_spec.rb -``` - -### 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. -You only need to run: - -```sh -docker build . -``` - -Please ensure that a docker daemon is running and that your user has the -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 - -The unit tests just check the code runs, not that it does exactly what -we want on a real machine. For that we're using -[beaker](https://github.com/puppetlabs/beaker). - -This fires up a new virtual machine (using vagrant) and runs a series of -simple tests against it after applying the module. You can run this -with: - -```sh -bundle exec rake acceptance -``` - -This will run the tests on the module's default nodeset. You can override the -nodeset used, e.g., - -```sh -BEAKER_set=centos-7-x64 bundle exec rake acceptance -``` - -There are default rake tasks for the various acceptance test modules, e.g., - -```sh -bundle exec rake beaker:centos-7-x64 -bundle exec rake beaker:ssh:centos-7-x64 -``` - -If you don't want to have to recreate the virtual machine every time you can -use `BEAKER_destroy=no` and `BEAKER_provision=no`. On the first run you will at -least need `BEAKER_provision` set to yes (the default). The Vagrantfile for the -created virtual machines will be in `.vagrant/beaker_vagrant_files`. - -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: - -``` -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 -``` - -You can replace the string `debian9` with any common operating system. -The following strings are known to work: - -* ubuntu1604 -* ubuntu1804 -* debian8 -* debian9 -* centos6 -* centos7 - -The easiest way to debug in a docker container is to open a shell: - -```sh -docker exec -it -u root ${container_id_or_name} bash -``` - -The source of this file is in our [modulesync_config](https://github.com/voxpupuli/modulesync_config/blob/master/moduleroot/.github/CONTRIBUTING.md.erb) -repository. diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 00000000..f2d08d6b --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,6 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +skip-changelog: + - head-branch: ['^release-*', 'release'] diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..f5b5d7a9 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,42 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes + +changelog: + exclude: + labels: + - duplicate + - invalid + - modulesync + - question + - skip-changelog + - wont-fix + - wontfix + + categories: + - title: Breaking Changes 🛠 + labels: + - backwards-incompatible + + - title: New Features 🎉 + labels: + - enhancement + + - title: Bug Fixes 🐛 + labels: + - bug + + - title: Documentation Updates 📚 + labels: + - documentation + - docs + + - title: Dependency Updates ⬆️ + labels: + - dependencies + + - title: Other Changes + labels: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e9744066 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +name: CI + +# yamllint disable-line rule:truthy +on: + pull_request: {} + push: + branches: + - main + - master + workflow_dispatch: + inputs: + beaker_staging_url: + description: |- + URL to a staging Server to test unreleased packages. + We will append the version to the Server and assume all packages are in the same directory. + Only supported for AIO packages. + required: false + type: string + default: 'https://artifacts.voxpupuli.org/openvox-agent' + beaker_collection: + description: |- + When set to staging, we will download the packages from staging_url. + Otherwise we will use the official repos. Supported values: puppet7, puppet8, openvox7, openvox8, staging. + When unset, we will generate a list of supported collections based on metadata.json. + required: false + type: string + beaker_staging_version: + description: |- + The package version we want to test. + Only used for beaker_collection = staging + required: false + type: string + +concurrency: + group: ${{ github.ref_name }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + puppet: + name: Puppet + uses: voxpupuli/gha-puppet/.github/workflows/beaker.yml@v4 + with: + beaker_staging_url: ${{ inputs.beaker_staging_url }} + beaker_collection: ${{ inputs.beaker_collection }} + beaker_staging_version: ${{ inputs.beaker_staging_version }} diff --git a/.github/workflows/create_tag.yml b/.github/workflows/create_tag.yml new file mode 100644 index 00000000..c835e75a --- /dev/null +++ b/.github/workflows/create_tag.yml @@ -0,0 +1,22 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +name: Create Git tag + +on: + workflow_dispatch: + +permissions: {} + +jobs: + create_tag: + uses: 'voxpupuli/gha-puppet/.github/workflows/create_tag.yml@v4' + with: + allowed_owner: 'voxpupuli' + git_name: 'pccibot' + git_email: '12855858+pccibot@users.noreply.github.com' + secrets: + # Configure secrets here: + # https://docs.github.com/en/actions/security-guides/encrypted-secrets + ssh_private_key: ${{ secrets.PCCI_SSH_PRIVATE_KEY }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 00000000..eacd0b33 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,22 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +name: "Pull Request Labeler" + +# yamllint disable-line rule:truthy +on: + pull_request_target: {} + +permissions: + contents: read + pull-requests: write + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 diff --git a/.github/workflows/prepare_release.yml b/.github/workflows/prepare_release.yml new file mode 100644 index 00000000..b3725319 --- /dev/null +++ b/.github/workflows/prepare_release.yml @@ -0,0 +1,30 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +name: 'Prepare Release' + +on: + workflow_dispatch: + inputs: + version: + description: 'Module version to be released. Must be a valid semver string without leading v. (1.2.3)' + required: false + +permissions: + contents: write + pull-requests: write + +jobs: + release_prep: + uses: 'voxpupuli/gha-puppet/.github/workflows/prepare_release.yml@v4' + with: + version: ${{ github.event.inputs.version }} + allowed_owner: 'voxpupuli' + git_name: 'pccibot' + git_email: '12855858+pccibot@users.noreply.github.com' + secrets: + # Configure secrets here: + # https://docs.github.com/en/actions/security-guides/encrypted-secrets + github_pat: '${{ secrets.PCCI_PAT_RELEASE_PREP }}' + ssh_private_key: '${{ secrets.PCCI_SSH_PRIVATE_KEY }}' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..9062a93c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +name: Release + +# yamllint disable-line rule:truthy +on: + push: + tags: + # https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onpushbranchestagsbranches-ignoretags-ignore + # https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#filter-pattern-cheat-sheet + - 'v[0-9]+.[0-9]+.[0-9]+' + +permissions: + contents: write + +jobs: + release: + name: Release + uses: voxpupuli/gha-puppet/.github/workflows/release.yml@v4 + with: + allowed_owner: 'voxpupuli' + secrets: + # Configure secrets here: + # https://docs.github.com/en/actions/security-guides/encrypted-secrets + username: ${{ secrets.PUPPET_FORGE_USERNAME }} + api_key: ${{ secrets.PUPPET_FORGE_API_KEY }} diff --git a/.gitignore b/.gitignore index e9b3cf4b..adea1b01 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,25 @@ -pkg/ -Gemfile.lock -Gemfile.local -vendor/ -.vendor/ -spec/fixtures/manifests/ -spec/fixtures/modules/ -.vagrant/ -.bundle/ -.ruby-version -coverage/ -log/ -.idea/ -.dependencies/ -.librarian/ -Puppetfile.lock +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +/pkg/ +/Gemfile.lock +/Gemfile.local +/vendor/ +/.vendor/ +/spec/fixtures/manifests/ +/spec/fixtures/modules/ +/.vagrant/ +/.bundle/ +/.ruby-version +/coverage/ +/log/ +/.idea/ +/.dependencies/ +/.librarian/ +/Puppetfile.lock *.iml .*.sw? -.yardoc/ -Guardfile +/.yardoc/ +/Guardfile +bolt-debug.log +.rerun.json diff --git a/.msync.yml b/.msync.yml index 4c6463a5..bfb9bee8 100644 --- a/.msync.yml +++ b/.msync.yml @@ -1 +1,5 @@ -modulesync_config_version: '2.5.1' +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +modulesync_config_version: '10.8.0' diff --git a/.overcommit.yml b/.overcommit.yml index 1b03fad7..4ed994cc 100644 --- a/.overcommit.yml +++ b/.overcommit.yml @@ -1,4 +1,5 @@ -# Managed by https://github.com/voxpupuli/modulesync_configs +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ # # Hooks are only enabled if you take action. # @@ -42,10 +43,12 @@ PreCommit: enabled: true description: 'Runs rubocop on modified files only' command: ['bundle', 'exec', 'rubocop'] - PuppetLint: + RakeTarget: enabled: true - description: 'Runs puppet-lint on modified files only' - command: ['bundle', 'exec', 'puppet-lint'] + description: 'Runs lint on modified files only' + targets: + - 'lint' + command: ['bundle', 'exec', 'rake'] YamlSyntax: enabled: true JsonSyntax: @@ -61,4 +64,4 @@ PrePush: - 'validate' - 'test' - 'rubocop' - command: [ 'bundle', 'exec', 'rake' ] + command: ['bundle', 'exec', 'rake'] diff --git a/.pmtignore b/.pmtignore index 4e6d54b8..a9d37aa0 100644 --- a/.pmtignore +++ b/.pmtignore @@ -1,21 +1,39 @@ -docs/ -pkg/ -Gemfile.lock -Gemfile.local -vendor/ -.vendor/ -spec/fixtures/manifests/ -spec/fixtures/modules/ -.vagrant/ -.bundle/ -.ruby-version -coverage/ -log/ -.idea/ -.dependencies/ -.librarian/ -Puppetfile.lock +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +/docs/ +/pkg/ +/Gemfile +/Gemfile.lock +/Gemfile.local +/vendor/ +/.vendor/ +/spec/ +/Rakefile +/.vagrant/ +/.bundle/ +/.ruby-version +/coverage/ +/log/ +/.idea/ +/.dependencies/ +/.github/ +/.librarian/ +/Puppetfile.lock +/Puppetfile *.iml +/.editorconfig +/.fixtures.yml +/.gitignore +/.msync.yml +/.overcommit.yml +/.pmtignore +/.rspec +/.rspec_parallel +/.rubocop.yml +/.sync.yml .*.sw? -.yardoc/ -Dockerfile +/.yardoc/ +/.yardopts +/Dockerfile +/HISTORY.md diff --git a/.puppet-lint.rc b/.puppet-lint.rc new file mode 100644 index 00000000..420e819f --- /dev/null +++ b/.puppet-lint.rc @@ -0,0 +1,5 @@ +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +--fail-on-warnings +--no-parameter_documentation-check diff --git a/.rspec b/.rspec deleted file mode 100644 index 8c18f1ab..00000000 --- a/.rspec +++ /dev/null @@ -1,2 +0,0 @@ ---format documentation ---color diff --git a/.rspec_parallel b/.rspec_parallel deleted file mode 100644 index e4d136b7..00000000 --- a/.rspec_parallel +++ /dev/null @@ -1 +0,0 @@ ---format progress diff --git a/.rubocop.yml b/.rubocop.yml index 099a11c5..fded90cf 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,545 +1,7 @@ -require: rubocop-rspec -AllCops: - TargetRubyVersion: 1.9 - Include: - - ./**/*.rb - Exclude: - - files/**/* - - vendor/**/* - - .vendor/**/* - - pkg/**/* - - spec/fixtures/**/* - - Gemfile - - Rakefile - - Guardfile - - Vagrantfile -Lint/ConditionPosition: - Enabled: True +--- +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ -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_from: .rubocop_todo.yml +inherit_gem: + voxpupuli-test: rubocop.yml diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..f8daacee --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,13 @@ +# This configuration was generated by +# `rubocop --auto-gen-config --no-auto-gen-timestamp` +# using RuboCop version 1.85.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 3 +RSpec/LeakyLocalVariable: + Exclude: + - 'spec/acceptance/class_spec.rb' + - 'spec/acceptance/facts_test_spec.rb' diff --git a/.sync.yml b/.sync.yml index b502a785..4fa6b004 100644 --- a/.sync.yml +++ b/.sync.yml @@ -1,10 +1,6 @@ --- -.travis.yml: - secret: "bBDDSSz8OQwK0zxJ4EjM01bE4uoNMzTXyxp2lllXdv6PYAJCI4bCCcdRF7OKLAWaRtm6c0HJGnfMXzmwqHF/pJSUZzfTGe4uwZrrmaGvdalP4fXtLWpviAoez8La0Nx7JYqwPPprP7nySBD8M3rUuOZJetXQM6yGgj4YSs2lKMo=" - docker_sets: - - set: ubuntu1404-64 - - set: ubuntu1604-64 - - set: ubuntu1804-64 - - set: debian8-64 - - set: debian9-64 - - set: centos7-64 +spec/spec_helper_acceptance.rb: + unmanaged: false +.puppet-lint.rc: + enabled_lint_checks: + - parameter_types diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a9f30f46..00000000 --- a/.travis.yml +++ /dev/null @@ -1,119 +0,0 @@ ---- -dist: xenial -language: ruby -cache: bundler -before_install: - - gem update --system - - gem update bundler - - bundle --version -script: - - 'bundle exec rake $CHECK' -matrix: - 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=ubuntu1404-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=ubuntu1404-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-nightly BEAKER_debug=true BEAKER_setfile=ubuntu1404-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=puppet6-nightly 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.5.3 - bundler_args: --without development release - env: PUPPET_INSTALL_TYPE=agent BEAKER_IS_PE=no BEAKER_PUPPET_COLLECTION=puppet6-nightly 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=puppet5 BEAKER_debug=true BEAKER_setfile=debian8-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=debian8-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-nightly BEAKER_debug=true BEAKER_setfile=debian8-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=puppet6-nightly 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=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=puppet6-nightly BEAKER_debug=true BEAKER_setfile=centos7-64 BEAKER_HYPERVISOR=docker CHECK=beaker - services: docker -branches: - only: - - master - - /^v\d/ -notifications: - email: false - irc: - on_success: always - on_failure: always - channels: - - "chat.freenode.org#voxpupuli-notifications" -deploy: - provider: puppetforge - user: puppet - password: - secure: "" - on: - tags: true - # all_branches is required to use tags - all_branches: true - # Only publish the build marked with "DEPLOY_TO_FORGE" - condition: "$DEPLOY_TO_FORGE = yes" diff --git a/.yardopts b/.yardopts deleted file mode 100644 index 3687f518..00000000 --- a/.yardopts +++ /dev/null @@ -1,2 +0,0 @@ ---markup markdown ---output-dir docs/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ef5be38..2c8c0db3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,411 @@ 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. +## [v9.0.0](https://github.com/voxpupuli/puppet-python/tree/v9.0.0) (2026-05-05) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v8.0.0...v9.0.0) + +**Breaking changes:** + +- `init.pp`: remove useless `exec` with `default` title that was trying to set a default `umask` [\#735](https://github.com/voxpupuli/puppet-python/pull/735) ([kenyon](https://github.com/kenyon)) +- Drop puppet, update openvox minimum version to 8.19 [\#729](https://github.com/voxpupuli/puppet-python/pull/729) ([TheMeier](https://github.com/TheMeier)) + +**Implemented enhancements:** + +- puppet/epel: Allow 6.x [\#751](https://github.com/voxpupuli/puppet-python/pull/751) ([bastelfreak](https://github.com/bastelfreak)) +- Add support for Debian 13 [\#740](https://github.com/voxpupuli/puppet-python/pull/740) ([smortex](https://github.com/smortex)) +- Do not pass `--log` to `pip install` [\#736](https://github.com/voxpupuli/puppet-python/pull/736) ([smortex](https://github.com/smortex)) +- Allow a version to start with "v" in `python::pip` [\#727](https://github.com/voxpupuli/puppet-python/pull/727) ([techsk8](https://github.com/techsk8)) + +**Fixed bugs:** + +- Fix group ownership for `pip.conf` on FreeBSD [\#739](https://github.com/voxpupuli/puppet-python/pull/739) ([Szparki](https://github.com/Szparki)) +- Replace legacy fact in gunicorn config templating [\#724](https://github.com/voxpupuli/puppet-python/pull/724) ([notCalle](https://github.com/notCalle)) + +**Closed issues:** + +- "Error: Could not find group root" on FreeBSD [\#738](https://github.com/voxpupuli/puppet-python/issues/738) +- Define pip\_package in hieradata [\#731](https://github.com/voxpupuli/puppet-python/issues/731) + +**Merged pull requests:** + +- Add section in README that simulates `python3 -m pip install pandas --user` [\#725](https://github.com/voxpupuli/puppet-python/pull/725) ([bschonec](https://github.com/bschonec)) + +## [v8.0.0](https://github.com/voxpupuli/puppet-python/tree/v8.0.0) (2025-04-28) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v7.4.0...v8.0.0) + +**Breaking changes:** + +- Drop EoL Ubuntu 20.04 support [\#719](https://github.com/voxpupuli/puppet-python/pull/719) ([smortex](https://github.com/smortex)) +- Drop EoL FreeBSD 11/12 support [\#718](https://github.com/voxpupuli/puppet-python/pull/718) ([smortex](https://github.com/smortex)) +- Drop EoL Ubuntu 18.04 support [\#710](https://github.com/voxpupuli/puppet-python/pull/710) ([bastelfreak](https://github.com/bastelfreak)) +- Drop EoL CentOS 7/8 support [\#709](https://github.com/voxpupuli/puppet-python/pull/709) ([bastelfreak](https://github.com/bastelfreak)) +- Drop EoL Debian 10 support [\#708](https://github.com/voxpupuli/puppet-python/pull/708) ([bastelfreak](https://github.com/bastelfreak)) + +**Fixed bugs:** + +- Fix bootstrapping `python::pyvenv` when Python is not installed [\#716](https://github.com/voxpupuli/puppet-python/pull/716) ([smortex](https://github.com/smortex)) + +## [v7.4.0](https://github.com/voxpupuli/puppet-python/tree/v7.4.0) (2024-11-27) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v7.3.0...v7.4.0) + +**Implemented enhancements:** + +- Add Ubuntu 24.04 support [\#707](https://github.com/voxpupuli/puppet-python/pull/707) ([bastelfreak](https://github.com/bastelfreak)) +- pyvenv: Harden datatype for `$environment` [\#704](https://github.com/voxpupuli/puppet-python/pull/704) ([bastelfreak](https://github.com/bastelfreak)) +- simplify packages version detection [\#703](https://github.com/voxpupuli/puppet-python/pull/703) ([maxadamo](https://github.com/maxadamo)) +- Add support for FreeBSD 14 [\#694](https://github.com/voxpupuli/puppet-python/pull/694) ([smortex](https://github.com/smortex)) + +**Fixed bugs:** + +- `python::pip`'s `notreallyaversion` is not compatible with latest `pip` \(\>= 24.1\) due to changed output \(again\) [\#695](https://github.com/voxpupuli/puppet-python/issues/695) +- Fix `python::pip` - use valid, but highly unlikely package version [\#696](https://github.com/voxpupuli/puppet-python/pull/696) ([acojocariu1-godaddy](https://github.com/acojocariu1-godaddy)) + +**Merged pull requests:** + +- CI: Dont pin pip to an outdated version and don't force python3 package installation [\#706](https://github.com/voxpupuli/puppet-python/pull/706) ([bastelfreak](https://github.com/bastelfreak)) + +## [v7.3.0](https://github.com/voxpupuli/puppet-python/tree/v7.3.0) (2024-02-08) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v7.2.0...v7.3.0) + +**Implemented enhancements:** + +- Add python\_path to pyvenv class [\#686](https://github.com/voxpupuli/puppet-python/pull/686) ([wmellema](https://github.com/wmellema)) + +## [v7.2.0](https://github.com/voxpupuli/puppet-python/tree/v7.2.0) (2024-01-01) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v7.1.0...v7.2.0) + +**Implemented enhancements:** + +- Add Support for RedHat/CentOS 9 [\#676](https://github.com/voxpupuli/puppet-python/pull/676) ([ValdrinLushaj](https://github.com/ValdrinLushaj)) + +**Fixed bugs:** + +- Make latest version detection portable [\#682](https://github.com/voxpupuli/puppet-python/pull/682) ([smortex](https://github.com/smortex)) + +## [v7.1.0](https://github.com/voxpupuli/puppet-python/tree/v7.1.0) (2023-11-29) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v7.0.0...v7.1.0) + +**Implemented enhancements:** + +- Add Ubuntu 22.04 support [\#679](https://github.com/voxpupuli/puppet-python/pull/679) ([bastelfreak](https://github.com/bastelfreak)) +- Add Debian 12 support [\#678](https://github.com/voxpupuli/puppet-python/pull/678) ([bastelfreak](https://github.com/bastelfreak)) +- Add OracleLinux/AlmaLinux/Rocky support [\#677](https://github.com/voxpupuli/puppet-python/pull/677) ([JakeTRogers](https://github.com/JakeTRogers)) +- Bump puppet-epel to allow 5.x [\#674](https://github.com/voxpupuli/puppet-python/pull/674) ([dandunckelman](https://github.com/dandunckelman)) +- Allow to skip management of python dev package [\#669](https://github.com/voxpupuli/puppet-python/pull/669) ([smortex](https://github.com/smortex)) + +**Fixed bugs:** + +- Use the wheel group by default on FreeBSD [\#672](https://github.com/voxpupuli/puppet-python/pull/672) ([smortex](https://github.com/smortex)) +- If user declares their requirements.txt in Puppet, don't skip pip installation in python::requirements [\#619](https://github.com/voxpupuli/puppet-python/pull/619) ([acullenn](https://github.com/acullenn)) + +## [v7.0.0](https://github.com/voxpupuli/puppet-python/tree/v7.0.0) (2023-07-27) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.4.0...v7.0.0) + +**Breaking changes:** + +- Drop Ubuntu 16.04 \(EOL\) [\#659](https://github.com/voxpupuli/puppet-python/pull/659) ([smortex](https://github.com/smortex)) +- Drop Debian 9 \(EOL\) [\#658](https://github.com/voxpupuli/puppet-python/pull/658) ([smortex](https://github.com/smortex)) +- Drop Puppet 6 support [\#656](https://github.com/voxpupuli/puppet-python/pull/656) ([bastelfreak](https://github.com/bastelfreak)) + +**Implemented enhancements:** + +- Add Puppet 8 support [\#664](https://github.com/voxpupuli/puppet-python/pull/664) ([bastelfreak](https://github.com/bastelfreak)) +- puppetlabs/stdlib: Allow 9.x [\#663](https://github.com/voxpupuli/puppet-python/pull/663) ([bastelfreak](https://github.com/bastelfreak)) + +**Fixed bugs:** + +- Fix pip installation on Gentoo [\#651](https://github.com/voxpupuli/puppet-python/pull/651) ([puppetjoy](https://github.com/puppetjoy)) + +## [v6.4.0](https://github.com/voxpupuli/puppet-python/tree/v6.4.0) (2022-11-06) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.3.0...v6.4.0) + +**Implemented enhancements:** + +- move static data from params.pp to init.pp [\#648](https://github.com/voxpupuli/puppet-python/pull/648) ([bastelfreak](https://github.com/bastelfreak)) +- cleanup acceptance tests [\#647](https://github.com/voxpupuli/puppet-python/pull/647) ([bastelfreak](https://github.com/bastelfreak)) +- Implement Arch Linux support [\#642](https://github.com/voxpupuli/puppet-python/pull/642) ([bastelfreak](https://github.com/bastelfreak)) +- Add prompt parameter to python::pyvenv [\#641](https://github.com/voxpupuli/puppet-python/pull/641) ([ookisan](https://github.com/ookisan)) +- Add extra\_index parameter to python::pip [\#640](https://github.com/voxpupuli/puppet-python/pull/640) ([ookisan](https://github.com/ookisan)) + +**Fixed bugs:** + +- use legacy pip resolver for pip versions \< 21.1 \> 20.2.4 [\#639](https://github.com/voxpupuli/puppet-python/pull/639) ([saz](https://github.com/saz)) + +## [v6.3.0](https://github.com/voxpupuli/puppet-python/tree/v6.3.0) (2022-07-18) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.2.1...v6.3.0) + +**Implemented enhancements:** + +- allow puppet/epel v4 [\#634](https://github.com/voxpupuli/puppet-python/pull/634) ([vchepkov](https://github.com/vchepkov)) +- cleanup references to obsolete virtualenv parameter/command [\#633](https://github.com/voxpupuli/puppet-python/pull/633) ([vchepkov](https://github.com/vchepkov)) + +**Fixed bugs:** + +- Add python-venv installation [\#579](https://github.com/voxpupuli/puppet-python/pull/579) ([crazymind1337](https://github.com/crazymind1337)) + +## [v6.2.1](https://github.com/voxpupuli/puppet-python/tree/v6.2.1) (2021-12-10) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.2.0...v6.2.1) + +**Fixed bugs:** + +- Correct python::pip::environment parameter example [\#629](https://github.com/voxpupuli/puppet-python/pull/629) ([traylenator](https://github.com/traylenator)) +- gunicorn: RHEL8 has a different package name [\#628](https://github.com/voxpupuli/puppet-python/pull/628) ([yakatz](https://github.com/yakatz)) +- Remove duplicate arguments in the pip install command [\#627](https://github.com/voxpupuli/puppet-python/pull/627) ([zanyou](https://github.com/zanyou)) + +**Closed issues:** + +- Package with provider pip3 tries installing every run. [\#626](https://github.com/voxpupuli/puppet-python/issues/626) + +**Merged pull requests:** + +- modulesync 5.1.0 & puppet-lint: fix params\_empty\_string\_assignment [\#631](https://github.com/voxpupuli/puppet-python/pull/631) ([bastelfreak](https://github.com/bastelfreak)) + +## [v6.2.0](https://github.com/voxpupuli/puppet-python/tree/v6.2.0) (2021-08-26) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.1.0...v6.2.0) + +**Implemented enhancements:** + +- Add support for Debian 11 [\#621](https://github.com/voxpupuli/puppet-python/pull/621) ([smortex](https://github.com/smortex)) + +**Merged pull requests:** + +- Allow stdlib 8.0.0 [\#622](https://github.com/voxpupuli/puppet-python/pull/622) ([smortex](https://github.com/smortex)) + +## [v6.1.0](https://github.com/voxpupuli/puppet-python/tree/v6.1.0) (2021-06-05) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.0.1...v6.1.0) + +Due to a bug in the release pipeline, release v6.0.1 didn't make it to the forge. v6.0.2 just contains [modulesync 4.1.0](https://github.com/voxpupuli/modulesync_config/blob/master/CHANGELOG.md#410-2021-04-03) patch. + +**Implemented enhancements:** + +- Add support for FreeBSD [\#612](https://github.com/voxpupuli/puppet-python/pull/612) ([smortex](https://github.com/smortex)) + +**Closed issues:** + +- Can't uninstall pip package because of duplicate variable name [\#532](https://github.com/voxpupuli/puppet-python/issues/532) +- audit metaparameter is deprecated [\#375](https://github.com/voxpupuli/puppet-python/issues/375) + +## [v6.0.1](https://github.com/voxpupuli/puppet-python/tree/v6.0.1) (2021-04-29) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v6.0.0...v6.0.1) + +**Fixed bugs:** + +- Use $real\_pkgname for pip uninstall command [\#607](https://github.com/voxpupuli/puppet-python/pull/607) ([brabiega](https://github.com/brabiega)) + +**Closed issues:** + +- Pip uninstall does not support pkgname variable [\#606](https://github.com/voxpupuli/puppet-python/issues/606) + +## [v6.0.0](https://github.com/voxpupuli/puppet-python/tree/v6.0.0) (2021-04-03) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v5.0.0...v6.0.0) + +**Breaking changes:** + +- Drop Puppet 5 support [\#603](https://github.com/voxpupuli/puppet-python/pull/603) ([bastelfreak](https://github.com/bastelfreak)) +- Drop python::virtualenv defined resource [\#596](https://github.com/voxpupuli/puppet-python/pull/596) ([bastelfreak](https://github.com/bastelfreak)) +- Set default python to 3 [\#595](https://github.com/voxpupuli/puppet-python/pull/595) ([bastelfreak](https://github.com/bastelfreak)) + +**Implemented enhancements:** + +- Add the possibility to specify the pip version in virtual envs [\#599](https://github.com/voxpupuli/puppet-python/pull/599) ([SaschaDoering](https://github.com/SaschaDoering)) +- Add Support for RedHat/CentOS 8 [\#594](https://github.com/voxpupuli/puppet-python/pull/594) ([treydock](https://github.com/treydock)) +- enhance pyvenv tests [\#590](https://github.com/voxpupuli/puppet-python/pull/590) ([bastelfreak](https://github.com/bastelfreak)) +- Add Debian 10 support [\#573](https://github.com/voxpupuli/puppet-python/pull/573) ([bastelfreak](https://github.com/bastelfreak)) + +**Fixed bugs:** + +- Fix python::virtualenv to allow virtualenv to not require absolute path [\#592](https://github.com/voxpupuli/puppet-python/pull/592) ([treydock](https://github.com/treydock)) +- python::gunicorn: Fix typo in datatype [\#585](https://github.com/voxpupuli/puppet-python/pull/585) ([bastelfreak](https://github.com/bastelfreak)) + +**Closed issues:** + +- Setting Pip Version for Virtual Environments [\#559](https://github.com/voxpupuli/puppet-python/issues/559) +- Can't install this using librarian-puppet [\#406](https://github.com/voxpupuli/puppet-python/issues/406) + +**Merged pull requests:** + +- puppetlabs/stdlib: Allow 7.x [\#604](https://github.com/voxpupuli/puppet-python/pull/604) ([bastelfreak](https://github.com/bastelfreak)) +- Support Puppet 7 [\#602](https://github.com/voxpupuli/puppet-python/pull/602) ([mattock](https://github.com/mattock)) +- Support Ubuntu 20.04 [\#593](https://github.com/voxpupuli/puppet-python/pull/593) ([treydock](https://github.com/treydock)) +- Add pyvenv acceptance test [\#588](https://github.com/voxpupuli/puppet-python/pull/588) ([bastelfreak](https://github.com/bastelfreak)) +- General linting/indent/syntax [\#580](https://github.com/voxpupuli/puppet-python/pull/580) ([crazymind1337](https://github.com/crazymind1337)) +- Use Python 3 for virtualenv tests [\#575](https://github.com/voxpupuli/puppet-python/pull/575) ([waipeng](https://github.com/waipeng)) +- Add acceptance test for managing Python 3 [\#572](https://github.com/voxpupuli/puppet-python/pull/572) ([bastelfreak](https://github.com/bastelfreak)) + +## [v5.0.0](https://github.com/voxpupuli/puppet-python/tree/v5.0.0) (2020-09-23) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v4.1.1...v5.0.0) + +**Breaking changes:** + +- Drop CentOS 6 support [\#566](https://github.com/voxpupuli/puppet-python/pull/566) ([bastelfreak](https://github.com/bastelfreak)) +- Drop EOL Debian 8 [\#563](https://github.com/voxpupuli/puppet-python/pull/563) ([bastelfreak](https://github.com/bastelfreak)) + +**Fixed bugs:** + +- Fix undefined method error in facts [\#555](https://github.com/voxpupuli/puppet-python/pull/555) ([wiebe](https://github.com/wiebe)) + +**Closed issues:** + +- "warning: already initialized constant PIP\_VERSION" when upgrading to agent 6.15.0 [\#553](https://github.com/voxpupuli/puppet-python/issues/553) +- "undefined method \[\]" in pip\_version and virtualenv\_version facts [\#527](https://github.com/voxpupuli/puppet-python/issues/527) +- Deprecation Warnings - Mocha mock\_with [\#432](https://github.com/voxpupuli/puppet-python/issues/432) + +**Merged pull requests:** + +- delete legacy nodesets [\#562](https://github.com/voxpupuli/puppet-python/pull/562) ([bastelfreak](https://github.com/bastelfreak)) +- modulesync 3.0.0 & puppet-lint updates [\#556](https://github.com/voxpupuli/puppet-python/pull/556) ([bastelfreak](https://github.com/bastelfreak)) +- Convert unit tests to rspec rather than 'mocha' [\#554](https://github.com/voxpupuli/puppet-python/pull/554) ([KeithWard](https://github.com/KeithWard)) + +## [v4.1.1](https://github.com/voxpupuli/puppet-python/tree/v4.1.1) (2020-04-30) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v4.1.0...v4.1.1) + +**Fixed bugs:** + +- Fixes for virtualenv\_version fact when virtualenv \> 20.x [\#537](https://github.com/voxpupuli/puppet-python/pull/537) ([pjonesIDBS](https://github.com/pjonesIDBS)) + +## [v4.1.0](https://github.com/voxpupuli/puppet-python/tree/v4.1.0) (2020-04-26) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v4.0.0...v4.1.0) + +**Implemented enhancements:** + +- Add option for not managing python and virtualenv packages. [\#500](https://github.com/voxpupuli/puppet-python/pull/500) ([tdukaric](https://github.com/tdukaric)) + +**Fixed bugs:** + +- Wrong pip referenced inside virtualenv [\#505](https://github.com/voxpupuli/puppet-python/issues/505) +- CentOS: Fix ordering dependency [\#546](https://github.com/voxpupuli/puppet-python/pull/546) ([bastelfreak](https://github.com/bastelfreak)) +- switch from stahnma/epel to puppet/epel / Ubuntu 16.04: Execute tests on Python 3 [\#545](https://github.com/voxpupuli/puppet-python/pull/545) ([bastelfreak](https://github.com/bastelfreak)) +- Remove resource collector overriding pip\_provider [\#511](https://github.com/voxpupuli/puppet-python/pull/511) ([jplindquist](https://github.com/jplindquist)) + +**Closed issues:** + +- python3.6+ venv proper installation command [\#533](https://github.com/voxpupuli/puppet-python/issues/533) +- Virtualenv doesn't install with the right python [\#384](https://github.com/voxpupuli/puppet-python/issues/384) + +**Merged pull requests:** + +- Use voxpupuli-acceptance [\#543](https://github.com/voxpupuli/puppet-python/pull/543) ([ekohl](https://github.com/ekohl)) +- update repo links to https [\#531](https://github.com/voxpupuli/puppet-python/pull/531) ([bastelfreak](https://github.com/bastelfreak)) + +## [v4.0.0](https://github.com/voxpupuli/puppet-python/tree/v4.0.0) (2019-12-10) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v3.0.1...v4.0.0) + +**Breaking changes:** + +- Drop Ubuntu 14.04 support [\#515](https://github.com/voxpupuli/puppet-python/pull/515) ([bastelfreak](https://github.com/bastelfreak)) + +**Fixed bugs:** + +- Allow python::version to contain a point \(e.g. python3.7\) [\#523](https://github.com/voxpupuli/puppet-python/pull/523) ([baurmatt](https://github.com/baurmatt)) +- Fix duplicate declaration for python-venv package [\#518](https://github.com/voxpupuli/puppet-python/pull/518) ([baurmatt](https://github.com/baurmatt)) +- Use shell to exec pip commands by default [\#498](https://github.com/voxpupuli/puppet-python/pull/498) ([jamebus](https://github.com/jamebus)) +- Fix a reassigned variable [\#497](https://github.com/voxpupuli/puppet-python/pull/497) ([SaschaDoering](https://github.com/SaschaDoering)) + +**Closed issues:** + +- Duplicate declaration for python$version-venv [\#517](https://github.com/voxpupuli/puppet-python/issues/517) +- Python 3.6 on ubuntu 18.04 not working [\#508](https://github.com/voxpupuli/puppet-python/issues/508) +- Module does not recognize Debian python package name [\#506](https://github.com/voxpupuli/puppet-python/issues/506) +- Gunicorn via Hiera [\#499](https://github.com/voxpupuli/puppet-python/issues/499) +- Python::Pip fails if $ensure='absent' [\#496](https://github.com/voxpupuli/puppet-python/issues/496) + +**Merged pull requests:** + +- Clean up requirements\_spec.rb [\#521](https://github.com/voxpupuli/puppet-python/pull/521) ([ekohl](https://github.com/ekohl)) +- Switch to int\_date for acceptance test [\#519](https://github.com/voxpupuli/puppet-python/pull/519) ([baurmatt](https://github.com/baurmatt)) +- Upgrade pip and setuptools on venv creation [\#516](https://github.com/voxpupuli/puppet-python/pull/516) ([baurmatt](https://github.com/baurmatt)) +- Recognize Debian python package name, fixes: \#506 [\#514](https://github.com/voxpupuli/puppet-python/pull/514) ([lordievader](https://github.com/lordievader)) +- Clean up acceptance spec helper [\#512](https://github.com/voxpupuli/puppet-python/pull/512) ([ekohl](https://github.com/ekohl)) +- Add badges to README [\#495](https://github.com/voxpupuli/puppet-python/pull/495) ([alexjfisher](https://github.com/alexjfisher)) + +## [v3.0.1](https://github.com/voxpupuli/puppet-python/tree/v3.0.1) (2019-06-13) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v3.0.0...v3.0.1) + +**Merged pull requests:** + +- Fix travis secret [\#493](https://github.com/voxpupuli/puppet-python/pull/493) ([alexjfisher](https://github.com/alexjfisher)) + +## [v3.0.0](https://github.com/voxpupuli/puppet-python/tree/v3.0.0) (2019-06-13) + +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v2.2.2...v3.0.0) + +**Breaking changes:** + +- modulesync 2.5.1 and drop Puppet 4 [\#467](https://github.com/voxpupuli/puppet-python/pull/467) ([bastelfreak](https://github.com/bastelfreak)) + +**Implemented enhancements:** + +- Allow HTTP\_PROXY on bootstrap. [\#488](https://github.com/voxpupuli/puppet-python/pull/488) ([pillarsdotnet](https://github.com/pillarsdotnet)) +- Modern pip can install wheels without wheel installed [\#483](https://github.com/voxpupuli/puppet-python/pull/483) ([asottile](https://github.com/asottile)) +- Allow arbitrary pip providers [\#480](https://github.com/voxpupuli/puppet-python/pull/480) ([emmatyping](https://github.com/emmatyping)) +- Add manage\_scl boolean to control managing SCL [\#464](https://github.com/voxpupuli/puppet-python/pull/464) ([bodgit](https://github.com/bodgit)) +- Allow pip to work in AIX systems [\#461](https://github.com/voxpupuli/puppet-python/pull/461) ([feltra](https://github.com/feltra)) +- move pip bootstrap into a seperate class [\#460](https://github.com/voxpupuli/puppet-python/pull/460) ([feltra](https://github.com/feltra)) +- Allow custom python versions and environments [\#451](https://github.com/voxpupuli/puppet-python/pull/451) ([jradmacher](https://github.com/jradmacher)) + +**Fixed bugs:** + +- Installing from git repo runs install on every Puppet run [\#193](https://github.com/voxpupuli/puppet-python/issues/193) +- Fix python::pip installing $editable VCS packages every Puppet run [\#491](https://github.com/voxpupuli/puppet-python/pull/491) ([mlow](https://github.com/mlow)) +- Fix $subscribe overloading [\#490](https://github.com/voxpupuli/puppet-python/pull/490) ([nward](https://github.com/nward)) +- Fix version-check. [\#489](https://github.com/voxpupuli/puppet-python/pull/489) ([pillarsdotnet](https://github.com/pillarsdotnet)) +- Update version validation [\#472](https://github.com/voxpupuli/puppet-python/pull/472) ([bodgit](https://github.com/bodgit)) +- Normalize Python version in `python::pyvenv` [\#466](https://github.com/voxpupuli/puppet-python/pull/466) ([thaiphv](https://github.com/thaiphv)) +- Fix Ubuntu bionic package installation [\#450](https://github.com/voxpupuli/puppet-python/pull/450) ([ekohl](https://github.com/ekohl)) +- Fix $filename and $mode types in python::dotfile [\#446](https://github.com/voxpupuli/puppet-python/pull/446) ([gdubicki](https://github.com/gdubicki)) +- Stop using 'pip search' for ensure =\> latest [\#434](https://github.com/voxpupuli/puppet-python/pull/434) ([gdubicki](https://github.com/gdubicki)) + +**Closed issues:** + +- Should set permissive umask before exec. [\#486](https://github.com/voxpupuli/puppet-python/issues/486) +- When updating pip via puppet-python, an error occurs. [\#484](https://github.com/voxpupuli/puppet-python/issues/484) +- Not possible to install Python-3 with this module [\#482](https://github.com/voxpupuli/puppet-python/issues/482) +- Cannot install pre-commit pip. [\#481](https://github.com/voxpupuli/puppet-python/issues/481) +- Allow the use of pip3.4 and pip3.6 [\#476](https://github.com/voxpupuli/puppet-python/issues/476) +- python3\_version fact doesn't work on SCL [\#475](https://github.com/voxpupuli/puppet-python/issues/475) +- missing https\_proxy when using https pypi of other https indexes [\#473](https://github.com/voxpupuli/puppet-python/issues/473) +- Unable to use SCL version [\#471](https://github.com/voxpupuli/puppet-python/issues/471) +- Variable $subscribe shoud not be overwritten [\#470](https://github.com/voxpupuli/puppet-python/issues/470) +- Add switch to not manage SCL setup [\#463](https://github.com/voxpupuli/puppet-python/issues/463) +- update dependencies to stdlib \>= 4.19 [\#458](https://github.com/voxpupuli/puppet-python/issues/458) +- Impossible to use version number in Ubuntu 16.04 [\#448](https://github.com/voxpupuli/puppet-python/issues/448) +- Documentation still includes the deprecated stankevich-python module for installation [\#441](https://github.com/voxpupuli/puppet-python/issues/441) +- No puppet strings docs/class reference docs [\#439](https://github.com/voxpupuli/puppet-python/issues/439) +- python::pip ensure =\> latest triggers refresh on each puppet run for some packages [\#433](https://github.com/voxpupuli/puppet-python/issues/433) +- Support for Python3.6 executables [\#420](https://github.com/voxpupuli/puppet-python/issues/420) +- Python 3 + virtualenv + centos 7 not working [\#354](https://github.com/voxpupuli/puppet-python/issues/354) +- --no-use-wheel argument fails requirement installation [\#173](https://github.com/voxpupuli/puppet-python/issues/173) + +**Merged pull requests:** + +- 486 Set permissive umask. [\#487](https://github.com/voxpupuli/puppet-python/pull/487) ([pillarsdotnet](https://github.com/pillarsdotnet)) +- Update `puppetlabs/stdlib` dependency to allow 6.x and require at least 4.19.0 \(where the `fact()` function was introduced\) [\#485](https://github.com/voxpupuli/puppet-python/pull/485) ([pillarsdotnet](https://github.com/pillarsdotnet)) +- Update pip url regex to support 'git+git://\' [\#477](https://github.com/voxpupuli/puppet-python/pull/477) ([gharper](https://github.com/gharper)) +- README.md: remove obsolete and redundant sections [\#453](https://github.com/voxpupuli/puppet-python/pull/453) ([kenyon](https://github.com/kenyon)) +- remove .DS\_Store [\#452](https://github.com/voxpupuli/puppet-python/pull/452) ([kenyon](https://github.com/kenyon)) +- Change default indent to 2 Spaces in .editorconfig [\#449](https://github.com/voxpupuli/puppet-python/pull/449) ([jradmacher](https://github.com/jradmacher)) +- Replace deprecated validate\_\* functions [\#443](https://github.com/voxpupuli/puppet-python/pull/443) ([baurmatt](https://github.com/baurmatt)) +- Update modules with defined types for variables as described in docs/Add reference.md [\#440](https://github.com/voxpupuli/puppet-python/pull/440) ([danquack](https://github.com/danquack)) + ## [v2.2.2](https://github.com/voxpupuli/puppet-python/tree/v2.2.2) (2018-10-20) [Full Changelog](https://github.com/voxpupuli/puppet-python/compare/v2.2.0...v2.2.2) @@ -78,7 +483,7 @@ These should not affect the functionality of the module. **Implemented enhancements:** - Add Debian 9 Support [\#398](https://github.com/voxpupuli/puppet-python/issues/398) -- Add support for Anaconda [\#409](https://github.com/voxpupuli/puppet-python/pull/409) ([grsakea](https://github.com/grsakea)) +- Add support for Anaconda [\#409](https://github.com/voxpupuli/puppet-python/pull/409) ([jb-abbadie](https://github.com/jb-abbadie)) - Add umask parameter to pip execs [\#368](https://github.com/voxpupuli/puppet-python/pull/368) ([jstaph](https://github.com/jstaph)) **Closed issues:** @@ -93,9 +498,9 @@ These should not affect the functionality of the module. **Merged pull requests:** -- Fix Python version regex in install.pp [\#410](https://github.com/voxpupuli/puppet-python/pull/410) ([fklajn-opera](https://github.com/fklajn-opera)) +- Fix Python version regex in install.pp [\#410](https://github.com/voxpupuli/puppet-python/pull/410) ([fklajn](https://github.com/fklajn)) - Remove docker nodesets [\#408](https://github.com/voxpupuli/puppet-python/pull/408) ([bastelfreak](https://github.com/bastelfreak)) -- Update README compatibility section [\#405](https://github.com/voxpupuli/puppet-python/pull/405) ([rkcpi](https://github.com/rkcpi)) +- Update README compatibility section [\#405](https://github.com/voxpupuli/puppet-python/pull/405) ([sandra-thieme](https://github.com/sandra-thieme)) - add secret for forge deployment via travis [\#404](https://github.com/voxpupuli/puppet-python/pull/404) ([bastelfreak](https://github.com/bastelfreak)) - Add deprecation notice for the old repository [\#403](https://github.com/voxpupuli/puppet-python/pull/403) ([stankevich](https://github.com/stankevich)) - virtualenv.pp: make creation of $venv\_dir optional [\#391](https://github.com/voxpupuli/puppet-python/pull/391) ([daylicron](https://github.com/daylicron)) @@ -120,10 +525,10 @@ These should not affect the functionality of the module. - Fix tests: Pin rake for ruby 1.9.3 [\#387](https://github.com/voxpupuli/puppet-python/pull/387) ([waipeng](https://github.com/waipeng)) - Support virtualenv for Ubuntu 16.04 [\#386](https://github.com/voxpupuli/puppet-python/pull/386) ([waipeng](https://github.com/waipeng)) - Set virtualenv package name for Debian stretch [\#383](https://github.com/voxpupuli/puppet-python/pull/383) ([sergiik](https://github.com/sergiik)) -- Update gunicorn.pp - Add manage\_config\_dir [\#382](https://github.com/voxpupuli/puppet-python/pull/382) ([bc-bjoern](https://github.com/bc-bjoern)) +- Update gunicorn.pp - Add manage\_config\_dir [\#382](https://github.com/voxpupuli/puppet-python/pull/382) ([epik0r](https://github.com/epik0r)) - Support latest puppet versions [\#376](https://github.com/voxpupuli/puppet-python/pull/376) ([ghoneycutt](https://github.com/ghoneycutt)) - Add python release as available facts [\#355](https://github.com/voxpupuli/puppet-python/pull/355) ([jcpunk](https://github.com/jcpunk)) -- Allow hiera config for dotfiles [\#344](https://github.com/voxpupuli/puppet-python/pull/344) ([PuppetNinja](https://github.com/PuppetNinja)) +- Allow hiera config for dotfiles [\#344](https://github.com/voxpupuli/puppet-python/pull/344) ([puppetninja](https://github.com/puppetninja)) - Ensure value is a string for =~ comparison [\#342](https://github.com/voxpupuli/puppet-python/pull/342) ([ghoneycutt](https://github.com/ghoneycutt)) - add an alias to the python-dev package [\#334](https://github.com/voxpupuli/puppet-python/pull/334) ([dannygoulder](https://github.com/dannygoulder)) @@ -141,7 +546,7 @@ These should not affect the functionality of the module. ## [1.18.1](https://github.com/voxpupuli/puppet-python/tree/1.18.1) (2016-12-08) -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.4.2...1.18.1) +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.18.0...1.18.1) **Closed issues:** @@ -153,23 +558,15 @@ These should not affect the functionality of the module. - Add name of package to pip uninstall command [\#340](https://github.com/voxpupuli/puppet-python/pull/340) ([dontreboot](https://github.com/dontreboot)) - EPEL only makes sense on RH systems but not Fedora [\#297](https://github.com/voxpupuli/puppet-python/pull/297) ([jcpunk](https://github.com/jcpunk)) -## [2.4.2](https://github.com/voxpupuli/puppet-python/tree/2.4.2) (2016-10-28) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.18.0...2.4.2) - ## [1.18.0](https://github.com/voxpupuli/puppet-python/tree/1.18.0) (2016-10-12) -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.4.1...1.18.0) +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.17.0...1.18.0) **Merged pull requests:** - Allow failure for Ruby 2.3.1 [\#337](https://github.com/voxpupuli/puppet-python/pull/337) ([ghoneycutt](https://github.com/ghoneycutt)) - Add support, tests and documentation for Gentoo [\#335](https://github.com/voxpupuli/puppet-python/pull/335) ([optiz0r](https://github.com/optiz0r)) -## [2.4.1](https://github.com/voxpupuli/puppet-python/tree/2.4.1) (2016-09-19) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.17.0...2.4.1) - ## [1.17.0](https://github.com/voxpupuli/puppet-python/tree/1.17.0) (2016-09-16) [Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.16.0...1.17.0) @@ -185,24 +582,12 @@ These should not affect the functionality of the module. ## [1.16.0](https://github.com/voxpupuli/puppet-python/tree/1.16.0) (2016-09-10) -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.4.0...1.16.0) +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.15.0...1.16.0) **Merged pull requests:** - RHSCL Repository installation made optional [\#328](https://github.com/voxpupuli/puppet-python/pull/328) ([diLLec](https://github.com/diLLec)) -## [2.4.0](https://github.com/voxpupuli/puppet-python/tree/2.4.0) (2016-09-04) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.3.1...2.4.0) - -## [2.3.1](https://github.com/voxpupuli/puppet-python/tree/2.3.1) (2016-08-29) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.3.0...2.3.1) - -## [2.3.0](https://github.com/voxpupuli/puppet-python/tree/2.3.0) (2016-08-29) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.15.0...2.3.0) - ## [1.15.0](https://github.com/voxpupuli/puppet-python/tree/1.15.0) (2016-08-24) [Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.14.2...1.15.0) @@ -239,23 +624,20 @@ These should not affect the functionality of the module. ## [1.14.0](https://github.com/voxpupuli/puppet-python/tree/1.14.0) (2016-07-20) -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.2.1...1.14.0) +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.13.0...1.14.0) **Merged pull requests:** - Fix regex for pip package versions [\#317](https://github.com/voxpupuli/puppet-python/pull/317) ([mdean](https://github.com/mdean)) -## [2.2.1](https://github.com/voxpupuli/puppet-python/tree/2.2.1) (2016-07-20) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.13.0...2.2.1) - ## [1.13.0](https://github.com/voxpupuli/puppet-python/tree/1.13.0) (2016-07-18) -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.2.0...1.13.0) +[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.12.0...1.13.0) **Closed issues:** - SCL package installation returns an error [\#308](https://github.com/voxpupuli/puppet-python/issues/308) +- Patch Release [\#295](https://github.com/voxpupuli/puppet-python/issues/295) - Can't install pip3 with Ubuntu [\#287](https://github.com/voxpupuli/puppet-python/issues/287) - SCL python27: add a workaround for libpython2.7.so.1.0 issue \(LD\_LIBRARY\_PATH\) [\#234](https://github.com/voxpupuli/puppet-python/issues/234) @@ -271,30 +653,6 @@ These should not affect the functionality of the module. - Configure workers [\#301](https://github.com/voxpupuli/puppet-python/pull/301) ([steverecio](https://github.com/steverecio)) - Fix support for Ruby 1.8.7 [\#298](https://github.com/voxpupuli/puppet-python/pull/298) ([ghoneycutt](https://github.com/ghoneycutt)) -## [2.2.0](https://github.com/voxpupuli/puppet-python/tree/2.2.0) (2016-05-31) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.1.0...2.2.0) - -## [2.1.0](https://github.com/voxpupuli/puppet-python/tree/2.1.0) (2016-05-29) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.0.2...2.1.0) - -## [2.0.2](https://github.com/voxpupuli/puppet-python/tree/2.0.2) (2016-05-22) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.0.1...2.0.2) - -## [2.0.1](https://github.com/voxpupuli/puppet-python/tree/2.0.1) (2016-05-19) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/2.0.0...2.0.1) - -## [2.0.0](https://github.com/voxpupuli/puppet-python/tree/2.0.0) (2016-05-19) - -[Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.12.0...2.0.0) - -**Closed issues:** - -- Patch Release [\#295](https://github.com/voxpupuli/puppet-python/issues/295) - ## [1.12.0](https://github.com/voxpupuli/puppet-python/tree/1.12.0) (2016-03-27) [Full Changelog](https://github.com/voxpupuli/puppet-python/compare/1.11.0...1.12.0) @@ -339,7 +697,7 @@ These should not affect the functionality of the module. - Revert "Update virtualenv\_version.rb" [\#267](https://github.com/voxpupuli/puppet-python/pull/267) ([shivapoudel](https://github.com/shivapoudel)) - Update virtualenv\_version.rb [\#265](https://github.com/voxpupuli/puppet-python/pull/265) ([shivapoudel](https://github.com/shivapoudel)) - Update params.pp [\#263](https://github.com/voxpupuli/puppet-python/pull/263) ([philippeback](https://github.com/philippeback)) -- Bug virtualenv instead of virtualenv-$version [\#261](https://github.com/voxpupuli/puppet-python/pull/261) ([Asher256](https://github.com/Asher256)) +- Bug virtualenv instead of virtualenv-$version [\#261](https://github.com/voxpupuli/puppet-python/pull/261) ([ghost](https://github.com/ghost)) - Addressing stankevich/puppet-python issue \#258. [\#260](https://github.com/voxpupuli/puppet-python/pull/260) ([rpocase](https://github.com/rpocase)) ## [1.10.0](https://github.com/voxpupuli/puppet-python/tree/1.10.0) (2015-10-29) @@ -376,7 +734,7 @@ These should not affect the functionality of the module. - Bootstrap pip installation [\#244](https://github.com/voxpupuli/puppet-python/pull/244) ([joshuaspence](https://github.com/joshuaspence)) - Various tidying up [\#242](https://github.com/voxpupuli/puppet-python/pull/242) ([joshuaspence](https://github.com/joshuaspence)) - Allow custom versions to be installed [\#241](https://github.com/voxpupuli/puppet-python/pull/241) ([joshuaspence](https://github.com/joshuaspence)) -- Check that we have results before returning a value [\#238](https://github.com/voxpupuli/puppet-python/pull/238) ([xaque208](https://github.com/xaque208)) +- Check that we have results before returning a value [\#238](https://github.com/voxpupuli/puppet-python/pull/238) ([zachfi](https://github.com/zachfi)) - Adjust test code to pass syntax checker [\#237](https://github.com/voxpupuli/puppet-python/pull/237) ([fluential](https://github.com/fluential)) ## [1.9.7](https://github.com/voxpupuli/puppet-python/tree/1.9.7) (2015-08-21) @@ -541,7 +899,7 @@ These should not affect the functionality of the module. **Closed issues:** - 'system' or any other version of python doesn't work, doesn't get validated [\#129](https://github.com/voxpupuli/puppet-python/issues/129) -- Could not look up qualified variable '::python::install::valid\_versions' [\#126](https://github.com/voxpupuli/puppet-python/issues/126) +- Could not look up qualified variable `python::install::valid_versions` [\#126](https://github.com/voxpupuli/puppet-python/issues/126) ## [1.7.11](https://github.com/voxpupuli/puppet-python/tree/1.7.11) (2014-10-11) @@ -549,7 +907,7 @@ These should not affect the functionality of the module. **Closed issues:** -- Unable to customize `APP\_MODULE` variable in gunicorn template [\#127](https://github.com/voxpupuli/puppet-python/issues/127) +- Unable to customize `APP_MODULE` variable in gunicorn template [\#127](https://github.com/voxpupuli/puppet-python/issues/127) - New release on the Puppet forge [\#125](https://github.com/voxpupuli/puppet-python/issues/125) ## [1.7.10](https://github.com/voxpupuli/puppet-python/tree/1.7.10) (2014-09-25) diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 27a33cf6..00000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ruby:2.5.1 - -WORKDIR /opt/puppet - -# https://github.com/puppetlabs/puppet/blob/06ad255754a38f22fb3a22c7c4f1e2ce453d01cb/lib/puppet/provider/service/runit.rb#L39 -RUN mkdir -p /etc/sv - -ARG PUPPET_VERSION="~> 6.0" -ARG PARALLEL_TEST_PROCESSORS=4 - -# Cache gems -COPY Gemfile . -RUN bundle install --without system_tests development release --path=${BUNDLE_PATH:-vendor/bundle} - -COPY . . - -RUN bundle install -RUN bundle exec release_checks - -# Container should not saved -RUN exit 1 diff --git a/Gemfile b/Gemfile index 6a74c57b..12839821 100644 --- a/Gemfile +++ b/Gemfile @@ -1,82 +1,28 @@ -source ENV['GEM_SOURCE'] || "https://rubygems.org" +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ -def location_for(place, fake_version = nil) - if place =~ /^(git[:@][^#]*)#(.*)/ - [fake_version, { :git => $1, :branch => $2, :require => false }].compact - elsif place =~ /^file:\/\/(.*)/ - ['>= 0', { :path => File.expand_path($1), :require => false }] - else - [place, { :require => false }] - end -end +source ENV['GEM_SOURCE'] || 'https://rubygems.org' group :test do - gem 'puppetlabs_spec_helper', '>= 2.11.0', :require => false - gem 'rspec-puppet-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 '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', '~> 14.0', :require => false + gem 'puppet_metadata', '~> 6.1', :require => false end group :development do - gem 'travis', :require => false - gem 'travis-lint', :require => false gem 'guard-rake', :require => false gem 'overcommit', '>= 0.39.1', :require => false 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', '~> 4.4', :require => false end group :release do - gem 'github_changelog_generator', :require => false, :git => 'https://github.com/github-changelog-generator/github-changelog-generator' - gem 'puppet-blacksmith', :require => false - gem 'voxpupuli-release', :require => false, :git => 'https://github.com/voxpupuli/voxpupuli-release-gem' - gem 'puppet-strings', '>= 1.0', :require => false + gem 'voxpupuli-release', '~> 5.3', :require => false end +gem 'rake', :require => false - -if facterversion = ENV['FACTER_GEM_VERSION'] - gem 'facter', facterversion.to_s, :require => false, :groups => [:test] -else - gem 'facter', :require => false, :groups => [:test] -end - -ENV['PUPPET_VERSION'].nil? ? puppetversion = '~> 6.0' : puppetversion = ENV['PUPPET_VERSION'].to_s -gem 'puppet', puppetversion, :require => false, :groups => [:test] +gem 'openvox', ENV.fetch('OPENVOX_GEM_VERSION', [">= 7", "< 9"]), :require => false, :groups => [:test] # vim: syntax=ruby diff --git a/README.md b/README.md index f905a36f..59d95fd3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ -# puppet-python [![Build Status](https://travis-ci.org/voxpupuli/puppet-python.svg?branch=master)](https://travis-ci.org/voxpupuli/puppet-python) +# puppet-python + +[![Build Status](https://github.com/voxpupuli/puppet-python/workflows/CI/badge.svg)](https://github.com/voxpupuli/puppet-python/actions?query=workflow%3ACI) +[![Release](https://github.com/voxpupuli/puppet-python/actions/workflows/release.yml/badge.svg)](https://github.com/voxpupuli/puppet-python/actions/workflows/release.yml) +[![Puppet Forge](https://img.shields.io/puppetforge/v/puppet/python.svg)](https://forge.puppetlabs.com/puppet/python) +[![Puppet Forge - downloads](https://img.shields.io/puppetforge/dt/puppet/python.svg)](https://forge.puppetlabs.com/puppet/python) +[![Puppet Forge - endorsement](https://img.shields.io/puppetforge/e/puppet/python.svg)](https://forge.puppetlabs.com/puppet/python) +[![Puppet Forge - scores](https://img.shields.io/puppetforge/f/puppet/python.svg)](https://forge.puppetlabs.com/puppet/python) +[![puppetmodule.info docs](http://www.puppetmodule.info/images/badge.png)](http://www.puppetmodule.info/m/puppet-python) +[![License](https://img.shields.io/github/license/voxpupuli/puppet-python.svg)](https://github.com/voxpupuli/puppet-python/blob/master/LICENSE) Puppet module for installing and managing python, pip, virtualenvs and Gunicorn virtual hosts. @@ -10,6 +19,35 @@ For class usage refer to the [Reference]("https://github.com/voxpupuli/puppet-py bundle exec rake strings:generate\[',,,,false,true'] ``` +### Install Python package to a user's default install directory + +The following code simulates + +```shell +python3 -m pip install pandas --user +``` +where pip installs packages to a user's default install directory -- +typically `~/.local/` on Linux. + +```puppet +# Somewhat hackishly, install Python PIP module PANDAS for Oracle Cloud API queries. +python::pyvenv { 'user_python_venv': + ensure => present, + version => 'system', + systempkgs => true, + venv_dir => '/home/example/.local', + owner => 'example', + group => 'example', + mode => '0750', +} + +python::pip { 'pandas': + virtualenv => '/home/example/.local', + owner => 'example', + group => 'example', +} +``` + ### hiera configuration This module supports configuration through hiera. The following example diff --git a/REFERENCE.md b/REFERENCE.md index 8ba1fa5f..9f19f1d8 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -1,34 +1,44 @@ # Reference + ## Table of Contents -**Classes** +### Classes -_Public Classes_ +#### Public Classes -* [`python`](#python): Installs and manages python, python-dev, python-virtualenv and gunicorn. +* [`python`](#python): Installs and manages python, python-dev and gunicorn. +* [`python::pip::bootstrap`](#python--pip--bootstrap): allow to bootstrap pip when python is managed from other module -_Private Classes_ +#### Private Classes * `python::config`: Optionally installs the gunicorn service * `python::install`: Installs core python packages * `python::params`: The python Module default configuration settings. -**Defined types** +### Defined types + +* [`python::dotfile`](#python--dotfile): Manages any python dotfiles with a simple config hash. +* [`python::gunicorn`](#python--gunicorn): Manages Gunicorn virtual hosts. +* [`python::pip`](#python--pip): Installs and manages packages from pip. +* [`python::pyvenv`](#python--pyvenv): Create a Python3 virtualenv using pyvenv. +* [`python::requirements`](#python--requirements): Installs and manages Python packages from requirements file. + +### Data types -* [`python::dotfile`](#pythondotfile): Manages any python dotfiles with a simple config hash. -* [`python::gunicorn`](#pythongunicorn): Manages Gunicorn virtual hosts. -* [`python::pip`](#pythonpip): Installs and manages packages from pip. -* [`python::pyvenv`](#pythonpyvenv): Create a Python3 virtualenv using pyvenv. -* [`python::requirements`](#pythonrequirements): Installs and manages Python packages from requirements file. -* [`python::virtualenv`](#pythonvirtualenv): Creates Python virtualenv. +* [`Python::Loglevel`](#Python--Loglevel): Match all valid loglevels for python +* [`Python::Package::Ensure`](#Python--Package--Ensure): Match all valid package ensures for python +* [`Python::Provider`](#Python--Provider): Match all valid provider for python +* [`Python::Umask`](#Python--Umask): Match valid umask for python +* [`Python::Venv::PipVersion`](#Python--Venv--PipVersion): A version type to ensure a specific Pip version in a virtual env. +* [`Python::Version`](#Python--Version): Match all valid versions for python ## Classes -### python +### `python` -Installs and manages python, python-dev, python-virtualenv and gunicorn. +Installs and manages python, python-dev and gunicorn. #### Examples @@ -39,37 +49,69 @@ class { 'python': version => 'system', pip => 'present', dev => 'present', - virtualenv => 'present', gunicorn => 'present', } ``` -##### install python3 from scl report +##### install python3 from scl repo ```puppet class { 'python' : ensure => 'present', version => 'rh-python36-python', dev => 'present', - virtualenv => 'present', } ``` #### Parameters -The following parameters are available in the `python` class. - -##### `ensure` - -Data type: `Enum['absent', 'present', 'latest']` +The following parameters are available in the `python` class: + +* [`default_system_version`](#-python--default_system_version) +* [`ensure`](#-python--ensure) +* [`version`](#-python--version) +* [`pip`](#-python--pip) +* [`dev`](#-python--dev) +* [`gunicorn`](#-python--gunicorn) +* [`manage_gunicorn`](#-python--manage_gunicorn) +* [`provider`](#-python--provider) +* [`use_epel`](#-python--use_epel) +* [`manage_scl`](#-python--manage_scl) +* [`umask`](#-python--umask) +* [`manage_gunicorn`](#-python--manage_gunicorn) +* [`manage_python_package`](#-python--manage_python_package) +* [`manage_dev_package`](#-python--manage_dev_package) +* [`manage_venv_package`](#-python--manage_venv_package) +* [`manage_pip_package`](#-python--manage_pip_package) +* [`venv`](#-python--venv) +* [`gunicorn_package_name`](#-python--gunicorn_package_name) +* [`python_pips`](#-python--python_pips) +* [`python_pyvenvs`](#-python--python_pyvenvs) +* [`python_requirements`](#-python--python_requirements) +* [`python_dotfiles`](#-python--python_dotfiles) +* [`rhscl_use_public_repository`](#-python--rhscl_use_public_repository) +* [`anaconda_installer_url`](#-python--anaconda_installer_url) +* [`anaconda_install_path`](#-python--anaconda_install_path) + +##### `default_system_version` + +Data type: `Python::Version` + +The default version of Python provided by the operating system. Only used as a fallback if Python is not installed yet to determine how to handle some actions that vary depending on the Python version used. + +Default value: `'3.11'` + +##### `ensure` + +Data type: `Python::Package::Ensure` Desired installation state for the Python package. -Default value: $python::params::ensure +Default value: `'present'` -##### `version` +##### `version` -Data type: `Any` +Data type: `Python::Version` Python version to install. Beware that valid values for this differ a) by the provider you choose and b) by the osfamily/operatingsystem you are using. Allowed values: @@ -80,147 +122,236 @@ Allowed values: - 3/3.3/... means you are going to install the python3/python3.3/... package, if available on your osfamily. -Default value: $python::params::version +Default value: `$facts['os']['family'] ? { 'Archlinux' => 'system', default => '3'` -##### `pip` +##### `pip` -Data type: `Enum['absent', 'present', 'latest']` +Data type: `Python::Package::Ensure` Desired installation state for the python-pip package. -Default value: $python::params::pip +Default value: `'present'` -##### `dev` +##### `dev` -Data type: `Enum['absent', 'present', 'latest']` +Data type: `Python::Package::Ensure` Desired installation state for the python-dev package. -Default value: $python::params::dev - -##### `virtualenv` - -Data type: `Enum['absent', 'present', 'latest']` - -Desired installation state for the virtualenv package - -Default value: $python::params::virtualenv +Default value: `'absent'` -##### `gunicorn` +##### `gunicorn` -Data type: `Enum['absent', 'present', 'latest']` +Data type: `Python::Package::Ensure` Desired installation state for Gunicorn. -Default value: $python::params::gunicorn +Default value: `'absent'` -##### `manage_gunicorn` +##### `manage_gunicorn` Data type: `Boolean` Allow Installation / Removal of Gunicorn. -Default value: $python::params::manage_gunicorn +Default value: `true` -##### `provider` +##### `provider` -Data type: `Optional[Enum['pip', 'scl', 'rhscl', 'anaconda', '']]` +Data type: `Optional[Python::Provider]` What provider to use for installation of the packages, except gunicorn and Python itself. -Default value: $python::params::provider +Default value: `undef` -##### `use_epel` +##### `use_epel` Data type: `Boolean` to determine if the epel class is used. -Default value: $python::params::use_epel +Default value: `$python::params::use_epel` -##### `gunicorn_package_name` +##### `manage_scl` -Data type: `Any` +Data type: `Boolean` +Whether to manage core SCL packages or not. +Default value: `true` -Default value: $python::params::gunicorn_package_name +##### `umask` -##### `valid_versions` +The default umask for invoked exec calls. -Data type: `Any` +##### `manage_gunicorn` +manage the state for package gunicorn +Default value: `true` -Default value: $python::params::valid_versions +##### `manage_python_package` -##### `python_pips` +Data type: `Boolean` -Data type: `Hash` +manage the state for package python + +Default value: `true` + +##### `manage_dev_package` + +Data type: `Boolean` + +manage the state of the python development package + +Default value: `true` + +##### `manage_venv_package` + +Data type: `Boolean` + +manage the state for package venv + +Default value: `$python::params::manage_venv_package` + +##### `manage_pip_package` + +Data type: `Boolean` + +manage the state for package pip + +Default value: `$python::params::manage_pip_package` + +##### `venv` +Data type: `Python::Package::Ensure` -Default value: { } -##### `python_virtualenvs` +Default value: `'absent'` + +##### `gunicorn_package_name` + +Data type: `String[1]` + + + +Default value: `$python::params::gunicorn_package_name` + +##### `python_pips` Data type: `Hash` -Default value: { } +Default value: `{}` -##### `python_pyvenvs` +##### `python_pyvenvs` Data type: `Hash` -Default value: { } +Default value: `{}` -##### `python_requirements` +##### `python_requirements` Data type: `Hash` -Default value: { } +Default value: `{}` -##### `python_dotfiles` +##### `python_dotfiles` Data type: `Hash` -Default value: { } +Default value: `{}` -##### `rhscl_use_public_repository` +##### `rhscl_use_public_repository` -Data type: `Any` +Data type: `Boolean` -Default value: $python::params::rhscl_use_public_repository +Default value: `true` -##### `anaconda_installer_url` +##### `anaconda_installer_url` Data type: `Stdlib::Httpurl` -Default value: $python::params::anaconda_installer_url +Default value: `'https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh'` -##### `anaconda_install_path` +##### `anaconda_install_path` Data type: `Stdlib::Absolutepath` -Default value: $python::params::anaconda_install_path +Default value: `'/opt/python'` + +### `python::pip::bootstrap` + +allow to bootstrap pip when python is managed from other module + +#### Examples + +##### + +```puppet +class { 'python::pip::bootstrap': + version => 'pip', +} +``` + +#### Parameters + +The following parameters are available in the `python::pip::bootstrap` class: + +* [`version`](#-python--pip--bootstrap--version) +* [`manage_python`](#-python--pip--bootstrap--manage_python) +* [`http_proxy`](#-python--pip--bootstrap--http_proxy) +* [`exec_provider`](#-python--pip--bootstrap--exec_provider) + +##### `version` + +Data type: `Enum['pip', 'pip3']` + +should be pip or pip3 + +Default value: `'pip'` + +##### `manage_python` + +Data type: `Variant[Boolean, String]` + +if python module will manage deps + +Default value: `false` + +##### `http_proxy` + +Data type: `Optional[Stdlib::HTTPUrl]` + +Proxy server to use for outbound connections. + +Default value: `undef` + +##### `exec_provider` + +Data type: `String[1]` + + + +Default value: `'shell'` ## Defined types -### python::dotfile +### `python::dotfile` Manages any python dotfiles with a simple config hash. @@ -244,57 +375,64 @@ python::dotfile { '/var/lib/jenkins/.pip/pip.conf': #### Parameters -The following parameters are available in the `python::dotfile` defined type. +The following parameters are available in the `python::dotfile` defined type: + +* [`ensure`](#-python--dotfile--ensure) +* [`filename`](#-python--dotfile--filename) +* [`mode`](#-python--dotfile--mode) +* [`owner`](#-python--dotfile--owner) +* [`group`](#-python--dotfile--group) +* [`config`](#-python--dotfile--config) -##### `ensure` +##### `ensure` Data type: `Enum['absent', 'present']` -Default value: 'present' +Default value: `'present'` -##### `filename` +##### `filename` -Data type: `Stdlib::Filemode` +Data type: `Stdlib::Absolutepath` Filename. -Default value: $title +Default value: `$title` -##### `mode` +##### `mode` -Data type: `String[1]` +Data type: `Stdlib::Filemode` File mode. -Default value: '0644' +Default value: `'0644'` -##### `owner` +##### `owner` Data type: `String[1]` user owner of dotfile -Default value: 'root' +Default value: `'root'` -##### `group` +##### `group` Data type: `String[1]` group owner of dotfile -Default value: 'root' +Default value: `getvar('python::params::group')` -##### `config` +##### `config` Data type: `Hash` Config hash. This will be expanded to an ini-file. -Default value: {} +Default value: `{}` -### python::gunicorn +### `python::gunicorn` Manages Gunicorn virtual hosts. @@ -321,59 +459,78 @@ python::gunicorn { 'vhost': #### Parameters -The following parameters are available in the `python::gunicorn` defined type. - -##### `ensure` +The following parameters are available in the `python::gunicorn` defined type: + +* [`ensure`](#-python--gunicorn--ensure) +* [`config_dir`](#-python--gunicorn--config_dir) +* [`manage_config_dir`](#-python--gunicorn--manage_config_dir) +* [`virtualenv`](#-python--gunicorn--virtualenv) +* [`mode`](#-python--gunicorn--mode) +* [`dir`](#-python--gunicorn--dir) +* [`bind`](#-python--gunicorn--bind) +* [`environment`](#-python--gunicorn--environment) +* [`appmodule`](#-python--gunicorn--appmodule) +* [`osenv`](#-python--gunicorn--osenv) +* [`timeout`](#-python--gunicorn--timeout) +* [`template`](#-python--gunicorn--template) +* [`args`](#-python--gunicorn--args) +* [`owner`](#-python--gunicorn--owner) +* [`group`](#-python--gunicorn--group) +* [`workers`](#-python--gunicorn--workers) +* [`access_log_format`](#-python--gunicorn--access_log_format) +* [`accesslog`](#-python--gunicorn--accesslog) +* [`errorlog`](#-python--gunicorn--errorlog) +* [`log_level`](#-python--gunicorn--log_level) + +##### `ensure` Data type: `Enum['present', 'absent']` -Default value: present +Default value: `present` -##### `config_dir` +##### `config_dir` -Data type: `Any` +Data type: `Stdlib::Absolutepath` Configure the gunicorn config directory path. -Default value: '/etc/gunicorn.d' +Default value: `'/etc/gunicorn.d'` -##### `manage_config_dir` +##### `manage_config_dir` -Data type: `Any` +Data type: `Boolean` Set if the gunicorn config directory should be created. Default value: `false` -##### `virtualenv` +##### `virtualenv` -Data type: `Any` +Data type: `Variant[Boolean,Stdlib::Absolutepath]` Run in virtualenv, specify directory. Default value: `false` -##### `mode` +##### `mode` Data type: `Enum['wsgi', 'django']` Gunicorn mode. -Default value: 'wsgi' +Default value: `'wsgi'` -##### `dir` +##### `dir` -Data type: `Any` +Data type: `Stdlib::Absolutepath` Application directory. -Default value: `false` - -##### `bind` +##### `bind` -Data type: `Any` +Data type: `Variant[String[1],Boolean]` Bind on: 'HOST', 'HOST:PORT', 'unix:PATH'. Default: system-wide: unix:/tmp/gunicorn-$name.socket @@ -381,111 +538,111 @@ Default: system-wide: unix:/tmp/gunicorn-$name.socket Default value: `false` -##### `environment` +##### `environment` -Data type: `Any` +Data type: `Variant[String[1],Boolean]` Set ENVIRONMENT variable. Default value: `false` -##### `appmodule` +##### `appmodule` -Data type: `Any` +Data type: `String[1]` Set the application module name for gunicorn to load when not using Django. -Default value: 'app:app' +Default value: `'app:app'` -##### `osenv` +##### `osenv` -Data type: `Any` +Data type: `Variant[Boolean,Hash]` Allows setting environment variables for the gunicorn service. Accepts a hash of 'key': 'value' pairs. Default value: `false` -##### `timeout` +##### `timeout` -Data type: `Any` +Data type: `Integer` Allows setting the gunicorn idle worker process time before being killed. The unit of time is seconds. -Default value: 30 +Default value: `30` -##### `template` +##### `template` -Data type: `Any` +Data type: `String[1]` Which ERB template to use. -Default value: 'python/gunicorn.erb' +Default value: `'python/gunicorn.erb'` -##### `args` +##### `args` -Data type: `Any` +Data type: `Array` Custom arguments to add in gunicorn config file. -Default value: [] +Default value: `[]` -##### `owner` +##### `owner` -Data type: `Any` +Data type: `String[1]` -Default value: 'www-data' +Default value: `'www-data'` -##### `group` +##### `group` -Data type: `Any` +Data type: `String[1]` -Default value: 'www-data' +Default value: `'www-data'` -##### `workers` +##### `workers` -Data type: `Any` +Data type: `Variant[Boolean,Integer]` Default value: `false` -##### `access_log_format` +##### `access_log_format` -Data type: `Any` +Data type: `Variant[Boolean,String[1]]` Default value: `false` -##### `accesslog` +##### `accesslog` -Data type: `Any` +Data type: `Variant[Boolean,Stdlib::Absolutepath]` Default value: `false` -##### `errorlog` +##### `errorlog` -Data type: `Any` +Data type: `Variant[Boolean,Stdlib::Absolutepath]` Default value: `false` -##### `log_level` +##### `log_level` -Data type: `Any` +Data type: `Python::Loglevel` -Default value: 'error' +Default value: `'error'` -### python::pip +### `python::pip` Installs and manages packages from pip. @@ -510,7 +667,7 @@ python::pip { 'cx_Oracle' : virtualenv => '/var/www/project1', owner => 'appuser', proxy => 'http://proxy.domain.com:3128', - environment => 'ORACLE_HOME=/usr/lib/oracle/11.2/client64', + environment => ['ORACLE_HOME=/usr/lib/oracle/11.2/client64'], install_args => '-e', timeout => 1800, } @@ -531,45 +688,68 @@ python::pip { 'requests' : #### Parameters -The following parameters are available in the `python::pip` defined type. - -##### `name` +The following parameters are available in the `python::pip` defined type: + +* [`name`](#-python--pip--name) +* [`pkgname`](#-python--pip--pkgname) +* [`ensure`](#-python--pip--ensure) +* [`virtualenv`](#-python--pip--virtualenv) +* [`pip_provider`](#-python--pip--pip_provider) +* [`url`](#-python--pip--url) +* [`owner`](#-python--pip--owner) +* [`group`](#-python--pip--group) +* [`index`](#-python--pip--index) +* [`extra_index`](#-python--pip--extra_index) +* [`proxy`](#-python--pip--proxy) +* [`editable`](#-python--pip--editable) +* [`environment`](#-python--pip--environment) +* [`extras`](#-python--pip--extras) +* [`timeout`](#-python--pip--timeout) +* [`install_args`](#-python--pip--install_args) +* [`uninstall_args`](#-python--pip--uninstall_args) +* [`log_dir`](#-python--pip--log_dir) +* [`egg`](#-python--pip--egg) +* [`umask`](#-python--pip--umask) +* [`path`](#-python--pip--path) +* [`exec_provider`](#-python--pip--exec_provider) + +##### `name` must be unique -##### `pkgname` +##### `pkgname` -Data type: `String` +Data type: `String[1]` the name of the package. -Default value: $name +Default value: `$name` -##### `ensure` +##### `ensure` Data type: `Variant[Enum[present, absent, latest], String[1]]` Require pip to be available. -Default value: present +Default value: `present` -##### `virtualenv` +##### `virtualenv` -Data type: `String` +Data type: `Variant[Enum['system'], Stdlib::Absolutepath]` virtualenv to run pip in. -Default value: 'system' +Default value: `'system'` -##### `pip_provider` +##### `pip_provider` -Data type: `Enum['pip', 'pip3']` +Data type: `String[1]` version of pip you wish to use. -Default value: 'pip' +Default value: `'pip'` -##### `url` +##### `url` Data type: `Variant[Boolean, String]` @@ -577,39 +757,47 @@ URL to install from. Default value: `false` -##### `owner` +##### `owner` Data type: `String[1]` The owner of the virtualenv being manipulated. -Default value: 'root' +Default value: `'root'` -##### `group` +##### `group` -Data type: `String[1]` +Data type: `Optional[String[1]]` The group of the virtualenv being manipulated. -Default value: 'root' +Default value: `getvar('python::params::group')` -##### `index` +##### `index` -Data type: `Any` +Data type: `Variant[Boolean,String[1]]` Base URL of Python package index. Default value: `false` -##### `proxy` +##### `extra_index` -Data type: `Variant[Boolean, String]` +Data type: `Variant[Boolean,String[1]]` -Proxy server to use for outbound connections. +Base URL of extra Python package index. Default value: `false` -##### `editable` +##### `proxy` + +Data type: `Optional[Stdlib::HTTPUrl]` + +Proxy server to use for outbound connections. + +Default value: `undef` + +##### `editable` Data type: `Boolean` @@ -617,55 +805,55 @@ If true the package is installed as an editable resource. Default value: `false` -##### `environment` +##### `environment` -Data type: `Any` +Data type: `Array` Additional environment variables required to install the packages. -Default value: [] +Default value: `[]` -##### `extras` +##### `extras` -Data type: `Any` +Data type: `Array` Extra features provided by the package which should be installed. -Default value: [] +Default value: `[]` -##### `timeout` +##### `timeout` Data type: `Numeric` The maximum time in seconds the "pip install" command should take. -Default value: 1800 +Default value: `1800` -##### `install_args` +##### `install_args` -Data type: `String` +Data type: `Optional[String[1]]` Any additional installation arguments that will be supplied when running pip install. -Default value: '' +Default value: `undef` -##### `uninstall_args` +##### `uninstall_args` -Data type: `String` +Data type: `Optional[String[1]]` Any additional arguments that will be supplied when running pip uninstall. -Default value: '' +Default value: `undef` -##### `log_dir` +##### `log_dir` Data type: `String[1]` Log directory -Default value: '/tmp' +Default value: `'/tmp'` -##### `egg` +##### `egg` Data type: `Any` @@ -673,23 +861,31 @@ The egg name to use Default value: `false` -##### `umask` +##### `umask` -Data type: `Any` +Data type: `Optional[Python::Umask]` Default value: `undef` -##### `path` +##### `path` Data type: `Array[String]` -Default value: ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'] +Default value: `['/usr/local/bin','/usr/bin','/bin', '/usr/sbin']` + +##### `exec_provider` + +Data type: `String[1]` + + + +Default value: `'shell'` -### python::pyvenv +### `python::pyvenv` Create a Python3 virtualenv using pyvenv. @@ -710,81 +906,118 @@ python::pyvenv { '/var/www/project1' : #### Parameters -The following parameters are available in the `python::pyvenv` defined type. +The following parameters are available in the `python::pyvenv` defined type: -##### `ensure` +* [`ensure`](#-python--pyvenv--ensure) +* [`version`](#-python--pyvenv--version) +* [`systempkgs`](#-python--pyvenv--systempkgs) +* [`venv_dir`](#-python--pyvenv--venv_dir) +* [`owner`](#-python--pyvenv--owner) +* [`group`](#-python--pyvenv--group) +* [`mode`](#-python--pyvenv--mode) +* [`path`](#-python--pyvenv--path) +* [`environment`](#-python--pyvenv--environment) +* [`prompt`](#-python--pyvenv--prompt) +* [`python_path`](#-python--pyvenv--python_path) +* [`pip_version`](#-python--pyvenv--pip_version) -Data type: `Any` +##### `ensure` +Data type: `Python::Package::Ensure` -Default value: present -##### `version` +Default value: `present` -Data type: `Any` +##### `version` + +Data type: `Python::Version` Python version to use. -Default value: 'system' +Default value: `'system'` -##### `systempkgs` +##### `systempkgs` -Data type: `Any` +Data type: `Boolean` Copy system site-packages into virtualenv Default value: `false` -##### `venv_dir` +##### `venv_dir` -Data type: `Any` +Data type: `Stdlib::Absolutepath` Directory to install virtualenv to -Default value: $name +Default value: `$name` -##### `owner` +##### `owner` -Data type: `Any` +Data type: `String[1]` The owner of the virtualenv being manipulated -Default value: 'root' +Default value: `'root'` -##### `group` +##### `group` -Data type: `Any` +Data type: `String[1]` The group relating to the virtualenv being manipulated -Default value: 'root' +Default value: `'root'` -##### `mode` +##### `mode` -Data type: `Any` +Data type: `Stdlib::Filemode` Optionally specify directory mode -Default value: '0755' +Default value: `'0755'` -##### `path` +##### `path` -Data type: `Any` +Data type: `Array[Stdlib::Absolutepath]` Specifies the PATH variable. -Default value: [ '/bin', '/usr/bin', '/usr/sbin', '/usr/local/bin' ] +Default value: `['/bin', '/usr/bin', '/usr/sbin', '/usr/local/bin',]` -##### `environment` +##### `environment` -Data type: `Any` +Data type: `Array[String[1]]` Optionally specify environment variables for pyvenv -Default value: [] +Default value: `[]` + +##### `prompt` + +Data type: `Optional[String[1]]` + +Optionally specify the virtualenv prompt (python >= 3.6) + +Default value: `undef` + +##### `python_path` + +Data type: `Optional[Stdlib::Absolutepath]` + +Optionally specify python path for creation of virtualenv + +Default value: `undef` + +##### `pip_version` + +Data type: `Python::Venv::PipVersion` + -### python::requirements + +Default value: `'latest'` + +### `python::requirements` Installs and manages Python packages from requirements file. @@ -803,57 +1036,73 @@ python::requirements { '/var/www/project1/requirements.txt' : #### Parameters -The following parameters are available in the `python::requirements` defined type. - -##### `requirements` +The following parameters are available in the `python::requirements` defined type: + +* [`requirements`](#-python--requirements--requirements) +* [`virtualenv`](#-python--requirements--virtualenv) +* [`pip_provider`](#-python--requirements--pip_provider) +* [`owner`](#-python--requirements--owner) +* [`group`](#-python--requirements--group) +* [`proxy`](#-python--requirements--proxy) +* [`src`](#-python--requirements--src) +* [`environment`](#-python--requirements--environment) +* [`forceupdate`](#-python--requirements--forceupdate) +* [`cwd`](#-python--requirements--cwd) +* [`extra_pip_args`](#-python--requirements--extra_pip_args) +* [`manage_requirements`](#-python--requirements--manage_requirements) +* [`fix_requirements_owner`](#-python--requirements--fix_requirements_owner) +* [`log_dir`](#-python--requirements--log_dir) +* [`timeout`](#-python--requirements--timeout) + +##### `requirements` -Data type: `Any` +Data type: `Stdlib::Absolutepath` Path to the requirements file. -Default value: $name +Default value: `$name` -##### `virtualenv` +##### `virtualenv` -Data type: `Any` +Data type: `Variant[Enum['system'],Stdlib::Absolutepath]` virtualenv to run pip in. -Default value: 'system' +Default value: `'system'` -##### `pip_provider` +##### `pip_provider` Data type: `Enum['pip', 'pip3']` version of pip you wish to use. -Default value: 'pip' +Default value: `'pip'` -##### `owner` +##### `owner` -Data type: `Any` +Data type: `String[1]` The owner of the virtualenv being manipulated. -Default value: 'root' +Default value: `'root'` -##### `group` +##### `group` -Data type: `Any` +Data type: `String[1]` The group relating to the virtualenv being manipulated. -Default value: 'root' +Default value: `'root'` -##### `proxy` +##### `proxy` -Data type: `Any` +Data type: `Optional[Stdlib::HTTPUrl]` Proxy server to use for outbound connections. -Default value: `false` +Default value: `undef` -##### `src` +##### `src` Data type: `Any` @@ -861,242 +1110,105 @@ Pip --src parameter to; if the requirements file contains --editable resources, Default value: `false` -##### `environment` +##### `environment` -Data type: `Any` +Data type: `Array` Additional environment variables required to install the packages. -Default value: [] +Default value: `[]` -##### `forceupdate` +##### `forceupdate` -Data type: `Any` +Data type: `Boolean` Run a pip install requirements even if we don't receive an event from the requirements file - Useful for when the requirements file is written as part of a resource other than file (E.g vcsrepo) Default value: `false` -##### `cwd` +##### `cwd` -Data type: `Any` +Data type: `Optional[Stdlib::Absolutepath]` The directory from which to run the "pip install" command. Default value: `undef` -##### `extra_pip_args` +##### `extra_pip_args` -Data type: `Any` +Data type: `Optional[String[1]]` Extra arguments to pass to pip after the requirements file -Default value: '' +Default value: `undef` -##### `manage_requirements` +##### `manage_requirements` -Data type: `Any` +Data type: `Boolean` Create the requirements file if it doesn't exist. Default value: `true` -##### `fix_requirements_owner` +##### `fix_requirements_owner` -Data type: `Any` +Data type: `Boolean` Change owner and group of requirements file. Default value: `true` -##### `log_dir` +##### `log_dir` -Data type: `Any` +Data type: `Stdlib::Absolutepath` Log directory. -Default value: '/tmp' +Default value: `'/tmp'` -##### `timeout` +##### `timeout` -Data type: `Any` +Data type: `Integer` The maximum time in seconds the "pip install" command should take. -Default value: 1800 - -### python::virtualenv - -Creates Python virtualenv. - -#### Examples - -##### install a virtual env at /var/www/project1 - -```puppet -python::virtualenv { '/var/www/project1': - ensure => present, - version => 'system', - requirements => '/var/www/project1/requirements.txt', - proxy => 'http://proxy.domain.com:3128', - systempkgs => true, - index => 'http://www.example.com/simple/', -} -``` - -#### Parameters +Default value: `1800` -The following parameters are available in the `python::virtualenv` defined type. +## Data types -##### `ensure` +### `Python::Loglevel` -Data type: `Any` +Match all valid loglevels for python +Alias of `Enum['debug', 'info', 'warning', 'error', 'critical']` +### `Python::Package::Ensure` -Default value: present +Match all valid package ensures for python -##### `version` - -Data type: `Any` +Alias of `Enum['absent', 'present', 'installed', 'latest']` -Python version to use. +### `Python::Provider` -Default value: 'system' +Match all valid provider for python -##### `requirements` +Alias of `Enum['pip', 'scl', 'rhscl', 'anaconda', '']` -Data type: `Any` +### `Python::Umask` -Path to pip requirements.txt file +Match valid umask for python -Default value: `false` +Alias of `Pattern[/[0-7]{1,4}/]` -##### `systempkgs` +### `Python::Venv::PipVersion` -Data type: `Any` +A version type to ensure a specific Pip version in a virtual env. -Copy system site-packages into virtualenv. +Alias of `Pattern[/^(<|>|<=|>=|==) [0-9]*(\.[0-9]+)*$/, /\Alatest\Z/]` -Default value: `false` - -##### `venv_dir` - -Data type: `Any` - -Directory to install virtualenv to - -Default value: $name - -##### `ensure_venv_dir` - -Data type: `Any` +### `Python::Version` -Create $venv_dir +Match all valid versions for python -Default value: `true` - -##### `distribute` - -Data type: `Any` - -Include distribute in the virtualenv - -Default value: `true` - -##### `index` - -Data type: `Any` - -Base URL of Python package index - -Default value: `false` - -##### `owner` - -Data type: `Any` - -The owner of the virtualenv being manipulated - -Default value: 'root' - -##### `group` - -Data type: `Any` - -The group relating to the virtualenv being manipulated - -Default value: 'root' - -##### `mode` - -Data type: `Any` - -Optionally specify directory mode - -Default value: '0755' - -##### `proxy` - -Data type: `Any` - -Proxy server to use for outbound connections - -Default value: `false` - -##### `environment` - -Data type: `Any` - -Additional environment variables required to install the packages - -Default value: [] - -##### `path` - -Data type: `Any` - -Specifies the PATH variable - -Default value: [ '/bin', '/usr/bin', '/usr/sbin', '/usr/local/bin' ] - -##### `cwd` - -Data type: `Any` - -The directory from which to run the "pip install" command - -Default value: `undef` - -##### `timeout` - -Data type: `Any` - -The maximum time in seconds the "pip install" command should take - -Default value: 1800 - -##### `pip_args` - -Data type: `Any` - -Arguments to pass to pip during initialization - -Default value: '' - -##### `extra_pip_args` - -Data type: `Any` - -Extra arguments to pass to pip after requirements file - -Default value: '' - -##### `virtualenv` - -Data type: `Any` - - - -Default value: `undef` +Alias of `Pattern[/\A(python)?[0-9](\.?[0-9])*/, /\Apypy\Z/, /\Asystem\Z/, /\Arh-python[0-9]{2}(?:-python)?\Z/]` diff --git a/Rakefile b/Rakefile index a6cf0acc..fab1b62a 100644 --- a/Rakefile +++ b/Rakefile @@ -1,63 +1,26 @@ -require 'puppetlabs_spec_helper/rake_tasks' +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ -# load optional tasks for releases -# only available if gem group releases is installed begin - require 'puppet_blacksmith/rake_tasks' - require 'voxpupuli/release/rake_tasks' - require 'puppet-strings/tasks' + require 'voxpupuli/test/rake' rescue LoadError + # only available if gem group test is installed end -PuppetLint.configuration.log_format = '%{path}:%{line}:%{check}:%{KIND}:%{message}' -PuppetLint.configuration.fail_on_warnings = true -PuppetLint.configuration.absolute_classname_reverse = true -PuppetLint.configuration.send('relative') -PuppetLint.configuration.send('disable_140chars') -PuppetLint.configuration.send('disable_class_inherits_from_params_class') -PuppetLint.configuration.send('disable_documentation') -PuppetLint.configuration.send('disable_single_quote_string_with_variables') - -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 - PuppetLint.configuration.fix = true - Rake::Task[:lint].invoke -end - -desc 'Run acceptance tests' -RSpec::Core::RakeTask.new(:acceptance) do |t| - t.pattern = 'spec/acceptance' +begin + require 'voxpupuli/acceptance/rake' +rescue LoadError + # only available if gem group acceptance is installed end -desc 'Run tests release_checks' -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 +begin + require 'voxpupuli/release/rake_tasks' +rescue LoadError + # only available if gem group releases is installed +else + GCGConfig.user = 'voxpupuli' + GCGConfig.project = 'puppet-python' 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 @@ -70,39 +33,4 @@ task test_with_coveralls: [:test] do end end -desc "Print supported beaker sets" -task 'beaker_sets', [:directory] do |t, args| - directory = args[:directory] - - metadata = JSON.load(File.read('metadata.json')) - - (metadata['operatingsystem_support'] || []).each do |os| - (os['operatingsystemrelease'] || []).each do |release| - if directory - beaker_set = "#{directory}/#{os['operatingsystem'].downcase}-#{release}" - else - beaker_set = "#{os['operatingsystem'].downcase}-#{release}-x64" - end - - filename = "spec/acceptance/nodesets/#{beaker_set}.yml" - - puts beaker_set if File.exists? filename - end - end -end - -begin - require 'github_changelog_generator/task' - GitHubChangelogGenerator::RakeTask.new :changelog do |config| - version = (Blacksmith::Modulefile.new).version - config.future_release = "v#{version}" if version =~ /^\d+\.\d+.\d+$/ - config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\nEach new release typically also includes the latest modulesync defaults.\nThese should not affect the functionality of the module." - config.exclude_labels = %w{duplicate question invalid wontfix wont-fix modulesync skip-changelog} - config.user = 'voxpupuli' - metadata_json = File.join(File.dirname(__FILE__), 'metadata.json') - metadata = JSON.load(File.read(metadata_json)) - config.project = metadata['name'] - end -rescue LoadError -end # vim: syntax=ruby diff --git a/data/common.yaml b/data/common.yaml new file mode 100644 index 00000000..8d945465 --- /dev/null +++ b/data/common.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.11" diff --git a/data/os/Archlinux.yaml b/data/os/Archlinux.yaml new file mode 100644 index 00000000..3bd58ed5 --- /dev/null +++ b/data/os/Archlinux.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.13" diff --git a/data/os/Debian/11.yaml b/data/os/Debian/11.yaml new file mode 100644 index 00000000..c3b18ece --- /dev/null +++ b/data/os/Debian/11.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.9" diff --git a/data/os/Debian/12.yaml b/data/os/Debian/12.yaml new file mode 100644 index 00000000..8d945465 --- /dev/null +++ b/data/os/Debian/12.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.11" diff --git a/data/os/Debian/13.yaml b/data/os/Debian/13.yaml new file mode 100644 index 00000000..3bd58ed5 --- /dev/null +++ b/data/os/Debian/13.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.13" diff --git a/data/os/FreeBSD.yaml b/data/os/FreeBSD.yaml new file mode 100644 index 00000000..8d945465 --- /dev/null +++ b/data/os/FreeBSD.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.11" diff --git a/data/os/Gentoo.yaml b/data/os/Gentoo.yaml new file mode 100644 index 00000000..68b52939 --- /dev/null +++ b/data/os/Gentoo.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.12" diff --git a/data/os/RedHat/8.yaml b/data/os/RedHat/8.yaml new file mode 100644 index 00000000..5de86ac2 --- /dev/null +++ b/data/os/RedHat/8.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.6" diff --git a/data/os/RedHat/9.yaml b/data/os/RedHat/9.yaml new file mode 100644 index 00000000..c3b18ece --- /dev/null +++ b/data/os/RedHat/9.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.9" diff --git a/data/os/Ubuntu/22.04.yaml b/data/os/Ubuntu/22.04.yaml new file mode 100644 index 00000000..383744c0 --- /dev/null +++ b/data/os/Ubuntu/22.04.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.10" diff --git a/data/os/Ubuntu/24.04.yaml b/data/os/Ubuntu/24.04.yaml new file mode 100644 index 00000000..68b52939 --- /dev/null +++ b/data/os/Ubuntu/24.04.yaml @@ -0,0 +1 @@ +python::default_system_version: "3.12" diff --git a/examples/gunicorn.pp b/examples/gunicorn.pp index 9308f000..c83a8224 100644 --- a/examples/gunicorn.pp +++ b/examples/gunicorn.pp @@ -1,7 +1,6 @@ class { 'python': - version => 'system', - dev => true, - virtualenv => true, + version => 'system', + dev => true, } python::gunicorn { 'vhost': diff --git a/examples/init.pp b/examples/init.pp index 4c51cc80..ab934fa9 100644 --- a/examples/init.pp +++ b/examples/init.pp @@ -1,5 +1,4 @@ class { 'python': - version => 'system', - dev => true, - virtualenv => true, + version => 'system', + dev => true, } diff --git a/examples/pip.pp b/examples/pip.pp index f0db1728..a65be945 100644 --- a/examples/pip.pp +++ b/examples/pip.pp @@ -1,7 +1,6 @@ class { 'python': - version => 'system', - dev => true, - virtualenv => true, + version => 'system', + dev => true, } python::pip { 'flask': diff --git a/examples/requirements.pp b/examples/requirements.pp index 90dccd8b..4dcf289e 100644 --- a/examples/requirements.pp +++ b/examples/requirements.pp @@ -1,7 +1,6 @@ class { 'python': - version => 'system', - dev => true, - virtualenv => true, + version => 'system', + dev => true, } python::requirements { '/var/www/project1/requirements.txt': diff --git a/examples/virtualenv.pp b/examples/virtualenv.pp deleted file mode 100644 index da5ab57c..00000000 --- a/examples/virtualenv.pp +++ /dev/null @@ -1,13 +0,0 @@ -class { 'python': - version => 'system', - dev => true, - virtualenv => true, -} - -python::virtualenv { '/var/www/project1': - ensure => present, - version => 'system', - requirements => '/var/www/project1/requirements.txt', - proxy => 'http://proxy.domain.com:3128', - systempkgs => true, -} diff --git a/hiera.yaml b/hiera.yaml new file mode 100644 index 00000000..9cea3e4d --- /dev/null +++ b/hiera.yaml @@ -0,0 +1,23 @@ +--- +version: 5 + +defaults: # Used for any hierarchy level that omits these keys. + datadir: data # This path is relative to hiera.yaml's directory. + data_hash: yaml_data # Use the built-in YAML backend. + +hierarchy: + - name: "archicture" + paths: + - "architecture/%{facts.os.architecture}.yaml" + - "architecture/common.yaml" + - name: "osfamily/major release" + paths: + - "os/%{facts.os.name}/%{facts.os.release.major}.yaml" # Used to distinguish between Debian and Ubuntu + - "os/%{facts.os.family}/%{facts.os.release.major}.yaml" # + - "os/%{facts.os.family}/%{facts.kernelrelease}.yaml" # Used for Solaris + - name: "osfamily" + paths: + - "os/%{facts.os.name}.yaml" + - "os/%{facts.os.family}.yaml" + - name: 'common' + path: 'common.yaml' diff --git a/lib/facter/pip_version.rb b/lib/facter/pip_version.rb index 808f1541..3303b237 100644 --- a/lib/facter/pip_version.rb +++ b/lib/facter/pip_version.rb @@ -1,9 +1,28 @@ +# frozen_string_literal: true + # Make pip version available as a fact +def get_pip_version(executable) + if Facter::Util::Resolution.which(executable) # rubocop:disable Style/GuardClause + results = Facter::Util::Resolution.exec("#{executable} --version 2>&1").match(%r{^pip (\d+\.\d+\.?\d*).*$}) + results[1] if results + end +end + Facter.add('pip_version') do setcode do - if Facter::Util::Resolution.which('pip') - Facter::Util::Resolution.exec('pip --version 2>&1').match(%r{^pip (\d+\.\d+\.?\d*).*$})[1] - end + get_pip_version 'pip' + end +end + +Facter.add('pip2_version') do + setcode do + get_pip_version 'pip2' + end +end + +Facter.add('pip3_version') do + setcode do + get_pip_version 'pip3' end end diff --git a/lib/facter/python_release.rb b/lib/facter/python_release.rb index 5013b5c3..fab88dbd 100644 --- a/lib/facter/python_release.rb +++ b/lib/facter/python_release.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Make python release available as facts def get_python_release(executable) diff --git a/lib/facter/python_version.rb b/lib/facter/python_version.rb index e21723bb..fe70684e 100644 --- a/lib/facter/python_version.rb +++ b/lib/facter/python_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Make python versions available as facts def get_python_version(executable) diff --git a/lib/facter/virtualenv_version.rb b/lib/facter/virtualenv_version.rb deleted file mode 100644 index cf717b91..00000000 --- a/lib/facter/virtualenv_version.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Make virtualenv version available as a fact - -Facter.add('virtualenv_version') do - setcode do - if Facter::Util::Resolution.which('virtualenv') - Facter::Util::Resolution.exec('virtualenv --version 2>&1').match(%r{^(\d+\.\d+\.?\d*).*$})[0] - end - end -end diff --git a/manifests/config.pp b/manifests/config.pp index 73a346d7..8c313313 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -5,15 +5,11 @@ # include python::config # class python::config { - Class['python::install'] -> Python::Pip <| |> Class['python::install'] -> Python::Requirements <| |> - Class['python::install'] -> Python::Virtualenv <| |> - - Python::Virtualenv <| |> -> Python::Pip <| |> if $python::manage_gunicorn { - if $python::gunicorn != 'absent' { + unless $python::gunicorn == 'absent' { Class['python::install'] -> Python::Gunicorn <| |> Python::Gunicorn <| |> ~> Service['gunicorn'] @@ -27,5 +23,4 @@ } } } - } diff --git a/manifests/dotfile.pp b/manifests/dotfile.pp index 47556fea..66d59b1e 100644 --- a/manifests/dotfile.pp +++ b/manifests/dotfile.pp @@ -24,17 +24,17 @@ # define python::dotfile ( Enum['absent', 'present'] $ensure = 'present', - String[1] $filename = $title, - String[1] $owner = 'root', - String[1] $group = 'root', - Stdlib::Filemode $mode = '0644', - Hash $config = {}, + Stdlib::Absolutepath $filename = $title, + String[1] $owner = 'root', + String[1] $group = getvar('python::params::group'), + Stdlib::Filemode $mode = '0644', + Hash $config = {}, ) { $parent_dir = dirname($filename) exec { "create ${title}'s parent dir": command => "install -o ${owner} -g ${group} -d ${parent_dir}", - path => [ '/usr/bin', '/bin', '/usr/local/bin', ], + path => ['/usr/bin', '/bin', '/usr/local/bin',], creates => $parent_dir, } diff --git a/manifests/gunicorn.pp b/manifests/gunicorn.pp index 9daa7ff1..5393ac33 100644 --- a/manifests/gunicorn.pp +++ b/manifests/gunicorn.pp @@ -34,27 +34,29 @@ # } # define python::gunicorn ( - Stdlib::Absolutepath $dir, - Enum['present', 'absent'] $ensure = present, - $config_dir = '/etc/gunicorn.d', - $manage_config_dir = false, - $virtualenv = false, - Enum['wsgi', 'django'] $mode = 'wsgi', - $bind = false, - $environment = false, - $owner = 'www-data', - $group = 'www-data', - $appmodule = 'app:app', - $osenv = false, - $timeout = 30, - $workers = false, - $access_log_format = false, - $accesslog = false, - $errorlog = false, - Enum['debug', 'info', 'warning', 'error', 'critical'] $log_level = 'error', - $template = 'python/gunicorn.erb', - $args = [], + Stdlib::Absolutepath $dir, + Enum['present', 'absent'] $ensure = present, + Stdlib::Absolutepath $config_dir = '/etc/gunicorn.d', + Boolean $manage_config_dir = false, + Variant[Boolean,Stdlib::Absolutepath] $virtualenv = false, + Enum['wsgi', 'django'] $mode = 'wsgi', + Variant[String[1],Boolean] $bind = false, + Variant[String[1],Boolean] $environment = false, + String[1] $owner = 'www-data', + String[1] $group = 'www-data', + String[1] $appmodule = 'app:app', + Variant[Boolean,Hash] $osenv = false, + Integer $timeout = 30, + Variant[Boolean,Integer] $workers = false, + Variant[Boolean,String[1]] $access_log_format = false, + Variant[Boolean,Stdlib::Absolutepath] $accesslog = false, + Variant[Boolean,Stdlib::Absolutepath] $errorlog = false, + Python::Loglevel $log_level = 'error', + String[1] $template = 'python/gunicorn.erb', + Array $args = [], ) { + $processor_count = fact('processors.count') + if $manage_config_dir { file { $config_dir: ensure => directory, @@ -62,6 +64,7 @@ owner => 'root', group => 'root', } + file { "${config_dir}/${name}": ensure => $ensure, mode => '0644', @@ -79,5 +82,4 @@ content => template($template), } } - } diff --git a/manifests/init.pp b/manifests/init.pp index 8b5ae4b6..31061daf 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,5 +1,6 @@ -# @summary Installs and manages python, python-dev, python-virtualenv and gunicorn. +# @summary Installs and manages python, python-dev and gunicorn. # +# @param default_system_version The default version of Python provided by the operating system. Only used as a fallback if Python is not installed yet to determine how to handle some actions that vary depending on the Python version used. # @param ensure Desired installation state for the Python package. # @param version Python version to install. Beware that valid values for this differ a) by the provider you choose and b) by the osfamily/operatingsystem you are using. # Allowed values: @@ -11,19 +12,23 @@ # package, if available on your osfamily. # @param pip Desired installation state for the python-pip package. # @param dev Desired installation state for the python-dev package. -# @param virtualenv Desired installation state for the virtualenv package # @param gunicorn Desired installation state for Gunicorn. # @param manage_gunicorn Allow Installation / Removal of Gunicorn. # @param provider What provider to use for installation of the packages, except gunicorn and Python itself. # @param use_epel to determine if the epel class is used. # @param manage_scl Whether to manage core SCL packages or not. +# @param umask The default umask for invoked exec calls. +# @param manage_gunicorn manage the state for package gunicorn +# @param manage_python_package manage the state for package python +# @param manage_dev_package manage the state of the python development package +# @param manage_venv_package manage the state for package venv +# @param manage_pip_package manage the state for package pip # # @example install python from system python # class { 'python': # version => 'system', # pip => 'present', # dev => 'present', -# virtualenv => 'present', # gunicorn => 'present', # } # @example install python3 from scl repo @@ -31,60 +36,48 @@ # ensure => 'present', # version => 'rh-python36-python', # dev => 'present', -# virtualenv => 'present', # } # class python ( - Enum['absent', 'present', 'latest'] $ensure = $python::params::ensure, - $version = $python::params::version, - Enum['absent', 'present', 'latest'] $pip = $python::params::pip, - Enum['absent', 'present', 'latest'] $dev = $python::params::dev, - Enum['absent', 'present', 'latest'] $virtualenv = $python::params::virtualenv, - Enum['absent', 'present', 'latest'] $gunicorn = $python::params::gunicorn, - Boolean $manage_gunicorn = $python::params::manage_gunicorn, - $gunicorn_package_name = $python::params::gunicorn_package_name, - Optional[Enum['pip', 'scl', 'rhscl', 'anaconda', '']] $provider = $python::params::provider, - $valid_versions = $python::params::valid_versions, - Hash $python_pips = { }, - Hash $python_virtualenvs = { }, - Hash $python_pyvenvs = { }, - Hash $python_requirements = { }, - Hash $python_dotfiles = { }, - Boolean $use_epel = $python::params::use_epel, - $rhscl_use_public_repository = $python::params::rhscl_use_public_repository, - Stdlib::Httpurl $anaconda_installer_url = $python::params::anaconda_installer_url, - Stdlib::Absolutepath $anaconda_install_path = $python::params::anaconda_install_path, - Boolean $manage_scl = $python::params::manage_scl, + Python::Version $default_system_version, + Python::Package::Ensure $ensure = 'present', + Python::Version $version = $facts['os']['family'] ? { 'Archlinux' => 'system', default => '3' }, + Python::Package::Ensure $pip = 'present', + Python::Package::Ensure $dev = 'absent', + Python::Package::Ensure $venv = 'absent', + Python::Package::Ensure $gunicorn = 'absent', + Boolean $manage_gunicorn = true, + Boolean $manage_python_package = true, + Boolean $manage_dev_package = true, + Boolean $manage_venv_package = $python::params::manage_venv_package, + Boolean $manage_pip_package = $python::params::manage_pip_package, + String[1] $gunicorn_package_name = $python::params::gunicorn_package_name, + Optional[Python::Provider] $provider = undef, + Hash $python_pips = {}, + Hash $python_pyvenvs = {}, + Hash $python_requirements = {}, + Hash $python_dotfiles = {}, + Boolean $use_epel = $python::params::use_epel, + Boolean $rhscl_use_public_repository = true, + Stdlib::Httpurl $anaconda_installer_url = 'https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh', + Stdlib::Absolutepath $anaconda_install_path = '/opt/python', + Boolean $manage_scl = true, ) inherits python::params { - $exec_prefix = $provider ? { 'scl' => "/usr/bin/scl enable ${version} -- ", 'rhscl' => "/usr/bin/scl enable ${version} -- ", default => '', } - unless $version =~ Pattern[/\A(python)?[0-9](\.[0-9])+/, - /\Apypy\Z/, /\Asystem\Z/, /\Arh-python[0-9]{2}(?:-python)?\Z/] { - fail("version needs to be pypy, system or a version string like '3.5' or 'python3.5)") - } + contain python::install + contain python::config - # Module compatibility check - $compatible = [ 'Debian', 'RedHat', 'Suse', 'Gentoo', 'AIX' ] - if ! ($facts['os']['family'] in $compatible) { - fail("Module is not compatible with ${::operatingsystem}") - } - - # Anchor pattern to contain dependencies - anchor { 'python::begin': } - -> class { 'python::install': } - -> class { 'python::config': } - -> anchor { 'python::end': } + Class['python::install'] + -> Class['python::config'] # Allow hiera configuration of python resources create_resources('python::pip', $python_pips) create_resources('python::pyvenv', $python_pyvenvs) - create_resources('python::virtualenv', $python_virtualenvs) create_resources('python::requirements', $python_requirements) create_resources('python::dotfile', $python_dotfiles) - } diff --git a/manifests/install.pp b/manifests/install.pp index 63c88079..60adfc05 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -5,80 +5,65 @@ # include python::install # class python::install { - - $python_version = getparam(Class['python'], 'version') - $python = $python_version ? { - 'system' => 'python', - 'pypy' => 'pypy', - /\A(python)?([0-9](\.?[0-9])+)/ => "python${2}", - /\Arh-python[0-9]{2}/ => $python_version, - default => "python${python::version}", + $python = $python::version ? { + 'system' => 'python', + 'pypy' => 'pypy', + /\A(python[23]\.[0-9]+)/ => $1, + /\A(python)?([0-9]+)/ => "python${2}", + /\Arh-python[0-9]{2}/ => $python::version, + default => "python${python::version}", } $pythondev = $facts['os']['family'] ? { - 'AIX' => "${python}-devel", - 'RedHat' => "${python}-devel", - 'Debian' => "${python}-dev", - 'Suse' => "${python}-devel", - 'Gentoo' => undef, - } - - $pip_ensure = $python::pip ? { - true => 'present', - false => 'absent', - default => $python::pip, + 'AIX' => "${python}-devel", + 'Debian' => "${python}-dev", + 'FreeBSD' => undef, + 'Gentoo' => undef, + 'Archlinux' => undef, + 'RedHat' => "${python}-devel", + 'Suse' => "${python}-devel", } - $venv_ensure = $python::virtualenv ? { - true => 'present', - false => 'absent', - default => $python::virtualenv, - } - - if $venv_ensure == 'present' { - $dev_ensure = 'present' - unless $python::dev { - # Error: python2-devel is needed by (installed) python-virtualenv-15.1.0-2.el7.noarch - # Python dev is required for virtual environment, but python environment is not required for python dev. - notify { 'Python virtual environment is dependent on python dev': } - } - } else { - $dev_ensure = $python::dev ? { - true => 'present', - false => 'absent', - default => $python::dev, + if $python::manage_python_package { + package { 'python': + ensure => $python::ensure, + name => $python, } } - package { 'python': - ensure => $python::ensure, - name => $python, - } - - package { 'virtualenv': - ensure => $venv_ensure, - require => Package['python'], + if $python::manage_venv_package { + ## + ## CentOS has no extra package for venv + ## + unless $facts['os']['family'] == 'RedHat' { + package { 'python-venv': + ensure => $python::venv, + name => "${python}-venv", + require => Package['python'], + } + } } case $python::provider { 'pip': { - - package { 'pip': - ensure => $pip_ensure, - require => Package['python'], + if $python::manage_pip_package { + package { 'pip': + ensure => $python::pip, + require => Package['python'], + } } - if $pythondev { + if $python::manage_dev_package and $pythondev { package { 'python-dev': - ensure => $dev_ensure, + ensure => $python::dev, name => $pythondev, } } - # Respect the $pip_ensure setting - unless $pip_ensure == 'absent' { + # Respect the $python::pip setting + unless $python::pip == 'absent' { # Install pip without pip, see https://pip.pypa.io/en/stable/installing/. - include 'python::pip::bootstrap' + include python::pip::bootstrap Exec['bootstrap pip'] -> File['pip-python'] -> Package <| provider == pip |> @@ -86,18 +71,6 @@ name => 'pip', provider => 'pip', } - if $pythondev { - Package <| title == 'virtualenv' |> { - name => 'virtualenv', - provider => 'pip', - require => Package['python-dev'], - } - } else { - Package <| title == 'virtualenv' |> { - name => 'virtualenv', - provider => 'pip', - } - } } } 'scl': { @@ -114,6 +87,7 @@ ensure => $install_scl_repo_package, before => Package['scl-utils'], } + package { 'scl-utils': ensure => 'present', before => Package['python'], @@ -121,20 +95,16 @@ Package['scl-utils'] -> Package["${python}-scldevel"] - if $pip_ensure != 'absent' { + if $python::pip != 'absent' { Package['scl-utils'] -> Exec['python-scl-pip-install'] } } - # This gets installed as a dependency anyway - # package { "${python::version}-python-virtualenv": - # ensure => $venv_ensure, - # require => Package['scl-utils'], - # } package { "${python}-scldevel": - ensure => $dev_ensure, + ensure => $python::dev, } - if $pip_ensure != 'absent' { + + if $python::pip != 'absent' { exec { 'python-scl-pip-install': command => "${python::exec_prefix}easy_install pip", path => ['/usr/bin', '/bin'], @@ -144,10 +114,11 @@ } 'rhscl': { # rhscl is RedHat SCLs from softwarecollections.org - if $::python::rhscl_use_public_repository { - $scl_package = "rhscl-${::python::version}-epel-${::operatingsystemmajrelease}-${::architecture}" + if $python::rhscl_use_public_repository { + $scl_package = "rhscl-${python::version}-epel-${facts['os']['release']['major']}-${facts['os']['architecture']}" + package { $scl_package: - source => "https://www.softwarecollections.org/en/scls/rhscl/${::python::version}/epel-${::operatingsystemmajrelease}-${::architecture}/download/${scl_package}.noarch.rpm", + source => "https://www.softwarecollections.org/en/scls/rhscl/${python::version}/epel-${facts['os']['release']['major']}-${facts['os']['architecture']}/download/${scl_package}.noarch.rpm", provider => 'rpm', tag => 'python-scl-repo', } @@ -157,138 +128,115 @@ tag => 'python-scl-package', } - Package <| title == 'virtualenv' |> { - name => "${python}-python-virtualenv", - } - package { "${python}-scldevel": - ensure => $dev_ensure, + ensure => $python::dev, tag => 'python-scl-package', } package { "${python}-python-pip": - ensure => $pip_ensure, + ensure => $python::pip, tag => 'python-pip-package', } - if $::python::rhscl_use_public_repository { + if $python::rhscl_use_public_repository { Package <| tag == 'python-scl-repo' |> -> Package <| tag == 'python-scl-package' |> } - Package <| tag == 'python-scl-package' |> - -> Package <| tag == 'python-pip-package' |> + Package <| tag == 'python-scl-package' |> -> Package <| tag == 'python-pip-package' |> } 'anaconda': { $installer_path = '/var/tmp/anaconda_installer.sh' file { $installer_path: - source => $::python::anaconda_installer_url, + source => $python::anaconda_installer_url, mode => '0700', } -> exec { 'install_anaconda_python': - command => "${installer_path} -b -p ${::python::anaconda_install_path}", - creates => $::python::anaconda_install_path, + command => "${installer_path} -b -p ${python::anaconda_install_path}", + creates => $python::anaconda_install_path, logoutput => true, } -> exec { 'install_anaconda_virtualenv': - command => "${::python::anaconda_install_path}/bin/pip install virtualenv", - creates => "${::python::anaconda_install_path}/bin/virtualenv", + command => "${python::anaconda_install_path}/bin/pip install virtualenv", + creates => "${python::anaconda_install_path}/bin/virtualenv", } } default: { case $facts['os']['family'] { 'AIX': { - if "${python_version}" =~ /^python3/ { #lint:ignore:only_variable_string - class { 'python::pip::bootstap': - version => 'pip3', + if String($python::version) =~ /^python3/ { + class { 'python::pip::bootstrap': + version => 'pip3', } } else { - package { 'python-pip': - ensure => $pip_ensure, - require => Package['python'], - provider => 'yum', + if $python::manage_pip_package { + package { 'python-pip': + ensure => $python::pip, + require => Package['python'], + provider => 'yum', + } } } - if $pythondev { + + if $python::manage_dev_package and $pythondev { package { 'python-dev': - ensure => $dev_ensure, + ensure => $python::dev, name => $pythondev, alias => $pythondev, provider => 'yum', } } - } default: { - package { 'pip': - ensure => $pip_ensure, - require => Package['python'], + if $python::manage_pip_package { + package { 'pip': + ensure => $python::pip, + require => Package['python'], + } } - if $pythondev { + + if $python::manage_dev_package and $pythondev { package { 'python-dev': - ensure => $dev_ensure, + ensure => $python::dev, name => $pythondev, alias => $pythondev, } } - } } - case $facts['os']['family'] { - 'RedHat': { - if $pip_ensure != 'absent' { - if $python::use_epel == true { - include 'epel' - Class['epel'] -> Package['pip'] - } - } - if ($venv_ensure != 'absent') and ($::operatingsystemrelease =~ /^6/) { - if $python::use_epel == true { - include 'epel' - Class['epel'] -> Package['virtualenv'] - } - } - - $virtualenv_package = "${python}-virtualenv" - } - 'Debian': { - if fact('lsbdistcodename') == 'trusty' { - $virtualenv_package = 'python-virtualenv' - } else { - $virtualenv_package = 'virtualenv' - } - } - 'Gentoo': { - $virtualenv_package = 'virtualenv' - } - default: { - $virtualenv_package = 'python-virtualenv' + if $facts['os']['family'] == 'RedHat' { + if $python::pip != 'absent' and $python::use_epel and ($python::manage_pip_package or $python::manage_python_package) { + require epel } } - if "${::python::version}" =~ /^python3/ { #lint:ignore:only_variable_string - $pip_category = undef - $pip_package = 'python3-pip' - } elsif ($::osfamily == 'RedHat') and (versioncmp($::operatingsystemmajrelease, '7') >= 0) { - $pip_category = undef - $pip_package = 'python2-pip' - } elsif $::osfamily == 'Gentoo' { - $pip_category = 'dev-python' - $pip_package = 'pip' + if String($python::version) =~ /^python3/ { + $pip_package = "${python}-pip" + $pip_provider = $python.regsubst(/^.*python3\.?/,'pip3.').regsubst(/\.$/,'') + } elsif $facts['os']['family'] == 'RedHat' { + $pip_package = 'python3-pip' + $pip_provider = pip3 + } elsif $facts['os']['family'] == 'FreeBSD' { + $pip_package = "py${python::version}-pip" + $pip_provider = 'pip' + } elsif $facts['os']['family'] == 'Gentoo' { + $pip_package = 'dev-python/pip' + $pip_provider = 'pip' + } elsif $facts['os']['name'] == 'Ubuntu' { + $pip_package = 'python3-pip' + $pip_provider = 'pip3' + } elsif $facts['os']['name'] == 'Debian' { + $pip_package = 'python3-pip' + $pip_provider = 'pip3' } else { - $pip_category = undef - $pip_package = 'python-pip' + $pip_package = 'python-pip' + $pip_provider = 'pip' } Package <| title == 'pip' |> { - name => $pip_package, - category => $pip_category, - } - - Package <| title == 'virtualenv' |> { - name => $virtualenv_package, + name => $pip_package, } } } diff --git a/manifests/params.pp b/manifests/params.pp index 6aa9f996..49bfdeac 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -4,44 +4,42 @@ # The python Module default configuration settings. # class python::params { - $ensure = 'present' - $version = 'system' - $pip = 'present' - $dev = 'absent' - $virtualenv = 'absent' - $gunicorn = 'absent' - $manage_gunicorn = true - $provider = undef - $valid_versions = undef - $manage_scl = true + # Module compatibility check + unless $facts['os']['family'] in ['AIX', 'Debian', 'FreeBSD', 'Gentoo', 'RedHat', 'Suse', 'Archlinux'] { + fail("Module is not compatible with ${facts['os']['name']}") + } - if $::osfamily == 'RedHat' { - if $::operatingsystem != 'Fedora' { - $use_epel = true - } else { - $use_epel = false - } + if $facts['os']['family'] == 'RedHat' and $facts['os']['name'] != 'Fedora' { + $use_epel = true } else { - $use_epel = false + $use_epel = false } $group = $facts['os']['family'] ? { - 'AIX' => 'system', - default => 'root' + 'AIX' => 'system', + 'FreeBSD' => 'wheel', + default => 'root' } $pip_lookup_path = $facts['os']['family'] ? { - 'AIX' => [ '/bin', '/usr/bin', '/usr/local/bin', '/opt/freeware/bin/' ], - default => [ '/bin', '/usr/bin', '/usr/local/bin' ] + 'AIX' => ['/bin', '/usr/bin', '/usr/local/bin', '/opt/freeware/bin/',], + default => ['/bin', '/usr/bin', '/usr/local/bin',] } $gunicorn_package_name = $facts['os']['family'] ? { - 'RedHat' => 'python-gunicorn', + 'RedHat' => $facts['os']['release']['major'] ? { + '7' => 'python-gunicorn', + default => 'python3-gunicorn', + }, default => 'gunicorn', } - $rhscl_use_public_repository = true - - $anaconda_installer_url = 'https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh' - $anaconda_install_path = '/opt/python' + $manage_pip_package = $facts['os']['family'] ? { + 'Archlinux' => false, + default => true, + } + $manage_venv_package = $facts['os']['family'] ? { + 'Archlinux' => false, + default => true, + } } diff --git a/manifests/pip.pp b/manifests/pip.pp index 56413f74..9d568207 100644 --- a/manifests/pip.pp +++ b/manifests/pip.pp @@ -9,6 +9,7 @@ # @param owner The owner of the virtualenv being manipulated. # @param group The group of the virtualenv being manipulated. # @param index Base URL of Python package index. +# @param extra_index Base URL of extra Python package index. # @param proxy Proxy server to use for outbound connections. # @param editable If true the package is installed as an editable resource. # @param environment Additional environment variables required to install the packages. @@ -33,7 +34,7 @@ # virtualenv => '/var/www/project1', # owner => 'appuser', # proxy => 'http://proxy.domain.com:3128', -# environment => 'ORACLE_HOME=/usr/lib/oracle/11.2/client64', +# environment => ['ORACLE_HOME=/usr/lib/oracle/11.2/client64'], # install_args => '-e', # timeout => 1800, # } @@ -48,32 +49,33 @@ # } # define python::pip ( - String $pkgname = $name, - Variant[Enum[present, absent, latest], String[1]] $ensure = present, - Variant[Enum['system'], Stdlib::Absolutepath] $virtualenv = 'system', - Enum['pip', 'pip3'] $pip_provider = 'pip', - Variant[Boolean, String] $url = false, - String[1] $owner = 'root', - $group = getvar('python::params::group'), - $umask = undef, - $index = false, - Variant[Boolean, String] $proxy = false, - $egg = false, - Boolean $editable = false, - $environment = [], - $extras = [], - String $install_args = '', - String $uninstall_args = '', - Numeric $timeout = 1800, - String[1] $log_dir = '/tmp', - Array[String] $path = ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'], -){ + String[1] $pkgname = $name, + Variant[Enum[present, absent, latest], String[1]] $ensure = present, + Variant[Enum['system'], Stdlib::Absolutepath] $virtualenv = 'system', + String[1] $pip_provider = 'pip', + Variant[Boolean, String] $url = false, + String[1] $owner = 'root', + Optional[String[1]] $group = getvar('python::params::group'), + Optional[Python::Umask] $umask = undef, + Variant[Boolean,String[1]] $index = false, + Variant[Boolean,String[1]] $extra_index = false, + Optional[Stdlib::HTTPUrl] $proxy = undef, + Any $egg = false, + Boolean $editable = false, + Array $environment = [], + Array $extras = [], + Optional[String[1]] $install_args = undef, + Optional[String[1]] $uninstall_args = undef, + Numeric $timeout = 1800, + String[1] $log_dir = '/tmp', + Array[String] $path = ['/usr/local/bin','/usr/bin','/bin', '/usr/sbin'], + String[1] $exec_provider = 'shell', +) { $python_provider = getparam(Class['python'], 'provider') $python_version = getparam(Class['python'], 'version') if $virtualenv != 'system' { Python::Pyvenv <| |> -> Python::Pip[$name] - Python::Virtualenv <| |> -> Python::Pip[$name] } # Get SCL exec prefix @@ -85,7 +87,7 @@ } $_path = $python_provider ? { - 'anaconda' => concat(["${::python::anaconda_install_path}/bin"], $path), + 'anaconda' => concat(["${python::anaconda_install_path}/bin"], $path), default => $path, } @@ -110,12 +112,17 @@ } $pypi_index = $index ? { - false => '', - default => "--index-url=${index}", - } + false => '', + default => "--index-url=${index}", + } + + $pypi_extra_index = $extra_index ? { + false => '', + default => "--extra-index-url=${extra_index}", + } $proxy_flag = $proxy ? { - false => '', + undef => '', default => "--proxy=${proxy}", } @@ -126,23 +133,35 @@ $install_editable = '' } - #TODO: Do more robust argument checking, but below is a start - if ($ensure == absent) and ($install_args != '') { + # TODO: Do more robust argument checking, but below is a start + if ($ensure == absent) and $install_args { fail('python::pip cannot provide install_args with ensure => absent') } - if ($ensure == present) and ($uninstall_args != '') { + if ($ensure == present) and $uninstall_args { fail('python::pip cannot provide uninstall_args with ensure => present') } - # Check if searching by explicit version. - if $ensure =~ /^((19|20)[0-9][0-9]-(0[1-9]|1[1-2])-([0-2][1-9]|3[0-1])|[0-9]+\.\w+\+?\w*(\.\w+)*)$/ { - $grep_regex = "^${pkgname}==${ensure}\$" - } else { - $grep_regex = $pkgname ? { - /==/ => "^${pkgname}\$", - default => "^${pkgname}==", + if $pkgname =~ /==/ { + $parts = split($pkgname, '==') + $real_pkgname = $parts[0] + + $_ensure = $ensure ? { + 'absent' => 'absent', + default => $parts[1], } + } else { + $real_pkgname = $pkgname + $_ensure = $ensure + } + + # We do not try to mimic a version scheme validation which is already implemented by the package manager. + # If it starts with a number it is probably a version. + # If it wasn't or if there is any error, the package manager will trigger a failure. + $grep_regex = $_ensure ? { + /^(present|absent|latest)$/ => "^${real_pkgname}[[:space:]].*$", + /^v?[0-9].*$/ => "^${real_pkgname}[[:space:]]\\+(\\?${_ensure}\\()$\\|$\\|, \\|[[:space:]]\\)", + default => fail('ensure can be a version number (e.g. 1.7.0 or v1.7.0) or one of: present, absent, latest') } $extras_string = empty($extras) ? { @@ -151,140 +170,95 @@ } $egg_name = $egg ? { - false => "${pkgname}${extras_string}", + false => "${real_pkgname}${extras_string}", default => $egg } $source = $url ? { - false => "${pkgname}${extras_string}", - /^(\/|[a-zA-Z]\:)/ => $url, - /^(git\+|hg\+|bzr\+|svn\+)(http|https|ssh|svn|sftp|ftp|lp)(:\/\/).+$/ => $url, - default => "${url}#egg=${egg_name}", + false => "${real_pkgname}${extras_string}", + /^(\/|[a-zA-Z]\:)/ => "'${url}'", + /^(git\+|hg\+|bzr\+|svn\+)(http|https|ssh|svn|sftp|ftp|lp|git)(:\/\/).+$/ => "'${url}'", + default => "'${url}#egg=${egg_name}'", } - # We need to jump through hoops to make sure we issue the correct pip command - # depending on wheel support and versions. - # - # Pip does not support wheels prior to version 1.4.0 - # Pip wheels require setuptools/distribute > 0.8 - # Python 2.6 and older does not support setuptools/distribute > 0.8 - # Pip >= 1.5 tries to use wheels by default, even if wheel package is not - # installed, in this case the --no-use-wheel flag needs to be passed - # Versions prior to 1.5 don't support the --no-use-wheel flag - # - # To check for this we test for wheel parameter using help and then using - # show, this makes sure we only use wheels if they are supported and - # installed - $wheel_check = "${pip_env} wheel --help > /dev/null 2>&1 && { ${pip_env} show wheel > /dev/null 2>&1 || wheel_support_flag='--no-binary :all:'; }" - - $pip_install = "${pip_env} --log ${log}/pip.log install" - $pip_common_args = "${pypi_index} ${proxy_flag} ${install_args} ${install_editable} ${source}" + $pip_install = "${pip_env} install" + $pip_common_args = "${pypi_index} ${pypi_extra_index} ${proxy_flag} ${install_editable} ${source}" # Explicit version out of VCS when PIP supported URL is provided - if $source =~ /^(git\+|hg\+|bzr\+|svn\+)(http|https|ssh|svn|sftp|ftp|lp)(:\/\/).+$/ { - if $ensure != present and $ensure != latest { - exec { "pip_install_${name}": - command => "${wheel_check} ; { ${pip_install} ${install_args} \$wheel_support_flag ${pip_common_args}@${ensure}#egg=${egg_name} || ${pip_install} ${install_args} ${pip_common_args}@${ensure}#egg=${egg_name} ;}", - unless => "${pip_env} freeze --all | grep -i -e ${grep_regex}", - user => $owner, - group => $group, - umask => $umask, - cwd => $cwd, - environment => $environment, - timeout => $timeout, - path => $_path, - } + if $source =~ /^'(git\+|hg\+|bzr\+|svn\+)(http|https|ssh|svn|sftp|ftp|lp|git)(:\/\/).+'$/ { + if $_ensure != present and $_ensure != latest { + $command = "${pip_install} ${install_args} ${pip_common_args}@${_ensure}#egg=${egg_name}" + $unless_command = "${pip_env} list | grep -i -e '${grep_regex}'" } else { - exec { "pip_install_${name}": - command => "${wheel_check} ; { ${pip_install} ${install_args} \$wheel_support_flag ${pip_common_args} || ${pip_install} ${install_args} ${pip_common_args} ;}", - unless => "${pip_env} freeze --all | grep -i -e ${grep_regex}", - user => $owner, - group => $group, - umask => $umask, - cwd => $cwd, - environment => $environment, - timeout => $timeout, - path => $_path, - } + $command = "${pip_install} ${install_args} ${pip_common_args}" + $unless_command = "${pip_env} list | grep -i -e '${grep_regex}'" } } else { - case $ensure { - /^((19|20)[0-9][0-9]-(0[1-9]|1[1-2])-([0-2][1-9]|3[0-1])|[0-9]+\.\w+\+?\w*(\.\w+)*)$/: { - # Version formats as per http://guide.python-distribute.org/specification.html#standard-versioning-schemes - # Explicit version. - exec { "pip_install_${name}": - command => "${wheel_check} ; { ${pip_install} ${install_args} \$wheel_support_flag ${pip_common_args}==${ensure} || ${pip_install} ${install_args} ${pip_common_args}==${ensure} ;}", - unless => "${pip_env} freeze --all | grep -i -e ${grep_regex} || ${pip_env} list | sed -e 's/[ ]\\+/==/' -e 's/[()]//g' | grep -i -e ${grep_regex}", - user => $owner, - group => $group, - umask => $umask, - cwd => $cwd, - environment => $environment, - timeout => $timeout, - path => $_path, - } + case $_ensure { + /^v?[0-9].*$/: { + # Specific version + $command = "${pip_install} ${install_args} ${pip_common_args}==${_ensure}" + $unless_command = "${pip_env} list | grep -i -e '${grep_regex}'" } -# + 'present': { # Whatever version is available. - exec { "pip_install_${name}": - command => "${wheel_check} ; { ${pip_install} \$wheel_support_flag ${pip_common_args} || ${pip_install} ${pip_common_args} ;}", - unless => "${pip_env} freeze --all | grep -i -e ${grep_regex} || ${pip_env} list | sed -e 's/[ ]\\+/==/' -e 's/[()]//g' | grep -i -e ${grep_regex}", - user => $owner, - group => $group, - umask => $umask, - cwd => $cwd, - environment => $environment, - timeout => $timeout, - path => $_path, - } + $command = "${pip_install} ${install_args} ${pip_common_args}" + $unless_command = "${pip_env} list | grep -i -e '${grep_regex}'" } 'latest': { + $pip_version = $facts['pip_version'] + if $pip_version and versioncmp($pip_version, '21.1') == -1 and versioncmp($pip_version, '20.2.4') == 1 { + $legacy_resolver = '--use-deprecated=legacy-resolver' + } else { + $legacy_resolver = '' + } + # Unfortunately this is the smartest way of getting the latest available package version with pip as of now # Note: we DO need to repeat ourselves with "from version" in both grep and sed as on some systems pip returns # more than one line with paretheses. - $latest_version = join(["${pip_install} ${pypi_index} ${proxy_flag} ${install_args} ${install_editable} ${pkgname}==notreallyaversion 2>&1", - ' | grep -oP "\(from versions: .*\)" | sed -E "s/\(from versions: (.*?, )*(.*)\)/\2/g"', - ' | tr -d "[:space:]"']) + $latest_version = join( + [ + "${pip_install} ${legacy_resolver} ${pypi_index} ${pypi_extra_index} ${proxy_flag}", + " ${install_args} ${install_editable} '${real_pkgname}==9!0dev0+x' 2>&1", + " | sed -nE 's/.*\\(from versions: (.*, )*(.*)\\)/\\2/p'", + ' | tr -d "[:space:]"', + ], + ) # Packages with underscores in their names are listed with dashes in their place in `pip freeze` output - $pkgname_with_dashes = regsubst($pkgname, '_', '-', 'G') + $pkgname_with_dashes = regsubst($real_pkgname, '_', '-', 'G') $grep_regex_pkgname_with_dashes = "^${pkgname_with_dashes}==" - $installed_version = join(["${pip_env} freeze --all", - " | grep -i -e ${grep_regex_pkgname_with_dashes} | cut -d= -f3", - " | tr -d '[:space:]'"]) + $installed_version = join(["${pip_env} freeze --all", " | grep -i -e ${grep_regex_pkgname_with_dashes} | cut -d= -f3", " | tr -d '[:space:]'",]) + $command = "${pip_install} --upgrade ${install_args} ${pip_common_args}" $unless_command = "[ \$(${latest_version}) = \$(${installed_version}) ]" - - # Latest version. - exec { "pip_install_${name}": - command => "${wheel_check} ; { ${pip_install} --upgrade \$wheel_support_flag ${pip_common_args} || ${pip_install} --upgrade ${pip_common_args} ;}", - unless => $unless_command, - user => $owner, - group => $group, - umask => $umask, - cwd => $cwd, - environment => $environment, - timeout => $timeout, - path => $_path, - } } default: { # Anti-action, uninstall. - exec { "pip_uninstall_${name}": - command => "echo y | ${pip_env} uninstall ${uninstall_args} ${proxy_flag} ${name}", - onlyif => "${pip_env} freeze --all | grep -i -e ${grep_regex}", - user => $owner, - group => $group, - umask => $umask, - cwd => $cwd, - environment => $environment, - timeout => $timeout, - path => $_path, - } + $command = "echo y | ${pip_env} uninstall ${uninstall_args} ${proxy_flag} ${real_pkgname}" + $unless_command = "! ${pip_env} list | grep -i -e '${grep_regex}'" } } } + + $pip_installer = ($ensure == 'absent') ? { + true => "pip_uninstall_${name}", + false => "pip_install_${name}", + } + + exec { $pip_installer: + command => $command, + unless => $unless_command, + user => $owner, + group => $group, + umask => $umask, + cwd => $cwd, + environment => $environment, + timeout => $timeout, + path => $_path, + provider => $exec_provider, + } } diff --git a/manifests/pip/bootstrap.pp b/manifests/pip/bootstrap.pp index 10b3c348..b060a6d0 100644 --- a/manifests/pip/bootstrap.pp +++ b/manifests/pip/bootstrap.pp @@ -1,17 +1,20 @@ -# # @summary allow to bootstrap pip when python is managed from other module # # @param version should be pip or pip3 # @param manage_python if python module will manage deps +# @param http_proxy Proxy server to use for outbound connections. # -# @example +# @example # class { 'python::pip::bootstrap': # version => 'pip', # } +# class python::pip::bootstrap ( - Enum['pip', 'pip3'] $version = 'pip', - Variant[Boolean, String] $manage_python = false, -) inherits ::python::params { + Enum['pip', 'pip3'] $version = 'pip', + Variant[Boolean, String] $manage_python = false, + Optional[Stdlib::HTTPUrl] $http_proxy = undef, + String[1] $exec_provider = 'shell', +) inherits python::params { if $manage_python { include python } else { @@ -19,34 +22,49 @@ 'AIX' => '/opt/freeware/bin', default => '/usr/bin' } + + $environ = $http_proxy ? { + undef => [], + default => $facts['os']['family'] ? { + 'AIX' => ["http_proxy=${http_proxy}", "https_proxy=${http_proxy}"], + default => ["HTTP_PROXY=${http_proxy}", "HTTPS_PROXY=${http_proxy}"], + } + } + if $version == 'pip3' { exec { 'bootstrap pip3': - command => '/usr/bin/curl https://bootstrap.pypa.io/get-pip.py | python3', - unless => 'which pip3', - path => $python::params::pip_lookup_path, - require => Package['python3'], + command => '/usr/bin/curl https://bootstrap.pypa.io/get-pip.py | python3', + environment => $environ, + unless => 'which pip3', + path => $python::params::pip_lookup_path, + require => Package['python3'], + provider => $exec_provider, } + # puppet is opinionated about the pip command name file { 'pip3-python': ensure => link, path => '/usr/bin/pip3', - target => "${target_src_pip_path}/pip${::facts['python3_release']}", + target => "${target_src_pip_path}/pip${facts['python3_release']}", require => Exec['bootstrap pip3'], } } else { - exec { 'bootstrap pip': - command => '/usr/bin/curl https://bootstrap.pypa.io/get-pip.py | python', - unless => 'which pip', - path => $python::params::pip_lookup_path, - require => Package['python'], - } - # puppet is opinionated about the pip command name - file { 'pip-python': - ensure => link, - path => '/usr/bin/pip', - target => "${target_src_pip_path}/pip${::facts['python2_release']}", - require => Exec['bootstrap pip'], - } + exec { 'bootstrap pip': + command => '/usr/bin/curl https://bootstrap.pypa.io/get-pip.py | python', + environment => $environ, + unless => 'which pip', + path => $python::params::pip_lookup_path, + require => Package['python'], + provider => $exec_provider, + } + + # puppet is opinionated about the pip command name + file { 'pip-python': + ensure => link, + path => '/usr/bin/pip', + target => "${target_src_pip_path}/pip${facts['python2_release']}", + require => Exec['bootstrap pip'], + } } } } diff --git a/manifests/pyvenv.pp b/manifests/pyvenv.pp index 59b582ed..7aa7202f 100644 --- a/manifests/pyvenv.pp +++ b/manifests/pyvenv.pp @@ -10,6 +10,8 @@ # @param mode Optionally specify directory mode # @param path Specifies the PATH variable. # @param environment Optionally specify environment variables for pyvenv +# @param prompt Optionally specify the virtualenv prompt (python >= 3.6) +# @param python_path Optionally specify python path for creation of virtualenv # # @example # python::pyvenv { '/var/www/project1' : @@ -22,74 +24,83 @@ # } # define python::pyvenv ( - $ensure = present, - $version = 'system', - $systempkgs = false, - $venv_dir = $name, - $owner = 'root', - $group = 'root', - $mode = '0755', - $path = [ '/bin', '/usr/bin', '/usr/sbin', '/usr/local/bin' ], - $environment = [], + Python::Package::Ensure $ensure = present, + Python::Version $version = 'system', + Boolean $systempkgs = false, + Stdlib::Absolutepath $venv_dir = $name, + String[1] $owner = 'root', + String[1] $group = 'root', + Stdlib::Filemode $mode = '0755', + Array[Stdlib::Absolutepath] $path = ['/bin', '/usr/bin', '/usr/sbin', '/usr/local/bin',], + Array[String[1]] $environment = [], + Optional[String[1]] $prompt = undef, + Python::Venv::PipVersion $pip_version = 'latest', + Optional[Stdlib::Absolutepath] $python_path = undef, ) { - include python if $ensure == 'present' { $python_version = $version ? { - 'system' => $facts['python3_version'], - default => $version, + 'system' => $facts['python3_version'].lest || { $python::default_system_version }, + default => $version, } - $python_version_parts = split($python_version, '[.]') + $python_version_parts = split($python_version, '[.]') $normalized_python_version = sprintf('%s.%s', $python_version_parts[0], $python_version_parts[1]) - # Debian splits the venv module into a seperate package - if ( $facts['os']['family'] == 'Debian'){ - $python3_venv_package="python${normalized_python_version}-venv" - case $facts['lsbdistcodename'] { - 'xenial','bionic','cosmic','disco', - 'jessie','stretch','buster': { - ensure_packages ($python3_venv_package, { - before => File[$venv_dir], - }) - } - default: {} - } + $local_exec_prefix = $python_path ? { + undef => $python::exec_prefix, + default => $python_path, } - # pyvenv is deprecated since 3.6 and will be removed in 3.8 - if (versioncmp($normalized_python_version, '3.6') >=0) { - $virtualenv_cmd = "${python::exec_prefix}python${normalized_python_version} -m venv" + if $python_path != undef { + $virtualenv_cmd = "${python_path} -m venv" + } elsif versioncmp($normalized_python_version, '3.6') >=0 { + $virtualenv_cmd = "${local_exec_prefix}python${normalized_python_version} -m venv" } else { - $virtualenv_cmd = "${python::exec_prefix}pyvenv-${normalized_python_version}" + $virtualenv_cmd = "${local_exec_prefix}pyvenv-${normalized_python_version}" } - $_path = $::python::provider ? { - 'anaconda' => concat(["${::python::anaconda_install_path}/bin"], $path), + $_path = $python::provider ? { + 'anaconda' => concat(["${python::anaconda_install_path}/bin"], $path), default => $path, } - if ( $systempkgs == true ) { + if $systempkgs == true { $system_pkgs_flag = '--system-site-packages' } else { $system_pkgs_flag = '' } + if versioncmp($normalized_python_version, '3.6') >=0 and $prompt { + $prompt_arg = "--prompt ${shell_escape($prompt)}" + } else { + $prompt_arg = '' + } + file { $venv_dir: - ensure => directory, - owner => $owner, - group => $group, - mode => $mode, + ensure => directory, + owner => $owner, + group => $group, + mode => $mode, + require => Class['python::install'], + } + + $pip_cmd = "${python::exec_prefix}${venv_dir}/bin/pip" + + $pip_upgrade = ($pip_version != 'latest') ? { + true => "--upgrade 'pip ${pip_version}'", + false => '--upgrade pip', } exec { "python_virtualenv_${venv_dir}": - command => "${virtualenv_cmd} --clear ${system_pkgs_flag} ${venv_dir}", + command => "${virtualenv_cmd} --clear ${system_pkgs_flag} ${prompt_arg} ${venv_dir} && ${pip_cmd} install ${pip_upgrade} && ${pip_cmd} install --upgrade setuptools", user => $owner, creates => "${venv_dir}/bin/activate", path => $_path, cwd => '/tmp', environment => $environment, + timeout => 600, unless => "grep '^[\\t ]*VIRTUAL_ENV=[\\\\'\\\"]*${venv_dir}[\\\"\\\\'][\\t ]*$' ${venv_dir}/bin/activate", #Unless activate exists and VIRTUAL_ENV is correct we re-create the virtualenv require => File[$venv_dir], } diff --git a/manifests/requirements.pp b/manifests/requirements.pp index 7d2a54a9..374a70ae 100644 --- a/manifests/requirements.pp +++ b/manifests/requirements.pp @@ -10,7 +10,7 @@ # @param src Pip --src parameter to; if the requirements file contains --editable resources, this parameter specifies where they will be installed. See the pip documentation for more. # @param environment Additional environment variables required to install the packages. # @param forceupdate Run a pip install requirements even if we don't receive an event from the requirements file - Useful for when the requirements file is written as part of a resource other than file (E.g vcsrepo) -# @param cwd The directory from which to run the "pip install" command. +# @param cwd The directory from which to run the "pip install" command. # @param extra_pip_args Extra arguments to pass to pip after the requirements file # @param manage_requirements Create the requirements file if it doesn't exist. # @param fix_requirements_owner Change owner and group of requirements file. @@ -26,23 +26,22 @@ # } # define python::requirements ( - $requirements = $name, - $virtualenv = 'system', - Enum['pip', 'pip3'] $pip_provider = 'pip', - $owner = 'root', - $group = 'root', - $proxy = false, - $src = false, - $environment = [], - $forceupdate = false, - $cwd = undef, - $extra_pip_args = '', - $manage_requirements = true, - $fix_requirements_owner = true, - $log_dir = '/tmp', - $timeout = 1800, + Stdlib::Absolutepath $requirements = $name, + Variant[Enum['system'],Stdlib::Absolutepath] $virtualenv = 'system', + Enum['pip', 'pip3'] $pip_provider = 'pip', + String[1] $owner = 'root', + String[1] $group = 'root', + Optional[Stdlib::HTTPUrl] $proxy = undef, + Any $src = false, + Array $environment = [], + Boolean $forceupdate = false, + Optional[Stdlib::Absolutepath] $cwd = undef, + Optional[String[1]] $extra_pip_args = undef, + Boolean $manage_requirements = true, + Boolean $fix_requirements_owner = true, + Stdlib::Absolutepath $log_dir = '/tmp', + Integer $timeout = 1800, ) { - include python if $virtualenv == 'system' and ($owner != 'root' or $group != 'root') { @@ -63,13 +62,13 @@ } $pip_env = $virtualenv ? { - 'system' => "${::python::exec_prefix} ${pip_provider}", - default => "${::python::exec_prefix} ${virtualenv}/bin/${pip_provider}", + 'system' => "${python::exec_prefix} ${pip_provider}", + default => "${python::exec_prefix} ${virtualenv}/bin/${pip_provider}", } $proxy_flag = $proxy ? { - false => '', - default => "--proxy=${proxy}", + undef => '', + default => "--proxy=${proxy}", } $src_flag = $src ? { @@ -81,7 +80,7 @@ # the same requirements file. if !defined(File[$requirements]) and $manage_requirements == true { file { $requirements: - ensure => present, + ensure => file, mode => '0644', owner => $owner_real, group => $group_real, @@ -89,19 +88,22 @@ replace => false, content => '# Puppet will install and/or update pip packages listed here', } - $subscribe = File[$requirements] + + $local_subscribe = File[$requirements] + } elsif File[$requirements] and $manage_requirements == true { + $local_subscribe = File[$requirements] } else { - $subscribe = undef + $local_subscribe = undef } exec { "python_requirements${name}": provider => shell, - command => "${pip_env} --log ${log}/pip.log install ${proxy_flag} ${src_flag} -r ${requirements} ${extra_pip_args}", + command => "${pip_env} install ${proxy_flag} ${src_flag} -r ${requirements} ${extra_pip_args}", refreshonly => !$forceupdate, timeout => $timeout, cwd => $cwd, user => $owner, - subscribe => $subscribe, + subscribe => $local_subscribe, environment => $environment, } } diff --git a/manifests/virtualenv.pp b/manifests/virtualenv.pp deleted file mode 100644 index 48885c56..00000000 --- a/manifests/virtualenv.pp +++ /dev/null @@ -1,177 +0,0 @@ -# -# @summary Creates Python virtualenv. -# -# @param ensure -# @param version Python version to use. -# @param requirements Path to pip requirements.txt file -# @param systempkgs Copy system site-packages into virtualenv. -# @param venv_dir Directory to install virtualenv to -# @param ensure_venv_dir Create $venv_dir -# @param distribute Include distribute in the virtualenv -# @param index Base URL of Python package index -# @param owner The owner of the virtualenv being manipulated -# @param group The group relating to the virtualenv being manipulated -# @param mode Optionally specify directory mode -# @param proxy Proxy server to use for outbound connections -# @param environment Additional environment variables required to install the packages -# @param path Specifies the PATH variable -# @param cwd The directory from which to run the "pip install" command -# @param timeout The maximum time in seconds the "pip install" command should take -# @param pip_args Arguments to pass to pip during initialization -# @param extra_pip_args Extra arguments to pass to pip after requirements file -# -# @example install a virtual env at /var/www/project1 -# python::virtualenv { '/var/www/project1': -# ensure => present, -# version => 'system', -# requirements => '/var/www/project1/requirements.txt', -# proxy => 'http://proxy.domain.com:3128', -# systempkgs => true, -# index => 'http://www.example.com/simple/', -# } -# -define python::virtualenv ( - $ensure = present, - $version = 'system', - $requirements = false, - $systempkgs = false, - $venv_dir = $name, - $ensure_venv_dir = true, - $distribute = true, - $index = false, - $owner = 'root', - $group = 'root', - $mode = '0755', - $proxy = false, - $environment = [], - $path = [ '/bin', '/usr/bin', '/usr/sbin', '/usr/local/bin' ], - $cwd = undef, - $timeout = 1800, - $pip_args = '', - $extra_pip_args = '', - $virtualenv = undef -) { - include python - $python_provider = getparam(Class['python'], 'provider') - $anaconda_path = getparam(Class['python'], 'anaconda_install_path') - - if $ensure == 'present' { - $python = $version ? { - 'system' => 'python', - 'pypy' => 'pypy', - default => "python${version}", - } - - $_path = $python_provider ? { - 'anaconda' => concat(["${anaconda_path}/bin"], $path), - default => $path, - } - - if $virtualenv == undef { - $used_virtualenv = 'virtualenv' - } else { - $used_virtualenv = $virtualenv - } - - $proxy_flag = $proxy ? { - false => '', - default => "--proxy=${proxy}", - } - - $proxy_command = $proxy ? { - false => '', - default => "&& export http_proxy=${proxy}", - } - - # Virtualenv versions prior to 1.7 do not support the - # --system-site-packages flag, default off for prior versions - # Prior to version 1.7 the default was equal to --system-site-packages - # and the flag --no-site-packages had to be passed to do the opposite - $_virtualenv_version = getvar('virtualenv_version') ? { - /.*/ => getvar('virtualenv_version'), - default => '', - } - if (( versioncmp($_virtualenv_version,'1.7') > 0 ) and ( $systempkgs == true )) { - $system_pkgs_flag = '--system-site-packages' - } elsif (( versioncmp($_virtualenv_version,'1.7') < 0 ) and ( $systempkgs == false )) { - $system_pkgs_flag = '--no-site-packages' - } else { - $system_pkgs_flag = $systempkgs ? { - true => '--system-site-packages', - false => '--no-site-packages', - default => fail('Invalid value for systempkgs. Boolean value is expected') - } - } - - $distribute_pkg = $distribute ? { - true => 'distribute', - default => 'setuptools', - } - $pypi_index = $index ? { - false => '', - default => "-i ${index}", - } - - # Python 2.6 and older does not support setuptools/distribute > 0.8 which - # is required for pip wheel support, pip therefor requires --no-use-wheel flag - # if the # pip version is more recent than 1.4.1 but using an old python or - # setuputils/distribute version - # To check for this we test for wheel parameter using help and then using - # version, this makes sure we only use wheels if they are supported - - if $ensure_venv_dir { - file { $venv_dir: - ensure => directory, - owner => $owner, - group => $group, - mode => $mode, - } - } - - $virtualenv_cmd = "${python::exec_prefix}${used_virtualenv}" - - $pip_cmd = "${python::exec_prefix}${venv_dir}/bin/pip" - $pip_flags = "${pypi_index} ${proxy_flag} ${pip_args}" - - exec { "python_virtualenv_${venv_dir}": - command => "true ${proxy_command} && ${virtualenv_cmd} ${system_pkgs_flag} -p ${python} ${venv_dir} && ${pip_cmd} --log ${venv_dir}/pip.log install ${pip_flags} --upgrade pip && ${pip_cmd} install ${pip_flags} --upgrade ${distribute_pkg}", - user => $owner, - creates => "${venv_dir}/bin/activate", - path => $_path, - cwd => '/tmp', - environment => $environment, - unless => "grep '^[\\t ]*VIRTUAL_ENV=[\\\\'\\\"]*${venv_dir}[\\\"\\\\'][\\t ]*$' ${venv_dir}/bin/activate", #Unless activate exists and VIRTUAL_ENV is correct we re-create the virtualenv - require => File[$venv_dir], - } - - if $requirements { - exec { "python_requirements_initial_install_${requirements}_${venv_dir}": - command => "${pip_cmd} --log ${venv_dir}/pip.log install ${pypi_index} ${proxy_flag} --no-binary :all: -r ${requirements} ${extra_pip_args}", - refreshonly => true, - timeout => $timeout, - user => $owner, - subscribe => Exec["python_virtualenv_${venv_dir}"], - environment => $environment, - cwd => $cwd, - } - - python::requirements { "${requirements}_${venv_dir}": - requirements => $requirements, - virtualenv => $venv_dir, - proxy => $proxy, - owner => $owner, - group => $group, - cwd => $cwd, - require => Exec["python_virtualenv_${venv_dir}"], - extra_pip_args => $extra_pip_args, - } - } - } elsif $ensure == 'absent' { - file { $venv_dir: - ensure => absent, - force => true, - recurse => true, - purge => true, - } - } -} diff --git a/metadata.json b/metadata.json index 53705035..9cd44130 100644 --- a/metadata.json +++ b/metadata.json @@ -1,17 +1,15 @@ { "name": "puppet-python", - "version": "2.2.3-rc0", + "version": "9.0.0", "author": "Vox Pupuli", - "summary": "Python Module", + "summary": "Puppet module for Python", "license": "Apache-2.0", - "source": "git://github.com/voxpupuli/puppet-python.git", + "source": "https://github.com/voxpupuli/puppet-python.git", "project_page": "https://github.com/voxpupuli/puppet-python", "issues_url": "https://github.com/voxpupuli/puppet-python/issues", - "description": "Puppet module for Python", "tags": [ "python", "pip", - "virtualenv", "gunicorn" ], "operatingsystem_support": [ @@ -22,18 +20,32 @@ "7100-05-03-1837" ] }, + { + "operatingsystem": "AlmaLinux", + "operatingsystemrelease": [ + "8", + "9" + ] + }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ - "6", - "7" + "9" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ - "8", - "9" + "11", + "12", + "13" + ] + }, + { + "operatingsystem": "FreeBSD", + "operatingsystemrelease": [ + "13", + "14" ] }, { @@ -42,9 +54,29 @@ { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ - "14.04", - "16.04", - "18.04" + "22.04", + "24.04" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "8", + "9" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "8", + "9" + ] + }, + { + "operatingsystem": "Rocky", + "operatingsystemrelease": [ + "8", + "9" ] }, { @@ -52,22 +84,25 @@ "operatingsystemrelease": [ "11.3" ] + }, + { + "operatingsystem": "Archlinux" } ], "requirements": [ { - "name": "puppet", - "version_requirement": ">= 5.5.8 < 7.0.0" + "name": "openvox", + "version_requirement": ">= 8.19.0 < 9.0.0" } ], "dependencies": [ { "name": "puppetlabs/stdlib", - "version_requirement": ">= 4.13.1 < 6.0.0" + "version_requirement": ">= 4.19.0 < 10.0.0" }, { - "name": "stahnma/epel", - "version_requirement": ">= 1.2.2 < 2.0.0" + "name": "puppet/epel", + "version_requirement": ">= 3.0.0 < 7.0.0" } ] } diff --git a/spec/acceptance/class_spec.rb b/spec/acceptance/class_spec.rb index c75207f1..70c573b0 100644 --- a/spec/acceptance/class_spec.rb +++ b/spec/acceptance/class_spec.rb @@ -1,16 +1,45 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' describe 'python class' do context 'default parameters' do + # Using puppet_apply as a helper + it 'works with no errors' do + pp = 'include python' + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + context 'installing python 3' do # Using puppet_apply as a helper it 'works with no errors' do pp = <<-EOS - class { 'python': } + class { 'python': + ensure => 'present', + pip => 'present', + dev => 'present', + venv => 'present', + } EOS # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end + + fact_notices = <<-EOS + notify{"pip_version: ${facts['pip3_version']}":} + notify{"python_version: ${facts['python3_version']}":} + EOS + it 'outputs python facts when not installed' do + apply_manifest(fact_notices, catch_failures: true) do |r| + expect(r.stdout).to match(%r{python_version: 3\.\S+}) + expect(r.stdout).to match(%r{pip_version: \S+}) + end + end end end diff --git a/spec/acceptance/declared_requirements_install_spec.rb b/spec/acceptance/declared_requirements_install_spec.rb new file mode 100644 index 00000000..bc9c07d4 --- /dev/null +++ b/spec/acceptance/declared_requirements_install_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +describe 'requirements' do + it 'checks declared requirements file is installed to venv' do + pp = <<-EOS + file { '/tmp/requirements.txt': + ensure => 'present', + content => 'requests', + } + + python::pyvenv { '/tmp/pyvenv': + ensure => 'present', + } + + python::requirements { '/tmp/requirements.txt': + virtualenv => '/tmp/pyvenv' + } + EOS + + apply_manifest(pp, catch_failures: true) + + expect(shell('/tmp/pyvenv/bin/pip3 list --no-index | grep requests').stdout).to match(%r{requests +\d+.\d+.\d+}) + end +end diff --git a/spec/acceptance/facts_test_spec.rb b/spec/acceptance/facts_test_spec.rb index 26b7b72e..b6393a79 100644 --- a/spec/acceptance/facts_test_spec.rb +++ b/spec/acceptance/facts_test_spec.rb @@ -1,28 +1,26 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' describe 'python class' do context 'facts' do install_python = <<-EOS class { 'python' : - version => 'system', pip => 'present', - virtualenv => 'present', } - EOS + EOS fact_notices = <<-EOS - notify{"pip_version: ${::pip_version}":} - notify{"system_python_version: ${::system_python_version}":} - notify{"python_version: ${::python_version}":} - notify{"virtualenv_version: ${::virtualenv_version}":} - EOS + notify{"pip_version: ${facts['pip_version']}":} + notify{"system_python_version: ${facts['system_python_version']}":} + notify{"python_version: ${facts['python_version']}":} + EOS # rubocop:disable RSpec/RepeatedExample - it 'outputs python facts when not installed' do # rubocop:disable RSpec/MultipleExpectations + it 'outputs python facts when not installed' do apply_manifest(fact_notices, catch_failures: true) do |r| expect(r.stdout).to match(%r{python_version: \S+}) expect(r.stdout).to match(%r{pip_version: \S+}) - expect(r.stdout).to match(%r{virtualenv_version: \S+}) expect(r.stdout).to match(%r{system_python_version: \S+}) end end @@ -31,11 +29,10 @@ class { 'python' : apply_manifest(install_python, catch_failures: true) end - it 'outputs python facts when installed' do # rubocop:disable RSpec/MultipleExpectations + it 'outputs python facts when installed' do apply_manifest(fact_notices, catch_failures: true) do |r| expect(r.stdout).to match(%r{python_version: \S+}) expect(r.stdout).to match(%r{pip_version: \S+}) - expect(r.stdout).to match(%r{virtualenv_version: \S+}) expect(r.stdout).to match(%r{system_python_version: \S+}) end end 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/centos-59-x64.yml b/spec/acceptance/nodesets/centos-59-x64.yml deleted file mode 100644 index 2ad90b86..00000000 --- a/spec/acceptance/nodesets/centos-59-x64.yml +++ /dev/null @@ -1,10 +0,0 @@ -HOSTS: - centos-59-x64: - roles: - - master - platform: el-5-x86_64 - box : centos-59-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box - hypervisor : vagrant -CONFIG: - type: git diff --git a/spec/acceptance/nodesets/centos-64-x64-pe.yml b/spec/acceptance/nodesets/centos-64-x64-pe.yml deleted file mode 100644 index 7d9242f1..00000000 --- a/spec/acceptance/nodesets/centos-64-x64-pe.yml +++ /dev/null @@ -1,12 +0,0 @@ -HOSTS: - centos-64-x64: - roles: - - master - - database - - dashboard - platform: el-6-x86_64 - box : centos-64-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box - hypervisor : vagrant -CONFIG: - type: pe diff --git a/spec/acceptance/nodesets/centos-65-x64.yml b/spec/acceptance/nodesets/centos-65-x64.yml deleted file mode 100644 index 4e2cb809..00000000 --- a/spec/acceptance/nodesets/centos-65-x64.yml +++ /dev/null @@ -1,10 +0,0 @@ -HOSTS: - centos-65-x64: - roles: - - master - platform: el-6-x86_64 - box : centos-65-x64-vbox436-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box - hypervisor : vagrant -CONFIG: - type: foss diff --git a/spec/acceptance/nodesets/debian-70rc1-x64.yml b/spec/acceptance/nodesets/debian-70rc1-x64.yml deleted file mode 100644 index 4b55677f..00000000 --- a/spec/acceptance/nodesets/debian-70rc1-x64.yml +++ /dev/null @@ -1,10 +0,0 @@ -HOSTS: - debian-70rc1-x64: - roles: - - master - platform: debian-70rc1-x64 - box : debian-70rc1-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box - hypervisor : vagrant -CONFIG: - type: foss diff --git a/spec/acceptance/nodesets/debian-73-x64.yml b/spec/acceptance/nodesets/debian-73-x64.yml deleted file mode 100644 index d7143455..00000000 --- a/spec/acceptance/nodesets/debian-73-x64.yml +++ /dev/null @@ -1,11 +0,0 @@ -HOSTS: - debian-73-x64: - roles: - - master - platform: debian-7-amd64 - box : debian-73-x64-virtualbox-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box - hypervisor : vagrant -CONFIG: - log_level: debug - type: git \ No newline at end of file diff --git a/spec/acceptance/nodesets/default.yml b/spec/acceptance/nodesets/default.yml deleted file mode 100644 index 45af9893..00000000 --- a/spec/acceptance/nodesets/default.yml +++ /dev/null @@ -1,11 +0,0 @@ -HOSTS: - ubuntu-server-12042-x64: - roles: - - master - platform: ubuntu-server-12.04-amd64 - box : ubuntu-server-12042-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box - hypervisor : vagrant -CONFIG: - type: foss - vagrant_ssh_port_random: true 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/acceptance/nodesets/ubuntu-server-10044-x64.yml b/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml deleted file mode 100644 index 5ca1514e..00000000 --- a/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml +++ /dev/null @@ -1,10 +0,0 @@ -HOSTS: - ubuntu-server-10044-x64: - roles: - - master - platform: ubuntu-10.04-amd64 - box : ubuntu-server-10044-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box - hypervisor : vagrant -CONFIG: - type: foss diff --git a/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml b/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml deleted file mode 100644 index d065b304..00000000 --- a/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml +++ /dev/null @@ -1,10 +0,0 @@ -HOSTS: - ubuntu-server-12042-x64: - roles: - - master - platform: ubuntu-12.04-amd64 - box : ubuntu-server-12042-x64-vbox4210-nocm - box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box - hypervisor : vagrant -CONFIG: - type: foss diff --git a/spec/acceptance/pip_spec.rb b/spec/acceptance/pip_spec.rb new file mode 100644 index 00000000..83a639fa --- /dev/null +++ b/spec/acceptance/pip_spec.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +describe 'python::pip defined resource' do + context 'install package with custom name' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + } + + python::pyvenv { '/opt/test-venv': + ensure => 'present', + systempkgs => false, + mode => '0755', + } + + python::pip { 'agent package': + virtualenv => '/opt/test-venv', + pkgname => 'agent', + ensure => '0.1.2', + } + PUPPET + + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + # rubocop:disable RSpec/RepeatedExampleGroupDescription + # rubocop:disable RSpec/RepeatedExampleGroupBody + describe command('/opt/test-venv/bin/pip list') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{agent.* 0\.1\.2} } + end + + context 'uninstall package with custom name' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + } + + python::pyvenv { '/opt/test-venv': + ensure => 'present', + systempkgs => false, + mode => '0755', + } + + python::pip { 'agent package install': + ensure => '0.1.2', + pkgname => 'agent', + virtualenv => '/opt/test-venv', + } + + python::pip { 'agent package uninstall custom pkgname': + ensure => 'absent', + pkgname => 'agent', + virtualenv => '/opt/test-venv', + require => Python::Pip['agent package install'], + } + + PUPPET + + apply_manifest(pp, catch_failures: true) + end + end + + describe command('/opt/test-venv/bin/pip list') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.not_to match %r{agent.* 0\.1\.2} } + end + + context 'fails to install package with wrong version' do + it 'throws an error' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + } + + python::pyvenv { '/opt/test-venv': + ensure => 'present', + systempkgs => false, + mode => '0755', + } + + python::pip { 'agent package': + virtualenv => '/opt/test-venv', + pkgname => 'agent', + ensure => '0.1.33+2020-this_is_something-fun', + } + PUPPET + + result = apply_manifest(pp, expect_failures: true) + expect(result.stderr).to contain(%r{returned 1 instead of one of}) + end + end + + describe command('/opt/test-venv/bin/pip show agent') do + its(:exit_status) { is_expected.to eq 1 } + end + + context 'install package via extra_index' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + } + + python::pyvenv { '/opt/test-venv': + ensure => 'present', + systempkgs => false, + mode => '0755', + } + + python::pip { 'agent package via extra_index': + virtualenv => '/opt/test-venv', + pkgname => 'agent', + index => 'invalid', + extra_index => 'https://pypi.org/simple', + ensure => '0.1.2', + } + PUPPET + + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + describe command('/opt/test-venv/bin/pip list') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{agent.* 0\.1\.2} } + end + # rubocop:enable RSpec/RepeatedExampleGroupBody + # rubocop:enable RSpec/RepeatedExampleGroupDescription +end diff --git a/spec/acceptance/pyvenv_spec.rb b/spec/acceptance/pyvenv_spec.rb new file mode 100644 index 00000000..263e4a40 --- /dev/null +++ b/spec/acceptance/pyvenv_spec.rb @@ -0,0 +1,238 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +describe 'python::pyvenv defined resource with python 3' do + context 'minimal parameters' do + # Using puppet_apply as a helper + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + venv => 'present', + } + user { 'agent': + ensure => 'present', + managehome => true, + home => '/opt/agent', + } + group { 'agent': + ensure => 'present', + system => true, + } + python::pyvenv { '/opt/agent/venv': + ensure => 'present', + systempkgs => true, + owner => 'agent', + group => 'agent', + mode => '0755', + } + PUPPET + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + context 'with python::pip' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + venv => 'present', + } + user { 'agent': + ensure => 'present', + managehome => true, + home => '/opt/agent', + } + group { 'agent': + ensure => 'present', + system => true, + } + python::pyvenv { '/opt/agent/venv': + ensure => 'present', + systempkgs => true, + owner => 'agent', + group => 'agent', + mode => '0755', + } + python::pip { 'agent' : + ensure => 'latest', + pkgname => 'agent', + pip_provider => 'pip', + virtualenv => '/opt/agent/venv', + owner => 'agent', + group => 'agent', + } + PUPPET + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + context 'with minimal python::pip' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + venv => 'present', + } + user { 'agent': + ensure => 'present', + managehome => true, + home => '/opt/agent', + } + group { 'agent': + ensure => 'present', + system => true, + } + python::pyvenv { '/opt/agent/venv': + ensure => 'present', + systempkgs => true, + owner => 'agent', + group => 'agent', + mode => '0755', + } + python::pip { 'agent' : + virtualenv => '/opt/agent/venv', + owner => 'agent', + group => 'agent', + } + PUPPET + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + context 'with minimal python::pip and without systempkgs' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + venv => 'present', + } + user { 'agent': + ensure => 'present', + managehome => true, + home => '/opt/agent', + } + group { 'agent': + ensure => 'present', + system => true, + } + python::pyvenv { '/opt/agent/venv': + ensure => 'present', + systempkgs => false, + owner => 'agent', + group => 'agent', + mode => '0755', + } + python::pip { 'agent' : + virtualenv => '/opt/agent/venv', + owner => 'agent', + group => 'agent', + } + PUPPET + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + end + + context 'with versioned minimal python::pip and without systempkgs' do + it 'works with no errors' do + pp = <<-PUPPET + class { 'python': + dev => 'present', + venv => 'present', + } + user { 'agent': + ensure => 'present', + managehome => true, + home => '/opt/agent', + } + group { 'agent': + ensure => 'present', + system => true, + } + python::pyvenv { '/opt/agent/venv': + ensure => 'present', + systempkgs => false, + owner => 'agent', + group => 'agent', + mode => '0755', + } + python::pip { 'agent' : + ensure => '0.1.2', + virtualenv => '/opt/agent/venv', + owner => 'agent', + group => 'agent', + } + PUPPET + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + + describe command('/opt/agent/venv/bin/pip list') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{agent.* 0\.1\.2} } + end + end + + context 'with versioned minimal python::pip and without systempkgs using custom python path' do + it 'works with no errors' do + pp = <<-PUPPET + + class { 'python': + dev => 'present', + venv => 'present', + } + file { '/usr/bin/mycustompython': + ensure => link, + target => '/usr/bin/python', + } + user { 'agent': + ensure => 'present', + managehome => true, + home => '/opt/agent', + } + group { 'agent': + ensure => 'present', + system => true, + } + python::pyvenv { '/opt/agent/venv': + ensure => 'present', + systempkgs => false, + owner => 'agent', + group => 'agent', + mode => '0755', + python_path => '/usr/bin/mycustompython', + } + python::pip { 'agent' : + ensure => '0.1.2', + virtualenv => '/opt/agent/venv', + owner => 'agent', + group => 'agent', + } + PUPPET + + # Run it twice and test for idempotency + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + + describe command('/opt/agent/venv/bin/pip list') do + its(:exit_status) { is_expected.to eq 0 } + its(:stdout) { is_expected.to match %r{agent.* 0\.1\.2} } + end + end +end diff --git a/spec/acceptance/virtualenv_spec.rb b/spec/acceptance/virtualenv_spec.rb deleted file mode 100644 index 4e4e4529..00000000 --- a/spec/acceptance/virtualenv_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -require 'spec_helper_acceptance' - -describe 'python class' do - context 'default parameters' do - # Using puppet_apply as a helper - it 'works with no errors' do - pp = <<-EOS - class { 'python' : - version => 'system', - pip => 'present', - virtualenv => 'present', - } - -> - python::virtualenv { 'venv' : - ensure => 'present', - systempkgs => false, - venv_dir => '/opt/venv', - owner => 'root', - group => 'root', - } - -> - python::pip { 'rpyc' : - ensure => '3.2.3', - virtualenv => '/opt/venv', - } - EOS - - # Run it twice and test for idempotency - apply_manifest(pp, catch_failures: true) - apply_manifest(pp, catch_changes: true) - end - it 'maintains pip version' do - pp = <<-EOS - class { 'python' : - version => 'system', - pip => 'present', - virtualenv => 'present', - } - -> - python::virtualenv { 'venv' : - ensure => 'present', - systempkgs => false, - venv_dir => '/opt/venv2', - owner => 'root', - group => 'root', - } - -> - python::pip { 'pip' : - ensure => '18.0', - virtualenv => '/opt/venv2', - } - EOS - - # Run it twice and test for idempotency - apply_manifest(pp, catch_failures: true) - apply_manifest(pp, catch_changes: true) - end - it 'works with ensure=>latest' do - pp = <<-EOS - class { 'python' : - version => 'system', - pip => 'present', - virtualenv => 'present', - } - -> - python::virtualenv { 'venv' : - ensure => 'present', - systempkgs => false, - venv_dir => '/opt/venv3', - owner => 'root', - group => 'root', - } - -> - python::pip { 'rpyc' : - ensure => 'latest', - virtualenv => '/opt/venv3', - } - EOS - - # Run it twice and test for idempotency - apply_manifest(pp, catch_failures: true) - # Of course this test will fail if between the applies a new version of the package will be released, - # but probability of this happening is minimal, so it should be acceptable. - apply_manifest(pp, catch_changes: true) - end - it 'works with ensure=>latest for package with underscore in its name' do - pp = <<-EOS - class { 'python' : - version => 'system', - pip => 'present', - virtualenv => 'present', - } - -> - python::virtualenv { 'venv' : - ensure => 'present', - systempkgs => false, - venv_dir => '/opt/venv4', - owner => 'root', - group => 'root', - } - -> - python::pip { 'Randomized_Requests' : - ensure => 'latest', - virtualenv => '/opt/venv4', - } - EOS - - # Run it twice and test for idempotency - apply_manifest(pp, catch_failures: true) - # Of course this test will fail if between the applies a new version of the package will be released, - # but probability of this happening is minimal, so it should be acceptable. - apply_manifest(pp, catch_changes: true) - end - end -end diff --git a/spec/classes/python_spec.rb b/spec/classes/python_spec.rb index 208462ca..f1c2d9a1 100644 --- a/spec/classes/python_spec.rb +++ b/spec/classes/python_spec.rb @@ -1,12 +1,68 @@ -require 'spec_helper' +# frozen_string_literal: true -describe 'python', type: :class do +require 'spec_helper' +describe 'python' do on_supported_os.each do |os, facts| - context "on #{os} " do + next if os == 'gentoo-3-x86_64' + + context "on #{os}" do let :facts do facts end + context 'with defaults' do + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('python::install') } + it { is_expected.to contain_class('python::params') } + it { is_expected.to contain_class('python::config') } + it { is_expected.to contain_package('python') } + + if facts[:os]['family'] == 'Archlinux' + it { is_expected.not_to contain_package('pip') } + else + it { is_expected.to contain_package('pip') } + end + + if %w[Archlinux RedHat].include?(facts[:os]['family']) + it { is_expected.not_to contain_package('python-venv') } + else + it { is_expected.to contain_package('python-venv') } + end + end + + context 'without managing things' do + let :params do + { + manage_python_package: false, + manage_dev_package: false, + manage_pip_package: false, + manage_venv_package: false, + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.not_to contain_package('python') } + it { is_expected.not_to contain_package('python-dev') } + it { is_expected.not_to contain_package('pip') } + it { is_expected.not_to contain_package('python-venv') } + end + + context 'with packages present' do + let :params do + { + manage_pip_package: true, + manage_venv_package: true, + pip: 'present', + venv: 'present', + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_package('pip').with(ensure: 'present') } + + it { is_expected.to contain_package('python-venv').with(ensure: 'present') } unless facts[:os]['family'] == 'RedHat' + end + case facts[:os]['family'] when 'Debian' @@ -17,41 +73,144 @@ it { is_expected.to contain_package('python') } it { is_expected.to contain_package('python-dev') } it { is_expected.to contain_package('pip') } - # Basic python packages (from pip) - it { is_expected.to contain_package('virtualenv') } + describe 'with python::version' do + context 'python3.7' do + let(:params) { { version: 'python3.7' } } + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_package('pip').with_name('python3.7-pip') } + it { is_expected.to contain_package('python').with_name('python3.7') } + it { is_expected.to contain_package('python-dev').with_name('python3.7-dev') } + end + end + + # rubocop:disable RSpec/RepeatedExampleGroupDescription describe 'with python::dev' do context 'true' do let(:params) { { dev: 'present' } } + it { is_expected.to compile.with_all_deps } it { is_expected.to contain_package('python-dev').with_ensure('present') } end + context 'empty/default' do + it { is_expected.to compile.with_all_deps } it { is_expected.to contain_package('python-dev').with_ensure('absent') } end end - describe 'with python::virtualenv, without python::dev' do - context 'true' do - let(:params) { { dev: 'absent', virtualenv: 'present' } } - - it { is_expected.to contain_package('python-dev').with_ensure('present') } - end + describe 'without python::dev' do context 'empty/default' do it { is_expected.to contain_package('python-dev').with_ensure('absent') } end end + describe 'with python::python_pyvenvs' do + context 'with two pyenvs' do + let(:params) do + { + python_pyvenvs: { + '/opt/env1' => { + version: '3.8', + }, + '/opt/env2' => { + version: '3.8', + }, + }, + } + end + + it { is_expected.to compile } + + it { is_expected.to contain_python__pyvenv('/opt/env1').with_ensure('present') } + it { is_expected.to contain_python__pyvenv('/opt/env2').with_ensure('present') } + it { is_expected.to contain_exec('python_virtualenv_/opt/env1') } + it { is_expected.to contain_exec('python_virtualenv_/opt/env2') } + it { is_expected.to contain_file('/opt/env1') } + it { is_expected.to contain_file('/opt/env2') } + end + end + + describe 'with python::python_pyvenvs and pip version defined' do + context 'with two pyenvs' do + let(:params) do + { + python_pyvenvs: { + '/opt/env1' => { + version: '3.8', + pip_version: 'latest', + }, + '/opt/env2' => { + version: '3.8', + pip_version: '<= 20.3.4', + }, + }, + } + end + + it { is_expected.to compile } + + it { is_expected.to contain_python__pyvenv('/opt/env1').with_ensure('present') } + it { is_expected.to contain_python__pyvenv('/opt/env2').with_ensure('present') } + + it { + expect(subject).to contain_exec('python_virtualenv_/opt/env1') + .with( + command: 'python3.8 -m venv --clear /opt/env1 && /opt/env1/bin/pip install --upgrade pip && /opt/env1/bin/pip install --upgrade setuptools', + user: 'root', + creates: '/opt/env1/bin/activate', + path: [ + '/bin', + '/usr/bin', + '/usr/sbin', + '/usr/local/bin', + ], + cwd: '/tmp', + environment: [], + timeout: 600, + unless: %r{^grep '\^\[\\t \]\*VIRTUAL_ENV=\[\\\\'\\"\]\*/opt/env1\[\\"\\\\'\]\[\\t \]\*\$' /opt/env1/bin/activate$}, + ) + .that_requires('File[/opt/env1]') + } + + it { + expect(subject).to contain_exec('python_virtualenv_/opt/env2') + .with( + command: 'python3.8 -m venv --clear /opt/env2 && /opt/env2/bin/pip install --upgrade \'pip <= 20.3.4\' && /opt/env2/bin/pip install --upgrade setuptools', + user: 'root', + creates: '/opt/env2/bin/activate', + path: [ + '/bin', + '/usr/bin', + '/usr/sbin', + '/usr/local/bin', + ], + cwd: '/tmp', + environment: [], + timeout: 600, + unless: %r{^grep '\^\[\\t \]\*VIRTUAL_ENV=\[\\\\'\\"\]\*/opt/env2\[\\"\\\\'\]\[\\t \]\*\$' /opt/env2/bin/activate$}, + ) + .that_requires('File[/opt/env2]') + } + + it { is_expected.to contain_file('/opt/env1') } + it { is_expected.to contain_file('/opt/env2') } + end + end + describe 'with manage_gunicorn' do context 'true' do let(:params) { { manage_gunicorn: true } } it { is_expected.to contain_package('gunicorn') } end + context 'empty args' do # let(:params) {{ :manage_gunicorn => '' }} it { is_expected.to contain_package('gunicorn') } end + context 'false' do let(:params) { { manage_gunicorn: false } } @@ -63,40 +222,14 @@ context 'pip' do let(:params) { { pip: 'present', provider: 'pip' } } - it { - is_expected.to contain_package('virtualenv').with( - 'provider' => 'pip' - ) - } - it { - is_expected.to contain_package('pip').with( - 'provider' => 'pip' - ) - } + it { is_expected.to contain_package('pip').with('provider' => 'pip') } end # python::provider context 'default' do let(:params) { { provider: '' } } - it { is_expected.to contain_package('virtualenv') } it { is_expected.to contain_package('pip') } - - describe 'with python::virtualenv' do - context 'true' do - let(:params) { { provider: '', virtualenv: 'present' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('present') } - end - end - - describe 'without python::virtualenv' do - context 'default/empty' do - let(:params) { { provider: '' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('absent') } - end - end end end @@ -106,6 +239,7 @@ it { is_expected.to contain_package('python-dev').with_ensure('present') } end + context 'default/empty' do it { is_expected.to contain_package('python-dev').with_ensure('absent') } end @@ -131,33 +265,19 @@ end when 'RedHat', 'CentOS' case facts[:os]['release']['major'] - when '5' - # written for RHEL 5 - context 'on a Redhat OS' do + when '8' + context 'on a Redhat 8 OS' do it { is_expected.to contain_class('python::install') } - # Base debian packages. - it { is_expected.to contain_package('python') } - it { is_expected.to contain_package('python-dev').with_name('python-devel') } - it { is_expected.to contain_package('python-dev').with_alias('python-devel') } - it { is_expected.to contain_package('pip') } - it { is_expected.to contain_package('pip').with_name('python-pip') } - # Basic python packages (from pip) - it { is_expected.to contain_package('virtualenv') } - - describe 'EPEL may be needed on EL' do - context 'default/empty' do - it { is_expected.to contain_class('epel') } - end - end + it { is_expected.to contain_package('pip').with_name('python3-pip') } - describe 'with python::dev' do - context 'true' do - let(:params) { { dev: 'present' } } + describe 'with python::version' do + context 'python36' do + let(:params) { { version: 'python36' } } - it { is_expected.to contain_package('python-dev').with_ensure('present') } - end - context 'empty/default' do - it { is_expected.to contain_package('python-dev').with_ensure('absent') } + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_package('pip').with_name('python36-pip') } + it { is_expected.to contain_package('python').with_name('python36') } + it { is_expected.to contain_package('python-dev').with_name('python36-devel') } end end @@ -165,87 +285,21 @@ context 'true' do let(:params) { { manage_gunicorn: true } } - it { is_expected.to contain_package('gunicorn') } + it { is_expected.to contain_package('gunicorn').with_name('python3-gunicorn') } end + context 'empty args' do # let(:params) {{ :manage_gunicorn => '' }} - it { is_expected.to contain_package('gunicorn') } + it { is_expected.to contain_package('gunicorn').with_name('python3-gunicorn') } end + context 'false' do let(:params) { { manage_gunicorn: false } } - it { is_expected.not_to contain_package('gunicorn') } + it { is_expected.not_to contain_package('gunicorn').with_name('python3-gunicorn') } end end - describe 'with python::provider' do - context 'pip' do - let(:params) { { provider: 'pip' } } - - it { - is_expected.to contain_package('virtualenv').with( - 'provider' => 'pip' - ) - } - it { - is_expected.to contain_package('pip').with( - 'provider' => 'pip' - ) - } - end - - context 'anaconda' do - let(:params) { { provider: 'anaconda', anaconda_install_path: '/opt/test_path' } } - - it { - is_expected.to contain_file('/var/tmp/anaconda_installer.sh') - is_expected.to contain_exec('install_anaconda_python').with_command('/var/tmp/anaconda_installer -b -p /opt/test_path') - is_expected.to contain_exec('install_anaconda_virtualenv').with_command('/opt/test_path/bin/pip install virtualenv') - } - end - - # python::provider - context 'default' do - let(:params) { { provider: '' } } - - it { is_expected.to contain_package('virtualenv') } - it { is_expected.to contain_package('pip') } - - describe 'with python::virtualenv' do - context 'true' do - let(:params) { { provider: '', virtualenv: 'present' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('present') } - end - end - - describe 'with python::virtualenv' do - context 'default/empty' do - let(:params) { { provider: '' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('absent') } - end - end - end - end - - describe 'with python::dev' do - context 'true' do - let(:params) { { dev: 'present' } } - - it { is_expected.to contain_package('python-dev').with_ensure('present') } - end - context 'default/empty' do - it { is_expected.to contain_package('python-dev').with_ensure('absent') } - end - end - end - when '6' - - context 'on a Redhat 6 OS' do - it { is_expected.to contain_class('python::install') } - it { is_expected.to contain_package('pip').with_name('python-pip') } - describe 'with python::provider' do context 'scl' do describe 'with version' do @@ -254,50 +308,14 @@ it { is_expected.to compile.with_all_deps } end - context '3.6 SCL python package' do - let(:params) { { version: 'rh-python36-python' } } - - it { is_expected.to compile.with_all_deps } - end - end - describe 'with manage_scl' do - context 'true' do - let(:params) { { provider: 'scl', manage_scl: true } } - - it { is_expected.to contain_package('centos-release-scl') } - it { is_expected.to contain_package('scl-utils') } - end - context 'false' do - let(:params) { { provider: 'scl', manage_scl: false } } - - it { is_expected.not_to contain_package('centos-release-scl') } - it { is_expected.not_to contain_package('scl-utils') } - end - end - end - end - end - - when '7' - - context 'on a Redhat 7 OS' do - it { is_expected.to contain_class('python::install') } - it { is_expected.to contain_package('pip').with_name('python2-pip') } - - describe 'with python::provider' do - context 'scl' do - describe 'with version' do - context '3.6 SCL meta package' do - let(:params) { { version: 'rh-python36' } } - it { is_expected.to compile.with_all_deps } - end context '3.6 SCL python package' do let(:params) { { version: 'rh-python36-python' } } it { is_expected.to compile.with_all_deps } end end + describe 'with manage_scl' do context 'true' do let(:params) { { provider: 'scl', manage_scl: true } } @@ -305,6 +323,7 @@ it { is_expected.to contain_package('centos-release-scl') } it { is_expected.to contain_package('scl-utils') } end + context 'false' do let(:params) { { provider: 'scl', manage_scl: false } } @@ -324,11 +343,9 @@ it { is_expected.to contain_class('python::install') } # Base Suse packages. it { is_expected.to contain_package('python') } - it { is_expected.to contain_package('python-dev').with_name('python-devel') } - it { is_expected.to contain_package('python-dev').with_alias('python-devel') } + it { is_expected.to contain_package('python-dev').with_name('python3-devel') } + it { is_expected.to contain_package('python-dev').with_alias('python3-devel') } it { is_expected.to contain_package('pip') } - # Basic python packages (from pip) - it { is_expected.to contain_package('virtualenv') } describe 'with python::dev' do context 'true' do @@ -336,6 +353,7 @@ it { is_expected.to contain_package('python-dev').with_ensure('present') } end + context 'empty/default' do it { is_expected.to contain_package('python-dev').with_ensure('absent') } end @@ -347,10 +365,12 @@ it { is_expected.to contain_package('gunicorn') } end + context 'empty args' do # let(:params) {{ :manage_gunicorn => '' }} it { is_expected.to contain_package('gunicorn') } end + context 'false' do let(:params) { { manage_gunicorn: false } } @@ -363,13 +383,8 @@ let(:params) { { provider: 'pip' } } it { - is_expected.to contain_package('virtualenv').with( - 'provider' => 'pip' - ) - } - it { - is_expected.to contain_package('pip').with( - 'provider' => 'pip' + expect(subject).to contain_package('pip').with( + 'provider' => 'pip', ) } end @@ -378,24 +393,7 @@ context 'default' do let(:params) { { provider: '' } } - it { is_expected.to contain_package('virtualenv') } it { is_expected.to contain_package('pip') } - - describe 'with python::virtualenv' do - context 'true' do - let(:params) { { provider: '', virtualenv: 'present' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('present') } - end - end - - describe 'with python::virtualenv' do - context 'default/empty' do - let(:params) { { provider: '' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('absent') } - end - end end end @@ -405,6 +403,7 @@ it { is_expected.to contain_package('python-dev').with_ensure('present') } end + context 'default/empty' do it { is_expected.to contain_package('python-dev').with_ensure('absent') } end @@ -422,9 +421,7 @@ it { is_expected.to contain_class('python::install') } # Base debian packages. it { is_expected.to contain_package('python') } - it { is_expected.to contain_package('pip').with('category' => 'dev-python') } - # Basic python packages (from pip) - it { is_expected.to contain_package('virtualenv') } + it { is_expected.to contain_package('pip').with('name' => 'dev-python/pip') } # Python::Dev it { is_expected.not_to contain_package('python-dev') } @@ -434,10 +431,12 @@ it { is_expected.to contain_package('gunicorn') } end + context 'empty args' do # let(:params) {{ :manage_gunicorn => '' }} it { is_expected.to contain_package('gunicorn') } end + context 'false' do let(:params) { { manage_gunicorn: false } } @@ -449,40 +448,7 @@ context 'pip' do let(:params) { { pip: 'present', provider: 'pip' } } - it { - is_expected.to contain_package('virtualenv').with( - 'provider' => 'pip' - ) - } - it { - is_expected.to contain_package('pip').with( - 'provider' => 'pip' - ) - } - end - - # python::provider - context 'default' do - let(:params) { { provider: '' } } - - it { is_expected.to contain_package('virtualenv') } - it { is_expected.to contain_package('pip') } - - describe 'with python::virtualenv' do - context 'true' do - let(:params) { { provider: '', virtualenv: 'present' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('present') } - end - end - - describe 'with python::virtualenv' do - context 'default/empty' do - let(:params) { { provider: '' } } - - it { is_expected.to contain_package('virtualenv').with_ensure('absent') } - end - end + it { is_expected.to contain_package('pip').with('provider' => 'pip') } end end end @@ -490,3 +456,4 @@ end end end +# rubocop:enable RSpec/RepeatedExampleGroupDescription diff --git a/spec/defines/dotfile_spec.rb b/spec/defines/dotfile_spec.rb index d7d469e4..a44426f7 100644 --- a/spec/defines/dotfile_spec.rb +++ b/spec/defines/dotfile_spec.rb @@ -1,42 +1,59 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'python::dotfile', type: :define do on_supported_os.each do |os, facts| - context("on #{os} ") do + context("on #{os}") do let :facts do facts end + let(:root_group) do + if facts[:os]['family'] == 'FreeBSD' + 'wheel' + else + 'root' + end + end + + let(:pre_condition) { 'include python' } + describe 'dotfile as' do context 'fails with empty string filename' do let(:title) { '' } it { is_expected.to raise_error(%r{Evaluation Error: Empty string title at 0. Title strings must have a length greater than zero.}) } end + context 'fails with incorrect mode' do let(:title) { '/etc/pip.conf' } let(:params) { { mode: 'not-a-mode' } } it { is_expected.to raise_error(%r{Evaluation Error: Error while evaluating a Resource}) } end + context 'succeeds with filename in existing path' do let(:title) { '/etc/pip.conf' } it { is_expected.to contain_file('/etc/pip.conf').with_mode('0644') } end + context 'succeeds with filename in a non-existing path' do let(:title) { '/home/someuser/.pip/pip.conf' } - it { is_expected.to contain_exec('create /home/someuser/.pip/pip.conf\'s parent dir').with_command('install -o root -g root -d /home/someuser/.pip') } + it { is_expected.to contain_exec('create /home/someuser/.pip/pip.conf\'s parent dir').with_command("install -o root -g #{root_group} -d /home/someuser/.pip") } it { is_expected.to contain_file('/home/someuser/.pip/pip.conf').with_mode('0644') } end + context 'succeeds when set owner' do let(:title) { '/home/someuser/.pip/pip.conf' } let(:params) { { owner: 'someuser' } } - it { is_expected.to contain_exec('create /home/someuser/.pip/pip.conf\'s parent dir').with_command('install -o someuser -g root -d /home/someuser/.pip') } + it { is_expected.to contain_exec('create /home/someuser/.pip/pip.conf\'s parent dir').with_command("install -o someuser -g #{root_group} -d /home/someuser/.pip") } it { is_expected.to contain_file('/home/someuser/.pip/pip.conf').with_owner('someuser') } end + context 'succeeds when set group set' do let(:title) { '/home/someuser/.pip/pip.conf' } let(:params) { { group: 'somegroup' } } diff --git a/spec/defines/gunicorn_spec.rb b/spec/defines/gunicorn_spec.rb index d2563054..de36c580 100644 --- a/spec/defines/gunicorn_spec.rb +++ b/spec/defines/gunicorn_spec.rb @@ -1,39 +1,46 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'python::gunicorn', type: :define do let(:title) { 'test-app' } - context 'on Debian OS' do - let :facts do - { - id: 'root', - kernel: 'Linux', - lsbdistcodename: 'squeeze', - osfamily: 'Debian', - operatingsystem: 'Debian', - operatingsystemrelease: '6', - path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', - concat_basedir: '/dne' - } - end + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) { facts } - describe 'test-app with default parameter values' do - context 'configures test app with default parameter values' do - let(:params) { { dir: '/srv/testapp' } } + describe 'test-app with default parameter values' do + context 'configures test app with default parameter values' do + let(:params) { { dir: '/srv/testapp' } } + let(:expected_workers) do + # manifests/gunicorn.pp + processor_count = facts.dig(:processors, 'count') - it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--log-level=error}) } - end + # templates/gunicorn.erb + (processor_count.to_i * 2) + 1 + end - context 'test-app with custom log level' do - let(:params) { { dir: '/srv/testapp', log_level: 'info' } } + it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--log-level=error}) } + it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--workers=#{expected_workers}}) } + end - it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--log-level=info}) } - end + context 'test-app with custom log level' do + let(:params) { { dir: '/srv/testapp', log_level: 'info' } } + + it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--log-level=info}) } + end + + context 'test-app with custom gunicorn preload arguments' do + let(:params) { { dir: '/srv/testapp', args: ['--preload'] } } + + it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--preload}) } + end - context 'test-app with custom gunicorn preload arguments' do - let(:params) { { dir: '/srv/testapp', args: ['--preload'] } } + context 'test-app with custom workers count' do + let(:params) { { dir: '/srv/testapp', workers: 42 } } - it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--preload}) } + it { is_expected.to contain_file('/etc/gunicorn.d/test-app').with_mode('0644').with_content(%r{--workers=#{params[:workers]}}) } + end end end end diff --git a/spec/defines/pip_spec.rb b/spec/defines/pip_spec.rb index 1548b7b6..a00a7792 100644 --- a/spec/defines/pip_spec.rb +++ b/spec/defines/pip_spec.rb @@ -1,6 +1,9 @@ -require 'spec_helper' +# frozen_string_literal: true -describe 'python::pip', type: :define do # rubocop:disable RSpec/MultipleDescribes +require 'spec_helper' +# rubocop:disable RSpec/MultipleDescribes +# rubocop:disable RSpec/RepeatedExampleGroupDescription +describe 'python::pip', type: :define do let(:title) { 'rpyc' } context 'on Debian OS' do @@ -10,13 +13,15 @@ kernel: 'Linux', lsbdistcodename: 'squeeze', os: { - family: 'Debian' + family: 'Debian', + release: { major: '6' }, }, osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '6', path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', - concat_basedir: '/dne' + concat_basedir: '/dne', + pip_version: '18.1', } end @@ -24,13 +29,15 @@ context 'fails with non qualified path' do let(:params) { { virtualenv: 'venv' } } - it { is_expected.to raise_error(%r{expects a match for Variant\[Enum\['system'\].*Stdlib::Windowspath = Pattern\[\/.*\/\], Stdlib::Unixpath = Pattern\[\/.*\/\]\]}) } + it { is_expected.to raise_error(%r{expects a match for Variant\[Enum\['system'\].*Stdlib::Windowspath = Pattern\[/.*/\], Stdlib::Unixpath = Pattern\[/.*/\]\]}) } end + context 'suceeds with qualified path' do let(:params) { { virtualenv: '/opt/venv' } } it { is_expected.to contain_exec('pip_install_rpyc').with_cwd('/opt/venv') } end + context 'defaults to system' do let(:params) { {} } @@ -45,12 +52,14 @@ it { is_expected.to contain_exec('pip_install_rpyc').with_command(%r{pip}) } it { is_expected.not_to contain_exec('pip_install_rpyc').with_command(%r{pip3}) } end + context 'use pip instead of pip3 when specified' do let(:params) { { pip_provider: 'pip' } } it { is_expected.to contain_exec('pip_install_rpyc').with_command(%r{pip}) } it { is_expected.not_to contain_exec('pip_install_rpyc').with_command(%r{pip3}) } end + context 'use pip3 instead of pip when specified' do let(:params) { { pip_provider: 'pip3' } } @@ -64,10 +73,11 @@ it { is_expected.not_to contain_exec('pip_install_rpyc').with_command(%r{--proxy}) } end + context 'adds proxy to install command if proxy set' do let(:params) { { proxy: 'http://my.proxy:3128' } } - it { is_expected.to contain_exec('pip_install_rpyc').with_command("pip wheel --help > /dev/null 2>&1 && { pip show wheel > /dev/null 2>&1 || wheel_support_flag='--no-binary :all:'; } ; { pip --log /tmp/pip.log install $wheel_support_flag --proxy=http://my.proxy:3128 rpyc || pip --log /tmp/pip.log install --proxy=http://my.proxy:3128 rpyc ;}") } + it { is_expected.to contain_exec('pip_install_rpyc').with_command('pip install --proxy=http://my.proxy:3128 rpyc') } end end @@ -77,28 +87,58 @@ it { is_expected.not_to contain_exec('pip_install_rpyc').with_command(%r{--index-url}) } end + context 'adds index to install command if index set' do let(:params) { { index: 'http://www.example.com/simple/' } } - it { is_expected.to contain_exec('pip_install_rpyc').with_command("pip wheel --help > /dev/null 2>&1 && { pip show wheel > /dev/null 2>&1 || wheel_support_flag='--no-binary :all:'; } ; { pip --log /tmp/pip.log install $wheel_support_flag --index-url=http://www.example.com/simple/ rpyc || pip --log /tmp/pip.log install --index-url=http://www.example.com/simple/ rpyc ;}") } + it { is_expected.to contain_exec('pip_install_rpyc').with_command('pip install --index-url=http://www.example.com/simple/ rpyc') } + end + end + + describe 'extra_index as' do + context 'defaults to empty' do + let(:params) { {} } + + it { is_expected.not_to contain_exec('pip_install_rpyc').with_command(%r{--extra-index-url}) } + end + + context 'adds extra_index to install command if extra_index set' do + let(:params) { { extra_index: 'http://www.example.com/extra/simple/' } } + + it { is_expected.to contain_exec('pip_install_rpyc').with_command('pip install --extra-index-url=http://www.example.com/extra/simple/ rpyc') } end end describe 'path as' do context 'adds anaconda path to pip invocation if provider is anaconda' do let(:params) { {} } - let(:pre_condition) { 'class {"::python": provider => "anaconda", anaconda_install_path => "/opt/python3"}' } + let(:pre_condition) { 'class {"python": provider => "anaconda", anaconda_install_path => "/opt/python3"}' } it { is_expected.to contain_exec('pip_install_rpyc').with_path(['/opt/python3/bin', '/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin']) } end end + describe 'install_args as' do + context 'adds install_args to install command if install_args set' do + let(:params) { { install_args: '--pre' } } + + it { is_expected.to contain_exec('pip_install_rpyc').with_command('pip install --pre rpyc') } + end + end + describe 'install latest' do + context 'does not use legacy resolver in unless' do + let(:params) { { ensure: 'latest' } } + + it { is_expected.not_to contain_exec('pip_install_rpyc').with_unless(%r{--use-deprecated=legacy-resolver}) } + end + context 'does not use pip search in unless' do let(:params) { { ensure: 'latest' } } it { is_expected.not_to contain_exec('pip_install_rpyc').with_unless(%r{search}) } end + context 'checks installed version of a package by converting underscores in its name to dashes' do let(:params) { { ensure: 'latest', pkgname: 'wordpress_json' } } @@ -106,10 +146,72 @@ it { is_expected.to contain_exec('pip_install_rpyc').with_unless(%r{wordpress-json}) } end end + + describe 'install specific version' do + context 'supports v-prefixed version string' do + let(:params) { { ensure: 'v1.7.0' } } + + it { is_expected.to contain_exec('pip_install_rpyc').with_command('pip install rpyc==v1.7.0') } + end + + context 'supports version string without v-prefix' do + let(:params) { { ensure: '1.7.0' } } + + it { is_expected.to contain_exec('pip_install_rpyc').with_command('pip install rpyc==1.7.0') } + end + end + + describe 'uninstall' do + context 'adds correct title' do + let(:params) { { ensure: 'absent' } } + + it { is_expected.not_to contain_exec('pip_install_rpyc') } + + it { is_expected.to contain_exec('pip_uninstall_rpyc').with_command(%r{uninstall.*rpyc$}) } + end + + context 'passes correct package name' do + let(:params) { { ensure: 'absent', pkgname: 'r-pyc' } } + + it { is_expected.not_to contain_exec('pip_install_rpyc') } + + it { is_expected.to contain_exec('pip_uninstall_rpyc').with_command(%r{uninstall.*r-pyc$}) } + end + end + end + + context 'on Debian OS with pip_version 20.3.4' do + let :facts do + { + id: 'root', + kernel: 'Linux', + lsbdistcodename: 'buster', + os: { + family: 'Debian', + release: { major: '10' }, + }, + osfamily: 'Debian', + operatingsystem: 'Debian', + operatingsystemrelease: '10.12', + path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + concat_basedir: '/dne', + pip_version: '20.3.4', + } + end + + describe 'install latest' do + context 'with legacy resolver in unless cmd' do + let(:params) { { ensure: 'latest' } } + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_exec('pip_install_rpyc').with_unless(%r{--use-deprecated=legacy-resolver}) } + end + end end end describe 'python::pip', type: :define do + # rubocop:enable RSpec/RepeatedExampleGroupDescription let(:title) { 'requests' } context 'on Debian OS' do @@ -119,13 +221,13 @@ kernel: 'Linux', lsbdistcodename: 'squeeze', os: { - family: 'Debian' + family: 'Debian', }, osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '6', path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', - concat_basedir: '/dne' + concat_basedir: '/dne', } end @@ -133,13 +235,15 @@ context 'suceeds with no extras' do let(:params) { {} } - it { is_expected.to contain_exec('pip_install_requests').with_command("pip wheel --help > /dev/null 2>&1 && { pip show wheel > /dev/null 2>&1 || wheel_support_flag='--no-binary :all:'; } ; { pip --log /tmp/pip.log install $wheel_support_flag requests || pip --log /tmp/pip.log install requests ;}") } + it { is_expected.to contain_exec('pip_install_requests').with_command('pip install requests') } end + context 'succeeds with extras' do let(:params) { { extras: ['security'] } } - it { is_expected.to contain_exec('pip_install_requests').with_command("pip wheel --help > /dev/null 2>&1 && { pip show wheel > /dev/null 2>&1 || wheel_support_flag='--no-binary :all:'; } ; { pip --log /tmp/pip.log install $wheel_support_flag requests[security] || pip --log /tmp/pip.log install requests[security] ;}") } + it { is_expected.to contain_exec('pip_install_requests').with_command('pip install requests[security]') } end end end end +# rubocop:enable RSpec/MultipleDescribes diff --git a/spec/defines/pyvenv_spec.rb b/spec/defines/pyvenv_spec.rb index aa66aac5..6ce6646b 100644 --- a/spec/defines/pyvenv_spec.rb +++ b/spec/defines/pyvenv_spec.rb @@ -1,36 +1,100 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'python::pyvenv', type: :define do on_supported_os.each do |os, facts| - context("on #{os} ") do - let :facts do - # python3 is required to use pyvenv - facts.merge( - python3_version: '3.5.1' - ) + next if os == 'gentoo-3-x86_64' + + let :title do + '/opt/env' + end + + context "on #{os}" do + context 'with default parameters' do + let :facts do + facts + end + + it { is_expected.to compile } end - let :title do - '/opt/env' + + context 'with a specific python3 version' do + let :facts do + # python3 is required to use pyvenv + facts.merge( + python3_version: '3.5.1', + ) + end + + context 'with default parameters' do + it { is_expected.to contain_file('/opt/env').that_requires('Class[python::install]') } + it { is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env && /opt/env/bin/pip install --upgrade pip && /opt/env/bin/pip install --upgrade setuptools') } + end + + describe 'when ensure' do + context 'is absent' do + let :params do + { + ensure: 'absent', + } + end + + it { + expect(subject).to contain_file('/opt/env').with_ensure('absent').with_purge(true) + } + end + end end - it { - is_expected.to contain_file('/opt/env') - is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env') - } + context "prompt on #{os} with python 3.6" do + let :facts do + # python 3.6 is required for venv and prompt + facts.merge( + python3_version: '3.6.1', + ) + end + let :title do + '/opt/env' + end + + context 'with prompt' do + let :params do + { + prompt: 'custom prompt', + } + end + + it { + is_expected.to contain_file('/opt/env').that_requires('Class[python::install]') + is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('python3.6 -m venv --clear --prompt custom\\ prompt /opt/env && /opt/env/bin/pip install --upgrade pip && /opt/env/bin/pip install --upgrade setuptools') + } + end + end + + context "prompt on #{os} with python 3.5" do + let :facts do + facts.merge( + python3_version: '3.5.1', + ) + end + let :title do + '/opt/env' + end - describe 'when ensure' do - context 'is absent' do + context 'with prompt' do let :params do { - ensure: 'absent' + prompt: 'custom prompt', } end it { - is_expected.to contain_file('/opt/env').with_ensure('absent').with_purge(true) + is_expected.to contain_file('/opt/env').that_requires('Class[python::install]') + is_expected.to contain_exec('python_virtualenv_/opt/env').with_command('pyvenv-3.5 --clear /opt/env && /opt/env/bin/pip install --upgrade pip && /opt/env/bin/pip install --upgrade setuptools') } end end - end # context + end end end diff --git a/spec/defines/requirements_spec.rb b/spec/defines/requirements_spec.rb index 29119422..82dc0b37 100644 --- a/spec/defines/requirements_spec.rb +++ b/spec/defines/requirements_spec.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'python::requirements', type: :define do on_supported_os.each do |os, facts| - context "on #{os} " do + context "on #{os}" do let :facts do facts end @@ -11,50 +13,57 @@ '/requirements.txt' end - context 'on Debian OS' do - describe 'requirements as' do - context '/requirements.txt' do - let :params do - { - requirements: '/requirements.txt' - } - end + context 'with /requirements.txt' do + let :params do + { + requirements: '/requirements.txt', + } + end - it { is_expected.to contain_file('/requirements.txt').with_mode('0644') } - end - context '/requirements.txt' do - let :params do - { - requirements: '/requirements.txt', - manage_requirements: false - } - end - - it { is_expected.not_to contain_file('/requirements.txt') } - end + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_file('/requirements.txt').with_mode('0644') } - describe 'with owner' do - context 'bob:bob' do - let :params do - { - owner: 'bob', - group: 'bob' - } - end - - it do - expect do - is_expected.to compile - end.to raise_error(%r{root user must be used when virtualenv is system}) - end - end - end + context 'with manage_requirements => false' do + let(:params) { super().merge(manage_requirements: false) } + + it { is_expected.not_to contain_file('/requirements.txt') } + end + end - describe 'with owner' do - context 'default' do - it { is_expected.to contain_file('/requirements.txt').with_owner('root').with_group('root') } - end + describe 'with owner' do + context 'bob:bob' do + let :params do + { + owner: 'bob', + group: 'bob', + } end + + it { is_expected.to compile.and_raise_error(%r{root user must be used when virtualenv is system}) } + end + end + + context 'without parameters' do + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('python::config') } + it { is_expected.to contain_class('python::install') } + it { is_expected.to contain_class('python::params') } + it { is_expected.to contain_class('python') } + it { is_expected.to contain_exec('python_requirements/requirements.txt') } + + if facts[:os]['family'] == 'Archlinux' + it { is_expected.not_to contain_package('pip') } + else + it { is_expected.to contain_package('pip') } + end + it { is_expected.to contain_package('python') } + it { is_expected.to contain_package('gunicorn') } + it { is_expected.to contain_file('/requirements.txt').with_owner('root').with_group('root') } + + if %w[Archlinux FreeBSD Gentoo].include?(facts[:os]['name']) + it { is_expected.not_to contain_package('python-dev') } + else + it { is_expected.to contain_package('python-dev') } end end end diff --git a/spec/spec.opts b/spec/spec.opts deleted file mode 100644 index 91cd6427..00000000 --- a/spec/spec.opts +++ /dev/null @@ -1,6 +0,0 @@ ---format -s ---colour ---loadby -mtime ---backtrace diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2f2279d2..58c9b66a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,38 +1,24 @@ -# This file is managed via modulesync -# https://github.com/voxpupuli/modulesync -# https://github.com/voxpupuli/modulesync_config -require 'puppetlabs_spec_helper/module_spec_helper' -require 'rspec-puppet-facts' -include RspecPuppetFacts +# frozen_string_literal: true -if File.exist?(File.join(__dir__, 'default_module_facts.yml')) - facts = YAML.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 +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ -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' - end -end +# 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', __dir__)) + +require 'voxpupuli/test/spec_helper' RSpec.configure do |c| - # Coverage generation - c.after(:suite) do - RSpec::Puppet::Coverage.report! + c.facterdb_string_keys = false +end + +add_mocked_facts! + +if File.exist?(File.join(__dir__, 'default_module_facts.yml')) + facts = YAML.safe_load(File.read(File.join(__dir__, 'default_module_facts.yml'))) + facts&.each do |name, value| + add_custom_fact name.to_sym, value end end +Dir['./spec/support/spec/**/*.rb'].sort.each { |f| require f } diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index c978c402..2681792e 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,19 +1,10 @@ -require 'beaker-rspec' -require 'beaker-puppet' -require 'beaker/puppet_install_helper' -require 'beaker/module_install_helper' +# frozen_string_literal: true -run_puppet_install_helper unless ENV['BEAKER_provision'] == 'no' -install_ca_certs unless ENV['PUPPET_INSTALL_TYPE'] =~ %r{pe}i -install_module_on(hosts) -install_module_dependencies_on(hosts) +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ -RSpec.configure do |c| - # Readable test descriptions - c.formatter = :documentation - hosts.each do |host| - if host[:platform] =~ %r{el-7-x86_64} && host[:hypervisor] =~ %r{docker} - on(host, "sed -i '/nodocs/d' /etc/yum.conf") - end - end -end +require 'voxpupuli/acceptance/spec_helper_acceptance' + +configure_beaker(modules: :metadata) + +Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f } diff --git a/spec/type_aliases/venv/pipversion_spec.rb b/spec/type_aliases/venv/pipversion_spec.rb new file mode 100644 index 00000000..920cf061 --- /dev/null +++ b/spec/type_aliases/venv/pipversion_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Python::Venv::PipVersion' do + describe 'valid values' do + [ + '< 1', + '< 0.1', + '< 1.2.3', + '< 1.2.3.40', + '<= 1', + '<= 0.1', + '<= 1.2.3', + '<= 1.2.3.40', + '> 1', + '> 0.1', + '> 1.2.3', + '> 1.2.3.40', + '>= 1', + '>= 0.1', + '>= 1.2.3', + '>= 1.2.3.40', + '== 1', + '== 0.1', + '== 1.2.3', + '== 1.2.3.40', + ].each do |value| + describe value.inspect do + it { + expect(subject).to allow_value(value) + } + end + end + end + + describe 'invalid values' do + [ + '+ 1', + '- 0.1', + '< -1', + '< 1.+2.3.40', + '<=', + '<= 0.-1', + '<= 1.f.3', + '1.2.3.0', + 'pip > 1', + 'all', + -1, + 65_536, + :undef, + ].each do |value| + describe value.inspect do + it { + expect(subject).not_to allow_value(value) + } + end + end + end +end diff --git a/spec/unit/facter/pip_version_spec.rb b/spec/unit/facter/pip_version_spec.rb index 7401cde5..3e6cd29f 100644 --- a/spec/unit/facter/pip_version_spec.rb +++ b/spec/unit/facter/pip_version_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Facter::Util::Fact do @@ -6,26 +8,70 @@ end let(:pip_version_output) do - <<-EOS -pip 6.0.6 from /opt/boxen/homebrew/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pip-6.0.6-py2.7.egg (python 2.7) -EOS + <<~EOS + pip 6.0.6 from /opt/boxen/homebrew/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pip-6.0.6-py2.7.egg (python 2.7) + EOS + end + + let(:pip2_version_output) do + <<~EOS + pip 9.0.1 from /usr/lib/python2.7/dist-packages/pip (python 2.7) + EOS + end + + let(:pip3_version_output) do + <<~EOS + pip 18.1 from /usr/lib/python3/dist-packages/pip (python 3.7) + EOS end describe 'pip_version' do context 'returns pip version when pip present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('pip').returns(true) - Facter::Util::Resolution.expects(:exec).with('pip --version 2>&1').returns(pip_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('pip').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('pip --version 2>&1').and_return(pip_version_output) expect(Facter.value(:pip_version)).to eq('6.0.6') end end context 'returns nil when pip not present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('pip').returns(false) - expect(Facter.value(:pip_version)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('pip').and_return(false) + expect(Facter.value(:pip_version)).to be_nil + end + end + end + + describe 'pip2_version' do + context 'returns pip2 version when pip2 present' do + it do + allow(Facter::Util::Resolution).to receive(:which).with('pip2').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('pip2 --version 2>&1').and_return(pip2_version_output) + expect(Facter.value(:pip2_version)).to eq('9.0.1') + end + end + + context 'returns nil when pip2 not present' do + it do + allow(Facter::Util::Resolution).to receive(:which).with('pip2').and_return(false) + expect(Facter.value(:pip2_version)).to be_nil + end + end + end + + describe 'pip3_version' do + context 'returns pip3 version when pip3 present' do + it do + allow(Facter::Util::Resolution).to receive(:which).with('pip3').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('pip3 --version 2>&1').and_return(pip3_version_output) + expect(Facter.value(:pip3_version)).to eq('18.1') + end + end + + context 'returns nil when pip3 not present' do + it do + allow(Facter::Util::Resolution).to receive(:which).with('pip3').and_return(false) + expect(Facter.value(:pip3_version)).to be_nil end end end diff --git a/spec/unit/facter/python_release_spec.rb b/spec/unit/facter/python_release_spec.rb index ad2dc30c..6026c1e3 100644 --- a/spec/unit/facter/python_release_spec.rb +++ b/spec/unit/facter/python_release_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Facter::Util::Fact do @@ -6,31 +8,30 @@ end let(:python2_version_output) do - <<-EOS -Python 2.7.9 -EOS + <<~EOS + Python 2.7.9 + EOS end let(:python3_version_output) do - <<-EOS -Python 3.3.0 -EOS + <<~EOS + Python 3.3.0 + EOS end describe 'python_release' do context 'returns Python release when `python` present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python2_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python2_version_output) expect(Facter.value(:python_release)).to eq('2.7') end end context 'returns nil when `python` not present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(false) - expect(Facter.value(:python_release)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:exec).and_return(false) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(false) + expect(Facter.value(:python_release)).to be_nil end end end @@ -38,40 +39,36 @@ describe 'python2_release' do context 'returns Python 2 release when `python` is present and Python 2' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python2_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python2_version_output) expect(Facter.value(:python2_release)).to eq('2.7') end end context 'returns Python 2 release when `python` is Python 3 and `python2` is present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python3_version_output) - Facter::Util::Resolution.expects(:which).with('python2').returns(true) - Facter::Util::Resolution.expects(:exec).with('python2 -V 2>&1').returns(python2_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python3_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python2').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python2 -V 2>&1').and_return(python2_version_output) expect(Facter.value(:python2_release)).to eq('2.7') end end context 'returns nil when `python` is Python 3 and `python2` is absent' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python3_version_output) - Facter::Util::Resolution.expects(:which).with('python2').returns(false) - expect(Facter.value(:python2_release)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python3_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python2').and_return(false) + expect(Facter.value(:python2_release)).to be_nil end end context 'returns nil when `python2` and `python` are absent' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(false) - Facter::Util::Resolution.expects(:which).with('python2').returns(false) - expect(Facter.value(:python2_release)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(false) + allow(Facter::Util::Resolution).to receive(:which).with('python2').and_return(false) + expect(Facter.value(:python2_release)).to be_nil end end end @@ -79,18 +76,16 @@ describe 'python3_release' do context 'returns Python 3 release when `python3` present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python3').returns(true) - Facter::Util::Resolution.expects(:exec).with('python3 -V 2>&1').returns(python3_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python3').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python3 -V 2>&1').and_return(python3_version_output) expect(Facter.value(:python3_release)).to eq('3.3') end end context 'returns nil when `python3` not present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python3').returns(false) - expect(Facter.value(:python3_release)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python3').and_return(false) + expect(Facter.value(:python3_release)).to be_nil end end end diff --git a/spec/unit/facter/python_version_spec.rb b/spec/unit/facter/python_version_spec.rb index 039318d9..d66d280b 100644 --- a/spec/unit/facter/python_version_spec.rb +++ b/spec/unit/facter/python_version_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Facter::Util::Fact do @@ -6,31 +8,29 @@ end let(:python2_version_output) do - <<-EOS -Python 2.7.9 -EOS + <<~EOS + Python 2.7.9 + EOS end let(:python3_version_output) do - <<-EOS -Python 3.3.0 -EOS + <<~EOS + Python 3.3.0 + EOS end describe 'python_version' do context 'returns Python version when `python` present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python2_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python2_version_output) expect(Facter.value(:python_version)).to eq('2.7.9') end end context 'returns nil when `python` not present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(false) - expect(Facter.value(:python_version)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(false) + expect(Facter.value(:python_version)).to be_nil end end end @@ -38,40 +38,36 @@ describe 'python2_version' do context 'returns Python 2 version when `python` is present and Python 2' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python2_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python2_version_output) expect(Facter.value(:python2_version)).to eq('2.7.9') end end context 'returns Python 2 version when `python` is Python 3 and `python2` is present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python3_version_output) - Facter::Util::Resolution.expects(:which).with('python2').returns(true) - Facter::Util::Resolution.expects(:exec).with('python2 -V 2>&1').returns(python2_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python3_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python2').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python2 -V 2>&1').and_return(python2_version_output) expect(Facter.value(:python2_version)).to eq('2.7.9') end end context 'returns nil when `python` is Python 3 and `python2` is absent' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(true) - Facter::Util::Resolution.expects(:exec).with('python -V 2>&1').returns(python3_version_output) - Facter::Util::Resolution.expects(:which).with('python2').returns(false) - expect(Facter.value(:python2_version)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python -V 2>&1').and_return(python3_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python2').and_return(false) + expect(Facter.value(:python2_version)).to be_nil end end context 'returns nil when `python2` and `python` are absent' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python').returns(false) - Facter::Util::Resolution.expects(:which).with('python2').returns(false) - expect(Facter.value(:python2_version)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python2').and_return(false) + allow(Facter::Util::Resolution).to receive(:which).with('python').and_return(false) + expect(Facter.value(:python2_version)).to be_nil end end end @@ -79,18 +75,16 @@ describe 'python3_version' do context 'returns Python 3 version when `python3` present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python3').returns(true) - Facter::Util::Resolution.expects(:exec).with('python3 -V 2>&1').returns(python3_version_output) + allow(Facter::Util::Resolution).to receive(:which).with('python3').and_return(true) + allow(Facter::Util::Resolution).to receive(:exec).with('python3 -V 2>&1').and_return(python3_version_output) expect(Facter.value(:python3_version)).to eq('3.3.0') end end context 'returns nil when `python3` not present' do it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('python3').returns(false) - expect(Facter.value(:python3_version)).to eq(nil) + allow(Facter::Util::Resolution).to receive(:which).with('python3').and_return(false) + expect(Facter.value(:python3_version)).to be_nil end end end diff --git a/spec/unit/facter/virtualenv_version_spec.rb b/spec/unit/facter/virtualenv_version_spec.rb deleted file mode 100644 index 1d625859..00000000 --- a/spec/unit/facter/virtualenv_version_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'spec_helper' - -describe Facter::Util::Fact do - before do - Facter.clear - end - - let(:virtualenv_version_output) do - <<-EOS -12.0.7 -EOS - end - - describe 'virtualenv_version' do - context 'returns virtualenv version when virtualenv present' do - it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('virtualenv').returns(true) - Facter::Util::Resolution.expects(:exec).with('virtualenv --version 2>&1').returns(virtualenv_version_output) - expect(Facter.value(:virtualenv_version)).to eq('12.0.7') - end - end - - context 'returns nil when virtualenv not present' do - it do - Facter::Util::Resolution.stubs(:exec) - Facter::Util::Resolution.expects(:which).with('virtualenv').returns(false) - expect(Facter.value(:virtualenv_version)).to eq(nil) - end - end - end -end diff --git a/templates/gunicorn.erb b/templates/gunicorn.erb index 07605ade..57dd4748 100644 --- a/templates/gunicorn.erb +++ b/templates/gunicorn.erb @@ -39,7 +39,7 @@ CONFIG = { <% if @workers -%> '--workers=<%= @workers %>', <% else -%> - '--workers=<%= @processorcount.to_i*2 + 1 %>', + '--workers=<%= @processor_count.to_i*2 + 1 %>', <% end -%> '--timeout=<%= @timeout %>', <% if @access_log_format -%> diff --git a/types/loglevel.pp b/types/loglevel.pp new file mode 100644 index 00000000..849c2236 --- /dev/null +++ b/types/loglevel.pp @@ -0,0 +1,3 @@ +# @summary Match all valid loglevels for python +# +type Python::Loglevel = Enum['debug', 'info', 'warning', 'error', 'critical'] diff --git a/types/package/ensure.pp b/types/package/ensure.pp new file mode 100644 index 00000000..9fa54968 --- /dev/null +++ b/types/package/ensure.pp @@ -0,0 +1,3 @@ +# @summary Match all valid package ensures for python +# +type Python::Package::Ensure = Enum['absent', 'present', 'installed', 'latest'] diff --git a/types/provider.pp b/types/provider.pp new file mode 100644 index 00000000..68fd7ff6 --- /dev/null +++ b/types/provider.pp @@ -0,0 +1,3 @@ +# @summary Match all valid provider for python +# +type Python::Provider = Enum['pip', 'scl', 'rhscl', 'anaconda', ''] diff --git a/types/umask.pp b/types/umask.pp new file mode 100644 index 00000000..39038093 --- /dev/null +++ b/types/umask.pp @@ -0,0 +1,3 @@ +# @summary Match valid umask for python +# +type Python::Umask = Pattern[/[0-7]{1,4}/] diff --git a/types/venv/pipversion.pp b/types/venv/pipversion.pp new file mode 100644 index 00000000..37584264 --- /dev/null +++ b/types/venv/pipversion.pp @@ -0,0 +1,6 @@ +# @summary A version type to ensure a specific Pip version in a virtual env. +# +type Python::Venv::PipVersion = Pattern[ + /^(<|>|<=|>=|==) [0-9]*(\.[0-9]+)*$/, + /\Alatest\Z/ +] diff --git a/types/version.pp b/types/version.pp new file mode 100644 index 00000000..5bbcaaa8 --- /dev/null +++ b/types/version.pp @@ -0,0 +1,8 @@ +# @summary Match all valid versions for python +# +type Python::Version = Pattern[ + /\A(python)?[0-9](\.?[0-9])*/, + /\Apypy\Z/, + /\Asystem\Z/, + /\Arh-python[0-9]{2}(?:-python)?\Z/ +]