| | |
| | | Enables puppet provider basic functionality with Solaris 11 zones. Also fixes a bug that |
| | | was introduced with the putback of 15886 into the puppet gate that prevented |
| | | zones networking from being created. |
| | | --- puppet-3.0.1/lib/puppet/provider/zone/solaris.rb.orig 2013-02-15 15:00:38.925896083 -0700 |
| | | +++ puppet-3.0.1/lib/puppet/provider/zone/solaris.rb 2013-02-15 15:00:48.805231725 -0700 |
| | | @@ -31,7 +31,7 @@ |
| | | Enhance the zone provider to configure zones using a zonecfg export file format. |
| | | Enhance the output of puppet resource zone, and fix zone clone functionality, which omitted '-c'. |
| | | |
| | | --- puppet-3.8.6/lib/puppet/provider/zone/solaris.rb.orig 2016-04-19 14:19:58.810028057 -0700 |
| | | +++ puppet-3.8.6/lib/puppet/provider/zone/solaris.rb 2016-04-19 14:20:32.183269425 -0700 |
| | | @@ -1,5 +1,9 @@ |
| | | +####################################################################### |
| | | +# Oracle has modified the originally distributed contents of this file. |
| | | +####################################################################### |
| | | + |
| | | Puppet::Type.type(:zone).provide(:solaris) do |
| | | - desc "Provider for Solaris Zones." |
| | | + desc "Provider for Solaris zones." |
| | | |
| | | def multi_conf(name, should, &action) |
| | | has = properties[name] |
| | | - has = [] if has == :absent |
| | | + has = [] if has == :absent or has.nil? |
| | | rms = has - should |
| | | adds = should - has |
| | | (rms.map{|o| action.call(:rm,o)} + adds.map{|o| action.call(:add,o)}).join("\n") |
| | | @@ -60,12 +60,36 @@ |
| | | commands :adm => "/usr/sbin/zoneadm", :cfg => "/usr/sbin/zonecfg" |
| | | defaultfor :osfamily => :solaris |
| | | @@ -8,129 +12,84 @@ |
| | | |
| | | # Convert the output of a list into a hash |
| | | def self.line2hash(line) |
| | | - fields = [:id, :name, :ensure, :path, :uuid, :brand, :iptype] |
| | | + fields = [:id, :name, :ensure, :zonepath, :uuid, :brand, :iptype ] |
| | | properties = Hash[fields.zip(line.split(':'))] |
| | | |
| | | - del_id = [:brand, :uuid] |
| | | + del_id = [:id, :uuid] |
| | | + |
| | | # Configured but not installed zones do not have IDs |
| | | del_id << :id if properties[:id] == "-" |
| | | del_id.each { |p| properties.delete(p) } |
| | | - |
| | | properties[:ensure] = properties[:ensure].intern |
| | | - properties[:iptype] = 'exclusive' if properties[:iptype] == 'excl' |
| | | |
| | | properties |
| | | end |
| | | |
| | | + |
| | | def self.instances |
| | | adm(:list, "-cp").split("\n").collect do |line| |
| | | new(line2hash(line)) |
| | | end |
| | | end |
| | | |
| | | + def self.def_net_prop(var, &conf) |
| | | + define_method(var.to_s) do |v| |
| | | + o = properties[var] |
| | | + return '' if o.nil? or o == :absent |
| | | + o.join(' ') |
| | | + end |
| | | + define_method('%s_conf'% var.to_s) do |v| |
| | | + multi_conf(var, v, &conf) |
| | | + end |
| | | + end |
| | | + |
| | | def_prop :iptype, "set ip-type=%s" |
| | | def_prop :autoboot, "set autoboot=%s" |
| | | def_prop :path, "set zonepath=%s" |
| | | def_prop :pool, "set pool=%s" |
| | | def_prop :shares, "add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=%s,action=none)\nend" |
| | | - def multi_conf(name, should, &action) |
| | | - has = properties[name] |
| | | - has = [] if !has || has == :absent |
| | | - rms = has - should |
| | | - adds = should - has |
| | | - (rms.map{|o| action.call(:rm,o)} + adds.map{|o| action.call(:add,o)}).join("\n") |
| | | - end |
| | | - |
| | | - def self.def_prop(var, str) |
| | | - define_method('%s_conf' % var.to_s) do |v| |
| | | - str % v |
| | | - end |
| | | - define_method('%s=' % var.to_s) do |v| |
| | | - setconfig self.send( ('%s_conf'% var).intern, v) |
| | | - end |
| | | - end |
| | | + |
| | | + # Read in the zone configuration parameters and properties and |
| | | + # perform the zone configuration. Options are cloning the zone, |
| | | + # which needs a zonecfg_export file, configuring an archive, which |
| | | + # takes optional zonecfg_export and archived_zonename parameters, |
| | | + # or performing a zone configuration, which requires a zonecfg_export |
| | | + # file or string. |
| | | + def configure |
| | | |
| | | + if ['5.11', '5.12'].include? Facter.value(:kernelrelease) |
| | | + def_net_prop :net_resource do |action, str| |
| | | + case action |
| | | + when :add |
| | | + cmd = [" add anet"] |
| | | + cmd << "end" |
| | | + cmd.join("\n") |
| | | + when :rm |
| | | + " remove anet" |
| | | - def self.def_multiprop(var, &conf) |
| | | - define_method(var.to_s) do |v| |
| | | - o = properties[var] |
| | | - return '' if o.nil? or o == :absent |
| | | - o.join(' ') |
| | | - end |
| | | - define_method('%s=' % var.to_s) do |v| |
| | | - setconfig self.send( ('%s_conf'% var).intern, v) |
| | | - end |
| | | - define_method('%s_conf' % var.to_s) do |v| |
| | | - multi_conf(var, v, &conf) |
| | | + if @resource[:archive].nil? && @resource[:zonecfg_export].nil? |
| | | + raise Puppet::Error, "No configuration resource is defined." |
| | | end |
| | | - end |
| | | |
| | | - def_prop :iptype, "set ip-type=%s" |
| | | - def_prop :autoboot, "set autoboot=%s" |
| | | - def_prop :path, "set zonepath=%s" |
| | | - def_prop :pool, "set pool=%s" |
| | | - def_prop :shares, "add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=%s,action=none)\nend" |
| | | - |
| | | - def_multiprop :ip do |action, str| |
| | | - interface, ip, defrouter = str.split(':') |
| | | - case action |
| | | - when :add |
| | | - cmd = ["add net"] |
| | | - cmd << "set physical=#{interface}" if interface |
| | | - cmd << "set address=#{ip}" if ip |
| | | - cmd << "set defrouter=#{defrouter}" if defrouter |
| | | - cmd << "end" |
| | | - cmd.join("\n") |
| | | - when :rm |
| | | - if ip |
| | | - "remove net address=#{ip}" |
| | | - elsif interface |
| | | - "remove net physical=#{interface}" |
| | | - else |
| | | - raise ArgumentError, "can not remove network based on default router" |
| | | + command = String.new |
| | | + if @resource[:clone] |
| | | + if !@resource[:zonecfg_export] |
| | | + raise Puppet::Error, "A zone configuration must be defined to |
| | | + clone a zone." |
| | | + end |
| | | + command = "#{command(:cfg)} -z #{@resource[:name]} -f #{@resource[:zonecfg_export]}" |
| | | + else |
| | | + unless @resource[:zonecfg_export].nil? || @resource[:zonecfg_export].empty? |
| | | + begin |
| | | + file = File.open(@resource[:zonecfg_export], "rb") |
| | | + str = file.read.gsub(/[\n]\n*\s*/, "; ") |
| | | + rescue |
| | | + str = @resource[:zonecfg_export].gsub(/[\n]\n*\s*/, "; ") |
| | | + ensure |
| | | + file.close unless file.nil? |
| | | + end |
| | | + end |
| | | + end |
| | | + |
| | | def_multiprop :ip do |action, str| |
| | | interface, ip, defrouter = str.split(':') |
| | | case action |
| | | @@ -96,20 +120,27 @@ |
| | | end |
| | | end |
| | | + @property_hash.clear |
| | | end |
| | | - else self.fail action |
| | | - end |
| | | - end |
| | | |
| | | - def_multiprop :dataset do |action, str| |
| | | - case action |
| | | - when :add; ['add dataset',"set name=#{str}",'end'].join("\n") |
| | | - when :rm; "remove dataset name=#{str}" |
| | | - else self.fail action |
| | | - end |
| | | - end |
| | | + unless @resource[:archive].nil? || @resource[:archive].empty? |
| | | + if !str.nil? |
| | | + command = "#{command(:cfg)} -z #{@resource[:name]} \'create -a #{@resource[:archive]};#{str}\'" |
| | | + else |
| | | + command = "#{command(:cfg)} -z #{@resource[:name]} create -a #{@resource[:archive]} " |
| | | + end |
| | | + if @resource[:archived_zonename] |
| | | + command << " -z #{@resource[:archived_zonename]}" |
| | | + end |
| | | + end |
| | | |
| | | - def_multiprop :inherit do |action, str| |
| | | - case action |
| | | - when :add; ['add inherit-pkg-dir', "set dir=#{str}",'end'].join("\n") |
| | | - when :rm; "remove inherit-pkg-dir dir=#{str}" |
| | | - else self.fail action |
| | | + if ['5.10'].include? Facter.value(:kernelrelease) |
| | | + def_multiprop :inherit do |action, str| |
| | | + case action |
| | | + when :add; ['add inherit-pkg-dir', "set dir=#{str}",'end'].join("\n") |
| | | + when :rm; "remove inherit-pkg-dir dir=#{str}" |
| | | + else self.fail action |
| | | + if !@resource[:zonecfg_export].nil? && @resource[:archive].nil? |
| | | + command = "#{command(:cfg)} -z #{@resource[:name]} \'#{str}\'" |
| | | + end |
| | | end |
| | | - end |
| | | |
| | | - def my_properties |
| | | - [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :inherit] |
| | | - end |
| | | - |
| | | - # Perform all of our configuration steps. |
| | | - def configure |
| | | - self.fail "Path is required" unless @resource[:path] |
| | | - arr = ["create -b #{@resource[:create_args]}"] |
| | | - |
| | | - # Then perform all of our configuration steps. It's annoying |
| | | - # that we need this much internal info on the resource. |
| | | - self.resource.properties.each do |property| |
| | | - next unless my_properties.include? property.name |
| | | - method = (property.name.to_s + '_conf').intern |
| | | - arr << self.send(method ,@resource[property.name]) unless property.safe_insync?(properties[property.name]) |
| | | + if command |
| | | + r = exec_cmd(:cmd => command) |
| | | end |
| | | - setconfig(arr.join("\n")) |
| | | end |
| | | |
| | | def destroy |
| | | zonecfg :delete, "-F" |
| | | end |
| | | |
| | | - def add_cmd(cmd) |
| | | - @cmds = [] if @cmds.nil? |
| | | - @cmds << cmd |
| | | - end |
| | | - |
| | | def exists? |
| | | properties[:ensure] != :absent |
| | | end |
| | | @@ -138,31 +97,35 @@ |
| | | # We cannot use the execpipe in util because the pipe is not opened in |
| | | # read/write mode. |
| | | def exec_cmd(var) |
| | | - # In bash, the exit value of the last command is the exit value of the |
| | | - # entire pipeline |
| | | - out = execute("echo \"#{var[:input]}\" | #{var[:cmd]}", :failonfail => false, :combine => true) |
| | | - st = $?.exitstatus |
| | | - {:out => out, :exit => st} |
| | | - end |
| | | - |
| | | - # Clear out the cached values. |
| | | - def flush |
| | | - return if @cmds.nil? || @cmds.empty? |
| | | - str = (@cmds << "commit" << "exit").join("\n") |
| | | - @cmds = [] |
| | | - @property_hash.clear |
| | | - |
| | | - command = "#{command(:cfg)} -z #{@resource[:name]} -f -" |
| | | - r = exec_cmd(:cmd => command, :input => str) |
| | | - if r[:exit] != 0 or r[:out] =~ /not allowed/ |
| | | - raise ArgumentError, "Failed to apply configuration" |
| | | + if var[:input] |
| | | + execute("echo \"#{var[:input]}\" | #{var[:cmd]}", :failonfail => true, :combine => true) |
| | | + else |
| | | + execute("#{var[:cmd]}", :failonfail => true, :combine => true) |
| | | end |
| | | end |
| | | |
| | | def my_properties |
| | | - [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :inherit] |
| | | + if ['5.11', '5.12'].include? Facter.value(:kernelrelease) |
| | | + [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :net_resource] |
| | | + elsif ['5.10'].include? Facter.value(:kernelrelease) |
| | | + [:path, :iptype, :autoboot, :pool, :shares, :ip, :dataset, :inherit] |
| | | + end |
| | | end |
| | | |
| | | # Perform all of our configuration steps. |
| | | def configure |
| | | + |
| | | self.fail "Path is required" unless @resource[:path] |
| | | arr = ["create -b #{@resource[:create_args]}"] |
| | | |
| | | @@ -161,6 +192,14 @@ |
| | | end |
| | | |
| | | def install(dummy_argument=:work_arround_for_ruby_GC_bug) |
| | | + if ['5.11', '5.12'].include? Facter.value(:kernelrelease) |
| | | + if !@resource[:install_args] and @resource[:config_profile] |
| | | + @resource[:install_args] = "-c " + @resource[:config_profile] |
| | | + else |
| | | + @resource[:install_args] << "-c " + @resource[:config_profile] |
| | | + @resource[:install_args] = " -c " + @resource[:config_profile] |
| | | + elsif !@resource[:install_args] and @resource[:archive] |
| | | + @resource[:install_args] = " -a " + @resource[:archive] |
| | | + if @resource[:archived_zonename] |
| | | + @resource[:install_args] << " -z " + @resource[:archived_zonename] |
| | | + end |
| | | + elsif @resource[:config_profile] |
| | | + @resource[:install_args] << " -c " + @resource[:config_profile] |
| | | + end |
| | | + end |
| | | + |
| | | if @resource[:clone] # TODO: add support for "-s snapshot" |
| | | zoneadm :clone, @resource[:clone] |
| | | elsif @resource[:install_args] |
| | | @@ -183,6 +222,7 @@ |
| | | - zoneadm :clone, @resource[:clone] |
| | | - elsif @resource[:install_args] |
| | | + if @resource[:config_profile] |
| | | + zoneadm :clone, @resource[:install_args].split(" "), @resource[:clone] |
| | | + else |
| | | + zoneadm :clone, @resource[:clone] |
| | | + end |
| | | + elsif @resource[:install_args] |
| | | zoneadm :install, @resource[:install_args].split(" ") |
| | | else |
| | | zoneadm :install |
| | | @@ -182,11 +145,12 @@ |
| | | end |
| | | end |
| | | @property_hash.dup |
| | |
| | | end |
| | | |
| | | # We need a way to test whether a zone is in process. Our 'ensure' |
| | | @@ -253,6 +293,7 @@ |
| | | # property models the static states, but we need to handle the temporary ones. |
| | | - def processing? |
| | | + def processing? |
| | | hash = status |
| | | return false unless hash |
| | | ["incomplete", "ready", "shutting_down"].include? hash[:ensure] |
| | | @@ -214,7 +178,6 @@ |
| | | # |
| | | def getconfig |
| | | output = zonecfg :info |
| | | - |
| | | name = nil |
| | | current = nil |
| | | hash = {} |
| | | @@ -244,14 +207,9 @@ |
| | | hash |
| | | end |
| | | |
| | | - # Execute a configuration string. Can't be private because it's called |
| | | - # by the properties. |
| | | - def setconfig(str) |
| | | - add_cmd str |
| | | - end |
| | | - |
| | | def start |
| | | # Check the sysidcfg stuff |
| | | + if ['5.10'].include? Facter.value(:kernelrelease) |
| | | if cfg = @resource[:sysidcfg] |
| | | self.fail "Path is required" unless @resource[:path] |
| | | zoneetc = File.join(@resource[:path], "root", "etc") |
| | | @@ -273,6 +314,7 @@ |
| | | @@ -272,7 +230,9 @@ |
| | | end |
| | | end |
| | | end |
| | | + end |
| | | |
| | | + # Boots the zone |
| | | zoneadm :boot |
| | | end |
| | | @@ -300,7 +342,11 @@ |
| | | |
| | | @@ -285,64 +245,35 @@ |
| | | end |
| | | |
| | | main = self.class.line2hash(output.chomp) |
| | | - |
| | | - # Now add in the configuration information |
| | | - config_status.each do |name, value| |
| | | - main[name] = value |
| | | - end |
| | | - |
| | | main |
| | | end |
| | | |
| | | def ready |
| | | + # Prepare the zone |
| | | zoneadm :ready |
| | | end |
| | | |
| | | def stop |
| | | - zoneadm :halt |
| | | + if ['5.10'].include? Facter.value(:kernelrelease) |
| | | + execute_zoneadm :halt |
| | | + elsif ['5.11', '5.12'].include? Facter.value(:kernelrelease) |
| | | + zoneadm :shutdown |
| | | + end |
| | | + # Shutdown the zone |
| | | + zoneadm :halt |
| | | end |
| | | + |
| | | |
| | | def unconfigure |
| | | + # Unconfigure and delete the zone |
| | | zonecfg :delete, "-F" |
| | | end |
| | | |
| | | def uninstall |
| | | + # Uninstall the zone |
| | | zoneadm :uninstall, "-F" |
| | | end |
| | | |
| | | private |
| | | |
| | | - # Turn the results of getconfig into status information. |
| | | - def config_status |
| | | - config = getconfig |
| | | - result = {} |
| | | - |
| | | - result[:autoboot] = config[:autoboot] ? config[:autoboot].intern : :true |
| | | - result[:pool] = config[:pool] |
| | | - result[:shares] = config[:shares] |
| | | - if dir = config["inherit-pkg-dir"] |
| | | - result[:inherit] = dir.collect { |dirs| dirs[:dir] } |
| | | - end |
| | | - if datasets = config["dataset"] |
| | | - result[:dataset] = datasets.collect { |dataset| dataset[:name] } |
| | | - end |
| | | - result[:iptype] = config[:'ip-type'] if config[:'ip-type'] |
| | | - if net = config["net"] |
| | | - result[:ip] = net.collect do |params| |
| | | - if params[:defrouter] |
| | | - "#{params[:physical]}:#{params[:address]}:#{params[:defrouter]}" |
| | | - elsif params[:address] |
| | | - "#{params[:physical]}:#{params[:address]}" |
| | | - else |
| | | - params[:physical] |
| | | - end |
| | | - end |
| | | - end |
| | | - |
| | | - result |
| | | - end |
| | | - |
| | | def zoneadm(*cmd) |
| | | + # Execute the zoneadm command with the arguments |
| | | + # provided |
| | | adm("-z", @resource[:name], *cmd) |
| | | rescue Puppet::ExecutionFailure => detail |
| | | self.fail Puppet::Error, "Could not #{cmd[0]} zone: #{detail}", detail |