├── .gitignore ├── .gitreview ├── .pdkignore ├── .zuul.yaml ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── bindep.txt ├── doc └── requirements.txt ├── examples └── virtual_packages.pp ├── facts.d ├── os_immutable.txt └── os_service_default.txt ├── lib ├── facter │ ├── os_service_default.rb │ └── os_workers.rb └── puppet │ ├── functions │ ├── inet6_prefix.rb │ ├── is_service_default.rb │ ├── normalize_ip_for_uri.rb │ ├── os_database_connection.rb │ ├── os_transport_url.rb │ └── os_url.rb │ ├── provider │ ├── openstack.rb │ ├── openstack │ │ ├── auth.rb │ │ └── credentials.rb │ ├── openstack_config │ │ ├── ini_setting.rb │ │ └── ruby.rb │ └── policy_rcd │ │ └── policy_rcd.rb │ ├── type │ ├── openstack_config.rb │ └── policy_rcd.rb │ └── util │ ├── openstackconfig.rb │ └── openstackconfig │ └── section.rb ├── manifests ├── clouds.pp ├── db │ ├── mysql.pp │ ├── mysql │ │ └── host_access.pp │ └── postgresql.pp ├── defaults.pp ├── iscsid.pp ├── messaging │ └── rabbitmq.pp ├── openstackclient.pp ├── params.pp ├── policy.pp ├── policy │ ├── base.pp │ └── default.pp ├── policyrcd.pp ├── service_validation.pp └── wsgi │ └── apache.pp ├── metadata.json ├── releasenotes ├── notes │ ├── Add-TLS-options-for-mysql-user-creation-172536d7f3963ce2.yaml │ ├── access_log_env_var-87f4bfd3356c6cd2.yaml │ ├── add-ssl_verify_client-87e52209cc80861d.yaml │ ├── apache-request_headers-1db72ccfd1e76735.yaml │ ├── apache-vhost-wsgi_daemon_process-3e90ea82934cbaea.yaml │ ├── bugfix-1664561-f5964a3777b9ed93.yaml │ ├── bump-mysql-dep-10-217373db021b4c1f.yaml │ ├── catch_403-237b79f33ab3364f.yaml │ ├── centos-9-support-899c5dc223ded57c.yaml │ ├── clouds-yaml-e8a87dfceba4619d.yaml │ ├── clouds-yaml-owner-group-4e7b2d4e7028cfef.yaml │ ├── db-password_hash-1045114a36b6f292.yaml │ ├── deprecate-puppet-5-support-1864c361a7a9d402.yaml │ ├── deprecate-puppet4-59a430de68834017.yaml │ ├── drop-fedora-66989e6f7049e5bd.yaml │ ├── ensure-policy-file-exists-1c53dc62e10c53d3.yaml │ ├── feature_add_default_config_placeholder-280f69c0edbf76c6.yaml │ ├── feature_add_exclusion_to_retry_mechanism-2acb52fa25bd315c.yaml │ ├── feature_add_transform_for_config.yaml │ ├── fix-openrc-parsing-2cc3a95b3bf2b259.yaml │ ├── ipv6_array_support-ea28cf0939e820f6.yaml │ ├── ipv6_brackets-7a453aea5e091855.yaml │ ├── iscsid-0a9fe8a9dba4047b.yaml │ ├── manage_policy_rc_d_file-747510db06792d52.yaml │ ├── memcached-inet6-prefix-91e867d03bc5f6e2.yaml │ ├── migrate-policy-format-from-json-to-yaml-3389e1d5348cd69b.yaml │ ├── more_db_options-d96316ae4eb5a78c.yaml │ ├── mysql-user-and-grants-optional-fd34f4686d44aec3.yaml │ ├── no-directory-listing-8e6270ed0e1eb1d0.yaml │ ├── openstacklib-multiple-wsgi-script-aliases-34ff48b463416e0f.yaml │ ├── openstacklib-wsgi-apache-keystone-support-54bc020f9f1553c6.yaml │ ├── openstacklib-wsgi-apache-log-level-f0f1567b27c64ac0.yaml │ ├── os_transport-alt-transport-7cd300380ece2fc9.yaml │ ├── os_transport_url-b6fe15a8f21d387b.yaml │ ├── os_url-efc774dd8ab4571d.yaml │ ├── os_workers-fact-0ce731f0536c2792.yaml │ ├── os_workers-fact-420e6ad783cba982.yaml │ ├── os_workers_for_worker_count-34eb55ddf55f4a11.yaml │ ├── os_workers_heat_engine-af8ce1fdf3ce1ae1.yaml │ ├── os_workers_large-fact-71afa253044ce56e.yaml │ ├── policy_rcd_provider-1ef3d203b9af1110.yaml │ ├── puppet-5-unsupported-ac35e83ee3d2b12c.yaml │ ├── puppet-8-4b210a58a65b61da.yaml │ ├── puppetlabs-mysql-update-dependency-7f84516724bbd9d8.yaml │ ├── purge-policy-file-1ad9f366345142e7.yaml │ ├── release-note-pyvers-f5f857f91ab978ed.yaml │ ├── release-note-ubuntu-py3-6663c95bf4a4f31f.yaml │ ├── remove-centos-8-8b9bc74045173169.yaml │ ├── remove-os_package_type-fact-9de4c7060b735a62.yaml │ ├── remove-policy-json-8902dc11c5576e73.yaml │ ├── remove-puppet-4-7edd1536c4078f7a.yaml │ ├── remove-puppet-6-14aa2ddd0e088922.yaml │ ├── retry_client-b8a0e1f9ff679281.yaml │ ├── service-validation-environment-ad85f84da786768c.yaml │ ├── support-for-yaml-policy-da1ccf9fa692dca3.yaml │ ├── support_for_setting_a_value_immutable-27e52b14f61ff6c3.yaml │ ├── support_region_name_in_providers-cde6d75f0ddbec28.yaml │ ├── system-scope-credential-113608525e12a22d.yaml │ ├── ubuntu-jammy-da580c780aeafbef.yaml │ ├── ubuntu-noble-89f5f89bd0e4c83d.yaml │ ├── use-reno-1caaec4ba5aa4285.yaml │ ├── wsgi-aliases-2f74cbb84fcfd706.yaml │ ├── wsgi-import-script-64665fae9dccf797.yaml │ ├── wsgi-setenv-8e8519fdb96d98b0.yaml │ └── wsgi_process_options-5ff706a7beb9b893.yaml └── source │ ├── 2023.1.rst │ ├── 2023.2.rst │ ├── 2024.1.rst │ ├── 2024.2.rst │ ├── 2025.1.rst │ ├── _static │ └── .placeholder │ ├── conf.py │ ├── index.rst │ ├── mitaka.rst │ ├── newton.rst │ ├── ocata.rst │ ├── pike.rst │ ├── queens.rst │ ├── rocky.rst │ ├── stein.rst │ ├── train.rst │ ├── unreleased.rst │ ├── ussuri.rst │ ├── victoria.rst │ ├── wallaby.rst │ ├── xena.rst │ ├── yoga.rst │ └── zed.rst ├── setup.cfg ├── setup.py ├── spec ├── acceptance │ ├── mysql_spec.rb │ ├── openstacklib_config_provider_spec.rb │ ├── openstacklib_policy_base_spec.rb │ └── rabbitmq_spec.rb ├── classes │ ├── openstacklib_defaults_spec.rb │ ├── openstacklib_iscsid_spec.rb │ ├── openstacklib_openstackclient_spec.rb │ └── openstacklib_policyrcd_spec.rb ├── defines │ ├── openstacklib_clouds_spec.rb │ ├── openstacklib_db_mysql_host_access_spec.rb │ ├── openstacklib_db_mysql_spec.rb │ ├── openstacklib_db_postgresql_spec.rb │ ├── openstacklib_messaging_rabbitmq_spec.rb │ ├── openstacklib_policy_base_spec.rb │ ├── openstacklib_policy_default_spec.rb │ ├── openstacklib_policy_spec.rb │ ├── openstacklib_service_validation_spec.rb │ └── openstacklib_wsgi_apache_spec.rb ├── functions │ ├── inet6_prefix_spec.rb │ ├── is_service_default_spec.rb │ ├── normalize_ip_for_uri_spec.rb │ ├── os_database_connection_spec.rb │ ├── os_transport_url_spec.rb │ └── os_url_spec.rb ├── shared_examples.rb ├── spec_helper.rb ├── spec_helper_acceptance.rb ├── type_aliases │ ├── policies_spec.rb │ └── servicedefault_spec.rb └── unit │ ├── facter │ ├── os_workers_heat_engine_spec.rb │ ├── os_workers_keystone_spec.rb │ ├── os_workers_large_spec.rb │ ├── os_workers_small_spec.rb │ └── os_workers_spec.rb │ ├── provider │ ├── openstack │ │ ├── auth_spec.rb │ │ └── credentials_spec.rb │ ├── openstack_config │ │ └── ini_setting_spec.rb │ ├── openstack_spec.rb │ └── policy_rcd │ │ └── policy_rcd_spec.rb │ ├── puppet │ └── util │ │ └── openstackconfig_spec.rb │ └── type │ └── policy_rcd_spec.rb ├── templates ├── clouds.yaml.erb └── policy-rc.d.erb ├── tox.ini └── types ├── policies.pp └── servicedefault.pp /.gitignore: -------------------------------------------------------------------------------- 1 | # Add patterns in here to exclude files created by tools integrated with this 2 | # repository, such as test frameworks from the project's recommended workflow, 3 | # rendered documentation and package builds. 4 | # 5 | # Don't add patterns to exclude files created by preferred personal tools 6 | # (editors, IDEs, your operating system itself even). These should instead be 7 | # maintained outside the repository, for example in a ~/.gitignore file added 8 | # with: 9 | # 10 | # git config --global core.excludesfile '~/.gitignore' 11 | 12 | pkg/ 13 | Gemfile.lock 14 | vendor/ 15 | spec/fixtures/ 16 | .vagrant/ 17 | .bundle/ 18 | coverage/ 19 | .idea/ 20 | *.iml 21 | /openstack 22 | /log 23 | 24 | # Files created by releasenotes build 25 | releasenotes/build 26 | .tox 27 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.opendev.org 3 | port=29418 4 | project=openstack/puppet-openstacklib.git 5 | -------------------------------------------------------------------------------- /.pdkignore: -------------------------------------------------------------------------------- 1 | # common list used in puppetlabs repos 2 | .git/ 3 | .*.sw[op] 4 | .metadata 5 | .yardoc 6 | .yardwarns 7 | *.iml 8 | /.bundle/ 9 | /.idea/ 10 | /.vagrant/ 11 | /coverage/ 12 | /bin/ 13 | /doc/ 14 | /Gemfile.local 15 | /Gemfile.lock 16 | /junit/ 17 | /log/ 18 | /pkg/ 19 | /spec/fixtures/manifests/ 20 | /spec/fixtures/modules/* 21 | /tmp/ 22 | /vendor/ 23 | /convert_report.txt 24 | /update_report.txt 25 | .DS_Store 26 | .project 27 | .envrc 28 | /inventory.yaml 29 | /spec/fixtures/litmus_inventory.yaml 30 | /.fixtures.yml 31 | /Gemfile 32 | /.gitattributes 33 | /.gitignore 34 | /.pdkignore 35 | /.puppet-lint.rc 36 | /Rakefile 37 | /rakelib/ 38 | /.rspec 39 | /..yml 40 | /.yardopts 41 | /spec/ 42 | /.vscode/ 43 | /.sync.yml 44 | /.devcontainer/ 45 | # OpenStack-specific files 46 | /bindep.txt 47 | /.gitreview 48 | /releasenotes/ 49 | /setup.cfg 50 | /setup.py 51 | /tox.ini 52 | /.zuul.yaml 53 | -------------------------------------------------------------------------------- /.zuul.yaml: -------------------------------------------------------------------------------- 1 | - project: 2 | templates: 3 | - puppet-openstack-check-jobs 4 | - puppet-openstack-module-unit-jobs 5 | - puppet-openstack-integration-jobs-all 6 | - puppet-openstack-litmus-jobs 7 | - release-notes-jobs-python3 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 8.0.0 and beyond 2 | 3 | From 8.0.0 release and beyond, release notes are published on 4 | [docs.openstack.org](http://docs.openstack.org/releasenotes/puppet-openstacklib/). 5 | 6 | ##2015-11-24 - 7.0.0 7 | ###Summary 8 | 9 | This is a backwards-compatible major release for OpenStack Liberty. 10 | 11 | ####Features 12 | - fallback to default rcfile 13 | - prepare $::os_package_type 14 | - add a proxy inifile provider 15 | - allow the use of an ensure_absent_val param 16 | - create is_service_default function 17 | - create os_service_default fact 18 | - allow to path custom fragment to vhost 19 | - pass necessary options to Apache when using WSGI 20 | 21 | ####Bugfixes 22 | - fix fact for puppet facter 2.0.1+ 23 | 24 | ####Maintenance 25 | - initial msync run for all Puppet OpenStack modules 26 | - enable acceptance tests for openstack_config 27 | - remove class_parameter_defaults puppet-lint check 28 | 29 | ##2015-10-10 - 6.1.0 30 | ###Summary 31 | 32 | This is a maintenance release in the Kilo series. 33 | 34 | ####Maintenance 35 | - acceptance: checkout stable/kilo puppet modules 36 | 37 | ##2015-07-08 - 6.0.0 38 | ###Summary 39 | 40 | This is a backwards-incompatible major release for OpenStack Kilo. 41 | 42 | ####Backwards-incompatible changes 43 | - MySQL: change default MySQL collate to utf8_general_ci 44 | 45 | ####Features 46 | - Puppet 4.x support 47 | - Add db::postgresql to openstacklib 48 | - Implement openstacklib::wsgi::apache 49 | - Move openstackclient parent provider to openstacklib 50 | - Keystone V3 API support 51 | - Restructures authentication for resource providers 52 | 53 | ####Bugfixes 54 | - Properly handle policy values containing spaces 55 | 56 | ####Maintenance 57 | - Bump mysql version to 3.x 58 | - Acceptance tests with Beaker 59 | 60 | ##2015-06-17 - 5.1.0 61 | ###Summary 62 | 63 | This is a feature and bugfix release in the Juno series. 64 | 65 | ####Features 66 | - Adding augeas insertion check 67 | 68 | ####Bugfixes 69 | - MySQL: change default MySQL collate to utf8_general_ci 70 | 71 | ####Maintenance 72 | - Update .gitreview file for project rename 73 | - spec: pin rspec-puppet to 1.0.1 74 | 75 | ##2014-11-25 - 5.0.0 76 | ###Summary 77 | 78 | Initial release for Juno. 79 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || "https://rubygems.org" 2 | 3 | group :development, :test, :system_tests do 4 | spec_helper_dir = '/home/zuul/src/opendev.org/openstack/puppet-openstack_spec_helper' 5 | if File.directory?(spec_helper_dir) 6 | if ENV['ZUUL_PROJECT'] == 'openstack/puppet-openstack_spec_helper' 7 | gem 'puppet-openstack_spec_helper', 8 | :path => '../..', 9 | :require => 'false' 10 | else 11 | gem 'puppet-openstack_spec_helper', 12 | :path => spec_helper_dir, 13 | :require => 'false' 14 | end 15 | else 16 | spec_helper_version = ENV['ZUUL_BRANCH'] || "master" 17 | gem 'puppet-openstack_spec_helper', 18 | :git => 'https://opendev.org/openstack/puppet-openstack_spec_helper', 19 | :ref => spec_helper_version, 20 | :require => 'false' 21 | end 22 | end 23 | 24 | if facterversion = ENV['FACTER_GEM_VERSION'] 25 | gem 'facter', facterversion, :require => false 26 | else 27 | gem 'facter', :require => false 28 | end 29 | 30 | if puppetversion = ENV['PUPPET_GEM_VERSION'] 31 | gem 'puppet', puppetversion, :require => false 32 | else 33 | gem 'puppet', :require => false 34 | end 35 | 36 | # vim:ft=ruby 37 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'puppet-openstack_spec_helper/rake_tasks' 2 | -------------------------------------------------------------------------------- /bindep.txt: -------------------------------------------------------------------------------- 1 | # This is a cross-platform list tracking distribution packages needed by tests; 2 | # see https://docs.openstack.org/infra/bindep/ for additional information. 3 | 4 | libxml2-devel [test platform:rpm] 5 | libxml2-dev [test platform:dpkg] 6 | libxslt-devel [test platform:rpm] 7 | libxslt1-dev [test platform:dpkg] 8 | ruby-devel [test platform:rpm] 9 | ruby-dev [test platform:dpkg] 10 | zlib1g-dev [test platform:dpkg] 11 | zlib-devel [test platform:rpm] 12 | puppet [build] 13 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | # This is required for the docs build jobs 2 | sphinx>=3.5.1 # BSD 3 | openstackdocstheme>=2.2.7 # Apache-2.0 4 | 5 | # This is required for the releasenotes build jobs 6 | reno>=3.2.0 # Apache-2.0 7 | -------------------------------------------------------------------------------- /examples/virtual_packages.pp: -------------------------------------------------------------------------------- 1 | Exec { logoutput => 'on_failure' } 2 | 3 | include openstacklib::defaults 4 | 5 | if $facts['os']['family'] == 'RedHat' { 6 | # Virtual package name, present in @base. 7 | package { 'perl(Net::HTTP)': 8 | ensure => present, 9 | tag => 'openstack', 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /facts.d/os_immutable.txt: -------------------------------------------------------------------------------- 1 | os_immutable=<_IMMUTABLE_> 2 | -------------------------------------------------------------------------------- /facts.d/os_service_default.txt: -------------------------------------------------------------------------------- 1 | os_service_default= 2 | -------------------------------------------------------------------------------- /lib/facter/os_service_default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # This adds the os_service_default fact for people with facter < 2.0.1 3 | # For people with facter >= 2.0.1, the facts.d/os_service_default.txt should 4 | # provide this information 5 | # 6 | require 'puppet/util/package' 7 | 8 | if Puppet::Util::Package.versioncmp(Facter.value(:facterversion), '2.0.1') < 0 9 | Facter.add('os_service_default') do 10 | setcode do 11 | '' 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/facter/os_workers.rb: -------------------------------------------------------------------------------- 1 | # 2 | # We've found that using $facts['processors']['count] for workers/threads can lead to 3 | # unexpected memory or process counts for people deploying on baremetal or 4 | # if they have large number of cpus. This fact allows us to tweak the formula 5 | # used to determine number of workers in a single place but use it across all 6 | # modules. 7 | # 8 | # The value for os_workers is max between '(<# processors> / 4)' and '2' with 9 | # a cap of 8. 10 | # 11 | # This fact can be overloaded by an external fact from /etc/factor/facts.d if 12 | # a user would like to provide their own default value. 13 | # 14 | # 15 | def get_proc_count 16 | procs = Facter.value('processors') 17 | if procs.key?('count') then 18 | procs['count'].to_i 19 | else 20 | 1 21 | end 22 | end 23 | 24 | Facter.add(:os_workers_small) do 25 | has_weight 100 26 | setcode do 27 | [ [ (get_proc_count / 4), 2 ].max, 8 ].min 28 | end 29 | end 30 | 31 | # 32 | # The value above for os_workers performs 3x worse in many cases compared to 33 | # the previous default of $facts['processors']['count']. 34 | # 35 | # Based on performance data [1], the following calculation is within 1-2%. 36 | # 37 | # The value for os_workers is max between '(<# processors> / 2)' and '2' with 38 | # a cap of 12. 39 | # 40 | # [1] http://elk.browbeatproject.org:80/goto/a23307fd511e314b975dedca6f65425d 41 | # 42 | Facter.add(:os_workers) do 43 | has_weight 100 44 | setcode do 45 | [ [ (get_proc_count / 2), 2 ].max, 12 ].min 46 | end 47 | end 48 | 49 | # 50 | # For cases where services are not co-located together (ie monolithic). 51 | # 52 | Facter.add(:os_workers_large) do 53 | has_weight 100 54 | setcode do 55 | [ (get_proc_count / 2), 1 ].max 56 | end 57 | end 58 | 59 | # 60 | # Heat Engine service can be more stressed than other services, so 61 | # a minimum of 4 and maximum of 24 workers should be fine, still 62 | # calculating with the number of processors. 63 | # 64 | Facter.add(:os_workers_heat_engine) do 65 | has_weight 100 66 | setcode do 67 | [ [ (get_proc_count / 2), 4 ].max, 24 ].min 68 | end 69 | end 70 | 71 | # 72 | # Since we have merged keystone admin and keystone public into a single 73 | # keystone instance, we need doubled workers to have the same number 74 | # of workers in total to avoid performance degradation. 75 | # 76 | Facter.add(:os_workers_keystone) do 77 | has_weight 100 78 | setcode do 79 | [ [ get_proc_count, 4 ].max, 24 ].min 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/puppet/functions/inet6_prefix.rb: -------------------------------------------------------------------------------- 1 | # Add inet6 prefix if the argument is an IPv6 address. 2 | # 3 | # This is useful for services relying on python-memcached which require 4 | # the inet6:[ format. 5 | # 6 | # Returns the argument untouched otherwise. 7 | Puppet::Functions.create_function(:inet6_prefix) do 8 | def inet6_prefix(*args) 9 | require 'ipaddr' 10 | 11 | result = [] 12 | args = args[0] if args[0].kind_of?(Array) 13 | args = [args] unless args.kind_of?(Array) 14 | args.each do |ip| 15 | begin 16 | unless ip.match(/^inet6:.+/) 17 | ip_parts = ip.split(/\s|\[|\]/).reject { |c| c.empty? } 18 | if IPAddr.new(ip_parts[0]).ipv6? 19 | Puppet.debug("#{ip} is changed to inet6:[#{ip}]") 20 | ip = "inet6:[#{ip_parts.shift}]#{ip_parts.join}" 21 | end 22 | end 23 | rescue ArgumentError, NoMethodError => e 24 | # ignore it 25 | end 26 | result << ip 27 | end 28 | return result[0] if args.size == 1 29 | result 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/puppet/functions/is_service_default.rb: -------------------------------------------------------------------------------- 1 | # This function can be used to check if a variable is set to the default value 2 | # of '' 3 | # 4 | # For reference: 5 | # http://lists.openstack.org/pipermail/openstack-dev/2015-July/069823.html 6 | # https://github.com/openstack/puppet-openstacklib/commit/3b85306d042292713d0fd89fa508e0a0fbf99671 7 | Puppet::Functions.create_function(:is_service_default) do 8 | def is_service_default(*args) 9 | raise(Puppet::ParseError, "is_service_default(): Wrong number of arguments" + 10 | "given (#{args.size} for 1)") if args.size != 1 11 | 12 | value = args[0] 13 | 14 | unless value.is_a?(String) 15 | return false 16 | end 17 | 18 | return (value == '') 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/puppet/functions/normalize_ip_for_uri.rb: -------------------------------------------------------------------------------- 1 | # Add brackets if the argument is an IPv6 address. 2 | # Returns the argument untouched otherwise. 3 | # 4 | # CAUTION: this code "fails" when the user is passing 5 | # an IPv6 address with the port in it without the 6 | # brackets: 2001::1:8080, to specify address 2001::1 7 | # and port 8080. This code will change it to 8 | # [2001::1:8080] as it's a valid ip address. This 9 | # shouldn't be an issue in most cases. 10 | # 11 | # If an array is given, each member will be normalized to 12 | # a valid IPv6 address with brackets when needed. 13 | Puppet::Functions.create_function(:normalize_ip_for_uri) do 14 | def normalize_ip_for_uri(*args) 15 | require 'ipaddr' 16 | 17 | result = [] 18 | args = args[0] if args[0].kind_of?(Array) 19 | args = [args] unless args.kind_of?(Array) 20 | args.each do |ip| 21 | begin 22 | if IPAddr.new(ip).ipv6? 23 | unless ip.match(/\[.+\]/) 24 | Puppet.debug("IP #{ip} is changed to [#{ip}]") 25 | ip = "[#{ip}]" 26 | end 27 | end 28 | rescue ArgumentError 29 | # ignore it 30 | end 31 | result << ip 32 | end 33 | return result[0] if args.size == 1 34 | result 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/puppet/functions/os_database_connection.rb: -------------------------------------------------------------------------------- 1 | Puppet::Functions.create_function(:os_database_connection) do 2 | def os_database_connection(*args) 3 | require 'erb' 4 | 5 | if (args.size != 1) then 6 | raise(Puppet::ParseError, "os_database_connection(): Wrong number of arguments " + 7 | "given (#{args.size} for 1)") 8 | end 9 | 10 | v = args[0] 11 | klass = v.class 12 | 13 | unless klass == Hash 14 | raise(Puppet::ParseError, "os_database_connection(): Requires an hash, got #{klass}") 15 | end 16 | 17 | v.keys.each do |key| 18 | klass = (key == 'extra') ? Hash : String 19 | unless (v[key].class == klass) or (v[key] == :undef) 20 | raise(Puppet::ParseError, "os_database_connection(): #{key} should be a #{klass}") 21 | end 22 | end 23 | 24 | parts = {} 25 | 26 | unless v.include?('dialect') 27 | raise(Puppet::ParseError, 'os_database_connection(): dialect is required') 28 | end 29 | 30 | if v.include?('host') 31 | parts[:host] = v['host'] 32 | end 33 | 34 | unless v.include?('database') 35 | raise(Puppet::ParseError, 'os_database_connection(): database is required') 36 | end 37 | 38 | if v.include?('port') 39 | if v.include?('host') 40 | parts[:port] = v['port'].to_i 41 | else 42 | raise(Puppet::ParseError, 'os_database_connection(): host is required with port') 43 | end 44 | end 45 | 46 | if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '') 47 | parts[:userinfo] = ERB::Util.url_encode(v['username']) 48 | if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '') 49 | parts[:userinfo] += ":#{ERB::Util.url_encode(v['password'])}" 50 | end 51 | end 52 | 53 | # support previous charset option on the function. Setting charset will 54 | # override charset if passed in via the extra parameters 55 | extra = {} 56 | if v.include?('extra') 57 | extra.merge!(v['extra']) 58 | end 59 | if v.include?('charset') 60 | extra.merge!({ 'charset' => v['charset'] }) 61 | end 62 | 63 | parts[:query] = extra.map{ |k,v| "#{k}=#{v}" }.join('&') if ! extra.empty? 64 | 65 | parts[:scheme] = v['dialect'] 66 | 67 | if v.include?('host') 68 | parts[:path] = "/#{v['database']}" 69 | else 70 | parts[:path] = "///#{v['database']}" 71 | end 72 | 73 | URI::Generic.build(parts).to_s 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /lib/puppet/functions/os_transport_url.rb: -------------------------------------------------------------------------------- 1 | # This function builds a os_transport_url string from a hash of parameters. 2 | # 3 | # Valid hash parameteres: 4 | # * transport - (string) type of transport, 'rabbit' or 'amqp' 5 | # * host - (string) single host 6 | # * hosts - (array) array of hosts to use 7 | # * port - (string | integer) port to connect to 8 | # * username - (string) connection username 9 | # * password - (string) connection password 10 | # * virtual_host - (string) virtual host to connect to 11 | # * ssl - (string) is the connection ssl or not ('1' or '0'). overrides the ssl 12 | # key in the query parameter 13 | # * query - (hash) hash of key,value pairs used to create a query string for 14 | # the transport_url. 15 | # 16 | # Only 'transport' and either 'host' or 'hosts' are required keys for the 17 | # parameters hash. 18 | # 19 | # The url format that will be generated: 20 | # transport://user:pass@host:port[,userN:passN@hostN:portN]/virtual_host?query 21 | # 22 | # NOTE: ipv6 addresses will automatically be bracketed for the URI using the 23 | # normalize_ip_for_uri function. 24 | # 25 | # Single Host Example: 26 | # os_transport_url({ 27 | # 'transport' => 'rabbit', 28 | # 'host' => '1.1.1.1', 29 | # 'port' => '5672', 30 | # 'username' => 'username', 31 | # 'password' => 'password', 32 | # 'virtual_host' => 'virtual_host', 33 | # 'ssl' => '1', 34 | # 'query' => { 'key' => 'value' }, 35 | # }) 36 | # 37 | # Generates: 38 | # rabbit://username:password@1.1.1.1:5672/virtual_host?key=value&ssl=1 39 | # 40 | # Multiple Hosts Example: 41 | # os_transport_url({ 42 | # 'transport' => 'rabbit', 43 | # 'hosts' => [ '1.1.1.1', '2.2.2.2' ], 44 | # 'port' => '5672', 45 | # 'username' => 'username', 46 | # 'password' => 'password', 47 | # 'virtual_host' => 'virtual_host', 48 | # 'query' => { 'key' => 'value' }, 49 | # }) 50 | # 51 | # Generates: 52 | # rabbit://username:password@1.1.1.1:5672,username:password@2.2.2.2:5672/virtual_host?key=value 53 | Puppet::Functions.create_function(:os_transport_url) do 54 | 55 | def os_transport_url(*args) 56 | require 'erb' 57 | 58 | unless args.size == 1 59 | raise(ArgumentError, 'os_transport_url(): Wrong number of arguments') 60 | end 61 | 62 | v_raw = args[0] 63 | klass = v_raw.class 64 | 65 | unless klass == Hash 66 | raise(Puppet::ParseError, "os_transport_url(): Requires an hash, got #{klass}") 67 | end 68 | 69 | v = {} 70 | # type checking for the parameter hash 71 | v_raw.keys.each do |key| 72 | if key == 'port' 73 | v[key] = v_raw[key].to_s 74 | else 75 | v[key] = v_raw[key] 76 | end 77 | klass = (key == 'hosts') ? Array : String 78 | klass = (key == 'query') ? Hash : klass 79 | unless (v[key].class == klass) or (v[key] == :undef) 80 | raise(Puppet::ParseError, "os_transport_url(): #{key} should be a #{klass}") 81 | end 82 | end 83 | 84 | # defaults 85 | parts = { 86 | :transport => 'rabbit', 87 | :hostinfo => 'localhost', 88 | :path => '/', 89 | } 90 | 91 | unless v.include?('transport') 92 | raise(Puppet::ParseError, 'os_transport_url(): transport is required') 93 | end 94 | 95 | unless v.include?('host') or v.include?('hosts') 96 | raise(Puppet::ParseError, 'os_transport_url(): host or hosts is required') 97 | end 98 | 99 | if v.include?('host') and v.include?('hosts') 100 | raise(Puppet::ParseError, 'os_transport_url(): cannot use both host and hosts.') 101 | end 102 | 103 | parts[:transport] = v['transport'] 104 | 105 | if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '') 106 | parts[:userinfo] = ERB::Util.url_encode(v['username']) 107 | if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '') 108 | parts[:userinfo] += ":#{ERB::Util.url_encode(v['password'])}" 109 | end 110 | end 111 | 112 | if v.include?('host') 113 | host = call_function('normalize_ip_for_uri', v['host']) 114 | host += ":#{v['port'].to_s}" if v.include?('port') 115 | if parts.include?(:userinfo) 116 | parts[:hostinfo] = "#{parts[:userinfo]}@#{host}" 117 | else 118 | parts[:hostinfo] = "#{host}" 119 | end 120 | end 121 | 122 | if v.include?('hosts') 123 | hosts = call_function('normalize_ip_for_uri', v['hosts']) 124 | # normalize_ip_for_uri may return a string, so check that we still have an 125 | # array 126 | hosts = [hosts] if hosts.kind_of?(String) 127 | hosts = hosts.map{ |h| "#{h}:#{v['port'].to_s}" } if v.include?('port') 128 | if parts.include?(:userinfo) 129 | parts[:hostinfo] = hosts.map { |h| "#{parts[:userinfo]}@#{h}" }.join(',') 130 | else 131 | parts[:hostinfo] = hosts.join(',') 132 | end 133 | end 134 | 135 | parts[:path] = "/#{v['virtual_host']}" if v.include?('virtual_host') 136 | 137 | query = {} 138 | if v.include?('query') 139 | query.merge!(v['query']) 140 | end 141 | 142 | # support previous ssl option on the function. Setting ssl will 143 | # override ssl if passed in via the query parameters 144 | if v.include?('ssl') 145 | # ssl can be passed in as a query paramter but should be 0/1. See 146 | # http://docs.celeryproject.org/projects/kombu/en/latest/userguide/connections.html#urls 147 | # so we rely on _str2bool and _bool2num to ensure it's in the 148 | # format 149 | # TODO(tobias-urdin): Rework this to using proper data types and not the 150 | # legacy puppet functions. 151 | ssl_str = call_function('str2bool', v['ssl']) 152 | ssl_val = call_function('bool2num', v['ssl']) 153 | 154 | query.merge!({ 'ssl' => ssl_val }) 155 | end 156 | 157 | parts[:query] = query.map{ |k,val| "#{k}=#{val}" }.join('&') if ! query.empty? 158 | 159 | url_parts = [] 160 | url_parts << parts[:transport] 161 | url_parts << '://' 162 | url_parts << parts[:hostinfo] 163 | url_parts << parts[:path] 164 | url_parts << '?' << parts[:query] if parts.include?(:query) 165 | url_parts.join() 166 | end 167 | end 168 | -------------------------------------------------------------------------------- /lib/puppet/functions/os_url.rb: -------------------------------------------------------------------------------- 1 | Puppet::Functions.create_function(:os_url) do 2 | def os_url(*args) 3 | require 'erb' 4 | 5 | if (args.size != 1) then 6 | raise(Puppet::ParseError, "os_url(): Wrong number of arguments " + 7 | "given (#{args.size} for 1)") 8 | end 9 | 10 | v = args[0] 11 | klass = v.class 12 | 13 | unless klass == Hash 14 | raise(Puppet::ParseError, "os_url(): Requires an hash, got #{klass}") 15 | end 16 | 17 | v.keys.each do |key| 18 | klass = (key == 'query') ? Hash : String 19 | unless (v[key].class == klass) or (v[key] == :undef) 20 | raise(Puppet::ParseError, "os_url(): #{key} should be a #{klass}") 21 | end 22 | end 23 | 24 | parts = {} 25 | 26 | if v.include?('scheme') 27 | parts[:scheme] = v['scheme'] 28 | else 29 | parts[:scheme] = 'http' 30 | end 31 | 32 | if v.include?('host') 33 | parts[:host] = v['host'] 34 | end 35 | 36 | if v.include?('port') 37 | if v.include?('host') 38 | parts[:port] = v['port'].to_i 39 | else 40 | raise(Puppet::ParseError, 'os_url(): host is required with port') 41 | end 42 | end 43 | 44 | if v.include?('path') 45 | parts[:path] = v['path'] 46 | end 47 | 48 | userinfo = '' 49 | if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '') 50 | userinfo = ERB::Util.url_encode(v['username']) 51 | end 52 | if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '') 53 | userinfo += ":#{ERB::Util.url_encode(v['password'])}" 54 | end 55 | 56 | if userinfo != '' 57 | parts[:userinfo] = userinfo 58 | end 59 | 60 | if v.include?('query') and ! v['query'].empty? 61 | parts[:query] = v['query'].map{ |k,v| "#{k}=#{v}" }.join('&') 62 | end 63 | 64 | URI::Generic.build(parts).to_s 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/puppet/provider/openstack.rb: -------------------------------------------------------------------------------- 1 | require 'csv' 2 | require 'puppet' 3 | require 'timeout' 4 | 5 | class Puppet::Error::OpenstackAuthInputError < Puppet::Error 6 | end 7 | 8 | class Puppet::Error::OpenstackUnauthorizedError < Puppet::Error 9 | end 10 | 11 | class Puppet::Provider::Openstack < Puppet::Provider 12 | 13 | initvars # so commands will work 14 | commands :openstack_command => 'openstack' 15 | 16 | @@no_retry_actions = %w(create remove delete) 17 | @@command_timeout = 90 18 | @@request_timeout = 300 19 | @@retry_sleep = 10 20 | class << self 21 | [:no_retry_actions, :request_timeout, :retry_sleep].each do |m| 22 | define_method m do 23 | self.class_variable_get("@@#{m}") 24 | end 25 | define_method :"#{m}=" do |value| 26 | self.class_variable_set("@@#{m}", value) 27 | end 28 | end 29 | end 30 | 31 | # timeout the openstack command 32 | # after this number of seconds 33 | # retry the command until the request_timeout, 34 | # unless it's a no_retry_actions call 35 | def self.command_timeout(action=nil) 36 | # give no_retry actions the full time limit to finish 37 | return self.request_timeout() if no_retry_actions.include? action 38 | self.class_variable_get("@@command_timeout") 39 | end 40 | 41 | # redact sensitive information in exception and raise 42 | def self.redact_and_raise(e) 43 | new_message = e.message.gsub(/\-\-password\ [\w]+/, "--password [redacted secret]") 44 | raise e.class, new_message 45 | end 46 | 47 | # with command_timeout 48 | def self.openstack(*args) 49 | begin 50 | action = args[1] 51 | Timeout.timeout(command_timeout(action)) do 52 | execute([command(:openstack_command)] + args, override_locale: false, failonfail: true, combine: true) 53 | end 54 | rescue Timeout::Error 55 | e = Puppet::ExecutionFailure.new "Command: 'openstack #{args.inspect}' has been running for more than #{command_timeout(action)} seconds" 56 | redact_and_raise(e) 57 | rescue Puppet::ExecutionFailure => e 58 | redact_and_raise(e) 59 | end 60 | end 61 | 62 | # get the current timestamp 63 | def self.current_time 64 | Time.now.to_i 65 | end 66 | 67 | def self.request_without_retry(&block) 68 | previous_timeout = self.request_timeout 69 | rc = nil 70 | if block_given? 71 | self.request_timeout = 0 72 | rc = yield 73 | end 74 | ensure 75 | self.request_timeout = previous_timeout 76 | rc 77 | end 78 | 79 | # Returns an array of hashes, where the keys are the downcased CSV headers 80 | # with underscores instead of spaces 81 | # 82 | # @param options [Hash] Other options 83 | # @options :no_retry_exception_msgs [Array,Regexp] exception without retries 84 | def self.request(service, action, properties, credentials=nil, options={}) 85 | env = credentials ? credentials.to_env : {} 86 | no_retry = options[:no_retry_exception_msgs] 87 | 88 | Puppet::Util.withenv(env) do 89 | rv = nil 90 | start_time = current_time 91 | end_time = start_time + request_timeout 92 | retry_count = 0 93 | loop do 94 | begin 95 | if action == 'list' 96 | # shell output is: 97 | # ID,Name,Description,Enabled 98 | response = openstack(service, action, '--quiet', '--format', 'csv', properties) 99 | response = parse_csv(response) 100 | keys = response.delete_at(0) 101 | rv = response.collect do |line| 102 | hash = {} 103 | keys.each_index do |index| 104 | key = keys[index].downcase.gsub(/ /, '_').to_sym 105 | hash[key] = line[index] 106 | end 107 | hash 108 | end 109 | elsif action == 'show' or action == 'create' 110 | rv = {} 111 | # shell output is: 112 | # name="value1" 113 | # id="value2" 114 | # description="value3" 115 | openstack(service, action, '--format', 'shell', properties).split("\n").each do |line| 116 | # key is everything before the first "=" 117 | key, val = line.split('=', 2) 118 | next unless val # Ignore warnings 119 | # value is everything after the first "=", with leading and trailing double quotes stripped 120 | val = val.gsub(/\A"|"\Z/, '') 121 | rv[key.downcase.to_sym] = val 122 | end 123 | else 124 | rv = openstack(service, action, properties) 125 | end 126 | break 127 | rescue Puppet::ExecutionFailure => exception 128 | raise Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate' if exception.message =~ /HTTP 40[13]/ 129 | raise Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate' if exception.message.match(/Missing value \S* required for auth plugin/) 130 | remaining_time = end_time - current_time 131 | if remaining_time < 0 132 | error_message = exception.message 133 | error_message += " (tried #{retry_count}, for a total of #{end_time - start_time} seconds)" 134 | raise(Puppet::ExecutionFailure, error_message) 135 | end 136 | 137 | raise exception if no_retry_actions.include? action 138 | if no_retry 139 | no_retry = [no_retry] unless no_retry.is_a?(Array) 140 | no_retry.each do |nr| 141 | raise exception if exception.message.match(nr) 142 | end 143 | end 144 | debug "Non-fatal error: '#{exception.message}'. Retrying for #{remaining_time} more seconds" 145 | sleep retry_sleep 146 | retry_count += 1 147 | retry 148 | end 149 | end 150 | return rv 151 | end 152 | end 153 | 154 | private 155 | 156 | def self.parse_csv(text) 157 | # Ignore warnings - assume legitimate output starts with a double quoted 158 | # string. Errors will be caught and raised prior to this 159 | text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n") 160 | return CSV.parse(text + "\n") 161 | end 162 | 163 | def self.parse_python_dict(text) 164 | return JSON.parse(text.gsub(/'/, '"').gsub(/: False([,}])/,': false\1').gsub(/: True([,}])/,': true\1')) 165 | end 166 | 167 | def self.parse_python_list(text) 168 | return JSON.parse(text.gsub(/'/, '"')) 169 | end 170 | end 171 | -------------------------------------------------------------------------------- /lib/puppet/provider/openstack/auth.rb: -------------------------------------------------------------------------------- 1 | #require 'puppet/provider/openstack/credentials' 2 | require File.join(File.dirname(__FILE__), '..','..','..', 'puppet/provider/openstack/credentials') 3 | 4 | module Puppet::Provider::Openstack::Auth 5 | 6 | RCFILENAME = "#{ENV['HOME']}/openrc" 7 | 8 | CLOUDSFILENAMES = [ 9 | # This allows overrides by users 10 | "/etc/openstack/puppet/clouds.yaml", 11 | # This is created by puppet-keystone 12 | "/etc/openstack/puppet/admin-clouds.yaml", 13 | ] 14 | 15 | def get_os_vars_from_env 16 | env = {} 17 | ENV.each { |k,v| env.merge!(k => v) if k =~ /^OS_/ } 18 | return env 19 | end 20 | 21 | def get_os_vars_from_cloudsfile(scope) 22 | cloudsfile = clouds_filenames.detect { |f| File.exist? f} 23 | unless cloudsfile.nil? 24 | { 25 | 'OS_CLOUD' => scope, 26 | 'OS_CLIENT_CONFIG_FILE' => cloudsfile 27 | } 28 | else 29 | {} 30 | end 31 | end 32 | 33 | def get_os_vars_from_rcfile(filename) 34 | env = {} 35 | rcfile = [filename, '/root/openrc'].detect { |f| File.exist? f } 36 | unless rcfile.nil? 37 | File.open(rcfile).readlines.delete_if{|l| l=~ /^#|^$/ }.each do |line| 38 | # we only care about the OS_ vars from the file LP#1699950 39 | if line =~ /OS_/ 40 | key, value = line.split('=') 41 | key = key.split(' ').last 42 | value = value.chomp.gsub(/'/, '') 43 | env.merge!(key => value) if key =~ /OS_/ 44 | end 45 | end 46 | end 47 | return env 48 | end 49 | 50 | def rc_filename 51 | RCFILENAME 52 | end 53 | 54 | def clouds_filenames 55 | CLOUDSFILENAMES 56 | end 57 | 58 | def request(service, action, properties=nil, options={}, scope='project') 59 | properties ||= [] 60 | 61 | # First, check environments 62 | set_credentials(@credentials, get_os_vars_from_env) 63 | 64 | unless @credentials.set? and (!@credentials.scope_set? or @credentials.scope == scope) 65 | # Then look for clouds.yaml 66 | @credentials.unset 67 | clouds_env = get_os_vars_from_cloudsfile(scope) 68 | if ! clouds_env.empty? 69 | set_credentials(@credentials, clouds_env) 70 | else 71 | # If it fails then check rc files, to keep backword compatibility. 72 | warning('Usage of rc file is deprecated and will be removed in a future release.') 73 | @credentials.unset 74 | set_credentials(@credentials, get_os_vars_from_rcfile(rc_filename)) 75 | end 76 | end 77 | 78 | unless @credentials.set? and (!@credentials.scope_set? or @credentials.scope == scope) 79 | raise(Puppet::Error::OpenstackAuthInputError, 'Insufficient credentials to authenticate') 80 | end 81 | super(service, action, properties, @credentials, options) 82 | end 83 | 84 | def set_credentials(creds, env) 85 | env.each do |key, val| 86 | var = key.sub(/^OS_/,'').downcase 87 | creds.set(var, val) 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/puppet/provider/openstack/credentials.rb: -------------------------------------------------------------------------------- 1 | require 'puppet' 2 | require 'puppet/provider/openstack' 3 | 4 | class Puppet::Provider::Openstack::Credentials 5 | 6 | KEYS = [ 7 | :auth_url, :password, :project_name, :username, 8 | :token, :endpoint, :url, 9 | :identity_api_version, 10 | :region_name, 11 | :interface 12 | ] 13 | 14 | KEYS.each { |var| attr_accessor var } 15 | 16 | def self.defined?(name) 17 | KEYS.include?(name.to_sym) 18 | end 19 | 20 | def set(key, val) 21 | if self.class.defined?(key.to_sym) 22 | self.instance_variable_set("@#{key}".to_sym, val) 23 | end 24 | end 25 | 26 | def set? 27 | return true if user_password_set? || service_token_set? 28 | end 29 | 30 | def service_token_set? 31 | return true if (@token && @endpoint) || (@token && @url) 32 | end 33 | 34 | def to_env 35 | env = {} 36 | self.instance_variables.each do |var| 37 | name = var.to_s.sub(/^@/,'OS_').upcase 38 | value = self.instance_variable_get(var) 39 | unless value.nil? 40 | env.merge!(name => value) 41 | end 42 | end 43 | env 44 | end 45 | 46 | def scope_set? 47 | @project_name 48 | end 49 | 50 | def scope 51 | if @project_name 52 | return 'project' 53 | else 54 | # When only service token is used, there is not way to determine 55 | # the scope unless we inspect the token using keystone API call. 56 | return nil 57 | end 58 | end 59 | 60 | def user_password_set? 61 | return true if @username && @password && @project_name && @auth_url 62 | end 63 | 64 | def unset 65 | self.instance_variables.each do |var| 66 | if var.to_s != '@identity_api_version' && 67 | self.instance_variable_defined?(var.to_s) 68 | set(var.to_s.sub(/^@/,''), nil) 69 | end 70 | end 71 | end 72 | 73 | def version 74 | self.class.to_s.sub(/.*V/,'').sub('_','.') 75 | end 76 | end 77 | 78 | class Puppet::Provider::Openstack::CredentialsV3 < Puppet::Provider::Openstack::Credentials 79 | 80 | KEYS = [ 81 | :cacert, 82 | :cert, 83 | :default_domain, 84 | :domain_id, 85 | :domain_name, 86 | :key, 87 | :project_domain_id, 88 | :project_domain_name, 89 | :project_id, 90 | :system_scope, 91 | :trust_id, 92 | :user_domain_id, 93 | :user_domain_name, 94 | :user_id, 95 | :cloud, 96 | :client_config_file, 97 | ] 98 | 99 | KEYS.each { |var| attr_accessor var } 100 | 101 | def self.defined?(name) 102 | KEYS.include?(name.to_sym) || super 103 | end 104 | 105 | def user_set? 106 | @username || @user_id 107 | end 108 | 109 | def scope_set? 110 | @system_scope || @domain_name || @domain_id || @project_name || @project_id 111 | end 112 | 113 | def scope 114 | if @project_name || @project_id 115 | return 'project' 116 | elsif @domain_name || @domain_id 117 | return 'domain' 118 | elsif @system_scope 119 | return 'system' 120 | else 121 | # When clouds.yaml is used, parameters are not directly passed to puppet 122 | # so the scope can't be detected. 123 | return nil 124 | end 125 | end 126 | 127 | def user_password_set? 128 | return true if (user_set? && @password && scope_set? && @auth_url) || @cloud 129 | end 130 | 131 | def initialize 132 | set(:identity_api_version, version) 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /lib/puppet/provider/openstack_config/ini_setting.rb: -------------------------------------------------------------------------------- 1 | require 'facter' 2 | 3 | Puppet::Type.type(:openstack_config).provide( 4 | :ini_setting, 5 | :parent => Puppet::Type.type(:ini_setting).provider(:ruby) 6 | ) do 7 | 8 | def exists? 9 | immutable_string = Facter.value(:os_immutable) || '<_IMMUTABLE_>' 10 | if resource[:value] == ensure_absent_val 11 | resource[:ensure] = :absent 12 | elsif resource[:value] == immutable_string or resource[:value] == [immutable_string] 13 | resource[:value] = value 14 | # when the value is undefined, we keep it that way. 15 | if value.nil? or (value.kind_of?(Array) and value[0].nil?) 16 | resource[:ensure] = :absent 17 | end 18 | end 19 | super 20 | end 21 | 22 | def create 23 | new_value = transform(:to, resource[:value]) 24 | if resource[:value] != new_value 25 | resource[:value] = new_value 26 | end 27 | super 28 | end 29 | 30 | def section 31 | resource[:name].split('/', 2).first 32 | end 33 | 34 | def setting 35 | resource[:name].split('/', 2).last 36 | end 37 | 38 | def value=(value) 39 | new_value = transform(:to, value) 40 | 41 | ini_file.set_value(section, setting, new_value) 42 | ini_file.save 43 | end 44 | 45 | def value 46 | value = ini_file.get_value(section, setting) 47 | new_value = transform(:from, value) 48 | @property_hash[:value] = new_value 49 | new_value 50 | end 51 | 52 | def ensure_absent_val 53 | resource[:ensure_absent_val] 54 | end 55 | 56 | def transform_to 57 | return nil unless resource.to_hash.has_key? :transform_to 58 | resource[:transform_to] 59 | end 60 | 61 | def transform_to=(value) 62 | @property_hash[:transform_to] = value 63 | end 64 | 65 | def separator 66 | if resource.class.validattr?(:key_val_separator) 67 | resource[:key_val_separator] || '=' 68 | else 69 | '=' 70 | end 71 | end 72 | 73 | def file_path 74 | self.class.file_path 75 | end 76 | 77 | def transform(direction, value) 78 | new_value = value 79 | if !transform_to.nil? && !transform_to.empty? 80 | transformation_function = "#{direction}_#{transform_to}".to_sym 81 | if self.respond_to?(transformation_function) 82 | new_value = send(transformation_function, value) 83 | else 84 | error("Cannot find transformation #{transformation_function} for #{value}") 85 | end 86 | end 87 | new_value 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /lib/puppet/provider/openstack_config/ruby.rb: -------------------------------------------------------------------------------- 1 | require 'facter' 2 | 3 | require File.expand_path('../../../util/openstackconfig', __FILE__) 4 | 5 | 6 | Puppet::Type.type(:openstack_config).provide(:ruby) do 7 | 8 | def self.instances 9 | if self.respond_to?(:file_path) 10 | config = Puppet::Util::OpenStackConfig.new(file_path) 11 | resources = [] 12 | config.section_names.each do |section_name| 13 | config.get_settings(section_name).each do |setting, value| 14 | resources.push( 15 | new( 16 | :name => namevar(section_name, setting), 17 | :value => value, 18 | :ensure => :present 19 | ) 20 | ) 21 | end 22 | end 23 | resources 24 | else 25 | raise(Puppet::Error, 26 | 'OpenStackConfig only support collecting instances when a file path ' + 27 | 'is hard coded' 28 | ) 29 | end 30 | end 31 | 32 | def self.namevar(section_name, setting) 33 | "#{section_name}/#{setting}" 34 | end 35 | 36 | def exists? 37 | immutable_string = Facter.value(:os_immutable) || '<_IMMUTABLE_>' 38 | if resource[:value] == ensure_absent_val 39 | resource[:ensure] = :absent 40 | elsif resource[:value] == immutable_string or resource[:value] == [immutable_string] 41 | resource[:value] = value 42 | # when the value is undefined, we keep it that way. 43 | if value.nil? or (value.kind_of?(Array) and value[0].nil?) 44 | resource[:ensure] = :absent 45 | end 46 | end 47 | !config.get_value(section, setting).nil? 48 | end 49 | 50 | def create 51 | config.set_value(section, setting, resource[:value]) 52 | config.save 53 | @config = nil 54 | end 55 | 56 | def destroy 57 | config.remove_setting(section, setting) 58 | config.save 59 | @config = nil 60 | end 61 | 62 | def value=(value) 63 | config.set_value(section, setting, resource[:value]) 64 | config.save 65 | end 66 | 67 | def value 68 | val = config.get_value(section, setting) 69 | if !val.kind_of?(Array) 70 | [val] 71 | else 72 | val 73 | end 74 | end 75 | 76 | def section 77 | resource[:name].split('/', 2).first 78 | end 79 | 80 | def setting 81 | resource[:name].split('/', 2).last 82 | end 83 | 84 | def ensure_absent_val 85 | # :array_matching => :all values comes in form of array even when they 86 | # are passed as single string 87 | if resource[:value].kind_of?(Array) and not resource[:ensure_absent_val].kind_of?(Array) 88 | [resource[:ensure_absent_val]] 89 | else 90 | resource[:ensure_absent_val] 91 | end 92 | end 93 | 94 | def file_path 95 | self.class.file_path 96 | end 97 | 98 | private 99 | def config 100 | @config ||= Puppet::Util::OpenStackConfig.new(file_path) 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /lib/puppet/provider/policy_rcd/policy_rcd.rb: -------------------------------------------------------------------------------- 1 | Puppet::Type.type(:policy_rcd).provide(:policy_rcd) do 2 | 3 | desc 'Provider for managing policy-rc.d for Ubuntu' 4 | 5 | mk_resource_methods 6 | 7 | def check_os 8 | Facter.value(:os)['family'] == 'Debian' 9 | end 10 | 11 | def check_policy_rcd 12 | return File.exist? policy_rcd 13 | end 14 | 15 | def file_lines 16 | @file_lines ||= File.open(policy_rcd).readlines 17 | end 18 | 19 | def policy_rcd 20 | '/usr/sbin/policy-rc.d' 21 | end 22 | 23 | def service 24 | @resource[:service] 25 | end 26 | 27 | def set_code 28 | @resource[:set_code] 29 | end 30 | 31 | def self.write_to_file(file, content, truncate=false) 32 | File.truncate(file, 0) if truncate 33 | policy = File.open(file, 'a+') 34 | policy.puts(content) 35 | policy.close 36 | File.chmod(0744, file) 37 | end 38 | 39 | def exists? 40 | # we won't do anything if os family is not debian 41 | return true unless check_os 42 | if check_policy_rcd 43 | file_lines.each do |line| 44 | unless line =~ /"#{@resource[:service]}"/ 45 | next 46 | end 47 | return true 48 | end 49 | end 50 | false 51 | end 52 | 53 | def create 54 | unless check_policy_rcd 55 | header = "#!/bin/bash\n# THIS FILE MANAGED BY PUPPET\n" 56 | else 57 | header = "" 58 | end 59 | content = "#{header}[[ \"$1\" == \"#{@resource[:service]}\" ]] && exit #{@resource[:set_code]}\n" 60 | self.class.write_to_file(policy_rcd, content) 61 | end 62 | 63 | def destroy 64 | if check_policy_rcd 65 | file_lines.delete_if { |l| l =~ /"#{@resource[:service]}"/ } 66 | self.class.write_to_file(policy_rcd, file_lines, true) 67 | end 68 | end 69 | 70 | def flush 71 | if @resource[:ensure] == :present and ! file_lines.nil? 72 | new_line = nil 73 | outdated_line = nil 74 | file_lines.each do |line| 75 | unless line =~ /"#{@resource[:service]}"/ 76 | next 77 | end 78 | code = line.match(/exit\s(\d+)/)[1] 79 | if code != @resource[:set_code] 80 | new_line = "[[ \"$1\" == \"#{@resource[:service]}\" ]] && exit #{@resource[:set_code]}\n" 81 | outdated_line = line 82 | end 83 | end 84 | unless new_line.nil? 85 | file_lines.delete(outdated_line) 86 | file_lines.push(new_line) 87 | self.class.write_to_file(policy_rcd, file_lines, true) 88 | end 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /lib/puppet/type/openstack_config.rb: -------------------------------------------------------------------------------- 1 | Puppet::Type.newtype(:openstack_config) do 2 | 3 | end 4 | -------------------------------------------------------------------------------- /lib/puppet/type/policy_rcd.rb: -------------------------------------------------------------------------------- 1 | Puppet::Type.newtype(:policy_rcd) do 2 | ensurable 3 | 4 | newparam(:name, :namevar => true) do 5 | newvalues(/\S+/) 6 | end 7 | 8 | newproperty(:service) do 9 | defaultto { @resource[:name] } 10 | newvalues(/\S+/) 11 | end 12 | 13 | newproperty(:set_code) do 14 | defaultto('101') 15 | validate do |value| 16 | # validate codes according to https://people.debian.org/~hmh/invokerc.d-policyrc.d-specification.txt 17 | allowed_codes = [ '0', '1', '100', '101', '102', '103', '104', '105', '106' ] 18 | raise ArgumentError, 'Unknown exit status code is set' unless allowed_codes.include?(value) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/puppet/util/openstackconfig.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author: Martin Magr 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | # Forked from https://github.com/puppetlabs/puppetlabs-inifile . 17 | 18 | require File.expand_path('../openstackconfig/section', __FILE__) 19 | 20 | 21 | module Puppet 22 | module Util 23 | class OpenStackConfig 24 | 25 | @@SECTION_REGEX = /^\s*\[(.*)\]\s*$/ 26 | 27 | def initialize(path) 28 | @path = path 29 | @order = [] 30 | @sections = {} 31 | parse_file 32 | end 33 | 34 | attr_reader :path 35 | 36 | def section_names 37 | @sections.keys 38 | end 39 | 40 | def get_settings(section_name) 41 | @sections[section_name].settings 42 | end 43 | 44 | def get_value(section_name, setting_name) 45 | if @sections.has_key?(section_name) 46 | @sections[section_name].settings[setting_name] 47 | end 48 | end 49 | 50 | def set_value(section_name, setting_name, value) 51 | unless @sections.has_key?(section_name) 52 | add_section(section_name) 53 | end 54 | if @sections[section_name].settings.has_key?(setting_name) 55 | @sections[section_name].update_setting(setting_name, value) 56 | else 57 | @sections[section_name].add_setting(setting_name, value) 58 | end 59 | end 60 | 61 | def remove_setting(section_name, setting_name, value=nil) 62 | @sections[section_name].remove_setting(setting_name, value) 63 | end 64 | 65 | def save 66 | File.open(@path, 'w') do |fh| 67 | @order.each do |section_name| 68 | if section_name.length > 0 69 | fh.puts("[#{section_name}]") 70 | end 71 | unless @sections[section_name].lines.empty? 72 | @sections[section_name].lines.each do |line| 73 | fh.puts(line) 74 | end 75 | end 76 | end 77 | end 78 | end 79 | 80 | private 81 | # This is mostly here because it makes testing easier 82 | # --we don't have to try to stub any methods on File. 83 | def self.readlines(path) 84 | # If this type is ever used with very large files, we should 85 | # write this in a different way, using a temp 86 | # file; for now assuming that this type is only used on 87 | # small-ish config files that can fit into memory without 88 | # too much trouble. 89 | File.file?(path) ? File.readlines(path) : [] 90 | end 91 | 92 | def parse_file 93 | # We always create a "global" section at the beginning of the file, 94 | # for anything that appears before the first named section. 95 | lines = [] 96 | current_section = '' 97 | OpenStackConfig.readlines(@path).each do |line| 98 | if match = @@SECTION_REGEX.match(line) 99 | add_section(current_section, lines) 100 | # start new section parsing 101 | lines = [] 102 | current_section = match[1] 103 | else 104 | lines.push(line) 105 | end 106 | end 107 | add_section(current_section, lines) 108 | end 109 | 110 | def add_section(section_name, lines=nil) 111 | @order.push(section_name) 112 | @sections[section_name] = Section.new(section_name, lines) 113 | end 114 | 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/puppet/util/openstackconfig/section.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author: Martin Magr 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | # 16 | # Forked from https://github.com/puppetlabs/puppetlabs-inifile . 17 | 18 | 19 | module Puppet 20 | module Util 21 | class OpenStackConfig 22 | class Section 23 | 24 | @@SETTING_REGEX = /^(\s*)([^#;\s]|[^#;\s].*?[^\s=])(\s*=[ \t]*)(.*)\s*$/ 25 | @@COMMENTED_SETTING_REGEX = /^(\s*)[#;]+(\s*)(.*?[^\s=])(\s*=[ \t]*)(.*)\s*$/ 26 | 27 | def initialize(name, lines=nil) 28 | @name = name 29 | @lines = lines.nil? ? [] : lines 30 | # parse lines 31 | @indentation = nil 32 | @settings = {} 33 | @lines.each do |line| 34 | if match = @@SETTING_REGEX.match(line) 35 | indent = match[1].length 36 | @indentation = [indent, @indentation || indent].min 37 | if @settings.include?(match[2]) 38 | if not @settings[match[2]].kind_of?(Array) 39 | @settings[match[2]] = [@settings[match[2]]] 40 | end 41 | @settings[match[2]].push(match[4]) 42 | else 43 | @settings[match[2]] = match[4] 44 | end 45 | end 46 | end 47 | end 48 | 49 | attr_reader :name, :indentation 50 | 51 | def settings 52 | Marshal.load(Marshal.dump(@settings)) 53 | end 54 | 55 | def lines 56 | @lines.clone 57 | end 58 | 59 | def is_global? 60 | @name == '' 61 | end 62 | 63 | def is_new_section? 64 | @lines.empty? 65 | end 66 | 67 | def setting_names 68 | @settings.keys 69 | end 70 | 71 | def add_setting(setting_name, value) 72 | @settings[setting_name] = value 73 | add_lines(setting_name, value) 74 | end 75 | 76 | def update_setting(setting_name, value) 77 | old_value = @settings[setting_name] 78 | @settings[setting_name] = value 79 | if value.kind_of?(Array) or old_value.kind_of?(Array) 80 | # ---- update lines for multi setting ---- 81 | old_value = old_value.kind_of?(Array) ? old_value : [old_value] 82 | new_value = value.kind_of?(Array) ? value : [value] 83 | if useless = old_value - new_value 84 | remove_lines(setting_name, useless) 85 | end 86 | if missing = new_value - old_value 87 | add_lines(setting_name, missing) 88 | end 89 | else 90 | # ---- update lines for single setting ---- 91 | @lines.each_with_index do |line, index| 92 | if match = @@SETTING_REGEX.match(line) 93 | if (match[2] == setting_name) 94 | @lines[index] = "#{match[1]}#{match[2]}#{match[3]}#{value}\n" 95 | end 96 | end 97 | end 98 | end 99 | end 100 | 101 | def remove_setting(setting_name, value=nil) 102 | if value.nil? or @settings[setting_name] == value 103 | @settings.delete(setting_name) 104 | else 105 | value.each do |val| 106 | @settings[setting_name].delete(val) 107 | end 108 | end 109 | remove_lines(setting_name, value) 110 | end 111 | 112 | private 113 | def find_commented_setting(setting_name) 114 | @lines.each_with_index do |line, index| 115 | if match = @@COMMENTED_SETTING_REGEX.match(line) 116 | if match[3] == setting_name 117 | return index 118 | end 119 | end 120 | end 121 | nil 122 | end 123 | 124 | def find_last_setting(setting_name) 125 | result = nil 126 | @lines.each_with_index do |line, index| 127 | if match = @@SETTING_REGEX.match(line) 128 | if match[2] == setting_name 129 | result = index 130 | end 131 | end 132 | end 133 | result 134 | end 135 | 136 | def remove_lines(setting_name, value=nil) 137 | if value.kind_of?(Array) 138 | val_arr = value 139 | else 140 | val_arr = [value] 141 | end 142 | val_arr.each do |val| 143 | @lines.each_with_index do |line, index| 144 | if (match = @@SETTING_REGEX.match(line)) 145 | if match[2] == setting_name 146 | if val.nil? or val_arr.include?(match[4]) 147 | @lines.delete_at(index) 148 | break 149 | end 150 | end 151 | end 152 | end 153 | end 154 | end 155 | 156 | def add_lines(setting_name, value) 157 | indent_str = ' ' * (indentation || 0) 158 | if current = find_last_setting(setting_name) 159 | offset = current 160 | elsif comment = find_commented_setting(setting_name) 161 | offset = comment + 1 162 | else 163 | offset = @lines.length 164 | end 165 | if value.kind_of?(Array) 166 | value.each do |val| 167 | @lines.insert(offset, "#{indent_str}#{setting_name}=#{val}\n") 168 | offset += 1 169 | end 170 | else 171 | @lines.insert(offset, "#{indent_str}#{setting_name}=#{value}\n") 172 | end 173 | end 174 | 175 | end 176 | end 177 | end 178 | end 179 | -------------------------------------------------------------------------------- /manifests/clouds.pp: -------------------------------------------------------------------------------- 1 | # == Class: openstacklib::clouds 2 | # 3 | # Generates clouds.yaml for openstack CLI 4 | # 5 | # == Parameters 6 | # 7 | # [*username*] 8 | # (Required) The name of the keystone user. 9 | # 10 | # [*password*] 11 | # (Required) Password of the keystone user. 12 | # 13 | # [*auth_url*] 14 | # (Required) The URL to use for authentication. 15 | # 16 | # [*path*] 17 | # (Optional) Path to the clouds.yaml file. 18 | # Defaults to $name 19 | # 20 | # [*user_domain_name*] 21 | # (Optional) Name of domain for $username. 22 | # Defaults to 'Default' 23 | # 24 | # [*project_name*] 25 | # (Optional) The name of the keystone project. 26 | # Defaults to undef 27 | # 28 | # [*project_domain_name*] 29 | # (Optional) Name of domain for $project_name. 30 | # Defaults to 'Default' 31 | # 32 | # [*system_scope*] 33 | # (Optional) Scope for system operations. 34 | # Defaults to undef 35 | # 36 | # [*interface*] 37 | # (Optional) Determine the endpoint to be used. 38 | # Defaults to undef 39 | # 40 | # [*region_name*] 41 | # (Optional) The region in which the service can be found. 42 | # Defaults to undef 43 | # 44 | # [*api_versions*] 45 | # (Optional) Hash of service type and version to determine API version 46 | # for that service to use. 47 | # Example: { 'identity' => '3', 'compute' => '2.latest' } 48 | # Defaults to {} 49 | # 50 | # [*file_user*] 51 | # (Optional) User that owns the clouds.yaml file. 52 | # Defaults to 'root'. 53 | # 54 | # [*file_group*] 55 | # (Optional) Group that owns the clouds.yaml file. 56 | # Defaults to 'root'. 57 | # 58 | define openstacklib::clouds ( 59 | String[1] $username, 60 | String[1] $password, 61 | Stdlib::HTTPUrl $auth_url, 62 | Stdlib::Absolutepath $path = $name, 63 | String[1] $user_domain_name = 'Default', 64 | Optional[String[1]] $project_name = undef, 65 | String[1] $project_domain_name = 'Default', 66 | Optional[String[1]] $system_scope = undef, 67 | Optional[Enum['public', 'internal', 'admin']] $interface = undef, 68 | Optional[String[1]] $region_name = undef, 69 | Hash $api_versions = {}, 70 | String $file_user = 'root', 71 | String $file_group = 'root', 72 | ) { 73 | if !$project_name and !$system_scope { 74 | fail('One of project_name and system_scope should be set') 75 | } 76 | 77 | file { $path: 78 | mode => '0600', 79 | owner => $file_user, 80 | group => $file_group, 81 | content => template('openstacklib/clouds.yaml.erb'), 82 | show_diff => false, 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /manifests/db/mysql.pp: -------------------------------------------------------------------------------- 1 | # == Definition: openstacklib::db::mysql 2 | # 3 | # This resource configures a mysql database for an OpenStack service 4 | # 5 | # == Parameters: 6 | # 7 | # [*password*] 8 | # Password to use for the database user for this service; 9 | # string; required 10 | # 11 | # [*plugin*] 12 | # Authentication plugin to use when connecting to the MySQL server; 13 | # string; optional; default to 'undef' 14 | # 15 | # [*dbname*] 16 | # The name of the database 17 | # string; optional; default to the $title of the resource, i.e. 'nova' 18 | # 19 | # [*user*] 20 | # The database user to create; 21 | # string; optional; default to the $title of the resource, i.e. 'nova' 22 | # 23 | # [*host*] 24 | # The IP address or hostname of the user in mysql_grant; 25 | # string; optional; default to '127.0.0.1' 26 | # 27 | # [*charset*] 28 | # The charset to use for the database; 29 | # string; optional; default to 'utf8' 30 | # 31 | # [*collate*] 32 | # The collate to use for the database; 33 | # string; optional; default to 'utf8_general_ci' 34 | # 35 | # [*allowed_hosts*] 36 | # Additional hosts that are allowed to access this database; 37 | # array or string; optional; default to undef 38 | # 39 | # [*privileges*] 40 | # Privileges given to the database user; 41 | # string or array of strings; optional; default to 'ALL' 42 | # 43 | # [*create_user*] 44 | # Flag to allow for the skipping of the user as part of the database setup. 45 | # Set to false to skip the user creation. 46 | # Defaults to true. 47 | # 48 | # [*create_grant*] 49 | # Flag to allow for the skipping of the user grants as part of the database 50 | # setup. Set to false to skip the user creation. 51 | # Defaults to true. 52 | # 53 | # [*tls_options*] 54 | # The TLS options that the user will have 55 | # Defaults to ['NONE'] 56 | # 57 | # DEPRECATED PARAMETERS 58 | # 59 | # [*password_hash*] 60 | # Password hash to use for the database user for this service; 61 | # string; optional; default to undef 62 | # 63 | define openstacklib::db::mysql ( 64 | Optional[String[1]] $password = undef, 65 | Optional[String[1]] $plugin = undef, 66 | String[1] $dbname = $title, 67 | String[1] $user = $title, 68 | String[1] $host = '127.0.0.1', 69 | String[1] $charset = 'utf8', 70 | String[1] $collate = 'utf8_general_ci', 71 | Variant[String[1], Array[String[1]]] $allowed_hosts = [], 72 | Variant[String[1], Array[String[1]]] $privileges = 'ALL', 73 | Boolean $create_user = true, 74 | Boolean $create_grant = true, 75 | Variant[String[1], Array[String[1]]] $tls_options = ['NONE'], 76 | # DEPRECATED PARAMETER 77 | Optional[String[1]] $password_hash = undef, 78 | ) { 79 | 80 | include mysql::server 81 | include mysql::client 82 | 83 | if $password_hash != undef { 84 | warning("The password_hash parameter was deprecated and will be removed \ 85 | in a future release. Use password instead") 86 | $password_hash_real = $password_hash 87 | } elsif $password != undef { 88 | $password_hash_real = mysql::password($password) 89 | } else { 90 | fail('password should be set') 91 | } 92 | 93 | mysql_database { $dbname: 94 | ensure => present, 95 | charset => $charset, 96 | collate => $collate, 97 | } 98 | 99 | Class['mysql::server'] ~> Mysql_database<| title == $dbname |> 100 | Class['mysql::client'] ~> Mysql_database<| title == $dbname |> 101 | 102 | if $create_user or $create_grant { 103 | $allowed_hosts_list = unique(concat(any2array($allowed_hosts), [$host])) 104 | $real_allowed_hosts = prefix($allowed_hosts_list, "${dbname}_") 105 | 106 | openstacklib::db::mysql::host_access { $real_allowed_hosts: 107 | user => $user, 108 | plugin => $plugin, 109 | password_hash => $password_hash_real, 110 | database => $dbname, 111 | privileges => $privileges, 112 | create_user => $create_user, 113 | create_grant => $create_grant, 114 | tls_options => $tls_options, 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /manifests/db/mysql/host_access.pp: -------------------------------------------------------------------------------- 1 | # Allow a user to access the database for the service 2 | # 3 | # == Namevar 4 | # String with the form dbname_host. The host part of the string is the host 5 | # to allow 6 | # 7 | # == Parameters 8 | # [*user*] 9 | # username to allow 10 | # 11 | # [*password_hash*] 12 | # user password hash 13 | # 14 | # [*database*] 15 | # the database name 16 | # 17 | # [*privileges*] 18 | # the privileges to grant to this user 19 | # 20 | # [*plugin*] 21 | # Authentication plugin to use when connecting to the MySQL server; 22 | # Defaults to undef 23 | # 24 | # [*create_user*] 25 | # Flag to allow for the skipping of the user as part of the database setup. 26 | # Set to false to skip the user creation. 27 | # Defaults to true. 28 | # 29 | # [*create_grant*] 30 | # Flag to allow for the skipping of the user grants as part of the database 31 | # setup. Set to false to skip the user creation. 32 | # Defaults to true. 33 | # 34 | # [*tls_options*] 35 | # The TLS options that the user will have 36 | # Defaults to ['NONE'] 37 | # 38 | define openstacklib::db::mysql::host_access ( 39 | String[1] $user, 40 | String[1] $password_hash, 41 | String[1] $database, 42 | Variant[String[1], Array[String[1]]] $privileges, 43 | Optional[String[1]] $plugin = undef, 44 | Boolean $create_user = true, 45 | Boolean $create_grant = true, 46 | Variant[String[1], Array[String[1]]] $tls_options = ['NONE'], 47 | ) { 48 | 49 | if ! ($title =~ /_/) { 50 | fail('Title must be $dbname_$host') 51 | } 52 | 53 | $host = inline_template('<%= @title.split("_").last.downcase %>') 54 | 55 | if $create_user { 56 | mysql_user { "${user}@${host}": 57 | plugin => $plugin, 58 | password_hash => $password_hash, 59 | tls_options => $tls_options, 60 | } 61 | Mysql_database<| title == $database |> 62 | ~> Mysql_user<| title == "${user}@${host}" |> 63 | } 64 | 65 | if $create_grant { 66 | mysql_grant { "${user}@${host}/${database}.*": 67 | privileges => $privileges, 68 | table => "${database}.*", 69 | user => "${user}@${host}", 70 | } 71 | Mysql_user<| title == "${user}@${host}" |> 72 | ~> Mysql_grant<| title == "${user}@${host}/${database}.*" |> 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /manifests/db/postgresql.pp: -------------------------------------------------------------------------------- 1 | # == Definition: openstacklib::db::postgresql 2 | # 3 | # This resource configures a postgresql database for an OpenStack service 4 | # 5 | # == Parameters: 6 | # 7 | # [*password*] 8 | # Password to use for the database user for this service; 9 | # string; required 10 | # 11 | # [*dbname*] 12 | # The name of the database 13 | # string; optional; default to the $title of the resource, i.e. 'nova' 14 | # 15 | # [*user*] 16 | # The database user to create; 17 | # string; optional; default to the $title of the resource, i.e. 'nova' 18 | # 19 | # [*encoding*] 20 | # The charset to use for the database; 21 | # string; optional; default to undef 22 | # 23 | # [*privileges*] 24 | # Privileges given to the database user; 25 | # string or array of strings; optional; default to 'ALL' 26 | # 27 | # DEPRECATED PARAMETERS 28 | # 29 | # [*password_hash*] 30 | # Password hash to use for the database user for this service; 31 | # string; required 32 | # 33 | define openstacklib::db::postgresql ( 34 | Optional[String[1]] $password = undef, 35 | String[1] $dbname = $title, 36 | String[1] $user = $title, 37 | Optional[String[1]] $encoding = undef, 38 | Variant[String[1], Array[String[1]]] $privileges = 'ALL', 39 | # DEPRECATED PARAMETERS 40 | Optional[String[1]] $password_hash = undef, 41 | ){ 42 | 43 | if $password_hash != undef { 44 | warning('The password_hash parameter was deprecated and will be removed 45 | in a future release. Use password instead') 46 | $password_hash_real = $password_hash 47 | } elsif $password != undef { 48 | $password_hash_real = postgresql::postgresql_password($user, $password) 49 | } else { 50 | fail('password should be set') 51 | } 52 | 53 | postgresql::server::db { $dbname: 54 | user => $user, 55 | password => $password_hash_real, 56 | encoding => $encoding, 57 | grant => $privileges, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /manifests/defaults.pp: -------------------------------------------------------------------------------- 1 | # == Class: openstacklib::defaults 2 | # 3 | # Default configuration for all openstack-puppet module. 4 | # 5 | # This file is loaded in the params.pp of each class. 6 | # 7 | class openstacklib::defaults { 8 | case $facts['os']['family'] { 9 | 'RedHat': { 10 | $pyver3 = '3.9' 11 | } 12 | 'Debian': { 13 | $pyver3 = '3' 14 | } 15 | default:{ 16 | fail("Unsupported osfamily: ${facts['os']['family']}") 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /manifests/iscsid.pp: -------------------------------------------------------------------------------- 1 | # == Class: openstacklib::iscsid 2 | # 3 | # Installs and configures the iscsid daemon 4 | # 5 | # == Parameters 6 | # 7 | # [*enabled*] 8 | # (optional) Should the service be enabled. 9 | # Defaults to true. 10 | # 11 | # [*manage_service*] 12 | # (optional) Whether the service should be managed by Puppet. 13 | # Defaults to true. 14 | # 15 | # [*package_ensure*] 16 | # (optional) ensure state for package. 17 | # Defaults to 'present' 18 | # 19 | class openstacklib::iscsid( 20 | Boolean $enabled = true, 21 | Boolean $manage_service = true, 22 | $package_ensure = 'present' 23 | ) { 24 | 25 | include openstacklib::params 26 | 27 | package { 'open-iscsi': 28 | ensure => $package_ensure, 29 | name => $::openstacklib::params::open_iscsi_package_name, 30 | tag => 'openstack', 31 | } 32 | 33 | # In CentOS9/RHEL9 initiatorname.iscsi is not created automatically 34 | # so should be created 35 | exec { 'create-initiatorname-file': 36 | command => 'echo "InitiatorName=`/usr/sbin/iscsi-iname`" > /etc/iscsi/initiatorname.iscsi', 37 | path => ['/usr/bin','/usr/sbin','/bin','/usr/bin'], 38 | creates => '/etc/iscsi/initiatorname.iscsi', 39 | require => Package['open-iscsi'], 40 | } 41 | 42 | if $manage_service { 43 | if $enabled { 44 | $service_ensure = 'running' 45 | } else { 46 | $service_ensure = 'stopped' 47 | } 48 | 49 | # iscsid service is started automatically when iscsiadm command is 50 | # executed but there is no harm even if the service is already started. 51 | service { 'iscsid': 52 | ensure => $service_ensure, 53 | enable => $enabled, 54 | } 55 | Package['open-iscsi'] ~> Service['iscsid'] 56 | Exec['create-initiatorname-file'] ~> Service['iscsid'] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /manifests/messaging/rabbitmq.pp: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2014 eNovance SAS 3 | # 4 | # Author: Emilien Macchi 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | # == Definition: openstacklib::messaging::rabbitmq 19 | # 20 | # This resource creates RabbitMQ resources for an OpenStack service. 21 | # 22 | # == Parameters: 23 | # 24 | # [*userid*] 25 | # (optional) The username to use when connecting to Rabbit 26 | # Defaults to 'guest' 27 | # 28 | # [*password*] 29 | # (optional) The password to use when connecting to Rabbit 30 | # Defaults to 'guest' 31 | # 32 | # [*virtual_host*] 33 | # (optional) The virtual host to use when connecting to Rabbit 34 | # Defaults to '/' 35 | # 36 | # [*is_admin*] 37 | # (optional) If the user should be admin or not 38 | # Defaults to false 39 | # 40 | # [*configure_permission*] 41 | # (optional) Define configure permission 42 | # Defaults to '.*' 43 | # 44 | # [*write_permission*] 45 | # (optional) Define write permission 46 | # Defaults to '.*' 47 | # 48 | # [*read_permission*] 49 | # (optional) Define read permission 50 | # Defaults to '.*' 51 | # 52 | # [*manage_user*] 53 | # (optional) Manage or not the user 54 | # Defaults to true 55 | # 56 | # [*manage_user_permissions*] 57 | # (optional) Manage or not user permissions 58 | # Defaults to true 59 | # 60 | # [*manage_vhost*] 61 | # (optional) Manage or not the vhost 62 | # Defaults to true 63 | # 64 | define openstacklib::messaging::rabbitmq( 65 | String[1] $userid = 'guest', 66 | String[1] $password = 'guest', 67 | String[1] $virtual_host = '/', 68 | Boolean $is_admin = false, 69 | String $configure_permission = '.*', 70 | String $write_permission = '.*', 71 | String $read_permission = '.*', 72 | Boolean $manage_user = true, 73 | Boolean $manage_user_permissions = true, 74 | Boolean $manage_vhost = true, 75 | ) { 76 | 77 | if $manage_user { 78 | if $userid == 'guest' { 79 | $is_admin_real = false 80 | } else { 81 | $is_admin_real = $is_admin 82 | } 83 | ensure_resource('rabbitmq_user', $userid, { 84 | 'admin' => $is_admin_real, 85 | 'password' => $password, 86 | 'provider' => 'rabbitmqctl', 87 | }) 88 | } 89 | 90 | if $manage_user_permissions { 91 | ensure_resource('rabbitmq_user_permissions', "${userid}@${virtual_host}", { 92 | 'configure_permission' => $configure_permission, 93 | 'write_permission' => $write_permission, 94 | 'read_permission' => $read_permission, 95 | 'provider' => 'rabbitmqctl', 96 | }) 97 | } 98 | 99 | if $manage_vhost { 100 | ensure_resource('rabbitmq_vhost', $virtual_host, { 101 | 'provider' => 'rabbitmqctl', 102 | }) 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /manifests/openstackclient.pp: -------------------------------------------------------------------------------- 1 | # == Class: openstacklib::openstackclient 2 | # 3 | # Installs the openstackclient 4 | # 5 | # == Parameters 6 | # 7 | # [*package_ensure*] 8 | # (Optional) Ensure state of the openstackclient package. 9 | # Defaults to 'present' 10 | # 11 | # [*package_name*] 12 | # (Optional) The name of the package to install 13 | # Defaults to $::openstacklib::params::openstackclient_package_name 14 | # 15 | class openstacklib::openstackclient( 16 | $package_name = $::openstacklib::params::openstackclient_package_name, 17 | $package_ensure = 'present', 18 | ) inherits openstacklib::params { 19 | 20 | ensure_packages($package_name, { 21 | 'ensure' => $package_ensure, 22 | 'tag' => ['openstack', 'openstackclient'] 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /manifests/params.pp: -------------------------------------------------------------------------------- 1 | # == Class: openstacklib::params 2 | # 3 | # These parameters need to be accessed from several locations and 4 | # should be considered to be constant 5 | # 6 | class openstacklib::params { 7 | 8 | include openstacklib::defaults 9 | 10 | $openstackclient_package_name = 'python3-openstackclient' 11 | 12 | case $facts['os']['family'] { 13 | 'RedHat': { 14 | $open_iscsi_package_name = 'iscsi-initiator-utils' 15 | } 16 | 'Debian': { 17 | $open_iscsi_package_name = 'open-iscsi' 18 | } 19 | default:{ 20 | fail("Unsupported osfamily: ${facts['os']['family']}") 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /manifests/policy.pp: -------------------------------------------------------------------------------- 1 | # == Define: openstacklib::policies 2 | # 3 | # This resource is an helper to call the policy definition 4 | # 5 | # == Parameters: 6 | # 7 | # [*policy_path*] 8 | # (Optional) Path to the policy file. This should be an asbolute path. 9 | # Defaults to $name 10 | # 11 | # [*policies*] 12 | # (Optional) Set of policies to configure. This parameter accepts a hash 13 | # value and is used to define the openstacklib::policies::base defined-type 14 | # resouces. For example 15 | # 16 | # { 17 | # 'my-context_is_admin' => { 18 | # 'key' => 'context_is_admin', 19 | # 'value' => 'true' 20 | # }, 21 | # 'default' => { 22 | # 'value' => 'rule:admin_or_owner' 23 | # } 24 | # } 25 | # 26 | # adds the following rules to the policy file. 27 | # 28 | # context_is_admin: true 29 | # default: rule:admin_or_owner 30 | # 31 | # Defaults to {} 32 | # 33 | # [*file_mode*] 34 | # (Optional) Permission mode for the policy file 35 | # Defaults to '0640' 36 | # 37 | # [*file_user*] 38 | # (Optional) User for the policy file 39 | # Defaults to undef 40 | # 41 | # [*file_group*] 42 | # (Optional) Group for the policy file 43 | # Defaults to undef 44 | # 45 | # [*file_format*] 46 | # (Optional) Format for file contents. Valid value is 'yaml'. 47 | # Defaults to 'yaml'. 48 | # 49 | # [*purge_config*] 50 | # (Optional) Whether to set only the specified policy rules in the policy 51 | # file. 52 | # Defaults to false. 53 | # 54 | define openstacklib::policy ( 55 | Stdlib::Absolutepath $policy_path = $name, 56 | Openstacklib::Policies $policies = {}, 57 | Stdlib::Filemode $file_mode = '0640', 58 | $file_user = undef, 59 | $file_group = undef, 60 | Enum['yaml'] $file_format = 'yaml', 61 | Boolean $purge_config = false, 62 | ) { 63 | 64 | if empty($policies) { 65 | create_resources('openstacklib::policy::default', { $policy_path => { 66 | file_mode => $file_mode, 67 | file_user => $file_user, 68 | file_group => $file_group, 69 | file_format => $file_format, 70 | purge_config => $purge_config, 71 | }}) 72 | } else { 73 | $policy_defaults = { 74 | file_path => $policy_path, 75 | file_mode => $file_mode, 76 | file_user => $file_user, 77 | file_group => $file_group, 78 | file_format => $file_format, 79 | purge_config => $purge_config 80 | } 81 | 82 | create_resources('openstacklib::policy::base', $policies, $policy_defaults) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /manifests/policy/base.pp: -------------------------------------------------------------------------------- 1 | # == Definition: openstacklib::policy::base 2 | # 3 | # This resource configures the policy file for an OpenStack service 4 | # 5 | # == Parameters: 6 | # 7 | # [*file_path*] 8 | # (required) Path to the policy file 9 | # 10 | # [*key*] 11 | # (optional) The key to replace the value for 12 | # Defaults to $name 13 | # 14 | # [*value*] 15 | # (optional) The value to set 16 | # Defaults to '' 17 | # 18 | # [*file_mode*] 19 | # (optional) Permission mode for the policy file 20 | # Defaults to '0640' 21 | # 22 | # [*file_user*] 23 | # (optional) User for the policy file 24 | # Defaults to undef 25 | # 26 | # [*file_group*] 27 | # (optional) Group for the policy file 28 | # Defaults to undef 29 | # 30 | # [*file_format*] 31 | # (optional) Format for file contents. Valid value is 'yaml' 32 | # Defaults to 'yaml'. 33 | # 34 | # [*purge_config*] 35 | # (optional) Whether to set only the specified policy rules in the policy 36 | # file. 37 | # Defaults to false. 38 | # 39 | define openstacklib::policy::base ( 40 | Stdlib::Absolutepath $file_path, 41 | String[1] $key = $name, 42 | String $value = '', 43 | Stdlib::Filemode $file_mode = '0640', 44 | $file_user = undef, 45 | $file_group = undef, 46 | Enum['yaml'] $file_format = 'yaml', 47 | Boolean $purge_config = false, 48 | ) { 49 | 50 | ensure_resource('openstacklib::policy::default', $file_path, { 51 | file_path => $file_path, 52 | file_mode => $file_mode, 53 | file_user => $file_user, 54 | file_group => $file_group, 55 | file_format => $file_format, 56 | purge_config => $purge_config 57 | }) 58 | 59 | # NOTE(tkajianm): Currently we use single quotes('') to quote the whole 60 | # value, thus a single quote in value should be escaped 61 | # by another single quote (which results in '') 62 | # NOTE(tkajinam): Replace '' by ' first in case ' is already escaped 63 | $value_real = regsubst(regsubst($value, '\'\'', '\'', 'G'), '\'', '\'\'', 'G') 64 | 65 | file_line { "${file_path}-${key}" : 66 | path => $file_path, 67 | line => "'${key}': '${value_real}'", 68 | match => "^['\"]?${key}(?!:)['\"]?\\s*:.+" 69 | } 70 | Openstacklib::Policy::Default<| title == $file_path |> 71 | -> File_line<| title == "${file_path}-${key}" |> 72 | } 73 | -------------------------------------------------------------------------------- /manifests/policy/default.pp: -------------------------------------------------------------------------------- 1 | # == Definition: openstacklib::policy::default 2 | # 3 | # Create a default (empty) policy fie for an OpenStack service 4 | # 5 | # == Parameters: 6 | # 7 | # [*file_path*] 8 | # (Optional) Path to the policy file 9 | # Defaults to $name 10 | # 11 | # [*file_mode*] 12 | # (Optional) Permission mode for the policy file 13 | # Defaults to '0640' 14 | # 15 | # [*file_user*] 16 | # (Optional) User for the policy file 17 | # Defaults to undef 18 | # 19 | # [*file_group*] 20 | # (Optional) Group for the policy file 21 | # Defaults to undef 22 | # 23 | # [*file_format*] 24 | # (Optional) Format for file contents. Valid value is 'yaml'. 25 | # Defaults to 'yaml'. 26 | # 27 | # [*purge_config*] 28 | # (Optional) Whether to set only the specified policy rules in the policy 29 | # file. 30 | # Defaults to false. 31 | # 32 | define openstacklib::policy::default ( 33 | Stdlib::Absolutepath $file_path = $name, 34 | Stdlib::Filemode $file_mode = '0640', 35 | $file_user = undef, 36 | $file_group = undef, 37 | Enum['yaml'] $file_format = 'yaml', 38 | Boolean $purge_config = false, 39 | ) { 40 | 41 | ensure_resource('file', $file_path, { 42 | mode => $file_mode, 43 | owner => $file_user, 44 | group => $file_group, 45 | replace => $purge_config, 46 | content => '' 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /manifests/policyrcd.pp: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016 Matthew J. Black 3 | # 4 | # Author: Matthew J. Black 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | # == Class: openstacklib::policyrcd 19 | # 20 | # [*services*] 21 | # (required) The services that should be in the policy-rc.d shell script 22 | # that should not autostart on install. 23 | # 24 | class openstacklib::policyrcd( 25 | Array[String[1]] $services 26 | ) { 27 | 28 | if $facts['os']['family'] == 'Debian' { 29 | # We put this out there so openstack services wont auto start 30 | # when installed. 31 | file { '/usr/sbin/policy-rc.d': 32 | ensure => present, 33 | content => template('openstacklib/policy-rc.d.erb'), 34 | mode => '0755', 35 | owner => root, 36 | group => root, 37 | } 38 | 39 | File['/usr/sbin/policy-rc.d'] -> Package<| tag == 'openstack' |> 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /manifests/service_validation.pp: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2014 eNovance SAS 3 | # 4 | # Author: Emilien Macchi 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | # == Definition: openstacklib::service_validation 19 | # 20 | # This resource does service validation for an OpenStack service. 21 | # 22 | # == Parameters: 23 | # 24 | # [*command*] 25 | # Command to run for validating the service; 26 | # string; required 27 | # 28 | # [*service_name*] 29 | # The name of the service to validate; 30 | # string; optional; default to the $title of the resource, i.e. 'nova-api' 31 | # 32 | # [*path*] 33 | # The path of the command to validate the service; 34 | # string; optional; default to '/usr/bin:/bin:/usr/sbin:/sbin' 35 | # 36 | # [*provider*] 37 | # The provider to use for the exec command; 38 | # string; optional; default to 'shell' 39 | # 40 | # [*refreshonly*] 41 | # If the service validation should only occur on a refresh/notification; 42 | # boolean; optional; default to false 43 | # 44 | # [*timeout*] 45 | # The maximum time the command should take; 46 | # string; optional; default to '60' 47 | # 48 | # [*tries*] 49 | # Number of times to retry validation; 50 | # string; optional; default to '10' 51 | # 52 | # [*try_sleep*] 53 | # Number of seconds between validation attempts; 54 | # string; optional; default to '2' 55 | # 56 | # [*onlyif*] 57 | # Run the exec if all conditions in the array return true. 58 | # string or array; optional; default to 'undef' 59 | # 60 | # [*unless*] 61 | # Run the exec if all conditions in the array return false. 62 | # string or array; optional; default to 'undef' 63 | # 64 | # [*environment*] 65 | # Environment to use 66 | # string; optional; default to empty array 67 | # 68 | define openstacklib::service_validation( 69 | $command, 70 | $service_name = $name, 71 | $path = '/usr/bin:/bin:/usr/sbin:/sbin', 72 | $provider = shell, 73 | $refreshonly = false, 74 | $timeout = '60', 75 | $tries = '10', 76 | $try_sleep = '2', 77 | $onlyif = undef, 78 | $unless = undef, 79 | $environment = [], 80 | ) { 81 | 82 | if $onlyif and $unless { 83 | fail ('Only one parameter should be declared: onlyif or unless') 84 | } 85 | 86 | exec { "execute ${service_name} validation": 87 | command => $command, 88 | environment => $environment, 89 | path => $path, 90 | provider => $provider, 91 | refreshonly => $refreshonly, 92 | timeout => $timeout, 93 | tries => $tries, 94 | try_sleep => $try_sleep, 95 | onlyif => $onlyif, 96 | unless => $unless, 97 | logoutput => 'on_failure', 98 | } 99 | 100 | anchor { "create ${service_name} anchor": } 101 | -> Exec<| title == "execute ${service_name} validation" |> 102 | 103 | } 104 | 105 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Puppet Labs and OpenStack Contributors", 3 | "dependencies": [ 4 | { 5 | "name": "puppetlabs/apache", 6 | "version_requirement": ">=5.0.0 <13.0.0" 7 | }, 8 | { 9 | "name": "puppetlabs/inifile", 10 | "version_requirement": ">=2.0.0 <7.0.0" 11 | }, 12 | { 13 | "name": "puppetlabs/mysql", 14 | "version_requirement": ">=6.0.0 <17.0.0" 15 | }, 16 | { 17 | "name": "puppetlabs/stdlib", 18 | "version_requirement": ">=5.0.0 <10.0.0" 19 | }, 20 | { 21 | "name": "puppet/rabbitmq", 22 | "version_requirement": ">=2.0.2 <15.0.0" 23 | }, 24 | { 25 | "name": "puppetlabs/postgresql", 26 | "version_requirement": ">=6.4.0 <11.0.0" 27 | } 28 | ], 29 | "description": "Puppet module library to expose common functionality between OpenStack modules.", 30 | "issues_url": "https://bugs.launchpad.net/puppet-openstacklib", 31 | "license": "Apache-2.0", 32 | "name": "openstack-openstacklib", 33 | "operatingsystem_support": [ 34 | { 35 | "operatingsystem": "Debian", 36 | "operatingsystemrelease": [ 37 | "12" 38 | ] 39 | }, 40 | { 41 | "operatingsystem": "RedHat", 42 | "operatingsystemrelease": [ 43 | "9" 44 | ] 45 | }, 46 | { 47 | "operatingsystem": "CentOS", 48 | "operatingsystemrelease": [ 49 | "9" 50 | ] 51 | }, 52 | { 53 | "operatingsystem": "Ubuntu", 54 | "operatingsystemrelease": [ 55 | "24.04" 56 | ] 57 | } 58 | ], 59 | "project_page": "https://launchpad.net/puppet-openstacklib", 60 | "requirements": [ 61 | { 62 | "name": "puppet", 63 | "version_requirement": ">= 7.0.0 < 9.0.0" 64 | } 65 | ], 66 | "source": "https://opendev.org/openstack/puppet-openstacklib.git", 67 | "summary": "Puppet OpenStack Libraries", 68 | "version": "26.0.0" 69 | } 70 | -------------------------------------------------------------------------------- /releasenotes/notes/Add-TLS-options-for-mysql-user-creation-172536d7f3963ce2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - For the users that result from the usage of the mysql resource, it is now 4 | possible to specify the TLS options. This is useful if one wants to force 5 | the user to only connect using TLS, or if one wants to force the usage of 6 | client certificates for this specific user. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/access_log_env_var-87f4bfd3356c6cd2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add access_log_env_var for apache vhost. 5 | Allows that only requests with particular environment 6 | variables set are logged. 7 | Example: set a dontlog variable for healthchecks, 8 | so healthchecks are not logged. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/add-ssl_verify_client-87e52209cc80861d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Added ssl_verify_client parameter to openstacklib::wsgi::apache. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/apache-request_headers-1db72ccfd1e76735.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The new ``openstacklib::wsgi::apache::request_headers`` parameter has been 5 | added. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/apache-vhost-wsgi_daemon_process-3e90ea82934cbaea.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | This module now requires a puppetlabs-apache version >= 5.0.0 5 | -------------------------------------------------------------------------------- /releasenotes/notes/bugfix-1664561-f5964a3777b9ed93.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Bugfix 1664561. Allow to use Integers and Strings 4 | for the port parameter. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/bump-mysql-dep-10-217373db021b4c1f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Puppet OpenStack now supports the 10.x release of the PuppetLabs MySQL module. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/catch_403-237b79f33ab3364f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Catch HTTP 403 responses (not authorized requests) in openstack provider. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/centos-9-support-899c5dc223ded57c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Now this module supports CentOS 9 and Red Hat Enterprise Linux 9. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/clouds-yaml-e8a87dfceba4619d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The new ``openstacklib::clouds`` resource type has been added, which 5 | manages the ``clouds.yaml`` file to store credentials for the ``openstack`` 6 | cli. 7 | 8 | - | 9 | Now ``Puppet::Provider::Openstack::CredentialsV3`` supports loading 10 | credentials from the ``clouds.yaml`` file. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/clouds-yaml-owner-group-4e7b2d4e7028cfef.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add ``file_user`` and ``file_group`` parameters to ``openstacklib::clouds`` 5 | resource to manage ``clouds.yaml`` file owner and group. -------------------------------------------------------------------------------- /releasenotes/notes/db-password_hash-1045114a36b6f292.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | deprecations: 3 | - | 4 | The ``password_hash`` parameter in ``openstacklib::db::mysql`` and 5 | ``openstacklib::db::postgresql`` were deprecated and will be removed in 6 | a future release. Use the ``password`` parameter instead, so that password 7 | hash is generated from given user and password in puppet-openstacklib. 8 | upgrade: 9 | - | 10 | Now this module requires puppetlabs-postgresql >= 6.4.0 . 11 | -------------------------------------------------------------------------------- /releasenotes/notes/deprecate-puppet-5-support-1864c361a7a9d402.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Puppet OpenStack has in this release deprecated Puppet 5 support. 4 | This version of Puppet will be EOL as of May 2020 which means that 5 | you can still use it during this release but in the V release using 6 | Puppet 6 will be a requirement. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/deprecate-puppet4-59a430de68834017.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | Puppet OpenStack has in this release deprecated Puppet 4 support. 4 | This older version of Puppet is EOL since October 2018 and will only 5 | get security fixes. We will continue to support this Puppet version 6 | for the duration of this release with minimal testing. In the next 7 | release Puppet 4 support will be removed completely and you should 8 | move to using Puppet 5 or the newly released Puppet 6. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-fedora-66989e6f7049e5bd.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Fedora is no longer supported. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/ensure-policy-file-exists-1c53dc62e10c53d3.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | The upstream services are moving their policy files into code which means 5 | they may not exist if a user tries to customize the policies. We've added 6 | an file resource to openstacklib::policy::base to ensure the file exists 7 | but this means that the user/group need to be passed into the module or 8 | it will possibly lock out services from being able to read this file as 9 | the defaults limit it to just root:root. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/feature_add_default_config_placeholder-280f69c0edbf76c6.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add a manifest which is loaded by all puppet modules in 4 | manifests/param.pp. This is described in 5 | `bug 1599113 6 | `__ 7 | 8 | fixes: 9 | - The first feature would help fixing RDO package using virtual 10 | package which is a recurring problem. Example of such problem is 11 | `bug 1599113 12 | `__ 13 | -------------------------------------------------------------------------------- /releasenotes/notes/feature_add_exclusion_to_retry_mechanism-2acb52fa25bd315c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add the possibility to exclude some exception from retry 4 | mechanism. It helps to fix `bug 1597357 5 | `__ 6 | -------------------------------------------------------------------------------- /releasenotes/notes/feature_add_transform_for_config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add the ability to transform values in config files. This allows 4 | operators to configure input directly at assignment by specifying 5 | a 'transform_to' attribute. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/fix-openrc-parsing-2cc3a95b3bf2b259.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Improve openrc parsing to prevent issues when additional bash code is 5 | present in a user's openrc file. LP#1699950 6 | -------------------------------------------------------------------------------- /releasenotes/notes/ipv6_array_support-ea28cf0939e820f6.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Allow to give an array of IP addresses to normalize_ip_for_uri and normalize 4 | each IP in the list. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/ipv6_brackets-7a453aea5e091855.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Utility to handle IPv6 address brackets with normalize_ip_for_uri 4 | is a function that help us to add brackets to IPv6 addresses 5 | when missing. The function moved to puppetlabs-stdlib but is not in latest release 6 | yet. Once it's done, we'll probably drop this function so our modules will use stdlib. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/iscsid-0a9fe8a9dba4047b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The new ``openstacklib::iscsid`` class has been added. This class can be 5 | used to set up basic configurations for the iscsid service. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/manage_policy_rc_d_file-747510db06792d52.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add a class that takes an array of services that can be 4 | configured to not autostart on package install. The most 5 | notable example is keystone. The policy-rc.d file is 6 | generated to return the correct exit code to prevent the 7 | services from autostarting on package install. This change 8 | is only meant for debian based systems. 9 | issues: 10 | - ubuntu cloud archive keystone package is auto-starting the 11 | eventlet process on package install. 12 | -------------------------------------------------------------------------------- /releasenotes/notes/memcached-inet6-prefix-91e867d03bc5f6e2.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Utility to handle prefixing IPv6 address with ``inet6:``. This is useful 5 | for services relying on python-memcached which require the 6 | ``inet6:[`` format. -------------------------------------------------------------------------------- /releasenotes/notes/migrate-policy-format-from-json-to-yaml-3389e1d5348cd69b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | deprecations: 3 | - | 4 | Json format of policy files has been deprecated and will be removed in 5 | a future release. Use yaml format instead. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/more_db_options-d96316ae4eb5a78c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add an "extra" hash parameter to os_database_connection that allows to extend 4 | the database uri configuration. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/mysql-user-and-grants-optional-fd34f4686d44aec3.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add the ability to skip the mysql user and/or grant creation as part of the 4 | openstack::db::mysql resource. 5 | fixes: 6 | - openstack::db::mysql could not be used to create multiple databases 7 | with the same user/password for access due to a duplicate mysql_user 8 | resource declaration. Now the user and/or grant creation process can be 9 | skipped if they already exist. 10 | -------------------------------------------------------------------------------- /releasenotes/notes/no-directory-listing-8e6270ed0e1eb1d0.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | security: 3 | - Do not authorize directory listing 4 | fixes: 5 | - rhbz#1778052 6 | - LP#1854442 7 | -------------------------------------------------------------------------------- /releasenotes/notes/openstacklib-multiple-wsgi-script-aliases-34ff48b463416e0f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | openstacklib::wsgi::apache now has a parameter named custom_wsgi_script_aliases 5 | which can be used to add more WSGI script alises to the apache::vhost resource. 6 | These additional WSGI script aliases is added upon the default script alias which 7 | is $path combined with $wsgi_script_dir and $wsgi_script_file. 8 | -------------------------------------------------------------------------------- /releasenotes/notes/openstacklib-wsgi-apache-keystone-support-54bc020f9f1553c6.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | openstacklib::wsgi::apache now has support for headers, access_log_pipe, 5 | access_log_syslog, error_log_pipe and error_log_syslog params which will 6 | be added to the apache::vhost setup. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/openstacklib-wsgi-apache-log-level-f0f1567b27c64ac0.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add `log_level` parameter to control `LogLevel` for Apache vhost. 5 | By default, Apache only logs warnings and errors in its errors logfile, 6 | while request timeouts are logged by `mod_reqtimeout` at LogLevel info. 7 | Default `log_level` value is not defined, which corresponds to 8 | the default Apache `LogLevel warn`. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/os_transport-alt-transport-7cd300380ece2fc9.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - bug 1651215 The transport parameter was not being used so 4 | transport was fixed value 'rabbit' 5 | -------------------------------------------------------------------------------- /releasenotes/notes/os_transport_url-b6fe15a8f21d387b.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - os_transport_url puppet parser function can be used to generate valid 4 | transport_url URIs from a hash of connection parameters. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/os_url-efc774dd8ab4571d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The new ``os_url`` function has been added. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/os_workers-fact-0ce731f0536c2792.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Moved existing $::os_workers to $::os_workers_small 4 | - Updated $::os_workers to have a value between '2' and '12'. 5 | The value of this fact is the larger value between '2' 6 | and the number of processors divided by '2' but will not 7 | exceed '12'. 8 | - Created fact $::os_workers_large to have a value of number 9 | of processors divided by '2' 10 | fixes: 11 | - bug 1650424 The current calculation for os_workers negatively 12 | impacts api response times 13 | -------------------------------------------------------------------------------- /releasenotes/notes/os_workers-fact-420e6ad783cba982.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Created a new fact called $::os_workers to be used as the defaults for any 4 | of the openstack service worker configurations. This fact will have a value 5 | between '2' and '8'. The value of this fact is the larger value between '2' 6 | and the number of processors divided by '4' but will not exceed '8'. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/os_workers_for_worker_count-34eb55ddf55f4a11.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | other: 3 | - Parameters that control the number of spawned child processes for 4 | distributing processing have had their default value changed from 5 | ::processorcount to ::os_workers. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/os_workers_heat_engine-af8ce1fdf3ce1ae1.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Implement a new fact, $::os_workers_heat_engine that is responding to 5 | a specific need with Heat Engine service, where minimum of workers will 6 | be 4 and maximum of 24. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/os_workers_large-fact-71afa253044ce56e.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | The os_workers_large fact now returns an Integer instead of a Tuple. 5 | It will also return a minimum value of 1. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/policy_rcd_provider-1ef3d203b9af1110.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Added policy_rcd provider for managing policy-rc.d for Debian family. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/puppet-5-unsupported-ac35e83ee3d2b12c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Puppet 5 is now officially unsupported and support may be broken in any of 5 | the Puppet modules in this cycle. We recommend all deployments to start 6 | using Puppet 6 in this release. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/puppet-8-4b210a58a65b61da.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | This module now officially supports Puppet 8. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/puppetlabs-mysql-update-dependency-7f84516724bbd9d8.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | The openstacklib module and all other OpenStack modules depending on this 5 | module now requires a puppetlabs-mysql version >= 6.0.0 6 | -------------------------------------------------------------------------------- /releasenotes/notes/purge-policy-file-1ad9f366345142e7.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Now the ``openstacklib::policies`` resource type provides the basic set 5 | of configurations for policy settings. It provides the purge_config 6 | parameter which ensures a policy file is purged. 7 | 8 | upgrade: 9 | - | 10 | The ``openstacklib::policies`` class has been re-implemented as a defined 11 | resource type. 12 | -------------------------------------------------------------------------------- /releasenotes/notes/release-note-pyvers-f5f857f91ab978ed.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | The openstacklib module now provides a variable openstacklib::params::pyvers 5 | that is used by all other OpenStack modules to determine if the operating 6 | system has packages with python3 or python3. It's very important that you 7 | have an updated openstacklib module when upgrading before using all other 8 | modules. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/release-note-ubuntu-py3-6663c95bf4a4f31f.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | prelude: > 3 | In this release Ubuntu has moved all projects that supported it to python3 4 | which means that there will be a lot of changes. The Puppet OpenStack project 5 | does not test the upgrade path from python2 to python3 packages so there might 6 | be manual steps required when moving to the python3 packages. 7 | upgrade: 8 | - | 9 | Ubuntu packages are now using python3, the upgrade path is not tested by 10 | Puppet OpenStack. Manual steps may be required when upgrading. 11 | -------------------------------------------------------------------------------- /releasenotes/notes/remove-centos-8-8b9bc74045173169.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | CentOS 8 Stream is no longer supported by this module. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/remove-os_package_type-fact-9de4c7060b735a62.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | The ``os_package_type`` fact has been removed. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/remove-policy-json-8902dc11c5576e73.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Support for json format policy files has been removed. Now yaml is the only 5 | supported format. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/remove-puppet-4-7edd1536c4078f7a.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Puppet OpenStack does not officially support Puppet 4 anymore. Deployments 5 | should use Puppet 5 or Puppet 6. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/remove-puppet-6-14aa2ddd0e088922.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Puppet 6 is no longer supported. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/retry_client-b8a0e1f9ff679281.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Add retries to the openstack command. 4 | Increase command timeout to 20s and request timeout to 60s 5 | and sleep 3s between retries. Do not retry non-idempotent actions. 6 | This is a more robust implementation that will prevent failures in case 7 | of Keystone API failures during a deployment. 8 | -------------------------------------------------------------------------------- /releasenotes/notes/service-validation-environment-ad85f84da786768c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | There's a new environment variable for service-validation. With it, it is 5 | possible to pass in things like OS_PASWORD which should never appear in 6 | the command line. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/support-for-yaml-policy-da1ccf9fa692dca3.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | Oslo policy is moving towards yaml as a policy file format and is 5 | deprecating json. Policy definitons now may contain a 'file_format' 6 | field to specify 'yaml' or 'json' as a file format. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/support_for_setting_a_value_immutable-27e52b14f61ff6c3.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | This add `os_immutable` fact that can be used in the puppet 5 | openstack module as value for all types that inherit 6 | openstack_config. Using ::os_immutable as a value of the 7 | configuration parameter will tell puppet to not change the current 8 | value, whatever it is. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/support_region_name_in_providers-cde6d75f0ddbec28.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - Add support for multiple regions in base provider code used by other puppet 4 | modules. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/system-scope-credential-113608525e12a22d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Now ``Puppet::Provider::Openstack::CredentialsV3`` supports system scope 5 | credential and domain scope credential in addition to project scope 6 | credential. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/ubuntu-jammy-da580c780aeafbef.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | This module now supports Ubuntu 22.04 (Jammy Jellyfish). 5 | 6 | upgrade: 7 | - | 8 | This module no longer supports Ubuntu 20.04 (Focal Fossa). 9 | -------------------------------------------------------------------------------- /releasenotes/notes/ubuntu-noble-89f5f89bd0e4c83d.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Ubuntu 24.04 is now formally supported. 5 | 6 | upgrade: 7 | - | 8 | Ubuntu 22.04 is no longer supported. 9 | -------------------------------------------------------------------------------- /releasenotes/notes/use-reno-1caaec4ba5aa4285.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Release notes are no longer maintained by hand, we now use the reno tool to 4 | manage them. 5 | -------------------------------------------------------------------------------- /releasenotes/notes/wsgi-aliases-2f74cbb84fcfd706.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The new ``openstacklib::wsgi::apache::aliases`` parameter has been added. 5 | This parameter can be used to add alias definitions to the httpd vhost. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/wsgi-import-script-64665fae9dccf797.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Add new WSGI related options that should allow faster application startup 5 | and loading. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/wsgi-setenv-8e8519fdb96d98b0.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | The new ``openstacklib::wsgi::apache::setenv`` parameter has been added. 5 | This paramaeter can be to define environment variables for vhost, passed 6 | by httpd. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/wsgi_process_options-5ff706a7beb9b893.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - Add two parameters to apache wsgi to allow overwrite 4 | and/or add additional wsgi process options. 5 | -------------------------------------------------------------------------------- /releasenotes/source/2023.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/2023.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2023.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2023.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2025.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2025.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2025.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/_static/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/puppet-openstacklib/9d3d43d8327dfcef98efb0c6a02a8d923aa1c3de/releasenotes/source/_static/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/index.rst: -------------------------------------------------------------------------------- 1 | ============================================= 2 | Welcome to puppet-openstacklib Release Notes! 3 | ============================================= 4 | 5 | Contents 6 | ======== 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | unreleased 12 | 2025.1 13 | 2024.2 14 | 2024.1 15 | 2023.2 16 | 2023.1 17 | zed 18 | yoga 19 | xena 20 | wallaby 21 | victoria 22 | ussuri 23 | train 24 | stein 25 | rocky 26 | queens 27 | pike 28 | ocata 29 | newton 30 | mitaka 31 | 32 | 33 | Indices and tables 34 | ================== 35 | 36 | * :ref:`genindex` 37 | * :ref:`search` 38 | -------------------------------------------------------------------------------- /releasenotes/source/mitaka.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Mitaka Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/mitaka 7 | -------------------------------------------------------------------------------- /releasenotes/source/newton.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Newton Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/newton 7 | -------------------------------------------------------------------------------- /releasenotes/source/ocata.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Ocata Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: origin/stable/ocata 7 | -------------------------------------------------------------------------------- /releasenotes/source/pike.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Pike Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/pike 7 | -------------------------------------------------------------------------------- /releasenotes/source/queens.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Queens Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/queens 7 | -------------------------------------------------------------------------------- /releasenotes/source/rocky.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Rocky Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/rocky 7 | -------------------------------------------------------------------------------- /releasenotes/source/stein.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Stein Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/stein 7 | -------------------------------------------------------------------------------- /releasenotes/source/train.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Train Series Release Notes 3 | ========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/train 7 | -------------------------------------------------------------------------------- /releasenotes/source/unreleased.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | Current Series Release Notes 3 | ============================== 4 | 5 | .. release-notes:: 6 | -------------------------------------------------------------------------------- /releasenotes/source/ussuri.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Ussuri Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/ussuri 7 | -------------------------------------------------------------------------------- /releasenotes/source/victoria.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | Victoria Series Release Notes 3 | ============================= 4 | 5 | .. release-notes:: 6 | :branch: stable/victoria 7 | -------------------------------------------------------------------------------- /releasenotes/source/wallaby.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Wallaby Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/wallaby 7 | -------------------------------------------------------------------------------- /releasenotes/source/xena.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Xena Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/xena 7 | -------------------------------------------------------------------------------- /releasenotes/source/yoga.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Yoga Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/yoga 7 | -------------------------------------------------------------------------------- /releasenotes/source/zed.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Zed Series Release Notes 3 | ======================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/zed 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = puppet-openstacklib 3 | summary = Puppet module for OpenStack Openstacklib 4 | description_file = 5 | README.md 6 | author = OpenStack 7 | author_email = openstack-discuss@lists.openstack.org 8 | home_page = https://docs.openstack.org/puppet-openstack-guide/latest 9 | license = Apache License, Version 2.0 10 | classifier = 11 | Intended Audience :: Developers 12 | Intended Audience :: Information Technology 13 | Intended Audience :: System Administrators 14 | License :: OSI Approved :: Apache Software License 15 | Operating System :: POSIX :: Linux 16 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import setuptools 17 | 18 | setuptools.setup( 19 | setup_requires=['pbr>=2.0.0'], 20 | py_modules=[], 21 | pbr=True) 22 | -------------------------------------------------------------------------------- /spec/acceptance/mysql_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper_acceptance' 2 | 3 | describe 'openstacklib mysql' do 4 | 5 | context 'default parameters' do 6 | 7 | it 'should work with no errors' do 8 | pp= <<-EOS 9 | Exec { logoutput => 'on_failure' } 10 | 11 | class { 'mysql::server': } 12 | 13 | $charset = $facts['os']['name'] ? { 14 | 'Ubuntu' => 'utf8mb3', 15 | default => 'utf8', 16 | } 17 | 18 | openstacklib::db::mysql { 'ci': 19 | charset => $charset, 20 | collate => "${charset}_general_ci", 21 | password_hash => mysql::password('keystone'), 22 | allowed_hosts => '127.0.0.1', 23 | } 24 | EOS 25 | 26 | # Run it twice and test for idempotency 27 | apply_manifest(pp, :catch_failures => true) 28 | apply_manifest(pp, :catch_changes => true) 29 | end 30 | 31 | describe port(3306) do 32 | it { is_expected.to be_listening.with('tcp') } 33 | end 34 | 35 | it 'should have ci database' do 36 | command("mysql -e 'show databases;' | grep -q ci") do |r| 37 | expect(r.exit_code).to eq 0 38 | end 39 | end 40 | 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/acceptance/openstacklib_config_provider_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper_acceptance' 2 | 3 | describe 'basic config provider resource' do 4 | 5 | context 'default parameters' do 6 | 7 | it 'should work with no errors' do 8 | pp= <<-EOS 9 | Exec { logoutput => 'on_failure' } 10 | 11 | # We create the file manually here because we only want to test 12 | # the logic of the provider hence installing the whole stack would 13 | # result in some overhead that is already tested in puppet-keystone 14 | File <||> -> Keystone_config <||> 15 | file { '/etc/keystone' : 16 | ensure => directory, 17 | } 18 | file { '/etc/keystone/keystone.conf' : 19 | ensure => file, 20 | } 21 | 22 | keystone_config { 'DEFAULT/thisshouldexist' : 23 | value => 'foo', 24 | } 25 | 26 | keystone_config { 'DEFAULT/thisshouldnotexist' : 27 | value => '', 28 | } 29 | 30 | keystone_config { 'DEFAULT/thisshouldexist2' : 31 | value => '', 32 | ensure_absent_val => 'toto', 33 | } 34 | 35 | keystone_config { 'DEFAULT/thisshouldnotexist2' : 36 | value => 'toto', 37 | ensure_absent_val => 'toto', 38 | } 39 | EOS 40 | 41 | 42 | # Run it twice and test for idempotency 43 | apply_manifest(pp, :catch_failures => true) 44 | apply_manifest(pp, :catch_changes => true) 45 | end 46 | 47 | describe file('/etc/keystone/keystone.conf') do 48 | it { should exist } 49 | it { should contain('thisshouldexist=foo') } 50 | it { should contain('thisshouldexist2=') } 51 | 52 | its(:content) { should_not match /thisshouldnotexist/ } 53 | end 54 | 55 | 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/acceptance/openstacklib_policy_base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper_acceptance' 2 | 3 | describe 'policy file management' do 4 | 5 | context 'with policy.yaml' do 6 | it 'should work with no errors' do 7 | pp= <<-EOS 8 | Exec { logoutput => 'on_failure' } 9 | openstacklib::policy::base { 'is_admin': 10 | file_path => '/tmp/policy.yaml', 11 | key => 'is_admin', 12 | value => 'role:admin', 13 | file_format => 'yaml', 14 | } 15 | openstacklib::policy::base { 'is_member': 16 | file_path => '/tmp/policy.yaml', 17 | key => 'is_member', 18 | value => 'role:member', 19 | file_format => 'yaml', 20 | } 21 | openstacklib::policy::base { 'get_router': 22 | file_path => '/tmp/policy.yaml', 23 | key => 'get_router', 24 | value => 'rule:admin_or_owner', 25 | file_format => 'yaml', 26 | } 27 | openstacklib::policy::base { 'get_router:distributed': 28 | file_path => '/tmp/policy.yaml', 29 | key => 'get_router:distributed', 30 | value => 'rule:admin_only', 31 | file_format => 'yaml', 32 | } 33 | 34 | EOS 35 | 36 | # Run it twice and test for idempotency 37 | apply_manifest(pp, :catch_failures => true) 38 | apply_manifest(pp, :catch_changes => true) 39 | end 40 | 41 | describe file('/tmp/policy.yaml') do 42 | it { should exist } 43 | it { should contain("'is_admin': 'role:admin'") } 44 | it { should contain("'is_member': 'role:member'") } 45 | it { should contain("'get_router': 'rule:admin_or_owner'") } 46 | it { should contain("'get_router:distributed': 'rule:admin_only'") } 47 | end 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /spec/acceptance/rabbitmq_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper_acceptance' 2 | 3 | describe 'openstacklib class' do 4 | 5 | context 'default parameters' do 6 | 7 | it 'should work with no errors' do 8 | pp= <<-EOS 9 | include openstack_integration 10 | include openstack_integration::repos 11 | include openstack_integration::rabbitmq 12 | 13 | # openstacklib resources 14 | include openstacklib::openstackclient 15 | 16 | ::openstacklib::messaging::rabbitmq { 'ci': 17 | userid => 'ci', 18 | is_admin => true, 19 | } 20 | EOS 21 | 22 | # Run it twice and test for idempotency 23 | apply_manifest(pp, :catch_failures => true) 24 | apply_manifest(pp, :catch_changes => true) 25 | end 26 | 27 | describe 'test rabbitmq resources' do 28 | it 'should list rabbitmq ci resources' do 29 | command('rabbitmqctl list_users') do |r| 30 | expect(r.stdout).to match(/^ci/) 31 | expect(r.stdout).not_to match(/^guest/) 32 | expect(r.exit_code).to eq(0) 33 | end 34 | 35 | command('rabbitmqctl list_permissions') do |r| 36 | expect(r.stdout).to match(/^ci\t\.\*\t\.\*\t\.\*$/) 37 | expect(r.exit_code).to eq(0) 38 | end 39 | end 40 | end 41 | 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/classes/openstacklib_defaults_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::defaults' do 4 | shared_examples 'openstacklib::defaults' do 5 | context 'with defaults' do 6 | it { should contain_class('openstacklib::defaults') } 7 | end 8 | end 9 | 10 | on_supported_os({ 11 | :supported_os => OSDefaults.get_supported_os 12 | }).each do |os,facts| 13 | context "on #{os}" do 14 | let (:facts) do 15 | facts.merge(OSDefaults.get_facts()) 16 | end 17 | 18 | it_behaves_like 'openstacklib::defaults' 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/classes/openstacklib_iscsid_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::iscsid' do 4 | shared_examples_for 'openstacklib::iscsid' do 5 | context 'with default params' do 6 | it { is_expected.to contain_package('open-iscsi').with( 7 | :name => platform_params[:open_iscsi_package_name], 8 | :ensure => 'present', 9 | :tag => 'openstack', 10 | )} 11 | 12 | it { is_expected.to contain_exec('create-initiatorname-file').with({ 13 | :command => 'echo "InitiatorName=`/usr/sbin/iscsi-iname`" > /etc/iscsi/initiatorname.iscsi', 14 | :path => ['/usr/bin','/usr/sbin','/bin','/usr/bin'], 15 | :creates => '/etc/iscsi/initiatorname.iscsi', 16 | }).that_requires('Package[open-iscsi]')} 17 | 18 | it { is_expected.to contain_service('iscsid').with( 19 | :ensure => 'running', 20 | :enable => true, 21 | ) } 22 | end 23 | 24 | end 25 | 26 | on_supported_os({ 27 | :supported_os => OSDefaults.get_supported_os 28 | }).each do |os,facts| 29 | context "on #{os}" do 30 | let (:facts) do 31 | facts.merge!(OSDefaults.get_facts()) 32 | end 33 | 34 | let(:platform_params) do 35 | case facts[:os]['family'] 36 | when 'Debian' 37 | { :open_iscsi_package_name => 'open-iscsi' } 38 | when 'RedHat' 39 | { :open_iscsi_package_name => 'iscsi-initiator-utils' } 40 | end 41 | end 42 | 43 | it_behaves_like 'openstacklib::iscsid' 44 | end 45 | end 46 | 47 | end 48 | -------------------------------------------------------------------------------- /spec/classes/openstacklib_openstackclient_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::openstackclient' do 4 | shared_examples_for 'openstacklib::openstackclient' do 5 | context 'with default params' do 6 | it { should contain_package(platform_params[:openstackclient_package_name]).with( 7 | :ensure => 'installed', 8 | :tag => ['openstack', 'openstackclient'] 9 | )} 10 | end 11 | 12 | context 'with non default package name' do 13 | let :params do 14 | { 15 | :package_name => 'my-openstackclient' 16 | } 17 | end 18 | 19 | it { should contain_package('my-openstackclient').with( 20 | :ensure => 'installed', 21 | :tag => ['openstack', 'openstackclient'] 22 | )} 23 | end 24 | end 25 | 26 | on_supported_os({ 27 | :supported_os => OSDefaults.get_supported_os 28 | }).each do |os,facts| 29 | context "on #{os}" do 30 | let (:facts) do 31 | facts.merge!(OSDefaults.get_facts()) 32 | end 33 | 34 | let(:platform_params) do 35 | case facts[:os]['family'] 36 | when 'Debian' 37 | { :openstackclient_package_name => 'python3-openstackclient' } 38 | when 'RedHat' 39 | { :openstackclient_package_name => 'python3-openstackclient' } 40 | end 41 | end 42 | 43 | it_behaves_like 'openstacklib::openstackclient' 44 | end 45 | end 46 | 47 | end 48 | -------------------------------------------------------------------------------- /spec/classes/openstacklib_policyrcd_spec.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016 Matthew J. Black 3 | # 4 | # Author: Matthew J. Black 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | # Unit tests for openstacklib::policyrcd 19 | # 20 | require 'spec_helper' 21 | 22 | describe 'openstacklib::policyrcd' do 23 | shared_examples 'openstacklib::policyrcd on Debian platforms' do 24 | context 'with single service' do 25 | let :params do 26 | { 27 | :services => ['keystone'] 28 | } 29 | end 30 | 31 | let(:contents) { 32 | <<-eof 33 | #!/bin/bash 34 | 35 | if [ "$1" == "keystone" ] 36 | then 37 | exit 101 38 | fi 39 | 40 | exit 0 41 | eof 42 | } 43 | 44 | it { should contain_file('/usr/sbin/policy-rc.d').with_content(contents) } 45 | end 46 | 47 | context 'with multiple services' do 48 | let :params do 49 | { 50 | :services => ['keystone', 'nova'] 51 | } 52 | end 53 | 54 | let(:contents) { 55 | <<-eof 56 | #!/bin/bash 57 | 58 | if [ "$1" == "keystone" ] 59 | then 60 | exit 101 61 | fi 62 | 63 | if [ "$1" == "nova" ] 64 | then 65 | exit 101 66 | fi 67 | 68 | exit 0 69 | eof 70 | } 71 | 72 | it { should contain_file('/usr/sbin/policy-rc.d').with_content(contents) } 73 | end 74 | end 75 | 76 | shared_examples 'openstacklib::policyrcd on RedHat platforms' do 77 | context 'with single service' do 78 | let :params do 79 | { 80 | :services => ['keystone'] 81 | } 82 | end 83 | 84 | it { should_not contain_file('/usr/sbin/policy-rc.d') } 85 | end 86 | end 87 | 88 | on_supported_os({ 89 | :supported_os => OSDefaults.get_supported_os 90 | }).each do |os,facts| 91 | context "on #{os}" do 92 | let (:facts) do 93 | facts.merge!(OSDefaults.get_facts()) 94 | end 95 | 96 | it_behaves_like "openstacklib::policyrcd on #{facts[:os]['family']} platforms" 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_clouds_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::clouds' do 4 | shared_examples 'openstacklib::clouds' do 5 | let :title do 6 | '/etc/openstack/clouds.yaml' 7 | end 8 | 9 | context 'with the required parameters' do 10 | let :params do 11 | { 12 | :username => 'admin', 13 | :password => 'secrete', 14 | :auth_url => 'http://127.0.0.1:5000/', 15 | :project_name => 'demo', 16 | } 17 | end 18 | 19 | it 'creates a clouds.yaml file' do 20 | should contain_file('/etc/openstack/clouds.yaml').with( 21 | :mode => '0600', 22 | :owner => 'root', 23 | :group => 'root', 24 | ) 25 | end 26 | end 27 | 28 | context 'with file owner/group' do 29 | let :params do 30 | { 31 | :username => 'admin', 32 | :password => 'secrete', 33 | :auth_url => 'http://127.0.0.1:5000/', 34 | :project_name => 'demo', 35 | :file_user => 'foo', 36 | :file_group => 'bar', 37 | } 38 | end 39 | 40 | it 'creates a clouds.yaml file with correct ownership' do 41 | should contain_file('/etc/openstack/clouds.yaml').with( 42 | :mode => '0600', 43 | :owner => 'foo', 44 | :group => 'bar', 45 | ) 46 | end 47 | end 48 | end 49 | 50 | on_supported_os({ 51 | :supported_os => OSDefaults.get_supported_os 52 | }).each do |os,facts| 53 | context "on #{os}" do 54 | let (:facts) do 55 | facts.merge!(OSDefaults.get_facts()) 56 | end 57 | 58 | it_behaves_like 'openstacklib::clouds' 59 | end 60 | end 61 | 62 | end 63 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_db_mysql_host_access_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::db::mysql::host_access' do 4 | let :pre_condition do 5 | "include mysql::server\n" + 6 | "openstacklib::db::mysql { 'nova':\n" + 7 | " password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601'}" 8 | end 9 | 10 | shared_examples 'openstacklib::db::mysql::host_access examples' do 11 | context 'with required parameters' do 12 | let (:title) { 'nova_10.0.0.1' } 13 | 14 | let :params do 15 | { 16 | :user => 'foobar', 17 | :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601', 18 | :database => 'nova', 19 | :privileges => 'ALL' 20 | } 21 | end 22 | 23 | it { should contain_mysql_user("#{params[:user]}@10.0.0.1").with( 24 | :plugin => nil, 25 | :password_hash => params[:password_hash], 26 | :tls_options => ['NONE'] 27 | )} 28 | 29 | it { should contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with( 30 | :user => "#{params[:user]}@10.0.0.1", 31 | :privileges => 'ALL', 32 | :table => "#{params[:database]}.*" 33 | )} 34 | end 35 | 36 | context 'with overriding authentication plugin' do 37 | let (:title) { 'nova_10.0.0.1' } 38 | 39 | let :params do 40 | { 41 | :user => 'foobar', 42 | :plugin => 'mysql_native_password', 43 | :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601', 44 | :database => 'nova', 45 | :privileges => 'ALL' 46 | } 47 | end 48 | 49 | it { should contain_mysql_user("#{params[:user]}@10.0.0.1").with( 50 | :plugin => params[:plugin], 51 | :password_hash => params[:password_hash], 52 | :tls_options => ['NONE'] 53 | )} 54 | 55 | it { should contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with( 56 | :user => "#{params[:user]}@10.0.0.1", 57 | :privileges => 'ALL', 58 | :table => "#{params[:database]}.*" 59 | )} 60 | end 61 | 62 | context 'with skipping user creation' do 63 | let (:title) { 'nova_10.0.0.1' } 64 | 65 | let :params do 66 | { 67 | :user => 'foobar', 68 | :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601', 69 | :database => 'nova', 70 | :privileges => 'ALL', 71 | :create_user => false, 72 | } 73 | end 74 | 75 | it { should_not contain_mysql_user("#{params[:user]}@10.0.0.1") } 76 | 77 | it { should contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with( 78 | :user => "#{params[:user]}@10.0.0.1", 79 | :privileges => 'ALL', 80 | :table => "#{params[:database]}.*" 81 | )} 82 | end 83 | 84 | context 'with skipping grant creation' do 85 | let (:title) { 'nova_10.0.0.1' } 86 | 87 | let :params do 88 | { 89 | :user => 'foobar', 90 | :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601', 91 | :database => 'nova', 92 | :privileges => 'ALL', 93 | :create_grant => false, 94 | } 95 | end 96 | 97 | it { should contain_mysql_user("#{params[:user]}@10.0.0.1").with( 98 | :plugin => nil, 99 | :password_hash => params[:password_hash] 100 | )} 101 | 102 | it { should_not contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*") } 103 | end 104 | 105 | context 'with skipping user and grant creation' do 106 | let (:title) { 'nova_10.0.0.1' } 107 | 108 | let :params do 109 | { 110 | :user => 'foobar', 111 | :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601', 112 | :database => 'nova', 113 | :privileges => 'ALL', 114 | :create_user => false, 115 | :create_grant => false, 116 | } 117 | end 118 | 119 | it { should_not contain_mysql_user("#{params[:user]}@10.0.0.1") } 120 | it { should_not contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*") } 121 | end 122 | end 123 | 124 | on_supported_os({ 125 | :supported_os => OSDefaults.get_supported_os 126 | }).each do |os,facts| 127 | context "on #{os}" do 128 | let (:facts) do 129 | facts.merge!(OSDefaults.get_facts()) 130 | end 131 | 132 | it_behaves_like 'openstacklib::db::mysql::host_access examples' 133 | end 134 | end 135 | 136 | end 137 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_db_mysql_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::db::mysql' do 4 | let :pre_condition do 5 | 'include mysql::server' 6 | end 7 | 8 | let (:title) { 'nova' } 9 | 10 | let :required_params do 11 | { 12 | :password => 'fooboozoo_default_password', 13 | } 14 | end 15 | 16 | shared_examples 'openstacklib::db::mysql examples' do 17 | context 'with only required parameters' do 18 | let :params do 19 | required_params 20 | end 21 | 22 | it { should contain_mysql_database(title).with( 23 | :charset => 'utf8', 24 | :collate => 'utf8_general_ci' 25 | )} 26 | 27 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 28 | :user => title, 29 | :plugin => nil, 30 | :database => title, 31 | :privileges => 'ALL', 32 | :tls_options => ['NONE'], 33 | )} 34 | end 35 | 36 | context 'with overriding dbname parameter' do 37 | let :params do 38 | required_params.merge!( :dbname => 'foobar' ) 39 | end 40 | 41 | it { should contain_mysql_database(params[:dbname]).with( 42 | :charset => 'utf8', 43 | :collate => 'utf8_general_ci' 44 | )} 45 | 46 | it { should contain_openstacklib__db__mysql__host_access("#{params[:dbname]}_127.0.0.1").with( 47 | :user => title, 48 | :plugin => nil, 49 | :database => params[:dbname], 50 | :privileges => 'ALL', 51 | :create_user => true, 52 | :create_grant => true, 53 | :tls_options => ['NONE'], 54 | )} 55 | end 56 | 57 | context 'with overriding user parameter' do 58 | let :params do 59 | required_params.merge!( :user => 'foobar' ) 60 | end 61 | 62 | it { should contain_mysql_database(title).with( 63 | :charset => 'utf8', 64 | :collate => 'utf8_general_ci' 65 | )} 66 | 67 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 68 | :user => params[:user], 69 | :plugin => nil, 70 | :database => title, 71 | :privileges => 'ALL', 72 | :create_user => true, 73 | :create_grant => true, 74 | :tls_options => ['NONE'], 75 | )} 76 | end 77 | 78 | context 'with overriding authentication plugin' do 79 | let :params do 80 | required_params.merge!( 81 | :plugin => 'mysql_native_password', 82 | ) 83 | end 84 | 85 | it { should contain_mysql_database(title).with( 86 | :charset => 'utf8', 87 | :collate => 'utf8_general_ci' 88 | )} 89 | 90 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 91 | :user => title, 92 | :plugin => params[:plugin], 93 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 94 | :database => title, 95 | :privileges => 'ALL', 96 | :create_user => true, 97 | :create_grant => true, 98 | :tls_options => ['NONE'], 99 | )} 100 | end 101 | 102 | context 'when overriding charset parameter' do 103 | let :params do 104 | required_params.merge!( :charset => 'latin1' ) 105 | end 106 | 107 | it { should contain_mysql_database(title).with_charset(params[:charset]) } 108 | end 109 | 110 | context 'when omitting the required parameter password' do 111 | let :params do 112 | {} 113 | end 114 | 115 | it { should raise_error(Puppet::Error) } 116 | end 117 | 118 | context 'when deprecated password_hash is used' do 119 | let :params do 120 | { :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206' } 121 | end 122 | 123 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 124 | :user => title, 125 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 126 | )} 127 | end 128 | 129 | context 'when notifying other resources' do 130 | let :pre_condition do 131 | 'exec {"nova-db-sync":}' 132 | end 133 | 134 | let :params do 135 | required_params.merge!( :notify => 'Exec[nova-db-sync]' ) 136 | end 137 | 138 | it { should contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Mysql[#{title}]") } 139 | end 140 | 141 | context 'when required for other openstack services' do 142 | let :pre_condition do 143 | 'service {"keystone":}' 144 | end 145 | 146 | let :title do 147 | 'keystone' 148 | end 149 | 150 | let :params do 151 | required_params.merge!( :before => 'Service[keystone]' ) 152 | end 153 | 154 | it { should contain_service('keystone').that_requires("Openstacklib::Db::Mysql[keystone]") } 155 | end 156 | 157 | context "overriding allowed_hosts parameter with array value" do 158 | let :params do 159 | required_params.merge!( :allowed_hosts => ['127.0.0.1', '%'] ) 160 | end 161 | 162 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 163 | :user => title, 164 | :plugin => nil, 165 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 166 | :database => title 167 | )} 168 | 169 | it { should contain_openstacklib__db__mysql__host_access("#{title}_%").with( 170 | :user => title, 171 | :plugin => nil, 172 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 173 | :database => title 174 | )} 175 | end 176 | 177 | context "overriding allowed_hosts parameter with string value" do 178 | let :params do 179 | required_params.merge!( :allowed_hosts => '192.168.1.1' ) 180 | end 181 | 182 | it { should contain_openstacklib__db__mysql__host_access("#{title}_192.168.1.1").with( 183 | :user => title, 184 | :plugin => nil, 185 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 186 | :database => title 187 | )} 188 | end 189 | 190 | context "overriding allowed_hosts parameter equals to host param " do 191 | let :params do 192 | required_params.merge!( :allowed_hosts => '127.0.0.1' ) 193 | end 194 | 195 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 196 | :user => title, 197 | :plugin => nil, 198 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 199 | :database => title 200 | )} 201 | end 202 | 203 | context 'with skipping user creation' do 204 | let :params do 205 | required_params.merge!( :create_user => false ) 206 | end 207 | 208 | it { should contain_mysql_database(title).with( 209 | :charset => 'utf8', 210 | :collate => 'utf8_general_ci' 211 | )} 212 | 213 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 214 | :user => title, 215 | :plugin => nil, 216 | :database => title, 217 | :privileges => 'ALL', 218 | :create_user => false, 219 | :create_grant => true, 220 | )} 221 | end 222 | 223 | context 'with skipping grant creation' do 224 | let :params do 225 | required_params.merge!( :create_grant => false ) 226 | end 227 | 228 | it { should contain_mysql_database(title).with( 229 | :charset => 'utf8', 230 | :collate => 'utf8_general_ci' 231 | )} 232 | 233 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 234 | :user => title, 235 | :plugin => nil, 236 | :database => title, 237 | :privileges => 'ALL', 238 | :create_user => true, 239 | :create_grant => false, 240 | )} 241 | end 242 | 243 | context 'with skipping user and grant creation' do 244 | let :params do 245 | required_params.merge!( :create_user => false, 246 | :create_grant => false ) 247 | end 248 | 249 | it { should contain_mysql_database(title).with( 250 | :charset => 'utf8', 251 | :collate => 'utf8_general_ci' 252 | )} 253 | 254 | it { should_not contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1") } 255 | end 256 | 257 | context 'overriding tls_options' do 258 | let :params do 259 | required_params.merge!( :tls_options => ['SSL'] ) 260 | end 261 | 262 | it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( 263 | :user => title, 264 | :plugin => nil, 265 | :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', 266 | :database => title, 267 | :tls_options => ['SSL'], 268 | )} 269 | end 270 | end 271 | 272 | on_supported_os({ 273 | :supported_os => OSDefaults.get_supported_os 274 | }).each do |os,facts| 275 | context "on #{os}" do 276 | let (:facts) do 277 | facts.merge!(OSDefaults.get_facts()) 278 | end 279 | 280 | it_behaves_like 'openstacklib::db::mysql examples' 281 | end 282 | end 283 | end 284 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_db_postgresql_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::db::postgresql' do 4 | let (:title) { 'nova' } 5 | 6 | let :required_params do 7 | { 8 | :password => 'pw' 9 | } 10 | end 11 | 12 | let (:pre_condition) do 13 | "include postgresql::server" 14 | end 15 | 16 | shared_examples 'openstacklib::db::postgresql examples' do 17 | context 'with only required parameters' do 18 | let :params do 19 | required_params 20 | end 21 | 22 | let :password_hash do 23 | case platform_params[:password_encryption] 24 | when 'scram-sha-256' 25 | 'SCRAM-SHA-256$4096:bm92YQ==$LiUdLrky9dt8Js3NPwLr3TrmmuQBa0NG/xmahcp98UM=:dVY0oEQewk/17+9zFMDkBTek1NRyTAt3iyyfLKHIR8M=' 26 | else 27 | 'md557ae0608fad632bf0155cb9502a6b454' 28 | end 29 | end 30 | 31 | it { should contain_postgresql__server__db(title).with( 32 | :user => title, 33 | :password => password_hash, 34 | )} 35 | end 36 | 37 | context 'when overriding encoding' do 38 | let :params do 39 | required_params.merge!( :encoding => 'latin1' ) 40 | end 41 | 42 | it { should contain_postgresql__server__db(title).with_encoding(params[:encoding]) } 43 | end 44 | 45 | context 'when omitting the required parameter password_hash' do 46 | let :params do 47 | {} 48 | end 49 | 50 | it { should raise_error(Puppet::Error) } 51 | end 52 | 53 | context 'when notifying other resources' do 54 | let :pre_condition do 55 | "include postgresql::server 56 | exec { 'nova-db-sync': }" 57 | end 58 | 59 | let :params do 60 | required_params.merge!( :notify => 'Exec[nova-db-sync]' ) 61 | end 62 | 63 | it { should contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Postgresql[#{title}]") } 64 | end 65 | 66 | context 'when required for other openstack services' do 67 | let :pre_condition do 68 | "include postgresql::server 69 | service {'keystone':}" 70 | end 71 | 72 | let :title do 73 | 'keystone' 74 | end 75 | 76 | let :params do 77 | required_params.merge!( :before => 'Service[keystone]' ) 78 | end 79 | 80 | it { should contain_service('keystone').that_requires("Openstacklib::Db::Postgresql[keystone]") } 81 | end 82 | 83 | context 'when deprecated password_hash is used' do 84 | let :params do 85 | { :password_hash => 'md557ae0608fad632bf0155cb9502a6b454' } 86 | end 87 | 88 | it { should contain_postgresql__server__db(title).with( 89 | :user => title, 90 | :password => 'md557ae0608fad632bf0155cb9502a6b454' 91 | )} 92 | end 93 | end 94 | 95 | on_supported_os({ 96 | :supported_os => OSDefaults.get_supported_os 97 | }).each do |os,facts| 98 | context "on #{os}" do 99 | let (:facts) do 100 | facts.merge!(OSDefaults.get_facts({ 101 | # puppet-postgresql requires the service_provider fact provided by 102 | # puppetlabs-postgresql. 103 | :service_provider => 'systemd' 104 | })) 105 | end 106 | 107 | let :platform_params do 108 | case facts[:os]['family'] 109 | when 'Debian' 110 | { :password_encryption => 'scram-sha-256' } 111 | when 'RedHat' 112 | { :password_encryption => 'ms5' } 113 | end 114 | end 115 | 116 | it_behaves_like 'openstacklib::db::postgresql examples' 117 | end 118 | end 119 | end 120 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_messaging_rabbitmq_spec.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2014 eNovance SAS 3 | # 4 | # Author: Emilien Macchi 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | 18 | require 'spec_helper' 19 | 20 | describe 'openstacklib::messaging::rabbitmq' do 21 | let (:title) { 'nova' } 22 | 23 | shared_examples 'openstacklib::messaging::rabbitmq examples' do 24 | let :params do 25 | {} 26 | end 27 | 28 | context 'with default parameters' do 29 | it { should contain_rabbitmq_user('guest').with( 30 | :admin => false, 31 | :password => 'guest', 32 | :provider => 'rabbitmqctl', 33 | )} 34 | 35 | it { should contain_rabbitmq_user_permissions('guest@/').with( 36 | :configure_permission => '.*', 37 | :write_permission => '.*', 38 | :read_permission => '.*', 39 | :provider => 'rabbitmqctl', 40 | )} 41 | 42 | it { should contain_rabbitmq_vhost('/').with( 43 | :provider => 'rabbitmqctl', 44 | )} 45 | end 46 | 47 | context 'with custom parameters' do 48 | before :each do 49 | params.merge!( 50 | :userid => 'nova', 51 | :password => 'secrete', 52 | :virtual_host => '/nova', 53 | :is_admin => true, 54 | :configure_permission => '.nova', 55 | :write_permission => '.nova', 56 | :read_permission => '.nova' 57 | ) 58 | end 59 | 60 | it { should contain_rabbitmq_user('nova').with( 61 | :admin => true, 62 | :password => 'secrete', 63 | :provider => 'rabbitmqctl', 64 | )} 65 | 66 | it { should contain_rabbitmq_user_permissions('nova@/nova').with( 67 | :configure_permission => '.nova', 68 | :write_permission => '.nova', 69 | :read_permission => '.nova', 70 | :provider => 'rabbitmqctl', 71 | )} 72 | 73 | it { should contain_rabbitmq_vhost('/nova').with( 74 | :provider => 'rabbitmqctl', 75 | )} 76 | end 77 | 78 | context 'when disabling vhost management' do 79 | before :each do 80 | params.merge!( :manage_vhost => false ) 81 | end 82 | 83 | it { should_not contain_rabbitmq_vhost('/') } 84 | end 85 | end 86 | 87 | on_supported_os({ 88 | :supported_os => OSDefaults.get_supported_os 89 | }).each do |os,facts| 90 | context "on #{os}" do 91 | let (:facts) do 92 | facts.merge!(OSDefaults.get_facts()) 93 | end 94 | 95 | it_behaves_like 'openstacklib::messaging::rabbitmq examples' 96 | end 97 | end 98 | 99 | end 100 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_policy_base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::policy::base' do 4 | shared_examples 'openstacklib::policy::base' do 5 | let :title do 6 | 'context_is_admin or owner' 7 | end 8 | 9 | context 'with policy.yaml' do 10 | let :params do 11 | { 12 | :file_path => '/etc/nova/policy.yaml', 13 | :value => 'foo:bar', 14 | :file_mode => '0644', 15 | :file_user => 'foo', 16 | :file_group => 'bar', 17 | } 18 | end 19 | 20 | it { should contain_openstacklib__policy__default('/etc/nova/policy.yaml').with( 21 | :file_mode => '0644', 22 | :file_user => 'foo', 23 | :file_group => 'bar', 24 | :file_format => 'yaml', 25 | :purge_config => false, 26 | )} 27 | 28 | it { should contain_file_line('/etc/nova/policy.yaml-context_is_admin or owner').with( 29 | :path => '/etc/nova/policy.yaml', 30 | :line => '\'context_is_admin or owner\': \'foo:bar\'', 31 | :match => '^[\'"]?context_is_admin or owner(?!:)[\'"]?\s*:.+' 32 | ) } 33 | 34 | context 'with single-quotes in value' do 35 | before do 36 | params.merge!({ 37 | :value => 'foo:\'bar\'' 38 | }) 39 | end 40 | 41 | it { should contain_file_line('/etc/nova/policy.yaml-context_is_admin or owner').with( 42 | :path => '/etc/nova/policy.yaml', 43 | :line => '\'context_is_admin or owner\': \'foo:\'\'bar\'\'\'', 44 | :match => '^[\'"]?context_is_admin or owner(?!:)[\'"]?\s*:.+' 45 | ) } 46 | end 47 | 48 | context 'with pre-formatted single-quotes in value' do 49 | before do 50 | params.merge!({ 51 | :value => 'foo:\'\'bar\'\'' 52 | }) 53 | end 54 | 55 | it { should contain_file_line('/etc/nova/policy.yaml-context_is_admin or owner').with( 56 | :path => '/etc/nova/policy.yaml', 57 | :line => '\'context_is_admin or owner\': \'foo:\'\'bar\'\'\'', 58 | :match => '^[\'"]?context_is_admin or owner(?!:)[\'"]?\s*:.+' 59 | ) } 60 | end 61 | end 62 | 63 | context 'with purge_config enabled' do 64 | let :params do 65 | { 66 | :file_path => '/etc/nova/policy.yaml', 67 | :value => 'foo:bar', 68 | :file_mode => '0644', 69 | :file_user => 'foo', 70 | :file_group => 'bar', 71 | :purge_config => true, 72 | } 73 | end 74 | 75 | it { should contain_openstacklib__policy__default('/etc/nova/policy.yaml').with( 76 | :file_mode => '0644', 77 | :file_user => 'foo', 78 | :file_group => 'bar', 79 | :file_format => 'yaml', 80 | :purge_config => true, 81 | )} 82 | end 83 | 84 | context 'with key overridden' do 85 | let :params do 86 | { 87 | :file_path => '/etc/nova/policy.yaml', 88 | :key => 'context_is_admin', 89 | :value => 'foo:bar', 90 | :file_mode => '0644', 91 | :file_user => 'foo', 92 | :file_group => 'bar', 93 | :file_format => 'yaml', 94 | } 95 | end 96 | 97 | it { should contain_file_line('/etc/nova/policy.yaml-context_is_admin').with( 98 | :path => '/etc/nova/policy.yaml', 99 | :line => '\'context_is_admin\': \'foo:bar\'', 100 | :match => '^[\'"]?context_is_admin(?!:)[\'"]?\s*:.+' 101 | ) } 102 | end 103 | end 104 | 105 | on_supported_os({ 106 | :supported_os => OSDefaults.get_supported_os 107 | }).each do |os,facts| 108 | context "on #{os}" do 109 | let (:facts) do 110 | facts.merge!(OSDefaults.get_facts()) 111 | end 112 | 113 | it_behaves_like 'openstacklib::policy::base' 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_policy_default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::policy::default' do 4 | shared_examples 'openstacklib::policy::default' do 5 | context 'with policy.yaml' do 6 | let :title do 7 | '/etc/nova/policy.yaml' 8 | end 9 | 10 | let :params do 11 | { 12 | :file_mode => '0644', 13 | :file_user => 'foo', 14 | :file_group => 'bar', 15 | } 16 | end 17 | 18 | it { should contain_file('/etc/nova/policy.yaml').with( 19 | :mode => '0644', 20 | :owner => 'foo', 21 | :group => 'bar', 22 | :content => '', 23 | :replace => false 24 | )} 25 | end 26 | 27 | context 'with purge_config enabled' do 28 | let :title do 29 | '/etc/nova/policy.yaml' 30 | end 31 | 32 | let :params do 33 | { 34 | :file_mode => '0644', 35 | :file_user => 'foo', 36 | :file_group => 'bar', 37 | :purge_config => true, 38 | } 39 | end 40 | 41 | it { should contain_file('/etc/nova/policy.yaml').with( 42 | :mode => '0644', 43 | :owner => 'foo', 44 | :group => 'bar', 45 | :content => '', 46 | :replace => true 47 | )} 48 | end 49 | end 50 | 51 | on_supported_os({ 52 | :supported_os => OSDefaults.get_supported_os 53 | }).each do |os,facts| 54 | context "on #{os}" do 55 | let (:facts) do 56 | facts.merge!(OSDefaults.get_facts()) 57 | end 58 | 59 | it_behaves_like 'openstacklib::policy::default' 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_policy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'openstacklib::policy' do 4 | shared_examples 'openstacklib::policy' do 5 | context 'with basic configuration' do 6 | let :title do 7 | '/etc/nova/policy.yaml' 8 | end 9 | 10 | let :params do 11 | { 12 | :policies => { 13 | 'foo' => { 14 | 'key' => 'context_is_admin', 15 | 'value' => 'foo:bar' 16 | } 17 | }, 18 | :file_mode => '0644', 19 | :file_user => 'foo', 20 | :file_group => 'baa', 21 | } 22 | end 23 | 24 | it { should contain_openstacklib__policy__base('foo').with( 25 | :file_path => '/etc/nova/policy.yaml', 26 | :key => 'context_is_admin', 27 | :value => 'foo:bar' 28 | )} 29 | end 30 | 31 | context 'with empty policies and purge_config enabled' do 32 | let :title do 33 | '/etc/nova/policy.yaml' 34 | end 35 | 36 | let :params do 37 | { 38 | :file_mode => '0644', 39 | :file_user => 'foo', 40 | :file_group => 'baa', 41 | :purge_config => true, 42 | } 43 | end 44 | 45 | it { should contain_openstacklib__policy__default('/etc/nova/policy.yaml').with( 46 | :file_mode => '0644', 47 | :file_user => 'foo', 48 | :file_group => 'baa', 49 | :file_format => 'yaml', 50 | :purge_config => true, 51 | )} 52 | end 53 | end 54 | 55 | on_supported_os({ 56 | :supported_os => OSDefaults.get_supported_os 57 | }).each do |os,facts| 58 | context "on #{os}" do 59 | let (:facts) do 60 | facts.merge!(OSDefaults.get_facts()) 61 | end 62 | 63 | it_behaves_like 'openstacklib::policy' 64 | end 65 | end 66 | 67 | end 68 | -------------------------------------------------------------------------------- /spec/defines/openstacklib_service_validation_spec.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2014 eNovance SAS 3 | # 4 | # Author: Emilien Macchi 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 7 | # not use this file except in compliance with the License. You may obtain 8 | # a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15 | # License for the specific language governing permissions and limitations 16 | # under the License. 17 | 18 | require 'spec_helper' 19 | 20 | describe 'openstacklib::service_validation' do 21 | let (:title) { 'nova-api' } 22 | 23 | let :required_params do 24 | { 25 | :command => 'nova list' 26 | } 27 | end 28 | 29 | shared_examples 'openstacklib::service_validation examples' do 30 | context 'with only required parameters' do 31 | let :params do 32 | required_params 33 | end 34 | 35 | it { should contain_exec("execute #{title} validation").with( 36 | :path => '/usr/bin:/bin:/usr/sbin:/sbin', 37 | :provider => 'shell', 38 | :command => 'nova list', 39 | :environment => [], 40 | :refreshonly => false, 41 | :timeout => '60', 42 | :tries => '10', 43 | :try_sleep => '2', 44 | :logoutput => 'on_failure', 45 | )} 46 | end 47 | 48 | context 'with unless parameter' do 49 | let :params do 50 | required_params.merge!({ :unless => 'pwd' }) 51 | end 52 | 53 | it { should contain_exec("execute #{title} validation").with( 54 | :path => '/usr/bin:/bin:/usr/sbin:/sbin', 55 | :provider => 'shell', 56 | :command => 'nova list', 57 | :refreshonly => false, 58 | :timeout => '60', 59 | :tries => '10', 60 | :try_sleep => '2', 61 | :unless => 'pwd', 62 | )} 63 | end 64 | 65 | context 'with onlyif parameter' do 66 | let :params do 67 | required_params.merge!({ :onlyif => 'pwd' }) 68 | end 69 | 70 | it { should contain_exec("execute #{title} validation").with( 71 | :path => '/usr/bin:/bin:/usr/sbin:/sbin', 72 | :provider => 'shell', 73 | :command => 'nova list', 74 | :refreshonly => false, 75 | :timeout => '60', 76 | :tries => '10', 77 | :try_sleep => '2', 78 | :onlyif => 'pwd', 79 | )} 80 | end 81 | 82 | context 'with environment parameter' do 83 | let :params do 84 | required_params.merge!({ :environment => ['OS_PASSWORD=secret'] }) 85 | end 86 | 87 | it { should contain_exec("execute #{title} validation").with( 88 | :environment => ['OS_PASSWORD=secret'], 89 | )} 90 | end 91 | 92 | context 'when omitting a required parameter command' do 93 | let :params do 94 | {} 95 | end 96 | 97 | it { should raise_error(Puppet::Error) } 98 | end 99 | end 100 | 101 | on_supported_os({ 102 | :supported_os => OSDefaults.get_supported_os 103 | }).each do |os,facts| 104 | context "on #{os}" do 105 | let (:facts) do 106 | facts.merge!(OSDefaults.get_facts()) 107 | end 108 | 109 | it_behaves_like 'openstacklib::service_validation examples' 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /spec/functions/inet6_prefix_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'inet6_prefix' do 4 | it { should run.with_params(false).and_return(false)} 5 | it { should run.with_params('not_an_ip').and_return('not_an_ip')} 6 | it { should run.with_params('127.0.0.1').and_return('127.0.0.1')} 7 | it { should run.with_params('::1').and_return('inet6:[::1]')} 8 | it { should run.with_params('[::1]:80').and_return('inet6:[::1]:80')} 9 | it { should run.with_params('[2001::01]').and_return('inet6:[2001::01]')} 10 | it { should run.with_params('[2001::01]:80').and_return('inet6:[2001::01]:80')} 11 | it { should run.with_params('inet6:[2001::01]:80').and_return('inet6:[2001::01]:80')} 12 | # You're not forced to pass an array, a list of argument will do. 13 | it { should run.with_params('::1','::2').and_return(['inet6:[::1]','inet6:[::2]'])} 14 | it { should run.with_params(['::1','::2']).and_return(['inet6:[::1]','inet6:[::2]'])} 15 | it { should run.with_params(['::1','[::2]','::3']).and_return(['inet6:[::1]','inet6:[::2]','inet6:[::3]'])} 16 | it { should run.with_params(['192.168.0.1','[::2]']).and_return(['192.168.0.1','inet6:[::2]'])} 17 | it { should run.with_params(['192.168.0.1','[::2]:80']).and_return(['192.168.0.1','inet6:[::2]:80'])} 18 | it { should run.with_params(['192.168.0.1','::2']).and_return(['192.168.0.1','inet6:[::2]'])} 19 | end 20 | -------------------------------------------------------------------------------- /spec/functions/is_service_default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'is_service_default' do 4 | 5 | it 'refuses without at least one argument' do 6 | is_expected.to run.with_params().\ 7 | and_raise_error(Puppet::ParseError, /Wrong number of arguments/) 8 | end 9 | 10 | it 'refuses too many arguments' do 11 | is_expected.to run.with_params('foo', 'bar').\ 12 | and_raise_error(Puppet::ParseError, /Wrong number of arguments/) 13 | end 14 | 15 | context 'is_service_default' do 16 | it 'with ' do 17 | is_expected.to run.with_params('').and_return(true) 18 | end 19 | 20 | it 'with string != ' do 21 | is_expected.to run.with_params('a value').and_return(false) 22 | end 23 | 24 | it 'with array' do 25 | is_expected.to run.with_params([1,2,3]).and_return(false) 26 | end 27 | 28 | it 'with hash' do 29 | is_expected.to run.with_params({'foo' => 'bar'}).and_return(false) 30 | end 31 | 32 | it 'with integer' do 33 | is_expected.to run.with_params(1234).and_return(false) 34 | end 35 | 36 | it 'with boolean' do 37 | is_expected.to run.with_params(false).and_return(false) 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/functions/normalize_ip_for_uri_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'normalize_ip_for_uri' do 4 | it { should run.with_params(false).and_return(false)} 5 | it { should run.with_params('not_an_ip').and_return('not_an_ip')} 6 | it { should run.with_params('127.0.0.1').and_return('127.0.0.1')} 7 | it { should run.with_params('::1').and_return('[::1]')} 8 | it { should run.with_params('[2001::01]').and_return('[2001::01]')} 9 | # You're not forced to pass an array, a list of argument will do. 10 | it { should run.with_params('::1','::2').and_return(['[::1]','[::2]'])} 11 | it { should run.with_params(['::1','::2']).and_return(['[::1]','[::2]'])} 12 | it { should run.with_params(['::1','[::2]','::3']).and_return(['[::1]','[::2]','[::3]'])} 13 | it { should run.with_params(['192.168.0.1','[::2]']).and_return(['192.168.0.1','[::2]'])} 14 | it { should run.with_params(['192.168.0.1','::2']).and_return(['192.168.0.1','[::2]'])} 15 | end 16 | -------------------------------------------------------------------------------- /spec/functions/os_database_connection_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_database_connection' do 4 | 5 | it 'refuses String' do 6 | is_expected.to run.with_params('foo').\ 7 | and_raise_error(Puppet::ParseError, /Requires an hash/) 8 | end 9 | 10 | it 'refuses Array' do 11 | is_expected.to run.with_params(['foo']).\ 12 | and_raise_error(Puppet::ParseError, /Requires an hash/) 13 | end 14 | 15 | it 'refuses without at least one argument' do 16 | is_expected.to run.with_params().\ 17 | and_raise_error(Puppet::ParseError, /Wrong number of arguments/) 18 | end 19 | 20 | it 'refuses too many arguments' do 21 | is_expected.to run.with_params('foo', 'bar').\ 22 | and_raise_error(Puppet::ParseError, /Wrong number of arguments/) 23 | end 24 | 25 | it 'refuses extra params passed as String' do 26 | is_expected.to run.with_params({ 27 | 'dialect' => 'sqlite', 28 | 'database' => '/var/lib/keystone/keystone.db', 29 | 'host' => '127.0.0.1', 30 | 'port' => '3306', 31 | 'extra' => 'charset=utf-8' 32 | }).and_raise_error(Puppet::ParseError, /extra should be a Hash/) 33 | end 34 | 35 | it 'fails if port is provided with missing host' do 36 | is_expected.to run.with_params({ 37 | 'dialect' => 'sqlite', 38 | 'database' => '/var/lib/keystone/keystone.db', 39 | 'port' => '3306', 40 | 'extra' => { 'charset' => 'utf-8' } 41 | }).and_raise_error(Puppet::ParseError, /host is required with port/) 42 | end 43 | 44 | context 'creates the correct connection URI' do 45 | 46 | it 'with all parameters' do 47 | is_expected.to run.with_params({ 48 | 'dialect' => 'mysql', 49 | 'host' => '127.0.0.1', 50 | 'port' => '3306', 51 | 'database' => 'test', 52 | 'username' => 'guest', 53 | 'password' => 's3cr3t', 54 | 'extra' => { 'charset' => 'utf-8', 'read_timeout' => '60' } 55 | }).and_return('mysql://guest:s3cr3t@127.0.0.1:3306/test?charset=utf-8&read_timeout=60') 56 | end 57 | 58 | it 'with all parameters and charset set' do 59 | is_expected.to run.with_params({ 60 | 'dialect' => 'mysql', 61 | 'host' => '127.0.0.1', 62 | 'port' => '3306', 63 | 'database' => 'test', 64 | 'username' => 'guest', 65 | 'password' => 's3cr3t', 66 | 'charset' => 'utf-8', 67 | 'extra' => { 'charset' => 'latin1', 'read_timeout' => '60' } 68 | }).and_return('mysql://guest:s3cr3t@127.0.0.1:3306/test?charset=utf-8&read_timeout=60') 69 | end 70 | 71 | it 'without port' do 72 | is_expected.to run.with_params({ 73 | 'dialect' => 'mysql', 74 | 'host' => '127.0.0.1', 75 | 'database' => 'test', 76 | 'username' => 'guest', 77 | 'password' => 's3cr3t', 78 | 'extra' => { 'charset' => 'utf-8' } 79 | }).and_return('mysql://guest:s3cr3t@127.0.0.1/test?charset=utf-8') 80 | end 81 | 82 | it 'without host and port' do 83 | is_expected.to run.with_params({ 84 | 'dialect' => 'sqlite', 85 | 'database' => '/var/lib/keystone/keystone.db', 86 | 'extra' => { 'charset' => 'utf-8' } 87 | }).and_return('sqlite:////var/lib/keystone/keystone.db?charset=utf-8') 88 | end 89 | 90 | it 'without username and password' do 91 | is_expected.to run.with_params({ 92 | 'dialect' => 'mysql', 93 | 'host' => '127.0.0.1', 94 | 'port' => '3306', 95 | 'database' => 'test', 96 | 'extra' => { 'charset' => 'utf-8' } 97 | }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8') 98 | end 99 | 100 | it 'with username set to undef' do 101 | is_expected.to run.with_params({ 102 | 'dialect' => 'mysql', 103 | 'host' => '127.0.0.1', 104 | 'port' => '3306', 105 | 'database' => 'test', 106 | 'username' => :undef, 107 | 'extra' => { 'charset' => 'utf-8' } 108 | }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8') 109 | end 110 | 111 | it 'with username set to an empty string' do 112 | is_expected.to run.with_params({ 113 | 'dialect' => 'mysql', 114 | 'host' => '127.0.0.1', 115 | 'port' => '3306', 116 | 'database' => 'test', 117 | 'username' => '', 118 | 'extra' => { 'charset' => 'utf-8' } 119 | }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8') 120 | end 121 | 122 | it 'without password' do 123 | is_expected.to run.with_params({ 124 | 'dialect' => 'mysql', 125 | 'host' => '127.0.0.1', 126 | 'port' => '3306', 127 | 'database' => 'test', 128 | 'username' => 'guest', 129 | 'extra' => { 'charset' => 'utf-8' } 130 | }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8') 131 | end 132 | 133 | it 'with password set to undef' do 134 | is_expected.to run.with_params({ 135 | 'dialect' => 'mysql', 136 | 'host' => '127.0.0.1', 137 | 'port' => '3306', 138 | 'database' => 'test', 139 | 'username' => 'guest', 140 | 'password' => :undef, 141 | 'extra' => { 'charset' => 'utf-8' } 142 | }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8') 143 | end 144 | 145 | it 'with password set to an empty string' do 146 | is_expected.to run.with_params({ 147 | 'dialect' => 'mysql', 148 | 'host' => '127.0.0.1', 149 | 'port' => '3306', 150 | 'database' => 'test', 151 | 'username' => 'guest', 152 | 'password' => '', 153 | 'extra' => { 'charset' => 'utf-8' } 154 | }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8') 155 | end 156 | end 157 | end 158 | -------------------------------------------------------------------------------- /spec/functions/os_url_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_url' do 4 | 5 | it 'refuses String' do 6 | is_expected.to run.with_params('foo').\ 7 | and_raise_error(Puppet::ParseError, /Requires an hash/) 8 | end 9 | 10 | it 'refuses Array' do 11 | is_expected.to run.with_params(['foo']).\ 12 | and_raise_error(Puppet::ParseError, /Requires an hash/) 13 | end 14 | 15 | it 'refuses without at least one argument' do 16 | is_expected.to run.with_params().\ 17 | and_raise_error(Puppet::ParseError, /Wrong number of arguments/) 18 | end 19 | 20 | it 'refuses too many arguments' do 21 | is_expected.to run.with_params('foo', 'bar').\ 22 | and_raise_error(Puppet::ParseError, /Wrong number of arguments/) 23 | end 24 | 25 | it 'refuses query params passed as String' do 26 | is_expected.to run.with_params({ 27 | 'query' => 'key=value' 28 | }).and_raise_error(Puppet::ParseError, /query should be a Hash/) 29 | end 30 | 31 | it 'fails if port is provided with missing host' do 32 | is_expected.to run.with_params({ 33 | 'port' => '8080', 34 | }).and_raise_error(Puppet::ParseError, /host is required with port/) 35 | end 36 | 37 | context 'creates the correct connection URI' do 38 | 39 | it 'with all parameters' do 40 | is_expected.to run.with_params({ 41 | 'scheme' => 'https', 42 | 'host' => '127.0.0.1', 43 | 'port' => '443', 44 | 'path' => '/test', 45 | 'username' => 'guest', 46 | 'password' => 's3cr3t', 47 | 'query' => { 'key1' => 'value1', 'key2' => 'value2' } 48 | }).and_return('https://guest:s3cr3t@127.0.0.1:443/test?key1=value1&key2=value2') 49 | end 50 | 51 | it 'without port' do 52 | is_expected.to run.with_params({ 53 | 'host' => '127.0.0.1', 54 | 'path' => '/test', 55 | 'username' => 'guest', 56 | 'password' => 's3cr3t', 57 | }).and_return('http://guest:s3cr3t@127.0.0.1/test') 58 | end 59 | 60 | it 'without host and port' do 61 | is_expected.to run.with_params({ 62 | 'scheme' => 'file', 63 | 'path' => '/test', 64 | }).and_return('file:///test') 65 | end 66 | 67 | it 'without username and password' do 68 | is_expected.to run.with_params({ 69 | 'host' => '127.0.0.1', 70 | }).and_return('http://127.0.0.1') 71 | end 72 | 73 | it 'with username set to undef' do 74 | is_expected.to run.with_params({ 75 | 'host' => '127.0.0.1', 76 | 'username' => :undef, 77 | }).and_return('http://127.0.0.1') 78 | end 79 | 80 | it 'with username set to an empty string' do 81 | is_expected.to run.with_params({ 82 | 'host' => '127.0.0.1', 83 | 'username' => '', 84 | }).and_return('http://127.0.0.1') 85 | end 86 | 87 | it 'without password' do 88 | is_expected.to run.with_params({ 89 | 'host' => '127.0.0.1', 90 | 'username' => 'guest', 91 | }).and_return('http://guest@127.0.0.1') 92 | end 93 | 94 | it 'with password' do 95 | is_expected.to run.with_params({ 96 | 'host' => '127.0.0.1', 97 | 'password' => 's3cr3t', 98 | }).and_return('http://:s3cr3t@127.0.0.1') 99 | end 100 | 101 | it 'with password set to undef' do 102 | is_expected.to run.with_params({ 103 | 'host' => '127.0.0.1', 104 | 'username' => 'guest', 105 | 'password' => :undef, 106 | }).and_return('http://guest@127.0.0.1') 107 | end 108 | 109 | it 'with password set to an empty string' do 110 | is_expected.to run.with_params({ 111 | 'host' => '127.0.0.1', 112 | 'username' => 'guest', 113 | 'password' => '', 114 | }).and_return('http://guest@127.0.0.1') 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /spec/shared_examples.rb: -------------------------------------------------------------------------------- 1 | shared_examples_for "a Puppet::Error" do |description| 2 | it "with message matching #{description.inspect}" do 3 | expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Load libraries here to simulate how they live together in a real puppet run (for provider unit tests) 2 | $LOAD_PATH.push(File.join(File.dirname(__FILE__), 'fixtures', 'modules', 'inifile', 'lib')) 3 | 4 | require 'puppetlabs_spec_helper/module_spec_helper' 5 | require 'shared_examples' 6 | require 'puppet-openstack_spec_helper/facts' 7 | 8 | fixture_path = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures')) 9 | 10 | RSpec.configure do |c| 11 | c.alias_it_should_behave_like_to :it_configures, 'configures' 12 | c.alias_it_should_behave_like_to :it_raises, 'raises' 13 | 14 | c.module_path = File.join(fixture_path, 'modules') 15 | end 16 | 17 | at_exit { RSpec::Puppet::Coverage.report! } 18 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | require 'puppet-openstack_spec_helper/litmus_spec_helper' 2 | -------------------------------------------------------------------------------- /spec/type_aliases/policies_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Openstacklib::Policies' do 4 | describe 'valid types' do 5 | context 'with valid types' do 6 | [ 7 | {}, 8 | {'name' => {'key' => 'mykey', 'value' => 'myvalue'}}, 9 | {'name' => {'value' => 'myvalue'}}, 10 | ].each do |value| 11 | describe value.inspect do 12 | it { is_expected.to allow_value(value) } 13 | end 14 | end 15 | end 16 | end 17 | 18 | describe 'invalid types' do 19 | context 'with garbage inputs' do 20 | [ 21 | {'name' => {}}, 22 | {'name' => {'key' => 'mykey'}}, 23 | {'name' => {'key' => 1, 'value' => 'myvalue'}}, 24 | {'name' => {'key' => 'mykey', 'value' => 1}}, 25 | {'name' => {'key' => 'mykey', 'value' => 'myvalue', 'foo' => 'bar'}}, 26 | {'name' => {'value' => 'myvalue', 'foo' => 'bar'}}, 27 | {0 => {'key' => 1, 'value' => 'myvalue'}}, 28 | ].each do |value| 29 | describe value.inspect do 30 | it { is_expected.not_to allow_value(value) } 31 | end 32 | end 33 | end 34 | end 35 | end 36 | 37 | -------------------------------------------------------------------------------- /spec/type_aliases/servicedefault_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'Openstacklib::ServiceDefault' do 4 | describe 'valid types' do 5 | context 'with valid types' do 6 | [ 7 | '', 8 | ].each do |value| 9 | describe value.inspect do 10 | it { is_expected.to allow_value(value) } 11 | end 12 | end 13 | end 14 | end 15 | 16 | describe 'invalid types' do 17 | context 'with garbage inputs' do 18 | [ 19 | 'somethink', 20 | true, 21 | nil, 22 | {}, 23 | '', 24 | 55555, 25 | ].each do |value| 26 | describe value.inspect do 27 | it { is_expected.not_to allow_value(value) } 28 | end 29 | end 30 | end 31 | end 32 | end 33 | 34 | -------------------------------------------------------------------------------- /spec/unit/facter/os_workers_heat_engine_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_workers_heat_engine' do 4 | 5 | before { Facter.clear } 6 | 7 | context 'with processorcount=1' do 8 | before do 9 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 1}) 10 | end 11 | 12 | it 'returns a minimum of 2' do 13 | expect(Facter.fact(:os_workers_heat_engine).value).to eq(4) 14 | end 15 | end 16 | 17 | context 'with processorcount=8' do 18 | before do 19 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 8}) 20 | end 21 | 22 | it 'returns processorcount/2' do 23 | expect(Facter.fact(:os_workers_heat_engine).value).to eq(4) 24 | end 25 | end 26 | 27 | context 'with processorcount=64' do 28 | before do 29 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 64}) 30 | end 31 | 32 | it 'returns a maximum of 24' do 33 | expect(Facter.fact(:os_workers_heat_engine).value).to eq(24) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/unit/facter/os_workers_keystone_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_workers_keystone' do 4 | 5 | before { Facter.clear } 6 | 7 | context 'with processorcount=1' do 8 | before do 9 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 1}) 10 | end 11 | 12 | it 'returns a minimum of 4' do 13 | expect(Facter.fact(:os_workers_keystone).value).to eq(4) 14 | end 15 | end 16 | 17 | context 'with processorcount=8' do 18 | before do 19 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 8}) 20 | end 21 | 22 | it 'returns processorcount' do 23 | expect(Facter.fact(:os_workers_keystone).value).to eq(8) 24 | end 25 | end 26 | 27 | context 'with processorcount=32' do 28 | before do 29 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 32}) 30 | end 31 | 32 | it 'returns a maximum of 24' do 33 | expect(Facter.fact(:os_workers_keystone).value).to eq(24) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/unit/facter/os_workers_large_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_workers_large' do 4 | 5 | before { Facter.clear } 6 | 7 | context 'with processorcount=1' do 8 | before do 9 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 1}) 10 | end 11 | 12 | it 'returns a minimum of 1' do 13 | expect(Facter.fact(:os_workers_large).value).to eq(1) 14 | end 15 | end 16 | 17 | context 'with processorcount=8' do 18 | before do 19 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 8}) 20 | end 21 | 22 | it 'returns processorcount/2' do 23 | expect(Facter.fact(:os_workers_large).value).to eq(4) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/facter/os_workers_small_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_workers_small' do 4 | 5 | before { Facter.clear } 6 | 7 | context 'with processorcount=1' do 8 | before do 9 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 1}) 10 | end 11 | 12 | it 'returns a minimum of 2' do 13 | expect(Facter.fact(:os_workers_small).value).to eq(2) 14 | end 15 | end 16 | 17 | context 'with processorcount=16' do 18 | before do 19 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 16}) 20 | end 21 | 22 | it 'returns processorcount/4' do 23 | expect(Facter.fact(:os_workers_small).value).to eq(4) 24 | end 25 | end 26 | 27 | context 'with processorcount=32' do 28 | before do 29 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 32}) 30 | end 31 | 32 | it 'returns a maximum of 8' do 33 | expect(Facter.fact(:os_workers_small).value).to eq(8) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/unit/facter/os_workers_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'os_workers' do 4 | 5 | before { Facter.clear } 6 | 7 | context 'with processorcount=1' do 8 | before do 9 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 1}) 10 | end 11 | 12 | it 'returns a minimum of 2' do 13 | expect(Facter.fact(:os_workers).value).to eq(2) 14 | end 15 | end 16 | 17 | context 'with processorcount=8' do 18 | before do 19 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 8}) 20 | end 21 | 22 | it 'returns processorcount/2' do 23 | expect(Facter.fact(:os_workers).value).to eq(4) 24 | end 25 | end 26 | 27 | context 'with processorcount=32' do 28 | before do 29 | allow(Facter.fact(:processors)).to receive(:value).and_return({'count' => 32}) 30 | end 31 | 32 | it 'returns a maximum of 12' do 33 | expect(Facter.fact(:os_workers).value).to eq(12) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/unit/provider/openstack/credentials_spec.rb: -------------------------------------------------------------------------------- 1 | require 'puppet' 2 | require 'spec_helper' 3 | require 'puppet/provider/openstack' 4 | require 'puppet/provider/openstack/credentials' 5 | 6 | 7 | describe Puppet::Provider::Openstack::Credentials do 8 | 9 | let(:creds) do 10 | creds = Puppet::Provider::Openstack::CredentialsV3.new 11 | end 12 | 13 | describe "#set with valid value" do 14 | it 'works with valid value' do 15 | expect(creds.class.defined?('auth_url')).to be_truthy 16 | creds.set('auth_url', 'http://localhost:5000/v2.0') 17 | expect(creds.auth_url).to eq('http://localhost:5000/v2.0') 18 | end 19 | end 20 | 21 | describe "#set with invalid value" do 22 | it 'works with invalid value' do 23 | expect(creds.class.defined?('foo')).to be_falsey 24 | creds.set('foo', 'junk') 25 | expect(creds.respond_to?(:foo)).to be_falsey 26 | expect(creds.instance_variable_defined?(:@foo)).to be_falsey 27 | expect { creds.foo }.to raise_error(NoMethodError, /undefined method/) 28 | end 29 | end 30 | 31 | describe '#service_token_set?' do 32 | context "with service credentials" do 33 | it 'is successful' do 34 | creds.token = 'token' 35 | creds.endpoint = 'endpoint' 36 | expect(creds.service_token_set?).to be_truthy 37 | expect(creds.user_password_set?).to be_falsey 38 | end 39 | 40 | it 'fails' do 41 | creds.token = 'token' 42 | expect(creds.service_token_set?).to be_falsey 43 | expect(creds.user_password_set?).to be_falsey 44 | end 45 | end 46 | end 47 | 48 | describe '#password_set?' do 49 | context "with user credentials" do 50 | it 'is successful with project scope credential' do 51 | creds.auth_url = 'auth_url' 52 | creds.password = 'password' 53 | creds.project_name = 'project_name' 54 | creds.username = 'username' 55 | expect(creds.user_password_set?).to be_truthy 56 | expect(creds.service_token_set?).to be_falsey 57 | end 58 | 59 | it 'is successful with project scope credential' do 60 | creds.auth_url = 'auth_url' 61 | creds.password = 'password' 62 | creds.domain_name = 'domain_name' 63 | creds.username = 'username' 64 | expect(creds.user_password_set?).to be_truthy 65 | expect(creds.service_token_set?).to be_falsey 66 | end 67 | 68 | it 'is successful with system scope credential' do 69 | creds.auth_url = 'auth_url' 70 | creds.password = 'password' 71 | creds.system_scope = 'all' 72 | creds.username = 'username' 73 | expect(creds.user_password_set?).to be_truthy 74 | expect(creds.service_token_set?).to be_falsey 75 | end 76 | 77 | it 'is successful with cloud' do 78 | creds.cloud = 'openstack' 79 | expect(creds.user_password_set?).to be_truthy 80 | expect(creds.service_token_set?).to be_falsey 81 | end 82 | 83 | it 'fails' do 84 | creds.auth_url = 'auth_url' 85 | creds.password = 'password' 86 | creds.project_name = 'project_name' 87 | expect(creds.user_password_set?).to be_falsey 88 | expect(creds.service_token_set?).to be_falsey 89 | end 90 | end 91 | end 92 | 93 | describe '#set?' do 94 | context "without any credential" do 95 | it 'fails' do 96 | expect(creds.set?).to be_falsey 97 | end 98 | end 99 | end 100 | 101 | describe '#version' do 102 | it 'is version 3' do 103 | expect(creds.version).to eq('3') 104 | end 105 | end 106 | 107 | describe '#unset' do 108 | context "with all instance variables set" do 109 | it 'resets all but the identity_api_version' do 110 | creds.auth_url = 'auth_url' 111 | creds.password = 'password' 112 | creds.project_name = 'project_name' 113 | creds.domain_name = 'domain_name' 114 | creds.system_scope = 'system_scope' 115 | creds.username = 'username' 116 | creds.token = 'token' 117 | creds.endpoint = 'endpoint' 118 | creds.region_name = 'region_name' 119 | creds.identity_api_version = 'identity_api_version' 120 | creds.cloud = 'openstack' 121 | creds.client_config_file = '/etc/openstack/clouds.yaml' 122 | creds.unset 123 | expect(creds.auth_url).to eq(nil) 124 | expect(creds.password).to eq(nil) 125 | expect(creds.project_name).to eq(nil) 126 | expect(creds.domain_name).to eq(nil) 127 | expect(creds.system_scope).to eq(nil) 128 | expect(creds.username).to eq(nil) 129 | expect(creds.token).to eq(nil) 130 | expect(creds.endpoint).to eq(nil) 131 | expect(creds.region_name).to eq(nil) 132 | expect(creds.identity_api_version).to eq('identity_api_version') 133 | expect(creds.cloud).to eq(nil) 134 | expect(creds.client_config_file).to eq(nil) 135 | newcreds = Puppet::Provider::Openstack::CredentialsV3.new 136 | expect(newcreds.identity_api_version).to eq('3') 137 | end 138 | end 139 | end 140 | 141 | describe '#to_env' do 142 | context "with an exhaustive data set" do 143 | it 'successfully returns content' do 144 | creds.auth_url = 'auth_url' 145 | creds.password = 'password' 146 | creds.project_name = 'project_name' 147 | creds.domain_name = 'domain_name' 148 | creds.system_scope = 'all' 149 | creds.username = 'username' 150 | creds.token = 'token' 151 | creds.endpoint = 'endpoint' 152 | creds.region_name = 'Region1' 153 | creds.identity_api_version = 'identity_api_version' 154 | creds.cloud = 'openstack' 155 | creds.client_config_file = '/etc/openstack/clouds.yaml' 156 | expect(creds.to_env).to eq({ 157 | 'OS_USERNAME' => 'username', 158 | 'OS_PASSWORD' => 'password', 159 | 'OS_PROJECT_NAME' => 'project_name', 160 | 'OS_DOMAIN_NAME' => 'domain_name', 161 | 'OS_SYSTEM_SCOPE' => 'all', 162 | 'OS_AUTH_URL' => 'auth_url', 163 | 'OS_TOKEN' => 'token', 164 | 'OS_ENDPOINT' => 'endpoint', 165 | 'OS_REGION_NAME' => 'Region1', 166 | 'OS_IDENTITY_API_VERSION' => 'identity_api_version', 167 | 'OS_CLOUD' => 'openstack', 168 | 'OS_CLIENT_CONFIG_FILE' => '/etc/openstack/clouds.yaml', 169 | }) 170 | end 171 | end 172 | end 173 | 174 | describe 'using v3' do 175 | let(:creds) do 176 | creds = Puppet::Provider::Openstack::CredentialsV3.new 177 | end 178 | describe 'with v3' do 179 | it 'uses v3 identity api' do 180 | creds.identity_api_version == '3' 181 | end 182 | end 183 | describe '#password_set? with username and project_name' do 184 | it 'is successful' do 185 | creds.auth_url = 'auth_url' 186 | creds.password = 'password' 187 | creds.project_name = 'project_name' 188 | creds.username = 'username' 189 | expect(creds.user_password_set?).to be_truthy 190 | expect(creds.scope).to eq('project') 191 | end 192 | end 193 | describe '#password_set? with username and domain_name' do 194 | it 'is successful' do 195 | creds.auth_url = 'auth_url' 196 | creds.password = 'password' 197 | creds.domain_name = 'domain_name' 198 | creds.username = 'username' 199 | expect(creds.user_password_set?).to be_truthy 200 | expect(creds.scope).to eq('domain') 201 | end 202 | end 203 | describe '#password_set? with username and system_scope' do 204 | it 'is successful' do 205 | creds.auth_url = 'auth_url' 206 | creds.password = 'password' 207 | creds.system_scope = 'all' 208 | creds.username = 'username' 209 | expect(creds.user_password_set?).to be_truthy 210 | expect(creds.scope).to eq('system') 211 | end 212 | end 213 | describe '#password_set? with cloud' do 214 | it 'is successful' do 215 | creds.cloud = 'openstack' 216 | expect(creds.user_password_set?).to be_truthy 217 | expect(creds.scope).to eq(nil) 218 | end 219 | end 220 | describe '#password_set? with user_id and project_id' do 221 | it 'is successful' do 222 | creds.auth_url = 'auth_url' 223 | creds.password = 'password' 224 | creds.project_id = 'projid' 225 | creds.user_id = 'userid' 226 | expect(creds.user_password_set?).to be_truthy 227 | expect(creds.scope).to eq('project') 228 | end 229 | end 230 | describe '#password_set? with user_id and domain_id' do 231 | it 'is successful' do 232 | creds.auth_url = 'auth_url' 233 | creds.password = 'password' 234 | creds.domain_id = 'domid' 235 | creds.user_id = 'userid' 236 | expect(creds.user_password_set?).to be_truthy 237 | expect(creds.scope).to eq('domain') 238 | end 239 | end 240 | end 241 | end 242 | -------------------------------------------------------------------------------- /spec/unit/provider/openstack_config/ini_setting_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | provider_class = Puppet::Type.type(:openstack_config).provider(:ini_setting) 3 | describe provider_class do 4 | 5 | let(:properties) do 6 | { 7 | :name => 'DEFAULT/foo', 8 | :value => 'bar', 9 | :ensure_absent_val => 'some_value', 10 | :ensure => :present, 11 | } 12 | end 13 | 14 | let(:transform_properties) do 15 | { 16 | :name => 'DEFAULT/foo', 17 | :value => 'bar', 18 | :transform_to => 'upper', 19 | :ensure_absent_val => 'some_value', 20 | :ensure => :present, 21 | } 22 | end 23 | 24 | let(:immutable_properties) do 25 | { 26 | :name => 'DEFAULT/foo', 27 | :value => '<_IMMUTABLE_>', 28 | :ensure => :present, 29 | } 30 | end 31 | 32 | let(:type) do 33 | Puppet::Type.newtype(:test_config) do 34 | newparam(:name, :namevar => true) 35 | newparam(:ensure) 36 | newproperty(:value) 37 | newparam(:ensure_absent_val) 38 | end 39 | end 40 | 41 | let(:transform_type) do 42 | Puppet::Type.newtype(:test_config) do 43 | newparam(:name, :namevar => true) 44 | newparam(:ensure) 45 | newproperty(:value) 46 | newparam(:ensure_absent_val) 47 | newparam(:transform_to) 48 | end 49 | end 50 | 51 | let(:immutable_type) do 52 | Puppet::Type.newtype(:test_config) do 53 | newparam(:name, :namevar => true) 54 | newparam(:ensure) 55 | newproperty(:value) 56 | newparam(:ensure_absent_val) 57 | end 58 | end 59 | 60 | let(:resource) do 61 | resource = type.new(properties) 62 | resource 63 | end 64 | 65 | let(:transform_resource) do 66 | resource = transform_type.new(transform_properties) 67 | resource 68 | end 69 | 70 | let(:immutable_resource) do 71 | resource = immutable_type.new(immutable_properties) 72 | resource 73 | end 74 | 75 | context '#exists?' do 76 | it 'ensure to present' do 77 | child_conf = Class.new(provider_class) do 78 | def self.file_path 79 | '/some/file/path' 80 | end 81 | end 82 | provider = child_conf.new(resource) 83 | provider.exists? 84 | expect(resource[:ensure]).to eq :present 85 | end 86 | 87 | it 'ensure to absent' do 88 | child_conf = Class.new(provider_class) do 89 | def self.file_path 90 | '/some/file/path' 91 | end 92 | end 93 | provider = child_conf.new(resource) 94 | resource[:ensure_absent_val] = 'bar' 95 | provider.exists? 96 | expect(resource[:ensure]).to eq :absent 97 | end 98 | end 99 | 100 | context 'transform_to' do 101 | it 'transforms a property' do 102 | child_conf = Class.new(provider_class) do 103 | def self.file_path 104 | '/some/file/path' 105 | end 106 | 107 | def to_upper(value) 108 | value.upcase! 109 | end 110 | end 111 | provider = child_conf.new(transform_resource) 112 | provider.exists? 113 | provider.transform(:to, transform_resource[:value]) 114 | expect(transform_resource[:value]).to eq 'BAR' 115 | end 116 | 117 | context 'immutable' do 118 | # could not set fact using the classic let(:facts) idiom. 119 | it 'ensure to no change when value set' do 120 | child_conf = Class.new(provider_class) do 121 | def self.file_path 122 | '/some/file/path' 123 | end 124 | # current value 125 | def value 126 | 'foo' 127 | end 128 | end 129 | provider = child_conf.new(immutable_resource) 130 | provider.exists? 131 | expect(immutable_resource[:value]).to eq 'foo' 132 | expect(immutable_resource[:ensure]).to eq :present 133 | end 134 | 135 | it 'ensure to no change when value unset' do 136 | child_conf = Class.new(provider_class) do 137 | def self.file_path 138 | '/some/file/path' 139 | end 140 | # current value 141 | def value 142 | [nil] 143 | end 144 | end 145 | provider = child_conf.new(immutable_resource) 146 | 147 | provider.exists? 148 | expect(immutable_resource[:value]).to eq nil 149 | expect(immutable_resource[:ensure]).to eq :absent 150 | end 151 | end 152 | 153 | end 154 | 155 | end 156 | -------------------------------------------------------------------------------- /spec/unit/provider/policy_rcd/policy_rcd_spec.rb: -------------------------------------------------------------------------------- 1 | require 'puppet' 2 | require 'spec_helper' 3 | require 'puppet/provider/policy_rcd/policy_rcd' 4 | require 'tempfile' 5 | 6 | provider_class = Puppet::Type.type(:policy_rcd).provider(:policy_rcd) 7 | 8 | describe provider_class do 9 | let(:attributes) do { 10 | :name => 'service', 11 | :set_code => '101' 12 | } 13 | end 14 | 15 | let(:resource) do 16 | Puppet::Type::Policy_rcd.new(attributes) 17 | end 18 | 19 | let(:provider) do 20 | resource.provider 21 | end 22 | 23 | let(:header) do 24 | "#!/bin/bash\n# THIS FILE MANAGED BY PUPPET\n" 25 | end 26 | 27 | describe 'managing policy' do 28 | describe '#create' do 29 | it 'creates a policy when policy-rc.d doesnt exist' do 30 | file = double('file') 31 | allow(provider).to receive(:policy_rcd).and_return(file) 32 | expect(File).to receive(:exist?).with(file).and_return(false) 33 | content = "#{header}[[ \"$1\" == \"service\" ]] && exit 101\n" 34 | expect(provider.class).to receive(:write_to_file).with(file, content) 35 | provider.create 36 | end 37 | 38 | it 'creates a policy when policy-rc.d exists' do 39 | file = double('file') 40 | allow(provider).to receive(:policy_rcd).and_return(file) 41 | expect(File).to receive(:exist?).with(file).and_return(true) 42 | content = "[[ \"$1\" == \"service\" ]] && exit 101\n" 43 | expect(provider.class).to receive(:write_to_file).with(file, content) 44 | provider.create 45 | end 46 | end 47 | 48 | describe '#destroy' do 49 | it 'destroy a policy' do 50 | file = double('file') 51 | file_content = "#{header}[[ \"$1\" == \"service\" ]] && exit 101\n" 52 | allow(provider).to receive(:policy_rcd).and_return(file) 53 | expect(File).to receive(:exist?).with(file).and_return(true) 54 | allow(provider).to receive(:file_lines).and_return(file_content.split("\n")) 55 | expect(provider.class).to receive(:write_to_file).with(file, ['#!/bin/bash', '# THIS FILE MANAGED BY PUPPET'], true) 56 | provider.destroy 57 | end 58 | end 59 | 60 | describe '#flush' do 61 | it 'update a policy' do 62 | file = double('file') 63 | allow(provider).to receive(:policy_rcd).and_return(file) 64 | file_content = "#{header}[[ \"$1\" == \"service\" ]] && exit 102\n" 65 | allow(provider).to receive(:file_lines).and_return(file_content.split("\n")) 66 | expect(provider.class).to receive(:write_to_file).with(file, ['#!/bin/bash', "# THIS FILE MANAGED BY PUPPET", "[[ \"$1\" == \"service\" ]] && exit 101\n"], true) 67 | provider.flush 68 | end 69 | 70 | it 'dont update a policy' do 71 | file = double('file') 72 | file_content = "#{header}[[ \"$1\" == \"service\" ]] && exit 101\n" 73 | allow(provider).to receive(:policy_rcd).and_return(file) 74 | allow(provider).to receive(:file_lines).and_return(file_content.split("\n")) 75 | provider.flush 76 | end 77 | end 78 | 79 | describe '#exists?' do 80 | it 'should exists on Debian family' do 81 | allow(provider).to receive(:check_os).and_return(true) 82 | file = double('file') 83 | file_content = "#{header}[[ \"$1\" == \"service\" ]] && exit 101\n" 84 | allow(provider).to receive(:policy_rcd).and_return(file) 85 | allow(provider).to receive(:check_policy_rcd).and_return(true) 86 | allow(provider).to receive(:file_lines).and_return(file_content.split("\n")) 87 | expect(provider.exists?).to be_truthy 88 | end 89 | 90 | it 'should not exists on Debian family when file is present' do 91 | allow(provider).to receive(:check_os).and_return(true) 92 | file = double('file') 93 | file_content = "#{header}[[ \"$1\" == \"new-service\" ]] && exit 101\n" 94 | allow(provider).to receive(:policy_rcd).and_return(file) 95 | allow(provider).to receive(:check_policy_rcd).and_return(true) 96 | allow(provider).to receive(:file_lines).and_return(file_content.split("\n")) 97 | expect(provider.exists?).to be_falsey 98 | end 99 | 100 | it 'should not exists on Debian family when file is not present' do 101 | allow(provider).to receive(:check_os).and_return(true) 102 | allow(provider).to receive(:check_policy_rcd).and_return(false) 103 | expect(provider.exists?).to be_falsey 104 | end 105 | 106 | it 'should exists on non-Debian family' do 107 | allow(provider).to receive(:check_os).and_return(false) 108 | expect(provider.exists?).to be_truthy 109 | end 110 | end 111 | 112 | describe 'write_to_file' do 113 | it 'should write to file' do 114 | file = double 115 | policy = double 116 | content = 'some_content' 117 | expect(File).to receive(:open).with(file, 'a+').and_return(policy) 118 | expect(policy).to receive(:puts).with(content) 119 | expect(policy).to receive(:close) 120 | expect(File).to receive(:chmod).with(0744, file) 121 | provider.class.write_to_file(file, content) 122 | end 123 | 124 | it 'should truncate file' do 125 | file = double 126 | policy = double 127 | content = 'some_content' 128 | expect(File).to receive(:truncate).with(file, 0) 129 | expect(File).to receive(:open).with(file, 'a+').and_return(policy) 130 | expect(policy).to receive(:puts).with(content) 131 | expect(policy).to receive(:close) 132 | expect(File).to receive(:chmod).with(0744, file) 133 | provider.class.write_to_file(file, content, true) 134 | end 135 | end 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /spec/unit/type/policy_rcd_spec.rb: -------------------------------------------------------------------------------- 1 | require 'puppet' 2 | require 'puppet/type/policy_rcd' 3 | 4 | describe Puppet::Type.type(:policy_rcd) do 5 | 6 | before :each do 7 | Puppet::Type.rmtype(:policy_rcd) 8 | end 9 | 10 | it 'should fail with wrong status code' do 11 | incorrect_input = { 12 | :name => 'test_type', 13 | :set_code => '356' 14 | } 15 | expect { Puppet::Type.type(:policy_rcd).new(incorrect_input) }.to raise_error(Puppet::ResourceError, /Unknown exit status code is set/) 16 | end 17 | 18 | it 'should be compiled withour errors' do 19 | correct_input = { 20 | :name => 'test_type', 21 | :set_code => '0' 22 | } 23 | expect { Puppet::Type.type(:policy_rcd).new(correct_input) }.to_not raise_error 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /templates/clouds.yaml.erb: -------------------------------------------------------------------------------- 1 | clouds: 2 | <% if @project_name -%> 3 | project: 4 | auth: 5 | auth_url: <%= @auth_url %> 6 | password: <%= @password %> 7 | username: <%= @username %> 8 | user_domain_name: <%= @user_domain_name %> 9 | project_name: <%= @project_name %> 10 | project_domain_name: <%= @project_domain_name %> 11 | <%- @api_versions.sort.each do |opt_name,opt_val| -%> 12 | <%= opt_name %>_api_version: <%= opt_val %> 13 | <%- end -%> 14 | <%- if !(@interface.nil?) -%> 15 | interface: <%= @interface %> 16 | <%- end -%> 17 | <%- if !(@region_name.nil?) -%> 18 | region_name: <%= @region_name %> 19 | <%- end -%> 20 | <% end -%> 21 | <% if @system_scope -%> 22 | system: 23 | auth: 24 | auth_url: <%= @auth_url %> 25 | password: <%= @password %> 26 | username: <%= @username %> 27 | user_domain_name: <%= @user_domain_name %> 28 | system_scope: <%= @system_scope %> 29 | <%- @api_versions.sort.each do |opt_name,opt_val| -%> 30 | <%= opt_name %>_api_version: <%= opt_val %> 31 | <%- end -%> 32 | <%- if !(@interface.nil?) -%> 33 | interface: <%= @interface %> 34 | <%- end -%> 35 | <%- if !(@region_name.nil?) -%> 36 | region_name: <%= @region_name %> 37 | <%- end -%> 38 | <% end -%> 39 | -------------------------------------------------------------------------------- /templates/policy-rc.d.erb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | <% @services.each do |service| %> 3 | if [ "$1" == "<%= service %>" ] 4 | then 5 | exit 101 6 | fi 7 | <% end %> 8 | exit 0 9 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 3.1 3 | skipsdist = True 4 | envlist = releasenotes 5 | ignore_basepython_conflict = True 6 | 7 | [testenv] 8 | basepython = python3 9 | 10 | [testenv:releasenotes] 11 | deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} 12 | -r{toxinidir}/doc/requirements.txt 13 | commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html 14 | -------------------------------------------------------------------------------- /types/policies.pp: -------------------------------------------------------------------------------- 1 | type Openstacklib::Policies = Hash[ 2 | String[1], Struct[ 3 | { 4 | key => Optional[String[1]], 5 | value => String[1], 6 | } 7 | ] 8 | ] 9 | -------------------------------------------------------------------------------- /types/servicedefault.pp: -------------------------------------------------------------------------------- 1 | type Openstacklib::ServiceDefault = Enum[''] 2 | --------------------------------------------------------------------------------