summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-06-02 23:38:55 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-06-02 23:38:55 +0000
commita3ed62936c81951105fd5d7676858c8f9add3b38 (patch)
treeecfd4a6bb1e03103352d69a1e919cb9045d7c94c /lib
parent81ce66a92a482aa1225fffa98fce4e874d2a83d0 (diff)
downloadpuppet-a3ed62936c81951105fd5d7676858c8f9add3b38.tar.gz
puppet-a3ed62936c81951105fd5d7676858c8f9add3b38.tar.xz
puppet-a3ed62936c81951105fd5d7676858c8f9add3b38.zip
Intermediate commit; most of the core zone functions now work, and some of the configuration functions work.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1233 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/type/zone.rb319
-rw-r--r--lib/puppet/util.rb7
2 files changed, 234 insertions, 92 deletions
diff --git a/lib/puppet/type/zone.rb b/lib/puppet/type/zone.rb
index b866ffcfd..ab9191a0e 100644
--- a/lib/puppet/type/zone.rb
+++ b/lib/puppet/type/zone.rb
@@ -1,26 +1,37 @@
Puppet::Type.newtype(:zone) do
@doc = "Solaris zones."
- # We should have a special state type for those states that modify
- # the zone's configuration.
- def self.newstate(name, &block) do
- super
-
- @states[name].class_eval do
- def cfgstate
- @cfgstate = true
+ class Puppet::State::ZoneState < Puppet::State
+ def self.cfgstate
+ @cfgstate = true
+ end
+
+ def self.cfgstate?
+ if defined? @cfgstate
+ @cfgstate
+ else
+ false
end
+ end
- def cfgstate?
- if defined? @cfgstate
- @cfgstate
- else
- false
- end
+ def cfgstate?
+ self.class.cfgstate?
+ end
+
+ def sync
+ if self.class.cfgstate
+ @parent.cfg self.configtext
+ else
+ super
end
end
end
+ # Use our state type as the parent type.
+ def self.newstate(name, parent = nil, &block)
+ state = super(name, Puppet::State::ZoneState, &block)
+ end
+
ensurable do
desc "The running state of the zone. The valid states directly reflect
the states that ``zoneadm`` provides. The states are linear,
@@ -28,35 +39,71 @@ Puppet::Type.newtype(:zone) do
only then can be ``running``. Note also that ``halt`` is currently
used to stop zones."
- @@list = [:absent, :configured, :installed, :running]
+ @states = {}
- newvalue(:absent) do
+ def self.newvalue(name, hash)
+ if @parametervalues.is_a? Hash
+ @parametervalues = []
+ end
+
+ @parametervalues << name
+
+ @states[name] = hash
+ hash[:name] = name
end
- newvalue(:configured) do
- @parent.configure
- # Um, don't do anything for now...
+ newvalue :absent, :down => :uninstall
+ newvalue :configured, :up => :configure, :down => :uninstall
+ newvalue :installed, :up => :install, :down => :stop
+ newvalue :running, :up => :start
+
+ def self.valueindex(value)
+ @parametervalues.index(value)
end
- newvalue(:installed) do
- begin
- execute("/usr/sbin/zlogin #{@parent[:name]} shutdown")
- rescue ExecutionFailure
- self.fail "Could not stop zone: %s" % output
+ # Return all of the states between two listed values, inclusively.
+ def self.valueslice(first, second)
+ list = @parametervalues[
+ @parametervalues.index(first)..@parametervalues.index(second)
+ ].collect do |name|
+ @states[name]
end
+
+ list[1..-1]
+ end
+
+ def is=(value)
+ value = value.intern if value.is_a? String
+ @is = value
end
- newvalue(:running) do
- begin
- execute("/usr/sbin/zoneadm #{@parent[:name]} boot")
- rescue ExecutionFailure
- self.fail "Could not stop zone: %s" % output
+ def sync
+ method = nil
+ if up?
+ dir = :up
+ else
+ dir = :down
+ end
+
+ # We need to get the state we're currently in and just call
+ # everything between it and us.
+ states = self.class.valueslice(self.is, self.should)
+
+ states.each do |st|
+ if method = st[dir]
+ @parent.send(method)
+ else
+ raise Puppet::DevError, "Cannot move %s from %s" %
+ [dir, st[:name]]
+ end
end
- return :zone_booted
+ return ("zone_" + self.should.to_s).intern
end
- def perform(value)
+ # Are we moving up the state tree?
+ def up?
+ self.class.valueindex(self.is) < self.class.valueindex(self.should)
end
end
@@ -80,6 +127,14 @@ Puppet::Type.newtype(:zone) do
cfgstate
end
+ newstate(:autoboot) do
+ desc "Whether the zone should automatically boot."
+
+ cfgstate
+
+ defaultto :true
+ end
+
newstate(:pool) do
desc "The resource pool for this zone."
@@ -101,9 +156,37 @@ Puppet::Type.newtype(:zone) do
# Add a directory to our list of inherited directories.
def adddir(dir)
- @parent.cfg "add inherit-pkg-dir
- set dir=#{dir}
- end"
+ "add inherit-pkg-dir\nset dir=#{dir}\nend"
+ end
+
+ def configtext
+ list = @should
+
+ unless @is.is_a? Symbol
+ if @is.is_a? Array
+ list += @is
+ else
+ list << @is
+ end
+ end
+
+ # Some hackery so we can test whether @is is an array or a symbol
+ if @is.is_a? Array
+ tmpis = @is
+ else
+ tmpis = [@is]
+ end
+
+ list.sort.uniq.collect do |dir|
+ # Skip directories that are configured and should be
+ next if tmpis.include?(dir) and @should.include?(dir)
+
+ if tmpis.include?(dir)
+ rmdir(dir)
+ else
+ adddir(dir)
+ end
+ end.join("\n")
end
# We want all specified directories to be included.
@@ -112,24 +195,14 @@ Puppet::Type.newtype(:zone) do
end
def rmdir(dir)
- @parent.cfg "remove inherit-pkg-dir{dir=#{dir}}"
+ "remove inherit-pkg-dir{dir=#{dir}}"
end
def sync
- [@is, @should].sort.uniq.each do |dir|
- # Skip directories that are configured and should be
- next if @is.include?(dir) and @should.include?(dir)
-
- if @is.include?(dir)
- rmdir(dir)
- else
- adddir(dir)
- end
- end
end
end
- newparam(:base) do
+ newparam(:path) do
desc "The root of the zone's filesystem. Must be a fully qualified
file name. If you include '%s' in the path, then it will be
replaced with the zone's name. At this point, you cannot use
@@ -153,8 +226,8 @@ Puppet::Type.newtype(:zone) do
# If Puppet is also managing the base dir or its parent dir, list them
# both as prerequisites.
autorequire(:file) do
- if @parameters.include? :base
- return [@parameters[:base], File.dirname(@parameters[:base])]
+ if @parameters.include? :path
+ [@parameters[:path].value, File.dirname(@parameters[:path].value)]
else
nil
end
@@ -162,7 +235,7 @@ Puppet::Type.newtype(:zone) do
# Convert the output of a list into a hash
def self.line2hash(line)
- fields = [:id, :name, :status, :base]
+ fields = [:id, :name, :ensure, :path]
hash = {}
line.split(":").each_with_index { |value, index|
@@ -194,7 +267,8 @@ Puppet::Type.newtype(:zone) do
# Execute a configuration string.
def cfg(str)
- IO.popen("/usr/sbin/zonecfg -z %s" % @parent[:name], "w") do |pipe|
+ info "Executing '%s'" % [str]
+ IO.popen("/usr/sbin/zonecfg -z %s -f -" % self[:name], "w") do |pipe|
pipe.puts str
end
@@ -203,66 +277,76 @@ Puppet::Type.newtype(:zone) do
end
end
+ # Turn the results of getconfig into status information.
+ def config2status(config)
+ config.each do |name, value|
+ case name
+ when :autoboot:
+ self.is = [:autoboot, value]
+ when :zonepath:
+ # Nothing; this is set in the zoneadm list command
+ when :pool:
+ self.is = [:pool, value]
+ when "inherit-pkg-dir":
+ dirs = value.collect do |hash|
+ hash[:dir]
+ end
+
+ self.is = [:inherits, dirs]
+ when "net":
+ vals = value.collect do |hash|
+ "%s:%s" % [hash[:physical], hash[:address]]
+ end
+ self.is = [:ip, vals]
+ end
+ end
+ end
+
# Perform all of our configuration steps.
def configure
# If the thing is entirely absent, then we need to create the config.
- if @states[:status].is == :absent
- cfg("create; set zonepath=%s" % self[:base])
- end
+ str = %{create -b
+ set zonepath=%s
+ set autoboot=true
+ } % self[:path]
# Then perform all of our configuration steps.
@states.each do |name, state|
if state.class.cfgstate? and ! state.insync?
- state.sync
+ str += state.configtext + "\n"
end
end
- end
- def create
- # First we must perform all of the configuration steps
-
- unless @parameters[:base]
- raise ArgumentError, "You must provide a zone root directory."
- end
-
- # Now do the rest of the steps.
- self.configure()
-
- # Then we must actually install the zone
- self.install()
-
- # And finally, boot it, if we're marked to do so.
- end
-
- def destroy
- if @states[:status].is == :running
- @states[:status].should = :stopped
- @states[:status].sync
- end
-
- begin
- execute("/usr/sbin/zoneadm #{@parent[:name]} uninstall")
- rescue ExecutionFailure
- self.fail "Could not stop zone: %s" % output
- end
+ str += "commit\n"
+ cfg(str)
end
# Collect the configuration of the zone.
- def info
+ def getconfig
output = execute("/usr/sbin/zonecfg -z %s info" % self[:name])
name = nil
+ current = nil
hash = {}
output.split("\n").each do |line|
case line
- when /^(\S+):\s*$/: name = $1
- when /^(\S+):\s*(.+)$/: hash[$1] = $2
+ when /^(\S+):\s*$/:
+ name = $1
+ current = nil # reset it
+ when /^(\S+):\s*(.+)$/:
+ hash[$1.intern] = $2
+ #self.is = [$1.intern, $2]
when /^\s+(\S+):\s*(.+)$/:
if name
- unless hash[name].is_a? Hash
- hash[name] = {}
+ unless hash.include? name
+ hash[name] = []
+ end
+
+ unless current
+ current = {}
+ hash[name] << current
end
- hash[name][$1] = $2
+ current[$1.intern] = $2
else
err "Ignoring '%s'" % line
end
@@ -270,21 +354,33 @@ Puppet::Type.newtype(:zone) do
debug "Ignoring zone output '%s'" % line
end
end
+ config2status(hash)
end
def install
+ begin
+ execute("/usr/sbin/zoneadm -z #{self[:name]} install")
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not install zone: %s" % detail
+ end
end
def retrieve
begin
- output = execute("/usr/sbin/zoneadm -z #{self[:name]} list -p")
- rescue ExecutionFailure
- @states[:ensure] = :absent
+ output = execute("/usr/sbin/zoneadm -z #{self[:name]} list -p 2>/dev/null")
+ rescue Puppet::ExecutionFailure => detail
+ @states.each do |name, state|
+ state.is = :absent
+ end
return
end
+ p output
+
hash = self.class.line2hash(output.chomp)
setstatus(hash)
+
+ # Now retrieve the configuration itself and set appropriately.
end
# Take the results of a listing and set everything appropriately.
@@ -298,6 +394,47 @@ Puppet::Type.newtype(:zone) do
self[param] = value
end
end
+
+ # For any configured items that aren't found, mark absent.
+ @states.each do |name, st|
+ next unless st.cfgstate?
+
+ unless hash.has_key? st.name
+ st.is = :absent
+ end
+ end
+ end
+
+ def start
+ begin
+ execute("/usr/sbin/zoneadm -z #{self[:name]} boot")
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not start zone: %s" % detail
+ end
+ end
+
+ def stop
+ begin
+ execute("/usr/sbin/zoneadm -z #{self[:name]} halt")
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not halt zone: %s" % detail
+ end
+ end
+
+ def unconfigure
+ begin
+ execute("/usr/sbin/zonecfg -z #{self[:name]} delete -F")
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not unconfigure zone: %s" % detail
+ end
+ end
+
+ def uninstall
+ begin
+ execute("/usr/sbin/zoneadm -z #{self[:name]} uninstall")
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not halt zone: %s" % detail
+ end
end
end
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index 2f6136ef0..770bbc954 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -351,7 +351,12 @@ module Util
# Execute the desired command, and return the status and output.
def execute(command, failonfail = true)
- output = %x{#{command}}
+ if respond_to? :debug
+ debug "Executing '%s'" % command
+ else
+ Puppet.debug "Executing '%s'" % command
+ end
+ output = %x{#{command} 2>&1}
if failonfail
unless $? == 0