diff --git a/lib/puppet/type/concat_file.rb b/lib/puppet/type/concat_file.rb index dd4316c..d1c0c9c 100644 --- a/lib/puppet/type/concat_file.rb +++ b/lib/puppet/type/concat_file.rb @@ -1,208 +1,217 @@ require 'puppet/type/file/owner' require 'puppet/type/file/group' require 'puppet/type/file/mode' require 'puppet/util/checksums' Puppet::Type.newtype(:concat_file) do @doc = "Gets all the file fragments and puts these into the target file. This will mostly be used with exported resources. example: Concat_fragment <<| tag == 'unique_tag' |>> concat_file { '/tmp/file': tag => 'unique_tag', # Mandatory path => '/tmp/file', # Optional. If given it overrides the resource name owner => 'root', # Optional. Default to undef group => 'root', # Optional. Default to undef mode => '0644' # Optional. Default to undef order => 'numeric' # Optional, Default to 'numeric' ensure_newline => false # Optional, Defaults to false } " ensurable do defaultvalues defaultto { :present } end def exists? self[:ensure] == :present end newparam(:name, :namevar => true) do desc "Resource name" end newparam(:tag) do desc "Tag reference to collect all concat_fragment's with the same tag" end newparam(:path) do desc "The output file" defaultto do resource.value(:name) end end newparam(:owner, :parent => Puppet::Type::File::Owner) do desc "Desired file owner." end newparam(:group, :parent => Puppet::Type::File::Group) do desc "Desired file group." end newparam(:mode, :parent => Puppet::Type::File::Mode) do desc "Desired file mode." end newparam(:order) do desc "Controls the ordering of fragments. Can be set to alphabetical or numeric." defaultto 'numeric' end newparam(:backup) do desc "Controls the filebucketing behavior of the final file and see File type reference for its use." defaultto 'puppet' end newparam(:replace) do desc "Whether to replace a file that already exists on the local system." defaultto true end newparam(:validate_cmd) do desc "Validates file." end newparam(:ensure_newline) do desc "Whether to ensure there is a newline after each fragment." defaultto false end # Inherit File parameters newparam(:selinux_ignore_defaults) do end newparam(:selrange) do end newparam(:selrole) do end newparam(:seltype) do end newparam(:seluser) do end newparam(:show_diff) do end # End file parameters autorequire(:concat_fragment) do catalog.resources.collect do |r| if r.is_a?(Puppet::Type.type(:concat_fragment)) && r[:tag] == self[:tag] r.name end end.compact end # Autorequire the file we are generating below autorequire(:file) do [self[:path]] end def should_content return @generated_content if @generated_content @generated_content = "" content_fragments = [] resources = catalog.resources.select do |r| r.is_a?(Puppet::Type.type(:concat_fragment)) && r[:tag] == self[:tag] end resources.each do |r| content_fragments << ["#{r[:order]}___#{r[:name]}", fragment_content(r)] end if self[:order] == 'numeric' sorted = content_fragments.sort do |a, b| def decompound(d) d.split('___').map { |v| v =~ /^\d+$/ ? v.to_i : v } end decompound(a[0]) <=> decompound(b[0]) end else sorted = content_fragments.sort_by do |a| a_order, a_name = a[0].split('__') [a_order, a_name] end end @generated_content = sorted.map { |cf| cf[1] }.join @generated_content end def fragment_content(r) if r[:content].nil? == false fragment_content = r[:content] elsif r[:source].nil? == false @source = nil Array(r[:source]).each do |source| if Puppet::FileServing::Metadata.indirection.find(source) @source = source break end end self.fail "Could not retrieve source(s) #{r[:source].join(", ")}" unless @source tmp = Puppet::FileServing::Content.indirection.find(@source) fragment_content = tmp.content unless tmp.nil? end if self[:ensure_newline] fragment_content<<"\n" unless fragment_content =~ /\n$/ end fragment_content end def generate file_opts = { :ensure => self[:ensure] == :absent ? :absent : :file, } [:path, :owner, :group, :mode, :replace, :backup, :selinux_ignore_defaults, :selrange, :selrole, :seltype, :seluser, :validate_cmd, :show_diff].each do |param| unless self[param].nil? file_opts[param] = self[param] end end + metaparams = Puppet::Type.metaparams + excluded_metaparams = [ :before, :notify, :require, :subscribe, :tag ] + + metaparams.reject! { |param| excluded_metaparams.include? param } + + metaparams.each do |metaparam| + file_opts[metaparam] = self[metaparam] if self[metaparam] + end + [Puppet::Type.type(:file).new(file_opts)] end def eval_generate content = should_content if !content.nil? and !content.empty? catalog.resource("File[#{self[:path]}]")[:content] = content end [ catalog.resource("File[#{self[:path]}]") ] end end diff --git a/spec/acceptance/concat_spec.rb b/spec/acceptance/concat_spec.rb index da417be..3e24a58 100644 --- a/spec/acceptance/concat_spec.rb +++ b/spec/acceptance/concat_spec.rb @@ -1,199 +1,228 @@ require 'spec_helper_acceptance' case fact('osfamily') when 'AIX' username = 'root' groupname = 'system' scriptname = 'concatfragments.rb' vardir = default.puppet['vardir'] if vardir.nil? or vardir == '' vardir = '/opt/puppetlabs/puppet/cache' end when 'Darwin' username = 'root' groupname = 'wheel' scriptname = 'concatfragments.rb' vardir = default.puppet['vardir'] if vardir.nil? or vardir == '' vardir = '/opt/puppetlabs/puppet/cache' end when 'windows' username = 'Administrator' groupname = 'Administrators' scriptname = 'concatfragments.rb' result = on default, "echo #{default.puppet['vardir']}" vardir = result.raw_output.chomp when 'Solaris' username = 'root' groupname = 'root' scriptname = 'concatfragments.rb' vardir = default.puppet['vardir'] if vardir.nil? or vardir == '' vardir = '/opt/puppetlabs/puppet/cache' end else username = 'root' groupname = 'root' scriptname = 'concatfragments.rb' vardir = default.puppet['vardir'] if vardir.nil? or vardir == '' vardir = '/opt/puppetlabs/puppet/cache' end end describe 'basic concat test' do basedir = default.tmpdir('concat') 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 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 } its(:content) { should match '1' should match '2' } 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 } 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 context 'works when set to present with path that has special characters' do filename = fact('osfamily') == 'windows' ? 'file(1)' : 'file(1:2)' before(:all) do pp = <<-EOS file { '#{basedir}': ensure => directory, } EOS apply_manifest(pp) end pp=" concat { '#{filename}': ensure => present, path => '#{basedir}/#{filename}', mode => '0644', } concat::fragment { '1': target => '#{filename}', content => '1', order => '01', } " it_behaves_like 'successfully_applied', pp describe file("#{basedir}/#{filename}") do it { should be_file } it("should be mode", :unless => (fact('osfamily') == 'AIX' or fact('osfamily') == 'windows')) { should be_mode 644 } its(:content) { should match '1' } end end + context 'noop properly' 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', + noop => true, + } + concat::fragment { '1': + target => 'file', + content => '1', + order => '01', + } + " + + it_behaves_like 'successfully_applied', pp + + describe file("#{basedir}/file") do + it { should_not be_file } + end + end end end