Re: [Puppet Users] property file provider

Stefan Schulte
Mon, 22 Aug 2011 23:36:41 -0000

On Mon, Aug 22, 2011 at 06:33:27PM -0400, David Kavanagh
wrote:
> I''m working on a type/provider for the eucalyptus.conf file. What
I
> have generally works for modifying properties. I have a couple of
> issues and not being very experienced with Ruby and custom providers,
> I wonder if anyone can help?
> The code is included below. The key/value constructs in the file look like:
>
> key="value"
>
> 1. I''m not getting the quotes surrounding the value, which I think
I
> can figure out myself.
> 2. I get all blanks and comments replaced by "=", which is more
of a problem.
>
> David
>
>
> require ''puppet/provider/parsedfile''
>
> eucaconf = "/etc/eucalyptus/eucalyptus.conf"
>
> Puppet::Type.type(:eucalyptus_config).provide(
>   :parsed,
>   :parent => Puppet::Provider::ParsedFile,
>   :default_target => eucaconf,
>   :filetype => :flat
> ) do
>
>   confine :exists => eucaconf
>   text_line :comment, :match => /^#/;
>   text_line :blank, :match => /^\s*$/;
>
>   record_line :parsed,
>     :fields => %w{line},
>     :match => /(.*)/ ,
>     :post_parse => proc { |hash|
>       Puppet.debug("eucalyptus config line:#{hash[:line]} has been
parsed")
>       if hash[:line] =~ /^\s*(\S+)\s*=\s*(\S+)\s*$/
>         hash[:name]=$1
>         hash[:value]=$2
>       elsif hash[:line] =~ /^\s*(\S+)\s*$/
>         hash[:name]=$1
>         hash[:value]=false
>       else
>         raise Puppet::Error, "Invalid line: #{hash[:line]}"
>       end
>     }

instead of the post_parse hook you can probably just change your regex
  :fields   => %w{name value},
  :optional => %w{value},
  :match    => /^\s*(.*?)(?:\s*=\s*"(\S+)")?\s*$/

This matches line like

  foo

and

  foo = "bar"

>
>   def self.to_line(hash)
>     "#{hash[:name]}=#{hash[:value]}"
>   end

If you just overwrite the to_line method you have to take care of the
different record_types (you defined :comment, :text and :parsed).
So you have to do

    def self.to_line(hash)
      return super unless hash[:record_type] == :parsed
      if hash[:value] == :absent
        hash[:name]
      else
        "#{hash[:name]}=\"#{hash[:value]}\""
      end
    end

Nevertheless the "right" thing to do is to pass a block to the
record_line method:

  record_line :parsed,
    :fields  => ...,
    :match   => ...,
    :to_line => proc { |hash|
      if hash[:value] == :absent
        hash[:name]
      else
        "#{hash[:name]}=\"#{hash[:value]}\""
      end
    }

Hope that helps.

-Stefan