1 Enhance the zone provider to configure zones using a zonecfg export file format.
2 Enhance the output of puppet resource zone, and fix zone clone functionality, which omitted '-c'.
4 --- puppet-3.8.6/lib/puppet/provider/zone/solaris.rb.orig 2016-04-19 14:19:58.810028057 -0700
5 +++ puppet-3.8.6/lib/puppet/provider/zone/solaris.rb 2016-04-19 14:20:32.183269425 -0700
7 +#######################################################################
8 +# Oracle has modified the originally distributed contents of this file.
9 +#######################################################################
11 Puppet::Type.type(:zone).provide(:solaris) do
12 - desc "Provider for Solaris Zones."
13 + desc "Provider for Solaris zones."
15 commands :adm => "/usr/sbin/zoneadm", :cfg => "/usr/sbin/zonecfg"
16 defaultfor :osfamily => :solaris
19 # Convert the output of a list into a hash
20 def self.line2hash(line)
21 - fields = [:id, :name, :ensure, :path, :uuid, :brand, :iptype]
22 + fields = [:id, :name, :ensure, :zonepath, :uuid, :brand, :iptype ]
23 properties = Hash[fields.zip(line.split(':'))]
25 - del_id = [:brand, :uuid]
26 + del_id = [:id, :uuid]
28 # Configured but not installed zones do not have IDs
29 del_id << :id if properties[:id] == "-"
30 del_id.each { |p| properties.delete(p) }
32 properties[:ensure] = properties[:ensure].intern
33 - properties[:iptype] = 'exclusive' if properties[:iptype] == 'excl'
40 adm(:list, "-cp").split("\n").collect do |line|
45 - def multi_conf(name, should, &action)
46 - has = properties[name]
47 - has = [] if !has || has == :absent
50 - (rms.map{|o| action.call(:rm,o)} + adds.map{|o| action.call(:add,o)}).join("\n")
53 - def self.def_prop(var, str)
54 - define_method('%s_conf' % var.to_s) do |v|
57 - define_method('%s=' % var.to_s) do |v|
58 - setconfig self.send( ('%s_conf'% var).intern, v)
62 + # Read in the zone configuration parameters and properties and
63 + # perform the zone configuration. Options are cloning the zone,
64 + # which needs a zonecfg_export file, configuring an archive, which
65 + # takes optional zonecfg_export and archived_zonename parameters,
66 + # or performing a zone configuration, which requires a zonecfg_export
70 - def self.def_multiprop(var, &conf)
71 - define_method(var.to_s) do |v|
73 - return '' if o.nil? or o == :absent
76 - define_method('%s=' % var.to_s) do |v|
77 - setconfig self.send( ('%s_conf'% var).intern, v)
79 - define_method('%s_conf' % var.to_s) do |v|
80 - multi_conf(var, v, &conf)
81 + if @resource[:archive].nil? && @resource[:zonecfg_export].nil?
82 + raise Puppet::Error, "No configuration resource is defined."
86 - def_prop :iptype, "set ip-type=%s"
87 - def_prop :autoboot, "set autoboot=%s"
88 - def_prop :path, "set zonepath=%s"
89 - def_prop :pool, "set pool=%s"
90 - def_prop :shares, "add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=%s,action=none)\nend"
92 - def_multiprop :ip do |action, str|
93 - interface, ip, defrouter = str.split(':')
97 - cmd << "set physical=#{interface}" if interface
98 - cmd << "set address=#{ip}" if ip
99 - cmd << "set defrouter=#{defrouter}" if defrouter
104 - "remove net address=#{ip}"
106 - "remove net physical=#{interface}"
108 - raise ArgumentError, "can not remove network based on default router"
109 + command = String.new
110 + if @resource[:clone]
111 + if !@resource[:zonecfg_export]
112 + raise Puppet::Error, "A zone configuration must be defined to
115 + command = "#{command(:cfg)} -z #{@resource[:name]} -f #{@resource[:zonecfg_export]}"
117 + unless @resource[:zonecfg_export].nil? || @resource[:zonecfg_export].empty?
119 + file = File.open(@resource[:zonecfg_export], "rb")
120 + str = file.read.gsub(/[\n]\n*\s*/, "; ")
122 + str = @resource[:zonecfg_export].gsub(/[\n]\n*\s*/, "; ")
124 + file.close unless file.nil?
126 + @property_hash.clear
128 - else self.fail action
132 - def_multiprop :dataset do |action, str|
134 - when :add; ['add dataset',"set name=#{str}",'end'].join("\n")
135 - when :rm; "remove dataset name=#{str}"
136 - else self.fail action
139 + unless @resource[:archive].nil? || @resource[:archive].empty?
141 + command = "#{command(:cfg)} -z #{@resource[:name]} \'create -a #{@resource[:archive]};#{str}\'"
143 + command = "#{command(:cfg)} -z #{@resource[:name]} create -a #{@resource[:archive]} "
145 + if @resource[:archived_zonename]
146 + command << " -z #{@resource[:archived_zonename]}"
150 - def_multiprop :inherit do |action, str|
152 - when :add; ['add inherit-pkg-dir', "set dir=#{str}",'end'].join("\n")
153 - when :rm; "remove inherit-pkg-dir dir=#{str}"
154 - else self.fail action
155 + if !@resource[:zonecfg_export].nil? && @resource[:archive].nil?
156 + command = "#{command(:cfg)} -z #{@resource[:name]} \'#{str}\'"
162 - [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :inherit]
165 - # Perform all of our configuration steps.
167 - self.fail "Path is required" unless @resource[:path]
168 - arr = ["create -b #{@resource[:create_args]}"]
170 - # Then perform all of our configuration steps. It's annoying
171 - # that we need this much internal info on the resource.
172 - self.resource.properties.each do |property|
173 - next unless my_properties.include? property.name
174 - method = (property.name.to_s + '_conf').intern
175 - arr << self.send(method ,@resource[property.name]) unless property.safe_insync?(properties[property.name])
177 + r = exec_cmd(:cmd => command)
179 - setconfig(arr.join("\n"))
183 zonecfg :delete, "-F"
187 - @cmds = [] if @cmds.nil?
192 properties[:ensure] != :absent
195 # We cannot use the execpipe in util because the pipe is not opened in
198 - # In bash, the exit value of the last command is the exit value of the
200 - out = execute("echo \"#{var[:input]}\" | #{var[:cmd]}", :failonfail => false, :combine => true)
202 - {:out => out, :exit => st}
205 - # Clear out the cached values.
207 - return if @cmds.nil? || @cmds.empty?
208 - str = (@cmds << "commit" << "exit").join("\n")
210 - @property_hash.clear
212 - command = "#{command(:cfg)} -z #{@resource[:name]} -f -"
213 - r = exec_cmd(:cmd => command, :input => str)
214 - if r[:exit] != 0 or r[:out] =~ /not allowed/
215 - raise ArgumentError, "Failed to apply configuration"
217 + execute("echo \"#{var[:input]}\" | #{var[:cmd]}", :failonfail => true, :combine => true)
219 + execute("#{var[:cmd]}", :failonfail => true, :combine => true)
224 def install(dummy_argument=:work_arround_for_ruby_GC_bug)
225 + if ['5.11', '5.12'].include? Facter.value(:kernelrelease)
226 + if !@resource[:install_args] and @resource[:config_profile]
227 + @resource[:install_args] = " -c " + @resource[:config_profile]
228 + elsif !@resource[:install_args] and @resource[:archive]
229 + @resource[:install_args] = " -a " + @resource[:archive]
230 + if @resource[:archived_zonename]
231 + @resource[:install_args] << " -z " + @resource[:archived_zonename]
233 + elsif @resource[:config_profile]
234 + @resource[:install_args] << " -c " + @resource[:config_profile]
238 if @resource[:clone] # TODO: add support for "-s snapshot"
239 - zoneadm :clone, @resource[:clone]
240 - elsif @resource[:install_args]
241 + if @resource[:config_profile]
242 + zoneadm :clone, @resource[:install_args].split(" "), @resource[:clone]
244 + zoneadm :clone, @resource[:clone]
246 + elsif @resource[:install_args]
247 zoneadm :install, @resource[:install_args].split(" ")
250 @@ -182,11 +145,12 @@
257 # We need a way to test whether a zone is in process. Our 'ensure'
258 # property models the static states, but we need to handle the temporary ones.
262 return false unless hash
263 ["incomplete", "ready", "shutting_down"].include? hash[:ensure]
267 output = zonecfg :info
276 - # Execute a configuration string. Can't be private because it's called
277 - # by the properties.
283 # Check the sysidcfg stuff
284 + if ['5.10'].include? Facter.value(:kernelrelease)
285 if cfg = @resource[:sysidcfg]
286 self.fail "Path is required" unless @resource[:path]
287 zoneetc = File.join(@resource[:path], "root", "etc")
298 @@ -285,64 +245,35 @@
301 main = self.class.line2hash(output.chomp)
303 - # Now add in the configuration information
304 - config_status.each do |name, value|
318 + # Shutdown the zone
324 + # Unconfigure and delete the zone
325 zonecfg :delete, "-F"
329 + # Uninstall the zone
330 zoneadm :uninstall, "-F"
335 - # Turn the results of getconfig into status information.
340 - result[:autoboot] = config[:autoboot] ? config[:autoboot].intern : :true
341 - result[:pool] = config[:pool]
342 - result[:shares] = config[:shares]
343 - if dir = config["inherit-pkg-dir"]
344 - result[:inherit] = dir.collect { |dirs| dirs[:dir] }
346 - if datasets = config["dataset"]
347 - result[:dataset] = datasets.collect { |dataset| dataset[:name] }
349 - result[:iptype] = config[:'ip-type'] if config[:'ip-type']
350 - if net = config["net"]
351 - result[:ip] = net.collect do |params|
352 - if params[:defrouter]
353 - "#{params[:physical]}:#{params[:address]}:#{params[:defrouter]}"
354 - elsif params[:address]
355 - "#{params[:physical]}:#{params[:address]}"
366 + # Execute the zoneadm command with the arguments
368 adm("-z", @resource[:name], *cmd)
369 rescue Puppet::ExecutionFailure => detail
370 self.fail Puppet::Error, "Could not #{cmd[0]} zone: #{detail}", detail