1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
unless Puppet::Util::Platform.jruby_fips?
require 'rubygems/commands/list_command'
end
require 'stringio'
require 'uri'
# Ruby gems support.
Puppet::Type.type(:package).provide :puppetserver_gem, :parent => :gem do
desc "Puppet Server Ruby Gem support. If a URL is passed via `source`, then
that URL is appended to the list of remote gem repositories which by default
contains rubygems.org; To ensure that only the specified source is used also
pass `--clear-sources` in via `install_options`; if a source is present but
is not a valid URL, it will be interpreted as the path to a local gem file.
If source is not present at all, the gem will be installed from the default
gem repositories."
has_feature :versionable, :install_options, :uninstall_options
confine :feature => :hocon
# see SERVER-2578
confine :fips_enabled => false
# Define the default provider package command name, as the parent 'gem' provider is targetable.
# Required by Puppet::Provider::Package::Targetable::resource_or_provider_command
def self.provider_command
command(:puppetservercmd)
end
# The gem command uses HOME to locate a gemrc file.
# CommandDefiner in provider.rb will set failonfail, combine, and environment.
has_command(:puppetservercmd, '/opt/puppetlabs/bin/puppetserver') do
environment(HOME: ENV['HOME'])
end
def self.gemlist(options)
command_options = ['gem', 'list']
if options[:local]
command_options << '--local'
else
command_options << '--remote'
end
if options[:source]
command_options << '--source' << options[:source]
end
if options[:justme]
gem_regex = '\A' + options[:justme] + '\z'
command_options << gem_regex
end
if options[:local]
list = execute_rubygems_list_command(command_options)
else
begin
list = puppetservercmd(command_options)
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, _("Could not list gems: %{detail}") % { detail: detail }, detail.backtrace
end
end
# When `/tmp` is mounted `noexec`, `puppetserver gem list` will output:
# *** LOCAL GEMS ***
# causing gemsplit to output:
# Warning: Could not match *** LOCAL GEMS ***
gem_list = list
.lines
.select { |x| x =~ /^(\S+)\s+\((.+)\)/ }
.map { |set| gemsplit(set) }
if options[:justme]
return gem_list.shift
else
return gem_list
end
end
def install(useversion = true)
command_options = ['gem', 'install']
command_options += install_options if resource[:install_options]
command_options << '-v' << resource[:ensure] if (!resource[:ensure].is_a? Symbol) && useversion
command_options << '--no-document'
if resource[:source]
begin
uri = URI.parse(resource[:source])
rescue => detail
self.fail Puppet::Error, _("Invalid source '%{uri}': %{detail}") % { uri: uri, detail: detail }, detail
end
case uri.scheme
when nil
# no URI scheme => interpret the source as a local file
command_options << resource[:source]
when /file/i
command_options << uri.path
when 'puppet'
# we don't support puppet:// URLs (yet)
raise Puppet::Error.new(_('puppet:// URLs are not supported as gem sources'))
else
# interpret it as a gem repository
command_options << '--source' << "#{resource[:source]}" << resource[:name]
end
else
command_options << resource[:name]
end
output = puppetservercmd(command_options)
# Apparently, some gem versions don't exit non-0 on failure.
self.fail _("Could not install: %{output}") % { output: output.chomp } if output.include?('ERROR')
end
def uninstall
command_options = ['gem', 'uninstall']
command_options << '--executables' << '--all' << resource[:name]
command_options += uninstall_options if resource[:uninstall_options]
output = puppetservercmd(command_options)
# Apparently, some gem versions don't exit non-0 on failure.
self.fail _("Could not uninstall: %{output}") % { output: output.chomp } if output.include?('ERROR')
end
private
# The puppetserver gem cli command is very slow, since it starts a JVM.
#
# Instead, for the list subcommand (which is executed with every puppet run),
# use the rubygems library from puppet ruby: setting GEM_HOME and GEM_PATH
# to the default values, or the values in the puppetserver configuration file.
#
# The rubygems library cannot access java platform gems,
# for example: json (1.8.3 java)
# but java platform gems should not be managed by this (or any) provider.
def self.execute_rubygems_list_command(command_options)
puppetserver_default_gem_home = '/opt/puppetlabs/server/data/puppetserver/jruby-gems'
puppetserver_default_vendored_jruby_gems = '/opt/puppetlabs/server/data/puppetserver/vendored-jruby-gems'
puppet_default_vendor_gems = '/opt/puppetlabs/puppet/lib/ruby/vendor_gems'
puppetserver_default_gem_path = [puppetserver_default_gem_home, puppetserver_default_vendored_jruby_gems, puppet_default_vendor_gems].join(':')
pe_puppetserver_conf_file = '/etc/puppetlabs/puppetserver/conf.d/pe-puppet-server.conf'
os_puppetserver_conf_file = '/etc/puppetlabs/puppetserver/puppetserver.conf'
puppetserver_conf_file = Puppet.runtime[:facter].value(:pe_server_version) ? pe_puppetserver_conf_file : os_puppetserver_conf_file
puppetserver_conf = Hocon.load(puppetserver_conf_file)
gem_env = {}
if puppetserver_conf.empty? || puppetserver_conf.key?('jruby-puppet') == false
gem_env['GEM_HOME'] = puppetserver_default_gem_home
gem_env['GEM_PATH'] = puppetserver_default_gem_path
else
gem_env['GEM_HOME'] = puppetserver_conf['jruby-puppet'].key?('gem-home') ? puppetserver_conf['jruby-puppet']['gem-home'] : puppetserver_default_gem_home
gem_env['GEM_PATH'] = puppetserver_conf['jruby-puppet'].key?('gem-path') ? puppetserver_conf['jruby-puppet']['gem-path'].join(':') : puppetserver_default_gem_path
end
gem_env['GEM_SPEC_CACHE'] = "/tmp/#{$$}"
# Remove the 'gem' from the command_options
command_options.shift
gem_out = execute_gem_command(Puppet::Type::Package::ProviderPuppet_gem.provider_command, command_options, gem_env)
# There is no method exclude default gems from the local gem list,
# for example: psych (default: 2.2.2)
# but default gems should not be managed by this (or any) provider.
gem_list = gem_out.lines.reject { |gem| gem =~ / \(default\: / }
gem_list.join("\n")
end
end
|