我正在使用puppet,但仅使用Ruby的解决方案也很好。
问题:我的木偶自定义提供程序ruby代码对尚未安装的Gem有一个require语句:
require 'rubygems'
require 'zip'
我为该gem添加了一个依赖项,但由于puppet用户定义的类型不会编译,所以它永远无法下载并安装gem。
以下是我打算加载gem的方法:
package { 'rubyzip':
ensure => 'latest',
provider => 'gem'
}
我以为我可以使用自动加载来延迟加载rubyzip gem并避开问题;在执行ruby代码时,gem已经安装好,不会发生运行时错误。
是否可以自动加载rubyzip?我试过,但得到语法错误。不知道怎么做。 我试过这个,因为我需要Zip :: File类:
module Zip
autoload :File, 'C:\PROGRA~2\PUPPET~1\PUPPET~1\sys\ruby\lib\ruby\gems\1.9.1\gems\rubyzip-1.1.6\lib\zip.rb'
end
这是错误:
C:/Progra~2/PUPPET~1/PUPPET~1/sys/ruby/lib/ruby/gems/1.9.1/gems/rubyzip-1.1.6/lib/zip/file.rb:45:in `<module:Zip>': uninitialized constant Zip::File (NameError)
from C:/Progra~2/PUPPET~1/PUPPET~1/sys/ruby/lib/ruby/gems/1.9.1/gems/rubyzip-1.1.6/lib/zip/file.rb:1:in `<top (required)>'
from C:/Progra~2/PUPPET~1/PUPPET~1/sys/ruby/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from C:/Progra~2/PUPPET~1/PUPPET~1/sys/ruby/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from C:/PROGRA~2/PUPPET~1/PUPPET~1/sys/ruby/lib/ruby/gems/1.9.1/gems/rubyzip-1.1.6/lib/zip.rb:14:in `<top (required)>'
from C:/Users/paul.chernoch/Documents/puppet deployer/phx_deployer/puppet/modules/mirrored_directory/lib/puppet/provider/mirrored_directory/zip/zipinstall.rb:92:in `from_zip'
from C:/Users/paul.chernoch/Documents/puppet deployer/phx_deployer/puppet/modules/mirrored_directory/lib/puppet/provider/mirrored_directory/zip/zipinstall.rb:254:in `differences'
from C:/Users/paul.chernoch/Documents/puppet deployer/phx_deployer/puppet/modules/mirrored_directory/lib/puppet/provider/mirrored_directory/zip/zipinstall.rb:235:in `has_differences?
'
from C:/Users/paul.chernoch/Documents/puppet deployer/phx_deployer/puppet/modules/mirrored_directory/lib/puppet/provider/mirrored_directory/zip/zipinstall.rb:485:in `<main>'
注意: 我也试图在下一个阶段之前使用木偶运行阶段来强制创建rubyzip包,但不确定如何使用阶段或者它们是否有效。
答案 0 :(得分:0)
您的问题的主要来源是您正在从模块的lib/
目录部署自定义事实。这一切都发生在名为pluginsync
的Puppet的一部分中,这是在解析或操作任何目录代码之前。基本上它是:
pluginsync
- &gt; upload facts
- &gt; return catalog
- &gt; execute
所以,没有多少木偶魔法(阶段,资源排序,你有什么)可以解决这个问题。
我看到两种可能性:
1)修改Ruby代码以解决require&#39; zipfile&#39;并为该事实设置一个虚拟值,例如“N / A”和“#N; A&#39;直到宝石可用。当然,更新任何依赖于这个事实的Puppet代码来预期这种行为,因为第一个Puppet运行总是没有这个事实。
2)修改系统引导/转出过程,以确保以其他方式使用Puppet安装此gem。
答案 1 :(得分:0)
我选择了解决问题的另一种方法。 我的傀儡表现为两阶段。 (你需要运行两次木偶申请。我没有使用木偶运行阶段,因为这不起作用。)
1)执行安装的第一部分,不需要解压缩文件。第一部分包括安装rubyzip gem。
2)执行安装的第二部分,解压缩文件并将其复制到目标目录中,然后执行并按照步骤进行操作。
这是通过以下方式完成的:
a)“限制”我的提供商仅在安装了gem的系统上可用。
b)在我需要拉链模块的地方放置一个救援区。
以下是我添加到自定义类型提供程序逻辑中的限制代码:
confine :true => begin
begin
require 'zip'
true
rescue LoadError
false
end
end
以下是我现在如何在我的ruby模块中使用rubygems:
require 'rubygems'
begin
require 'zip'
rescue LoadError
end
(注意:我试图在我的限制逻辑中使用自定义功能,但由于我对如何正确定义它们的无知而无法使用。)
为了帮助其他失去的木偶爱好者(比如我自己),这里是整个提供者ruby文件,“zip.rb”。我在互联网上阅读的建议的一半问题是,人们在没有上下文的情况下提供了小小的片段,我总是将代码插入错误的位置。
# Resource Type: mirrored_directory
# Provider: zip
#
# Provides the interface between the Puppet custom resource type 'mirrored_directory'
# and the ruby class 'ZipInstall::Unzipper'.
# This permits missing or changed files to be extracted from a Zip archive on a Windows system,
# while unchanged files are left alone.
require 'rubygems'
require 'puppet/provider/mirrored_directory/zip/zipinstall'
Puppet::Type.type(:mirrored_directory).provide :zip do
desc "Uses rubyzip to extract new or modified files from a zip archive on a Windows system."
# Confine this provider to (a) Windows Systems where (b) the rubyzip gem is installed.
confine :osfamily => :windows
confine :true => begin
begin
require 'zip'
true
rescue LoadError
false
end
end
defaultfor :osfamily => :windows
include Puppet::Util::Warnings
# The mirrored_directory resource exists iff the target directory exists.
def exists?
Puppet::FileSystem::File.exist?(@resource[:name])
end
# Assuming that the target directory is empty (or only contains excluded files),
# extract all included files from the source archive and deposit them in the target directory
# (or corresponding subdirectory).
# Do not delete any files.
def create
Puppet::Util::Log.new(:level => :debug, :message => "create: About to unzip #{@resource[:source]}")
change_count = unzipper.extract(false)
@property_hash[:ensure] = exists? ? :present : :absent
end
# Delete the contents of the target directory and subdirectories
# (other than those that are excluded).
def destroy
change_count = unzipper.delete
@property_hash.clear
end
# Check if the files in the target directory match those in the source zip archive or not.
def is_current
Puppet::Util::Log.new(:level => :debug, :message => "is_current: About to examine #{@resource[:source]}")
!unzipper.has_differences?(false)
end
# Extract each file from the source archive that differs from the corresponding file
# in the target directory.
# Optionally delete files found in the target directory but not in the source archive,
# according to the parameter :do_deletes.
def is_current=(value)
unzipper_to_use = unzipper
changes = unzipper_to_use.differences(false, false)
count = unzipper_to_use.apply_changes(changes, @resource[:do_deletes])
@property_hash[:is_current] = value
0
end
# TODO: Search computer for all installed directories so that the installed
# mirrored_directory resource instances can be queried by puppet.
def self.instances
[]
end
# Construct a new Unzipper, using these parameters supplied to the resource type:
# :source, :name, :exclude, :include
# Supplies a logger that delegate to puppet's own logging.
def unzipper
# Puppet has numerous loggin levels, including:
# :crit, :err, :warning, :notice, :info, :debug
logger = ->(level,message) {
Puppet::Util::Log.new(:level => level, :message => message)
}
ZipInstall::Unzipper.new(@resource[:source], @resource[:name], :prefix_depth => @resource[:prefix_depth], :exclude_files => @resource[:exclude], :include_files => @resource[:include], :logger => logger)
end
end
以下是使用提供程序的关联自定义类型文件mirrored_directory.rb:
Puppet::Type.newtype(:mirrored_directory) do
desc 'mirrored_directory keeps a directory in sync with an archive by extracting new or changed files from the archive and/or deleting extraneous files from the directory.'
ensurable
newparam(:path, :namevar => true) do
desc 'path of the target root directory into which files will be extracted.'
validate do |value|
fail("Invalid path #{value}") unless Pathname.new(value).absolute?
end
end
newparam(:source) do
desc 'source path to the archive from which files will be extracted.'
validate do |value|
fail("Invalid path #{value}") unless Pathname.new(value).absolute?
end
end
newparam(:prefix_depth) do
desc 'Number of directory segments to remove from beginning of paths extracted from zip file.'
defaultto 0
end
newparam(:exclude, :array_matching => :all) do
desc 'List of wildcards that match target files that should NOT be updated or deleted.'
defaultto []
end
newparam(:include, :array_matching => :all) do
desc 'List of wildcards that match source files that MAY be extracted from the archive.'
defaultto ['*']
end
newparam(:do_deletes) do
desc 'Determines if files will be deleted or not when found in the target directory but not in the archive.'
newvalues(:true, :yes, :false, :no)
defaultto false
validate { |arg| }
munge do |value|
newval = super(value)
case newval
when :true, :yes; true
when :false, :no; false
else
self.fail "Invalid do_deletes value #{value.inspect} (expecting 'true' or 'false')"
end
end
end
newproperty(:is_current) do
desc 'Indicates if the files in the target directory are consistent with those in the source archive.'
newvalues(:true, :yes, :false, :no)
defaultto true
validate { |arg| }
munge do |value|
newval = super(value)
case newval
when :true, :yes; true
when :false, :no; false
else
self.fail "Invalid is_current value #{value.inspect} (expecting 'true' or 'false')"
end
end
end
# Require that the source archive exist.
autorequire(:file) { self[:source] if Pathname.new(self[:source]).absolute? }
end