Permalink
Browse files

Merge branch 'next'

  • Loading branch information...
2 parents 2b8e834 + 8e2a945 commit d19f36e7e7d498b9ca12c5ce536f3ee3db114279 Paul Berry committed Nov 17, 2010
@@ -53,49 +53,81 @@ class MCXContentProviderException < Exception
confine :operatingsystem => :darwin
defaultfor :operatingsystem => :darwin
- # self.instances is all important.
- # This is the only class method, it returns
- # an array of instances of this class.
def self.instances
mcx_list = []
- for ds_type in TypeMap.keys
+ TypeMap.keys.each do |ds_type|
ds_path = "/Local/Default/#{TypeMap[ds_type]}"
output = dscl 'localhost', '-list', ds_path
member_list = output.split
- for ds_name in member_list
+ member_list.each do |ds_name|
content = mcxexport(ds_type, ds_name)
if content.empty?
Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data."
else
# This node has MCX data.
- rsrc = self.new(
- :name => "/#{TypeMap[ds_type]}/#{ds_name}",
- :ds_type => ds_type,
- :ds_name => ds_name,
-
- :content => content)
- mcx_list << rsrc
+ mcx_list << self.new(
+ :name => "/#{TypeMap[ds_type]}/#{ds_name}",
+ :ds_type => ds_type,
+ :ds_name => ds_name,
+ :content => content
+ )
end
end
end
mcx_list
end
- private
-
- # mcxexport is used by instances, and therefore
- # a class method.
def self.mcxexport(ds_type, ds_name)
ds_t = TypeMap[ds_type]
ds_n = ds_name.to_s
ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
dscl 'localhost', '-mcxexport', ds_path
end
+
+ def create
+ self.content=(resource[:content])
+ end
+
+ def destroy
+ ds_parms = get_dsparams
+ ds_t = TypeMap[ds_parms[:ds_type]]
+ ds_n = ds_parms[:ds_name].to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+
+ dscl 'localhost', '-mcxdelete', ds_path
+ end
+
+ def exists?
+ begin
+ has_mcx?
+ rescue Puppet::ExecutionFailure => e
+ return false
+ end
+ end
+
+ def content
+ ds_parms = get_dsparams
+
+ self.class.mcxexport(ds_parms[:ds_type], ds_parms[:ds_name])
+ end
+
+ def content=(value)
+ # dscl localhost -mcximport
+ ds_parms = get_dsparams
+
+ mcximport(ds_parms[:ds_type], ds_parms[:ds_name], resource[:content])
+ end
+
+ private
+
+ def has_mcx?
+ !content.empty?
+ end
+
def mcximport(ds_type, ds_name, val)
ds_t = TypeMap[ds_type]
- ds_n = ds_name.to_s
ds_path = "/Local/Default/#{ds_t}/#{ds_name}"
tmp = Tempfile.new('puppet_mcx')
@@ -111,33 +143,31 @@ def mcximport(ds_type, ds_name, val)
# Given the resource name string, parse ds_type out.
def parse_type(name)
- tmp = name.split('/')[1]
- if ! tmp.is_a? String
+ ds_type = name.split('/')[1]
+ unless ds_type
raise MCXContentProviderException,
"Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
end
# De-pluralize and downcase.
- tmp = tmp.chop.downcase.to_sym
- if not TypeMap.keys.member? tmp
+ ds_type = ds_type.chop.downcase.to_sym
+ unless TypeMap.key? ds_type
raise MCXContentProviderException,
"Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
end
- tmp
+ ds_type
end
# Given the resource name string, parse ds_name out.
def parse_name(name)
ds_name = name.split('/')[2]
- if ! ds_name.is_a? String
+ unless ds_name
raise MCXContentProviderException,
"Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter."
end
ds_name
end
- # Gather ds_type and ds_name from resource or
- # parse it out of the name.
- # This is a private instance method, not a class method.
+ # Gather ds_type and ds_name from resource or parse it out of the name.
def get_dsparams
ds_type = resource[:ds_type]
ds_type ||= parse_type(resource[:name])
@@ -146,60 +176,10 @@ def get_dsparams
ds_name = resource[:ds_name]
ds_name ||= parse_name(resource[:name])
- rval = {
+ {
:ds_type => ds_type.to_sym,
:ds_name => ds_name,
}
-
- return rval
-
- end
-
- public
-
- def create
- self.content=(resource[:content])
- end
-
- def destroy
- ds_parms = get_dsparams
- ds_t = TypeMap[ds_parms[:ds_type]]
- ds_n = ds_parms[:ds_name].to_s
- ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
-
- dscl 'localhost', '-mcxdelete', ds_path
- end
-
- def exists?
- # JJM Just re-use the content method and see if it's empty.
- begin
- mcx = content
- rescue Puppet::ExecutionFailure => e
- return false
- end
- has_mcx = ! mcx.empty?
- end
-
- def content
- ds_parms = get_dsparams
-
- mcx = self.class.mcxexport(
- ds_parms[:ds_type],
-
- ds_parms[:ds_name])
- mcx
- end
-
- def content=(value)
- # dscl localhost -mcximport
- ds_parms = get_dsparams
-
- mcx = mcximport(
- ds_parms[:ds_type],
- ds_parms[:ds_name],
-
- resource[:content])
- mcx
end
end
@@ -0,0 +1,73 @@
+Puppet::Type.type(:service).provide :upstart, :parent => :init do
+ desc "Ubuntu service manager upstart.
+
+ This provider manages upstart jobs which have replaced initd.
+
+ See:
+ * http://upstart.ubuntu.com/
+ "
+ # confine to :ubuntu for now because I haven't tested on other platforms
+ confine :operatingsystem => :ubuntu #[:ubuntu, :fedora, :debian]
+
+ commands :start => "/sbin/start",
+ :stop => "/sbin/stop",
+ :restart => "/sbin/restart",
+ :status_exec => "/sbin/status",
+ :initctl => "/sbin/initctl"
+
+ # upstart developer haven't implemented initctl enable/disable yet:
+ # http://www.linuxplanet.com/linuxplanet/tutorials/7033/2/
+ # has_feature :enableable
+
+ def self.instances
+ instances = []
+ execpipe("#{command(:initctl)} list") { |process|
+ process.each { |line|
+ # needs special handling of services such as network-interface:
+ # initctl list:
+ # network-interface (lo) start/running
+ # network-interface (eth0) start/running
+ # network-interface-security start/running
+ name = \
+ if matcher = line.match(/^(network-interface)\s\(([^\)]+)\)/)
+ "#{matcher[1]} INTERFACE=#{matcher[2]}"
+ else
+ line.split.first
+ end
+ instances << new(:name => name)
+ }
+ }
+ instances
+ end
+
+ def startcmd
+ [command(:start), @resource[:name]]
+ end
+
+ def stopcmd
+ [command(:stop), @resource[:name]]
+ end
+
+ def restartcmd
+ (@resource[:hasrestart] == :true) && [command(:restart), @resource[:name]]
+ end
+
+ def status
+ # allows user override of status command
+ if @resource[:status]
+ ucommand(:status, false)
+ if $?.exitstatus == 0
+ return :running
+ else
+ return :stopped
+ end
+ else
+ output = status_exec(@resource[:name].split)
+ if (! $?.nil?) && (output =~ /start\//)
+ return :running
+ else
+ return :stopped
+ end
+ end
+ end
+end
View
@@ -210,7 +210,7 @@ def value=(value)
def refresh
# Only remount if we're supposed to be mounted.
- provider.remount if self.should(:fstype) != "swap" and provider.mounted?
+ provider.remount if self.should(:fstype) != "swap" and self.should(:ensure) == :mounted
end
def value(name)
@@ -0,0 +1,50 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+provider_class = Puppet::Type.type(:service).provider(:upstart)
+
+describe provider_class do
+ describe "#instances" do
+ it "should be able to find all instances" do
+ processes = ["rc stop/waiting", "ssh start/running, process 712"]
+ provider_class.stubs(:execpipe).yields(processes)
+ provider_class.instances.map {|provider| provider.name}.should =~ ["rc","ssh"]
+ end
+
+ it "should attach the interface name for network interfaces" do
+ processes = ["network-interface (eth0)"]
+ provider_class.stubs(:execpipe).yields(processes)
+ provider_class.instances.first.name.should == "network-interface INTERFACE=eth0"
+ end
+ end
+
+ describe "#status" do
+ it "should allow the user to override the status command" do
+ resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart, :status => "/bin/foo")
+ provider = provider_class.new(resource)
+
+ Process::Status.any_instance.stubs(:exitstatus).returns(0)
+ provider.expects(:ucommand)
+ provider.status.should == :running
+ end
+
+ it "should use the default status command if none is specified" do
+ resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart)
+ provider = provider_class.new(resource)
+
+ provider.expects(:status_exec).with(["foo"]).returns("foo start/running, process 1000")
+ Process::Status.any_instance.stubs(:exitstatus).returns(0)
+ provider.status.should == :running
+ end
+
+ it "should properly handle services with 'start' in their name" do
+ resource = Puppet::Type.type(:service).new(:name => "foostartbar", :provider => :upstart)
+ provider = provider_class.new(resource)
+
+ provider.expects(:status_exec).with(["foostartbar"]).returns("foostartbar stop/waiting")
+ Process::Status.any_instance.stubs(:exitstatus).returns(0)
+ provider.status.should == :stopped
+ end
+ end
+end
@@ -203,23 +203,45 @@ def mount_stub(params)
end
end
- describe Puppet::Type.type(:mount), "when responding to events" do
+ describe Puppet::Type.type(:mount), "when responding to refresh" do
- it "should remount if it is currently mounted" do
- @provider.expects(:mounted?).returns(true)
+ it "should remount if it is supposed to be mounted" do
+ @mount[:ensure] = "mounted"
@provider.expects(:remount)
@mount.refresh
end
- it "should not remount if it is not currently mounted" do
- @provider.expects(:mounted?).returns(false)
+ it "should not remount if it is supposed to be present" do
+ @mount[:ensure] = "present"
+ @provider.expects(:remount).never
+
+ @mount.refresh
+ end
+
+ it "should not remount if it is supposed to be absent" do
+ @mount[:ensure] = "absent"
+ @provider.expects(:remount).never
+
+ @mount.refresh
+ end
+
+ it "should not remount if it is supposed to be defined" do
+ @mount[:ensure] = "defined"
+ @provider.expects(:remount).never
+
+ @mount.refresh
+ end
+
+ it "should not remount if it is supposed to be unmounted" do
+ @mount[:ensure] = "unmounted"
@provider.expects(:remount).never
@mount.refresh
end
it "should not remount swap filesystems" do
+ @mount[:ensure] = "mounted"
@mount[:fstype] = "swap"
@provider.expects(:remount).never
@@ -108,7 +108,7 @@ task :mail_patches do
files = Dir.glob("00*.patch")
files.each do |file|
contents = File.read(file)
- contents.sub!(/^---$/, "#{additional_info}---")
+ contents.sub!(/^---\n/, "---\n#{additional_info}")
File.open(file, 'w') do |file_handle|
file_handle.print contents
end

0 comments on commit d19f36e

Please sign in to comment.