diff --git a/.fixtures.yml b/.fixtures.yml index b784c9b..93ec5df 100644 --- a/.fixtures.yml +++ b/.fixtures.yml @@ -6,3 +6,4 @@ fixtures: stdlib: "puppetlabs/stdlib" concat: "puppetlabs/concat" selinux_core: "puppetlabs/selinux_core" + iniifile: "puppetlabs/inifile" diff --git a/.github/workflows/run-pdk-tests-on-puppet-7.yml b/.github/workflows/run-pdk-tests-on-puppet-7.yml new file mode 100644 index 0000000..1b13f18 --- /dev/null +++ b/.github/workflows/run-pdk-tests-on-puppet-7.yml @@ -0,0 +1,34 @@ +name: Run PDK tests on Puppet 7.x + +on: + - push + - pull_request + +jobs: + validate-7: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Run pdk validate + uses: puppets-epic-show-theatre/action-pdk-validate@v1 + with: + puppet-version: "7" + # [optional] A string indicating the Puppet version to validate against, such as "5.4.2" or "5.5". + # pe-version: "" + # [optional] A string indicating the PE version to validate against, such as "2017.3.5" or "2018.1". + + test-7: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Run unit tests + uses: puppets-epic-show-theatre/action-pdk-test-unit@v1 + with: + puppet-version: "7" + # [optional] A string indicating the Puppet version to validate against, such as "5.4.2" or "5.5". + # pe-version: "" + # [optional] A string indicating the PE version to validate against, such as "2017.3.5" or "2018.1". diff --git a/.github/workflows/run-pdk-tests-on-puppet-8.yml b/.github/workflows/run-pdk-tests-on-puppet-8.yml new file mode 100644 index 0000000..12460e0 --- /dev/null +++ b/.github/workflows/run-pdk-tests-on-puppet-8.yml @@ -0,0 +1,34 @@ +name: Run PDK tests on Puppet 8.x + +on: + - push + - pull_request + +jobs: + validate-8: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Run pdk validate + uses: puppets-epic-show-theatre/action-pdk-validate@v1 + with: + puppet-version: "8" + # [optional] A string indicating the Puppet version to validate against, such as "5.4.2" or "5.5". + # pe-version: "" + # [optional] A string indicating the PE version to validate against, such as "2017.3.5" or "2018.1". + + test-8: + runs-on: ubuntu-latest + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Run unit tests + uses: puppets-epic-show-theatre/action-pdk-test-unit@v1 + with: + puppet-version: "8" + # [optional] A string indicating the Puppet version to validate against, such as "5.4.2" or "5.5". + # pe-version: "" + # [optional] A string indicating the PE version to validate against, such as "2017.3.5" or "2018.1". diff --git a/.gitignore b/.gitignore index 2767022..3f15512 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ /log/ /pkg/ /spec/fixtures/manifests/ -/spec/fixtures/modules/ +/spec/fixtures/modules/* /tmp/ /vendor/ /convert_report.txt @@ -25,3 +25,4 @@ .project .envrc /inventory.yaml +/spec/fixtures/litmus_inventory.yaml diff --git a/.pdkignore b/.pdkignore index a74c4c4..584438f 100644 --- a/.pdkignore +++ b/.pdkignore @@ -16,7 +16,7 @@ /log/ /pkg/ /spec/fixtures/manifests/ -/spec/fixtures/modules/ +/spec/fixtures/modules/* /tmp/ /vendor/ /convert_report.txt @@ -25,19 +25,17 @@ .project .envrc /inventory.yaml -/appveyor.yml +/spec/fixtures/litmus_inventory.yaml /.fixtures.yml /Gemfile /.gitattributes /.gitignore -/.gitlab-ci.yml /.pdkignore /.puppet-lint.rc /Rakefile /rakelib/ /.rspec -/.rubocop.yml -/.travis.yml +/..yml /.yardopts /spec/ /.vscode/ diff --git a/.rubocop.yml b/.rubocop.yml index 8f782e7..5be1f9f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,7 +4,7 @@ require: - rubocop-rspec AllCops: DisplayCopNames: true - TargetRubyVersion: '2.4' + TargetRubyVersion: '2.6' Include: - "**/*.rb" Exclude: @@ -111,8 +111,14 @@ Style/MethodCalledOnDoEndBlock: Enabled: true Style/StringMethods: Enabled: true +Bundler/GemFilename: + Enabled: false Bundler/InsecureProtocolSource: Enabled: false +Capybara/CurrentPathExpectation: + Enabled: false +Capybara/VisibilityMatcher: + Enabled: false Gemspec/DuplicatedAssignment: Enabled: false Gemspec/OrderedDependencies: @@ -287,11 +293,9 @@ Performance/UriDefaultParser: Enabled: false RSpec/Be: Enabled: false -RSpec/Capybara/CurrentPathExpectation: - Enabled: false RSpec/Capybara/FeatureMethods: Enabled: false -RSpec/Capybara/VisibilityMatcher: +RSpec/ContainExactly: Enabled: false RSpec/ContextMethod: Enabled: false @@ -331,6 +335,8 @@ RSpec/LeakyConstantDeclaration: Enabled: false RSpec/LetBeforeExamples: Enabled: false +RSpec/MatchArray: + Enabled: false RSpec/MissingExampleGroupArgument: Enabled: false RSpec/MultipleExpectations: @@ -373,8 +379,6 @@ Style/AccessModifierDeclarations: Enabled: false Style/AccessorGrouping: Enabled: false -Style/AsciiComments: - Enabled: false Style/BisectedAttrAccessor: Enabled: false Style/CaseLikeIf: @@ -485,35 +489,235 @@ Style/TrailingMethodEndStatement: Enabled: false Style/UnpackFirst: Enabled: false +Capybara/MatchStyle: + Enabled: false +Capybara/NegationMatcher: + Enabled: false +Capybara/SpecificActions: + Enabled: false +Capybara/SpecificFinders: + Enabled: false +Capybara/SpecificMatcher: + Enabled: false +Gemspec/DeprecatedAttributeAssignment: + Enabled: false +Gemspec/DevelopmentDependencies: + Enabled: false +Gemspec/RequireMFA: + Enabled: false +Layout/LineContinuationLeadingSpace: + Enabled: false +Layout/LineContinuationSpacing: + Enabled: false +Layout/LineEndStringConcatenationIndentation: + Enabled: false +Layout/SpaceBeforeBrackets: + Enabled: false +Lint/AmbiguousAssignment: + Enabled: false +Lint/AmbiguousOperatorPrecedence: + Enabled: false +Lint/AmbiguousRange: + Enabled: false +Lint/ConstantOverwrittenInRescue: + Enabled: false +Lint/DeprecatedConstants: + Enabled: false Lint/DuplicateBranch: Enabled: false +Lint/DuplicateMagicComment: + Enabled: false Lint/DuplicateRegexpCharacterClassElement: Enabled: false Lint/EmptyBlock: Enabled: false Lint/EmptyClass: Enabled: false +Lint/EmptyInPattern: + Enabled: false +Lint/IncompatibleIoSelectWithFiberScheduler: + Enabled: false +Lint/LambdaWithoutLiteralBlock: + Enabled: false Lint/NoReturnInBeginEndBlocks: Enabled: false +Lint/NonAtomicFileOperation: + Enabled: false +Lint/NumberedParameterAssignment: + Enabled: false +Lint/OrAssignmentToConstant: + Enabled: false +Lint/RedundantDirGlobSort: + Enabled: false +Lint/RefinementImportMethods: + Enabled: false +Lint/RequireRangeParentheses: + Enabled: false +Lint/RequireRelativeSelfPath: + Enabled: false +Lint/SymbolConversion: + Enabled: false Lint/ToEnumArguments: Enabled: false +Lint/TripleQuotes: + Enabled: false Lint/UnexpectedBlockArity: Enabled: false Lint/UnmodifiedReduceAccumulator: Enabled: false +Lint/UselessRescue: + Enabled: false +Lint/UselessRuby2Keywords: + Enabled: false +Metrics/CollectionLiteralLength: + Enabled: false +Naming/BlockForwarding: + Enabled: false Performance/CollectionLiteralInLoop: Enabled: false +Performance/ConcurrentMonotonicTime: + Enabled: false +Performance/MapCompact: + Enabled: false +Performance/RedundantEqualityComparisonBlock: + Enabled: false +Performance/RedundantSplitRegexpArgument: + Enabled: false +Performance/StringIdentifierArgument: + Enabled: false +RSpec/BeEq: + Enabled: false +RSpec/BeNil: + Enabled: false +RSpec/ChangeByZero: + Enabled: false +RSpec/ClassCheck: + Enabled: false +RSpec/DuplicatedMetadata: + Enabled: false +RSpec/ExcessiveDocstringSpacing: + Enabled: false +RSpec/FactoryBot/ConsistentParenthesesStyle: + Enabled: false +RSpec/FactoryBot/FactoryNameStyle: + Enabled: false +RSpec/FactoryBot/SyntaxMethods: + Enabled: false +RSpec/IdenticalEqualityAssertion: + Enabled: false +RSpec/NoExpectationExample: + Enabled: false +RSpec/PendingWithoutReason: + Enabled: false +RSpec/Rails/AvoidSetupHook: + Enabled: false +RSpec/Rails/HaveHttpStatus: + Enabled: false +RSpec/Rails/InferredSpecType: + Enabled: false +RSpec/Rails/MinitestAssertions: + Enabled: false +RSpec/Rails/TravelAround: + Enabled: false +RSpec/RedundantAround: + Enabled: false +RSpec/SkipBlockInsideExample: + Enabled: false +RSpec/SortMetadata: + Enabled: false +RSpec/SubjectDeclaration: + Enabled: false +RSpec/VerifiedDoubleReference: + Enabled: false +Security/CompoundHash: + Enabled: false +Security/IoMethods: + Enabled: false Style/ArgumentsForwarding: Enabled: false +Style/ArrayIntersect: + Enabled: false Style/CollectionCompact: Enabled: false +Style/ComparableClamp: + Enabled: false +Style/ConcatArrayLiterals: + Enabled: false +Style/DirEmpty: + Enabled: false Style/DocumentDynamicEvalDefinition: Enabled: false +Style/EmptyHeredoc: + Enabled: false +Style/EndlessMethod: + Enabled: false +Style/EnvHome: + Enabled: false +Style/FetchEnvVar: + Enabled: false +Style/FileEmpty: + Enabled: false +Style/FileRead: + Enabled: false +Style/FileWrite: + Enabled: false +Style/HashConversion: + Enabled: false +Style/HashExcept: + Enabled: false +Style/IfWithBooleanLiteralBranches: + Enabled: false +Style/InPatternThen: + Enabled: false +Style/MagicCommentFormat: + Enabled: false +Style/MapCompactWithConditionalBlock: + Enabled: false +Style/MapToHash: + Enabled: false +Style/MapToSet: + Enabled: false +Style/MinMaxComparison: + Enabled: false +Style/MultilineInPatternThen: + Enabled: false Style/NegatedIfElseCondition: Enabled: false +Style/NestedFileDirname: + Enabled: false Style/NilLambda: Enabled: false +Style/NumberedParameters: + Enabled: false +Style/NumberedParametersLimit: + Enabled: false +Style/ObjectThen: + Enabled: false +Style/OpenStructUse: + Enabled: false +Style/OperatorMethodCall: + Enabled: false +Style/QuotedSymbols: + Enabled: false Style/RedundantArgument: Enabled: false +Style/RedundantConstantBase: + Enabled: false +Style/RedundantDoubleSplatHashBraces: + Enabled: false +Style/RedundantEach: + Enabled: false +Style/RedundantHeredocDelimiterQuotes: + Enabled: false +Style/RedundantInitialize: + Enabled: false +Style/RedundantSelfAssignmentBranch: + Enabled: false +Style/RedundantStringEscape: + Enabled: false +Style/SelectByRegexp: + Enabled: false +Style/StringChars: + Enabled: false Style/SwapValues: Enabled: false diff --git a/Gemfile b/Gemfile index a167b88..add1873 100644 --- a/Gemfile +++ b/Gemfile @@ -13,21 +13,32 @@ def location_for(place_or_version, fake_version = nil) end end -ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments -minor_version = ruby_version_segments[0..1].join('.') - group :development do - gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 2.8.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "puppet-module-posix-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] - gem "puppet-module-posix-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] - gem "puppet-module-win-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] - gem "puppet-module-win-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.5.1', require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "racc", '~> 1.4.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) + gem "voxpupuli-puppet-lint-plugins", '~> 5.0', require: false + gem "facterdb", '~> 1.18', require: false + gem "metadata-json-lint", '~> 3.0', require: false + gem "puppetlabs_spec_helper", '~> 6.0', require: false + gem "rspec-puppet-facts", '~> 2.0', require: false + gem "codecov", '~> 0.2', require: false + gem "dependency_checker", '~> 1.0.0', require: false + gem "parallel_tests", '= 3.12.1', require: false + gem "pry", '~> 0.10', require: false + gem "simplecov-console", '~> 0.5', require: false + gem "puppet-debugger", '~> 1.0', require: false + gem "rubocop", '= 1.48.1', require: false + gem "rubocop-performance", '= 1.16.0', require: false + gem "rubocop-rspec", '= 2.19.0', require: false + gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] end group :system_tests do - gem "puppet-module-posix-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] - gem "puppet-module-win-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet_litmus", '~> 1.0', require: false, platforms: [:ruby, :x64_mingw] + gem "serverspec", '~> 2.41', require: false end puppet_version = ENV['PUPPET_GEM_VERSION'] diff --git a/Rakefile b/Rakefile index 2906c15..74415a9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,11 @@ # frozen_string_literal: true require 'bundler' -require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any? +require 'puppet_litmus/rake_tasks' if Gem.loaded_specs.key? 'puppet_litmus' require 'puppetlabs_spec_helper/rake_tasks' require 'puppet-syntax/tasks/puppet-syntax' -require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any? -require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any? -require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any? +require 'github_changelog_generator/task' if Gem.loaded_specs.key? 'github_changelog_generator' +require 'puppet-strings/tasks' if Gem.loaded_specs.key? 'puppet-strings' def changelog_user return unless Rake.application.top_level_tasks.include? "changelog" @@ -43,7 +42,8 @@ end PuppetLint.configuration.send('disable_relative') -if Bundler.rubygems.find_name('github_changelog_generator').any? + +if Gem.loaded_specs.key? 'github_changelog_generator' GitHubChangelogGenerator::RakeTask.new :changelog do |config| raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil? config.user = "#{changelog_user}" diff --git a/lib/facter/podman.rb b/lib/facter/podman.rb index caf7aa2..65404f5 100644 --- a/lib/facter/podman.rb +++ b/lib/facter/podman.rb @@ -7,11 +7,9 @@ confine { Facter::Core::Execution.which('podman') } setcode do - begin - JSON.parse(Facter::Core::Execution.exec("podman version --format '{{json .}}'")) - rescue - nil - end + JSON.parse(Facter::Core::Execution.exec("podman version --format '{{json .}}'")) + rescue + nil end end @@ -33,19 +31,17 @@ end chunk(:socket_user) do - begin - val = {} - Dir.glob('/run/user/*/podman/podman.sock') do |path| - next unless File.exist?(path) - uid = path.split(File::SEPARATOR)[3].to_i - - val['socket'] = {} if val['socket'].nil? - val['socket'][Etc.getpwuid(uid)[:name]] = path - end - - val - rescue - nil + val = {} + Dir.glob('/run/user/*/podman/podman.sock') do |path| + next unless File.exist?(path) + uid = path.split(File::SEPARATOR)[3].to_i + + val['socket'] = {} if val['socket'].nil? + val['socket'][Etc.getpwuid(uid)[:name]] = path end + + val + rescue + nil end end diff --git a/manifests/container.pp b/manifests/container.pp index d8c53de..0d71fe2 100644 --- a/manifests/container.pp +++ b/manifests/container.pp @@ -65,19 +65,19 @@ # } # define podman::container ( - String $image = '', - String $user = '', - Hash $flags = {}, - Hash $service_flags = {}, - String $command = '', - String $ensure = 'present', - Boolean $enable = true, - Boolean $update = true, - Stdlib::Unixpath $ruby = $facts['ruby']['sitedir'] ? { + Optional[String] $image = undef, + Optional[String] $user = undef, + Hash $flags = {}, + Hash $service_flags = {}, + Optional[String] $command = undef, + String $ensure = 'present', + Boolean $enable = true, + Boolean $update = true, + Stdlib::Unixpath $ruby = $facts['ruby']['sitedir'] ? { /^\/opt\/puppetlabs\// => '/opt/puppetlabs/puppet/bin/ruby', default => '/usr/bin/ruby', }, -){ +) { require podman::install # Add a label of base64 encoded flags defined for the container resource @@ -94,11 +94,11 @@ } # If a container name is not set, use the Puppet resource name - $merged_flags = merge({ name => $title, label => $label}, $no_label ) + $merged_flags = merge({ name => $title, label => $label }, $no_label ) $container_name = $merged_flags['name'] # A rootless container will run as the defined user - if $user != '' { + if $user != undef and $user != '' { ensure_resource('podman::rootless', $user, {}) $systemctl = 'systemctl --user ' @@ -158,21 +158,23 @@ case $ensure { 'present': { - if $image == '' { fail('A source image is required') } + if $image == undef { fail('A source image is required') } # Detect changes to the defined podman flags and re-deploy if needed exec { "verify_container_flags_${handle}": command => 'true', provider => 'shell', + # lint:ignore:strict_indent unless => @("END"/$L), - if podman container exists ${container_name} - then - saved_resource_flags="\$(podman container inspect ${container_name} \ - --format '{{.Config.Labels.puppet_resource_flags}}')" - current_resource_flags="${flags_base64}" - test "\${saved_resource_flags}" = "\${current_resource_flags}" - fi - |END + if podman container exists ${container_name} + then + saved_resource_flags="\$(podman container inspect ${container_name} \ + --format '{{.Config.Labels.puppet_resource_flags}}')" + current_resource_flags="${flags_base64}" + test "\${saved_resource_flags}" = "\${current_resource_flags}" + fi + |END + # lint:endignore notify => Exec["podman_remove_container_${handle}"], require => $requires, * => $exec_defaults, @@ -183,6 +185,7 @@ exec { "verify_container_image_${handle}": command => 'true', provider => 'shell', + # lint:ignore:strict_indent unless => @("END"/$L), if podman container exists ${container_name} then @@ -196,6 +199,7 @@ test "\${running_digest}" = "\${latest_digest}" fi |END + # lint:endignore notify => [ Exec["podman_remove_image_${handle}"], Exec["podman_remove_container_${handle}"], @@ -208,6 +212,7 @@ exec { "verify_container_image_${handle}": command => 'true', provider => 'shell', + # lint:ignore:strict_indent unless => @("END"/$L), if podman container exists ${container_name} then @@ -220,6 +225,7 @@ exit 1 fi |END + # lint:endignore notify => [ Exec["podman_remove_image_${handle}"], Exec["podman_remove_container_${handle}"], @@ -235,13 +241,14 @@ command => "podman rmi ${image} || exit 0", refreshonly => true, notify => Exec["podman_create_${handle}"], - require => [ $requires, Exec["podman_remove_container_${handle}"]], + require => [$requires, Exec["podman_remove_container_${handle}"]], * => $exec_defaults, } exec { "podman_remove_container_${handle}": # Try to stop the container service, then the container directly provider => 'shell', + # lint:ignore:strict_indent command => @("END"/L), ${systemctl} stop podman-${container_name} || true podman container stop --time 60 ${container_name} || true @@ -251,6 +258,7 @@ test $(podmain container inspect --format json ${container_name} |\ ${ruby} -rjson -e 'puts (JSON.parse(STDIN.read))[0]["State"]["Running"]') = |END + # lint:endignore refreshonly => true, notify => Exec["podman_create_${handle}"], require => $requires, @@ -297,7 +305,7 @@ * => $exec_defaults, } - if $user != '' { + if $user != undef and $user != '' { exec { "podman_generate_service_${handle}": command => "podman generate systemd ${_service_flags} ${container_name} > ${service_unit_file}", refreshonly => true, @@ -307,10 +315,12 @@ } # Work-around for managing user systemd services - if $enable { $action = 'start'; $startup = 'enable' } - else { $action = 'stop'; $startup = 'disable' + if $enable { + $action = 'start'; $startup = 'enable' + } else { $action = 'stop'; $startup = 'disable' } exec { "service_podman_${handle}": + # lint:ignore:strict_indent command => @("END"/L), ${systemctl} ${startup} podman-${container_name}.service ${systemctl} ${action} podman-${container_name}.service @@ -319,6 +329,7 @@ ${systemctl} is-active podman-${container_name}.service && \ ${systemctl} is-enabled podman-${container_name}.service |END + # lint:endignore require => $requires, * => $exec_defaults, } @@ -332,8 +343,10 @@ } # Configure the container service per parameters - if $enable { $state = 'running'; $startup = 'true' } - else { $state = 'stopped'; $startup = 'false' + if $enable { + $state = 'running'; $startup = 'true' + } else { + $state = 'stopped'; $startup = 'false' } service { "podman-${handle}": ensure => $state, @@ -344,6 +357,7 @@ 'absent': { exec { "service_podman_${handle}": + # lint:ignore:strict_indent command => @("END"/L), ${systemctl} stop podman-${container_name} ${systemctl} disable podman-${container_name} @@ -352,6 +366,7 @@ test "\$(${systemctl} is-active podman-${container_name} 2>&1)" = "active" -o \ "\$(${systemctl} is-enabled podman-${container_name} 2>&1)" = "enabled" |END + # lint:endignore notify => Exec["podman_remove_container_${handle}"], require => $requires, * => $exec_defaults, @@ -370,7 +385,7 @@ provider => 'shell', command => "podman rmi ${image} || exit 0", refreshonly => true, - require => [ $requires, Exec["podman_remove_container_${handle}"]], + require => [$requires, Exec["podman_remove_container_${handle}"]], * => $exec_defaults, } @@ -389,4 +404,3 @@ } } } - diff --git a/manifests/image.pp b/manifests/image.pp index 9d1d135..e3a7117 100644 --- a/manifests/image.pp +++ b/manifests/image.pp @@ -33,9 +33,9 @@ String $image, String $ensure = 'present', Hash $flags = {}, - String $user = '', + Optional[String] $user = undef, Array $exec_env = [], -){ +) { require podman::install # Convert $flags hash to command arguments @@ -52,17 +52,17 @@ } } - if $user != '' { + if $user != undef and $user != '' { ensure_resource('podman::rootless', $user, {}) # Set execution environment for the rootless user $exec_defaults = { path => '/sbin:/usr/sbin:/bin:/usr/bin', environment => [ - "HOME=${User[$user]['home']}", - "XDG_RUNTIME_DIR=/run/user/${User[$user]['uid']}", - "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${User[$user]['uid']}/bus", - ] + $exec_env, + "HOME=${User[$user]['home']}", + "XDG_RUNTIME_DIR=/run/user/${User[$user]['uid']}", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${User[$user]['uid']}/bus", + ] + $exec_env, cwd => User[$user]['home'], provider => 'shell', user => $user, diff --git a/manifests/init.pp b/manifests/init.pp index 722091f..d7241b1 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -129,7 +129,7 @@ Hash $images = {}, Hash $containers = {}, Hash $networks = {}, -){ +) { include podman::install include podman::options include podman::service diff --git a/manifests/install.pp b/manifests/install.pp index 9043cb7..61d1b84 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -22,13 +22,13 @@ default: order => 1, content => $podman::file_header, - ; + ; 'subuid_header': target => '/etc/subuid', - ; + ; 'subgid_header': target => '/etc/subgid', - ; + ; } if $podman::match_subuid_subgid { @@ -40,7 +40,7 @@ } } - if $facts['selinux'] == true or $facts['os']['selinux']['enabled'] == true { + if $facts['os']['selinux']['enabled'] == true { selboolean { 'container_manage_cgroup': persistent => true, value => on, diff --git a/manifests/network.pp b/manifests/network.pp index 2b92251..3ce662d 100644 --- a/manifests/network.pp +++ b/manifests/network.pp @@ -54,7 +54,7 @@ Hash[String,String] $labels = {}, Optional[String] $subnet = undef, Boolean $ipv6 = false, - String $user = '', + Optional[String] $user = undef, ) { require podman::install @@ -106,7 +106,7 @@ } # A rootless container network will be defined as the defined user - if $user != '' { + if $user != undef and $user != '' { # Set default execution environment for the rootless user $exec_defaults = { user => $user, @@ -129,10 +129,7 @@ case $ensure { 'present': { exec { "podman_create_network_${title}": - command => @("END"/L), - podman network create ${title} --driver ${driver} ${_opts} \ - ${_gateway} ${_internal} ${_ip_range} ${_labels} ${_subnet} ${_ipv6} - |END + command => "podman network create ${title} --driver ${driver} ${_opts} ${_gateway} ${_internal} ${_ip_range} ${_labels} ${_subnet} ${_ipv6}", # lint:ignore:140chars unless => "podman network exists ${title}", path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], require => $requires, diff --git a/manifests/pod.pp b/manifests/pod.pp index 2a8623a..e01b3c4 100644 --- a/manifests/pod.pp +++ b/manifests/pod.pp @@ -23,7 +23,7 @@ define podman::pod ( String $ensure = 'present', Hash $flags = {}, - String $user = '', + Optional[String] $user = undef, ) { require podman::install @@ -45,7 +45,7 @@ } } - if $user != '' { + if $user != undef and $user != '' { ensure_resource('podman::rootless', $user, {}) # Set execution environment for the rootless user @@ -87,7 +87,7 @@ } } default: { - fail('"ensure" must be "present" or "absent"') + fail('"ensure" must be "present" or "absent"') } } } diff --git a/manifests/rootless.pp b/manifests/rootless.pp index af0f5fd..c4ce717 100644 --- a/manifests/rootless.pp +++ b/manifests/rootless.pp @@ -9,13 +9,13 @@ require => User[$name], notify => Service['podman systemd-logind'], } - ensure_resource('Service', 'podman systemd-logind', { name => 'systemd-logind.service', ensure => 'running' } ) + ensure_resource('Service', 'podman systemd-logind', { name => 'systemd-logind.service', ensure => 'running' }) # Ensure the systemd directory tree exists for user services ensure_resource('File', [ - "${User[$name]['home']}/.config", - "${User[$name]['home']}/.config/systemd", - "${User[$name]['home']}/.config/systemd/user" + "${User[$name]['home']}/.config", + "${User[$name]['home']}/.config/systemd", + "${User[$name]['home']}/.config/systemd/user" ], { ensure => directory, owner => $name, diff --git a/manifests/subgid.pp b/manifests/subgid.pp index 1a30039..533d500 100644 --- a/manifests/subgid.pp +++ b/manifests/subgid.pp @@ -20,7 +20,6 @@ Integer $count, Integer $order = 10, ) { - Concat::Fragment { "subgid_fragment_${title}": order => $order, target => '/etc/subgid', diff --git a/manifests/subuid.pp b/manifests/subuid.pp index 3d0c0a3..848a2b4 100644 --- a/manifests/subuid.pp +++ b/manifests/subuid.pp @@ -20,7 +20,6 @@ Integer $count, Integer $order = 10, ) { - Concat::Fragment { "subuid_fragment_${title}": order => $order, target => '/etc/subuid', diff --git a/manifests/volume.pp b/manifests/volume.pp index e3547d4..01ffbed 100644 --- a/manifests/volume.pp +++ b/manifests/volume.pp @@ -24,7 +24,7 @@ define podman::volume ( String $ensure = 'present', Hash $flags = {}, - String $user = '', + Optional[String] $user = undef, ) { require podman::install @@ -42,7 +42,7 @@ } } - if $user != '' { + if $user != undef and $user != '' { ensure_resource('podman::rootless', $user, {}) # Set execution environment for the rootless user @@ -87,4 +87,3 @@ } } } - diff --git a/metadata.json b/metadata.json index e709bc2..fe21a0f 100644 --- a/metadata.json +++ b/metadata.json @@ -54,7 +54,7 @@ "version_requirement": ">= 4.10.0 < 9.0.0" } ], - "pdk-version": "2.3.0", - "template-url": "pdk-default#2.3.0", - "template-ref": "tags/2.3.0-0-g8aaceff" + "pdk-version": "3.0.0", + "template-url": "pdk-default#3.0.0", + "template-ref": "tags/3.0.0-0-g056e50d" } diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb new file mode 100644 index 0000000..3ba0c1c --- /dev/null +++ b/spec/classes/init_spec.rb @@ -0,0 +1,370 @@ +require 'spec_helper' + +describe 'podman' do + on_supported_os.each do |os, os_facts| + context "on #{os} with defaults for all parameters" do + let(:facts) { os_facts } + + it { is_expected.to compile } + it { is_expected.to contain_class('podman::install') } + it { is_expected.to contain_class('podman::options') } + it { is_expected.to contain_class('podman::service') } + it { is_expected.to have_package_resource_count(6) } + it { is_expected.to have_podman__pod_resource_count(0) } + it { is_expected.to have_podman__volume_resource_count(0) } + it { is_expected.to have_podman__image_resource_count(0) } + it { is_expected.to have_podman__container_resource_count(0) } + it { is_expected.to have_podman__network_resource_count(0) } + it { is_expected.to have_podman__rootless_resource_count(0) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + it { is_expected.to contain_service('podman.socket') } # from podman::service + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with podman_pkg set to valid testing' do + let(:params) { { podman_pkg: 'testing' } } # parameter used in podman::install + + it { is_expected.to contain_package('testing') } + end + + context 'with skopeo_pkg set to valid testing' do + let(:params) { { skopeo_pkg: 'testing' } } # parameter used in podman::install + + it { is_expected.to contain_package('testing') } + end + + context 'with buildah_pkg set to valid testing' do + let(:params) { { buildah_pkg: 'testing' } } # parameter used in podman::install + + it { is_expected.to contain_package('testing') } + end + + context 'with podman_docker_pkg set to valid testing' do + let(:params) { { podman_docker_pkg: 'testing' } } # parameter used in podman::install + + it { is_expected.to contain_package('testing') } + end + + context 'with compose_pkg set to valid testing' do + let(:params) { { compose_pkg: 'testing' } } # parameter used in podman::install + + it { is_expected.to contain_package('testing') } + end + + context 'with machinectl_pkg set to valid testing' do + let(:params) { { machinectl_pkg: 'testing' } } # parameter used in podman::install + + it { is_expected.to contain_package('testing') } + end + + context 'with buildah_pkg_ensure set to valid installed' do + let(:params) { { buildah_pkg_ensure: 'installed' } } # parameter used in podman::install + + it { is_expected.to contain_package('buildah').with_ensure('installed') } + end + + context 'with podman_docker_pkg_ensure set to valid absent' do + let(:params) { { podman_docker_pkg_ensure: 'absent' } } # parameter used in podman::install + + it { is_expected.to contain_package('podman-docker').with_ensure('absent') } + end + context 'with compose_pkg_ensure set to valid installed' do + let(:params) { { compose_pkg_ensure: 'installed' } } # parameter used in podman::install + + it { is_expected.to contain_package('podman-compose').with_ensure('installed') } + end + context 'with machinectl_pkg_ensure set to valid absent' do + let(:params) { { machinectl_pkg_ensure: 'absent' } } # parameter used in podman::install + + it { is_expected.to contain_package('systemd-container').with_ensure('absent') } + end + + context 'with nodocker set to valid file' do + let(:params) { { nodocker: 'file' } } # parameter used in podman::install + + it { is_expected.to contain_file('/etc/containers/nodocker').with_ensure('file') } + end + + context 'with storage_options set to valid hash' do + let(:params) { { storage_options: { testing1: { option1: 'value1', option2: 'value2' }, testing2: { option3: 'value3' } } } } + + it do + is_expected.to contain_ini_setting('/etc/containers/storage.conf [testing1] option1').only_with( + { + 'section' => 'testing1', + 'setting' => 'option1', + 'value' => 'value1', + 'ensure' => 'present', + 'path' => '/etc/containers/storage.conf', + }, + ) + end + + it do + is_expected.to contain_ini_setting('/etc/containers/storage.conf [testing1] option2').only_with( + { + 'section' => 'testing1', + 'setting' => 'option2', + 'value' => 'value2', + 'ensure' => 'present', + 'path' => '/etc/containers/storage.conf', + }, + ) + end + + it do + is_expected.to contain_ini_setting('/etc/containers/storage.conf [testing2] option3').only_with( + { + 'section' => 'testing2', + 'setting' => 'option3', + 'value' => 'value3', + 'ensure' => 'present', + 'path' => '/etc/containers/storage.conf', + }, + ) + end + end + + context 'with rootless_users set to valid [test, ing]' do + let(:params) { { rootless_users: ['test', 'ing'] } } + let(:pre_condition) do + "# user & file needed by podman::rootless + user { 'test': + ensure => 'present', + gid => 1111, + home => '/home/test', + uid => 3333, + } + user { 'ing': + ensure => 'present', + gid => 1111, + home => '/home/ing', + uid => 4444, + } + file { '/home/test': } + file { '/home/ing': } + " + end + + it { is_expected.to contain_podman__rootless('test').only_with({}) } + it { is_expected.to contain_podman__rootless('ing').only_with({}) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_test') } # from podman::rootless + it { is_expected.to contain_exec('loginctl_linger_ing') } # from podman::rootless + it { is_expected.to contain_exec('start_test.slice') } # from podman::rootless + it { is_expected.to contain_exec('start_ing.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/ing/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_file('/home/ing/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/ing/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/test/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_file('/home/test/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/test/.config') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + end + + context 'with enable_api_socket set to valid true' do + let(:params) { { enable_api_socket: true } } + + it do # parameter used in podman::service + is_expected.to contain_service('podman.socket').with( + { + 'ensure' => 'running', + 'enable' => true, + }, + ) + end + end + + context 'with enable_api_socket set to valid true when rootless_users is set to valid [dummy]' do + let(:params) { { enable_api_socket: true, rootless_users: ['dummy'] } } # parameter used in podman::service & podman::rootless + let(:pre_condition) do + "# user & file needed by podman::rootless + user { 'dummy': + ensure => 'present', + gid => 1111, + home => '/home/dummy', + uid => 3333, + } + file { '/home/dummy': } + " + end + + it do + is_expected.to contain_service('podman.socket').with( + { + 'ensure' => 'running', + 'enable' => true, + }, + ) + end + + it do + is_expected.to contain_exec('podman rootless api socket dummy').only_with( + { + 'command' => 'systemctl --user enable --now podman.socket', + 'path' => os_facts[:path], + 'user' => 'dummy', + 'environment' => ['HOME=/home/dummy', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'unless' => 'systemctl --user status podman.socket', + 'require' => ['Exec[loginctl_linger_dummy]', 'Exec[start_dummy.slice]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_dummy') } # from podman::rootless + it { is_expected.to contain_exec('start_dummy.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + it { is_expected.to contain_podman__rootless('dummy') } # from podman::rootless + end + + context 'with manage_subuid set to valid true' do + let(:params) { { manage_subuid: true } } # parameter used in podman::install + + it { is_expected.to contain_concat('/etc/subuid') } + it { is_expected.to contain_concat('/etc/subgid') } + it { is_expected.to contain_concat_fragment('subuid_header') } + it { is_expected.to contain_concat_fragment('subgid_header') } + end + + context 'with manage_subuid set to valid true when subid is a valid hash' do + let(:params) { { manage_subuid: true, subid: { dummy: { subuid: 242, count: 1 } } } } # parameter used in podman::install + + it { is_expected.to contain_concat('/etc/subuid') } + it { is_expected.to contain_concat('/etc/subgid') } + it { is_expected.to contain_concat_fragment('subuid_header') } + it { is_expected.to contain_concat_fragment('subgid_header') } + it { is_expected.to contain_podman__subuid('dummy') } + it { is_expected.to contain_podman__subgid('dummy') } + + # only here to reach 100% resource coverage + it { is_expected.to contain_concat__fragment('subgid_fragment_dummy') } # from podman::subgid + it { is_expected.to contain_concat__fragment('subuid_fragment_dummy') } # from podman::subuid + end + + context 'with match_subuid_subgid set to valid false when manage_subuid is true and subid is a valid hash' do + let(:params) { { match_subuid_subgid: false, manage_subuid: true, subid: { dummy: { subuid: 242, count: 1 } } } } # parameter used in podman::install + + it { is_expected.not_to contain_podman__subuid('dummy') } + it { is_expected.not_to contain_podman__subgid('dummy') } + end + + context 'with file_header set to valid #testing when manage_subuid is true' do + let(:params) { { file_header: '#testing', manage_subuid: true } } # parameter used in podman::install + + it { is_expected.to contain_concat_fragment('subuid_header').with_content('#testing') } + it { is_expected.to contain_concat_fragment('subgid_header').with_content('#testing') } + end + + context 'with subid set to valid hash when manage_subuid is true' do + let(:params) { { subid: { testing: { subuid: 242, count: 1 } }, manage_subuid: true } } # parameter used in podman::install + + it { is_expected.to contain_podman__subuid('testing') } + it { is_expected.to contain_podman__subgid('testing') } + + # only here to reach 100% resource coverage + it { is_expected.to contain_concat__fragment('subgid_fragment_testing') } # from podman::subgid + it { is_expected.to contain_concat__fragment('subuid_fragment_testing') } # from podman::subuid + end + + context 'with pods set to valid hash' do + let(:params) { { pods: { test1: { flags: { label: 'dummy1' } }, test2: { flags: { label: 'dummy2' } } } } } + + it { is_expected.to contain_podman__pod('test1').with_flags({ 'label' => 'dummy1' }) } + it { is_expected.to contain_podman__pod('test2').with_flags({ 'label' => 'dummy2' }) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('create_pod_test1') } # from podman::pod + it { is_expected.to contain_exec('create_pod_test2') } # from podman::pod + end + + context 'with volumes set to valid hash' do + let(:params) { { volumes: { test1: { flags: { label: 'dummy1' } }, test2: { flags: { label: 'dummy2' } } } } } + + it { is_expected.to contain_podman__volume('test1').with_flags({ 'label' => 'dummy1' }) } + it { is_expected.to contain_podman__volume('test2').with_flags({ 'label' => 'dummy2' }) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('podman_create_volume_test1') } # from podman::volume + it { is_expected.to contain_exec('podman_create_volume_test2') } # from podman::volume + end + + context 'with images set to valid hash' do + let(:params) { { images: { test1: { flags: { label: 'dummy1' }, image: 'dummy:242' }, test2: { flags: { label: 'dummy2' }, image: 'dummy:242' } } } } + + it { is_expected.to contain_podman__image('test1').with_flags({ 'label' => 'dummy1' }) } + it { is_expected.to contain_podman__image('test2').with_flags({ 'label' => 'dummy2' }) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('pull_image_test1') } # from podman::image + it { is_expected.to contain_exec('pull_image_test2') } # from podman::image + end + + context 'with containers set to valid hash' do + let(:params) { { containers: { test1: { flags: { label: 'dummy1' }, image: 'dummy:242' }, test2: { flags: { label: 'dummy2' }, image: 'dummy:242' } } } } + + it { is_expected.to contain_podman__container('test1').with_flags({ 'label' => 'dummy1' }) } + it { is_expected.to contain_podman__container('test2').with_flags({ 'label' => 'dummy2' }) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('podman_create_test1') } # from podman::container + it { is_expected.to contain_exec('podman_create_test2') } # from podman::container + it { is_expected.to contain_exec('podman_generate_service_test1') } # from podman::container + it { is_expected.to contain_exec('podman_generate_service_test2') } # from podman::container + it { is_expected.to contain_exec('podman_remove_container_test1') } # from podman::container + it { is_expected.to contain_exec('podman_remove_container_test2') } # from podman::container + it { is_expected.to contain_exec('podman_remove_image_test1') } # from podman::container + it { is_expected.to contain_exec('podman_remove_image_test2') } # from podman::container + it { is_expected.to contain_exec('verify_container_flags_test1') } # from podman::container + it { is_expected.to contain_exec('verify_container_flags_test2') } # from podman::container + it { is_expected.to contain_exec('verify_container_image_test1') } # from podman::container + it { is_expected.to contain_exec('verify_container_image_test2') } # from podman::container + it { is_expected.to contain_service('podman-test1') } # from podman::container + it { is_expected.to contain_service('podman-test2') } # from podman::container + it { is_expected.to contain_exec('podman_systemd_reload') } # from podman::container + end + + context 'with networks set to valid hash' do + let(:params) { { networks: { test1: { labels: { dummy1: 'dummy1' } }, test2: { labels: { dummy2: 'dummy2' } } } } } + + it { is_expected.to contain_podman__network('test1').with_labels({ 'dummy1' => 'dummy1' }) } + it { is_expected.to contain_podman__network('test2').with_labels({ 'dummy2' => 'dummy2' }) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('podman_create_network_test1') } # from podman::network + it { is_expected.to contain_exec('podman_create_network_test2') } # from podman::network + end + end +end diff --git a/spec/classes/install_spec.rb b/spec/classes/install_spec.rb new file mode 100644 index 0000000..bf523b4 --- /dev/null +++ b/spec/classes/install_spec.rb @@ -0,0 +1,217 @@ +require 'spec_helper' + +describe 'podman::install' do + let(:pre_condition) { 'include podman' } + + on_supported_os.each do |os, os_facts| + context "on #{os} with defaults for all parameters" do + let(:facts) { os_facts } + + it { is_expected.to compile } + it { is_expected.to contain_package('buildah').with_ensure('absent') } + it { is_expected.to contain_package('podman-compose').with_ensure('absent') } + it { is_expected.to contain_package('podman-docker').with_ensure('installed') } + it { is_expected.to contain_package('podman').with_ensure('installed') } + it { is_expected.to contain_package('skopeo').with_ensure('installed') } + + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd').with_ensure('installed') } + else + it { is_expected.to contain_package('systemd-container').with_ensure('installed') } + end + + if os_facts[:os]['selinux']['enabled'] == true + it do + is_expected.to contain_selboolean('container_manage_cgroup').only_with( + { + 'persistent' => true, + 'value' => 'on', + 'require' => 'Package[podman]', + }, + ) + end + end + + it do + is_expected.to contain_file('/etc/containers/nodocker').only_with( + { + 'ensure' => 'absent', + 'group' => 'root', + 'owner' => 'root', + 'mode' => '0644', + 'require' => 'Package[podman]', + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_service('podman.socket') } # from podman::service + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'when podman::podman_pkg is set to valid testing' do + let(:pre_condition) { 'class { "podman": podman_pkg => "testing" }' } + + it { is_expected.to contain_package('testing') } + end + + context 'when podman::skopeo_pkg is set to valid testing' do + let(:pre_condition) { 'class { "podman": skopeo_pkg => "testing" }' } + + it { is_expected.to contain_package('testing') } + end + + context 'when podman::buildah_pkg is set to valid testing' do + let(:pre_condition) { 'class { "podman": buildah_pkg => "testing" }' } + + it { is_expected.to contain_package('testing') } + end + + context 'when podman::buildah_pkg_ensure is set to valid installed' do + let(:pre_condition) { 'class { "podman": buildah_pkg_ensure => "installed" }' } + + it { is_expected.to contain_package('buildah').with_ensure('installed') } + end + + context 'when podman::podman_docker_pkg is set to valid testing' do + let(:pre_condition) { 'class { "podman": podman_docker_pkg => "testing" }' } + + it { is_expected.to contain_package('testing') } + end + + context 'when podman::podman_docker_pkg_ensure is set to valid absent' do + let(:pre_condition) { 'class { "podman": podman_docker_pkg_ensure => "absent" }' } + + it { is_expected.to contain_package('podman-docker').with_ensure('absent') } + end + + context 'when podman::compose_pkg is set to valid testing' do + let(:pre_condition) { 'class { "podman": compose_pkg => "testing" }' } + + it { is_expected.to contain_package('testing') } + end + + context 'when podman::compose_pkg_ensure is set to valid installed' do + let(:pre_condition) { 'class { "podman": compose_pkg_ensure => "installed" }' } + + it { is_expected.to contain_package('podman-compose').with_ensure('installed') } + end + + context 'when podman::machinectl_pkg is set to valid testing' do + let(:pre_condition) { 'class { "podman": machinectl_pkg => "testing" }' } + + it { is_expected.to contain_package('testing') } + end + + context 'when podman::machinectl_pkg_ensure is set to valid absent' do + let(:pre_condition) { 'class { "podman": machinectl_pkg_ensure => "absent" }' } + + it { is_expected.to contain_package('systemd-container').with_ensure('absent') } + end + + context 'when podman::manage_subuid is set to valid true' do + let(:pre_condition) { 'class { "podman": manage_subuid => true }' } + + it do + is_expected.to contain_concat('/etc/subuid').with( + { + 'owner' => 'root', + 'group' => 'root', + 'mode' => '0644', + 'order' => 'alpha', + 'ensure_newline' => true, + }, + ) + end + + it do + is_expected.to contain_concat('/etc/subgid').with( + { + 'owner' => 'root', + 'group' => 'root', + 'mode' => '0644', + 'order' => 'alpha', + 'ensure_newline' => true, + }, + ) + end + + it do + is_expected.to contain_concat_fragment('subuid_header').only_with( + { + 'target' => '/etc/subuid', + 'order' => '1', + 'content' => '# FILE MANAGED BY PUPPET', + }, + ) + end + + it do + is_expected.to contain_concat_fragment('subgid_header').only_with( + { + 'target' => '/etc/subgid', + 'order' => '1', + 'content' => '# FILE MANAGED BY PUPPET', + }, + ) + end + + it { is_expected.to have_podman__subuid_resource_count(0) } + it { is_expected.to have_podman__subgid_resource_count(0) } + end + + context 'when podman::manage_subuid is set to valid true when podman::subid is a valid hash' do + let(:pre_condition) { 'class { "podman": manage_subuid => true, subid => { dummy => { subuid => 242, count => 1 } } }' } + + it do + is_expected.to contain_podman__subuid('dummy').only_with( + { + 'subuid' => 242, + 'count' => 1, + 'order' => 10, + }, + ) + end + + it do + is_expected.to contain_podman__subgid('dummy').only_with( + { + 'subgid' => 242, + 'count' => 1, + 'order' => 10, + }, + ) + end + + it { is_expected.to have_podman__subuid_resource_count(1) } + it { is_expected.to have_podman__subgid_resource_count(1) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_concat__fragment('subgid_fragment_dummy') } # from podman::subgid + it { is_expected.to contain_concat__fragment('subuid_fragment_dummy') } # from podman::subuid + end + + context 'when podman::manage_subuid is set to valid true when match_subuid_subgid is false and podman::subid is a valid hash' do + let(:pre_condition) { 'class { "podman": manage_subuid => true, match_subuid_subgid => false, subid => { dummy => { subuid => 242, count => 1 } } }' } + + it { is_expected.to have_podman__subuid_resource_count(0) } + it { is_expected.to have_podman__subgid_resource_count(0) } + end + end +end diff --git a/spec/classes/options_spec.rb b/spec/classes/options_spec.rb new file mode 100644 index 0000000..f07ec63 --- /dev/null +++ b/spec/classes/options_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe 'podman::options' do + let(:pre_condition) { 'include podman' } + + on_supported_os.each do |os, os_facts| + context "on #{os} with defaults for all parameters" do + let(:facts) { os_facts } + + it { is_expected.to compile } + it { is_expected.to contain_class('podman::options') } + it { is_expected.to have_ini_setting_resource_count(0) } + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_class('podman::install') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + it { is_expected.to contain_service('podman.socket') } # from podman::service + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'when podman::storage_options is set to valid hash' do + let(:pre_condition) { 'class { "podman": storage_options => { testing1 => { option1 => "value1", option2 => "value2" }, testing2 => { option3 => "value3" } } }' } + + it do + is_expected.to contain_ini_setting('/etc/containers/storage.conf [testing1] option1').only_with( + { + 'section' => 'testing1', + 'setting' => 'option1', + 'value' => 'value1', + 'ensure' => 'present', + 'path' => '/etc/containers/storage.conf', + }, + ) + end + + it do + is_expected.to contain_ini_setting('/etc/containers/storage.conf [testing1] option2').only_with( + { + 'section' => 'testing1', + 'setting' => 'option2', + 'value' => 'value2', + 'ensure' => 'present', + 'path' => '/etc/containers/storage.conf', + }, + ) + end + + it do + is_expected.to contain_ini_setting('/etc/containers/storage.conf [testing2] option3').only_with( + { + 'section' => 'testing2', + 'setting' => 'option3', + 'value' => 'value3', + 'ensure' => 'present', + 'path' => '/etc/containers/storage.conf', + }, + ) + end + end + end +end diff --git a/spec/classes/podman_spec.rb b/spec/classes/podman_spec.rb deleted file mode 100644 index be68be3..0000000 --- a/spec/classes/podman_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -require 'spec_helper' - -describe 'podman' do - on_supported_os.each do |os, os_facts| - context "on #{os}" do - let(:facts) { os_facts } - let(:params) do - { - podman_pkg: 'podman', - skopeo_pkg: 'skopeo', - buildah_pkg: 'buildah', - machinectl_pkg: 'machinectl', - buildah_pkg_ensure: 'installed', - podman_docker_pkg: 'podman-docker', - podman_docker_pkg_ensure: 'installed', - manage_subuid: true, - } - end - let(:pre_condition) do - 'User { "user1": - uid => 10001, - gid => 10001, - home => "/home/user1", - } - User { "user2": - uid => 10002, - gid => 10002, - home => "/home/user2", - }' - end - - it { is_expected.to compile } - it { is_expected.to contain_class('podman::install') } - it { is_expected.to contain_class('podman::service') } - - it do - is_expected.to contain_service('podman.socket').with( - 'ensure' => 'stopped', - 'enable' => false, - ) - end - end - - context "on #{os} with API socket enabled" do - let(:facts) { os_facts } - let(:params) do - { - 'enable_api_socket' => true, - } - end - - it { is_expected.to compile } - it { is_expected.to contain_class('podman::service') } - - it do - is_expected.to contain_service('podman.socket').with( - 'ensure' => 'running', - 'enable' => true, - ) - end - end - end -end diff --git a/spec/classes/service_spec.rb b/spec/classes/service_spec.rb new file mode 100644 index 0000000..359f9f9 --- /dev/null +++ b/spec/classes/service_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe 'podman::service' do + let(:pre_condition) { 'include podman' } + + on_supported_os.each do |os, os_facts| + context "on #{os} with defaults for all parameters" do + let(:facts) { os_facts } + + it { is_expected.to compile } + it { is_expected.to contain_class('podman::install') } + + it do + is_expected.to contain_service('podman.socket').only_with( + { + 'ensure' => 'stopped', + 'enable' => false, + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'when podman::enable_api_socket is set to valid true' do + let(:pre_condition) { 'class { "podman": enable_api_socket => true }' } + + it do + is_expected.to contain_service('podman.socket').only_with( + { + 'ensure' => 'running', + 'enable' => true, + }, + ) + end + end + end +end diff --git a/spec/defines/container_spec.rb b/spec/defines/container_spec.rb index 5f08001..fda5fff 100644 --- a/spec/defines/container_spec.rb +++ b/spec/defines/container_spec.rb @@ -2,25 +2,839 @@ describe 'podman::container' do let(:title) { 'namevar' } - let(:params) do - { - image: 'registry:latest', - } - end + let(:params) { { image: 'registry:latest' } } let(:pre_condition) { 'include podman' } on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} with defaults for all parameters and image set to valid value" do let(:facts) { os_facts } it { is_expected.to compile.with_all_deps } - context "with flag['label'] set" do - let(:params) do - super().merge(flags: { label: 'a=b' }) + it { is_expected.to contain_class('podman') } + it { is_expected.to contain_class('podman::install') } + + it do + is_expected.to contain_exec('podman_systemd_reload').only_with( + { + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'command' => 'systemctl daemon-reload', + 'refreshonly' => true, + }, + ) + end + + unless_flags = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | saved_resource_flags="$(podman container inspect namevar --format '{{.Config.Labels.puppet_resource_flags}}')" + | current_resource_flags="e30=" + | test "${saved_resource_flags}" = "${current_resource_flags}" + |fi + END + + it do + is_expected.to contain_exec('verify_container_flags_namevar').only_with( + { + 'command' => 'true', + 'provider' => 'shell', + 'unless' => unless_flags, + 'notify' => 'Exec[podman_remove_container_namevar]', + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + if %r{^\/opt\/puppetlabs\/}.match?(os_facts[:ruby]['sitedir']) + unless_image = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | image_name=$(podman container inspect namevar --format '{{.ImageName}}') + | running_digest=$(podman image inspect ${image_name} --format '{{.Digest}}') + | latest_digest=$(skopeo inspect docker://registry:latest | /opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | [[ $? -ne 0 ]] && latest_digest=$(skopeo inspect --no-creds docker://registry:latest | /opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | test -z "${latest_digest}" && exit 0 # Do not update if unable to get latest digest + | test "${running_digest}" = "${latest_digest}" + |fi + END + else + unless_image = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | image_name=$(podman container inspect namevar --format '{{.ImageName}}') + | running_digest=$(podman image inspect ${image_name} --format '{{.Digest}}') + | latest_digest=$(skopeo inspect docker://registry:latest | /usr/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | [[ $? -ne 0 ]] && latest_digest=$(skopeo inspect --no-creds docker://registry:latest | /usr/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | test -z "${latest_digest}" && exit 0 # Do not update if unable to get latest digest + | test "${running_digest}" = "${latest_digest}" + |fi + END + end + + it do + is_expected.to contain_exec('verify_container_image_namevar').only_with( + { + 'command' => 'true', + 'provider' => 'shell', + 'unless' => unless_image, + 'notify' => ['Exec[podman_remove_image_namevar]', 'Exec[podman_remove_container_namevar]'], + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_image_namevar').only_with( + { + 'provider' => 'shell', + 'command' => 'podman rmi registry:latest || exit 0', + 'refreshonly' => true, + 'notify' => 'Exec[podman_create_namevar]', + 'require' => [ 'Exec[podman_remove_container_namevar]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + remove_command = <<-END.gsub(%r{^\s+\|}, '') + |systemctl stop podman-namevar || true + |podman container stop --time 60 namevar || true + |podman container rm --force namevar || true + END + + remove_onlyif = if %r{^\/opt\/puppetlabs\/}.match?(os_facts[:ruby]['sitedir']) + <<-END.gsub(%r{^\s+\|}, '') + |test $(podmain container inspect --format json namevar |/opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))[0]["State"]["Running"]') =#{' '} + END + else + <<-END.gsub(%r{^\s+\|}, '') + |test $(podmain container inspect --format json namevar |/usr/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))[0]["State"]["Running"]') =#{' '} + END + end + + it do + is_expected.to contain_exec('podman_remove_container_namevar').only_with( + { + 'provider' => 'shell', + 'command' => remove_command, + 'onlyif' => remove_onlyif, + 'refreshonly' => true, + 'notify' => 'Exec[podman_create_namevar]', + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + it do + is_expected.to contain_exec('podman_create_namevar').only_with( + { + 'command' => "podman container create --name 'namevar' --label 'puppet_resource_flags=e30=' registry:latest ", + 'unless' => 'podman container exists namevar', + 'notify' => 'Exec[podman_generate_service_namevar]', + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + it do + is_expected.to contain_exec('podman_generate_service_namevar').only_with( + { + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'command' => 'podman generate systemd namevar > /etc/systemd/system/podman-namevar.service', + 'refreshonly' => true, + 'notify' => 'Service[podman-namevar]', + }, + ) + end + + it do + is_expected.to contain_service('podman-namevar').only_with( + { + 'ensure' => 'running', + 'enable' => true, + }, + ) + end + + # only here to reach 100% resource coverage] + context 'cover additional resource from other classes' do + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_service('podman.socket') } # from podman::service + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install end + end + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with image set to valid testing:latest' do + let(:params) { { image: 'testing:latest' } } + + unless_image = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | image_name=$(podman container inspect namevar --format '{{.ImageName}}') + | running_digest=$(podman image inspect ${image_name} --format '{{.Digest}}') + | latest_digest=$(skopeo inspect docker://testing:latest | /opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | [[ $? -ne 0 ]] && latest_digest=$(skopeo inspect --no-creds docker://testing:latest | /opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | test -z "${latest_digest}" && exit 0 # Do not update if unable to get latest digest + | test "${running_digest}" = "${latest_digest}" + |fi + END + + it { is_expected.to contain_exec('verify_container_image_namevar').with_unless(unless_image) } + it { is_expected.to contain_exec('podman_remove_image_namevar').with_command('podman rmi testing:latest || exit 0') } + it { is_expected.to contain_exec('podman_create_namevar').with_unless('podman container exists namevar') } + end + + context 'with image set to valid testing:latest when update is set to valid false' do + let(:params) { { image: 'testing:latest', update: false } } + + unless_image = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | running=$(podman container inspect namevar --format '{{.ImageName}}' | awk -F/ '{print $NF}') + | declared=$(echo "testing:latest" | awk -F/ '{print $NF}') + | test "${running}" = "${declared}" && exit 0 + | available=$(skopeo inspect docker://testing:latest | /opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Name"]') + | test -z "${available}" && exit 0 # Do not update update if unable to get the new image + | exit 1 + |fi + END + + it { is_expected.to contain_exec('verify_container_image_namevar').with_unless(unless_image) } + end + + context 'with image set to valid testing:latest when ensure is set to valid absent' do + let(:params) { { image: 'testing:latest', ensure: 'absent' } } + + it { is_expected.to contain_exec('podman_remove_image_namevar').with_command('podman rmi testing:latest || exit 0') } + end + + context 'with user set to valid testing' do + let(:params) { { user: 'testing', image: 'mandatory:latest', } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it { is_expected.to contain_podman__rootless('testing').only_with({}) } + + it do + is_expected.to contain_exec('podman_systemd_testing_reload').with( + { + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('verify_container_flags_testing-namevar').with( + { + 'notify' => 'Exec[podman_remove_container_testing-namevar]', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('verify_container_image_testing-namevar').with( + { + 'notify' => ['Exec[podman_remove_image_testing-namevar]', 'Exec[podman_remove_container_testing-namevar]'], + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_image_testing-namevar').with( + { + 'notify' => 'Exec[podman_create_testing-namevar]', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]', 'Exec[podman_remove_container_testing-namevar]'], + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_container_testing-namevar').with( + { + 'notify' => 'Exec[podman_create_testing-namevar]', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('podman_create_testing-namevar').with( + { + 'notify' => 'Exec[podman_generate_service_testing-namevar]', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('podman_generate_service_testing-namevar').only_with( + { + 'command' => 'podman generate systemd namevar > /home/testing/.config/systemd/user/podman-namevar.service', + 'refreshonly' => true, + 'notify' => 'Exec[service_podman_testing-namevar]', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('service_podman_testing-namevar').only_with( + { + 'command' => "systemctl --user enable podman-namevar.service\nsystemctl --user start podman-namevar.service\n", + 'unless' => "systemctl --user is-active podman-namevar.service && systemctl --user is-enabled podman-namevar.service\n", + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + # only here to reach 100% resource coverage + context 'cover additional resource from other classes' do + it { is_expected.to contain_exec('loginctl_linger_testing') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_exec('start_testing.slice') } # from podman::rootless + end + end + + context 'with user set to valid testing when ensure is set to valid absent' do + let(:params) { { user: 'testing', ensure: 'absent', image: 'mandatory:latest', } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it { is_expected.to contain_podman__rootless('testing').only_with({}) } + + it do + is_expected.to contain_exec('podman_systemd_testing_reload').with( + { + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('service_podman_testing-namevar').with( + { + 'notify' => 'Exec[podman_remove_container_testing-namevar]', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_container_testing-namevar').with( + { + 'notify' => 'Exec[podman_remove_image_testing-namevar]', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_image_testing-namevar').with( + { + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]', 'Exec[podman_remove_container_testing-namevar]'], + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'user' => 'testing', + }, + ) + end + + it do + is_expected.to contain_file('/home/testing/.config/systemd/user/podman-namevar.service').with( + { + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]', 'Exec[service_podman_testing-namevar]'], + }, + ) + end + end + + context 'with flags set to valid hash' do + let(:params) { { flags: { publish: ['242:242'], volume: 'jenkins:/test/ing' }, image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + unless_flags = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | saved_resource_flags="$(podman container inspect namevar --format '{{.Config.Labels.puppet_resource_flags}}')" + | current_resource_flags="eyJwdWJsaXNoIj0+WyIyNDI6MjQyIl0sICJ2b2x1bWUiPT4iamVua2luczovdGVzdC9pbmcifQ==" + | test "${saved_resource_flags}" = "${current_resource_flags}" + |fi + END - it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_exec('verify_container_flags_namevar').with_unless(unless_flags) } + + it do + is_expected.to contain_exec('podman_create_namevar').with( + { + 'command' => "podman container create --name 'namevar' " \ + "--label 'puppet_resource_flags=eyJwdWJsaXNoIj0+WyIyNDI6MjQyIl0sICJ2b2x1bWUiPT4iamVua2luczovdGVzdC9pbmcifQ==' " \ + "--publish '242:242' --volume 'jenkins:/test/ing' mandatory:latest ", + }, + ) + end + + it do + is_expected.to contain_exec('podman_generate_service_namevar').with( + { + 'command' => 'podman generate systemd namevar > /etc/systemd/system/podman-namevar.service', + }, + ) + end + end + + context 'with flags set to valid hash containing a label' do + let(:params) { { flags: { publish: ['242:242'], volume: 'jenkins:/test/ing', label: 'test' }, image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + unless_flags = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | saved_resource_flags="$(podman container inspect namevar --format '{{.Config.Labels.puppet_resource_flags}}')" + | current_resource_flags="eyJwdWJsaXNoIj0+WyIyNDI6MjQyIl0sICJ2b2x1bWUiPT4iamVua2luczovdGVzdC9pbmciLCAibGFiZWwiPT4idGVzdCJ9" + | test "${saved_resource_flags}" = "${current_resource_flags}" + |fi + END + + it { is_expected.to contain_exec('verify_container_flags_namevar').with_unless(unless_flags) } + + it do + is_expected.to contain_exec('podman_create_namevar').with( + { + 'command' => "podman container create --name 'namevar' --label 'test' " \ + "--label 'puppet_resource_flags=eyJwdWJsaXNoIj0+WyIyNDI6MjQyIl0sICJ2b2x1bWUiPT4iamVua2luczovdGVzdC9pbmciLCAibGFiZWwiPT4idGVzdCJ9' " \ + "--publish '242:242' --volume 'jenkins:/test/ing' mandatory:latest ", + }, + ) + end + + it do + is_expected.to contain_exec('podman_generate_service_namevar').with( + { + 'command' => 'podman generate systemd namevar > /etc/systemd/system/podman-namevar.service', + }, + ) + end + end + + context 'with flags set to valid hash when user is set to valid testing' do + let(:params) { { flags: { publish: ['242:242'], volume: 'jenkins:/test/ing' }, user: 'testing', image: 'mandatory:latest' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + unless_flags = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | saved_resource_flags="$(podman container inspect namevar --format '{{.Config.Labels.puppet_resource_flags}}')" + | current_resource_flags="eyJwdWJsaXNoIj0+WyIyNDI6MjQyIl0sICJ2b2x1bWUiPT4iamVua2luczovdGVzdC9pbmcifQ==" + | test "${saved_resource_flags}" = "${current_resource_flags}" + |fi + END + + it { is_expected.to contain_exec('verify_container_flags_testing-namevar').with_unless(unless_flags) } + + it do + is_expected.to contain_exec('podman_create_testing-namevar').with( + { + 'command' => "podman container create --name 'namevar' " \ + "--label 'puppet_resource_flags=eyJwdWJsaXNoIj0+WyIyNDI6MjQyIl0sICJ2b2x1bWUiPT4iamVua2luczovdGVzdC9pbmcifQ==' " \ + "--publish '242:242' --volume 'jenkins:/test/ing' mandatory:latest ", + }, + ) + end + + it do + is_expected.to contain_exec('podman_generate_service_testing-namevar').with( + { + 'command' => 'podman generate systemd namevar > /home/testing/.config/systemd/user/podman-namevar.service', + }, + ) end + + it do + is_expected.to contain_exec('service_podman_testing-namevar').with( + { + 'command' => "systemctl --user enable podman-namevar.service\nsystemctl --user start podman-namevar.service\n", + 'unless' => "systemctl --user is-active podman-namevar.service && systemctl --user is-enabled podman-namevar.service\n", + }, + ) + end + end + + context 'with command set to valid /test/ing' do + let(:params) { { command: '/test/ing', image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + it do + is_expected.to contain_exec('podman_create_namevar').with( + { + 'command' => "podman container create --name 'namevar' --label 'puppet_resource_flags=e30=' mandatory:latest /test/ing", + }, + ) + end + end + + context 'with ensure set to valid absent' do + let(:params) { { ensure: 'absent', image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + it do + is_expected.to contain_exec('service_podman_namevar').only_with( + { + 'command' => "systemctl stop podman-namevar\nsystemctl disable podman-namevar\n", + 'onlyif' => "test \"$(systemctl is-active podman-namevar 2>&1)\" = \"active\" -o \"$(systemctl is-enabled podman-namevar 2>&1)\" = \"enabled\"\n", + 'notify' => 'Exec[podman_remove_container_namevar]', + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_container_namevar').only_with( + { + 'command' => 'podman container rm --force namevar', + 'unless' => 'podman container exists namevar; test $? -eq 1', + 'notify' => 'Exec[podman_remove_image_namevar]', + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_image_namevar').only_with( + { + 'provider' => 'shell', + 'command' => 'podman rmi mandatory:latest || exit 0', + 'refreshonly' => true, + 'require' => ['Exec[podman_remove_container_namevar]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + it do + is_expected.to contain_file('/etc/systemd/system/podman-namevar.service').only_with( + { + 'ensure' => 'absent', + 'require' => ['Exec[service_podman_namevar]'], + 'notify' => 'Exec[podman_systemd_reload]', + }, + ) + end + end + + context 'with ensure set to valid absent when user is set to valid value' do + let(:params) { { ensure: 'absent', user: 'user', image: 'mandatory:latest' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'user': + ensure => 'present', + gid => 1111, + home => '/home/user', + uid => 3333, + } + file { '/home/user': } + " + end + + it { is_expected.to contain_podman__rootless('user').only_with({}) } + + it do + is_expected.to contain_exec('podman_systemd_user_reload').only_with( + { + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'command' => 'systemctl --user daemon-reload', + 'refreshonly' => true, + 'environment' => ['HOME=/home/user', 'XDG_RUNTIME_DIR=/run/user/3333'], + 'cwd' => '/home/user', + 'provider' => 'shell', + 'user' => 'user', + }, + ) + end + + it do + is_expected.to contain_exec('service_podman_user-namevar').only_with( + { + 'command' => "systemctl --user stop podman-namevar\nsystemctl --user disable podman-namevar\n", + 'onlyif' => "test \"$(systemctl --user is-active podman-namevar 2>&1)\" = \"active\" -o \"$(systemctl --user is-enabled podman-namevar 2>&1)\" = \"enabled\"\n", + 'notify' => 'Exec[podman_remove_container_user-namevar]', + 'require' => ['Podman::Rootless[user]', 'Service[podman systemd-logind]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/user', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/user', + 'user' => 'user', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_container_user-namevar').only_with( + { + 'command' => 'podman container rm --force namevar', + 'unless' => 'podman container exists namevar; test $? -eq 1', + 'notify' => 'Exec[podman_remove_image_user-namevar]', + 'require' => ['Podman::Rootless[user]', 'Service[podman systemd-logind]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/user', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/user', + 'user' => 'user', + }, + ) + end + + it do + is_expected.to contain_exec('podman_remove_image_user-namevar').only_with( + { + 'provider' => 'shell', + 'command' => 'podman rmi mandatory:latest || exit 0', + 'refreshonly' => true, + 'require' => ['Podman::Rootless[user]', 'Service[podman systemd-logind]', 'Exec[podman_remove_container_user-namevar]'], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/user', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/user', + 'user' => 'user', + }, + ) + end + + it do + is_expected.to contain_file('/home/user/.config/systemd/user/podman-namevar.service').only_with( + { + 'ensure' => 'absent', + 'require' => ['Podman::Rootless[user]', 'Service[podman systemd-logind]', 'Exec[service_podman_user-namevar]'], + 'notify' => 'Exec[podman_systemd_user_reload]', + }, + ) + end + + # only here to reach 100% resource coverage] + context 'cover additional resource from other classes' do + it { is_expected.to contain_exec('loginctl_linger_user') } # from podman::rootless + it { is_expected.to contain_file('/home/user/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/user/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/user/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_exec('start_user.slice') } # from podman::rootless + end + end + + context 'with enable set to valid false' do + let(:params) { { enable: false, image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + it do + is_expected.to contain_service('podman-namevar').only_with( + { + 'ensure' => 'stopped', + 'enable' => false, + }, + ) + end + end + + context 'with enable set to valid false when user is set to valid value' do + let(:params) { { enable: false, user: 'user', image: 'mandatory:latest' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'user': + ensure => 'present', + gid => 1111, + home => '/home/user', + uid => 3333, + } + file { '/home/user': } + " + end + + it do + is_expected.to contain_exec('service_podman_user-namevar').with( + { + 'command' => "systemctl --user disable podman-namevar.service\nsystemctl --user stop podman-namevar.service\n", + }, + ) + end + + it { is_expected.to contain_exec('verify_container_flags_user-namevar') } + it { is_expected.to contain_exec('verify_container_image_user-namevar') } + it { is_expected.to contain_exec('podman_create_user-namevar') } + it { is_expected.to contain_exec('podman_generate_service_user-namevar') } + end + + context 'with update set to valid false' do + let(:params) { { update: false, image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + unless_image = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | running=$(podman container inspect namevar --format '{{.ImageName}}' | awk -F/ '{print $NF}') + | declared=$(echo "mandatory:latest" | awk -F/ '{print $NF}') + | test "\${running}" = "\${declared}" && exit 0 + | available=$(skopeo inspect docker://mandatory:latest | /opt/puppetlabs/puppet/bin/ruby -rjson -e 'puts (JSON.parse(STDIN.read))["Name"]') + | test -z "\${available}" && exit 0 # Do not update update if unable to get the new image + | exit 1 + |fi + END + + it do + is_expected.to contain_exec('verify_container_image_namevar').only_with( + { + 'command' => 'true', + 'provider' => 'shell', + 'unless' => unless_image, + 'notify' => ['Exec[podman_remove_image_namevar]', 'Exec[podman_remove_container_namevar]'], + 'require' => [], + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + end + + context 'with ruby set to valid /test/ing' do + let(:params) { { ruby: '/test/ing', image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + unless_ruby = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | image_name=$(podman container inspect namevar --format '{{.ImageName}}') + | running_digest=$(podman image inspect ${image_name} --format '{{.Digest}}') + | latest_digest=$(skopeo inspect docker://mandatory:latest | /test/ing -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | [[ $? -ne 0 ]] && latest_digest=$(skopeo inspect --no-creds docker://mandatory:latest | /test/ing -rjson -e 'puts (JSON.parse(STDIN.read))["Digest"]') + | test -z "${latest_digest}" && exit 0 # Do not update if unable to get latest digest + | test "${running_digest}" = "${latest_digest}" + |fi + END + + it { is_expected.to contain_exec('verify_container_image_namevar').with_unless(unless_ruby) } + + onlyif_ruby = <<-END.gsub(%r{^\s+\|}, '') + |test $(podmain container inspect --format json namevar |/test/ing -rjson -e 'puts (JSON.parse(STDIN.read))[0]["State"]["Running"]') =#{' '} + END + + it { is_expected.to contain_exec('podman_remove_container_namevar').with_onlyif(onlyif_ruby) } + end + + context 'with ruby set to valid /test/ing when update is false' do + let(:params) { { ruby: '/test/ing', update: false, image: 'mandatory:latest' } } + let(:pre_condition) { 'include podman' } + + unless_ruby = <<-END.gsub(%r{^\s+\|}, '') + |if podman container exists namevar + | then + | running=$(podman container inspect namevar --format '{{.ImageName}}' | awk -F/ '{print $NF}') + | declared=$(echo "mandatory:latest" | awk -F/ '{print $NF}') + | test "\${running}" = "\${declared}" && exit 0 + | available=$(skopeo inspect docker://mandatory:latest | /test/ing -rjson -e 'puts (JSON.parse(STDIN.read))["Name"]') + | test -z "\${available}" && exit 0 # Do not update update if unable to get the new image + | exit 1 + |fi + END + + it { is_expected.to contain_exec('verify_container_image_namevar').with_unless(unless_ruby) } + + onlyif_ruby = <<-END.gsub(%r{^\s+\|}, '') + |test $(podmain container inspect --format json namevar |/test/ing -rjson -e 'puts (JSON.parse(STDIN.read))[0]["State"]["Running"]') =#{' '} + END + + it { is_expected.to contain_exec('podman_remove_container_namevar').with_onlyif(onlyif_ruby) } end end end diff --git a/spec/defines/image_spec.rb b/spec/defines/image_spec.rb index ae5cf2c..546111f 100644 --- a/spec/defines/image_spec.rb +++ b/spec/defines/image_spec.rb @@ -1,19 +1,284 @@ require 'spec_helper' describe 'podman::image' do - let(:title) { 'namevar' } - let(:params) do - { - image: 'registry:latest', - } - end + let(:title) { 'title' } let(:pre_condition) { 'include podman' } on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} with defaults for all parameters and image set to valid value" do let(:facts) { os_facts } + let(:params) { { image: 'image:test' } } it { is_expected.to compile } + it { is_expected.to contain_class('podman::install') } + + it do + is_expected.to contain_exec('pull_image_title').only_with( + { + 'command' => 'podman image pull image:test', + 'unless' => 'podman image exists image:test', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => [], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_service('podman.socket') } # from podman::service + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with ensure set to valid absent' do + let(:params) { { ensure: 'absent', image: 'image:test' } } + + it do + is_expected.to contain_exec('pull_image_title').only_with( + { + 'command' => 'podman image pull image:test', + 'unless' => 'podman rmi image:test', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => [], + }, + ) + end + end + + context 'with ensure set to valid absent when user is set to valid dummy' do + let(:params) { { ensure: 'absent', user: 'dummy', image: 'image:test' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'dummy': + ensure => 'present', + gid => 1111, + home => '/home/dummy', + uid => 3333, + } + file { '/home/dummy': } + " + end + + it { is_expected.to contain_podman__rootless('dummy').only_with({}) } + + it do + is_expected.to contain_exec('pull_image_title').only_with( + { + 'command' => 'podman image pull image:test', + 'unless' => 'podman rmi image:test', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/dummy', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/dummy', + 'provider' => 'shell', + 'user' => 'dummy', + 'require' => ['Podman::Rootless[dummy]', 'Service[podman systemd-logind]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_dummy') } # from podman::rootless + it { is_expected.to contain_exec('start_dummy.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd/user') } # from podman::rootless + end + + context 'with ensure set to valid present when user is set to valid dummy' do + let(:params) { { ensure: 'present', user: 'dummy', image: 'image:test' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'dummy': + ensure => 'present', + gid => 1111, + home => '/home/dummy', + uid => 3333, + } + file { '/home/dummy': } + " + end + + it { is_expected.to contain_podman__rootless('dummy').only_with({}) } + + it do + is_expected.to contain_exec('pull_image_title').only_with( + { + 'command' => 'podman image pull image:test', + 'unless' => 'podman image exists image:test', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/dummy', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/dummy', + 'provider' => 'shell', + 'user' => 'dummy', + 'require' => ['Podman::Rootless[dummy]', 'Service[podman systemd-logind]'], + }, + ) + end + end + + context 'with flags set to valid hash' do + let(:params) { { flags: { publish: ['242:242'], volume: 'jenkins:/test/ing' }, image: 'image:test' } } + + it do + is_expected.to contain_exec('pull_image_title').with( + { + 'command' => "podman image pull --publish '242:242' --volume 'jenkins:/test/ing' image:test", + }, + ) + end + end + + context 'with flags set to valid hash when ensure is set to valid absent' do + let(:params) { { flags: { publish: ['242:242'], volume: 'jenkins:/test/ing' }, ensure: 'absent', image: 'image:test' } } + + it do + is_expected.to contain_exec('pull_image_title').with( + { + 'command' => "podman image pull --publish '242:242' --volume 'jenkins:/test/ing' image:test", + }, + ) + end + end + + context 'with user set to valid testing' do + let(:params) { { user: 'testing', image: 'image:test' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it { is_expected.to contain_podman__rootless('testing').only_with({}) } + + it do + is_expected.to contain_exec('pull_image_title').only_with( + { + 'command' => 'podman image pull image:test', + 'unless' => 'podman image exists image:test', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'provider' => 'shell', + 'user' => 'testing', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_testing') } # from podman::rootless + it { is_expected.to contain_exec('start_testing.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + end + + context 'with user set to valid testing when ensure is set to valid absent' do + let(:params) { { user: 'testing', ensure: 'absent', image: 'image:test' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it { is_expected.to contain_podman__rootless('testing').only_with({}) } + + it do + is_expected.to contain_exec('pull_image_title').only_with( + { + 'command' => 'podman image pull image:test', + 'unless' => 'podman rmi image:test', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'provider' => 'shell', + 'user' => 'testing', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + }, + ) + end + end + + context 'with exec_env set to valid [TEST=/test/ing]' do + let(:params) { { exec_env: ['TEST=/test/ing'], image: 'image:test' } } + + it do + is_expected.to contain_exec('pull_image_title').with( + { + 'environment' => ['TEST=/test/ing'], + }, + ) + end + end + + context 'with exec_env set to valid [TEST=/test/ing] when user is set to valid dummy' do + let(:params) { { exec_env: ['TEST=/test/ing'], user: 'dummy', image: 'image:test' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'dummy': + ensure => 'present', + gid => 1111, + home => '/home/dummy', + uid => 3333, + } + file { '/home/dummy': } + " + end + + it do + is_expected.to contain_exec('pull_image_title').with( + { + 'environment' => ['HOME=/home/dummy', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus', 'TEST=/test/ing'], + }, + ) + end end end end diff --git a/spec/defines/network_spec.rb b/spec/defines/network_spec.rb new file mode 100644 index 0000000..49c4a2e --- /dev/null +++ b/spec/defines/network_spec.rb @@ -0,0 +1,253 @@ +require 'spec_helper' + +describe 'podman::network' do + let(:title) { 'testing-title' } + let(:pre_condition) { 'include podman' } + + on_supported_os.each do |os, os_facts| + context "on #{os} with defaults for all parameters" do + let(:facts) { os_facts } + + it { is_expected.to compile } + it { is_expected.to contain_class('podman::install') } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').only_with( + { + 'command' => 'podman network create testing-title --driver bridge ', + 'unless' => 'podman network exists testing-title', + 'path' => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], + 'require' => [], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_service('podman.socket') } # from podman::service + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with ensure set to valid absent' do + let(:params) { { ensure: 'absent' } } + + it do + is_expected.to contain_exec('podman_remove_network_testing-title').only_with( + { + 'command' => 'podman network rm testing-title', + 'onlyif' => 'podman network exists testing-title', + 'path' => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], + 'require' => [], + }, + ) + end + end + + context 'with ensure set to valid absent when user is set to valid dummy' do + let(:params) { { ensure: 'absent', user: 'dummy' } } + let(:pre_condition) do + "include podman + ensure_resource('podman::rootless', 'dummy', {}) + # user & file needed by podman::rootless + user { 'dummy': + ensure => 'present', + gid => 1111, + home => '/home/dummy', + uid => 3333, + } + file { '/home/dummy': } + " + end + + it do + is_expected.to contain_exec('podman_remove_network_testing-title').only_with( + { + 'command' => 'podman network rm testing-title', + 'onlyif' => 'podman network exists testing-title', + 'path' => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'], + 'require' => ['Podman::Rootless[dummy]', 'Service[podman systemd-logind]'], + 'user' => 'dummy', + 'environment' => ['HOME=/home/dummy', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/dummy', + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_dummy') } # from podman::rootless + it { is_expected.to contain_exec('start_dummy.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + end + + context 'with driver set to valid macvlan' do + let(:params) { { driver: 'macvlan' } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver macvlan ', + }, + ) + end + end + + # disable_dns currently has no functionality + context 'with disable_dns set to valid true' do + let(:params) { { disable_dns: true } } + + it { is_expected.to compile } + end + + context 'with opts set to valid array [test, ing]' do + let(:params) { { opts: ['test', 'ing'] } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver bridge --flag test --flag ing ', + }, + ) + end + end + + context 'with gateway set to valid testing' do + let(:params) { { gateway: 'testing' } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver bridge --gateway testing ', + }, + ) + end + end + + context 'with internal set to valid true' do + let(:params) { { internal: true } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver bridge --internal ', + }, + ) + end + end + + context 'with ip_range set to valid testing' do + let(:params) { { ip_range: 'testing' } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver bridge --ip-range testing ', + }, + ) + end + end + + context 'with labels set to valid hash' do + let(:params) { { labels: { test: 'ing', test2: 'ing2' } } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => "podman network create testing-title --driver bridge --label test 'ing' --label test2 'ing2' ", + }, + ) + end + end + + context 'with subnet set to valid testing' do + let(:params) { { subnet: 'testing' } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver bridge --subnet testing ', + }, + ) + end + end + + context 'with ipv6 set to valid true' do + let(:params) { { ipv6: true } } + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'command' => 'podman network create testing-title --driver bridge --ipv6', + }, + ) + end + end + + context 'with user set to valid testing' do + let(:params) { { user: 'testing' } } + let(:pre_condition) do + "include podman + ensure_resource('podman::rootless', 'testing', {}) + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it do + is_expected.to contain_exec('podman_create_network_testing-title').with( + { + 'user' => 'testing', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_testing') } # from podman::rootless + it { is_expected.to contain_exec('start_testing.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd/user') } # from podman::rootless + end + end +end diff --git a/spec/defines/pod_spec.rb b/spec/defines/pod_spec.rb index 7340377..735c0d7 100644 --- a/spec/defines/pod_spec.rb +++ b/spec/defines/pod_spec.rb @@ -1,21 +1,167 @@ require 'spec_helper' describe 'podman::pod' do - let(:title) { 'testpod' } - let(:params) do - { - flags: { - label: 'app=wordpress', - }, - } - end + let(:title) { 'testing-title' } let(:pre_condition) { 'include podman' } on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} with defaults for all parameters" do let(:facts) { os_facts } it { is_expected.to compile } + it { is_expected.to contain_class('podman::install') } + + it do + is_expected.to contain_exec('create_pod_testing-title').only_with( + { + 'command' => "podman pod create --name 'testing-title'", + 'unless' => 'podman pod exists testing-title', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'provider' => 'shell', + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + it { is_expected.to contain_service('podman.socket') } # from podman::service + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with ensure set to valid absent' do + let(:params) { { ensure: 'absent' } } + + it do + is_expected.to contain_exec('remove_pod_testing-title').only_with( + { + 'command' => 'podman pod rm testing-title', + 'unless' => 'podman pod exists testing-title; test $? -eq 1', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'provider' => 'shell', + }, + ) + end + end + + context 'with ensure set to valid absent when user is set to valid dummy' do + let(:params) { { ensure: 'absent', user: 'dummy' } } + let(:pre_condition) do + "include podman + ensure_resource('podman::rootless', 'dummy', {}) + # user & file needed by podman::rootless + user { 'dummy': + ensure => 'present', + gid => 1111, + home => '/home/dummy', + uid => 3333, + } + file { '/home/dummy': } + " + end + + it do + is_expected.to contain_exec('remove_pod_testing-title').only_with( + { + 'command' => 'podman pod rm testing-title', + 'unless' => 'podman pod exists testing-title; test $? -eq 1', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/dummy', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/dummy', + 'provider' => 'shell', + 'user' => 'dummy', + 'require' => ['Podman::Rootless[dummy]', 'Service[podman systemd-logind]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_dummy') } # from podman::rootless + it { is_expected.to contain_exec('start_dummy.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/dummy/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + end + + context 'with flags set to valid hash' do + let(:params) { { flags: { test1: ['value1'], test2: 'value2' } } } + + it do + is_expected.to contain_exec('create_pod_testing-title').with( + { + 'command' => "podman pod create --name 'testing-title' --test1 'value1' --test2 'value2'", + }, + ) + end + end + + context 'with user set to valid value testing' do + let(:params) { { user: 'testing' } } + let(:pre_condition) do + "include podman + ensure_resource('podman::rootless', 'testing', {}) + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it do + is_expected.to contain_exec('create_pod_testing-title').only_with( + { + 'command' => "podman pod create --name 'testing-title'", + 'unless' => 'podman pod exists testing-title', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'provider' => 'shell', + 'user' => 'testing', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_testing') } # from podman::rootless + it { is_expected.to contain_exec('start_testing.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd/user') } # from podman::rootless end end end diff --git a/spec/defines/rootless_spec.rb b/spec/defines/rootless_spec.rb index 4d917c0..fe8725c 100644 --- a/spec/defines/rootless_spec.rb +++ b/spec/defines/rootless_spec.rb @@ -1,34 +1,160 @@ -# frozen_string_literal: true - require 'spec_helper' describe 'podman::rootless' do - let(:title) { 'user1' } - let(:params) do - {} - end + let(:title) { 'testing-title' } let(:pre_condition) do - <<~END - include podman - group { 'user1': } - -> user { 'user1': - gid => 'user1', - home => '/home/user1', - } - -> file { '/home/user1': - ensure => directory, - owner => 'user1', - group => 'user1', - mode => '0700', - } - END + "include podman + # user & file needed by podman::rootless + user { 'testing-title': + ensure => 'present', + gid => 1111, + home => '/home/testing-title', + uid => 3333, + } + file { '/home/testing-title': } + " end on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} with defaults for all parameters" do let(:facts) { os_facts } it { is_expected.to compile } + + it do + is_expected.to contain_exec('loginctl_linger_testing-title').only_with( + { + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'command' => 'loginctl enable-linger testing-title', + 'provider' => 'shell', + 'unless' => "test $(loginctl show-user testing-title --property=Linger) = 'Linger=yes'", + 'require' => 'User[testing-title]', + 'notify' => 'Service[podman systemd-logind]', + }, + ) + end + + it do + is_expected.to contain_service('podman systemd-logind').only_with( + { + 'name' => 'systemd-logind.service', + 'ensure' => 'running', + }, + ) + end + + it do + is_expected.to contain_file('/home/testing-title/.config').only_with( + { + 'ensure' => 'directory', + 'owner' => 'testing-title', + 'group' => '1111', + 'mode' => '0700', + 'require' => 'File[/home/testing-title]', + }, + ) + end + + it do + is_expected.to contain_file('/home/testing-title/.config/systemd').only_with( + { + 'ensure' => 'directory', + 'owner' => 'testing-title', + 'group' => '1111', + 'mode' => '0700', + 'require' => 'File[/home/testing-title]', + }, + ) + end + + it do + is_expected.to contain_file('/home/testing-title/.config/systemd/user').only_with( + { + 'ensure' => 'directory', + 'owner' => 'testing-title', + 'group' => '1111', + 'mode' => '0700', + 'require' => 'File[/home/testing-title]', + }, + ) + end + + it do + is_expected.to contain_exec('start_testing-title.slice').only_with( + { + 'path' => os_facts[:path], + 'command' => "machinectl shell testing-title@.host '/bin/true'", + 'unless' => 'systemctl is-active user-3333.slice', + 'require' => ['Exec[loginctl_linger_testing-title]', 'Service[podman systemd-logind]', 'File[/home/testing-title/.config/systemd/user]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman::install') } # from podman + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + it { is_expected.to contain_service('podman.socket') } # from podman::service + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with podman::enable_api_socket is set to valid true' do + let(:facts) { os_facts } + let(:pre_condition) do + "class { 'podman': + enable_api_socket => true, + } + # user & file needed by podman::rootless + user { 'testing-title': + ensure => 'present', + gid => 1111, + home => '/home/testing-title', + uid => 3333, + } + file { '/home/testing-title': } + " + end + + it do + is_expected.to contain_exec('podman rootless api socket testing-title').only_with( + { + 'command' => 'systemctl --user enable --now podman.socket', + 'path' => os_facts[:path], + 'user' => 'testing-title', + 'environment' => ['HOME=/home/testing-title', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'unless' => 'systemctl --user status podman.socket', + 'require' => ['Exec[loginctl_linger_testing-title]', 'Exec[start_testing-title.slice]'], + }, + ) + end end end end diff --git a/spec/defines/subgid_spec.rb b/spec/defines/subgid_spec.rb index df1994e..7cce8ac 100644 --- a/spec/defines/subgid_spec.rb +++ b/spec/defines/subgid_spec.rb @@ -1,19 +1,50 @@ require 'spec_helper' describe 'podman::subgid' do - let(:title) { 'namevar' } - let(:params) do - { - subgid: 2_000_000, - count: 1000, - } - end + let(:title) { 'testing-title' } on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} when all mandatory parameters are set to valid values" do let(:facts) { os_facts } + let(:params) { { subgid: 2_000_000, count: 1000 } } it { is_expected.to compile } + + it do + is_expected.to contain_concat__fragment('subgid_fragment_testing-title').only_with( + { + 'order' => '10', + 'target' => '/etc/subgid', + 'content' => 'testing-title:2000000:1000' + }, + ) + end + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with subgid set to valid 242 and count set to valid 3' do + let(:params) { { subgid: 242, count: 3 } } + + it { is_expected.to contain_concat__fragment('subgid_fragment_testing-title').with_content('testing-title:242:3') } + end + + context 'with order set to valid 242 when all mandatory parameters are set to valid values' do + let(:params) { { order: 242, subgid: 2_000_000, count: 1000 } } + + it { is_expected.to contain_concat__fragment('subgid_fragment_testing-title').with_order(242) } end end end diff --git a/spec/defines/subuid_spec.rb b/spec/defines/subuid_spec.rb index b1d9844..ae38544 100644 --- a/spec/defines/subuid_spec.rb +++ b/spec/defines/subuid_spec.rb @@ -1,19 +1,50 @@ require 'spec_helper' describe 'podman::subuid' do - let(:title) { 'namevar' } - let(:params) do - { - subuid: 2_000_000, - count: 1000, - } - end + let(:title) { 'testing-title' } on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} when all mandatory parameters are set to valid values" do let(:facts) { os_facts } + let(:params) { { subuid: 2_000_000, count: 1000 } } it { is_expected.to compile } + + it do + is_expected.to contain_concat__fragment('subuid_fragment_testing-title').only_with( + { + 'order' => '10', + 'target' => '/etc/subuid', + 'content' => 'testing-title:2000000:1000' + }, + ) + end + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with subuid set to valid 242 and count set to valid 3' do + let(:params) { { subuid: 242, count: 3 } } + + it { is_expected.to contain_concat__fragment('subuid_fragment_testing-title').with_content('testing-title:242:3') } + end + + context 'with order set to valid 242 when all mandatory parameters are set to valid values' do + let(:params) { { order: 242, subuid: 2_000_000, count: 1000 } } + + it { is_expected.to contain_concat__fragment('subuid_fragment_testing-title').with_order(242) } end end end diff --git a/spec/defines/volume_spec.rb b/spec/defines/volume_spec.rb index c7ab78d..a1c110f 100644 --- a/spec/defines/volume_spec.rb +++ b/spec/defines/volume_spec.rb @@ -1,49 +1,161 @@ require 'spec_helper' describe 'podman::volume' do - let(:title) { 'testvol' } - let(:params) do - { - ensure: 'present', - user: 'testuser', - } - end - let(:pre_condition) do - 'user {"testuser": - ensure => "present", - home => "/home/testuser", - uid => 5000, - gid => 5000, - managehome => true, - } - file {"/home/testuser": - ensure => "directory", - } - class {"podman": - podman_pkg => "podman", - skopeo_pkg => "skopeo", - buildah_pkg => "buildah", - buildah_pkg_ensure => "installed", - podman_docker_pkg_ensure => "installed", - podman_docker_pkg => "podman-docker", - manage_subuid => true, - file_header => " FILE MANAGED BY PUPPET", - match_subuid_subgid => true, - subid => { - testuser => { - subuid => 5000000, - count => 1000, - }, - }, - nodocker => "file", - }' - end + let(:title) { 'testing-title' } + let(:pre_condition) { 'include podman' } on_supported_os.each do |os, os_facts| - context "on #{os}" do + context "on #{os} with defaults for all parameters" do let(:facts) { os_facts } it { is_expected.to compile } + it { is_expected.to contain_class('podman::install') } + + it do + is_expected.to contain_exec('podman_create_volume_testing-title').only_with( + { + 'command' => 'podman volume create testing-title', + 'unless' => 'podman volume inspect testing-title', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_class('podman::options') } # from podman + it { is_expected.to contain_class('podman::service') } # from podman + it { is_expected.to contain_class('podman') } # from pre_condition + it { is_expected.to contain_file('/etc/containers/nodocker') } # from podman::install + it { is_expected.to contain_package('buildah') } # from podman::install + it { is_expected.to contain_package('podman-compose') } # from podman::install + it { is_expected.to contain_package('podman-docker') } # from podman::install + it { is_expected.to contain_package('podman') } # from podman::install + it { is_expected.to contain_package('skopeo') } # from podman::install + if os_facts[:os]['family'] == 'Archlinux' + it { is_expected.to contain_package('systemd') } # from podman::install + else + it { is_expected.to contain_package('systemd-container') } # from podman::install + end + if os_facts[:os]['selinux']['enabled'] == true + it { is_expected.to contain_selboolean('container_manage_cgroup') } # from podman::install + end + it { is_expected.to contain_service('podman.socket') } # from podman::service + end + end + + # The following tests are OS independent, so we only test one supported OS + redhat = { + supported_os: [ + { + 'operatingsystem' => 'RedHat', + 'operatingsystemrelease' => ['9'], + }, + ], + } + + on_supported_os(redhat).each do |_os, os_facts| + let(:facts) { os_facts } + + context 'with ensure set to valid absent' do + let(:params) { { ensure: 'absent' } } + + it do + is_expected.to contain_exec('podman_remove_volume_testing-title').only_with( + { + 'command' => 'podman volume rm testing-title', + 'unless' => 'podman volume inspect testing-title; test $? -ne 0', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + end + + context 'with flags set to valid hash' do + let(:params) { { flags: { test1: ['242:242'], test2: 'jenkins:/test/ing' } } } + + it do + is_expected.to contain_exec('podman_create_volume_testing-title').only_with( + { + 'command' => "podman volume create --test1 '242:242' --test2 'jenkins:/test/ing' testing-title", + 'unless' => 'podman volume inspect testing-title', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + }, + ) + end + end + + context 'with user set to valid testing' do + let(:params) { { user: 'testing' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it { is_expected.to contain_podman__rootless('testing').only_with({}) } + + it do + is_expected.to contain_exec('podman_create_volume_testing-title').only_with( + { + 'command' => 'podman volume create testing-title', + 'unless' => 'podman volume inspect testing-title', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'provider' => 'shell', + 'user' => 'testing', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + }, + ) + end + + # only here to reach 100% resource coverage + it { is_expected.to contain_exec('loginctl_linger_testing') } # from podman::rootless + it { is_expected.to contain_exec('start_testing.slice') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd') } # from podman::rootless + it { is_expected.to contain_file('/home/testing/.config/systemd/user') } # from podman::rootless + it { is_expected.to contain_service('podman systemd-logind') } # from podman::rootless + end + + context 'with user set to valid testing when ensure is set to valid absent' do + let(:params) { { user: 'testing', ensure: 'absent' } } + let(:pre_condition) do + "include podman + # user & file needed by podman::rootless + user { 'testing': + ensure => 'present', + gid => 1111, + home => '/home/testing', + uid => 3333, + } + file { '/home/testing': } + " + end + + it { is_expected.to contain_podman__rootless('testing').only_with({}) } + + it do + is_expected.to contain_exec('podman_remove_volume_testing-title').only_with( + { + 'command' => 'podman volume rm testing-title', + 'unless' => 'podman volume inspect testing-title; test $? -ne 0', + 'path' => '/sbin:/usr/sbin:/bin:/usr/bin', + 'environment' => ['HOME=/home/testing', 'XDG_RUNTIME_DIR=/run/user/3333', 'DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/3333/bus'], + 'cwd' => '/home/testing', + 'provider' => 'shell', + 'user' => 'testing', + 'require' => ['Podman::Rootless[testing]', 'Service[podman systemd-logind]'], + }, + ) + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b367fde..6820ceb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,8 +25,8 @@ next unless File.exist?(f) && File.readable?(f) && File.size?(f) begin - default_facts.merge!(YAML.safe_load(File.read(f), [], [], true)) - rescue => e + default_facts.merge!(YAML.safe_load(File.read(f), permitted_classes: [], permitted_symbols: [], aliases: true)) + rescue StandardError => e RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" end end @@ -46,6 +46,19 @@ end c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] c.after(:suite) do + RSpec::Puppet::Coverage.report!(0) + end + + # Filter backtrace noise + backtrace_exclusion_patterns = [ + %r{spec_helper}, + %r{gems}, + ] + + if c.respond_to?(:backtrace_exclusion_patterns) + c.backtrace_exclusion_patterns = backtrace_exclusion_patterns + elsif c.respond_to?(:backtrace_clean_patterns) + c.backtrace_clean_patterns = backtrace_exclusion_patterns end end