diff --git a/files/concatfragments.rb b/files/concatfragments.rb index 904f824..b16f3e1 100644 --- a/files/concatfragments.rb +++ b/files/concatfragments.rb @@ -1,150 +1,153 @@ #!/usr/bin/env ruby # Script to concat files to a config file. # # Given a directory like this: # /path/to/conf.d # |-- fragments # | |-- 00_named.conf # | |-- 10_domain.net # | `-- zz_footer # # The script supports a test option that will build the concat file to a temp location and # use /usr/bin/cmp to verify if it should be run or not. This would result in the concat happening # twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds. # # Without the test option and the unless combo your services that depend on the final file would end up # restarting on each run, or in other manifest models some changes might get missed. # # OPTIONS: # -o The file to create from the sources # -d The directory where the fragments are kept # -t Test to find out if a build is needed, basically concats the files to a temp # location and compare with what's in the final location, return codes are designed # for use with unless on an exec resource # -w Add a shell style comment at the top of the created file to warn users that it # is generated by puppet # -f Enables the creation of empty output files when no fragments are found # -n Sort the output numerically rather than the default alpha sort # # the command: # # concatfragments.rb -o /path/to/conffile.cfg -d /path/to/conf.d # # creates /path/to/conf.d/fragments.concat and copies the resulting # file to /path/to/conffile.cfg. The files will be sorted alphabetically # pass the -n switch to sort numerically. # # The script does error checking on the various dirs and files to make # sure things don't fail. require 'optparse' require 'fileutils' settings = { - :outfile => "", - :workdir => "", - :test => false, - :force => false, - :warn => "", - :sortarg => "", - :newline => false + :outfile => "", + :workdir => "", + :test => false, + :force => false, + :warn => "", + :sortarg => "", + :newline => false } OptionParser.new do |opts| opts.banner = "Usage: #{$0} [options]" opts.separator "Specific options:" opts.on("-o", "--outfile OUTFILE", String, "The file to create from the sources") do |o| settings[:outfile] = o end opts.on("-d", "--workdir WORKDIR", String, "The directory where the fragments are kept") do |d| settings[:workdir] = d end opts.on("-t", "--test", "Test to find out if a build is needed") do settings[:test] = true end opts.separator "Other options:" opts.on("-w", "--warn WARNMSG", String, "Add a shell style comment at the top of the created file to warn users that it is generated by puppet") do |w| settings[:warn] = w end opts.on("-f", "--force", "Enables the creation of empty output files when no fragments are found") do settings[:force] = true end opts.on("-n", "--sort", "Sort the output numerically rather than the default alpha sort") do settings[:sortarg] = "-n" end opts.on("-l", "--line", "Append a newline") do settings[:newline] = true end end.parse! # do we have -o? raise 'Please specify an output file with -o' unless !settings[:outfile].empty? # do we have -d? raise 'Please specify fragments directory with -d' unless !settings[:workdir].empty? # can we write to -o? if File.file?(settings[:outfile]) if !File.writable?(settings[:outfile]) raise "Cannot write to #{settings[:outfile]}" end else if !File.writable?(File.dirname(settings[:outfile])) raise "Cannot write to dirname #{File.dirname(settings[:outfile])} to create #{settings[:outfile]}" end end # do we have a fragments subdir inside the work dir? if !File.directory?(File.join(settings[:workdir], "fragments")) && !File.executable?(File.join(settings[:workdir], "fragments")) raise "Cannot access the fragments directory" end # are there actually any fragments? if (Dir.entries(File.join(settings[:workdir], "fragments")) - %w{ . .. }).empty? if !settings[:force] raise "The fragments directory is empty, cowardly refusing to make empty config files" end end Dir.chdir(settings[:workdir]) if settings[:warn].empty? - File.open("fragments.concat", 'w') {|f| f.write("") } + File.open("fragments.concat", 'w') { |f| f.write("") } else - File.open("fragments.concat", 'w') {|f| f.write("#{settings[:warn]}\n") } + File.open("fragments.concat", 'w') { |f| f.write("#{settings[:warn]}\n") } end # find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir open('fragments.concat', 'a') do |f| - Dir.entries("fragments").sort.each{ |entry| - + fragments = Dir.entries("fragments").sort + if settings[:sortarg] == '-n' + fragments = fragments.sort_by { |v| v.split('_').map(&:to_i) } + end + fragments.each { |entry| if File.file?(File.join("fragments", entry)) f << File.read(File.join("fragments", entry)) # append a newline if we were asked to (invoked with -l) if settings[:newline] f << "\n" end end } end if !settings[:test] # This is a real run, copy the file to outfile FileUtils.cp 'fragments.concat', settings[:outfile] else # Just compare the result to outfile to help the exec decide if FileUtils.cmp 'fragments.concat', settings[:outfile] exit 0 else exit 1 end end diff --git a/spec/acceptance/concat_spec.rb b/spec/acceptance/concat_spec.rb index 7cec1a5..7a6d95c 100644 --- a/spec/acceptance/concat_spec.rb +++ b/spec/acceptance/concat_spec.rb @@ -1,215 +1,217 @@ require 'spec_helper_acceptance' case fact('osfamily') -when 'AIX' - username = 'root' - groupname = 'system' - scriptname = 'concatfragments.sh' - vardir = default['puppetvardir'] -when 'Darwin' - username = 'root' - groupname = 'wheel' - scriptname = 'concatfragments.sh' - vardir = default['puppetvardir'] -when 'windows' - username = 'Administrator' - groupname = 'Administrators' - scriptname = 'concatfragments.rb' - result = on default, "echo #{default['puppetvardir']}" - vardir = result.raw_output.chomp -when 'Solaris' - username = 'root' - groupname = 'root' - scriptname = 'concatfragments.rb' - vardir = default['puppetvardir'] -else - username = 'root' - groupname = 'root' - scriptname = 'concatfragments.sh' - vardir = default['puppetvardir'] + when 'AIX' + username = 'root' + groupname = 'system' + scriptname = 'concatfragments.sh' + vardir = default['puppetvardir'] + when 'Darwin' + username = 'root' + groupname = 'wheel' + scriptname = 'concatfragments.sh' + vardir = default['puppetvardir'] + when 'windows' + username = 'Administrator' + groupname = 'Administrators' + scriptname = 'concatfragments.rb' + result = on default, "echo #{default['puppetvardir']}" + vardir = result.raw_output.chomp + when 'Solaris' + username = 'root' + groupname = 'root' + scriptname = 'concatfragments.rb' + vardir = default['puppetvardir'] + else + username = 'root' + groupname = 'root' + scriptname = 'concatfragments.sh' + vardir = default['puppetvardir'] end describe 'basic concat test' do basedir = default.tmpdir('concat') - safe_basedir = basedir.gsub(/[\/:]/,'_') + safe_basedir = basedir.gsub(/[\/:]/, '_') shared_examples 'successfully_applied' do |pp| it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{vardir}/concat") do it { should be_directory } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 755 } end - describe file("#{vardir}/concat/bin") do + describe file("#{vardir}/concat/bin") do it { should be_directory } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 755 } end describe file("#{vardir}/concat/bin/#{scriptname}") do it { should be_file } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 755 } end describe file("#{vardir}/concat/#{safe_basedir}_file") do it { should be_directory } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 750 } end describe file("#{vardir}/concat/#{safe_basedir}_file/fragments") do it { should be_directory } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 750 } end describe file("#{vardir}/concat/#{safe_basedir}_file/fragments.concat") do it { should be_file } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 640 } end describe file("#{vardir}/concat/#{safe_basedir}_file/fragments.concat.out") do it { should be_file } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 640 } end end context 'owner/group root' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': owner => '#{username}', group => '#{groupname}', mode => '0644', } concat::fragment { '1': target => '#{basedir}/file', content => '1', order => '01', } concat::fragment { '2': target => '#{basedir}/file', content => '2', order => '02', } EOS it_behaves_like 'successfully_applied', pp describe file("#{basedir}/file") do it { should be_file } it { should be_owned_by username } it("should be group", :unless => (fact('osfamily') == 'windows')) { should be_grouped_into groupname } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 644 } - it { should contain '1' } - it { should contain '2' } + its(:content) { + should match '1' + should match '2' + } end describe file("#{vardir}/concat/#{safe_basedir}_file/fragments/01_1") do it { should be_file } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 640 } end describe file("#{vardir}/concat/#{safe_basedir}_file/fragments/02_2") do it { should be_file } it { should be_owned_by username } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 640 } end end context 'ensure' do context 'works when set to present with path set' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp=" concat { 'file': ensure => present, path => '#{basedir}/file', mode => '0644', } concat::fragment { '1': target => 'file', content => '1', order => '01', } " it_behaves_like 'successfully_applied', pp describe file("#{basedir}/file") do it { should be_file } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 644 } - it { should contain '1' } + its(:content) { should match '1' } end end context 'works when set to absent with path set' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp=" concat { 'file': ensure => absent, path => '#{basedir}/file', mode => '0644', } concat::fragment { '1': target => 'file', content => '1', order => '01', } " it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should_not be_file } end end end end diff --git a/spec/acceptance/deprecation_warnings_spec.rb b/spec/acceptance/deprecation_warnings_spec.rb index dc2f234..11133ea 100644 --- a/spec/acceptance/deprecation_warnings_spec.rb +++ b/spec/acceptance/deprecation_warnings_spec.rb @@ -1,232 +1,238 @@ require 'spec_helper_acceptance' describe 'deprecation warnings' do basedir = default.tmpdir('concat') - shared_examples 'has_warning'do |pp, w| + shared_examples 'has_warning' do |pp, w| it 'applies the manifest twice with a stderr regex' do expect(apply_manifest(pp, :catch_failures => true).stderr).to match(/#{Regexp.escape(w)}/m) expect(apply_manifest(pp, :catch_changes => true).stderr).to match(/#{Regexp.escape(w)}/m) end end context 'concat gnu parameter' do pp = <<-EOS concat { '#{basedir}/file': gnu => 'foo', } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', } EOS w = 'The $gnu parameter to concat is deprecated and has no effect' it_behaves_like 'has_warning', pp, w end context 'concat warn parameter =>' do ['true', 'yes', 'on'].each do |warn| context warn do pp = <<-EOS concat { '#{basedir}/file': warn => '#{warn}', } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', } EOS w = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release' it_behaves_like 'has_warning', pp, w describe file("#{basedir}/file") do it { should be_file } - it { should contain '# This file is managed by Puppet. DO NOT EDIT.' } - it { should contain 'bar' } + its(:content) { + should match '# This file is managed by Puppet. DO NOT EDIT.' + should match 'bar' + } end end end ['false', 'no', 'off'].each do |warn| context warn do pp = <<-EOS concat { '#{basedir}/file': warn => '#{warn}', } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', } EOS w = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release' it_behaves_like 'has_warning', pp, w describe file("#{basedir}/file") do it { should be_file } - it { should_not contain '# This file is managed by Puppet. DO NOT EDIT.' } - it { should contain 'bar' } + its(:content) { + should_not match '# This file is managed by Puppet. DO NOT EDIT.' + should match 'bar' + } end end end end context 'concat::fragment ensure parameter', :unless => fact('osfamily') == 'windows' do context 'target file exists' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/file1': content => "file1 contents\n", } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', ensure => '#{basedir}/file1', } EOS w = 'Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated. If you want to use the content of a file as a fragment please use the $source parameter.' it_behaves_like 'has_warning', pp, w describe file("#{basedir}/file") do it { should be_file } - it { should contain 'file1 contents' } + its(:content) { should match 'file1 contents' } end describe 'the fragment can be changed from a symlink to a plain file', :unless => (fact("osfamily") == "windows") do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', content => 'new content', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain 'new content' } - it { should_not contain 'file1 contents' } + its(:content) { + should match 'new content' + should_not match 'file1 contents' + } end end end # target file exists context 'target does not exist', :unless => fact('osfamily') == 'windows' do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', ensure => '#{basedir}/file1', } EOS w = 'Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated. If you want to use the content of a file as a fragment please use the $source parameter.' it_behaves_like 'has_warning', pp, w describe file("#{basedir}/file") do it { should be_file } end describe 'the fragment can be changed from a symlink to a plain file', :unless => (fact('osfamily') == 'windows') do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', content => 'new content', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain 'new content' } + its(:content) { should match 'new content' } end end end # target file exists end # concat::fragment ensure parameter context 'concat::fragment mode parameter' do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', mode => 'bar', } EOS w = 'The $mode parameter to concat::fragment is deprecated and has no effect' it_behaves_like 'has_warning', pp, w end context 'concat::fragment owner parameter' do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', owner => 'bar', } EOS w = 'The $owner parameter to concat::fragment is deprecated and has no effect' it_behaves_like 'has_warning', pp, w end context 'concat::fragment group parameter' do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', group => 'bar', } EOS w = 'The $group parameter to concat::fragment is deprecated and has no effect' it_behaves_like 'has_warning', pp, w end context 'concat::fragment backup parameter' do pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { 'foo': target => '#{basedir}/file', content => 'bar', backup => 'bar', } EOS w = 'The $backup parameter to concat::fragment is deprecated and has no effect' it_behaves_like 'has_warning', pp, w end context 'include concat::setup' do pp = <<-EOS include concat::setup EOS w = 'concat::setup is deprecated as a public API of the concat module and should no longer be directly included in the manifest.' it_behaves_like 'has_warning', pp, w end end diff --git a/spec/acceptance/empty_spec.rb b/spec/acceptance/empty_spec.rb index dc57cb7..4ab6e1e 100644 --- a/spec/acceptance/empty_spec.rb +++ b/spec/acceptance/empty_spec.rb @@ -1,23 +1,23 @@ require 'spec_helper_acceptance' describe 'concat force empty parameter' do basedir = default.tmpdir('concat') context 'should run successfully' do pp = <<-EOS concat { '#{basedir}/file': mode => '0644', force => true, } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should_not contain '1\n2' } + its(:content) { should_not match /1\n2/ } end end end diff --git a/spec/acceptance/fragment_source_spec.rb b/spec/acceptance/fragment_source_spec.rb index f3bbfcc..a174e02 100644 --- a/spec/acceptance/fragment_source_spec.rb +++ b/spec/acceptance/fragment_source_spec.rb @@ -1,149 +1,157 @@ require 'spec_helper_acceptance' case fact('osfamily') -when 'AIX' - username = 'root' - groupname = 'system' -when 'Darwin' - username = 'root' - groupname = 'wheel' -when 'windows' - username = 'Administrator' - groupname = 'Administrators' -else - username = 'root' - groupname = 'root' + when 'AIX' + username = 'root' + groupname = 'system' + when 'Darwin' + username = 'root' + groupname = 'wheel' + when 'windows' + username = 'Administrator' + groupname = 'Administrators' + else + username = 'root' + groupname = 'root' end describe 'concat::fragment source' do basedir = default.tmpdir('concat') context 'should read file fragments from local system' do pp = <<-EOS file { '#{basedir}/file1': content => "file1 contents\n" } file { '#{basedir}/file2': content => "file2 contents\n" } concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', source => '#{basedir}/file1', require => File['#{basedir}/file1'], } concat::fragment { '2': target => '#{basedir}/foo', content => 'string1 contents', } concat::fragment { '3': target => '#{basedir}/foo', source => '#{basedir}/file2', require => File['#{basedir}/file2'], } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/foo") do it { should be_file } - it { should contain 'file1 contents' } - it { should contain 'string1 contents' } - it { should contain 'file2 contents' } + its(:content) { + should match 'file1 contents' + should match 'string1 contents' + should match 'file2 contents' + } end end # should read file fragments from local system context 'should create files containing first match only.' do pp = <<-EOS file { '#{basedir}/file1': content => "file1 contents\n" } file { '#{basedir}/file2': content => "file2 contents\n" } concat { '#{basedir}/result_file1': owner => '#{username}', group => '#{groupname}', mode => '0644', } concat { '#{basedir}/result_file2': owner => '#{username}', group => '#{groupname}', mode => '0644', } concat { '#{basedir}/result_file3': owner => '#{username}', group => '#{groupname}', mode => '0644', } concat::fragment { '1': target => '#{basedir}/result_file1', source => [ '#{basedir}/file1', '#{basedir}/file2' ], require => [ File['#{basedir}/file1'], File['#{basedir}/file2'] ], order => '01', } concat::fragment { '2': target => '#{basedir}/result_file2', source => [ '#{basedir}/file2', '#{basedir}/file1' ], require => [ File['#{basedir}/file1'], File['#{basedir}/file2'] ], order => '01', } concat::fragment { '3': target => '#{basedir}/result_file3', source => [ '#{basedir}/file1', '#{basedir}/file2' ], require => [ File['#{basedir}/file1'], File['#{basedir}/file2'] ], order => '01', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/result_file1") do it { should be_file } - it { should contain 'file1 contents' } - it { should_not contain 'file2 contents' } + its(:content) { + should match 'file1 contents' + should_not match 'file2 contents' + } end describe file("#{basedir}/result_file2") do it { should be_file } - it { should contain 'file2 contents' } - it { should_not contain 'file1 contents' } + its(:content) { + should match 'file2 contents' + should_not match 'file1 contents' + } end describe file("#{basedir}/result_file3") do it { should be_file } - it { should contain 'file1 contents' } - it { should_not contain 'file2 contents' } + its(:content) { + should match 'file1 contents' + should_not match 'file2 contents' + } end end context 'should fail if no match on source.' do pp = <<-EOS concat { '#{basedir}/fail_no_source': owner => '#{username}', group => '#{groupname}', mode => '0644', } concat::fragment { '1': target => '#{basedir}/fail_no_source', source => [ '#{basedir}/nofilehere', '#{basedir}/nothereeither' ], order => '01', } EOS it 'applies the manifest with resource failures' do apply_manifest(pp, :expect_failures => true) end describe file("#{basedir}/fail_no_source") do #FIXME: Serverspec::Type::File doesn't support exists? for some reason. so... hack. it { should_not be_file } it { should_not be_directory } end end end diff --git a/spec/acceptance/fragments_are_always_replaced_spec.rb b/spec/acceptance/fragments_are_always_replaced_spec.rb index ac714a9..70d7382 100644 --- a/spec/acceptance/fragments_are_always_replaced_spec.rb +++ b/spec/acceptance/fragments_are_always_replaced_spec.rb @@ -1,133 +1,139 @@ require 'spec_helper_acceptance' describe 'concat::fragment replace' do basedir = default.tmpdir('concat') context 'should create fragment files' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp1 = <<-EOS concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'caller has replace unset run 1', } EOS pp2 = <<-EOS concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'caller has replace unset run 2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp1, :catch_failures => true) apply_manifest(pp1, :catch_changes => true) apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) end describe file("#{basedir}/foo") do it { should be_file } - it { should_not contain 'caller has replace unset run 1' } - it { should contain 'caller has replace unset run 2' } + its(:content) { + should_not match 'caller has replace unset run 1' + should match 'caller has replace unset run 2' + } end end # should create fragment files context 'should replace its own fragment files when caller has File { replace=>true } set' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp1 = <<-EOS File { replace=>true } concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'caller has replace true set run 1', } EOS pp2 = <<-EOS File { replace=>true } concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'caller has replace true set run 2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp1, :catch_failures => true) apply_manifest(pp1, :catch_changes => true) apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) end describe file("#{basedir}/foo") do it { should be_file } - it { should_not contain 'caller has replace true set run 1' } - it { should contain 'caller has replace true set run 2' } + its(:content) { + should_not match 'caller has replace true set run 1' + should match 'caller has replace true set run 2' + } end end # should replace its own fragment files when caller has File(replace=>true) set context 'should replace its own fragment files even when caller has File { replace=>false } set' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp1 = <<-EOS File { replace=>false } concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'caller has replace false set run 1', } EOS pp2 = <<-EOS File { replace=>false } concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'caller has replace false set run 2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp1, :catch_failures => true) apply_manifest(pp1, :catch_changes => true) apply_manifest(pp2, :catch_failures => true) apply_manifest(pp2, :catch_changes => true) end describe file("#{basedir}/foo") do it { should be_file } - it { should_not contain 'caller has replace false set run 1' } - it { should contain 'caller has replace false set run 2' } + its(:content) { + should_not match 'caller has replace false set run 1' + should match 'caller has replace false set run 2' + } end end # should replace its own fragment files even when caller has File(replace=>false) set end diff --git a/spec/acceptance/newline_spec.rb b/spec/acceptance/newline_spec.rb index d182f2a..c1fa16a 100644 --- a/spec/acceptance/newline_spec.rb +++ b/spec/acceptance/newline_spec.rb @@ -1,67 +1,67 @@ require 'spec_helper_acceptance' describe 'concat ensure_newline parameter' do basedir = default.tmpdir('concat') context '=> false' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': ensure_newline => false, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain '12' } + its(:content) { should match '12' } end end context '=> true' do pp = <<-EOS concat { '#{basedir}/file': ensure_newline => true, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) + apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it("should contain 1\n2\n", :unless => (fact('osfamily') == 'Solaris')) { - should contain "1\n2\n" + its(:content) { + should match /1\n2\n/ } end end end diff --git a/spec/acceptance/order_spec.rb b/spec/acceptance/order_spec.rb index fd7b05b..c158dd8 100644 --- a/spec/acceptance/order_spec.rb +++ b/spec/acceptance/order_spec.rb @@ -1,143 +1,123 @@ require 'spec_helper_acceptance' describe 'concat order' do basedir = default.tmpdir('concat') - context '=> alpha' do - pp = <<-EOS + context '=> ' do + shared_examples 'sortby' do |order_by, match_output| + pp = <<-EOS concat { '#{basedir}/foo': - order => 'alpha' + order => '#{order_by}' } concat::fragment { '1': target => '#{basedir}/foo', content => 'string1', + order => '1', } concat::fragment { '2': target => '#{basedir}/foo', content => 'string2', + order => '2', } concat::fragment { '10': target => '#{basedir}/foo', content => 'string10', } - EOS + EOS - it 'applies the manifest twice with no stderr' do - apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) - end + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end - describe file("#{basedir}/foo") do - it { should be_file } - #XXX Solaris 10 doesn't support multi-line grep - it("should contain string10\nstring1\nsring2", :unless => (fact('osfamily') == 'Solaris')) { - should contain "string10\nstring1\nsring2" - } + describe file("#{basedir}/foo") do + it { should be_file } + its(:content) { should match match_output } + end end - end - context '=> numeric' do - pp = <<-EOS - concat { '#{basedir}/foo': - order => 'numeric' - } - concat::fragment { '1': - target => '#{basedir}/foo', - content => 'string1', - } - concat::fragment { '2': - target => '#{basedir}/foo', - content => 'string2', - } - concat::fragment { '10': - target => '#{basedir}/foo', - content => 'string10', - } - EOS - - it 'applies the manifest twice with no stderr' do - apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) + describe 'alpha' do + it_behaves_like 'sortby', 'alpha', /string10string1string2/ end - describe file("#{basedir}/foo") do - it { should be_file } - #XXX Solaris 10 doesn't support multi-line grep - it("should contain string1\nstring2\nsring10", :unless => (fact('osfamily') == 'Solaris')) { - should contain "string1\nstring2\nsring10" - } + describe 'numeric' do + it_behaves_like 'sortby', 'numeric', /string1string2string10/ end end end # concat order describe 'concat::fragment order' do basedir = default.tmpdir('concat') context '=> reverse order' do - pp = <<-EOS - concat { '#{basedir}/foo': } + shared_examples 'order_by' do |order_by, match_output| + pp = <<-EOS + concat { '#{basedir}/foo': + order => '#{order_by}' + } concat::fragment { '1': target => '#{basedir}/foo', content => 'string1', order => '15', } concat::fragment { '2': target => '#{basedir}/foo', content => 'string2', # default order 10 } concat::fragment { '3': target => '#{basedir}/foo', content => 'string3', order => '1', } - EOS + EOS - it 'applies the manifest twice with no stderr' do - apply_manifest(pp, :catch_failures => true) - apply_manifest(pp, :catch_changes => true) - end + it 'applies the manifest twice with no stderr' do + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end - describe file("#{basedir}/foo") do - it { should be_file } - #XXX Solaris 10 doesn't support multi-line grep - it("should contain string3\nstring2\nsring1", :unless => (fact('osfamily') == 'Solaris')) { - should contain "string3\nstring2\nsring1" - } + describe file("#{basedir}/foo") do + it { should be_file } + its(:content) { should match match_output } + end + end + describe 'alpha' do + it_should_behave_like 'order_by', 'alpha', /string2string1string3/ + end + describe 'numeric' do + it_should_behave_like 'order_by', 'numeric', /string3string2string1/ end end context '=> normal order' do pp = <<-EOS concat { '#{basedir}/foo': } concat::fragment { '1': target => '#{basedir}/foo', content => 'string1', order => '01', } concat::fragment { '2': target => '#{basedir}/foo', content => 'string2', order => '02' } concat::fragment { '3': target => '#{basedir}/foo', content => 'string3', order => '03', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/foo") do it { should be_file } - #XXX Solaris 10 doesn't support multi-line grep - it("should contain string1\nstring2\nsring3", :unless => (fact('osfamily') == 'Solaris')) { - should contain "string1\nstring2\nsring3" - } + its(:content) { should match /string1string2string3/ } end end end # concat::fragment order diff --git a/spec/acceptance/quoted_paths_spec.rb b/spec/acceptance/quoted_paths_spec.rb index 165c153..042425f 100644 --- a/spec/acceptance/quoted_paths_spec.rb +++ b/spec/acceptance/quoted_paths_spec.rb @@ -1,44 +1,42 @@ require 'spec_helper_acceptance' describe 'quoted paths' do basedir = default.tmpdir('concat') before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/concat test': ensure => directory, } EOS apply_manifest(pp) end context 'path with blanks' do pp = <<-EOS concat { '#{basedir}/concat test/foo': } concat::fragment { '1': target => '#{basedir}/concat test/foo', content => 'string1', } concat::fragment { '2': target => '#{basedir}/concat test/foo', content => 'string2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/concat test/foo") do it { should be_file } - it("should contain string1\nstring2", :unless => (fact('osfamily') == 'Solaris')) { - should contain "string1\nstring2" - } + its(:content) { should match /string1string2/ } end end end diff --git a/spec/acceptance/replace_spec.rb b/spec/acceptance/replace_spec.rb index 6882345..bd597ed 100644 --- a/spec/acceptance/replace_spec.rb +++ b/spec/acceptance/replace_spec.rb @@ -1,256 +1,262 @@ require 'spec_helper_acceptance' describe 'replacement of' do basedir = default.tmpdir('concat') context 'file' do context 'should not succeed' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/file': content => "file exists\n" } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': replace => false, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain 'file exists' } - it { should_not contain '1' } - it { should_not contain '2' } + its(:content) { + should match 'file exists' + should_not match '1' + should_not match '2' + } end end context 'should succeed' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/file': content => "file exists\n" } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': replace => true, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should_not contain 'file exists' } - it { should contain '1' } - it { should contain '2' } + its(:content) { + should_not match 'file exists' + should match '1' + should match '2' + } end end end # file context 'symlink', :unless => (fact("osfamily") == "windows") do context 'should not succeed' do # XXX the core puppet file type will replace a symlink with a plain file # when using ensure => present and source => ... but it will not when using # ensure => present and content => ...; this is somewhat confusing behavior before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/file': ensure => link, target => '#{basedir}/dangling', } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': replace => false, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end # XXX specinfra doesn't support be_linked_to on AIX describe file("#{basedir}/file"), :unless => (fact("osfamily") == "AIX" or fact("osfamily") == "windows") do it { should be_linked_to "#{basedir}/dangling" } end describe file("#{basedir}/dangling") do # XXX serverspec does not have a matcher for 'exists' it { should_not be_file } it { should_not be_directory } end end context 'should succeed' do # XXX the core puppet file type will replace a symlink with a plain file # when using ensure => present and source => ... but it will not when using # ensure => present and content => ...; this is somewhat confusing behavior before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/file': ensure => link, target => '#{basedir}/dangling', } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': replace => true, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain '1' } - it { should contain '2' } + its(:content) { + should match '1' + should match '2' + } end end end # symlink context 'directory' do context 'should not succeed' do before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } file { '#{basedir}/file': ensure => directory, } EOS apply_manifest(pp) end pp = <<-EOS concat { '#{basedir}/file': } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with stderr for changing to file' do expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/change from directory to file failed/) expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/change from directory to file failed/) end describe file("#{basedir}/file") do it { should be_directory } end end # XXX concat's force param currently enables the creation of empty files # when there are no fragments, and the replace param will only replace # files and symlinks, not directories. The semantics either need to be # changed, extended, or a new param introduced to control directory # replacement. context 'should succeed', :pending => 'not yet implemented' do pp = <<-EOS concat { '#{basedir}/file': force => true, } concat::fragment { '1': target => '#{basedir}/file', content => '1', } concat::fragment { '2': target => '#{basedir}/file', content => '2', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain '1' } + its(:content) { should match '1' } end end end # directory end diff --git a/spec/acceptance/specinfra_stubs.rb b/spec/acceptance/specinfra_stubs.rb new file mode 100644 index 0000000..d42e1c0 --- /dev/null +++ b/spec/acceptance/specinfra_stubs.rb @@ -0,0 +1,18 @@ +class Specinfra::Command::Windows::Base::File < Specinfra::Command::Windows::Base + class << self + def check_is_owned_by(file, owner) + Backend::PowerShell::Command.new do + exec "((gci '#{file}').GetAccessControl().Owner -match '#{owner}').Length -gt 0" + end + end + end +end + + +class Specinfra::Command::Base::File < Specinfra::Command::Base + class << self + def get_content(file) + "cat '#{file}' 2> /dev/null || echo -n" + end + end +end diff --git a/spec/acceptance/symbolic_name_spec.rb b/spec/acceptance/symbolic_name_spec.rb index b0dceac..df8d54f 100644 --- a/spec/acceptance/symbolic_name_spec.rb +++ b/spec/acceptance/symbolic_name_spec.rb @@ -1,33 +1,35 @@ require 'spec_helper_acceptance' describe 'symbolic name' do basedir = default.tmpdir('concat') pp = <<-EOS concat { 'not_abs_path': path => '#{basedir}/file', } concat::fragment { '1': target => 'not_abs_path', content => '1', order => '01', } concat::fragment { '2': target => 'not_abs_path', content => '2', order => '02', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain '1' } - it { should contain '2' } + its(:content) { + should match '1' + should match '2' + } end end diff --git a/spec/acceptance/warn_spec.rb b/spec/acceptance/warn_spec.rb index 2fa529d..7101f61 100644 --- a/spec/acceptance/warn_spec.rb +++ b/spec/acceptance/warn_spec.rb @@ -1,98 +1,102 @@ require 'spec_helper_acceptance' describe 'concat warn =>' do basedir = default.tmpdir('concat') context 'true should enable default warning message' do pp = <<-EOS concat { '#{basedir}/file': warn => true, } concat::fragment { '1': target => '#{basedir}/file', content => '1', order => '01', } concat::fragment { '2': target => '#{basedir}/file', content => '2', order => '02', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain '# This file is managed by Puppet. DO NOT EDIT.' } - it { should contain '1' } - it { should contain '2' } + its(:content) { + should match '# This file is managed by Puppet. DO NOT EDIT.' + should match '1' + should match '2' + } end end context 'false should not enable default warning message' do pp = <<-EOS concat { '#{basedir}/file': warn => false, } concat::fragment { '1': target => '#{basedir}/file', content => '1', order => '01', } concat::fragment { '2': target => '#{basedir}/file', content => '2', order => '02', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } it { should_not contain '# This file is managed by Puppet. DO NOT EDIT.' } it { should contain '1' } it { should contain '2' } end end context '# foo should overide default warning message' do pp = <<-EOS concat { '#{basedir}/file': warn => '# foo', } concat::fragment { '1': target => '#{basedir}/file', content => '1', order => '01', } concat::fragment { '2': target => '#{basedir}/file', content => '2', order => '02', } EOS it 'applies the manifest twice with no stderr' do apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) end describe file("#{basedir}/file") do it { should be_file } - it { should contain '# foo' } - it { should contain '1' } - it { should contain '2' } + its(:content) { + should match '# foo' + should match '1' + should match '2' + } end end end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index aef9f39..da994f8 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,59 +1,61 @@ require 'beaker-rspec/spec_helper' require 'beaker-rspec/helpers/serverspec' +require 'acceptance/specinfra_stubs' unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no' # This will install the latest available package on el and deb based # systems fail on windows and osx, and install via gem on other *nixes foss_opts = {:default_action => 'gem_install'} if default.is_pe?; then install_pe; else install_puppet(foss_opts); end hosts.each do |host| on hosts, "mkdir -p #{host['distmoduledir']}" if host['platform'] =~ /sles-1/i || host['platform'] =~ /solaris-1/i get_stdlib = <<-EOS package{'wget':} exec{'download': - command => "wget -P /root/ https://forgeapi.puppetlabs.com/v3/files/puppetlabs-stdlib-4.3.2.tar.gz --no-check-certificate", + command => "wget -P /root/ https://forgeapi.puppetlabs.com/v3/files/puppetlabs-stdlib-4.5.1.tar.gz --no-check-certificate", path => ['/opt/csw/bin/','/usr/bin/'] } EOS apply_manifest_on(host, get_stdlib) # have to use force otherwise it checks ssl cert even though it is a local file - on host, puppet('module install /root/puppetlabs-stdlib-4.3.2.tar.gz --force --ignore-dependencies'), {:acceptable_exit_codes => [0, 1]} + on host, puppet('module install /root/puppetlabs-stdlib-4.5.1.tar.gz --force --ignore-dependencies'), {:acceptable_exit_codes => [0, 1]} elsif host['platform'] =~ /windows/i - on host, shell('curl -k -o c:/puppetlabs-stdlib-4.3.2.tar.gz https://forgeapi.puppetlabs.com/v3/files/puppetlabs-stdlib-4.3.2.tar.gz') - on host, puppet('module install c:/puppetlabs-stdlib-4.3.2.tar.gz --force --ignore-dependencies'), {:acceptable_exit_codes => [0, 1]} + on host, shell('curl -k -o c:/puppetlabs-stdlib-4.5.1.tar.gz https://forgeapi.puppetlabs.com/v3/files/puppetlabs-stdlib-4.5.1.tar.gz') + on host, puppet('module install c:/puppetlabs-stdlib-4.5.1.tar.gz --force --ignore-dependencies'), {:acceptable_exit_codes => [0, 1]} else on host, puppet('module install puppetlabs-stdlib'), {:acceptable_exit_codes => [0, 1]} end end end RSpec.configure do |c| # Project root proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) # Readable test descriptions c.formatter = :documentation # Configure all nodes in nodeset c.before :suite do hosts.each do |host| copy_module_to(host, :source => proj_root, :module_name => 'concat') end end c.before(:all) do shell('mkdir -p /tmp/concat') end c.after(:all) do shell('rm -rf /tmp/concat /var/lib/puppet/concat') end c.treat_symbols_as_metadata_keys_with_true_values = true end +