├── examples ├── prerun_command.pp └── init.pp ├── .sync.yml ├── .puppet-lint.rc ├── .msync.yml ├── .rubocop.yml ├── lib └── facter │ ├── r10k_environment.rb │ └── r10k_path.rb ├── spec ├── default_module_facts.yml ├── spec_helper_acceptance.rb ├── unit │ └── facter │ │ └── r10k_path_spec.rb ├── classes │ ├── install │ │ ├── puppet_gem_spec.rb │ │ └── bundle_spec.rb │ ├── params_spec.rb │ ├── r10k_spec.rb │ ├── mcollective_spec.rb │ ├── postrun_command_spec.rb │ ├── prerun_command_spec.rb │ ├── webhook_spec.rb │ └── init_spec.rb ├── acceptance │ ├── r10k_spec.rb │ └── r10k_webhook_spec.rb ├── spec_helper.rb └── type_aliases │ └── webhook │ └── config_spec.rb ├── .github ├── labeler.yml ├── workflows │ ├── labeler.yml │ ├── ci.yml │ ├── release.yml │ └── prepare_release.yml ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md └── release.yml ├── types └── webhook │ ├── config │ ├── server │ │ ├── tls.pp │ │ └── queue.pp │ ├── chatops.pp │ ├── server.pp │ └── r10k.pp │ └── config.pp ├── .editorconfig ├── manifests ├── webhook │ ├── config.pp │ ├── service.pp │ └── package.pp ├── install │ ├── puppet_gem.pp │ └── bundle.pp ├── postrun_command.pp ├── prerun_command.pp ├── mcollective.pp ├── mcollective │ └── application.pp ├── install.pp ├── params.pp ├── config.pp ├── webhook.pp └── init.pp ├── .gitignore ├── files ├── prefix_command.rb ├── post-receive ├── config_version.sh ├── mcollective │ ├── application │ │ └── r10k.rb │ └── agent │ │ ├── r10k.ddl │ │ ├── r10k.rb │ │ └── r10k.json ├── pre-commit └── stash_mco.rb ├── .pmtignore ├── Gemfile ├── tasks ├── deploy.json └── deploy.rb ├── Rakefile ├── .fixtures.yml ├── .overcommit.yml ├── metadata.json ├── LICENSE ├── REFERENCE.md └── README.md /examples/prerun_command.pp: -------------------------------------------------------------------------------- 1 | include r10k::prerun_command 2 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | .puppet-lint.rc: 2 | enabled_lint_checks: 3 | - parameter_documentation 4 | - parameter_types 5 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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: '10.4.0' 6 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /lib/facter/r10k_environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet' 4 | Facter.add('r10k_environment') do 5 | setcode do 6 | Puppet[:environment].to_s 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/default_module_facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | pe_version: '2016.4.1' 3 | puppet_environmentpath: '/etc/puppetlabs/code/environments' 4 | puppet_vardir: '/opt/puppetlabs/puppet/cache' 5 | service_provider: systemd 6 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /lib/facter/r10k_path.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Facter.add(:r10k_path) do 4 | confine kernel: :linux 5 | setcode do 6 | Facter::Util::Resolution.exec('which r10k 2> /dev/null') 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /types/webhook/config/server/tls.pp: -------------------------------------------------------------------------------- 1 | # @summary webhook config server tls type 2 | type R10k::Webhook::Config::Server::Tls = Struct[ 3 | { 4 | enabled => Boolean, 5 | certificate => Optional[Stdlib::Absolutepath], 6 | key => Optional[Stdlib::Absolutepath], 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /types/webhook/config.pp: -------------------------------------------------------------------------------- 1 | # @summary webhook config type 2 | type R10k::Webhook::Config = Struct[ 3 | { 4 | server => Optional[R10k::Webhook::Config::Server], 5 | chatops => Optional[R10k::Webhook::Config::Chatops], 6 | r10k => Optional[R10k::Webhook::Config::R10k], 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /types/webhook/config/server/queue.pp: -------------------------------------------------------------------------------- 1 | # @summary webhook config server queue type 2 | type R10k::Webhook::Config::Server::Queue = Struct[ 3 | { 4 | enabled => Boolean, 5 | max_concurrent_jobs => Optional[Integer], 6 | max_history_items => Optional[Integer], 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | require 'voxpupuli/acceptance/spec_helper_acceptance' 7 | 8 | configure_beaker(modules: :metadata) 9 | 10 | Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f } 11 | -------------------------------------------------------------------------------- /manifests/webhook/config.pp: -------------------------------------------------------------------------------- 1 | # Class: r10k::webhook::config 2 | # 3 | # 4 | class r10k::webhook::config ( 5 | ) { 6 | file { 'webhook.yml': 7 | ensure => $r10k::webhook::config_ensure, 8 | path => $r10k::webhook::config_path, 9 | content => stdlib::to_yaml($r10k::webhook::config), 10 | owner => 'root', 11 | group => 'root', 12 | mode => '0644', 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /types/webhook/config/chatops.pp: -------------------------------------------------------------------------------- 1 | # @summary webhook config chatops type 2 | type R10k::Webhook::Config::Chatops = Struct[ 3 | { 4 | enabled => Boolean, 5 | service => Optional[Enum['slack', 'rocketchat']], 6 | channel => Optional[String[1]], 7 | user => Optional[String[1]], 8 | auth_token => Optional[String[1]], 9 | server_uri => Optional[String[1]], 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /manifests/install/puppet_gem.pp: -------------------------------------------------------------------------------- 1 | # This class links the r10k binary for Puppet FOSS 4.2 and up 2 | class r10k::install::puppet_gem { 3 | if versioncmp("${::facts['puppetversion']}", '4.2.0') >= 0 { #lint:ignore:only_variable_string 4 | file { '/usr/bin/r10k': 5 | ensure => link, 6 | target => '/opt/puppetlabs/puppet/bin/r10k', 7 | require => Package['r10k'], 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /types/webhook/config/server.pp: -------------------------------------------------------------------------------- 1 | # @summary webhook config server type 2 | type R10k::Webhook::Config::Server = Struct[ 3 | { 4 | protected => Boolean, 5 | user => Optional[String[1]], 6 | password => Optional[String[1]], 7 | port => Optional[Stdlib::Port], 8 | tls => Optional[R10k::Webhook::Config::Server::Tls], 9 | queue => Optional[R10k::Webhook::Config::Server::Queue], 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /manifests/webhook/service.pp: -------------------------------------------------------------------------------- 1 | # Class: r10k::webhook::service 2 | # 3 | # 4 | class r10k::webhook::service () { 5 | service { 'webhook-go.service': 6 | ensure => $r10k::webhook::service_ensure, 7 | enable => $r10k::webhook::service_enabled, 8 | } 9 | if $r10k::webhook::service_user { 10 | systemd::dropin_file { 'user.conf': 11 | unit => 'webhook-go.service', 12 | content => "[Service]\nUser=${r10k::webhook::service_user}\n", 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /types/webhook/config/r10k.pp: -------------------------------------------------------------------------------- 1 | # @summary webhook config r10k type 2 | type R10k::Webhook::Config::R10k = Struct[ 3 | { 4 | command_path => Optional[Stdlib::Absolutepath], 5 | config_path => Optional[Stdlib::Absolutepath], 6 | default_branch => Optional[String[1]], 7 | prefix => Optional[String[1]], 8 | allow_uppercase => Optional[Boolean], 9 | verbose => Optional[Boolean], 10 | deploy_modules => Optional[Boolean], 11 | generate_types => Optional[Boolean], 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /.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 | permissions: 12 | contents: read 13 | pull-requests: write 14 | 15 | jobs: 16 | labeler: 17 | permissions: 18 | contents: read 19 | pull-requests: write 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/labeler@v5 23 | -------------------------------------------------------------------------------- /.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 | permissions: 20 | contents: read 21 | 22 | jobs: 23 | puppet: 24 | name: Puppet 25 | uses: voxpupuli/gha-puppet/.github/workflows/beaker.yml@v4 26 | -------------------------------------------------------------------------------- /manifests/postrun_command.pp: -------------------------------------------------------------------------------- 1 | # @summary This class will configure r10k to run as part of the masters agent run 2 | # 3 | # @param command 4 | # @param ensure 5 | # 6 | class r10k::postrun_command ( 7 | String[1] $command = $r10k::params::pre_postrun_command, 8 | Enum['present', 'absent'] $ensure = 'present', 9 | ) inherits r10k::params { 10 | ini_setting { 'r10k_postrun_command': 11 | ensure => $ensure, 12 | path => "${r10k::params::puppetconf_path}/puppet.conf", 13 | section => 'agent', 14 | setting => 'postrun_command', 15 | value => $command, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /manifests/prerun_command.pp: -------------------------------------------------------------------------------- 1 | # @summary This class will configure r10k to run as part of the masters agent run 2 | # 3 | # @param command 4 | # @param ensure 5 | # 6 | class r10k::prerun_command ( 7 | String[1] $command = $r10k::params::pre_postrun_command, 8 | Enum['present', 'absent'] $ensure = 'present', 9 | ) inherits r10k::params { 10 | ini_setting { 'r10k_prerun_command': 11 | ensure => $ensure, 12 | path => "${r10k::params::puppetconf_path}/puppet.conf", 13 | section => 'agent', 14 | setting => 'prerun_command', 15 | value => $command, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/init.pp: -------------------------------------------------------------------------------- 1 | # The baseline for module testing used by Puppet Labs is that each manifest 2 | # should have a corresponding test manifest that declares that class or defined 3 | # type. 4 | # 5 | # Tests are then run by using puppet apply --noop (to check for compilation errors 6 | # and view a log of events) or by fully applying the test in a virtual environment 7 | # (to compare the resulting system state to the desired state). 8 | # 9 | # Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html 10 | # 11 | class { 'r10k': 12 | remote => 'git@github.com:acidprime/puppet.git', 13 | } 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | #### Pull Request (PR) description 10 | 13 | 14 | #### This Pull Request (PR) fixes the following issues 15 | 21 | -------------------------------------------------------------------------------- /files/prefix_command.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'json' 3 | require 'yaml' 4 | 5 | if STDIN.tty? 6 | puts 'This command is meant be launched by webhook' 7 | else 8 | prefixes = YAML.load_file('/etc/puppetlabs/r10k/r10k.yaml') 9 | 10 | json_data = JSON.parse(STDIN.read) 11 | url = json_data['repository']['url'] 12 | 13 | prefix = "" 14 | 15 | prefixes[:sources].each do |key,value| 16 | if url == value['remote'] then 17 | if value['prefix'] == true 18 | prefix = key 19 | elsif value['prefix'].is_a? String 20 | prefix = value['prefix'] 21 | end 22 | end 23 | end 24 | 25 | puts prefix 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/facter/r10k_path_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'facter/r10k_path' 5 | 6 | describe 'r10k_path fact specs', type: :fact do 7 | before do 8 | Facter.clear 9 | allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux') 10 | end 11 | 12 | describe 'r10k_path' do 13 | before do 14 | allow(Facter::Util::Resolution).to receive(:exec).with('which r10k 2> /dev/null').and_return('/usr/local/bin/r10k') 15 | end 16 | 17 | it 'defaults to /usr/local/bin/r10k' do 18 | expect(Facter.fact(:r10k_path).value).to eq('/usr/local/bin/r10k') 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /files/post-receive: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # based on https://gist.github.com/rpflorence/478846 3 | # figure out which repository this is 4 | # assumes it's a bare repository 5 | repository = /([^\/]*?)\.git$/.match(`pwd`.chomp)[1] 6 | 7 | # get the stdins from git 8 | stdins = []; stdins << $_ while gets 9 | 10 | stdins.each do |str| 11 | # parse the stdin string 12 | arr = str.split 13 | refs = arr[2].split('/') 14 | 15 | # what we're really after 16 | oldrev = arr[0] # SHA 17 | newrev = arr[1] # SHA 18 | ref_type = refs[1] # tags || heads (branch) 19 | ref_name = refs[2] # develop, 1.4 etc. 20 | system('mco r10k synchronize') 21 | # now do whatcha gotta do 22 | end 23 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /spec/classes/install/puppet_gem_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k::install::puppet_gem', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | let :pre_condition do 12 | 'include r10k' 13 | end 14 | 15 | context 'with defaults' do 16 | it do 17 | expect(subject).to contain_file('/usr/bin/r10k').with( 18 | ensure: 'link', 19 | target: '/opt/puppetlabs/puppet/bin/r10k', 20 | require: 'Package[r10k]' 21 | ) 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /.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 | permissions: 14 | contents: write 15 | 16 | jobs: 17 | release: 18 | name: Release 19 | uses: voxpupuli/gha-puppet/.github/workflows/release.yml@v3 20 | with: 21 | allowed_owner: 'voxpupuli' 22 | secrets: 23 | # Configure secrets here: 24 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 25 | username: ${{ secrets.PUPPET_FORGE_USERNAME }} 26 | api_key: ${{ secrets.PUPPET_FORGE_API_KEY }} 27 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /spec/classes/params_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k::params', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | context 'with Puppet Enterprise' do 12 | let :facts do 13 | facts.merge( 14 | is_pe: true 15 | ) 16 | end 17 | 18 | it { is_expected.to contain_class('r10k::params') } 19 | it { expect(catalogue.resources.size).to eq(4) } 20 | end 21 | 22 | context 'with Puppet FOSS' do 23 | it { is_expected.to contain_class('r10k::params') } 24 | it { expect(catalogue.resources.size).to eq(4) } 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/acceptance/r10k_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'r10k tests' do 6 | context 'when defaults used' do 7 | it_behaves_like 'an idempotent resource' do 8 | let(:manifest) do 9 | <<-PUPPET 10 | include 'r10k' 11 | PUPPET 12 | end 13 | end 14 | 15 | describe command('r10k version') do 16 | its(:stdout) { is_expected.to match(%r{r10k 4}) } if fact('puppetversion')[0] == '7' 17 | its(:exit_status) { is_expected.to eq 0 } 18 | end 19 | 20 | describe file('//etc/puppetlabs/r10k/r10k.yaml') do 21 | it 'exists and has content' do 22 | expect(subject).to exist 23 | expect(subject).to be_owned_by 'root' 24 | expect(subject).to be_grouped_into 'root' 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /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', '~> 13.0', :require => false 8 | gem 'puppet_metadata', '~> 5.0', :require => false 9 | end 10 | 11 | group :development do 12 | gem 'guard-rake', :require => false 13 | gem 'overcommit', '>= 0.39.1', :require => false 14 | end 15 | 16 | group :system_tests do 17 | gem 'voxpupuli-acceptance', '~> 4.0', :require => false 18 | end 19 | 20 | group :release do 21 | gem 'voxpupuli-release', '~> 5.0', :require => false 22 | end 23 | 24 | gem 'rake', :require => false 25 | 26 | gem 'openvox', ENV.fetch('OPENVOX_GEM_VERSION', [">= 7", "< 9"]), :require => false, :groups => [:test] 27 | 28 | # vim: syntax=ruby 29 | -------------------------------------------------------------------------------- /tasks/deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Trigger an r10k deployment.", 3 | "puppet_task_version": 1, 4 | "parameters": { 5 | "environment": { 6 | "description": "The environment to deploy.", 7 | "type": "Optional[Pattern[/\\A[a-zA-Z0-9_]+\\Z/]]" 8 | }, 9 | "environments": { 10 | "description": "A comma separated list of environments to deploy. Takes precedence over `environment`.", 11 | "type": "Optional[Pattern[/\\A[a-zA-Z0-9_,]+\\Z/]]" 12 | }, 13 | "module": { 14 | "description": "A module to deploy across all environments.", 15 | "type": "Optional[Pattern[/\\A[a-z0-9_]+\\Z/]]" 16 | }, 17 | "modules": { 18 | "description": "A comma separated list of modules to deploy. Takes precedence over `module`.", 19 | "type": "Optional[Pattern[/\\A[a-z0-9_,]+\\Z/]]" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Managed by modulesync - DO NOT EDIT 4 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 5 | 6 | # puppetlabs_spec_helper will set up coverage if the env variable is set. 7 | # We want to do this if lib exists and it hasn't been explicitly set. 8 | ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../lib', __dir__)) 9 | 10 | require 'voxpupuli/test/spec_helper' 11 | 12 | RSpec.configure do |c| 13 | c.facterdb_string_keys = false 14 | end 15 | 16 | add_mocked_facts! 17 | 18 | if File.exist?(File.join(__dir__, 'default_module_facts.yml')) 19 | facts = YAML.safe_load(File.read(File.join(__dir__, 'default_module_facts.yml'))) 20 | facts&.each do |name, value| 21 | add_custom_fact name.to_sym, value 22 | end 23 | end 24 | Dir['./spec/support/spec/**/*.rb'].sort.each { |f| require f } 25 | -------------------------------------------------------------------------------- /.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 | permissions: 15 | contents: write 16 | pull-requests: write 17 | 18 | jobs: 19 | release_prep: 20 | uses: 'voxpupuli/gha-puppet/.github/workflows/prepare_release.yml@v3' 21 | with: 22 | version: ${{ github.event.inputs.version }} 23 | allowed_owner: 'voxpupuli' 24 | secrets: 25 | # Configure secrets here: 26 | # https://docs.github.com/en/actions/security-guides/encrypted-secrets 27 | github_pat: '${{ secrets.PCCI_PAT_RELEASE_PREP }}' 28 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /spec/classes/r10k_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | context 'with a github remote' do 12 | let :params do 13 | { 14 | remote: 'git@github.com:someuser/puppet.git' 15 | } 16 | end 17 | 18 | it { is_expected.to contain_class('r10k::params') } 19 | it { is_expected.to contain_class('r10k::install') } 20 | it { is_expected.to contain_class('r10k::config') } 21 | it { is_expected.not_to contain_class('r10k::mcollective') } 22 | end 23 | 24 | context 'with mcollective', if: facts[:os]['name'] != 'Gentoo' do 25 | let :params do 26 | { 27 | mcollective: true 28 | } 29 | end 30 | 31 | it { is_expected.to contain_class('r10k::mcollective') } 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /manifests/mcollective.pp: -------------------------------------------------------------------------------- 1 | # @summary Install the r10k mcollective agent 2 | # 3 | # @param ensure 4 | # @param server 5 | # @param client 6 | # @param http_proxy 7 | # @param policies 8 | # 9 | class r10k::mcollective ( 10 | String[1] $ensure = 'present', 11 | Boolean $server = true, 12 | Boolean $client = true, 13 | String $http_proxy = '', # lint:ignore:params_empty_string_assignment 14 | Array $policies = [], 15 | ) inherits r10k::params { 16 | include mcollective 17 | mcollective::module_plugin { 'mcollective_agent_r10k': 18 | ensure => $ensure, 19 | server => $server, 20 | client => $client, 21 | server_config => { 22 | 'http_proxy' => $http_proxy, 23 | }, 24 | config_name => 'r10k', 25 | common_files => [ 26 | 'agent/r10k.ddl', 27 | 'agent/r10k.json', 28 | ], 29 | server_files => [ 30 | 'agent/r10k.rb', 31 | ], 32 | client_files => [ 33 | 'application/r10k.rb', 34 | ], 35 | policies => $policies, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Managed by modulesync - DO NOT EDIT 2 | # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ 3 | 4 | begin 5 | require 'voxpupuli/test/rake' 6 | rescue LoadError 7 | # only available if gem group test is installed 8 | end 9 | 10 | begin 11 | require 'voxpupuli/acceptance/rake' 12 | rescue LoadError 13 | # only available if gem group acceptance is installed 14 | end 15 | 16 | begin 17 | require 'voxpupuli/release/rake_tasks' 18 | rescue LoadError 19 | # only available if gem group releases is installed 20 | else 21 | GCGConfig.user = 'voxpupuli' 22 | GCGConfig.project = 'puppet-r10k' 23 | end 24 | 25 | desc "Run main 'test' task and report merged results to coveralls" 26 | task test_with_coveralls: [:test] do 27 | if Dir.exist?(File.expand_path('../lib', __FILE__)) 28 | require 'coveralls/rake/task' 29 | Coveralls::RakeTask.new 30 | Rake::Task['coveralls:push'].invoke 31 | else 32 | puts 'Skipping reporting to coveralls. Module has no lib dir' 33 | end 34 | end 35 | 36 | # vim: syntax=ruby 37 | -------------------------------------------------------------------------------- /manifests/install/bundle.pp: -------------------------------------------------------------------------------- 1 | # @summary This class installs the r10k bundle 2 | # 3 | # @param revision 4 | # @param source 5 | # 6 | class r10k::install::bundle ( 7 | String[1] $revision = 'master', 8 | String[1] $source = 'https://github.com/adrienthebo/r10k.git', 9 | ) { 10 | # The bundle install has prefix support as of writing this, I want bleeding edge. 11 | package { "${module_name}-bundle": 12 | ensure => installed, 13 | name => 'bundler', 14 | provider => 'gem', 15 | } 16 | vcsrepo { "${module_name}-r10k-github": 17 | ensure => latest, 18 | provider => 'git', 19 | path => '/tmp/r10k', 20 | source => $source, 21 | revision => $revision, 22 | } 23 | exec { "${module_name}-install-via-bundle": 24 | command => 'bundle && bundle install --path /opt/ --binstubs /usr/local/bin/', 25 | cwd => '/tmp/r10k', 26 | require => [Package["${module_name}-bundle"], Vcsrepo["${module_name}-r10k-github"]], 27 | unless => 'bundle list | grep -q " r10k "', 28 | path => $::facts['path'], 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /files/config_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Create a environment.conf in your control repo 3 | # and set the path to this script i.e. 4 | # config_version = scripts/config_version.sh $environment 5 | # https://docs.puppetlabs.com/puppet/latest/reference/config_file_environment.html#configversion 6 | # Don't forget to restart pe-puppetserver/pe-httpd to pickup on the new config_version 7 | # Return the latest commit with the GitHub URL for it 8 | # The repos are placed using r10k 9 | 10 | ENVIRONMENT="$1" 11 | ENVIRONMENT_PATH="/etc/puppetlabs/code/environments" 12 | 13 | # Get the hash of the latest commit 14 | sha=$(git --git-dir "/${ENVIRONMENT_PATH}/${ENVIRONMENT}/.git" rev-parse HEAD) 15 | 16 | message=$(git --git-dir "/${ENVIRONMENT_PATH}/${ENVIRONMENT}/.git" log -1 --pretty='%s') 17 | 18 | # Get the address for remote origin 19 | remote=$(git --git-dir "/${ENVIRONMENT_PATH}/${ENVIRONMENT}/.git" config --get remote.origin.url) 20 | 21 | # Sanitize the git remote to be an http url. 22 | #url=$(echo "${remote}"|/bin/sed -e 's/git@//g; s/:/\//g; s/.git$//g') 23 | url=$(echo "${remote}"| awk -F'[@:]' '{ sub(/.git$/,"");print "http://"$2"/"$3}') 24 | 25 | # Return a full URL for it 26 | echo "[${message}](${url}/tree/${sha})" 27 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fixtures: 3 | repositories: 4 | apt: https://github.com/puppetlabs/puppetlabs-apt.git 5 | choria: https://github.com/choria-io/puppet-choria.git 6 | concat: https://github.com/puppetlabs/puppetlabs-concat.git 7 | cron_core: https://github.com/puppetlabs/puppetlabs-cron_core.git 8 | git: https://github.com/puppetlabs/puppetlabs-git.git 9 | inifile: https://github.com/puppetlabs/puppetlabs-inifile.git 10 | mcollective: https://github.com/choria-io/puppet-mcollective.git 11 | stdlib: https://github.com/puppetlabs/puppetlabs-stdlib.git 12 | systemd: https://github.com/voxpupuli/puppet-systemd.git 13 | vcsrepo: https://github.com/puppetlabs/puppetlabs-vcsrepo.git 14 | yumrepo_core: https://github.com/puppetlabs/puppetlabs-yumrepo_core.git 15 | mcollective_agent_filemgr: https://github.com/choria-plugins/filemgr-agent.git 16 | mcollective_agent_package: https://github.com/choria-plugins/package-agent.git 17 | mcollective_agent_puppet: https://github.com/choria-plugins/puppet-agent.git 18 | mcollective_agent_service: https://github.com/choria-plugins/service-agent.git 19 | mcollective_choria: https://github.com/choria-plugins/mcollective_choria.git 20 | mcollective_util_actionpolicy: https://github.com/choria-plugins/action-policy.git 21 | -------------------------------------------------------------------------------- /manifests/mcollective/application.pp: -------------------------------------------------------------------------------- 1 | # @summary Install the r10k mcollective application to a client 2 | # 3 | # @param agent_name 4 | # @param app_name 5 | # @param agent_ddl 6 | # @param agent_path 7 | # @param app_path 8 | # @param mc_service 9 | # 10 | class r10k::mcollective::application ( 11 | Optional[String] $agent_name = $r10k::params::mc_agent_name, 12 | Optional[String] $app_name = $r10k::params::mc_app_name, 13 | Optional[String] $agent_ddl = $r10k::params::mc_agent_ddl_name, 14 | Optional[String] $agent_path = $r10k::params::mc_agent_path, 15 | Optional[String] $app_path = $r10k::params::mc_application_path, 16 | Optional[String] $mc_service = $r10k::params::mc_service_name, 17 | ) inherits r10k::params { 18 | require r10k 19 | 20 | File { 21 | ensure => present, 22 | owner => $r10k::root_user, 23 | group => $r10k::root_group, 24 | mode => '0644', 25 | } 26 | # Install the agent and its ddl file 27 | file { 'mcollective_application_exec': 28 | path => "${app_path}/${app_name}", 29 | source => "puppet:///modules/${module_name}/application/${agent_name}", 30 | } 31 | 32 | file { 'mcollective_application_ddl': 33 | path => "${agent_path}/${agent_ddl}", 34 | source => "puppet:///modules/${module_name}/agent/${agent_ddl}", 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /spec/type_aliases/webhook/config_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'R10k::Webhook::Config' do 6 | context 'full valid configuration' do 7 | let(:data) do 8 | { 9 | server: { 10 | protected: true, 11 | user: 'foo', 12 | password: 'bar', 13 | port: 4000, 14 | tls: { 15 | enabled: true, 16 | certificate: '/some/path/to/cert.pem', 17 | key: '/some/path/to/key.pem', 18 | }, 19 | queue: { 20 | enabled: true, 21 | max_concurrent_jobs: 10, 22 | max_history_items: 20, 23 | }, 24 | }, 25 | chatops: { 26 | enabled: true, 27 | service: 'slack', 28 | channel: '#deploy', 29 | user: 'baz', 30 | auth_token: 'abcde', 31 | server_uri: 'https://test.com/slack', 32 | }, 33 | r10k: { 34 | command_path: '/some/path/to/r10k', 35 | config_path: '/some/path/to/r10k.yaml', 36 | default_branch: 'main', 37 | prefix: 'prefix', 38 | allow_uppercase: false, 39 | verbose: true, 40 | deploy_modules: true, 41 | generate_types: true, 42 | } 43 | } 44 | end 45 | 46 | it { is_expected.to allow_value(data) } 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /files/mcollective/application/r10k.rb: -------------------------------------------------------------------------------- 1 | class MCollective::Application::R10k= 1 4 | configuration[:command] = ARGV.shift 5 | case configuration[:command] 6 | when 'push','pull','status' 7 | configuration[:path] = ARGV.shift || docs 8 | when 'deploy' 9 | configuration[:environment] = ARGV.shift || docs 10 | when 'deploy_module' 11 | configuration[:module_name] = ARGV.shift || docs 12 | end 13 | else 14 | docs 15 | end 16 | end 17 | 18 | def docs 19 | puts "Usage: #{$0} push | pull | status | deploy | deploy_module" 20 | end 21 | 22 | def main 23 | mc = rpcclient("r10k", :chomp => true) 24 | options = {:path => configuration[:path]} if ['push','pull','status'].include? configuration[:command] 25 | options = {:environment => configuration[:environment]} if ['deploy'].include? configuration[:command] 26 | options = {:module_name => configuration[:module_name]} if ['deploy_module'].include? configuration[:command] 27 | mc.send(configuration[:command], options).each do |resp| 28 | puts "#{resp[:sender]}:" 29 | if resp[:statuscode] == 0 30 | responses = resp[:data][:output] 31 | puts responses if responses and ['push','pull','status','deploy','deploy_module'].include? configuration[:command] 32 | else 33 | puts resp[:statusmsg] 34 | end 35 | end 36 | mc.disconnect 37 | printrpcstats 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /manifests/webhook/package.pp: -------------------------------------------------------------------------------- 1 | # Class: r10k::webhook::package 2 | # 3 | # 4 | class r10k::webhook::package () { 5 | case $r10k::webhook::install_method { # lint:ignore:case_without_default 6 | 'package': { 7 | case $facts['os']['family'] { 8 | 'RedHat': { 9 | $provider = 'rpm' 10 | $pkg_file = '/tmp/webhook-go.rpm' 11 | $package_url = "https://github.com/voxpupuli/webhook-go/releases/download/v${r10k::webhook::version}/webhook-go_${r10k::webhook::version}_linux_amd64.rpm" 12 | } 13 | 'Debian', 'Ubuntu': { 14 | $provider = 'dpkg' 15 | $pkg_file = '/tmp/webhook-go.deb' 16 | $package_url = "https://github.com/voxpupuli/webhook-go/releases/download/v${r10k::webhook::version}/webhook-go_${r10k::webhook::version}_linux_amd64.deb" 17 | } 18 | default: { 19 | fail("Operating system ${facts['os']['name']} not supported for packages") 20 | } 21 | } 22 | 23 | file { $pkg_file: 24 | ensure => file, 25 | source => $package_url, 26 | before => Package['webhook-go'], 27 | } 28 | 29 | package { 'webhook-go': 30 | ensure => 'present', 31 | source => $pkg_file, 32 | provider => $provider, 33 | } 34 | } 35 | 'repo': { 36 | warning('webhook-go: configuring a repo is not implemented yet') 37 | } 38 | # none = people configure a repo on their own 39 | 'none': { 40 | package { 'webhook-go': 41 | ensure => 'installed', 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /spec/classes/mcollective_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k::mcollective', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | # Gentoo has no choria package and upstream doesn't offer a 3rd party repo 12 | context 'With defaults', if: facts[:os]['name'] != 'Gentoo' do 13 | it { is_expected.to compile.with_all_deps } 14 | it { is_expected.to contain_class('r10k::params') } 15 | 16 | it do 17 | expect(subject).to contain_mcollective__module_plugin('mcollective_agent_r10k').with( 18 | ensure: 'present', 19 | server: 'true', 20 | client: 'true', 21 | server_config: { 22 | 'http_proxy' => '', 23 | }, 24 | config_name: 'r10k', 25 | common_files: [ 26 | 'agent/r10k.ddl', 27 | 'agent/r10k.json', 28 | ], 29 | server_files: [ 30 | 'agent/r10k.rb', 31 | ], 32 | client_files: [ 33 | 'application/r10k.rb' 34 | ] 35 | ) 36 | end 37 | end 38 | 39 | context 'Removing the mcollective agent & application', if: facts[:os]['name'] != 'Gentoo' do 40 | let :params do 41 | { 42 | ensure: 'absent' 43 | } 44 | end 45 | 46 | it { is_expected.to contain_mcollective__module_plugin('mcollective_agent_r10k').with(ensure: 'absent') } 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /tasks/deploy.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'json' 5 | require 'open3' 6 | 7 | params = JSON.parse($stdin.read) 8 | 9 | # Munge items into arrays of things to deploy 10 | environments = params['environments'] || params['environment'] 11 | environments = environments.split(',') if environments 12 | 13 | modules = params['modules'] || params['module'] 14 | modules = modules.split(',') if modules 15 | 16 | messages = [] 17 | warnings = [] 18 | errors = [] 19 | exitstatus = 0 20 | environments&.each do |env| 21 | output, status = Open3.capture2e('r10k', 'deploy', 'environment', env, '--puppetfile') 22 | messages << "Deploying environment #{env}" 23 | exitstatus += status.exitstatus 24 | 25 | next if output.empty? 26 | 27 | (status.success? ? warnings : errors) << output 28 | end 29 | 30 | if modules 31 | output, status = Open3.capture2e('r10k', 'deploy', 'module', *modules) 32 | messages << "Deploying modules '#{modules.join(', ')}'" 33 | exitstatus += status.exitstatus 34 | 35 | unless output.empty? 36 | (status.success? ? warnings : errors) << output 37 | end 38 | end 39 | 40 | if environments.nil? && modules.nil? 41 | output, status = Open3.capture2e('r10k', 'deploy', 'environment', '--puppetfile') 42 | messages << 'Deploying all environments' 43 | exitstatus += status.exitstatus 44 | 45 | unless output.empty? 46 | (status.success? ? warnings : errors) << output 47 | end 48 | end 49 | 50 | puts({ 51 | 'status' => exitstatus.zero?, 52 | 'messages' => messages, 53 | 'warnings' => warnings, 54 | 'errors' => errors 55 | }.to_json) 56 | exit exitstatus 57 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /files/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'rubygems' 4 | require 'yaml' 5 | require 'json' 6 | 7 | def puppet_parser_validate(file) 8 | system('puppet parser validate ' + file) 9 | end 10 | 11 | def r10k_puppetfile_check(file) 12 | system('r10k puppetfile check ' + file) 13 | end 14 | 15 | def bash_check(file) 16 | system('bash -n ' + file) 17 | end 18 | 19 | def puppet_lint(file) 20 | system('puppet-lint ' + File.absolute_path(file)) 21 | end 22 | 23 | def puppet_erb_check(file) 24 | system("erb -x -T '-' ' + #{file} + ' | ruby -c") 25 | end 26 | 27 | def yaml_check(file) 28 | YAML.load_file(file) 29 | rescue Exception => err 30 | puts "YAML invalid: #{err}" 31 | false 32 | end 33 | 34 | def json_check(file) 35 | JSON.parse( IO.read(file) ) 36 | rescue Exception => err 37 | puts "JSON invalid: #{err}" 38 | false 39 | end 40 | 41 | # go through list of files, and call adequate checks 42 | IO.popen('git diff --cached --name-only --diff-filter=ACM').readlines.each { |file| 43 | file.sub!(/^\w (.*)\n/,'\1') 44 | file.chomp! unless file.nil? 45 | puts "Processing #{file}" 46 | if file.match('.pp$') 47 | exit 1 unless puppet_parser_validate file 48 | exit 1 unless puppet_lint file 49 | elsif file.match('.erb$') 50 | exit 1 unless puppet_erb_check file 51 | elsif file.match('Puppetfile') 52 | exit 1 unless r10k_puppetfile_check file 53 | elsif file.match('.sh$') 54 | exit 1 unless bash_check file 55 | elsif file.match(/(.yaml$|.yml$|.eyaml$)/) 56 | exit 1 unless yaml_check file 57 | elsif file.match('.json$') 58 | exit 1 unless json_check file 59 | end 60 | } 61 | -------------------------------------------------------------------------------- /files/stash_mco.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This script is meant to be used with the external hooks script for Stash: 4 | # https://marketplace.atlassian.com/plugins/com.ngs.stash.externalhooks.external-hooks 5 | # 6 | # The above plugin is used instead of the "Atlassian Post-Receive 7 | # Webhooks plugin" because the Atlassian plugin does not support ignoring 8 | # ssl self signed certificates. 9 | # 10 | # The external hook is useful beyond just this script, thus I prefer it. 11 | # 12 | require 'getoptlong' 13 | 14 | opts = GetoptLong.new( 15 | [ '--target', '-t', GetoptLong::REQUIRED_ARGUMENT ], 16 | [ '--insecure', '-k', GetoptLong::NO_ARGUMENT ], 17 | [ '--help', '-h', GetoptLong::NO_ARGUMENT ] 18 | ) 19 | 20 | target = nil 21 | insecure = nil 22 | 23 | opts.each do |opt,arg| 24 | case opt 25 | when '--help' 26 | puts <<-EOF 27 | stash_mco.rb [OPTIONS] 28 | 29 | -h, --help 30 | show help 31 | 32 | -t, --target [url] 33 | the target url to post to 34 | example: https://puppet:puppet@localhost:8088/payload 35 | user/pass should be specified as part of the target 36 | 37 | -k, --insecure 38 | pass the 'insecure' flag to curl to ignore ssl cert verification 39 | EOF 40 | 41 | when '--target' 42 | target = arg 43 | when '--insecure' 44 | insecure = '-k' 45 | end 46 | end 47 | 48 | # the external-hooks script passes the following on stdin 49 | # 50 | # old_hash new_hash ref/ref/ref 51 | # 52 | # for example: 53 | # 0000000000000000000000000000000000000000 ad91e3697d0711985e06d5bbbf6a7c5dc3b657f7 refs/heads/production 54 | # 55 | # All we care about is refs/heads/ 56 | # 57 | # Test this script with: 58 | # echo "000000 123456 refs/heads/production" | stash_mco.rb -k -t https://puppet:puppet@localhost:8088/payload 59 | 60 | while post = gets 61 | post_data = "{ \"ref\": \"#{post.split[2]}\" }" 62 | end 63 | 64 | system( "curl -q #{insecure} -d '#{post_data}' -H 'Accept: application/json' #{target}") 65 | 66 | -------------------------------------------------------------------------------- /manifests/install.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary This class is used by the ruby or pe_ruby class 3 | # 4 | # @api private 5 | # 6 | class r10k::install { 7 | assert_private() 8 | 9 | case $r10k::provider { 10 | 'bundle': { 11 | include r10k::install::bundle 12 | } 13 | 'puppet_gem', 'gem', 'openbsd', 'pkgng', 'pacman', 'portage': { 14 | if $r10k::provider == 'puppet_gem' { 15 | # Puppet FOSS 4.2 and up ships a vendor provided ruby. 16 | # Using puppet_gem uses that instead of the system ruby. 17 | include r10k::install::puppet_gem 18 | } 19 | 20 | # Currently we share a package resource to keep things simple 21 | # Puppet seems to have a bug (see #87 ) related to passing an 22 | # empty to value to the gem providers This code 23 | # converts an empty array to semi-standard gem options 24 | # This was previously undef but that caused strict var issues 25 | if $r10k::provider in ['puppet_gem', 'gem'] and $r10k::install_options == [] { 26 | $provider_install_options = ['--no-document'] 27 | } else { 28 | $provider_install_options = $r10k::install_options 29 | } 30 | 31 | # Puppet Enterprise 3.8 and ships an embedded r10k so thats all thats supported 32 | # This conditional should not effect FOSS customers based on the fact 33 | $ensure = $r10k::ensure ? { 34 | 'present' => $r10k::version, 35 | 'absent' => 'absent', 36 | } 37 | # we need to pin the faraday-net_http version for puppet 7 38 | if versioncmp($facts['puppetversion'], '8.0.0') < 0 { 39 | package { 'faraday': 40 | ensure => present, 41 | provider => $r10k::provider, 42 | install_options => [ 43 | { '-v' => '2.8.1' }, 44 | ], 45 | } 46 | } 47 | package { $r10k::package_name: 48 | ensure => $ensure, 49 | provider => $r10k::provider, 50 | source => $r10k::gem_source, 51 | install_options => $provider_install_options, 52 | } 53 | } 54 | default: { fail("${module_name}: ${r10k::provider} is not supported. Valid values are: 'gem', 'puppet_gem', 'bundle', 'openbsd'") } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /spec/acceptance/r10k_webhook_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'r10k::webhook tests', if: fact('os.name') != 'Archlinux' do 6 | context 'when defaults used' do 7 | it_behaves_like 'an idempotent resource' do 8 | let(:manifest) do 9 | <<-PUPPET 10 | class { 'r10k': } 11 | -> class { 'r10k::webhook': } 12 | PUPPET 13 | end 14 | end 15 | 16 | describe package('webhook-go') do 17 | it { is_expected.to be_installed } 18 | end 19 | 20 | describe file('/etc/voxpupuli/webhook.yml') do 21 | it 'exists and has content' do 22 | expect(subject).to exist 23 | expect(subject).to be_owned_by 'root' 24 | expect(subject).to be_grouped_into 'root' 25 | expect(subject).to contain "---\nserver:\n protected: true\n user: puppet\n password: puppet\n" 26 | end 27 | end 28 | 29 | describe service('webhook-go') do 30 | it { is_expected.to be_enabled } 31 | it { is_expected.to be_running } 32 | end 33 | 34 | describe command('systemctl cat webhook-go') do 35 | its(:stdout) { is_expected.to match(%r{webhook-go}) } 36 | end 37 | end 38 | 39 | context 'with service_user = puppet' do 40 | it_behaves_like 'an idempotent resource' do 41 | let(:manifest) do 42 | <<-PUPPET 43 | user { 'puppet': 44 | ensure => 'present', 45 | } 46 | -> group { 'puppet': 47 | ensure => 'present', 48 | } 49 | -> class { 'r10k': } 50 | -> class { 'r10k::webhook': 51 | service_user => 'puppet', 52 | } 53 | PUPPET 54 | end 55 | end 56 | 57 | describe package('webhook-go') do 58 | it { is_expected.to be_installed } 59 | end 60 | 61 | describe file('/etc/voxpupuli/webhook.yml') do 62 | it 'exists' do 63 | expect(subject).to exist 64 | expect(subject).to be_owned_by 'root' 65 | expect(subject).to be_grouped_into 'root' 66 | end 67 | end 68 | 69 | describe service('webhook-go') do 70 | it { is_expected.to be_enabled } 71 | it { is_expected.to be_running } 72 | end 73 | 74 | describe command('systemctl cat webhook-go') do 75 | its(:stdout) { is_expected.to match(%r{User=puppet}) } 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /manifests/params.pp: -------------------------------------------------------------------------------- 1 | # Reasonable defaults for all classes 2 | class r10k::params { 3 | $package_name = $facts['os']['name'] ? { 4 | 'OpenBSD' => 'ruby31-r10k', 5 | default => 'r10k' 6 | } 7 | # 4.1.0 is the oldest version that supports ruby >=2.6.0 8 | # That's required on Puppet 7 9 | # pacman provider has no versionable flag 10 | $version = if versioncmp($facts['puppetversion'], '8.0.0') < 0 and $facts['os']['name'] != 'Archlinux' { 11 | '4.1.0' 12 | } else { 13 | 'installed' 14 | } 15 | $manage_modulepath = false 16 | $root_user = 'root' 17 | $root_group = 'root' 18 | 19 | $provider = $facts['os']['name'] ? { 20 | 'Archlinux' => 'pacman', 21 | 'Gentoo' => 'portage', 22 | default => 'puppet_gem', 23 | } 24 | 25 | $puppet_master = true 26 | 27 | if 'puppet_environment' in $facts { 28 | $r10k_basedir = $facts['puppet_environmentpath'] 29 | } else { 30 | $r10k_basedir = '/etc/puppetlabs/code/environments' 31 | } 32 | $r10k_binary = 'r10k' 33 | $pre_postrun_command = "${r10k_binary} deploy environment --modules" 34 | $puppetconf_path = '/etc/puppetlabs/puppet' 35 | # Git configuration 36 | $git_server = $settings::ca_server #lint:ignore:top_scope_facts 37 | $repo_path = '/var/repos' 38 | $remote = "ssh://${git_server}${repo_path}/modules.git" 39 | 40 | # Include the mcollective agent 41 | $mcollective = false 42 | 43 | case $facts['os']['family'] { 44 | 'Debian': { 45 | $functions_path = '/lib/lsb/init-functions' 46 | $start_pidfile_args = '--pidfile=$pidfile' 47 | } 48 | 'SUSE': { $functions_path = '/etc/rc.status' } 49 | default: { 50 | $functions_path = '/etc/rc.d/init.d/functions' 51 | $start_pidfile_args = '--pidfile $pidfile' 52 | } 53 | } 54 | 55 | # We check for the function right now instead of $::pe_server_version 56 | # which does not get populated on agent nodes as some users use r10k 57 | # with razor see https://github.com/acidprime/r10k/pull/219 58 | if fact('is_pe') == true or fact('is_pe') == 'true' { 59 | # < PE 4 60 | $is_pe_server = true 61 | $pe_module_path = '/opt/puppetlabs/puppet/modules' 62 | $modulepath = "${r10k_basedir}/\$environment/modules:${pe_module_path}" 63 | } 64 | else { 65 | # FOSS 66 | $is_pe_server = false 67 | $modulepath = "${r10k_basedir}/\$environment/modules" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /manifests/config.pp: -------------------------------------------------------------------------------- 1 | # 2 | # @summary Set up the root r10k config file (/etc/r10k.yaml). 3 | # 4 | # @see https://github.com/adrienthebo/r10k#dynamic-environment-configuration 5 | # 6 | # @api private 7 | # 8 | # @author Charlie Sharpsteen 9 | # @author Zack Smith 10 | # 11 | class r10k::config { 12 | assert_private() 13 | if $r10k::sources { 14 | $r10k_sources = $r10k::sources 15 | $source_keys = keys($r10k_sources) 16 | } else { 17 | $r10k_sources = { 18 | 'puppet' => { 19 | 'basedir' => $r10k::r10k_basedir, 20 | 'remote' => $r10k::remote, 21 | }, 22 | } 23 | $source_keys = keys($r10k_sources) 24 | } 25 | 26 | $dir_ensure = $r10k::ensure ? { 27 | 'absent' => { ensure => 'absent', recurse => true, force => true }, 28 | 'present' => { ensure => 'directory', }, 29 | } 30 | $file_ensure = $r10k::ensure ? { 31 | 'absent' => 'absent', 32 | 'present' => 'file', 33 | } 34 | $link_ensure = $r10k::ensure ? { 35 | 'absent' => 'absent', 36 | 'present' => 'link', 37 | } 38 | if $r10k::configfile == '/etc/puppetlabs/r10k/r10k.yaml' { 39 | file { '/etc/puppetlabs/r10k': 40 | owner => $r10k::root_user, 41 | group => $r10k::root_group, 42 | mode => '0755', 43 | * => $dir_ensure, 44 | } 45 | } 46 | 47 | $config = { 48 | 'pool_size' => $r10k::pool_size, 49 | 'proxy' => $r10k::proxy, 50 | 'forge' => $r10k::forge_settings, 51 | 'git' => $r10k::git_settings, 52 | 'deploy' => $r10k::deploy_settings, 53 | 'cachedir' => $r10k::cachedir, 54 | 'postrun' => $r10k::postrun, 55 | 'sources' => $r10k_sources, 56 | }.delete_undef_values 57 | file { 'r10k.yaml': 58 | ensure => $file_ensure, 59 | owner => $r10k::root_user, 60 | group => $r10k::root_group, 61 | mode => '0644', 62 | path => $r10k::configfile, 63 | content => stdlib::to_yaml($config), 64 | } 65 | 66 | if $r10k::manage_configfile_symlink { 67 | file { 'symlink_r10k.yaml': 68 | ensure => $link_ensure, 69 | path => $r10k::configfile_symlink, 70 | target => $r10k::configfile, 71 | } 72 | } 73 | 74 | if $r10k::manage_modulepath { 75 | ini_setting { 'R10k Modulepath': 76 | ensure => $r10k::ensure, 77 | path => "${r10k::puppetconf_path}/puppet.conf", 78 | section => 'main', 79 | setting => 'modulepath', 80 | value => $r10k::modulepath, 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /spec/classes/install/bundle_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k::install::bundle', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | context 'Puppet with bundle & no params' do 12 | let :facts do 13 | facts 14 | end 15 | 16 | it do 17 | expect(subject).to contain_package('r10k-bundle').with( 18 | ensure: 'installed', 19 | name: 'bundler', 20 | provider: 'gem' 21 | ) 22 | end 23 | 24 | it do 25 | expect(subject).to contain_vcsrepo('r10k-r10k-github').with( 26 | ensure: 'latest', 27 | provider: 'git', 28 | path: '/tmp/r10k', 29 | source: 'https://github.com/adrienthebo/r10k.git', 30 | revision: 'master' 31 | ) 32 | end 33 | 34 | it do 35 | expect(subject).to contain_exec('r10k-install-via-bundle').with( 36 | command: 'bundle && bundle install --path /opt/ --binstubs /usr/local/bin/', 37 | cwd: '/tmp/r10k', 38 | unless: 'bundle list | grep -q " r10k "' 39 | ) 40 | end 41 | end 42 | 43 | context 'Puppet Enterprise with bundle & custom params' do 44 | let :params do 45 | { 46 | revision: 'new_feature', 47 | source: 'https://github.com/acidprime/r10k-fork.git' 48 | } 49 | end 50 | let :facts do 51 | facts 52 | end 53 | 54 | it do 55 | expect(subject).to contain_package('r10k-bundle').with( 56 | ensure: 'installed', 57 | name: 'bundler', 58 | provider: 'gem' 59 | ) 60 | end 61 | 62 | it do 63 | expect(subject).to contain_vcsrepo('r10k-r10k-github').with( 64 | ensure: 'latest', 65 | provider: 'git', 66 | path: '/tmp/r10k', 67 | source: 'https://github.com/acidprime/r10k-fork.git', 68 | revision: 'new_feature' 69 | ) 70 | end 71 | 72 | it do 73 | expect(subject).to contain_exec('r10k-install-via-bundle').with( 74 | command: 'bundle && bundle install --path /opt/ --binstubs /usr/local/bin/', 75 | cwd: '/tmp/r10k', 76 | unless: 'bundle list | grep -q " r10k "' 77 | ) 78 | end 79 | end 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /manifests/webhook.pp: -------------------------------------------------------------------------------- 1 | # @summary install and configure the webhook-go package as local webhook receiver to trigger r10k runs 2 | # 3 | # @param service_user the user that should run the service 4 | # @param install_method 5 | # how the package should be installed 6 | # @param ensure 7 | # @param version 8 | # @param service_ensure 9 | # @param service_enabled 10 | # @param config_ensure 11 | # @param config_path 12 | # @param chatops 13 | # @param tls 14 | # @param queue 15 | # @param server 16 | # @param r10k 17 | # @param config 18 | # 19 | class r10k::webhook ( 20 | Optional $service_user = undef, 21 | Enum['package', 'repo', 'none'] $install_method = 'package', 22 | Boolean $ensure = false, 23 | String[1] $version = '2.10.0', 24 | Variant[ 25 | Enum['running', 'stopped'], 26 | Boolean 27 | ] $service_ensure = 'running', 28 | Boolean $service_enabled = true, 29 | String $config_ensure = 'file', 30 | String $config_path = '/etc/voxpupuli/webhook.yml', 31 | R10k::Webhook::Config::ChatOps $chatops = { 32 | enabled => false, 33 | service => undef, 34 | channel => undef, 35 | user => undef, 36 | auth_token => undef, 37 | server_uri => undef, 38 | }, 39 | R10k::Webhook::Config::Server::Tls $tls = { 40 | enabled => false, 41 | certificate => undef, 42 | key => undef, 43 | }, 44 | R10k::Webhook::Config::Server::Queue $queue = { 45 | enabled => false, 46 | max_concurrent_jobs => undef, 47 | max_history_items => undef, 48 | }, 49 | R10k::Webhook::Config::Server $server = { 50 | protected => true, 51 | user => 'puppet', 52 | password => 'puppet', 53 | port => 4000, 54 | tls => $tls, 55 | queue => $queue, 56 | }, 57 | R10k::Webhook::Config::R10k $r10k = { 58 | command_path => '/opt/puppetlabs/puppet/bin/r10k', 59 | config_path => '/etc/puppetlabs/r10k/r10k.yaml', 60 | default_branch => 'production', 61 | prefix => undef, 62 | allow_uppercase => false, 63 | verbose => true, 64 | deploy_modules => true, 65 | generate_types => true, 66 | }, 67 | R10k::Webhook::Config $config = { 68 | server => $server, 69 | chatops => $chatops, 70 | r10k => $r10k, 71 | }, 72 | ) inherits r10k::params { 73 | contain r10k::webhook::package 74 | contain r10k::webhook::config 75 | contain r10k::webhook::service 76 | 77 | Class['r10k::webhook::package'] 78 | -> Class['r10k::webhook::config'] 79 | ~> Class['r10k::webhook::service'] 80 | } 81 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Vox Pupuli", 3 | "license": "Apache-2.0", 4 | "name": "puppet-r10k", 5 | "version": "15.0.1-rc0", 6 | "operatingsystem_support": [ 7 | { 8 | "operatingsystem": "Debian", 9 | "operatingsystemrelease": [ 10 | "12", 11 | "13" 12 | ] 13 | }, 14 | { 15 | "operatingsystem": "CentOS", 16 | "operatingsystemrelease": [ 17 | "9", 18 | "10" 19 | ] 20 | }, 21 | { 22 | "operatingsystem": "RedHat", 23 | "operatingsystemrelease": [ 24 | "8", 25 | "9", 26 | "10" 27 | ] 28 | }, 29 | { 30 | "operatingsystem": "Rocky", 31 | "operatingsystemrelease": [ 32 | "8", 33 | "9", 34 | "10" 35 | ] 36 | }, 37 | { 38 | "operatingsystem": "AlmaLinux", 39 | "operatingsystemrelease": [ 40 | "8", 41 | "9", 42 | "10" 43 | ] 44 | }, 45 | { 46 | "operatingsystem": "OracleLinux", 47 | "operatingsystemrelease": [ 48 | "8", 49 | "9", 50 | "10" 51 | ] 52 | }, 53 | { 54 | "operatingsystem": "Ubuntu", 55 | "operatingsystemrelease": [ 56 | "22.04", 57 | "24.04" 58 | ] 59 | }, 60 | { 61 | "operatingsystem": "Archlinux" 62 | }, 63 | { 64 | "operatingsystem": "Gentoo" 65 | } 66 | ], 67 | "project_page": "https://github.com/voxpupuli/puppet-r10k", 68 | "issues_url": "https://github.com/voxpupuli/puppet-r10k/issues", 69 | "source": "https://github.com/voxpupuli/puppet-r10k", 70 | "summary": "Module for setting up dynamic environments using r10k", 71 | "tags": [ 72 | "git", 73 | "pe", 74 | "environment", 75 | "mcollective", 76 | "r10k" 77 | ], 78 | "dependencies": [ 79 | { 80 | "name": "puppetlabs/stdlib", 81 | "version_requirement": ">= 9.0.0 < 10.0.0" 82 | }, 83 | { 84 | "name": "puppetlabs/inifile", 85 | "version_requirement": ">= 1.4.1 < 7.0.0" 86 | }, 87 | { 88 | "name": "puppetlabs/vcsrepo", 89 | "version_requirement": ">= 1.3.1 < 8.0.0" 90 | }, 91 | { 92 | "name": "choria/mcollective", 93 | "version_requirement": ">= 0.10.0 <1.0.0" 94 | }, 95 | { 96 | "name": "puppet/systemd", 97 | "version_requirement": ">= 3.2.0 < 10.0.0" 98 | } 99 | ], 100 | "requirements": [ 101 | { 102 | "name": "openvox", 103 | "version_requirement": ">= 8.19.0 < 9.0.0" 104 | } 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /spec/classes/postrun_command_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k::postrun_command', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | context 'with Puppet Enterprise' do 12 | let :facts do 13 | facts.merge( 14 | is_pe: true 15 | ) 16 | end 17 | 18 | context 'adding custom postrun_command' do 19 | let :params do 20 | { 21 | command: 'r10k synchronize', 22 | ensure: 'present' 23 | } 24 | end 25 | 26 | it { is_expected.to contain_class('r10k::params') } 27 | 28 | it do 29 | expect(subject).to contain_ini_setting('r10k_postrun_command').with( 30 | ensure: 'present', 31 | section: 'agent', 32 | setting: 'postrun_command', 33 | value: 'r10k synchronize' 34 | ) 35 | end 36 | end 37 | 38 | context 'removing custom postrun_command' do 39 | let :params do 40 | { 41 | command: 'r10k synchronize', 42 | ensure: 'absent' 43 | } 44 | end 45 | 46 | it { is_expected.to contain_class('r10k::params') } 47 | 48 | it do 49 | expect(subject).to contain_ini_setting('r10k_postrun_command').with( 50 | ensure: 'absent', 51 | section: 'agent', 52 | setting: 'postrun_command', 53 | value: 'r10k synchronize' 54 | ) 55 | end 56 | end 57 | end 58 | 59 | context 'with Puppet FOSS' do 60 | context 'adding default postrun_command' do 61 | it { is_expected.to contain_class('r10k::params') } 62 | 63 | it do 64 | expect(subject).to contain_ini_setting('r10k_postrun_command').with( 65 | ensure: 'present', 66 | section: 'agent', 67 | setting: 'postrun_command', 68 | value: 'r10k deploy environment --modules' 69 | ) 70 | end 71 | end 72 | 73 | context 'adding custom postrun_command' do 74 | let :params do 75 | { 76 | command: 'r10k21 synchronize', 77 | ensure: 'present' 78 | } 79 | end 80 | 81 | it { is_expected.to contain_class('r10k::params') } 82 | 83 | it do 84 | expect(subject).to contain_ini_setting('r10k_postrun_command').with( 85 | ensure: 'present', 86 | section: 'agent', 87 | setting: 'postrun_command', 88 | value: 'r10k21 synchronize' 89 | ) 90 | end 91 | end 92 | 93 | context 'removing custom postrun_command' do 94 | let :params do 95 | { 96 | command: 'r10k21 synchronize', 97 | ensure: 'absent' 98 | } 99 | end 100 | 101 | it { is_expected.to contain_class('r10k::params') } 102 | 103 | it do 104 | expect(subject).to contain_ini_setting('r10k_postrun_command').with( 105 | ensure: 'absent', 106 | section: 'agent', 107 | setting: 'postrun_command', 108 | value: 'r10k21 synchronize' 109 | ) 110 | end 111 | end 112 | end 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /spec/classes/prerun_command_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | describe 'r10k::prerun_command', type: :class do 5 | on_supported_os.each do |os, facts| 6 | context "on #{os}" do 7 | let :facts do 8 | facts 9 | end 10 | 11 | context 'with Puppet Enterprise' do 12 | let :facts do 13 | facts.merge( 14 | is_pe: true 15 | ) 16 | end 17 | 18 | context 'adding custom prerun_command' do 19 | let :params do 20 | { 21 | command: 'r10k synchronize', 22 | ensure: 'present' 23 | } 24 | end 25 | 26 | it { is_expected.to contain_class('r10k::params') } 27 | 28 | it do 29 | expect(subject).to contain_ini_setting('r10k_prerun_command').with( 30 | ensure: 'present', 31 | section: 'agent', 32 | setting: 'prerun_command', 33 | value: 'r10k synchronize' 34 | ) 35 | end 36 | end 37 | 38 | context 'removing custom prerun_command' do 39 | let :params do 40 | { 41 | command: 'r10k synchronize', 42 | ensure: 'absent' 43 | } 44 | end 45 | 46 | it { is_expected.to contain_class('r10k::params') } 47 | 48 | it do 49 | expect(subject).to contain_ini_setting('r10k_prerun_command').with( 50 | ensure: 'absent', 51 | section: 'agent', 52 | setting: 'prerun_command', 53 | value: 'r10k synchronize' 54 | ) 55 | end 56 | end 57 | end 58 | 59 | context 'with Puppet FOSS' do 60 | context 'default prerun_command' do 61 | it { is_expected.to contain_class('r10k::params') } 62 | 63 | it do 64 | expect(subject).to contain_ini_setting('r10k_prerun_command').with( 65 | ensure: 'present', 66 | section: 'agent', 67 | setting: 'prerun_command', 68 | value: 'r10k deploy environment --modules' 69 | ) 70 | end 71 | end 72 | 73 | context 'adding custom prerun_command' do 74 | let :params do 75 | { 76 | command: 'r10k21 synchronize', 77 | ensure: 'present' 78 | } 79 | end 80 | 81 | it { is_expected.to contain_class('r10k::params') } 82 | 83 | it do 84 | expect(subject).to contain_ini_setting('r10k_prerun_command').with( 85 | ensure: 'present', 86 | section: 'agent', 87 | setting: 'prerun_command', 88 | value: 'r10k21 synchronize' 89 | ) 90 | end 91 | end 92 | 93 | context 'removing custom prerun_command' do 94 | let :params do 95 | { 96 | command: 'r10k21 synchronize', 97 | ensure: 'absent' 98 | } 99 | end 100 | 101 | it { is_expected.to contain_class('r10k::params') } 102 | 103 | it do 104 | expect(subject).to contain_ini_setting('r10k_prerun_command').with( 105 | ensure: 'absent', 106 | section: 'agent', 107 | setting: 'prerun_command', 108 | value: 'r10k21 synchronize' 109 | ) 110 | end 111 | end 112 | end 113 | 114 | context 'removing custom prerun_command' do 115 | let :params do 116 | { 117 | command: 'r10k22 synchronize', 118 | ensure: 'absent' 119 | } 120 | end 121 | 122 | it { is_expected.to contain_class('r10k::params') } 123 | 124 | it do 125 | expect(subject).to contain_ini_setting('r10k_prerun_command').with( 126 | ensure: 'absent', 127 | section: 'agent', 128 | setting: 'prerun_command', 129 | value: 'r10k22 synchronize' 130 | ) 131 | end 132 | end 133 | end 134 | end 135 | end 136 | -------------------------------------------------------------------------------- /files/mcollective/agent/r10k.ddl: -------------------------------------------------------------------------------- 1 | metadata :name => "r10k", 2 | :description => "Syncs modules using git", 3 | :author => "Zack Smith", 4 | :license => "MIT", 5 | :version => "1.0", 6 | :url => "http://puppetlabs.com", 7 | :timeout => 900 8 | 9 | ['push', 10 | 'pull', 11 | 'status'].each do |act| 12 | action act, :description => "#{act.capitalize} " do 13 | input :path, 14 | :prompt => "Module path", 15 | :description => "Operating on #{act}", 16 | :type => :string, 17 | :validation => '.', 18 | :optional => false, 19 | :maxlength => 256 20 | 21 | input :user, 22 | :prompt => "User", 23 | :description => "User to run as", 24 | :type => :string, 25 | :validation => '\w+', 26 | :optional => true, 27 | :maxlength => 32 28 | 29 | output :path, 30 | :description => "Operating on #{act}", 31 | :display_as => "Path" 32 | 33 | output :output, 34 | :description => "Output from git", 35 | :display_as => "Output" 36 | 37 | output :error, 38 | :description => "Error from git", 39 | :display_as => "Errors" 40 | display :always 41 | end 42 | end 43 | ['cache', 44 | 'synchronize', 45 | 'sync'].each do |act| 46 | action act, :description => "#{act.capitalize} " do 47 | input :user, 48 | :prompt => "User", 49 | :description => "User to run as", 50 | :type => :string, 51 | :validation => '\w+', 52 | :optional => true, 53 | :maxlength => 32 54 | 55 | output :output, 56 | :description => "Output from git", 57 | :display_as => "Output" 58 | 59 | output :error, 60 | :description => "Error from git", 61 | :display_as => "Errors" 62 | display :always 63 | end 64 | end 65 | action 'deploy', :description => "Deploy a specific environment, and its Puppetfile specified modules" do 66 | input :environment, 67 | :prompt => "Specific environment", 68 | :description => "Deploy a particular environment", 69 | :type => :string, 70 | # Wanted to rubyize the following regex but didn't have time to test: ^(?!/|.*([/.]\.|//|@\{|\\\\))[^\040\177 ~^:?*\[]+(? '.', 72 | :optional => true, 73 | :maxlength => 256 74 | 75 | input :user, 76 | :prompt => "User", 77 | :description => "User to run as", 78 | :type => :string, 79 | :validation => '\w+', 80 | :optional => true, 81 | :maxlength => 32 82 | 83 | output :environment, 84 | :description => "Deploy a particular environment", 85 | :display_as => "Specific environment" 86 | 87 | output :output, 88 | :description => "Output from r10k", 89 | :display_as => "Output" 90 | 91 | output :error, 92 | :description => "Error from r10k", 93 | :display_as => "Errors" 94 | 95 | display :always 96 | end 97 | 98 | action 'deploy_module', :description => "Deploy a specific module" do 99 | input :module_name, 100 | :prompt => "Specific module", 101 | :description => "Deploy a particular module", 102 | :type => :string, 103 | :validation => '.', 104 | :optional => true, 105 | :maxlength => 256 106 | 107 | input :user, 108 | :prompt => "User", 109 | :description => "User to run as", 110 | :type => :string, 111 | :validation => '\w+', 112 | :optional => true, 113 | :maxlength => 32 114 | 115 | output :module_name, 116 | :description => "Deploy a particular module", 117 | :display_as => "Specific module" 118 | 119 | output :output, 120 | :description => "Output from r10k", 121 | :display_as => "Output" 122 | 123 | output :error, 124 | :description => "Error from r10k", 125 | :display_as => "Errors" 126 | 127 | display :always 128 | end 129 | # vim: set syntax=ruby: 130 | -------------------------------------------------------------------------------- /files/mcollective/agent/r10k.rb: -------------------------------------------------------------------------------- 1 | module MCollective 2 | module Agent 3 | class R10k /dev/null` 9 | if r10k_binary == "" 10 | #r10k not found on path. 11 | Log.error('r10k binary not found in PATH') 12 | false 13 | else 14 | true 15 | end 16 | end 17 | ['push', 18 | 'pull', 19 | 'status'].each do |act| 20 | action act do 21 | validate :path, :shellsafe 22 | path = request[:path] 23 | reply.fail "Path not found #{path}" unless File.exist?(path) 24 | return unless reply.statuscode == 0 25 | lock do 26 | run_cmd act, path 27 | end 28 | reply[:path] = path 29 | end 30 | end 31 | ['cache', 32 | 'synchronize', 33 | 'deploy', 34 | 'deploy_module', 35 | 'sync'].each do |act| 36 | action act do 37 | if act == 'deploy' 38 | validate :environment, :shellsafe 39 | environment = request[:environment] 40 | lock do 41 | run_cmd act, environment 42 | end 43 | reply[:environment] = environment 44 | elsif act == 'deploy_module' 45 | validate :module_name, :shellsafe 46 | module_name = request[:module_name] 47 | lock do 48 | run_cmd act, module_name 49 | end 50 | reply[:module_name] = module_name 51 | else 52 | lock do 53 | run_cmd act 54 | end 55 | end 56 | end 57 | end 58 | private 59 | 60 | def cmd_as_user(cmd, cwd = nil) 61 | if /^\w+$/.match(request[:user]) 62 | cmd_as_user = ['su', '-', request[:user], '-c', '\''] 63 | if cwd 64 | cmd_as_user += ['cd', cwd, '&&'] 65 | end 66 | cmd_as_user += cmd + ["'"] 67 | 68 | # doesn't seem to execute when passed as an array 69 | cmd_as_user.join(' ') 70 | else 71 | cmd 72 | end 73 | end 74 | 75 | def run_cmd(action,arg=nil) 76 | output = '' 77 | git = ['/usr/bin/env', 'git'] 78 | r10k = ['/usr/bin/env', 'r10k'] 79 | # Given most people using this are using Puppet Enterprise, add the PE Path 80 | environment = {"LC_ALL" => "C","PATH" => "#{ENV['PATH']}:/opt/puppet/bin:/usr/local/bin"} 81 | environment["http_proxy"] = config.pluginconf.fetch("r10k.http_proxy", "") 82 | case action 83 | when 'push','pull','status' 84 | cmd = git 85 | cmd << 'push' if action == 'push' 86 | cmd << 'pull' if action == 'pull' 87 | cmd << 'status' if action == 'status' 88 | reply[:status] = run(cmd_as_user(cmd, arg), :stderr => :error, :stdout => :output, :chomp => true, :cwd => arg, :environment => environment ) 89 | when 'cache','synchronize','sync', 'deploy', 'deploy_module' 90 | cmd = r10k 91 | cmd << 'cache' if action == 'cache' 92 | cmd << 'deploy' << 'environment' << '-p' if action == 'synchronize' or action == 'sync' 93 | if action == 'deploy' 94 | cmd << 'deploy' << 'environment' << arg << '-p' 95 | elsif action == 'deploy_module' 96 | cmd << 'deploy' << 'module' << arg 97 | end 98 | reply[:status] = run(cmd_as_user(cmd), :stderr => :error, :stdout => :output, :chomp => true, :environment => environment) 99 | end 100 | end 101 | 102 | def lock 103 | File.open('/var/run/r10k.lock', 'w+') do |f| 104 | if (not f.flock(File::LOCK_EX | File::LOCK_NB)) 105 | reply.fail "Another instance of r10k already running" 106 | Log.info "Another instance of r10k already running" 107 | else 108 | yield 109 | end 110 | end 111 | end 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /manifests/init.pp: -------------------------------------------------------------------------------- 1 | # @summary This class configures r10k 2 | # 3 | # @param remote 4 | # @param configfile 5 | # @param version 6 | # @param puppet_master 7 | # @param modulepath 8 | # @param manage_modulepath 9 | # @param r10k_basedir 10 | # @param package_name 11 | # @param provider 12 | # @param gentoo_keywords 13 | # @param install_options 14 | # @param mcollective 15 | # @param git_settings 16 | # @param deploy_settings 17 | # @param root_user 18 | # @param gem_source 19 | # @param root_group 20 | # @param include_prerun_command 21 | # @param include_postrun_command 22 | # @param puppetconf_path 23 | # @param cachedir 24 | # Path to a directory to be used by r10k for caching data 25 | # @param sources 26 | # Hash containing data sources to be used by r10k to create dynamic Puppet environments 27 | # @param postrun 28 | # Array containing the parts of a system call Example: ['/usr/bin/curl', '-F', 'deploy=done', 'http://my-app.site/endpoint'] 29 | # @param manage_configfile_symlink 30 | # determine if a symlink to the r10k config file is to be managed 31 | # @param configfile_symlink 32 | # Location of symlink that points to configfile 33 | # @param forge_settings 34 | # Hash containing settings for downloading modules from the Puppet Forge 35 | # @param proxy 36 | # String containing proxy setting for r10k.yaml 37 | # @param pool_size 38 | # Integer defining how many threads should be spawn while updating modules 39 | # @param ensure 40 | # if r10k should be installed or purged 41 | class r10k ( 42 | String[1] $remote = $r10k::params::remote, 43 | Optional[Hash] $sources = undef, 44 | Stdlib::Absolutepath $cachedir = "${facts['puppet_vardir']}/r10k", 45 | Stdlib::Absolutepath $configfile = '/etc/puppetlabs/r10k/r10k.yaml', 46 | String[1] $version = $r10k::params::version, 47 | Boolean $puppet_master = $r10k::params::puppet_master, 48 | String[1] $modulepath = $r10k::params::modulepath, 49 | Boolean $manage_modulepath = $r10k::params::manage_modulepath, 50 | Stdlib::Absolutepath $r10k_basedir = $r10k::params::r10k_basedir, 51 | String[1] $package_name = $r10k::params::package_name, 52 | String[1] $provider = $r10k::params::provider, 53 | String $gentoo_keywords = '', # lint:ignore:params_empty_string_assignment 54 | Variant[Array,String] $install_options = [], 55 | Boolean $mcollective = $r10k::params::mcollective, 56 | Boolean $manage_configfile_symlink = false, 57 | Stdlib::Absolutepath $configfile_symlink = '/etc/r10k.yaml', 58 | Optional[Hash] $git_settings = undef, 59 | Optional[Hash] $forge_settings = undef, 60 | Hash $deploy_settings = { 'generate_types' => true, 'exclude_spec' => true, }, 61 | String[1] $root_user = $r10k::params::root_user, 62 | Optional[String[1]] $proxy = undef, 63 | Integer[1] $pool_size = $facts['processors']['count'], 64 | Optional[String[1]] $gem_source = undef, 65 | String[1] $root_group = $r10k::params::root_group, 66 | Optional[Array[String[1]]] $postrun = undef, 67 | Boolean $include_prerun_command = false, 68 | Boolean $include_postrun_command = false, 69 | Stdlib::Absolutepath $puppetconf_path = $r10k::params::puppetconf_path, 70 | Enum['absent','present'] $ensure = 'present', 71 | ) inherits r10k::params { 72 | # Check if user is declaring both classes 73 | # Other classes like r10k::webhook is supported but 74 | # using both classes makes no sense unless given pe_r10k 75 | # overrides this modules default config 76 | if defined(Class['pe_r10k']) { 77 | fail('This module does not support being declared with pe_r10k') 78 | } 79 | 80 | if $include_prerun_command { 81 | include r10k::prerun_command 82 | } 83 | 84 | if $include_postrun_command { 85 | include r10k::postrun_command 86 | } 87 | 88 | contain r10k::install 89 | contain r10k::config 90 | 91 | if $mcollective { 92 | class { 'r10k::mcollective': } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /spec/classes/webhook_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe 'r10k::webhook' do 6 | on_supported_os.each do |os, os_facts| 7 | context "on #{os}" do 8 | let :facts do 9 | os_facts 10 | end 11 | 12 | context 'with default params' do 13 | if %w[archlinux-rolling-x86_64 archlinux-6-x86_64 gentoo-2-x86_64].include?(os) 14 | it { is_expected.not_to compile } 15 | else 16 | it { is_expected.to compile.with_all_deps } 17 | it { is_expected.to contain_class('r10k::webhook::package') } 18 | it { is_expected.to contain_class('r10k::webhook::service') } 19 | it { is_expected.to contain_class('r10k::webhook::config') } 20 | it { is_expected.to contain_package('webhook-go').with_ensure('present') } 21 | it { is_expected.to contain_service('webhook-go.service').with_ensure('running') } 22 | end 23 | end 24 | 25 | context 'with params' do 26 | let :params do 27 | { 28 | ensure: true, 29 | version: '1.0.0', 30 | service_ensure: 'running', 31 | service_enabled: true, 32 | config_ensure: 'file', 33 | config_path: '/etc/voxpupuli/webhook.yml', 34 | chatops: { 35 | enabled: true, 36 | service: 'slack', 37 | channel: '#channel', 38 | user: 'root', 39 | auth_token: 'ABCDEF123456789', 40 | server_uri: 'https://webhook.slack.com/endpoint', 41 | }, 42 | server: { 43 | protected: true, 44 | user: 'puppet', 45 | password: 'puppet', 46 | port: 4000, 47 | tls: { 48 | enabled: true, 49 | certificate: '/path/to/cert', 50 | key: '/path/to/key', 51 | }, 52 | queue: { 53 | enabled: true, 54 | max_concurrent_jobs: 10, 55 | max_history_items: 20, 56 | } 57 | }, 58 | r10k: { 59 | command_path: '/opt/puppetlabs/puppet/bin/r10k', 60 | config_path: '/etc/puppetlabs/r10k/r10k.yaml', 61 | default_branch: 'production', 62 | allow_uppercase: false, 63 | verbose: true, 64 | deploy_modules: true, 65 | generate_types: true, 66 | } 67 | } 68 | end 69 | 70 | content = '--- 71 | server: 72 | protected: true 73 | user: puppet 74 | password: puppet 75 | port: 4000 76 | tls: 77 | enabled: true 78 | certificate: "/path/to/cert" 79 | key: "/path/to/key" 80 | queue: 81 | enabled: true 82 | max_concurrent_jobs: 10 83 | max_history_items: 20 84 | chatops: 85 | enabled: true 86 | service: slack 87 | channel: "#channel" 88 | user: root 89 | auth_token: ABCDEF123456789 90 | server_uri: https://webhook.slack.com/endpoint 91 | r10k: 92 | command_path: "/opt/puppetlabs/puppet/bin/r10k" 93 | config_path: "/etc/puppetlabs/r10k/r10k.yaml" 94 | default_branch: production 95 | allow_uppercase: false 96 | verbose: true 97 | deploy_modules: true 98 | generate_types: true 99 | ' 100 | context 'with default install_method' do 101 | if %w[archlinux-rolling-x86_64 archlinux-6-x86_64 gentoo-2-x86_64].include?(os) 102 | it { is_expected.not_to compile } 103 | else 104 | it { is_expected.to compile.with_all_deps } 105 | it { is_expected.to contain_class('r10k::webhook::package') } 106 | it { is_expected.to contain_class('r10k::webhook::service') } 107 | it { is_expected.to contain_class('r10k::webhook::config') } 108 | it { is_expected.to contain_package('webhook-go').with_ensure('present') } 109 | it { is_expected.to contain_service('webhook-go.service').with_ensure('running') } 110 | it { is_expected.not_to contain_systemd__dropin_file('user.conf') } 111 | it { is_expected.to contain_file('webhook.yml').with_content(content) } 112 | 113 | if os_facts[:os]['family'] == 'RedHat' 114 | it { is_expected.to contain_file('/tmp/webhook-go.rpm') } 115 | it { is_expected.not_to contain_file('/tmp/webhook-go.deb') } 116 | elsif os_facts[:os]['family'] == 'Debian' 117 | it { is_expected.not_to contain_file('/tmp/webhook-go.rpm') } 118 | it { is_expected.to contain_file('/tmp/webhook-go.deb') } 119 | end 120 | end 121 | end 122 | 123 | context 'with install_method = none' do 124 | let :params do 125 | super().merge({ install_method: 'none' }) 126 | end 127 | 128 | it { is_expected.to compile.with_all_deps } 129 | end 130 | 131 | context 'with service_user = puppet' do 132 | let :params do 133 | super().merge({ service_user: 'puppet' }) 134 | end 135 | 136 | if %w[archlinux-rolling-x86_64 archlinux-6-x86_64 gentoo-2-x86_64].include?(os) 137 | it { is_expected.not_to compile } 138 | else 139 | it { is_expected.to contain_systemd__dropin_file('user.conf').with_content("[Service]\nUser=puppet\n") } 140 | end 141 | end 142 | end 143 | end 144 | end 145 | end 146 | -------------------------------------------------------------------------------- /files/mcollective/agent/r10k.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://choria.io/schemas/mcorpc/ddl/v1/agent.json", 3 | "metadata": { 4 | "name": "r10k", 5 | "description": "Syncs modules using git", 6 | "author": "Zack Smith", 7 | "license": "MIT", 8 | "version": "1.0", 9 | "url": "http://puppetlabs.com", 10 | "timeout": 900 11 | }, 12 | "actions": [ 13 | { 14 | "action": "cache", 15 | "input": { 16 | "user": { 17 | "prompt": "User", 18 | "description": "User to run as", 19 | "type": "string", 20 | "default": null, 21 | "optional": true, 22 | "validation": "\\w+", 23 | "maxlength": 32 24 | } 25 | }, 26 | "output": { 27 | "output": { 28 | "description": "Output from git", 29 | "display_as": "Output", 30 | "default": null 31 | }, 32 | "error": { 33 | "description": "Error from git", 34 | "display_as": "Errors", 35 | "default": null 36 | } 37 | }, 38 | "display": "always", 39 | "description": "Cache " 40 | }, 41 | { 42 | "action": "deploy", 43 | "input": { 44 | "environment": { 45 | "prompt": "Specific environment", 46 | "description": "Deploy a particular environment", 47 | "type": "string", 48 | "default": null, 49 | "optional": true, 50 | "validation": ".", 51 | "maxlength": 256 52 | }, 53 | "user": { 54 | "prompt": "User", 55 | "description": "User to run as", 56 | "type": "string", 57 | "default": null, 58 | "optional": true, 59 | "validation": "\\w+", 60 | "maxlength": 32 61 | } 62 | }, 63 | "output": { 64 | "environment": { 65 | "description": "Deploy a particular environment", 66 | "display_as": "Specific environment", 67 | "default": null 68 | }, 69 | "output": { 70 | "description": "Output from r10k", 71 | "display_as": "Output", 72 | "default": null 73 | }, 74 | "error": { 75 | "description": "Error from r10k", 76 | "display_as": "Errors", 77 | "default": null 78 | } 79 | }, 80 | "display": "always", 81 | "description": "Deploy a specific environment, and its Puppetfile specified modules" 82 | }, 83 | { 84 | "action": "deploy_module", 85 | "input": { 86 | "module_name": { 87 | "prompt": "Specific module", 88 | "description": "Deploy a particular module", 89 | "type": "string", 90 | "default": null, 91 | "optional": true, 92 | "validation": ".", 93 | "maxlength": 256 94 | }, 95 | "user": { 96 | "prompt": "User", 97 | "description": "User to run as", 98 | "type": "string", 99 | "default": null, 100 | "optional": true, 101 | "validation": "\\w+", 102 | "maxlength": 32 103 | } 104 | }, 105 | "output": { 106 | "module_name": { 107 | "description": "Deploy a particular module", 108 | "display_as": "Specific module", 109 | "default": null 110 | }, 111 | "output": { 112 | "description": "Output from r10k", 113 | "display_as": "Output", 114 | "default": null 115 | }, 116 | "error": { 117 | "description": "Error from r10k", 118 | "display_as": "Errors", 119 | "default": null 120 | } 121 | }, 122 | "display": "always", 123 | "description": "Deploy a specific module" 124 | }, 125 | { 126 | "action": "pull", 127 | "input": { 128 | "path": { 129 | "prompt": "Module path", 130 | "description": "Operating on pull", 131 | "type": "string", 132 | "default": null, 133 | "optional": false, 134 | "validation": ".", 135 | "maxlength": 256 136 | }, 137 | "user": { 138 | "prompt": "User", 139 | "description": "User to run as", 140 | "type": "string", 141 | "default": null, 142 | "optional": true, 143 | "validation": "\\w+", 144 | "maxlength": 32 145 | } 146 | }, 147 | "output": { 148 | "path": { 149 | "description": "Operating on pull", 150 | "display_as": "Path", 151 | "default": null 152 | }, 153 | "output": { 154 | "description": "Output from git", 155 | "display_as": "Output", 156 | "default": null 157 | }, 158 | "error": { 159 | "description": "Error from git", 160 | "display_as": "Errors", 161 | "default": null 162 | } 163 | }, 164 | "display": "always", 165 | "description": "Pull " 166 | }, 167 | { 168 | "action": "push", 169 | "input": { 170 | "path": { 171 | "prompt": "Module path", 172 | "description": "Operating on push", 173 | "type": "string", 174 | "default": null, 175 | "optional": false, 176 | "validation": ".", 177 | "maxlength": 256 178 | }, 179 | "user": { 180 | "prompt": "User", 181 | "description": "User to run as", 182 | "type": "string", 183 | "default": null, 184 | "optional": true, 185 | "validation": "\\w+", 186 | "maxlength": 32 187 | } 188 | }, 189 | "output": { 190 | "path": { 191 | "description": "Operating on push", 192 | "display_as": "Path", 193 | "default": null 194 | }, 195 | "output": { 196 | "description": "Output from git", 197 | "display_as": "Output", 198 | "default": null 199 | }, 200 | "error": { 201 | "description": "Error from git", 202 | "display_as": "Errors", 203 | "default": null 204 | } 205 | }, 206 | "display": "always", 207 | "description": "Push " 208 | }, 209 | { 210 | "action": "status", 211 | "input": { 212 | "path": { 213 | "prompt": "Module path", 214 | "description": "Operating on status", 215 | "type": "string", 216 | "default": null, 217 | "optional": false, 218 | "validation": ".", 219 | "maxlength": 256 220 | }, 221 | "user": { 222 | "prompt": "User", 223 | "description": "User to run as", 224 | "type": "string", 225 | "default": null, 226 | "optional": true, 227 | "validation": "\\w+", 228 | "maxlength": 32 229 | } 230 | }, 231 | "output": { 232 | "path": { 233 | "description": "Operating on status", 234 | "display_as": "Path", 235 | "default": null 236 | }, 237 | "output": { 238 | "description": "Output from git", 239 | "display_as": "Output", 240 | "default": null 241 | }, 242 | "error": { 243 | "description": "Error from git", 244 | "display_as": "Errors", 245 | "default": null 246 | } 247 | }, 248 | "display": "always", 249 | "description": "Status " 250 | }, 251 | { 252 | "action": "sync", 253 | "input": { 254 | "user": { 255 | "prompt": "User", 256 | "description": "User to run as", 257 | "type": "string", 258 | "default": null, 259 | "optional": true, 260 | "validation": "\\w+", 261 | "maxlength": 32 262 | } 263 | }, 264 | "output": { 265 | "output": { 266 | "description": "Output from git", 267 | "display_as": "Output", 268 | "default": null 269 | }, 270 | "error": { 271 | "description": "Error from git", 272 | "display_as": "Errors", 273 | "default": null 274 | } 275 | }, 276 | "display": "always", 277 | "description": "Sync " 278 | }, 279 | { 280 | "action": "synchronize", 281 | "input": { 282 | "user": { 283 | "prompt": "User", 284 | "description": "User to run as", 285 | "type": "string", 286 | "default": null, 287 | "optional": true, 288 | "validation": "\\w+", 289 | "maxlength": 32 290 | } 291 | }, 292 | "output": { 293 | "output": { 294 | "description": "Output from git", 295 | "display_as": "Output", 296 | "default": null 297 | }, 298 | "error": { 299 | "description": "Error from git", 300 | "display_as": "Errors", 301 | "default": null 302 | } 303 | }, 304 | "display": "always", 305 | "description": "Synchronize " 306 | } 307 | ] 308 | } 309 | -------------------------------------------------------------------------------- /spec/classes/init_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | version = '2.0.0' 6 | 7 | describe 'r10k' do 8 | on_supported_os.each do |os, os_facts| 9 | context "on #{os}" do 10 | let :facts do 11 | os_facts 12 | end 13 | 14 | context 'with default values' do 15 | it { is_expected.to compile.with_all_deps } 16 | it { is_expected.to contain_class('r10k::install') } 17 | it { is_expected.to contain_class('r10k::config') } 18 | it { is_expected.not_to contain_class('r10k::mcollective') } 19 | it { is_expected.not_to contain_class('r10k::prerun_command') } 20 | it { is_expected.not_to contain_class('r10k::postrun_command') } 21 | end 22 | 23 | context 'with param include_prerun_command set to true' do 24 | let :params do 25 | { 26 | include_prerun_command: true 27 | } 28 | end 29 | 30 | it { is_expected.to compile } 31 | it { is_expected.to contain_class('r10k::prerun_command') } 32 | end 33 | 34 | context 'with param include_postrun_command set to true' do 35 | let :params do 36 | { 37 | include_postrun_command: true 38 | } 39 | end 40 | 41 | it { is_expected.to compile } 42 | it { is_expected.to contain_class('r10k::postrun_command') } 43 | end 44 | 45 | context 'modified file locations and ownership' do 46 | let :params do 47 | { 48 | configfile: '/etc/r10k.yaml', 49 | cachedir: '/var/cache/r10k', 50 | manage_modulepath: false, 51 | root_user: 'root', 52 | root_group: 'root' 53 | } 54 | end 55 | 56 | it do 57 | expect(subject).to contain_file('r10k.yaml').with( 58 | ensure: 'file', 59 | owner: 'root', 60 | group: 'root', 61 | mode: '0644', 62 | path: '/etc/r10k.yaml' 63 | ) 64 | end 65 | end 66 | 67 | context 'set to value true and a configfile specified' do 68 | let :params do 69 | { 70 | manage_configfile_symlink: true 71 | } 72 | end 73 | 74 | it do 75 | expect(subject).to contain_file('symlink_r10k.yaml').with( 76 | ensure: 'link', 77 | path: '/etc/r10k.yaml', 78 | target: '/etc/puppetlabs/r10k/r10k.yaml' 79 | ) 80 | end 81 | end 82 | 83 | context 'Managing r10k with rugged turned on via git_settings' do 84 | let :params do 85 | { 86 | git_settings: { 'private_key' => '/root/.ssh/id_dsa', 'provider' => 'rugged' } 87 | } 88 | end 89 | 90 | it { is_expected.to contain_file('r10k.yaml').with_content(%r{git:\n.*private_key: "/root/\.ssh/id_dsa"\n.*provider: rugged\n}) } 91 | end 92 | 93 | context 'managing git repository settings' do 94 | let :params do 95 | { 96 | git_settings: { 97 | repositories: [{ 98 | remote: 'https://github.com/voxpupuli/fake_repo', 99 | proxy: 'http://some.proxy.com' 100 | }] 101 | } 102 | } 103 | end 104 | 105 | it { is_expected.to contain_file('r10k.yaml').with_content(%r{git:\n\s+repositories:\n\s+- remote: https://github\.com/voxpupuli/fake_repo\n\s+proxy: http://some\.proxy\.com\n}) } 106 | end 107 | 108 | context 'manage forge settings of r10k via forge_settings' do 109 | let :params do 110 | { 111 | forge_settings: { 'baseurl' => 'https://forgeapi.puppetlabs.com', 'proxy' => 'https://proxy.example.com:3128' } 112 | } 113 | end 114 | 115 | it { is_expected.to contain_file('r10k.yaml').with_content(%r{forge:\n.*baseurl: https://forgeapi\.puppetlabs\.com\n.*proxy: https://proxy\.example\.com:3128\n}) } 116 | end 117 | 118 | context 'with optional parameter postrun specified with array of system call "/usr/bin/curl -F deploy=done http://my-app.site/endpoint"' do 119 | let :params do 120 | { 121 | configfile: '/etc/r10k.yaml', 122 | cachedir: '/var/cache/r10k', 123 | manage_modulepath: false, 124 | postrun: ['/usr/bin/curl', '-F', 'deploy=done', 'http://my-app.site/endpoint'], 125 | root_user: 'root', 126 | root_group: 'root' 127 | } 128 | end 129 | 130 | it { is_expected.to contain_file('r10k.yaml').with_content(%r{^postrun:\n.*"/usr/bin/curl"\n.*"-F"\n.*deploy=done\n.*http://my-app\.site/endpoint\n}) } 131 | end 132 | 133 | context 'with empty proxy' do 134 | let :params do 135 | { 136 | proxy: :undef 137 | } 138 | end 139 | 140 | it { is_expected.to contain_file('r10k.yaml').without_content(%r{^proxy: .*$}) } 141 | end 142 | 143 | context 'with proxy' do 144 | let :params do 145 | { 146 | proxy: 'https://proxy.local:8080' 147 | } 148 | end 149 | 150 | it { is_expected.to contain_file('r10k.yaml').with_content(%r{^proxy: https://proxy.local:8080$}) } 151 | end 152 | 153 | context 'with pool_size' do 154 | let :params do 155 | { 156 | pool_size: 5 157 | } 158 | end 159 | 160 | it { is_expected.to contain_file('r10k.yaml').with_content(%r{^pool_size: 5$}) } 161 | end 162 | # This install method uses the archived puppetlabs/ruby module 163 | # It doesn't support Gentoo 164 | 165 | context 'with gem provider', if: os_facts[:os]['name'] != 'Gentoo' do 166 | let :params do 167 | { 168 | install_options: '', 169 | provider: 'gem', 170 | version: version, 171 | puppet_master: true 172 | } 173 | end 174 | 175 | it do 176 | expect(subject).to contain_package('r10k').with( 177 | ensure: version, 178 | provider: 'gem' 179 | ) 180 | end 181 | end 182 | 183 | context 'with gem with empty install_options', if: os_facts[:os]['name'] != 'Gentoo' do 184 | let :params do 185 | { 186 | provider: 'gem', 187 | version: version, 188 | install_options: [], 189 | puppet_master: true 190 | } 191 | end 192 | 193 | it do 194 | expect(subject).to contain_package('r10k').with( 195 | ensure: version, 196 | provider: 'gem', 197 | install_options: ['--no-document'] 198 | ) 199 | end 200 | end 201 | 202 | context 'with gem with populated install_options', if: os_facts[:os]['name'] != 'Gentoo' do 203 | let :params do 204 | { 205 | provider: 'gem', 206 | version: version, 207 | install_options: ['BOGON'], 208 | puppet_master: true 209 | } 210 | end 211 | 212 | it do 213 | expect(subject).to contain_package('r10k').with( 214 | ensure: version, 215 | provider: 'gem', 216 | install_options: ['BOGON'] 217 | ) 218 | end 219 | end 220 | 221 | context 'with puppet_gem provider' do 222 | let :params do 223 | { 224 | version: version, 225 | provider: 'puppet_gem', 226 | install_options: '' 227 | } 228 | end 229 | 230 | it { is_expected.to contain_class('r10k::install::puppet_gem') } 231 | 232 | it do 233 | expect(subject).to contain_package('r10k').with( 234 | ensure: version, 235 | provider: 'puppet_gem' 236 | ) 237 | end 238 | end 239 | 240 | context 'with puppet_gem on Puppet FOSS' do 241 | let :params do 242 | { 243 | install_options: '', 244 | provider: 'puppet_gem', 245 | version: version, 246 | } 247 | end 248 | 249 | it { 250 | is_expected.to contain_package('r10k').with( 251 | ensure: version, 252 | provider: 'puppet_gem' 253 | ) 254 | } 255 | 256 | it do 257 | expect(subject).to contain_file('/usr/bin/r10k').with( 258 | ensure: 'link', 259 | target: '/opt/puppetlabs/puppet/bin/r10k', 260 | require: 'Package[r10k]' 261 | ) 262 | end 263 | end 264 | 265 | context 'with defaults and source specified', if: os_facts[:os]['name'] != 'Gentoo' do 266 | let :params do 267 | { 268 | provider: 'gem', 269 | version: version, 270 | gem_source: 'https://some.alternate.source.com/', 271 | install_options: [], 272 | puppet_master: true 273 | } 274 | end 275 | 276 | it do 277 | expect(subject).to contain_package('r10k').with( 278 | ensure: version, 279 | provider: 'gem', 280 | source: 'https://some.alternate.source.com/' 281 | ) 282 | end 283 | end 284 | 285 | context 'with bundle provider' do 286 | let :params do 287 | { 288 | version: version, 289 | provider: 'bundle', 290 | install_options: '', 291 | puppet_master: true 292 | } 293 | end 294 | 295 | it { is_expected.to contain_class('r10k::install::bundle') } 296 | it { is_expected.not_to contain_package('r10k') } 297 | end 298 | end 299 | end 300 | end 301 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 Puppet Labs Inc 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 | -------------------------------------------------------------------------------- /REFERENCE.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | 4 | 5 | ## Table of Contents 6 | 7 | ### Classes 8 | 9 | #### Public Classes 10 | 11 | * [`r10k`](#r10k): This class configures r10k 12 | * [`r10k::install::bundle`](#r10k--install--bundle): This class installs the r10k bundle 13 | * [`r10k::install::puppet_gem`](#r10k--install--puppet_gem): This class links the r10k binary for Puppet FOSS 4.2 and up 14 | * [`r10k::mcollective`](#r10k--mcollective): Install the r10k mcollective agent 15 | * [`r10k::mcollective::application`](#r10k--mcollective--application): Install the r10k mcollective application to a client 16 | * [`r10k::params`](#r10k--params): Reasonable defaults for all classes 17 | * [`r10k::postrun_command`](#r10k--postrun_command): This class will configure r10k to run as part of the masters agent run 18 | * [`r10k::prerun_command`](#r10k--prerun_command): This class will configure r10k to run as part of the masters agent run 19 | * [`r10k::webhook`](#r10k--webhook): install and configure the webhook-go package as local webhook receiver to trigger r10k runs 20 | * [`r10k::webhook::config`](#r10k--webhook--config): Class: r10k::webhook::config 21 | * [`r10k::webhook::package`](#r10k--webhook--package): Class: r10k::webhook::package 22 | * [`r10k::webhook::service`](#r10k--webhook--service): Class: r10k::webhook::service 23 | 24 | #### Private Classes 25 | 26 | * `r10k::config`: Set up the root r10k config file (/etc/r10k.yaml). 27 | * `r10k::install`: This class is used by the ruby or pe_ruby class 28 | 29 | ### Data types 30 | 31 | * [`R10k::Webhook::Config`](#R10k--Webhook--Config): webhook config type 32 | * [`R10k::Webhook::Config::Chatops`](#R10k--Webhook--Config--Chatops): webhook config chatops type 33 | * [`R10k::Webhook::Config::R10k`](#R10k--Webhook--Config--R10k): webhook config r10k type 34 | * [`R10k::Webhook::Config::Server`](#R10k--Webhook--Config--Server): webhook config server type 35 | * [`R10k::Webhook::Config::Server::Queue`](#R10k--Webhook--Config--Server--Queue): webhook config server queue type 36 | * [`R10k::Webhook::Config::Server::Tls`](#R10k--Webhook--Config--Server--Tls): webhook config server tls type 37 | 38 | ### Tasks 39 | 40 | * [`deploy`](#deploy): Trigger an r10k deployment. 41 | 42 | ## Classes 43 | 44 | ### `r10k` 45 | 46 | This class configures r10k 47 | 48 | #### Parameters 49 | 50 | The following parameters are available in the `r10k` class: 51 | 52 | * [`remote`](#-r10k--remote) 53 | * [`configfile`](#-r10k--configfile) 54 | * [`version`](#-r10k--version) 55 | * [`puppet_master`](#-r10k--puppet_master) 56 | * [`modulepath`](#-r10k--modulepath) 57 | * [`manage_modulepath`](#-r10k--manage_modulepath) 58 | * [`r10k_basedir`](#-r10k--r10k_basedir) 59 | * [`package_name`](#-r10k--package_name) 60 | * [`provider`](#-r10k--provider) 61 | * [`gentoo_keywords`](#-r10k--gentoo_keywords) 62 | * [`install_options`](#-r10k--install_options) 63 | * [`mcollective`](#-r10k--mcollective) 64 | * [`git_settings`](#-r10k--git_settings) 65 | * [`deploy_settings`](#-r10k--deploy_settings) 66 | * [`root_user`](#-r10k--root_user) 67 | * [`gem_source`](#-r10k--gem_source) 68 | * [`root_group`](#-r10k--root_group) 69 | * [`include_prerun_command`](#-r10k--include_prerun_command) 70 | * [`include_postrun_command`](#-r10k--include_postrun_command) 71 | * [`puppetconf_path`](#-r10k--puppetconf_path) 72 | * [`cachedir`](#-r10k--cachedir) 73 | * [`sources`](#-r10k--sources) 74 | * [`postrun`](#-r10k--postrun) 75 | * [`manage_configfile_symlink`](#-r10k--manage_configfile_symlink) 76 | * [`configfile_symlink`](#-r10k--configfile_symlink) 77 | * [`forge_settings`](#-r10k--forge_settings) 78 | * [`proxy`](#-r10k--proxy) 79 | * [`pool_size`](#-r10k--pool_size) 80 | * [`ensure`](#-r10k--ensure) 81 | 82 | ##### `remote` 83 | 84 | Data type: `String[1]` 85 | 86 | 87 | 88 | Default value: `$r10k::params::remote` 89 | 90 | ##### `configfile` 91 | 92 | Data type: `Stdlib::Absolutepath` 93 | 94 | 95 | 96 | Default value: `'/etc/puppetlabs/r10k/r10k.yaml'` 97 | 98 | ##### `version` 99 | 100 | Data type: `String[1]` 101 | 102 | 103 | 104 | Default value: `$r10k::params::version` 105 | 106 | ##### `puppet_master` 107 | 108 | Data type: `Boolean` 109 | 110 | 111 | 112 | Default value: `$r10k::params::puppet_master` 113 | 114 | ##### `modulepath` 115 | 116 | Data type: `String[1]` 117 | 118 | 119 | 120 | Default value: `$r10k::params::modulepath` 121 | 122 | ##### `manage_modulepath` 123 | 124 | Data type: `Boolean` 125 | 126 | 127 | 128 | Default value: `$r10k::params::manage_modulepath` 129 | 130 | ##### `r10k_basedir` 131 | 132 | Data type: `Stdlib::Absolutepath` 133 | 134 | 135 | 136 | Default value: `$r10k::params::r10k_basedir` 137 | 138 | ##### `package_name` 139 | 140 | Data type: `String[1]` 141 | 142 | 143 | 144 | Default value: `$r10k::params::package_name` 145 | 146 | ##### `provider` 147 | 148 | Data type: `String[1]` 149 | 150 | 151 | 152 | Default value: `$r10k::params::provider` 153 | 154 | ##### `gentoo_keywords` 155 | 156 | Data type: `String` 157 | 158 | 159 | 160 | Default value: `''` 161 | 162 | ##### `install_options` 163 | 164 | Data type: `Variant[Array,String]` 165 | 166 | 167 | 168 | Default value: `[]` 169 | 170 | ##### `mcollective` 171 | 172 | Data type: `Boolean` 173 | 174 | 175 | 176 | Default value: `$r10k::params::mcollective` 177 | 178 | ##### `git_settings` 179 | 180 | Data type: `Optional[Hash]` 181 | 182 | 183 | 184 | Default value: `undef` 185 | 186 | ##### `deploy_settings` 187 | 188 | Data type: `Hash` 189 | 190 | 191 | 192 | Default value: `{ 'generate_types' => true, 'exclude_spec' => true, }` 193 | 194 | ##### `root_user` 195 | 196 | Data type: `String[1]` 197 | 198 | 199 | 200 | Default value: `$r10k::params::root_user` 201 | 202 | ##### `gem_source` 203 | 204 | Data type: `Optional[String[1]]` 205 | 206 | 207 | 208 | Default value: `undef` 209 | 210 | ##### `root_group` 211 | 212 | Data type: `String[1]` 213 | 214 | 215 | 216 | Default value: `$r10k::params::root_group` 217 | 218 | ##### `include_prerun_command` 219 | 220 | Data type: `Boolean` 221 | 222 | 223 | 224 | Default value: `false` 225 | 226 | ##### `include_postrun_command` 227 | 228 | Data type: `Boolean` 229 | 230 | 231 | 232 | Default value: `false` 233 | 234 | ##### `puppetconf_path` 235 | 236 | Data type: `Stdlib::Absolutepath` 237 | 238 | 239 | 240 | Default value: `$r10k::params::puppetconf_path` 241 | 242 | ##### `cachedir` 243 | 244 | Data type: `Stdlib::Absolutepath` 245 | 246 | Path to a directory to be used by r10k for caching data 247 | 248 | Default value: `"${facts['puppet_vardir']}/r10k"` 249 | 250 | ##### `sources` 251 | 252 | Data type: `Optional[Hash]` 253 | 254 | Hash containing data sources to be used by r10k to create dynamic Puppet environments 255 | 256 | Default value: `undef` 257 | 258 | ##### `postrun` 259 | 260 | Data type: `Optional[Array[String[1]]]` 261 | 262 | Array containing the parts of a system call Example: ['/usr/bin/curl', '-F', 'deploy=done', 'http://my-app.site/endpoint'] 263 | 264 | Default value: `undef` 265 | 266 | ##### `manage_configfile_symlink` 267 | 268 | Data type: `Boolean` 269 | 270 | determine if a symlink to the r10k config file is to be managed 271 | 272 | Default value: `false` 273 | 274 | ##### `configfile_symlink` 275 | 276 | Data type: `Stdlib::Absolutepath` 277 | 278 | Location of symlink that points to configfile 279 | 280 | Default value: `'/etc/r10k.yaml'` 281 | 282 | ##### `forge_settings` 283 | 284 | Data type: `Optional[Hash]` 285 | 286 | Hash containing settings for downloading modules from the Puppet Forge 287 | 288 | Default value: `undef` 289 | 290 | ##### `proxy` 291 | 292 | Data type: `Optional[String[1]]` 293 | 294 | String containing proxy setting for r10k.yaml 295 | 296 | Default value: `undef` 297 | 298 | ##### `pool_size` 299 | 300 | Data type: `Integer[1]` 301 | 302 | Integer defining how many threads should be spawn while updating modules 303 | 304 | Default value: `$facts['processors']['count']` 305 | 306 | ##### `ensure` 307 | 308 | Data type: `Enum['absent','present']` 309 | 310 | if r10k should be installed or purged 311 | 312 | Default value: `'present'` 313 | 314 | ### `r10k::install::bundle` 315 | 316 | This class installs the r10k bundle 317 | 318 | #### Parameters 319 | 320 | The following parameters are available in the `r10k::install::bundle` class: 321 | 322 | * [`revision`](#-r10k--install--bundle--revision) 323 | * [`source`](#-r10k--install--bundle--source) 324 | 325 | ##### `revision` 326 | 327 | Data type: `String[1]` 328 | 329 | 330 | 331 | Default value: `'master'` 332 | 333 | ##### `source` 334 | 335 | Data type: `String[1]` 336 | 337 | 338 | 339 | Default value: `'https://github.com/adrienthebo/r10k.git'` 340 | 341 | ### `r10k::install::puppet_gem` 342 | 343 | This class links the r10k binary for Puppet FOSS 4.2 and up 344 | 345 | ### `r10k::mcollective` 346 | 347 | Install the r10k mcollective agent 348 | 349 | #### Parameters 350 | 351 | The following parameters are available in the `r10k::mcollective` class: 352 | 353 | * [`ensure`](#-r10k--mcollective--ensure) 354 | * [`server`](#-r10k--mcollective--server) 355 | * [`client`](#-r10k--mcollective--client) 356 | * [`http_proxy`](#-r10k--mcollective--http_proxy) 357 | * [`policies`](#-r10k--mcollective--policies) 358 | 359 | ##### `ensure` 360 | 361 | Data type: `String[1]` 362 | 363 | 364 | 365 | Default value: `'present'` 366 | 367 | ##### `server` 368 | 369 | Data type: `Boolean` 370 | 371 | 372 | 373 | Default value: `true` 374 | 375 | ##### `client` 376 | 377 | Data type: `Boolean` 378 | 379 | 380 | 381 | Default value: `true` 382 | 383 | ##### `http_proxy` 384 | 385 | Data type: `String` 386 | 387 | 388 | 389 | Default value: `''` 390 | 391 | ##### `policies` 392 | 393 | Data type: `Array` 394 | 395 | 396 | 397 | Default value: `[]` 398 | 399 | ### `r10k::mcollective::application` 400 | 401 | Install the r10k mcollective application to a client 402 | 403 | #### Parameters 404 | 405 | The following parameters are available in the `r10k::mcollective::application` class: 406 | 407 | * [`agent_name`](#-r10k--mcollective--application--agent_name) 408 | * [`app_name`](#-r10k--mcollective--application--app_name) 409 | * [`agent_ddl`](#-r10k--mcollective--application--agent_ddl) 410 | * [`agent_path`](#-r10k--mcollective--application--agent_path) 411 | * [`app_path`](#-r10k--mcollective--application--app_path) 412 | * [`mc_service`](#-r10k--mcollective--application--mc_service) 413 | 414 | ##### `agent_name` 415 | 416 | Data type: `Optional[String]` 417 | 418 | 419 | 420 | Default value: `$r10k::params::mc_agent_name` 421 | 422 | ##### `app_name` 423 | 424 | Data type: `Optional[String]` 425 | 426 | 427 | 428 | Default value: `$r10k::params::mc_app_name` 429 | 430 | ##### `agent_ddl` 431 | 432 | Data type: `Optional[String]` 433 | 434 | 435 | 436 | Default value: `$r10k::params::mc_agent_ddl_name` 437 | 438 | ##### `agent_path` 439 | 440 | Data type: `Optional[String]` 441 | 442 | 443 | 444 | Default value: `$r10k::params::mc_agent_path` 445 | 446 | ##### `app_path` 447 | 448 | Data type: `Optional[String]` 449 | 450 | 451 | 452 | Default value: `$r10k::params::mc_application_path` 453 | 454 | ##### `mc_service` 455 | 456 | Data type: `Optional[String]` 457 | 458 | 459 | 460 | Default value: `$r10k::params::mc_service_name` 461 | 462 | ### `r10k::params` 463 | 464 | Reasonable defaults for all classes 465 | 466 | ### `r10k::postrun_command` 467 | 468 | This class will configure r10k to run as part of the masters agent run 469 | 470 | #### Parameters 471 | 472 | The following parameters are available in the `r10k::postrun_command` class: 473 | 474 | * [`command`](#-r10k--postrun_command--command) 475 | * [`ensure`](#-r10k--postrun_command--ensure) 476 | 477 | ##### `command` 478 | 479 | Data type: `String[1]` 480 | 481 | 482 | 483 | Default value: `$r10k::params::pre_postrun_command` 484 | 485 | ##### `ensure` 486 | 487 | Data type: `Enum['present', 'absent']` 488 | 489 | 490 | 491 | Default value: `'present'` 492 | 493 | ### `r10k::prerun_command` 494 | 495 | This class will configure r10k to run as part of the masters agent run 496 | 497 | #### Parameters 498 | 499 | The following parameters are available in the `r10k::prerun_command` class: 500 | 501 | * [`command`](#-r10k--prerun_command--command) 502 | * [`ensure`](#-r10k--prerun_command--ensure) 503 | 504 | ##### `command` 505 | 506 | Data type: `String[1]` 507 | 508 | 509 | 510 | Default value: `$r10k::params::pre_postrun_command` 511 | 512 | ##### `ensure` 513 | 514 | Data type: `Enum['present', 'absent']` 515 | 516 | 517 | 518 | Default value: `'present'` 519 | 520 | ### `r10k::webhook` 521 | 522 | install and configure the webhook-go package as local webhook receiver to trigger r10k runs 523 | 524 | #### Parameters 525 | 526 | The following parameters are available in the `r10k::webhook` class: 527 | 528 | * [`service_user`](#-r10k--webhook--service_user) 529 | * [`install_method`](#-r10k--webhook--install_method) 530 | * [`ensure`](#-r10k--webhook--ensure) 531 | * [`version`](#-r10k--webhook--version) 532 | * [`service_ensure`](#-r10k--webhook--service_ensure) 533 | * [`service_enabled`](#-r10k--webhook--service_enabled) 534 | * [`config_ensure`](#-r10k--webhook--config_ensure) 535 | * [`config_path`](#-r10k--webhook--config_path) 536 | * [`chatops`](#-r10k--webhook--chatops) 537 | * [`tls`](#-r10k--webhook--tls) 538 | * [`queue`](#-r10k--webhook--queue) 539 | * [`server`](#-r10k--webhook--server) 540 | * [`r10k`](#-r10k--webhook--r10k) 541 | * [`config`](#-r10k--webhook--config) 542 | 543 | ##### `service_user` 544 | 545 | Data type: `Optional` 546 | 547 | the user that should run the service 548 | 549 | Default value: `undef` 550 | 551 | ##### `install_method` 552 | 553 | Data type: `Enum['package', 'repo', 'none']` 554 | 555 | how the package should be installed 556 | 557 | Default value: `'package'` 558 | 559 | ##### `ensure` 560 | 561 | Data type: `Boolean` 562 | 563 | 564 | 565 | Default value: `false` 566 | 567 | ##### `version` 568 | 569 | Data type: `String[1]` 570 | 571 | 572 | 573 | Default value: `'2.10.0'` 574 | 575 | ##### `service_ensure` 576 | 577 | Data type: 578 | 579 | ```puppet 580 | Variant[ 581 | Enum['running', 'stopped'], 582 | Boolean 583 | ] 584 | ``` 585 | 586 | 587 | 588 | Default value: `'running'` 589 | 590 | ##### `service_enabled` 591 | 592 | Data type: `Boolean` 593 | 594 | 595 | 596 | Default value: `true` 597 | 598 | ##### `config_ensure` 599 | 600 | Data type: `String` 601 | 602 | 603 | 604 | Default value: `'file'` 605 | 606 | ##### `config_path` 607 | 608 | Data type: `String` 609 | 610 | 611 | 612 | Default value: `'/etc/voxpupuli/webhook.yml'` 613 | 614 | ##### `chatops` 615 | 616 | Data type: `R10k::Webhook::Config::ChatOps` 617 | 618 | 619 | 620 | Default value: 621 | 622 | ```puppet 623 | { 624 | enabled => false, 625 | service => undef, 626 | channel => undef, 627 | user => undef, 628 | auth_token => undef, 629 | server_uri => undef, 630 | } 631 | ``` 632 | 633 | ##### `tls` 634 | 635 | Data type: `R10k::Webhook::Config::Server::Tls` 636 | 637 | 638 | 639 | Default value: 640 | 641 | ```puppet 642 | { 643 | enabled => false, 644 | certificate => undef, 645 | key => undef, 646 | } 647 | ``` 648 | 649 | ##### `queue` 650 | 651 | Data type: `R10k::Webhook::Config::Server::Queue` 652 | 653 | 654 | 655 | Default value: 656 | 657 | ```puppet 658 | { 659 | enabled => false, 660 | max_concurrent_jobs => undef, 661 | max_history_items => undef, 662 | } 663 | ``` 664 | 665 | ##### `server` 666 | 667 | Data type: `R10k::Webhook::Config::Server` 668 | 669 | 670 | 671 | Default value: 672 | 673 | ```puppet 674 | { 675 | protected => true, 676 | user => 'puppet', 677 | password => 'puppet', 678 | port => 4000, 679 | tls => $tls, 680 | queue => $queue, 681 | } 682 | ``` 683 | 684 | ##### `r10k` 685 | 686 | Data type: `R10k::Webhook::Config::R10k` 687 | 688 | 689 | 690 | Default value: 691 | 692 | ```puppet 693 | { 694 | command_path => '/opt/puppetlabs/puppet/bin/r10k', 695 | config_path => '/etc/puppetlabs/r10k/r10k.yaml', 696 | default_branch => 'production', 697 | prefix => undef, 698 | allow_uppercase => false, 699 | verbose => true, 700 | deploy_modules => true, 701 | generate_types => true, 702 | } 703 | ``` 704 | 705 | ##### `config` 706 | 707 | Data type: `R10k::Webhook::Config` 708 | 709 | 710 | 711 | Default value: 712 | 713 | ```puppet 714 | { 715 | server => $server, 716 | chatops => $chatops, 717 | r10k => $r10k, 718 | } 719 | ``` 720 | 721 | ### `r10k::webhook::config` 722 | 723 | Class: r10k::webhook::config 724 | 725 | ### `r10k::webhook::package` 726 | 727 | Class: r10k::webhook::package 728 | 729 | ### `r10k::webhook::service` 730 | 731 | Class: r10k::webhook::service 732 | 733 | ## Data types 734 | 735 | ### `R10k::Webhook::Config` 736 | 737 | webhook config type 738 | 739 | Alias of 740 | 741 | ```puppet 742 | Struct[{ 743 | server => Optional[R10k::Webhook::Config::Server], 744 | chatops => Optional[R10k::Webhook::Config::Chatops], 745 | r10k => Optional[R10k::Webhook::Config::R10k], 746 | }] 747 | ``` 748 | 749 | ### `R10k::Webhook::Config::Chatops` 750 | 751 | webhook config chatops type 752 | 753 | Alias of 754 | 755 | ```puppet 756 | Struct[{ 757 | enabled => Boolean, 758 | service => Optional[Enum['slack', 'rocketchat']], 759 | channel => Optional[String[1]], 760 | user => Optional[String[1]], 761 | auth_token => Optional[String[1]], 762 | server_uri => Optional[String[1]], 763 | }] 764 | ``` 765 | 766 | ### `R10k::Webhook::Config::R10k` 767 | 768 | webhook config r10k type 769 | 770 | Alias of 771 | 772 | ```puppet 773 | Struct[{ 774 | command_path => Optional[Stdlib::Absolutepath], 775 | config_path => Optional[Stdlib::Absolutepath], 776 | default_branch => Optional[String[1]], 777 | prefix => Optional[String[1]], 778 | allow_uppercase => Optional[Boolean], 779 | verbose => Optional[Boolean], 780 | deploy_modules => Optional[Boolean], 781 | generate_types => Optional[Boolean], 782 | }] 783 | ``` 784 | 785 | ### `R10k::Webhook::Config::Server` 786 | 787 | webhook config server type 788 | 789 | Alias of 790 | 791 | ```puppet 792 | Struct[{ 793 | protected => Boolean, 794 | user => Optional[String[1]], 795 | password => Optional[String[1]], 796 | port => Optional[Stdlib::Port], 797 | tls => Optional[R10k::Webhook::Config::Server::Tls], 798 | queue => Optional[R10k::Webhook::Config::Server::Queue], 799 | }] 800 | ``` 801 | 802 | ### `R10k::Webhook::Config::Server::Queue` 803 | 804 | webhook config server queue type 805 | 806 | Alias of 807 | 808 | ```puppet 809 | Struct[{ 810 | enabled => Boolean, 811 | max_concurrent_jobs => Optional[Integer], 812 | max_history_items => Optional[Integer], 813 | }] 814 | ``` 815 | 816 | ### `R10k::Webhook::Config::Server::Tls` 817 | 818 | webhook config server tls type 819 | 820 | Alias of 821 | 822 | ```puppet 823 | Struct[{ 824 | enabled => Boolean, 825 | certificate => Optional[Stdlib::Absolutepath], 826 | key => Optional[Stdlib::Absolutepath], 827 | }] 828 | ``` 829 | 830 | ## Tasks 831 | 832 | ### `deploy` 833 | 834 | Trigger an r10k deployment. 835 | 836 | **Supports noop?** false 837 | 838 | #### Parameters 839 | 840 | ##### `environment` 841 | 842 | Data type: `Optional[Pattern[/\A[a-zA-Z0-9_]+\Z/]]` 843 | 844 | The environment to deploy. 845 | 846 | ##### `environments` 847 | 848 | Data type: `Optional[Pattern[/\A[a-zA-Z0-9_,]+\Z/]]` 849 | 850 | A comma separated list of environments to deploy. Takes precedence over `environment`. 851 | 852 | ##### `module` 853 | 854 | Data type: `Optional[Pattern[/\A[a-z0-9_]+\Z/]]` 855 | 856 | A module to deploy across all environments. 857 | 858 | ##### `modules` 859 | 860 | Data type: `Optional[Pattern[/\A[a-z0-9_,]+\Z/]]` 861 | 862 | A comma separated list of modules to deploy. Takes precedence over `module`. 863 | 864 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # r10k Configuration Module 2 | [![Puppet Forge](http://img.shields.io/puppetforge/v/puppet/r10k.svg)](https://forge.puppetlabs.com/puppet/r10k) 3 | ![Build Status](https://github.com/voxpupuli/puppet-r10k/actions/workflows/ci.yml/badge.svg?branch=master) 4 | [![Github Tag](https://img.shields.io/github/tag/voxpupuli/puppet-r10k.svg)](https://github.com/voxpupuli/puppet-r10k) 5 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/voxpupuli/puppet-r10k?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 6 | [![Puppet Forge Downloads](http://img.shields.io/puppetforge/dt/puppet/r10k.svg)](https://forge.puppetlabs.com/puppet/r10k) 7 | [![Puppet Forge Endorsement](https://img.shields.io/puppetforge/e/puppet/r10k.svg)](https://forge.puppetlabs.com/puppet/r10k) 8 | 9 | 10 | #### Table of Contents 11 | 12 | 1. [Overview](#overview) 13 | 1. [Module Description - What the module does and why it is useful](#module-description) 14 | 1. [Setup - The basics of getting started with r10k](#setup) 15 | * [Prefix Example](#prefix-example) 16 | * [What r10k affects](#what-r10k-affects) 17 | * [Setup Requirements](#setup-requirements) 18 | * [Beginning with r10k](#beginning-with-r10k) 19 | * [Using an internal gem server](#using-an-internal-gem-server) 20 | * [Mcollective Support](#mcollective-support) 21 | 1. [Webhook Support](#webhook-support) 22 | 1. [Reference - An under-the-hood peek at what the module is doing and how](#reference) 23 | 1. [Limitations - OS compatibility, etc.](#limitations) 24 | 1. [Support](#support) 25 | 1. [Development - Guide for contributing to the module](#development) 26 | 1. [Running tests](#running-tests) 27 | 28 | ## Overview 29 | 30 | This module was built to install and configure r10k. It has a base class to configure r10k to 31 | synchronize [dynamic environments](https://github.com/adrienthebo/r10k/blob/master/doc/dynamic-environments.mkd). 32 | It also has a series of lateral scripts and tools that assist in general workflow, that will be separated into 33 | their own modules into the future. 34 | 35 | ## Module Description 36 | 37 | This module is meant to manage the installation and configuration of r10k using multiple installation methods on multiple platforms. 38 | 39 | ## Setup 40 | 41 | Please refer to the official [r10k docs](https://github.com/puppetlabs/r10k/tree/master/doc) for specific configuration patterns. 42 | 43 | ### Prefix Example 44 | Instead of passing a single `remote`, you can pass a puppet [hash](https://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#hashes) as the `sources` 45 | parameter. This allows you to configure r10k with [prefix](https://github.com/puppetlabs/r10k/blob/910709a2924d6167e2e53e03d64d2cc1a64827d4/doc/dynamic-environments/configuration.mkd#prefix) support. This often used when multiple teams use separate repos, or if hiera and puppet are distributed across two repos. 46 | 47 | ```puppet 48 | class { 'r10k': 49 | sources => { 50 | 'webteam' => { 51 | 'remote' => 'ssh://git@github.com/webteam/somerepo.git', 52 | 'basedir' => "${::settings::codedir}/environments", 53 | 'prefix' => true, 54 | }, 55 | 'secteam' => { 56 | 'remote' => 'ssh://git@github.com/secteam/someotherrepo.git', 57 | 'basedir' => '/some/other/basedir', 58 | 'prefix' => true, 59 | }, 60 | }, 61 | } 62 | ``` 63 | ### What r10k affects 64 | 65 | * Installation of the r10k `gem` 66 | * Installation of ruby when not using an existing ruby stack i.e. when using `puppet_gem` 67 | * Management of the `r10k.yaml` in /etc 68 | * Installation and configuration of a sinatra app when using the [webhook](#webhook-support). 69 | 70 | 71 | #### Version chart 72 | 73 | Gem installation is pinned to a default version in this module, the following chart shows the gem installation tested with the respective module version. 74 | You can override this by passing the `version` parameter. 75 | 76 | | Module Version | r10k Version | 77 | | -------------- | ------------ | 78 | | v4.0.0+ | [![Latest Version](https://img.shields.io/gem/v/r10k.svg?style=flat-square)](https://rubygems.org/gems/r10k) | 79 | | v3.0.x | 1.5.1 | 80 | | v2.8.2 | 1.5.1 | 81 | | v2.7.x | 1.5.1 | 82 | | v2.6.5 | 1.4.1 | 83 | | v2.5.4 | 1.4.0 | 84 | | v2.4.4 | 1.3.5 | 85 | | v2.3.1 | 1.3.4 | 86 | | v2.3.0 | 1.3.2 | 87 | | v2.2.8 | 1.3.1 | 88 | | v2.2.x | 1.1.0 | 89 | 90 | 91 | ### Setup Requirements 92 | 93 | r10k connects via ssh and does so silently in the background, this typically requires ssh keys to be deployed in advance of configuring r10k. This includes the known host ( public ) key of the respective git server, and the user running r10k's private key used to authenticate git/ssh during background runs. If you are going to use git repos to retrieve modules, you also need git installed. 94 | 95 | Here is an example of deploying the git package and ssh keys needed for r10k to connect to a repo called puppet/control on a gitlab server. This is helpful when you need to automatically deploy new masters 96 | 97 | ```puppet 98 | package { 'git': 99 | ensure => installed, 100 | } 101 | 102 | #https://docs.puppetlabs.com/references/latest/type.html#sshkey 103 | sshkey { 'your.internal.gitlab.server.com': 104 | ensure => present, 105 | type => 'ssh-rsa', 106 | target => '/root/.ssh/known_hosts', 107 | key => '...+dffsfHQ==', 108 | } 109 | 110 | # Resource git_webhook is provided by https://github.com/bjvrielink/abrader-gms/tree/fixup 111 | git_deploy_key { 'add_deploy_key_to_puppet_control': 112 | ensure => present, 113 | name => $facts['networking']['fqdn'], 114 | path => '/root/.ssh/id_dsa.pub', 115 | token => hiera('gitlab_api_token'), 116 | project_name => 'puppet/control', 117 | server_url => 'http://your.internal.gitlab.server.com', 118 | provider => 'gitlab', 119 | } 120 | ``` 121 | A simple example of creating an ssh private key would use an exec to call `yes y | ssh-keygen -t dsa -C "r10k" -f /root/.ssh/id_dsa -q -N ''`. 122 | The example above shows using `git_deploy_key` which would deploy that key to the remote git server via its api. This is often required in the programtic creation of compile masters. 123 | 124 | Given r10k will likely be downloading your modules, often on the first server 125 | it's run on, you will have to `puppet apply` this module to bootstrap this 126 | configuration and allow for ongoing management from there. 127 | 128 | ### Beginning with r10k 129 | 130 | The simplest example of using it would be to declare a single remote that would be written to r10k.yaml. 131 | 132 | ```puppet 133 | class { 'r10k': 134 | remote => 'git@github.com:someuser/puppet.git', 135 | } 136 | ``` 137 | This will configure `/etc/r10k.yaml` and install the r10k gem after installing 138 | ruby using the [puppetlabs/ruby](http://forge.puppetlabs.com/puppetlabs/ruby) module. 139 | 140 | It also supports installation via multiple providers, such as installation in the puppet_enterprise ruby stack in versions less than 3.8 141 | 142 | Installing into the Puppet Enterprise ruby stack in PE 2015.x 143 | 144 | ```puppet 145 | class { 'r10k': 146 | remote => 'git@github.com:someuser/puppet.git', 147 | provider => 'puppet_gem', 148 | } 149 | ``` 150 | 151 | _Note: It is recommended you migrate to using the `pe_r10k` module which is basically 152 | a clone of this modules features and file tickets for anything missing._ 153 | 154 | 155 | ### Using an internal gem server 156 | 157 | Depending on implementation requirements, there are two ways to use alternate gem sources. 158 | 159 | #### The gemrc approach 160 | Create a global gemrc for Puppet Enterprise to add the local gem source. See http://projects.puppetlabs.com/issues/18053#note-12 for more information. 161 | 162 | ```puppet 163 | file { '/opt/puppet/etc': 164 | ensure => 'directory', 165 | owner => 'root', 166 | group => '0', 167 | mode => '0755', 168 | } 169 | 170 | file { 'gemrc': 171 | ensure => 'file', 172 | path => '/opt/puppet/etc/gemrc', 173 | owner => 'root', 174 | group => '0', 175 | mode => '0644', 176 | content => "---\nupdate_sources: true\n:sources:\n- http://your.internal.gem.server.com/rubygems/\n", 177 | } 178 | 179 | class { 'r10k': 180 | remote => 'git@github.com:someuser/puppet.git', 181 | provider => 'pe_gem', 182 | require => File['gemrc'], 183 | } 184 | ``` 185 | 186 | #### The parameter approach 187 | Add gem_source to declaration. 188 | 189 | ```puppet 190 | class { 'r10k': 191 | remote => 'git@github.com:someuser/puppet.git', 192 | provider => 'gem', 193 | gem_source => 'https://some.alternate.source.com/', 194 | } 195 | ``` 196 | 197 | ### Mcollective Support 198 | ![alt tag](https://gist.githubusercontent.com/acidprime/7013041/raw/1a99e0a8d28b13bc20b74d2dc4ab60c7e752088c/post_recieve_overview.png) 199 | 200 | An mcollective agent is included in this module which can be used to do 201 | on demand synchronization. This mcollective application and agent can be 202 | installed on all masters using the following class 203 | _Note: You must have mcollective already configured for this tool to work, 204 | Puppet Enterprise users will automatically have mcollective configured._ 205 | This class does not restart the mcollective or pe-mcollective server on the 206 | nodes to which it is applied, so you may need to restart mcollective for it 207 | to see the newly installed r10k agent. 208 | ```puppet 209 | include r10k::mcollective 210 | ``` 211 | 212 | Using mco you can then trigger mcollective to call r10k using 213 | 214 | ```shell 215 | mco r10k synchronize 216 | ``` 217 | 218 | You can sync an individual environment using: 219 | 220 | ```shell 221 | mco r10k deploy 222 | ``` 223 | Note: This implies `-p` 224 | 225 | You can sync an individual module using: 226 | 227 | ```shell 228 | mco r10k deploy_module 229 | ``` 230 | 231 | If you are required to run `r10k` as a specific user, you can do so by passing 232 | the `user` parameter: 233 | 234 | ```shell 235 | mco r10k synchronize user=r10k 236 | ``` 237 | 238 | To obtain the output of running the shell command, run the agent like this: 239 | 240 | ```shell 241 | mco rpc r10k synchronize -v 242 | ``` 243 | 244 | An example post-receive hook is included in the files directory. 245 | This hook can automatically cause code to synchronize on your 246 | servers at time of push in git. More modern git systems use webhooks, for those see below. 247 | 248 | #### Passing proxy info through mco 249 | 250 | The mcollective agent can be configured to supply r10k/git environment `http_proxy`, `https_proxy` variables via the following example 251 | 252 | ```puppet 253 | class { 'r10k::mcollective': 254 | http_proxy => 'http://proxy.example.lan:3128', 255 | git_ssl_no_verify => 1, 256 | } 257 | ``` 258 | 259 | #### Install mcollective support for post receive hooks 260 | Install the `mco` command from the puppet enterprise installation directory i.e. 261 | ```shell 262 | cd ~/puppet-enterprise-3.0.1-el-6-x86_64/packages/el-6-x86_64 263 | sudo rpm -i pe-mcollective-client-2.2.4-2.pe.el6.noarch.rpm 264 | ``` 265 | Copy the peadmin mcollective configuration and private keys from the certificate authority (puppet master) 266 | ~~~ 267 | /var/lib/peadmin/.mcollective 268 | /var/lib/peadmin/.mcollective.d/mcollective-public.pem 269 | /var/lib/peadmin/.mcollective.d/peadmin-cacert.pem 270 | /var/lib/peadmin/.mcollective.d/peadmin-cert.pem 271 | /var/lib/peadmin/.mcollective.d/peadmin-private.pem 272 | /var/lib/peadmin/.mcollective.d/peadmin-public.pem 273 | ~~~ 274 | Ensure you update the paths in _~/.mcollective_ when copying to new users whose name is not peadmin. 275 | Ideally mcollective will be used with more then just the peadmin user's certificate 276 | in the future. That said, if your git user does not have a home directory, you can rename .mcollective as /etc/client.cfg 277 | and copy the certs to somewhere that is readable by the respective user. 278 | ~~~ 279 | /home/gitolite/.mcollective 280 | /home/gitolite/.mcollective.d/mcollective-public.pem 281 | /home/gitolite/.mcollective.d/peadmin-cacert.pem 282 | /home/gitolite/.mcollective.d/peadmin-cert.pem 283 | /home/gitolite/.mcollective.d/peadmin-private.pem 284 | /home/gitolite/.mcollective.d/peadmin-public.pem 285 | ~~~ 286 | _Note: PE2 only requires the .mcollective file as the default auth was psk_ 287 | 288 | #### Removing the mcollective agent 289 | 290 | ```puppet 291 | class { 'r10k::mcollective': 292 | ensure => false, 293 | } 294 | ``` 295 | This will remove the mcollective agent/application and ddl files from disk. This likely would be if you are migrating to Code manager in Puppet Enterprise. 296 | 297 | ## Webhook Support 298 | 299 | ![alt tag](https://gist.githubusercontent.com/acidprime/be25026c11a76bf3e7fb/raw/44df86181c3e5d14242a1b1f4281bf24e9c48509/webhook.gif) 300 | For version control systems that use web driven post-receive processes you can use the example webhook included in this module. 301 | When the webhook receives the post-receive event, it will synchronize environments on your puppet masters. 302 | These settings are all configurable for your specific use case, as shown below in these configuration examples. 303 | 304 | **NOTE: MCollective and Bolt aren't currently supported with Webhook Go. This will be addressed in a future release of Webhook Go, but is an issue related to the complex nature of Bolt and MCollective/Choria commands that cause issues with the way Go executes shell commands.** 305 | 306 | ### Webhook Github Enterprise - Non Authenticated 307 | This is an example of using the webhook without authentication. 308 | The `git_webhook` type will use the [api token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) to add the webhook to the "control" repo that contains your puppetfile. This is typically useful when you want to automate the addition of the webhook to the repo. 309 | 310 | ```puppet 311 | # Instead of running via mco, run r10k directly 312 | class {'r10k::webhook::config': 313 | use_mcollective => false, 314 | } 315 | 316 | class {'r10k::webhook': 317 | ensure => true, 318 | server => { 319 | protected => false, 320 | }, 321 | } 322 | 323 | # Add webhook to control repository ( the repo where the Puppetfile lives ) 324 | # 325 | # Resource git_webhook is provided by https://github.com/bjvrielink/abrader-gms/tree/fixup 326 | git_webhook { 'web_post_receive_webhook' : 327 | ensure => present, 328 | webhook_url => 'http://master.of.masters:8088/payload', 329 | token => hiera('github_api_token'), 330 | project_name => 'organization/control', 331 | server_url => 'https://your.github.enterprise.com', 332 | provider => 'github', 333 | } 334 | 335 | 336 | # Add webhook to module repo if we are tracking branch in Puppetfile i.e. 337 | # mod 'module_name', 338 | # :git => 'http://github.com/organization/puppet-module_name', 339 | # :branch => 'master' 340 | # The module name is determined from the repo name , i.e. 341 | # All characters with left and including any hyphen are removed i.e. 342 | # 343 | # Resource git_webhook is provided by https://github.com/bjvrielink/abrader-gms/tree/fixup 344 | git_webhook { 'web_post_receive_webhook_for_module' : 345 | ensure => present, 346 | webhook_url => 'http://master.of.masters:8088/module', 347 | token => hiera('github_api_token'), 348 | project_name => 'organization/puppet-module_name', 349 | server_url => 'https://your.github.enterprise.com', 350 | provider => 'github', 351 | } 352 | ``` 353 | 354 | ### Webhook Github Example - Authenticated 355 | This is an example of using the webhook with authentication. 356 | The `git_webhook` type will use the [api token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) to add the webhook to the "control" repo that contains your puppetfile. This is typically useful when you want to automate the addition of the webhook to the repo. 357 | 358 | ```puppet 359 | # Instead of running via mco, run r10k directly 360 | class {'r10k::webhook::config': 361 | use_mcollective => false, 362 | } 363 | 364 | # External webhooks often need authentication and ssl and authentication 365 | # Change the url below if this is changed 366 | 367 | class {'r10k::webhook': 368 | ensure => true, 369 | server => { 370 | protected => true, 371 | }, 372 | tls => { 373 | enabled => true, 374 | certificate => '/path/to/ssl/certificate', 375 | key => '/path/to/ssl/key', 376 | }, 377 | } 378 | 379 | # Add webhook to control repository ( the repo where the Puppetfile lives ) 380 | # 381 | # Resource git_webhook is provided by https://github.com/bjvrielink/abrader-gms/tree/fixup 382 | git_webhook { 'web_post_receive_webhook' : 383 | ensure => present, 384 | webhook_url => 'https://puppet:puppet@hole.in.firewall:8088/payload', 385 | token => hiera('github_api_token'), 386 | project_name => 'organization/control', 387 | server_url => 'https://api.github.com', 388 | disable_ssl_verify => true, 389 | provider => 'github', 390 | } 391 | 392 | # Add webhook to module repo if we are tracking branch in Puppetfile i.e. 393 | # mod 'module_name', 394 | # :git => 'http://github.com/organization/puppet-module_name', 395 | # :branch => 'master' 396 | # The module name is determined from the repo name , i.e. 397 | # All characters with left and including any hyphen are removed i.e. 398 | # 399 | # Resource git_webhook is provided by https://github.com/bjvrielink/abrader-gms/tree/fixup 400 | git_webhook { 'web_post_receive_webhook_for_module' : 401 | ensure => present, 402 | webhook_url => 'https://puppet:puppet@hole.in.firewall:8088/module', 403 | token => hiera('github_api_token'), 404 | project_name => 'organization/puppet-module_name', 405 | server_url => 'https://api.github.com', 406 | disable_ssl_verify => true, 407 | provider => 'github', 408 | } 409 | ``` 410 | 411 | ### Webhook Bitbucket Example 412 | This is an example of using the webhook with Atlassian Bitbucket (former Stash). 413 | Requires the `external hooks` addon by https://marketplace.atlassian.com/plugins/com.ngs.stash.externalhooks.external-hooks/server/overview 414 | and a specific Bitbucket user/pass. 415 | Remember to place the `stash_mco.rb` on the bitbucket server an make it executable. 416 | Enable the webhook over the repository settings `External Async Post Receive Hook`: 417 | - Executable: e.g. `/opt/atlassian/bitbucket-data/external-hooks/stash_mco.rb` (see hook_exe) 418 | - Positional parameters: `-t http://git.example.com:8088/payload` 419 | 420 | ```puppet 421 | # Add deploy key 422 | git_deploy_key { 'add_deploy_key_to_puppet_control': 423 | ensure => present, 424 | name => $facts['networking']['fqdn'], 425 | path => '/root/.ssh/id_rsa.pub', 426 | username => 'api', 427 | password => 'pass', 428 | project_name => 'project', 429 | repo_name => 'puppet', 430 | server_url => 'https://git.example.com', 431 | provider => 'stash', 432 | } 433 | 434 | # Add webhook 435 | git_webhook { 'web_post_receive_webhook' : 436 | ensure => present, 437 | webhook_url => 'https://puppet:puppet@hole.in.firewall:8088/module', 438 | password => 'pass', 439 | username => 'api', 440 | project_name => 'project', 441 | repo_name => 'puppet', 442 | server_url => 'https://git.example.com', 443 | provider => 'stash', 444 | hook_exe => '/opt/atlassian/bitbucket-data/external-hooks/stash_mco.rb', 445 | } 446 | ``` 447 | 448 | ### Webhook - remove webhook init script and config file. 449 | For use when moving to Code Manager, or other solutions, and the webhook should be removed. 450 | ```puppet 451 | class {'r10k::webhook': 452 | ensure => false, 453 | } 454 | ``` 455 | 456 | ### Webhook Prefix Example 457 | 458 | Prefixing the command is currently not supported in Webhook Go. This support is expected to be added with a later release. 459 | 460 | ### Webhook FOSS support with MCollective 461 | 462 | MCollective is currently unsupported by Webhook Go. This is expected to be added in a future release and documentation will be updated for that then. 463 | 464 | ### Webhook Slack notifications 465 | 466 | You can enable Slack notifications for the webhook. You will need a 467 | Slack webhook URL and the `slack-notifier` gem installed. 468 | 469 | To get the Slack webhook URL you need to: 470 | 471 | 1. Go to 472 | [https://slack.com/apps/A0F7XDUAZ-incoming-webhooks](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks). 473 | 2. Choose your team, press `Configure`. 474 | 3. In configurations press `Add configuration`. 475 | 4. Choose channel, press `Add Incoming WebHooks integration`. 476 | 477 | Then configure the webhook to add your Slack Webhook URL. 478 | 479 | ```puppet 480 | class { 'r10k::webhook': 481 | . . . 482 | chatops => { 483 | enabled => true, 484 | service => 'slack', 485 | server_uri => 'http://slack.webhook/webhook', # mandatory for usage 486 | channel => '#channel', # defaults to #default 487 | user => 'r10k', # the username to use 488 | auth_token => "SLACKAUTHTOKEN", 489 | } 490 | } 491 | ``` 492 | 493 | ### Webhook Rocket.Chat notifications 494 | 495 | You can enable Rocket.Chat notifications for the webhook. You will need a 496 | Rocket.Chat incoming webhook URL and the `rocket-chat-notifier` gem installed. 497 | 498 | To get the Rocket.Chat incoming webhook URL you need to: 499 | 500 | 1. Go to your Rocket.Chat and then select `Administration-Integrations`. 501 | 2. Choose `New integration`. 502 | 3. Choose `Incoming WebHook`. In the webhook form configure: 503 | * `Enabled`: `True`. 504 | * `Name`: A name for your webhook. 505 | * `Post to Channel`: The channel to post to by default. 506 | 4. Save changes with `Save Changes` bottom. 507 | 508 | Then configure the webhook to add your Rocket.Chat Webhook URL. 509 | 510 | ```puppet 511 | class { 'r10k::webhook': 512 | . . . 513 | chatops => { 514 | enabled => true, 515 | service => 'rocketchat', 516 | server_uri => '', 517 | user => 'username', 518 | channel => '#channel', 519 | auth_token => 'ROCKETCHATAUTHTOKEN', 520 | } 521 | } 522 | ``` 523 | 524 | ### Webhook Default Branch 525 | 526 | The default branch of the controlrepo is commonly called `production`. This value can be overridden if you use another default branch name, such as `master`. 527 | 528 | ```puppet 529 | class { 'r10k::webhook': 530 | ensure => true, 531 | r10k => { 532 | default_branch => 'master', # Optional. Defaults to 'production' 533 | }, 534 | } 535 | ``` 536 | 537 | ### Triggering the webhook from curl 538 | 539 | To aid in debugging, or to give you some hints as to how to trigger the webhook by unsupported systems, here's a curl command to trigger the webhook to deploy the 'production' environment: 540 | 541 | ```bash 542 | curl --header "X-Gitlab-Event: Push Hook" -d ' 543 | { 544 | "repository": {"name": "foo", "owner": {"login": "foo"}}, 545 | "ref": "production" 546 | }' http://puppet-master.example:4000/api/v1/r10k/environment 547 | ``` 548 | 549 | If you are utilizing environment prefixes, you'll need to specify the full environment title (including the prefix) in the 'ref' parameter: 550 | 551 | ```bash 552 | curl --header "X-Gitlab-Event: Push Hook" -d ' 553 | { 554 | "repository": {"name": "bar", "owner": {"login": "foo"}}, 555 | "ref": "bar_production" 556 | }' http://puppet-master.example:4000/api/v1/r10k/environment 557 | ``` 558 | 559 | ### Troubleshooting 560 | 561 | If you're not sure whether your webhook setup works: 562 | 563 | - Try to make a GET request to the `heartbeat` endpoint (e.g. http://puppet-master.example:8088/heartbeat). 564 |  You should see a short JSON answer similar to `{"status":"success","message":"running"}`. 565 | - Watch the webhook logfile at `/var/log/webhook/access.log`, and send requests (e.g. using curl). 566 | Example output if successful: 567 | 568 | ``` bash 569 | $ journalctl -f -u webhook-go.service 570 | ... 571 | Jun 05 11:24:54 pop-os systemd[1]: Started Puppet Deployment API Server.... 572 | ``` 573 | 574 | ### Docker 575 | 576 | If you are building your image with the puppet, you need to prevent the webhook process from starting as a daemon. 577 | 578 | The following is an example of declaring the webhook without a background mode 579 | 580 | ```puppet 581 | class { 'r10k::webhook': 582 | ensure => false, 583 | } 584 | ``` 585 | 586 | ### Ignore deploying some environments 587 | 588 | Since [2.10.0](https://github.com/voxpupuli/webhook-go/releases/tag/v2.10.0) the webhook has support for ignoring certain branches. 589 | This is not yet configureable via the puppet module. 590 | 591 | ### configuring the webservice/deploy user 592 | 593 | For historic reasons, webhook-go runs as root and executes r10k with the same user. 594 | Via `r10k::webhook::service_user` you can change the user. 595 | With the 15.0.0 release the default will switch from root to puppet. 596 | 597 | ## Reference 598 | 599 | #### Class: `r10k` 600 | This is the main public class to be declared , handingly installation and configuration declarations 601 | 602 | **Parameters within `r10k`:** 603 | 604 | ##### `remote` 605 | A string to be passed in as the source with a hardcode prefix of `puppet` 606 | 607 | ##### `sources` 608 | A hash of all sources, this gets read out into the file as yaml. Must not be declared with `remote` 609 | 610 | ##### `cachedir` 611 | A single string setting the `r10k.yaml` configuration value of the same name 612 | 613 | ##### `configfile` 614 | A path to the configuration file to manage. Be aware Puppet Enterprise 4.0 and higher may conflict if you manage `/etc/puppetlabs/puppet/r10k.yaml` 615 | 616 | ##### `version` 617 | A value passed to the package resource for managing the gem version 618 | 619 | ##### `modulepath` 620 | Deprecated: for older [configfile](https://docs.puppetlabs.com/puppet/latest/reference/environments_classic.html) environments configuration of modulepath in puppet.conf 621 | 622 | ##### `manage_modulepath` 623 | Deprecated: declare a resource for managing `modulepath` in Puppet.conf 624 | 625 | ##### `proxy` 626 | A string setting the`r10k.yaml` configuration value of the same name 627 | 628 | ##### `gem_source` 629 | An optional string specifying location to retrieve gem 630 | 631 | ##### `pool_size` 632 | Integer defining how many threads should be spawn while updating modules. Only available for r10k >= 3.3.0. 633 | 634 | ##### `r10k_basedir` 635 | 636 | ##### `package_name` 637 | The name of the package to be installed via the provider 638 | 639 | ##### `provider` 640 | The supported installation modes for this module 641 | 642 | * bundle 643 | * puppet_gem 644 | * gem 645 | 646 | ##### `install_options` 647 | Options to pass to the `provider` declaration 648 | 649 | ##### `mcollective` 650 | Install mcollective application and agents. This does NOT configure mcollective automatically 651 | 652 | ##### `manage_configfile_symlink` 653 | Manage a symlink to the configuration file, for systems installed in weird file system configurations 654 | 655 | ##### `git_settings` 656 | This is the `git:` key in r10k, it accepts a hash that can be used to configure 657 | rugged support. 658 | 659 | ```puppet 660 | $git_settings = { 661 | 'provider' => 'rugged', 662 | 'private_key' => '/root/.ssh/id_rsa', 663 | } 664 | 665 | class {'r10k': 666 | remote => 'git@github.com:acidprime/puppet.git', 667 | git_settings => $git_settings, 668 | } 669 | ``` 670 | 671 | ##### `forge_settings` 672 | This is the `forge:` key in r10k, it accepts a hash that contains settings for downloading modules from the Puppet Forge. 673 | 674 | ```puppet 675 | $forge_settings = { 676 | 'proxy' => 'https://proxy.example.com:3128', 677 | 'baseurl' => 'https://forgeapi.puppetlabs.com', 678 | } 679 | 680 | class {'r10k': 681 | remote => 'git@github.com:acidprime/puppet.git', 682 | forge_settings => $forge_settings, 683 | } 684 | ``` 685 | 686 | ##### `deploy_settings` 687 | This is the `deploy:` key in r10k, it accepts a hash that contains setting that control how r10k code deployments behave. Documentation for the settings can be found [here](https://docs.puppet.com/pe/latest/r10k_custom.html#deploy). 688 | 689 | ```puppet 690 | $deploy_settings = { 691 | 'purge_levels' => ['puppetfile'], 692 | } 693 | 694 | class {'r10k': 695 | remote => 'git@github.com:voxpupuli/puppet.git', 696 | deploy_settings => $deploy_settings, 697 | } 698 | ``` 699 | 700 | ##### `configfile_symlink` 701 | boolean if to manage symlink 702 | 703 | ##### `include_prerun_command` 704 | Deprecated: Add [prerun_command](https://docs.puppetlabs.com/references/latest/configuration.html#preruncommand) to puppet.conf to run r10k when the agent on the master runs. 705 | Suggest instead declaring `r10k::postrun_command ` as that will run after the agent runs which prevents r10k from stopping configuration management of masters from occurring as it does with `prerun_command`s 706 | 707 | ##### `include_postrun_command` 708 | ``` 709 | r10k::include_postrun_command: true 710 | ``` 711 | 712 | The concept here is that this is declared on the puppet master(s) that have 713 | been configured with r10k. This will cause r10k to synchronize after each 714 | puppet run. Any errors synchronizing will be logged to the standard puppet run. 715 | 716 | ## Limitations 717 | The 4.1.x release *deprecates* support for: 718 | * Puppet 3 719 | * Ruby 1.9.3 720 | 721 | These items are planned for removal in v5.0.0. 722 | 723 | ## Support 724 | 725 | Please log tickets and issues at our [Projects site](https://github.com/voxpupuli/puppet-r10k/issues) 726 | 727 | ## Development 728 | 729 | ### Contributing 730 | 731 | Modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. 732 | 733 | We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. 734 | 735 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for more details. 736 | 737 | ### Running tests 738 | 739 | This project contains tests for [rspec-puppet](http://rspec-puppet.com/) to 740 | verify functionality. For in-depth information please see their respective 741 | documentation, as well as [CONTRIBUTING](.github/CONTRIBUTING.md). 742 | 743 | Quickstart: 744 | 745 | ``` 746 | gem install bundler 747 | bundle install --without system_tests 748 | bundle exec rake test 749 | bundle exec rake lint 750 | ``` 751 | 752 | Check the .travis.yml for supported Operating System Versions 753 | --------------------------------------------------------------------------------