Issue #3132 has been updated by Markus Roberts.

Branch set to http://github.com/amsibamsi/puppet

Normally we want these on branches (e.g. ticket/master/3132) rather than your 
master, but it'll do.
----------------------------------------
Feature #3132: FreeBSD service provider shortcomings
http://projects.puppetlabs.com/issues/3132

Author: Anselm Strauss
Status: Ready for Testing
Priority: Normal
Assigned to: Markus Roberts
Category: FreeBSD
Target version: Rowlf
Affected version: 0.25.3
Keywords: freebsd, service provider, rcvar, rc.conf.d
Branch: http://github.com/amsibamsi/puppet


The current service provider for FreeBSD has several issues:

* It ignores the fact that a service name can be different from the init script 
filename (e.g. @/usr/local/rc.d/mysql-server@ needs @mysql_enable="YES"@)
* A service is not necessarily disabled when it's config file in 
@/etc/rc.conf.d@ is removed (e.g. syslogd is enabled by default, without 
explicit config file)
* One might not want to use @/etc/rc.conf.d@ at all, but just @/etc/rc.conf@ 
instead

I wrote a new provider which should fix these problems:

<pre><code class="ruby">
Puppet::Type.type(:service).provide :freebsd2, :parent => :init do

  desc "Provider for FreeBSD. Makes use of rcvar argument of init scripts and 
parses/edits rc files."

  confine :operatingsystem => [:freebsd]

  @@rcconf = '/etc/rc.conf'
  @@rcconf_local = '/etc/rc.conf.local'
  @@rcconf_dir = '/etc/rc.conf.d'

  def self.defpath
    superclass.defpath
  end

  # Executing an init script with the 'rcvar' argument returns
  # the service name and whether it's enabled/disabled
  def rcvar
    rcvar = execute([self.initscript, :rcvar], :failonfail => true, :squelch => 
false)
    rcvar = rcvar.lines.to_a[1].gsub(/\n/, "")
    self.debug("rcvar is #{rcvar}")
    return rcvar
  end

  # Extract the service name from the rcvar
  def rcvar_name
    name = self.rcvar.gsub(/(.*)_enable=(.*)/, '\1')
    self.debug("rcvar name is #{name}")
    return name
  end

  # Edit rc files and set the service to yes/no
  def rc_edit(yesno)
    name = self.rcvar_name
    self.debug("Editing rc files: setting #{name} to #{yesno}")
    if not self.rc_replace(yesno, name)
      self.rc_add(yesno, name)
    end
  end

  # Try to find an existing setting in the rc files 
  # and replace the value
  def rc_replace(yesno, name)
    success = false
    # Replace in all files, not just in the first found with a match
    [@@rcconf, @@rcconf_local, @@rcconf_dir + "/#{name}"].each do |filename|
      if File.exists?(filename)
        s = File.read(filename)
        if s.gsub!(/(#{name}_enable)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"")
          File.open(filename, File::WRONLY) { |f| f << s }
          self.debug("Replaced in #{filename}")
          success = true
        end
      end
    end
    return success
  end

  # Add a new setting to the rc files
  def rc_add(yesno, name)
    append = "\n\# Added by Puppet\n#{name}_enable=\"#{yesno}\""
    # First, try the one-file-per-service style
    if File.exists?(@@rcconf_dir)
      File.open(@@rcconf_dir + "/#{name}", File::WRONLY | File::APPEND | 
File::CREAT, 0644) {
        |f| f << append
        self.debug("Appended to #{f.path}")
      }
    else
      # Else, check the local rc file first, but don't create it
      if File.exists?(@@rcconf_local)
        File.open(@@rcconf_local, File::WRONLY | File::APPEND) {
          |f| f << append
          self.debug("Appended to #{f.path}")
        }
      else
        # At last use the standard rc.conf file
        File.open(@@rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) {
          |f| f << append
          self.debug("Appended to #{f.path}")
        }
      end
    end
  end

  def enabled?
    if /YES$/ =~ self.rcvar then
      self.debug("Is enabled")
      return :true
    end
    self.debug("Is disabled")
    return :false
  end

  def enable
    self.debug("Enabling")
    self.rc_edit("YES")
  end

  def disable
    self.debug("Disabling")
    self.rc_edit("NO")
  end

  def startcmd
    [self.initscript, :onestart]
  end

  def stopcmd
    [self.initscript, :onestop]
  end

end
</code></pre>

Maybe someone besides me wants to test this code and maybe some ideas can be 
included in a next version of puppet?

However, I think some things here are very difficult to solve through the 
nature of FreeBSD's init system. The rc config files are actually shell scripts 
that are sourced. Parsing them can get very complex if you want to catch all 
possibilities. Not only a line like @ntpd_enable="YES"@ is correct, but so 
would be
<pre>
ntpd_enable\
="`echo YES`"
</pre>
I'm not sure how important it is to catch such a case, but it surely is not 
covered by the provider. Maybe it's a flaw in FreeBSD's init system, that it's 
not easily _machine controlable_. Enabling a service is not just done by 
creating a symlink or executing @chkconfig@ with a static argument, but by 
editing a shell file, which can be a hard job to automate.


-- 
You have received this notification because you have either subscribed to it, 
or are involved in it.
To change your notification preferences, please click here: 
http://projects.puppetlabs.com/my/account

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Bugs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-bugs?hl=en.

Reply via email to