apt_key: Support fetching keys over FTP.
This commit is contained in:
parent
738ef15316
commit
c3b3f5bb42
5 changed files with 134 additions and 4 deletions
|
@ -1,7 +1,15 @@
|
||||||
require 'date'
|
require 'date'
|
||||||
require 'open-uri'
|
require 'open-uri'
|
||||||
|
require 'net/ftp'
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
|
if RUBY_VERSION == '1.8.7'
|
||||||
|
# Mothers cry, puppies die and Ruby 1.8.7's open-uri needs to be
|
||||||
|
# monkeypatched to support passing in :ftp_passive_mode.
|
||||||
|
require 'puppet_x/apt_key/patch_openuri'
|
||||||
|
OpenURI::Options.merge!({:ftp_active_mode => false,})
|
||||||
|
end
|
||||||
|
|
||||||
Puppet::Type.type(:apt_key).provide(:apt_key) do
|
Puppet::Type.type(:apt_key).provide(:apt_key) do
|
||||||
|
|
||||||
KEY_LINE = {
|
KEY_LINE = {
|
||||||
|
@ -99,8 +107,8 @@ Puppet::Type.type(:apt_key).provide(:apt_key) do
|
||||||
value
|
value
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
key = open(value).read
|
key = open(value, :ftp_active_mode => false).read
|
||||||
rescue OpenURI::HTTPError => e
|
rescue OpenURI::HTTPError, Net::FTPPermError => e
|
||||||
fail("#{e.message} for #{resource[:source]}")
|
fail("#{e.message} for #{resource[:source]}")
|
||||||
rescue SocketError
|
rescue SocketError
|
||||||
fail("could not resolve #{resource[:source]}")
|
fail("could not resolve #{resource[:source]}")
|
||||||
|
|
|
@ -49,8 +49,8 @@ Puppet::Type.newtype(:apt_key) do
|
||||||
end
|
end
|
||||||
|
|
||||||
newparam(:source) do
|
newparam(:source) do
|
||||||
desc 'Location of a GPG key file, /path/to/file, http:// or https://'
|
desc 'Location of a GPG key file, /path/to/file, ftp://, http:// or https://'
|
||||||
newvalues(/\Ahttps?:\/\//, /\A\/\w+/)
|
newvalues(/\Ahttps?:\/\//, /\Aftp:\/\//, /\A\/\w+/)
|
||||||
end
|
end
|
||||||
|
|
||||||
autorequire(:file) do
|
autorequire(:file) do
|
||||||
|
|
63
lib/puppet_x/apt_key/patch_openuri.rb
Normal file
63
lib/puppet_x/apt_key/patch_openuri.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
require 'uri'
|
||||||
|
require 'stringio'
|
||||||
|
require 'time'
|
||||||
|
|
||||||
|
module URI
|
||||||
|
class FTP
|
||||||
|
def buffer_open(buf, proxy, options) # :nodoc:
|
||||||
|
if proxy
|
||||||
|
OpenURI.open_http(buf, self, proxy, options)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
require 'net/ftp'
|
||||||
|
|
||||||
|
directories = self.path.split(%r{/}, -1)
|
||||||
|
directories.shift if directories[0] == '' # strip a field before leading slash
|
||||||
|
directories.each {|d|
|
||||||
|
d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") }
|
||||||
|
}
|
||||||
|
unless filename = directories.pop
|
||||||
|
raise ArgumentError, "no filename: #{self.inspect}"
|
||||||
|
end
|
||||||
|
directories.each {|d|
|
||||||
|
if /[\r\n]/ =~ d
|
||||||
|
raise ArgumentError, "invalid directory: #{d.inspect}"
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if /[\r\n]/ =~ filename
|
||||||
|
raise ArgumentError, "invalid filename: #{filename.inspect}"
|
||||||
|
end
|
||||||
|
typecode = self.typecode
|
||||||
|
if typecode && /\A[aid]\z/ !~ typecode
|
||||||
|
raise ArgumentError, "invalid typecode: #{typecode.inspect}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# The access sequence is defined by RFC 1738
|
||||||
|
ftp = Net::FTP.open(self.host)
|
||||||
|
ftp.passive = true if !options[:ftp_active_mode]
|
||||||
|
# todo: extract user/passwd from .netrc.
|
||||||
|
user = 'anonymous'
|
||||||
|
passwd = nil
|
||||||
|
user, passwd = self.userinfo.split(/:/) if self.userinfo
|
||||||
|
ftp.login(user, passwd)
|
||||||
|
directories.each {|cwd|
|
||||||
|
ftp.voidcmd("CWD #{cwd}")
|
||||||
|
}
|
||||||
|
if typecode
|
||||||
|
# xxx: typecode D is not handled.
|
||||||
|
ftp.voidcmd("TYPE #{typecode.upcase}")
|
||||||
|
end
|
||||||
|
if options[:content_length_proc]
|
||||||
|
options[:content_length_proc].call(ftp.size(filename))
|
||||||
|
end
|
||||||
|
ftp.retrbinary("RETR #{filename}", 4096) { |str|
|
||||||
|
buf << str
|
||||||
|
options[:progress_proc].call(buf.size) if options[:progress_proc]
|
||||||
|
}
|
||||||
|
ftp.close
|
||||||
|
buf.io.rewind
|
||||||
|
end
|
||||||
|
|
||||||
|
include OpenURI::OpenRead
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,9 @@ require 'spec_helper_acceptance'
|
||||||
PUPPETLABS_GPG_KEY_ID = '4BD6EC30'
|
PUPPETLABS_GPG_KEY_ID = '4BD6EC30'
|
||||||
PUPPETLABS_APT_URL = 'apt.puppetlabs.com'
|
PUPPETLABS_APT_URL = 'apt.puppetlabs.com'
|
||||||
PUPPETLABS_GPG_KEY_FILE = 'pubkey.gpg'
|
PUPPETLABS_GPG_KEY_FILE = 'pubkey.gpg'
|
||||||
|
CENTOS_GPG_KEY_ID = 'C105B9DE'
|
||||||
|
CENTOS_REPO_URL = 'ftp.cvut.cz/centos'
|
||||||
|
CENTOS_GPG_KEY_FILE = 'RPM-GPG-KEY-CentOS-6'
|
||||||
|
|
||||||
describe 'apt_key' do
|
describe 'apt_key' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
|
@ -251,6 +254,55 @@ ugVIB2pi+8u84f+an4Hml4xlyijgYu05pqNvnLRyJDLd61hviLC8GYU=
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'ftp://' do
|
||||||
|
before(:each) do
|
||||||
|
shell("apt-key del #{CENTOS_GPG_KEY_ID}",
|
||||||
|
:acceptable_exit_codes => [0,1,2])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works' do
|
||||||
|
pp = <<-EOS
|
||||||
|
apt_key { 'CentOS 6':
|
||||||
|
id => '#{CENTOS_GPG_KEY_ID}',
|
||||||
|
ensure => 'present',
|
||||||
|
source => 'ftp://#{CENTOS_REPO_URL}/#{CENTOS_GPG_KEY_FILE}',
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
|
||||||
|
apply_manifest(pp, :catch_failures => true)
|
||||||
|
expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
|
||||||
|
shell("apt-key list | grep #{CENTOS_GPG_KEY_ID}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails with a 550' do
|
||||||
|
pp = <<-EOS
|
||||||
|
apt_key { 'CentOS 6':
|
||||||
|
id => '#{CENTOS_GPG_KEY_ID}',
|
||||||
|
ensure => 'present',
|
||||||
|
source => 'ftp://#{CENTOS_REPO_URL}/herpderp.gpg',
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
|
||||||
|
apply_manifest(pp, :expect_failures => true) do |r|
|
||||||
|
expect(r.stderr).to match(/550 Failed to open/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fails with a socket error' do
|
||||||
|
pp = <<-EOS
|
||||||
|
apt_key { 'puppetlabs':
|
||||||
|
id => '#{PUPPETLABS_GPG_KEY_ID}',
|
||||||
|
ensure => 'present',
|
||||||
|
source => 'ftp://apt.puppetlabss.com/herpderp.gpg',
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
|
||||||
|
apply_manifest(pp, :expect_failures => true) do |r|
|
||||||
|
expect(r.stderr).to match(/could not resolve/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'https://' do
|
context 'https://' do
|
||||||
it 'works' do
|
it 'works' do
|
||||||
pp = <<-EOS
|
pp = <<-EOS
|
||||||
|
|
|
@ -143,6 +143,13 @@ describe Puppet::Type::type(:apt_key) do
|
||||||
)}.to_not raise_error
|
)}.to_not raise_error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'allows the ftp URI scheme in source' do
|
||||||
|
expect { Puppet::Type.type(:apt_key).new(
|
||||||
|
:id => '4BD6EC30',
|
||||||
|
:source => 'ftp://pgp.mit.edu'
|
||||||
|
)}.to_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
it 'allows an absolute path in source' do
|
it 'allows an absolute path in source' do
|
||||||
expect { Puppet::Type.type(:apt_key).new(
|
expect { Puppet::Type.type(:apt_key).new(
|
||||||
:id => '4BD6EC30',
|
:id => '4BD6EC30',
|
||||||
|
|
Loading…
Reference in a new issue