├── .editorconfig ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── labeler.yml ├── release.yml └── workflows │ ├── ci.yml │ ├── labeler.yml │ ├── prepare_release.yml │ └── release.yml ├── .gitignore ├── .msync.yml ├── .overcommit.yml ├── .pmtignore ├── .puppet-lint.rc ├── .rubocop.yml ├── .sync.yml ├── CHANGELOG.md ├── Gemfile ├── HISTORY.md ├── LICENSE ├── README.md ├── Rakefile ├── lib └── puppet │ ├── provider │ ├── alternative_entry │ │ ├── chkconfig.rb │ │ └── dpkg.rb │ └── alternatives │ │ ├── chkconfig.rb │ │ └── dpkg.rb │ └── type │ ├── alternative_entry.rb │ └── alternatives.rb ├── metadata.json └── spec ├── acceptance ├── alternatives_spec.rb └── family_spec.rb ├── fixtures └── unit │ └── provider │ └── alternatives │ ├── chkconfig │ ├── alternatives │ │ ├── sample │ │ └── testcmd │ └── display │ │ ├── sample │ │ └── testcmd │ └── dpkg │ └── get-selections ├── spec_helper.rb ├── spec_helper_acceptance.rb └── unit ├── provider └── alternatives │ ├── chkconfig_spec.rb │ └── dpkg_spec.rb └── type └── alternatives_spec.rb /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | root = true 7 | 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | tab_width = 2 13 | indent_style = space 14 | insert_final_newline = true 15 | trim_trailing_whitespace = true 16 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | ## Table of contents 4 | 5 | * [Contributing](#contributing) 6 | * [Writing proper commits - short version](#writing-proper-commits-short-version) 7 | * [Writing proper commits - long version](#writing-proper-commits-long-version) 8 | * [Dependencies](#dependencies) 9 | * [Note for OS X users](#note-for-os-x-users) 10 | * [The test matrix](#the-test-matrix) 11 | * [Syntax and style](#syntax-and-style) 12 | * [Running the unit tests](#running-the-unit-tests) 13 | * [Unit tests in docker](#unit-tests-in-docker) 14 | * [Integration tests](#integration-tests) 15 | 16 | This module has grown over time based on a range of contributions from 17 | people using it. If you follow these contributing guidelines your patch 18 | will likely make it into a release a little more quickly. 19 | 20 | ## Contributing 21 | 22 | Please note that this project is released with a Contributor Code of Conduct. 23 | By participating in this project you agree to abide by its terms. 24 | [Contributor Code of Conduct](https://voxpupuli.org/coc/). 25 | 26 | * Fork the repo. 27 | * Create a separate branch for your change. 28 | * We only take pull requests with passing tests, and documentation. [GitHub Actions](https://docs.github.com/en/actions) run the tests for us. You can also execute them locally. This is explained [in a later section](#the-test-matrix). 29 | * Checkout [our docs](https://voxpupuli.org/docs/reviewing_pr/) we use to review a module and the [official styleguide](https://puppet.com/docs/puppet/6.0/style_guide.html). They provide some guidance for new code that might help you before you submit a pull request. 30 | * 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. 31 | * Squash your commits down into logical components. Make sure to rebase against our current master. 32 | * Push the branch to your fork and submit a pull request. 33 | 34 | Please be prepared to repeat some of these steps as our contributors review your code. 35 | 36 | Also consider sending in your profile code that calls this component module as an acceptance test or provide it via an issue. This helps reviewers a lot to test your use case and prevents future regressions! 37 | 38 | ## Writing proper commits - short version 39 | 40 | * Make commits of logical units. 41 | * Check for unnecessary whitespace with "git diff --check" before committing. 42 | * Commit using Unix line endings (check the settings around "crlf" in git-config(1)). 43 | * Do not check in commented out code or unneeded files. 44 | * The first line of the commit message should be a short description (50 characters is the soft limit, excluding ticket number(s)), and should skip the full stop. 45 | * Associate the issue in the message. The first line should include the issue number in the form "(#XXXX) Rest of message". 46 | * The body should provide a meaningful commit message, which: 47 | *uses the imperative, present tense: `change`, not `changed` or `changes`. 48 | * includes motivation for the change, and contrasts its implementation with the previous behavior. 49 | * Make sure that you have tests for the bug you are fixing, or feature you are adding. 50 | * Make sure the test suites passes after your commit: 51 | * When introducing a new feature, make sure it is properly documented in the README.md 52 | 53 | ## Writing proper commits - long version 54 | 55 | 1. Make separate commits for logically separate changes. 56 | 57 | Please break your commits down into logically consistent units 58 | which include new or changed tests relevant to the rest of the 59 | change. The goal of doing this is to make the diff easier to 60 | read for whoever is reviewing your code. In general, the easier 61 | your diff is to read, the more likely someone will be happy to 62 | review it and get it into the code base. 63 | 64 | If you are going to refactor a piece of code, please do so as a 65 | separate commit from your feature or bug fix changes. 66 | 67 | We also really appreciate changes that include tests to make 68 | sure the bug is not re-introduced, and that the feature is not 69 | accidentally broken. 70 | 71 | Describe the technical detail of the change(s). If your 72 | description starts to get too long, that is a good sign that you 73 | probably need to split up your commit into more finely grained 74 | pieces. 75 | 76 | Commits which plainly describe the things which help 77 | reviewers check the patch and future developers understand the 78 | code are much more likely to be merged in with a minimum of 79 | bike-shedding or requested changes. Ideally, the commit message 80 | would include information, and be in a form suitable for 81 | inclusion in the release notes for the version of Puppet that 82 | includes them. 83 | 84 | Please also check that you are not introducing any trailing 85 | whitespace or other "whitespace errors". You can do this by 86 | running "git diff --check" on your changes before you commit. 87 | 88 | 2. Sending your patches 89 | 90 | To submit your changes via a GitHub pull request, we _highly_ 91 | recommend that you have them on a topic branch, instead of 92 | directly on `master`. 93 | It makes things much easier to keep track of, especially if 94 | you decide to work on another thing before your first change 95 | is merged in. 96 | 97 | GitHub has some pretty good 98 | [general documentation](http://help.github.com/) on using 99 | their site. They also have documentation on 100 | [creating pull requests](http://help.github.com/send-pull-requests/). 101 | 102 | In general, after pushing your topic branch up to your 103 | repository on GitHub, you can switch to the branch in the 104 | GitHub UI and click "Pull Request" towards the top of the page 105 | in order to open a pull request. 106 | 107 | 108 | 3. Update the related GitHub issue. 109 | 110 | If there is a GitHub issue associated with the change you 111 | submitted, then you should update the ticket to include the 112 | location of your branch, along with any other commentary you 113 | may wish to make. 114 | 115 | ## Dependencies 116 | 117 | The testing and development tools have a bunch of dependencies, 118 | all managed by [bundler](http://bundler.io/) according to the 119 | [Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions). 120 | 121 | By default the tests use a baseline version of Puppet. 122 | 123 | If you have Ruby 2.x or want a specific version of Puppet, 124 | you must set an environment variable such as: 125 | 126 | ```sh 127 | export PUPPET_GEM_VERSION="~> 6.1.0" 128 | ``` 129 | 130 | You can install all needed gems for spec tests into the modules directory by 131 | running: 132 | 133 | ```sh 134 | bundle config set --local path '.vendor/' 135 | bundle config set --local without 'development system_tests release' 136 | bundle install --jobs "$(nproc)" 137 | ``` 138 | 139 | If you also want to run acceptance tests: 140 | 141 | ```sh 142 | bundle config set --local path '.vendor/' 143 | bundle config set --local without 'development release' 144 | bundle config set --local with 'system_tests' 145 | bundle install --jobs "$(nproc)" 146 | ``` 147 | 148 | Our all in one solution if you don't know if you need to install or update gems: 149 | 150 | ```sh 151 | bundle config set --local path '.vendor/' 152 | bundle config set --local without 'development release' 153 | bundle config set --local with 'system_tests' 154 | bundle install --jobs "$(nproc)" 155 | bundle update 156 | bundle clean 157 | ``` 158 | 159 | As an alternative to the `--jobs "$(nproc)` parameter, you can set an 160 | environment variable: 161 | 162 | ```sh 163 | BUNDLE_JOBS="$(nproc)" 164 | ``` 165 | 166 | ### Note for OS X users 167 | 168 | `nproc` isn't a valid command under OS x. As an alternative, you can do: 169 | 170 | ```sh 171 | --jobs "$(sysctl -n hw.ncpu)" 172 | ``` 173 | 174 | ## The test matrix 175 | 176 | ### Syntax and style 177 | 178 | The test suite will run [Puppet Lint](http://puppet-lint.com/) and 179 | [Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to 180 | check various syntax and style things. You can run these locally with: 181 | 182 | ```sh 183 | bundle exec rake lint 184 | bundle exec rake validate 185 | ``` 186 | 187 | It will also run some [Rubocop](http://batsov.com/rubocop/) tests 188 | against it. You can run those locally ahead of time with: 189 | 190 | ```sh 191 | bundle exec rake rubocop 192 | ``` 193 | 194 | ### Running the unit tests 195 | 196 | The unit test suite covers most of the code, as mentioned above please 197 | add tests if you're adding new functionality. If you've not used 198 | [rspec-puppet](http://rspec-puppet.com/) before then feel free to ask 199 | about how best to test your new feature. 200 | 201 | To run the linter, the syntax checker and the unit tests: 202 | 203 | ```sh 204 | bundle exec rake test 205 | ``` 206 | 207 | To run your all the unit tests 208 | 209 | ```sh 210 | bundle exec rake spec 211 | ``` 212 | 213 | To run a specific spec test set the `SPEC` variable: 214 | 215 | ```sh 216 | bundle exec rake spec SPEC=spec/foo_spec.rb 217 | ``` 218 | 219 | #### Unit tests in docker 220 | 221 | Some people don't want to run the dependencies locally or don't want to install 222 | ruby. We ship a Dockerfile that enables you to run all unit tests and linting. 223 | You only need to run: 224 | 225 | ```sh 226 | docker build . 227 | ``` 228 | 229 | Please ensure that a docker daemon is running and that your user has the 230 | permission to talk to it. You can specify a remote docker host by setting the 231 | `DOCKER_HOST` environment variable. it will copy the content of the module into 232 | the docker image. So it will not work if a Gemfile.lock exists. 233 | 234 | ### Integration tests 235 | 236 | The unit tests just check the code runs, not that it does exactly what 237 | we want on a real machine. For that we're using 238 | [beaker](https://github.com/puppetlabs/beaker). 239 | 240 | This fires up a new virtual machine (using vagrant) and runs a series of 241 | simple tests against it after applying the module. You can run this 242 | with: 243 | 244 | ```sh 245 | BEAKER_PUPPET_COLLECTION=puppet7 BEAKER_setfile=debian11-64 bundle exec rake beaker 246 | ``` 247 | 248 | or 249 | 250 | ```sh 251 | BEAKER_PUPPET_COLLECTION=none BEAKER_setfile=archlinux-64 bundle exec rake beaker 252 | ``` 253 | 254 | This latter example will use the distribution's own version of Puppet. 255 | 256 | You can replace the string `debian11` with any common operating system. 257 | The following strings are known to work: 258 | 259 | * ubuntu2004 260 | * ubuntu2204 261 | * debian11 262 | * debian12 263 | * centos9 264 | * archlinux 265 | * almalinux8 266 | * almalinux9 267 | * fedora36 268 | 269 | For more information and tips & tricks, see [voxpupuli-acceptance's documentation](https://github.com/voxpupuli/voxpupuli-acceptance#running-tests). 270 | 271 | The source of this file is in our [modulesync_config](https://github.com/voxpupuli/modulesync_config/blob/master/moduleroot/.github/CONTRIBUTING.md.erb) 272 | repository. 273 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | ## Affected Puppet, Ruby, OS and module versions/distributions 12 | 13 | - Puppet: 14 | - Ruby: 15 | - Distribution: 16 | - Module version: 17 | 18 | ## How to reproduce (e.g Puppet code you use) 19 | 20 | ## What are you seeing 21 | 22 | ## What behaviour did you expect instead 23 | 24 | ## Output log 25 | 26 | ## Any additional information you'd like to impart 27 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | #### Pull Request (PR) description 10 | 13 | 14 | #### This Pull Request (PR) fixes the following issues 15 | 21 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | skip-changelog: 6 | - head-branch: ['^release-*', 'release'] 7 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes 6 | 7 | changelog: 8 | exclude: 9 | labels: 10 | - duplicate 11 | - invalid 12 | - modulesync 13 | - question 14 | - skip-changelog 15 | - wont-fix 16 | - wontfix 17 | 18 | categories: 19 | - title: Breaking Changes 🛠 20 | labels: 21 | - backwards-incompatible 22 | 23 | - title: New Features 🎉 24 | labels: 25 | - enhancement 26 | 27 | - title: Bug Fixes 🐛 28 | labels: 29 | - bug 30 | 31 | - title: Documentation Updates 📚 32 | labels: 33 | - documentation 34 | - docs 35 | 36 | - title: Dependency Updates ⬆️ 37 | labels: 38 | - dependencies 39 | 40 | - title: Other Changes 41 | labels: 42 | - "*" 43 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: CI 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | pull_request: {} 10 | push: 11 | branches: 12 | - main 13 | - master 14 | 15 | concurrency: 16 | group: ${{ github.ref_name }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | puppet: 21 | name: Puppet 22 | uses: voxpupuli/gha-puppet/.github/workflows/beaker.yml@v3 23 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: "Pull Request Labeler" 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | pull_request_target: {} 10 | 11 | jobs: 12 | labeler: 13 | permissions: 14 | contents: read 15 | pull-requests: write 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/labeler@v5 19 | -------------------------------------------------------------------------------- /.github/workflows/prepare_release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: 'Prepare Release' 6 | 7 | on: 8 | workflow_dispatch: 9 | inputs: 10 | version: 11 | description: 'Module version to be released. Must be a valid semver string without leading v. (1.2.3)' 12 | required: false 13 | 14 | jobs: 15 | release_prep: 16 | uses: 'voxpupuli/gha-puppet/.github/workflows/prepare_release.yml@v3' 17 | with: 18 | version: ${{ github.event.inputs.version }} 19 | allowed_owner: 'voxpupuli' 20 | secrets: 21 | # Configure secrets here: 22 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 23 | github_pat: '${{ secrets.PCCI_PAT_RELEASE_PREP }}' 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | name: Release 6 | 7 | # yamllint disable-line rule:truthy 8 | on: 9 | push: 10 | tags: 11 | - '*' 12 | 13 | jobs: 14 | release: 15 | name: Release 16 | uses: voxpupuli/gha-puppet/.github/workflows/release.yml@v3 17 | with: 18 | allowed_owner: 'voxpupuli' 19 | secrets: 20 | # Configure secrets here: 21 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 22 | username: ${{ secrets.PUPPET_FORGE_USERNAME }} 23 | api_key: ${{ secrets.PUPPET_FORGE_API_KEY }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | /pkg/ 5 | /Gemfile.lock 6 | /Gemfile.local 7 | /vendor/ 8 | /.vendor/ 9 | /spec/fixtures/manifests/ 10 | /spec/fixtures/modules/ 11 | /.vagrant/ 12 | /.bundle/ 13 | /.ruby-version 14 | /coverage/ 15 | /log/ 16 | /.idea/ 17 | /.dependencies/ 18 | /.librarian/ 19 | /Puppetfile.lock 20 | *.iml 21 | .*.sw? 22 | /.yardoc/ 23 | /Guardfile 24 | bolt-debug.log 25 | .rerun.json 26 | -------------------------------------------------------------------------------- /.msync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | modulesync_config_version: '9.5.0' 6 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | # 4 | # Hooks are only enabled if you take action. 5 | # 6 | # To enable the hooks run: 7 | # 8 | # ``` 9 | # bundle exec overcommit --install 10 | # # ensure .overcommit.yml does not harm to you and then 11 | # bundle exec overcommit --sign 12 | # ``` 13 | # 14 | # (it will manage the .git/hooks directory): 15 | # 16 | # Examples howto skip a test for a commit or push: 17 | # 18 | # ``` 19 | # SKIP=RuboCop git commit 20 | # SKIP=PuppetLint git commit 21 | # SKIP=RakeTask git push 22 | # ``` 23 | # 24 | # Don't invoke overcommit at all: 25 | # 26 | # ``` 27 | # OVERCOMMIT_DISABLE=1 git commit 28 | # ``` 29 | # 30 | # Read more about overcommit: https://github.com/brigade/overcommit 31 | # 32 | # To manage this config yourself in your module add 33 | # 34 | # ``` 35 | # .overcommit.yml: 36 | # unmanaged: true 37 | # ``` 38 | # 39 | # to your modules .sync.yml config 40 | --- 41 | PreCommit: 42 | RuboCop: 43 | enabled: true 44 | description: 'Runs rubocop on modified files only' 45 | command: ['bundle', 'exec', 'rubocop'] 46 | RakeTarget: 47 | enabled: true 48 | description: 'Runs lint on modified files only' 49 | targets: 50 | - 'lint' 51 | command: ['bundle', 'exec', 'rake'] 52 | YamlSyntax: 53 | enabled: true 54 | JsonSyntax: 55 | enabled: true 56 | TrailingWhitespace: 57 | enabled: true 58 | 59 | PrePush: 60 | RakeTarget: 61 | enabled: true 62 | description: 'Run rake targets' 63 | targets: 64 | - 'validate' 65 | - 'test' 66 | - 'rubocop' 67 | command: ['bundle', 'exec', 'rake'] 68 | -------------------------------------------------------------------------------- /.pmtignore: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | /docs/ 5 | /pkg/ 6 | /Gemfile 7 | /Gemfile.lock 8 | /Gemfile.local 9 | /vendor/ 10 | /.vendor/ 11 | /spec/ 12 | /Rakefile 13 | /.vagrant/ 14 | /.bundle/ 15 | /.ruby-version 16 | /coverage/ 17 | /log/ 18 | /.idea/ 19 | /.dependencies/ 20 | /.github/ 21 | /.librarian/ 22 | /Puppetfile.lock 23 | /Puppetfile 24 | *.iml 25 | /.editorconfig 26 | /.fixtures.yml 27 | /.gitignore 28 | /.msync.yml 29 | /.overcommit.yml 30 | /.pmtignore 31 | /.rspec 32 | /.rspec_parallel 33 | /.rubocop.yml 34 | /.sync.yml 35 | .*.sw? 36 | /.yardoc/ 37 | /.yardopts 38 | /Dockerfile 39 | /HISTORY.md 40 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | --fail-on-warnings 5 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Managed by modulesync - DO NOT EDIT 3 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 4 | 5 | inherit_gem: 6 | voxpupuli-test: rubocop.yml 7 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spec/spec_helper.rb: 3 | unmanaged: true 4 | .puppet-lint.rc: 5 | enabled_lint_checks: 6 | - parameter_documentation 7 | - parameter_types 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | Each new release typically also includes the latest modulesync defaults. 5 | These should not affect the functionality of the module. 6 | 7 | ## [v6.0.0](https://github.com/voxpupuli/puppet-alternatives/tree/v6.0.0) (2024-09-18) 8 | 9 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v5.1.0...v6.0.0) 10 | 11 | **Breaking changes:** 12 | 13 | - Drop EoL Ubuntu 18.04 support [\#157](https://github.com/voxpupuli/puppet-alternatives/pull/157) ([bastelfreak](https://github.com/bastelfreak)) 14 | - Drop EoL Debian 10 support [\#156](https://github.com/voxpupuli/puppet-alternatives/pull/156) ([bastelfreak](https://github.com/bastelfreak)) 15 | - Drop EoL CentOS 8 support [\#155](https://github.com/voxpupuli/puppet-alternatives/pull/155) ([bastelfreak](https://github.com/bastelfreak)) 16 | - drop support for EL7 [\#154](https://github.com/voxpupuli/puppet-alternatives/pull/154) ([jhoblitt](https://github.com/jhoblitt)) 17 | 18 | **Implemented enhancements:** 19 | 20 | - switch from legacy to structured facts [\#159](https://github.com/voxpupuli/puppet-alternatives/pull/159) ([bastelfreak](https://github.com/bastelfreak)) 21 | - Add Ubuntu 24.04 support [\#158](https://github.com/voxpupuli/puppet-alternatives/pull/158) ([bastelfreak](https://github.com/bastelfreak)) 22 | 23 | ## [v5.1.0](https://github.com/voxpupuli/puppet-alternatives/tree/v5.1.0) (2023-10-30) 24 | 25 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v5.0.0...v5.1.0) 26 | 27 | **Implemented enhancements:** 28 | 29 | - Add Debian 12 support [\#144](https://github.com/voxpupuli/puppet-alternatives/pull/144) ([bastelfreak](https://github.com/bastelfreak)) 30 | 31 | ## [v5.0.0](https://github.com/voxpupuli/puppet-alternatives/tree/v5.0.0) (2023-06-21) 32 | 33 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v4.2.0...v5.0.0) 34 | 35 | **Breaking changes:** 36 | 37 | - Drop Puppet 6 support [\#136](https://github.com/voxpupuli/puppet-alternatives/pull/136) ([bastelfreak](https://github.com/bastelfreak)) 38 | 39 | **Implemented enhancements:** 40 | 41 | - Add puppet 8 support [\#139](https://github.com/voxpupuli/puppet-alternatives/pull/139) ([bastelfreak](https://github.com/bastelfreak)) 42 | - add EL9 support [\#133](https://github.com/voxpupuli/puppet-alternatives/pull/133) ([jhoblitt](https://github.com/jhoblitt)) 43 | - Add AlmaLinux and Rocky support [\#132](https://github.com/voxpupuli/puppet-alternatives/pull/132) ([bastelfreak](https://github.com/bastelfreak)) 44 | 45 | **Closed issues:** 46 | 47 | - Error: Could not autoload puppet/provider/alternatives/chkconfig [\#125](https://github.com/voxpupuli/puppet-alternatives/issues/125) 48 | 49 | ## [v4.2.0](https://github.com/voxpupuli/puppet-alternatives/tree/v4.2.0) (2022-09-20) 50 | 51 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v4.1.0...v4.2.0) 52 | 53 | **Implemented enhancements:** 54 | 55 | - Allow family to be used instead of full path [\#127](https://github.com/voxpupuli/puppet-alternatives/pull/127) ([alexjfisher](https://github.com/alexjfisher)) 56 | 57 | **Fixed bugs:** 58 | 59 | - Fixes multiple expressions in case statement [\#124](https://github.com/voxpupuli/puppet-alternatives/pull/124) ([otterz](https://github.com/otterz)) 60 | 61 | **Closed issues:** 62 | 63 | - Could not determine mode after upgrade to 4.1.0 [\#123](https://github.com/voxpupuli/puppet-alternatives/issues/123) 64 | - Using a full path for path is not always desirable. [\#71](https://github.com/voxpupuli/puppet-alternatives/issues/71) 65 | 66 | **Merged pull requests:** 67 | 68 | - Add basic acceptance tests [\#126](https://github.com/voxpupuli/puppet-alternatives/pull/126) ([jhoblitt](https://github.com/jhoblitt)) 69 | 70 | ## [v4.1.0](https://github.com/voxpupuli/puppet-alternatives/tree/v4.1.0) (2022-05-13) 71 | 72 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v4.0.0...v4.1.0) 73 | 74 | **Implemented enhancements:** 75 | 76 | - Add CentOS 8 support [\#121](https://github.com/voxpupuli/puppet-alternatives/pull/121) ([bastelfreak](https://github.com/bastelfreak)) 77 | 78 | ## [v4.0.0](https://github.com/voxpupuli/puppet-alternatives/tree/v4.0.0) (2021-11-26) 79 | 80 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v3.0.0...v4.0.0) 81 | 82 | **Breaking changes:** 83 | 84 | - Drop support for Puppet 5 \(EOL\) [\#113](https://github.com/voxpupuli/puppet-alternatives/pull/113) ([smortex](https://github.com/smortex)) 85 | - Drop support for Debian 8, 9; RedHat 6 and derivatives \(EOL\) [\#112](https://github.com/voxpupuli/puppet-alternatives/pull/112) ([smortex](https://github.com/smortex)) 86 | - drop Ubuntu support [\#98](https://github.com/voxpupuli/puppet-alternatives/pull/98) ([bastelfreak](https://github.com/bastelfreak)) 87 | 88 | **Implemented enhancements:** 89 | 90 | - Add support for Debian 11, Ubuntu 18.04 and 20.04 [\#115](https://github.com/voxpupuli/puppet-alternatives/pull/115) ([smortex](https://github.com/smortex)) 91 | - Add support for Puppet 7 [\#114](https://github.com/voxpupuli/puppet-alternatives/pull/114) ([smortex](https://github.com/smortex)) 92 | - renamed provider to fit current status of alternative usage in distributions / Add SLES12/15 support [\#101](https://github.com/voxpupuli/puppet-alternatives/pull/101) ([pseiler](https://github.com/pseiler)) 93 | - add Debian working versions to metadata [\#97](https://github.com/voxpupuli/puppet-alternatives/pull/97) ([trefzer](https://github.com/trefzer)) 94 | 95 | **Closed issues:** 96 | 97 | - SLES 12 and 15 do not work with puppet-alternatives [\#105](https://github.com/voxpupuli/puppet-alternatives/issues/105) 98 | - check debian support [\#78](https://github.com/voxpupuli/puppet-alternatives/issues/78) 99 | 100 | **Merged pull requests:** 101 | 102 | - Remove duplicate CONTRIBUTING.md file [\#99](https://github.com/voxpupuli/puppet-alternatives/pull/99) ([dhoppe](https://github.com/dhoppe)) 103 | 104 | ## [v3.0.0](https://github.com/voxpupuli/puppet-alternatives/tree/v3.0.0) (2019-03-03) 105 | 106 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v2.1.0...v3.0.0) 107 | 108 | **Breaking changes:** 109 | 110 | - modulesync 2.5.1 & drop Puppet 4 [\#92](https://github.com/voxpupuli/puppet-alternatives/pull/92) ([bastelfreak](https://github.com/bastelfreak)) 111 | 112 | **Fixed bugs:** 113 | 114 | - handle broken alternatives entries more gracefully [\#91](https://github.com/voxpupuli/puppet-alternatives/pull/91) ([fraenki](https://github.com/fraenki)) 115 | - Fix mode detection for rpm provider [\#87](https://github.com/voxpupuli/puppet-alternatives/pull/87) ([treydock](https://github.com/treydock)) 116 | 117 | **Closed issues:** 118 | 119 | - Could not determine auto or manual mode [\#80](https://github.com/voxpupuli/puppet-alternatives/issues/80) 120 | - missing alternatives is not added - it breaks instead [\#54](https://github.com/voxpupuli/puppet-alternatives/issues/54) 121 | 122 | ## [v2.1.0](https://github.com/voxpupuli/puppet-alternatives/tree/v2.1.0) (2018-10-14) 123 | 124 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v2.0.1...v2.1.0) 125 | 126 | **Implemented enhancements:** 127 | 128 | - seting multiple alternatives to the same path [\#41](https://github.com/voxpupuli/puppet-alternatives/issues/41) 129 | 130 | **Fixed bugs:** 131 | 132 | - alternative\_entry keying to the wrong parameter? [\#40](https://github.com/voxpupuli/puppet-alternatives/issues/40) 133 | - Added namevar to altlink to create a composite namevar name:altlink. [\#75](https://github.com/voxpupuli/puppet-alternatives/pull/75) ([Raskil](https://github.com/Raskil)) 134 | 135 | **Merged pull requests:** 136 | 137 | - modulesync 2.1.0 and allow puppet 6.x [\#85](https://github.com/voxpupuli/puppet-alternatives/pull/85) ([Dan33l](https://github.com/Dan33l)) 138 | - Remove docker nodesets [\#79](https://github.com/voxpupuli/puppet-alternatives/pull/79) ([bastelfreak](https://github.com/bastelfreak)) 139 | - drop EOL OSs; fix puppet version range [\#76](https://github.com/voxpupuli/puppet-alternatives/pull/76) ([bastelfreak](https://github.com/bastelfreak)) 140 | 141 | ## [v2.0.1](https://github.com/voxpupuli/puppet-alternatives/tree/v2.0.1) (2018-04-03) 142 | 143 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v2.0.0...v2.0.1) 144 | 145 | **Merged pull requests:** 146 | 147 | - bump puppet to latest supported version 4.10.0 [\#73](https://github.com/voxpupuli/puppet-alternatives/pull/73) ([bastelfreak](https://github.com/bastelfreak)) 148 | - Add support for Puppet 5 [\#69](https://github.com/voxpupuli/puppet-alternatives/pull/69) ([juniorsysadmin](https://github.com/juniorsysadmin)) 149 | 150 | ## [v2.0.0](https://github.com/voxpupuli/puppet-alternatives/tree/v2.0.0) (2017-11-15) 151 | 152 | [Full Changelog](https://github.com/voxpupuli/puppet-alternatives/compare/v1.1.0...v2.0.0) 153 | 154 | **Closed issues:** 155 | 156 | - plugin sync error? [\#39](https://github.com/voxpupuli/puppet-alternatives/issues/39) 157 | - How does one set alternative entry back to 'auto' mode? [\#32](https://github.com/voxpupuli/puppet-alternatives/issues/32) 158 | 159 | **Merged pull requests:** 160 | 161 | - Fix github license detection [\#62](https://github.com/voxpupuli/puppet-alternatives/pull/62) ([alexjfisher](https://github.com/alexjfisher)) 162 | 163 | ## [v1.1.0](https://github.com/voxpupuli/puppet-alternatives/tree/v1.1.0) (2017-02-10) 164 | 165 | This is the last release with Puppet3 support! 166 | * Modulesync with latest Vox Pupuli defaults 167 | 168 | ## 2016-12-25 Release 1.0.2 169 | 170 | * Modulesync with latest Vox Pupuli defaults 171 | * Fix ALT_RPM_QUERY_REGEX to catch all entries and not only the default ones 172 | * Add Spectest for rpm provider 173 | 174 | ## 2016-08-12 Release 1.0.1 175 | 176 | * Modulesync with latest Vox Pupuli defaults 177 | * Drop of ruby183 support 178 | * new aternative_entry with rpm provider 179 | * Enable explicitly setting mode property to manual 180 | * First release under the Voxpupuli namespace! Migrated from Adrien Thebo 181 | * Rerelease of 1.0.0, which didn't make it to the forge 182 | 183 | 184 | ## 2014-12-19 Release 0.3.0 185 | 186 | * New RPM based providers for alternatives and alternative_entry 187 | * Debian based distributions use `update-alternatives` based on $PATH 188 | * The alternatives type now autorequires matching alternate_entry types 189 | * dpkg provider explicitly sets the mode property to manual 190 | * alternative_entry can check for alernative entries for a non-existent entry 191 | 192 | 193 | ## 2014-08-21 Release 0.2.0 194 | 195 | * New type: alternative_entry 196 | * The alternatives type now has the `mode` property to use the automatic 197 | option for a given alternative. 198 | * The update-alternatives binary is no longer hardcoded to use 199 | /usr/sbin/update-alternatives 200 | 201 | ### Thanks 202 | 203 | Thanks to Michael Moll and jakov Sosic for their work on this release. 204 | 205 | 206 | ## 2013-07-16 Release 0.1.1 207 | 208 | This is a backwards compatible bugfix release. 209 | 210 | * Module rebuilt with correct permissions. 211 | 212 | 213 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 214 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 5 | 6 | group :test do 7 | gem 'voxpupuli-test', '~> 9.0', :require => false 8 | gem 'coveralls', :require => false 9 | gem 'simplecov-console', :require => false 10 | gem 'puppet_metadata', '~> 5.0', :require => false 11 | end 12 | 13 | group :development do 14 | gem 'guard-rake', :require => false 15 | gem 'overcommit', '>= 0.39.1', :require => false 16 | end 17 | 18 | group :system_tests do 19 | gem 'voxpupuli-acceptance', '~> 3.5', :require => false 20 | end 21 | 22 | group :release do 23 | gem 'voxpupuli-release', '~> 3.0', :require => false 24 | end 25 | 26 | gem 'rake', :require => false 27 | gem 'facter', ENV['FACTER_GEM_VERSION'], :require => false, :groups => [:test] 28 | 29 | puppetversion = ENV['PUPPET_GEM_VERSION'] || [">= 7.24", "< 9"] 30 | gem 'puppet', puppetversion, :require => false, :groups => [:test] 31 | 32 | # vim: syntax=ruby 33 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | ## [v1.1.0](https://github.com/voxpupuli/puppet-alternatives/tree/v1.1.0) (2017-02-10) 2 | 3 | This is the last release with Puppet3 support! 4 | * Modulesync with latest Vox Pupuli defaults 5 | 6 | ## 2016-12-25 Release 1.0.2 7 | 8 | * Modulesync with latest Vox Pupuli defaults 9 | * Fix ALT_RPM_QUERY_REGEX to catch all entries and not only the default ones 10 | * Add Spectest for rpm provider 11 | 12 | ## 2016-08-12 Release 1.0.1 13 | 14 | * Modulesync with latest Vox Pupuli defaults 15 | * Drop of ruby183 support 16 | * new aternative_entry with rpm provider 17 | * Enable explicitly setting mode property to manual 18 | * First release under the Voxpupuli namespace! Migrated from Adrien Thebo 19 | * Rerelease of 1.0.0, which didn't make it to the forge 20 | 21 | 22 | ## 2014-12-19 Release 0.3.0 23 | 24 | * New RPM based providers for alternatives and alternative_entry 25 | * Debian based distributions use `update-alternatives` based on $PATH 26 | * The alternatives type now autorequires matching alternate_entry types 27 | * dpkg provider explicitly sets the mode property to manual 28 | * alternative_entry can check for alernative entries for a non-existent entry 29 | 30 | 31 | ## 2014-08-21 Release 0.2.0 32 | 33 | * New type: alternative_entry 34 | * The alternatives type now has the `mode` property to use the automatic 35 | option for a given alternative. 36 | * The update-alternatives binary is no longer hardcoded to use 37 | /usr/sbin/update-alternatives 38 | 39 | ### Thanks 40 | 41 | Thanks to Michael Moll and jakov Sosic for their work on this release. 42 | 43 | 44 | ## 2013-07-16 Release 0.1.1 45 | 46 | This is a backwards compatible bugfix release. 47 | 48 | * Module rebuilt with correct permissions. 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Adrien Thebo 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # puppet-alternatives 2 | 3 | [![Build Status](https://github.com/voxpupuli/puppet-alternatives/workflows/CI/badge.svg)](https://github.com/voxpupuli/puppet-alternatives/actions?query=workflow%3ACI) 4 | [![Release](https://github.com/voxpupuli/puppet-alternatives/actions/workflows/release.yml/badge.svg)](https://github.com/voxpupuli/puppet-alternatives/actions/workflows/release.yml) 5 | [![Puppet Forge](https://img.shields.io/puppetforge/v/puppet/alternatives.svg)](https://forge.puppetlabs.com/puppet/alternatives) 6 | [![Puppet Forge - downloads](https://img.shields.io/puppetforge/dt/puppet/alternatives.svg)](https://forge.puppetlabs.com/puppet/alternatives) 7 | [![Puppet Forge - endorsement](https://img.shields.io/puppetforge/e/puppet/alternatives.svg)](https://forge.puppetlabs.com/puppet/alternatives) 8 | [![Puppet Forge - scores](https://img.shields.io/puppetforge/f/puppet/alternatives.svg)](https://forge.puppetlabs.com/puppet/alternatives) 9 | [![puppetmodule.info docs](https://www.puppetmodule.info/images/badge.svg)](https://www.puppetmodule.info/m/puppet-alternatives) 10 | [![Apache-2.0 License](https://img.shields.io/github/license/voxpupuli/puppet-alternatives.svg)](LICENSE) 11 | [![Donated by Camptocamp](https://img.shields.io/badge/donated%20by-camptocamp-fb7047.svg)](#transfer-notice) 12 | 13 | Manage alternatives symlinks. 14 | 15 | ## Synopsis 16 | 17 | Using `puppet resource` to inspect alternatives 18 | 19 | root@master:~# puppet resource alternatives 20 | alternatives { 'aptitude': 21 | path => '/usr/bin/aptitude-curses', 22 | } 23 | alternatives { 'awk': 24 | path => '/usr/bin/mawk', 25 | } 26 | alternatives { 'builtins.7.gz': 27 | path => '/usr/share/man/man7/bash-builtins.7.gz', 28 | } 29 | alternatives { 'c++': 30 | path => '/usr/bin/g++', 31 | } 32 | alternatives { 'c89': 33 | path => '/usr/bin/c89-gcc', 34 | } 35 | alternatives { 'c99': 36 | path => '/usr/bin/c99-gcc', 37 | } 38 | alternatives { 'cc': 39 | path => '/usr/bin/gcc', 40 | } 41 | 42 | - - - 43 | 44 | Using `puppet resource` to update an alternative 45 | 46 | root@master:~# puppet resource alternatives editor 47 | alternatives { 'editor': 48 | path => '/bin/nano', 49 | } 50 | root@master:~# puppet resource alternatives editor path=/usr/bin/vim.tiny 51 | notice: /Alternatives[editor]/path: path changed '/bin/nano' to '/usr/bin/vim.tiny' 52 | alternatives { 'editor': 53 | path => '/usr/bin/vim.tiny', 54 | } 55 | 56 | - - - 57 | 58 | Using the alternatives resource in a manifest: 59 | 60 | ```puppet 61 | class ruby_193 { 62 | 63 | package { 'ruby1.9.3': 64 | ensure => present, 65 | } 66 | 67 | # Will also update gem, irb, rdoc, rake, etc. 68 | alternatives { 'ruby': 69 | path => '/usr/bin/ruby1.9.3', 70 | require => Package['ruby1.9.3'], 71 | } 72 | } 73 | 74 | include ruby_193 75 | ``` 76 | 77 | - - - 78 | 79 | Creating a new alternative entry: 80 | 81 | ```puppet 82 | alternative_entry { '/usr/bin/gcc-4.4': 83 | ensure => present, 84 | altlink => '/usr/bin/gcc', 85 | altname => 'gcc', 86 | priority => 10, 87 | require => Package['gcc-4.4-multilib'], 88 | } 89 | ``` 90 | 91 | - - - 92 | 93 | On RedHat, configuring an alternative using a family instead of a full path: 94 | 95 | ```puppet 96 | alternatives { 'java': 97 | path => 'java-1.8.0-openjdk.x86_64', 98 | require => Package['java-1.8.0-openjdk'], 99 | } 100 | ``` 101 | 102 | This module should work on any Debian and RHEL based distribution. 103 | 104 | ## Transfer notice 105 | 106 | This module was formerly maintained by Adrien Thebo at [forge.puppet.com/adrien/alternatives/](https://forge.puppet.com/modules/adrien/alternatives/readme) 107 | 108 | ## Contact 109 | 110 | * [Source code](https://github.com/voxpupuli/puppet-alternatives) 111 | * [Issue tracker](https://github.com/voxpupuli/puppet-alternatives/issues) 112 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | # Attempt to load voxpupuli-test (which pulls in puppetlabs_spec_helper), 5 | # otherwise attempt to load it directly. 6 | begin 7 | require 'voxpupuli/test/rake' 8 | rescue LoadError 9 | begin 10 | require 'puppetlabs_spec_helper/rake_tasks' 11 | rescue LoadError 12 | end 13 | end 14 | 15 | # load optional tasks for acceptance 16 | # only available if gem group releases is installed 17 | begin 18 | require 'voxpupuli/acceptance/rake' 19 | rescue LoadError 20 | end 21 | 22 | # load optional tasks for releases 23 | # only available if gem group releases is installed 24 | begin 25 | require 'voxpupuli/release/rake_tasks' 26 | rescue LoadError 27 | # voxpupuli-release not present 28 | else 29 | GCGConfig.user = 'voxpupuli' 30 | GCGConfig.project = 'puppet-alternatives' 31 | end 32 | 33 | desc "Run main 'test' task and report merged results to coveralls" 34 | task test_with_coveralls: [:test] do 35 | if Dir.exist?(File.expand_path('../lib', __FILE__)) 36 | require 'coveralls/rake/task' 37 | Coveralls::RakeTask.new 38 | Rake::Task['coveralls:push'].invoke 39 | else 40 | puts 'Skipping reporting to coveralls. Module has no lib dir' 41 | end 42 | end 43 | 44 | # vim: syntax=ruby 45 | -------------------------------------------------------------------------------- /lib/puppet/provider/alternative_entry/chkconfig.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.type(:alternative_entry).provide(:chkconfig) do 4 | confine 'os.family' => :redhat 5 | defaultfor 'os.family' => :redhat 6 | 7 | commands update: '/usr/sbin/alternatives' 8 | 9 | mk_resource_methods 10 | 11 | def create 12 | update('--install', 13 | @resource.value(:altlink), 14 | @resource.value(:altname), 15 | @resource.value(:name), 16 | @resource.value(:priority)) 17 | end 18 | 19 | def exists? 20 | @property_hash[:ensure] == :present 21 | end 22 | 23 | def destroy 24 | update('--remove', @resource.value(:altname), @resource.value(:name)) 25 | rescue StandardError # rubocop:disable Lint/SuppressedException 26 | end 27 | 28 | def self.instances 29 | output = Dir.glob('/var/lib/alternatives/*').map { |x| File.basename(x) } 30 | 31 | entries = [] 32 | 33 | output.each do |altname| 34 | query_alternative(altname).each do |alt| 35 | entries << new(alt) unless alt.empty? 36 | end 37 | end 38 | entries 39 | end 40 | 41 | def self.prefetch(resources) 42 | catalog = resources.values.first.catalog 43 | instances.each do |prov| 44 | catalog.resources.each do |item| 45 | item.provider = prov if item.instance_of?(Puppet::Type::Alternative_entry) && item.name == prov.name && item.parameter('altlink').value == prov.altlink 46 | end 47 | end 48 | end 49 | 50 | ALT_RPM_QUERY_REGEX = %r{^(.*/[^/]*) -.*priority (\w+)$}.freeze # rubocop:disable Lint/ConstantDefinitionInBlock 51 | 52 | def self.query_alternative(altname) 53 | output = update('--display', altname) 54 | altlink = File.readlines("/var/lib/alternatives/#{altname}")[1].chomp 55 | output.scan(ALT_RPM_QUERY_REGEX).map do |(path, priority)| 56 | { altname: altname, altlink: altlink, name: path, priority: priority, altlink_ro: altlink, ensure: :present } 57 | end 58 | rescue StandardError 59 | Puppet.warning format(_('Failed to parse alternatives entry %{name}'), name: name) 60 | {} 61 | end 62 | 63 | def name=(new_name) 64 | rebuild do 65 | @property_hash[:name] = new_name 66 | end 67 | end 68 | 69 | def altname=(new_altname) 70 | rebuild do 71 | @property_hash[:altname] = new_altname 72 | end 73 | end 74 | 75 | def altlink=(new_altlink) 76 | rebuild do 77 | @property_hash[:altlink] = new_altlink 78 | end 79 | end 80 | 81 | def priority=(new_priority) 82 | rebuild do 83 | @property_hash[:priority] = new_priority 84 | end 85 | end 86 | 87 | private 88 | 89 | def rebuild(&_block) 90 | destroy 91 | yield 92 | create 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /lib/puppet/provider/alternative_entry/dpkg.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.type(:alternative_entry).provide(:dpkg) do 4 | confine 'os.family' => %i[debian suse] 5 | defaultfor ['os.name' => %i[debian ubuntu], 'os.family' => :suse] 6 | 7 | commands update: 'update-alternatives' 8 | 9 | mk_resource_methods 10 | 11 | def create 12 | update('--install', 13 | @resource.value(:altlink), 14 | @resource.value(:altname), 15 | @resource.value(:name), 16 | @resource.value(:priority)) 17 | end 18 | 19 | def exists? 20 | # we cannot fetch @resource.value(:altname) if running 'puppet resource alternative_entry' 21 | begin 22 | output = update('--list', @resource.value(:altname) || altname) 23 | rescue StandardError 24 | return false 25 | end 26 | 27 | output.split(%r{\n}).map(&:strip).any? do |line| 28 | line == @resource.value(:name) 29 | end 30 | end 31 | 32 | def destroy 33 | update('--remove', @resource.value(:altname), @resource.value(:name)) 34 | end 35 | 36 | def self.instances 37 | output = update('--get-selections') 38 | 39 | entries = [] 40 | 41 | output.each_line do |line| 42 | altname = line.split(%r{\s+}).first 43 | query_alternative(altname).each do |alt| 44 | entries << new(alt) 45 | end 46 | end 47 | 48 | entries 49 | end 50 | 51 | def self.prefetch(resources) 52 | catalog = resources.values.first.catalog 53 | instances.each do |prov| 54 | catalog.resources.each do |item| 55 | item.provider = prov if item.instance_of?(Puppet::Type::Alternative_entry) && item.name == prov.name && item.parameter('altlink').value == prov.altlink 56 | end 57 | end 58 | end 59 | 60 | ALT_QUERY_REGEX = %r{Alternative: (.*?)$.Priority: (.*?)$}m.freeze # rubocop:disable Lint/ConstantDefinitionInBlock 61 | 62 | def self.query_alternative(altname) 63 | output = update('--query', altname) 64 | 65 | altlink = output.match(%r{Link: (.*)$})[1] 66 | 67 | output.scan(ALT_QUERY_REGEX).map do |(path, priority)| 68 | { altname: altname, altlink: altlink, name: path, priority: priority } 69 | end 70 | end 71 | 72 | def name=(new_name) 73 | rebuild do 74 | @property_hash[:name] = new_name 75 | end 76 | end 77 | 78 | def altname=(new_altname) 79 | rebuild do 80 | @property_hash[:altname] = new_altname 81 | end 82 | end 83 | 84 | def altlink=(new_altlink) 85 | rebuild do 86 | @property_hash[:altlink] = new_altlink 87 | end 88 | end 89 | 90 | def priority=(new_priority) 91 | rebuild do 92 | @property_hash[:priority] = new_priority 93 | end 94 | end 95 | 96 | private 97 | 98 | def rebuild(&_block) 99 | destroy 100 | yield 101 | create 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /lib/puppet/provider/alternatives/chkconfig.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.type(:alternatives).provide(:chkconfig) do 4 | confine 'os.family' => :redhat 5 | defaultfor 'os.family' => :redhat 6 | 7 | commands update: 'alternatives' 8 | 9 | has_feature :mode 10 | 11 | # Return all instances for this provider 12 | # 13 | # @return [Array] A list of all current provider instances 14 | def self.instances 15 | all.map { |name, attributes| new(name: name, path: attributes[:path]) } 16 | end 17 | 18 | def self.list_alternatives 19 | Dir.glob('/var/lib/alternatives/*') 20 | end 21 | 22 | ALT_RPM_QUERY_CURRENT_REGEX = %r{status is (\w+)\.\n\slink currently points to (.*/[^/]*)\n}.freeze # rubocop:disable Lint/ConstantDefinitionInBlock 23 | 24 | # Generate a hash of hashes containing a link name and associated properties 25 | # 26 | # This is structured as {'key' => {attributes}} to do fast lookups on entries 27 | # 28 | # @return [Hash>] 29 | def self.all 30 | hash = {} 31 | list_alternatives.map { |x| File.basename(x) }.each do |name| 32 | output = update('--display', name) 33 | mode = output.match(ALT_RPM_QUERY_CURRENT_REGEX)[1] 34 | path = output.match(ALT_RPM_QUERY_CURRENT_REGEX)[2] 35 | hash[name] = { path: path, mode: mode } 36 | if (matches = output.match(%r{^#{path} - family (.+) priority \d+$})) 37 | hash[name][:family] = matches[1] 38 | end 39 | rescue StandardError 40 | Puppet.warning format(_('Failed to parse alternatives entry %{name}'), name: name) 41 | end 42 | hash 43 | end 44 | 45 | def family 46 | name = @resource.value(:name) 47 | self.class.all[name][:family] 48 | end 49 | 50 | # Retrieve the current path link 51 | def path 52 | name = @resource.value(:name) 53 | self.class.all[name][:path] 54 | end 55 | 56 | # @param [String] newpath The path to use as the new alternative link 57 | def path=(newpath) 58 | name = @resource.value(:name) 59 | update('--set', name, newpath) 60 | end 61 | 62 | # @return [String] The alternative mode 63 | def mode 64 | output = update('--display', @resource.value(:name)) 65 | first = output.split("\n").first 66 | 67 | case first 68 | when %r{auto mode}, %r{status is auto} 69 | 'auto' 70 | when %r{manual mode}, %r{status is manual} 71 | 'manual' 72 | else 73 | raise Puppet::Error, "Could not determine if #{self} is in auto or manual mode" 74 | end 75 | end 76 | 77 | # Set the mode to manual or auto. 78 | # @param [Symbol] newmode Either :auto or :manual for the alternatives mode 79 | def mode=(newmode) 80 | case newmode 81 | when :auto 82 | update('--auto', @resource.value(:name)) 83 | when :manual 84 | # No change in value, but sets it to manual 85 | update('--set', name, path) 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/puppet/provider/alternatives/dpkg.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.type(:alternatives).provide(:dpkg) do 4 | confine 'os.family' => %i[debian suse] 5 | defaultfor ['os.name' => %i[debian ubuntu], 'os.family' => :suse] 6 | commands update: 'update-alternatives' 7 | 8 | has_feature :mode 9 | 10 | # Return all instances for this provider 11 | # 12 | # @return [Array] A list of all current provider instances 13 | def self.instances 14 | all.map { |name, attributes| new(name: name, path: attributes[:path]) } 15 | end 16 | 17 | # Generate a hash of hashes containing a link name and associated properties 18 | # 19 | # This is structured as {'key' => {attributes}} to do fast lookups on entries 20 | # 21 | # @return [Hash>] 22 | def self.all 23 | output = update('--get-selections') 24 | # Ruby 1.8.7 does not have each_with_object 25 | # rubocop:disable Style/EachWithObject 26 | output.split(%r{\n}).reduce({}) do |hash, line| 27 | # rubocop:enable Style/EachWithObject 28 | name, mode, path = line.split(%r{\s+}) 29 | hash[name] = { path: path, mode: mode } 30 | hash 31 | end 32 | end 33 | 34 | # Retrieve the current path link 35 | def path 36 | name = @resource.value(:name) 37 | # rubocop:disable Style/GuardClause 38 | if (attrs = self.class.all[name]) 39 | # rubocop:enable Style/GuardClause 40 | attrs[:path] 41 | end 42 | end 43 | 44 | # @param [String] newpath The path to use as the new alternative link 45 | def path=(newpath) 46 | name = @resource.value(:name) 47 | update('--set', name, newpath) 48 | end 49 | 50 | # @return [String] The alternative mode 51 | def mode 52 | output = update('--display', @resource.value(:name)) 53 | first = output.split("\n").first 54 | 55 | case first 56 | when %r{auto mode} 57 | 'auto' 58 | when %r{manual mode} 59 | 'manual' 60 | else 61 | raise Puppet::Error, "Could not determine if #{self} is in auto or manual mode" 62 | end 63 | end 64 | 65 | # Set the mode to manual or auto. 66 | # @param [Symbol] newmode Either :auto or :manual for the alternatives mode 67 | def mode=(newmode) 68 | case newmode 69 | when :auto 70 | update('--auto', @resource.value(:name)) 71 | when :manual 72 | # No change in value, but sets it to manual 73 | update('--set', name, path) 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /lib/puppet/type/alternative_entry.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:alternative_entry) do 4 | ensurable 5 | 6 | newparam(:name) do 7 | desc 'The path to the actual alternative' 8 | 9 | isnamevar 10 | 11 | validate do |path| 12 | raise ArgumentError, 'path must be a fully qualified path' unless absolute_path? path 13 | end 14 | end 15 | 16 | newparam(:altlink) do 17 | desc 'The name of the generic symlink for this alternative entry' 18 | 19 | isnamevar 20 | 21 | validate do |path| 22 | raise ArgumentError, 'path must be a fully qualified path' unless absolute_path? path 23 | end 24 | end 25 | 26 | newproperty(:altlink_ro, readonly: true) do 27 | desc 'The name of the generic symlink for this alternative entry as parameter. This is readonly.' 28 | end 29 | 30 | newproperty(:altname) do 31 | desc 'The name of symlink in the alternatives directory' 32 | end 33 | 34 | newproperty(:priority) do 35 | desc 'The value of the priority of this alternative' 36 | 37 | validate do |prio| 38 | Integer(prio) 39 | rescue StandardError 40 | raise ArgumentError, 'priority must be an integer' 41 | end 42 | end 43 | 44 | def self.title_patterns 45 | [ 46 | [ 47 | %r{^([^:]+)$}, 48 | [ 49 | [:name] 50 | ] 51 | ], 52 | [ 53 | %r{^(.*):([a-z]:(/|\\).*)$}i, 54 | [ 55 | [:name], 56 | [:altlink] 57 | ] 58 | ], 59 | [ 60 | %r{^(.*):(.*)$}, 61 | [ 62 | [:name], 63 | [:altlink] 64 | ] 65 | ] 66 | ] 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/puppet/type/alternatives.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Puppet::Type.newtype(:alternatives) do 4 | feature :mode, 'The alternative can provide auto and manual modes' 5 | 6 | newparam(:name, isnamevar: true) do 7 | desc 'The name of the alternative.' 8 | end 9 | 10 | newproperty(:path) do 11 | desc 'The path of the desired source for the given alternative. On RedHat, a family can be specified instead' 12 | 13 | def insync?(is) 14 | if absolute_path? should 15 | is == should 16 | else 17 | provider.family == should 18 | end 19 | end 20 | 21 | validate do |path| 22 | raise ArgumentError, 'path must be a fully qualified path' unless (absolute_path? path) || (Facter.value('os.family') == 'RedHat') 23 | end 24 | end 25 | 26 | newproperty(:mode, required_features: [:mode]) do 27 | desc 'Use the automatic option for this alternative' 28 | 29 | newvalue('auto') 30 | newvalue('manual') 31 | end 32 | 33 | validate do 34 | case self[:mode] 35 | when :auto 36 | raise Puppet::Error, "Mode cannot be 'auto' if a path is given" if self[:path] 37 | when :manual 38 | raise Puppet::Error, "Mode cannot be 'manual' without a path" unless self[:path] 39 | end 40 | end 41 | 42 | autorequire(:alternative_entry) do 43 | self[:path] 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppet-alternatives", 3 | "version": "6.0.1-rc0", 4 | "author": "Vox Pupuli", 5 | "summary": "Maintain symbolic links determining default commands", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/voxpupuli/puppet-alternatives", 8 | "project_page": "https://github.com/voxpupuli/puppet-alternatives", 9 | "issues_url": "https://github.com/voxpupuli/puppet-alternatives", 10 | "operatingsystem_support": [ 11 | { 12 | "operatingsystem": "Debian", 13 | "operatingsystemrelease": [ 14 | "11", 15 | "12" 16 | ] 17 | }, 18 | { 19 | "operatingsystem": "Ubuntu", 20 | "operatingsystemrelease": [ 21 | "20.04", 22 | "22.04", 23 | "24.04" 24 | ] 25 | }, 26 | { 27 | "operatingsystem": "RedHat", 28 | "operatingsystemrelease": [ 29 | "8", 30 | "9" 31 | ] 32 | }, 33 | { 34 | "operatingsystem": "CentOS", 35 | "operatingsystemrelease": [ 36 | "9" 37 | ] 38 | }, 39 | { 40 | "operatingsystem": "OracleLinux", 41 | "operatingsystemrelease": [ 42 | "8" 43 | ] 44 | }, 45 | { 46 | "operatingsystem": "SLES", 47 | "operatingsystemrelease": [ 48 | "12 SP4", 49 | "15 SP1" 50 | ] 51 | }, 52 | { 53 | "operatingsystem": "AlmaLinux", 54 | "operatingsystemrelease": [ 55 | "8", 56 | "9" 57 | ] 58 | }, 59 | { 60 | "operatingsystem": "Rocky", 61 | "operatingsystemrelease": [ 62 | "8", 63 | "9" 64 | ] 65 | } 66 | ], 67 | "requirements": [ 68 | { 69 | "name": "puppet", 70 | "version_requirement": ">= 7.0.0 < 9.0.0" 71 | }, 72 | { 73 | "name": "openvox", 74 | "version_requirement": ">= 7.0.0 < 9.0.0" 75 | } 76 | ], 77 | "dependencies": [ 78 | 79 | ] 80 | } 81 | -------------------------------------------------------------------------------- /spec/acceptance/alternatives_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'alternatives type' do 6 | let(:pp) do 7 | <<-PP 8 | # Note that debian 10 & 11 do not have a merged /bin & /usr/bin. 9 | alternative_entry {'/usr/bin/yes': 10 | ensure => present, 11 | altlink => '/usr/bin/dne', 12 | altname => 'dne', 13 | priority => 10, 14 | } 15 | 16 | alternative_entry {'/usr/bin/toe': 17 | ensure => present, 18 | altlink => '/usr/bin/dne', 19 | altname => 'dne', 20 | priority => 20, 21 | } 22 | 23 | alternative_entry {'/usr/bin/wc': 24 | ensure => present, 25 | altlink => '/usr/bin/dne', 26 | altname => 'dne', 27 | priority => 30, 28 | } 29 | 30 | Alternative_entry<| |> 31 | -> alternatives { 'dne': 32 | path => '/usr/bin/toe', 33 | } 34 | PP 35 | end 36 | 37 | it_behaves_like 'an idempotent resource' 38 | 39 | describe file('/usr/bin/dne') do 40 | it { is_expected.to be_symlink } 41 | it { is_expected.to be_owned_by 'root' } 42 | it { is_expected.to be_grouped_into 'root' } 43 | it { is_expected.to be_linked_to '/etc/alternatives/dne' } 44 | end 45 | 46 | describe file('/etc/alternatives/dne') do 47 | it { is_expected.to be_symlink } 48 | it { is_expected.to be_owned_by 'root' } 49 | it { is_expected.to be_grouped_into 'root' } 50 | it { is_expected.to be_linked_to '/usr/bin/toe' } 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/acceptance/family_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | if os[:family] == 'redhat' 6 | describe 'setting alternatives with a `family`' do 7 | context 'java 8' do 8 | let(:pp) do 9 | <<-PP 10 | package { ['java-1.8.0-openjdk','java-11-openjdk']: 11 | ensure => installed, 12 | before => Alternatives['java'], 13 | } 14 | 15 | alternatives { 'java': 16 | path => 'java-1.8.0-openjdk.x86_64', 17 | } 18 | PP 19 | end 20 | 21 | it_behaves_like 'an idempotent resource' 22 | 23 | describe command('java -version') do 24 | its(:stderr) { is_expected.to match %r{1\.8\.0} } 25 | end 26 | end 27 | 28 | context 'java 11' do 29 | let(:pp) do 30 | <<-PP 31 | package { ['java-1.8.0-openjdk','java-11-openjdk']: 32 | ensure => installed, 33 | before => Alternatives['java'], 34 | } 35 | 36 | alternatives { 'java': 37 | path => 'java-11-openjdk.x86_64', 38 | } 39 | PP 40 | end 41 | 42 | it_behaves_like 'an idempotent resource' 43 | 44 | describe command('java -version') do 45 | its(:stderr) { is_expected.to match %r{11\.0} } 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/fixtures/unit/provider/alternatives/chkconfig/alternatives/sample: -------------------------------------------------------------------------------- 1 | manual 2 | /usr/bin/sample 3 | 4 | /opt/sample1 5 | 10 6 | /opt/sample2 7 | 20 8 | /opt/sample3 9 | 30 -------------------------------------------------------------------------------- /spec/fixtures/unit/provider/alternatives/chkconfig/alternatives/testcmd: -------------------------------------------------------------------------------- 1 | manual 2 | /usr/bin/testcmd 3 | 4 | /opt/testcmd1 5 | 10 6 | /opt/testcmd2 7 | 20 -------------------------------------------------------------------------------- /spec/fixtures/unit/provider/alternatives/chkconfig/display/sample: -------------------------------------------------------------------------------- 1 | sample - status is manual. 2 | link currently points to /opt/sample2 3 | /opt/sample1 - priority 10 4 | /opt/sample2 - priority 20 5 | Current `best' version is /opt/sample2. -------------------------------------------------------------------------------- /spec/fixtures/unit/provider/alternatives/chkconfig/display/testcmd: -------------------------------------------------------------------------------- 1 | testcmd - status is manual. 2 | link currently points to /opt/testcmd1 3 | /opt/testcmd1 - priority 10 4 | /opt/testcmd2 - priority 20 5 | Current `best' version is /opt/testcmd2. -------------------------------------------------------------------------------- /spec/fixtures/unit/provider/alternatives/dpkg/get-selections: -------------------------------------------------------------------------------- 1 | aptitude auto /usr/bin/aptitude-curses 2 | awk auto /usr/bin/mawk 3 | builtins.7.gz auto /usr/share/man/man7/bash-builtins.7.gz 4 | c++ auto /usr/bin/g++ 5 | c89 auto /usr/bin/c89-gcc 6 | c99 auto /usr/bin/c99-gcc 7 | cc auto /usr/bin/gcc 8 | cpp auto /usr/bin/cpp 9 | editor manual /usr/bin/vim.tiny 10 | ex auto /usr/bin/vim.basic 11 | fakeroot auto /usr/bin/fakeroot-sysv 12 | from auto /usr/bin/bsd-from 13 | ftp auto /usr/bin/netkit-ftp 14 | gem auto /usr/bin/gem1.9.1 15 | infobrowser auto /usr/bin/info 16 | lft auto /usr/bin/lft.db 17 | locate auto /usr/bin/mlocate 18 | lzma auto /usr/bin/xz 19 | mailx auto /usr/bin/bsd-mailx 20 | mt auto /bin/mt-gnu 21 | mutt auto /usr/bin/mutt-org 22 | nc auto /bin/nc.traditional 23 | pager auto /bin/less 24 | pico auto /bin/nano 25 | rcp auto /usr/bin/scp 26 | rename auto /usr/bin/prename 27 | rlogin auto /usr/bin/slogin 28 | rmt auto /usr/sbin/rmt-tar 29 | rsh auto /usr/bin/ssh 30 | ruby auto /usr/bin/ruby1.9.1 31 | rview auto /usr/bin/vim.basic 32 | rvim auto /usr/bin/vim.basic 33 | tcptraceroute auto /usr/sbin/tcptraceroute.db 34 | telnet auto /usr/bin/telnet.netkit 35 | traceproto auto /usr/bin/traceproto.db 36 | traceroute auto /usr/bin/traceroute.db 37 | traceroute6 auto /usr/bin/traceroute6.db 38 | vi auto /usr/bin/vim.basic 39 | view auto /usr/bin/vim.basic 40 | vim auto /usr/bin/vim.basic 41 | vimdiff auto /usr/bin/vim.basic 42 | w auto /usr/bin/w.procps 43 | write auto /usr/bin/bsd-write 44 | www-browser auto /usr/bin/w3m 45 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | dir = File.expand_path(File.join(File.dirname(__FILE__), '..')) 4 | $LOAD_PATH.unshift(dir, "#{dir}lib", "#{dir}../lib") 5 | 6 | require 'mocha/api' 7 | require 'puppet' 8 | 9 | if Dir.exist?(File.expand_path('../lib', __dir__)) && RUBY_VERSION !~ %r{^1.9} 10 | require 'coveralls' 11 | require 'simplecov' 12 | require 'simplecov-console' 13 | SimpleCov.formatters = [ 14 | SimpleCov::Formatter::HTMLFormatter, 15 | SimpleCov::Formatter::Console, 16 | Coveralls::SimpleCov::Formatter 17 | ] 18 | SimpleCov.start do 19 | track_files 'lib/**/*.rb' 20 | add_filter '/spec' 21 | add_filter '/vendor' 22 | add_filter '/.vendor' 23 | end 24 | end 25 | 26 | PROJECT_ROOT = File.expand_path('..', File.dirname(__FILE__)) 27 | 28 | RSpec.configure do |config| 29 | config.mock_with :mocha 30 | end 31 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'voxpupuli/acceptance/spec_helper_acceptance' 4 | 5 | configure_beaker 6 | 7 | shared_examples 'an idempotent resource' do 8 | it 'applies with no errors' do 9 | apply_manifest(pp, catch_failures: true) 10 | end 11 | 12 | it 'applies a second time without changes' do 13 | apply_manifest(pp, catch_changes: true) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/unit/provider/alternatives/chkconfig_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Puppet::Type.type(:alternatives).provider(:chkconfig) do 6 | def my_fixture_alternatives 7 | Dir.glob(File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'provider', 'alternatives', 'chkconfig', 'alternatives', '*')) 8 | end 9 | 10 | def my_fixture_display(type, path) 11 | File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'provider', 'alternatives', 'chkconfig', type, path) 12 | end 13 | 14 | def my_fixture_read(type, path) 15 | File.read(my_fixture_display(type, path)) 16 | end 17 | 18 | let(:stub_selections) do 19 | { 20 | 'sample' => { path: '/opt/sample1' }, 21 | 'testcmd' => { path: '/opt/testcmd1' } 22 | } 23 | end 24 | 25 | describe '.all' do 26 | it 'List all alternatives in folder /var/lib/alternatives' do 27 | described_class.expects(:list_alternatives).returns my_fixture_alternatives 28 | described_class.expects(:update).with('--display', 'sample').returns my_fixture_read('display', 'sample') 29 | described_class.expects(:update).with('--display', 'testcmd').returns my_fixture_read('display', 'testcmd') 30 | described_class.all 31 | end 32 | 33 | describe 'returning data' do 34 | subject { described_class.all } 35 | 36 | before do 37 | described_class.stubs(:list_alternatives).returns my_fixture_alternatives 38 | described_class.stubs(:update).with('--display', 'sample').returns my_fixture_read('display', 'sample') 39 | described_class.stubs(:update).with('--display', 'testcmd').returns my_fixture_read('display', 'testcmd') 40 | end 41 | 42 | it { is_expected.to be_a Hash } 43 | it { expect(subject['sample']).to eq(mode: 'manual', path: '/opt/sample2') } 44 | it { expect(subject['testcmd']).to eq(mode: 'manual', path: '/opt/testcmd1') } 45 | end 46 | end 47 | 48 | describe '.instances' do 49 | it 'delegates to .all' do 50 | described_class.expects(:all).returns(stub_selections) 51 | described_class.expects(:new).twice.returns(stub) 52 | described_class.instances 53 | end 54 | end 55 | 56 | describe 'instances' do 57 | subject { described_class.new(name: 'sample') } 58 | 59 | let(:resource) { Puppet::Type.type(:alternatives).new(name: 'sample') } 60 | 61 | before do 62 | Puppet::Type.type(:alternatives).stubs(:defaultprovider).returns described_class 63 | described_class.stubs(:update).with('--display', 'sample').returns my_fixture_read('display', 'sample') 64 | described_class.stubs(:update).with('--display', 'testcmd').returns my_fixture_read('display', 'testcmd') 65 | resource.provider = subject 66 | described_class.stubs(:all).returns(stub_selections) 67 | end 68 | 69 | it '#path retrieves the path from class.all' do 70 | expect(subject.path).to eq('/opt/sample1') 71 | end 72 | 73 | it '#path= updates the path with alternatives --set' do 74 | subject.expects(:update).with('--set', 'sample', '/opt/sample1') 75 | subject.path = '/opt/sample1' 76 | end 77 | 78 | it '#mode=(:auto) calls alternatives --auto' do 79 | subject.expects(:update).with('--auto', 'sample') 80 | subject.mode = :auto 81 | end 82 | 83 | it '#mode=(:manual) calls alternatives --set with current value' do 84 | subject.expects(:path).returns('/opt/sample2') 85 | subject.expects(:update).with('--set', 'sample', '/opt/sample2') 86 | subject.mode = :manual 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/unit/provider/alternatives/dpkg_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Puppet::Type.type(:alternatives).provider(:dpkg) do 6 | def my_fixture(path) 7 | File.join(PROJECT_ROOT, 'spec', 'fixtures', 'unit', 'provider', 'alternatives', 'dpkg', path) 8 | end 9 | 10 | def my_fixture_read(path) 11 | File.read(my_fixture(path)) 12 | end 13 | 14 | let(:stub_selections) do 15 | { 16 | 'editor' => { mode: 'manual', path: '/usr/bin/vim.tiny' }, 17 | 'aptitude' => { mode: 'auto', path: '/usr/bin/aptitude-curses' } 18 | } 19 | end 20 | 21 | describe '.all' do 22 | it 'calls update-alternatives --get-selections' do 23 | described_class.expects(:update).with('--get-selections').returns my_fixture_read('get-selections') 24 | described_class.all 25 | end 26 | 27 | describe 'returning data' do 28 | subject { described_class.all } 29 | 30 | before do 31 | described_class.stubs(:update).with('--get-selections').returns my_fixture_read('get-selections') 32 | end 33 | 34 | it { is_expected.to be_a Hash } 35 | it { expect(subject['editor']).to eq(mode: 'manual', path: '/usr/bin/vim.tiny') } 36 | it { expect(subject['aptitude']).to eq(mode: 'auto', path: '/usr/bin/aptitude-curses') } 37 | end 38 | end 39 | 40 | describe '.instances' do 41 | it 'delegates to .all' do 42 | described_class.expects(:all).returns(stub_selections) 43 | described_class.expects(:new).twice.returns(stub) 44 | described_class.instances 45 | end 46 | end 47 | 48 | describe 'instances' do 49 | subject { described_class.new(name: 'editor') } 50 | 51 | let(:resource) { Puppet::Type.type(:alternatives).new(name: 'editor') } 52 | 53 | before do 54 | Puppet::Type.type(:alternatives).stubs(:defaultprovider).returns described_class 55 | resource.provider = subject 56 | described_class.stubs(:all).returns(stub_selections) 57 | end 58 | 59 | it '#path retrieves the path from class.all' do 60 | expect(subject.path).to eq('/usr/bin/vim.tiny') 61 | end 62 | 63 | it '#path= updates the path with update-alternatives --set' do 64 | subject.expects(:update).with('--set', 'editor', '/bin/nano') 65 | subject.path = '/bin/nano' 66 | end 67 | 68 | it '#mode=(:auto) calls update-alternatives --auto' do 69 | subject.expects(:update).with('--auto', 'editor') 70 | subject.mode = :auto 71 | end 72 | 73 | it '#mode=(:manual) calls update-alternatives --set with current value' do 74 | subject.expects(:path).returns('/usr/bin/vim.tiny') 75 | subject.expects(:update).with('--set', 'editor', '/usr/bin/vim.tiny') 76 | subject.mode = :manual 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /spec/unit/type/alternatives_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe Puppet::Type.type(:alternatives) do 6 | describe 'property `path`' do 7 | context 'on Debian systems' do 8 | before do 9 | Facter.stubs(:value).with('os.family').returns('Debian') 10 | end 11 | 12 | it 'passes validation with an absolute path' do 13 | expect { described_class.new(name: 'ruby', path: '/usr/bin/ruby1.9') }.not_to raise_error 14 | end 15 | 16 | it 'fails validation without an absolute path' do 17 | expect { described_class.new(name: 'ruby', path: "The bees they're in my eyes") }.to raise_error Puppet::Error, %r{must be a fully qualified path} 18 | end 19 | end 20 | 21 | context 'on RedHat systems' do 22 | before do 23 | Facter.stubs(:value).with('os.family').returns('RedHat') 24 | end 25 | 26 | it 'passes validation with an absolute path' do 27 | expect { described_class.new(name: 'java', path: '/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.342.b07-1.el7_9.x86_64/jre/bin/java') }.not_to raise_error 28 | end 29 | 30 | it 'fails validation without an absolute path' do 31 | expect { described_class.new(name: 'java', path: 'java-1.8.0-openjdk.x86_64') }.not_to raise_error 32 | end 33 | end 34 | end 35 | 36 | describe 'validating the mode' do 37 | it 'raises an error if the mode is auto and a path is set' do 38 | expect do 39 | described_class.new(name: 'thing', mode: 'auto', path: '/usr/bin/explode') 40 | end.to raise_error Puppet::Error, %r{Mode cannot be 'auto'} 41 | end 42 | 43 | it 'raises an error if the mode is manual and a path is not set' do 44 | expect do 45 | described_class.new(name: 'thing', mode: 'manual').validate 46 | end.to raise_error Puppet::Error, %r{Mode cannot be 'manual'} 47 | end 48 | end 49 | 50 | describe 'when autorequiring resources' do 51 | alternative_entry = Puppet::Type.type(:alternative_entry).new( 52 | name: '/usr/pgsql-9.1/bin/pg_config', 53 | ensure: :present, 54 | altlink: '/usr/bin/pg_config', 55 | altname: 'pgsql-pg_config', 56 | priority: '910' 57 | ) 58 | alternatives = described_class.new( 59 | name: 'pgsql-pg_config', 60 | path: '/usr/pgsql-9.1/bin/pg_config' 61 | ) 62 | 63 | catalog = Puppet::Resource::Catalog.new 64 | catalog.add_resource alternative_entry 65 | catalog.add_resource alternatives 66 | req = alternatives.autorequire 67 | 68 | it 'is equal' do 69 | expect(req.size).to eq(1) 70 | end 71 | 72 | it 'has matching source' do 73 | expect(req[0].source).to eq alternative_entry 74 | end 75 | 76 | it 'has matching target' do 77 | expect(req[0].target).to eq alternatives 78 | end 79 | end 80 | end 81 | --------------------------------------------------------------------------------