forked from evolvingweb/puppet-apt
-
Notifications
You must be signed in to change notification settings - Fork 461
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #212 from daenney/apt-key
apt_key type/provider
- Loading branch information
Showing
5 changed files
with
831 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
require 'date' | ||
require 'open-uri' | ||
require 'tempfile' | ||
|
||
Puppet::Type.type(:apt_key).provide(:apt_key) do | ||
|
||
KEY_LINE = { | ||
:date => '[0-9]{4}-[0-9]{2}-[0-9]{2}', | ||
:key_type => '(R|D)', | ||
:key_size => '\d{4}', | ||
:key_id => '[0-9a-fA-F]+', | ||
:expires => 'expire(d|s)', | ||
} | ||
|
||
confine :osfamily => :debian | ||
defaultfor :osfamily => :debian | ||
commands :apt_key => 'apt-key' | ||
|
||
def self.instances | ||
key_array = apt_key('list').split("\n").collect do |line| | ||
line_hash = key_line_hash(line) | ||
next unless line_hash | ||
expired = false | ||
|
||
if line_hash[:key_expiry] | ||
expired = Date.today > Date.parse(line_hash[:key_expiry]) | ||
end | ||
|
||
new( | ||
:name => line_hash[:key_id], | ||
:id => line_hash[:key_id], | ||
:ensure => :present, | ||
:expired => expired, | ||
:expiry => line_hash[:key_expiry], | ||
:size => line_hash[:key_size], | ||
:type => line_hash[:key_type] == 'R' ? :rsa : :dsa, | ||
:created => line_hash[:key_created] | ||
) | ||
end | ||
key_array.compact! | ||
end | ||
|
||
def self.prefetch(resources) | ||
apt_keys = instances | ||
resources.keys.each do |name| | ||
if provider = apt_keys.find{ |key| key.name == name } | ||
resources[name].provider = provider | ||
end | ||
end | ||
end | ||
|
||
def self.key_line_hash(line) | ||
line_array = line.match(key_line_regexp).to_a | ||
return nil if line_array.length < 5 | ||
|
||
return_hash = { | ||
:key_id => line_array[3], | ||
:key_size => line_array[1], | ||
:key_type => line_array[2], | ||
:key_created => line_array[4], | ||
:key_expiry => nil, | ||
} | ||
|
||
return_hash[:key_expiry] = line_array[7] if line_array.length == 8 | ||
return return_hash | ||
end | ||
|
||
def self.key_line_regexp | ||
# This regexp is trying to match the following output | ||
# pub 4096R/4BD6EC30 2010-07-10 [expires: 2016-07-08] | ||
# pub 1024D/CD2EFD2A 2009-12-15 | ||
regexp = /\A | ||
pub # match only the public key, not signatures | ||
\s+ # bunch of spaces after that | ||
(#{KEY_LINE[:key_size]}) # size of the key, usually a multiple of 1024 | ||
#{KEY_LINE[:key_type]} # type of the key, usually R or D | ||
\/ # separator between key_type and key_id | ||
(#{KEY_LINE[:key_id]}) # hex id of the key | ||
\s+ # bunch of spaces after that | ||
(#{KEY_LINE[:date]}) # date the key was added to the keyring | ||
# following an optional block which indicates if the key has an expiration | ||
# date and if it has expired yet | ||
( | ||
\s+ # again with thes paces | ||
\[ # we open with a square bracket | ||
#{KEY_LINE[:expires]} # expires or expired | ||
\: # a colon | ||
\s+ # more spaces | ||
(#{KEY_LINE[:date]}) # date indicating key expiry | ||
\] # we close with a square bracket | ||
)? # end of the optional block | ||
\Z/x | ||
regexp | ||
end | ||
|
||
def source_to_file(value) | ||
if URI::parse(value).scheme.nil? | ||
fail("The file #{value} does not exist") unless File.exists?(value) | ||
value | ||
else | ||
begin | ||
key = open(value).read | ||
rescue OpenURI::HTTPError => e | ||
fail("#{e.message} for #{resource[:source]}") | ||
rescue SocketError | ||
fail("could not resolve #{resource[:source]}") | ||
else | ||
tempfile(key) | ||
end | ||
end | ||
end | ||
|
||
def tempfile(content) | ||
file = Tempfile.new('apt_key') | ||
file.write content | ||
file.close | ||
file.path | ||
end | ||
|
||
def exists? | ||
@property_hash[:ensure] == :present | ||
end | ||
|
||
def create | ||
command = [] | ||
if resource[:source].nil? and resource[:content].nil? | ||
# Breaking up the command like this is needed because it blows up | ||
# if --recv-keys isn't the last argument. | ||
command.push('adv', '--keyserver', resource[:server]) | ||
unless resource[:keyserver_options].nil? | ||
command.push('--keyserver-options', resource[:keyserver_options]) | ||
end | ||
command.push('--recv-keys', resource[:id]) | ||
elsif resource[:content] | ||
command.push('add', tempfile(resource[:content])) | ||
elsif resource[:source] | ||
command.push('add', source_to_file(resource[:source])) | ||
# In case we really screwed up, better safe than sorry. | ||
else | ||
fail("an unexpected condition occurred while trying to add the key: #{resource[:id]}") | ||
end | ||
apt_key(command) | ||
@property_hash[:ensure] = :present | ||
end | ||
|
||
def destroy | ||
apt_key('del', resource[:id]) | ||
@property_hash.clear | ||
end | ||
|
||
def read_only(value) | ||
fail('This is a read-only property.') | ||
end | ||
|
||
mk_resource_methods | ||
|
||
# Needed until PUP-1470 is fixed and we can drop support for Puppet versions | ||
# before that. | ||
def expired | ||
@property_hash[:expired] | ||
end | ||
|
||
# Alias the setters of read-only properties | ||
# to the read_only function. | ||
alias :created= :read_only | ||
alias :expired= :read_only | ||
alias :expiry= :read_only | ||
alias :size= :read_only | ||
alias :type= :read_only | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
require 'pathname' | ||
|
||
Puppet::Type.newtype(:apt_key) do | ||
|
||
@doc = <<-EOS | ||
This type provides Puppet with the capabilities to manage GPG keys needed | ||
by apt to perform package validation. Apt has it's own GPG keyring that can | ||
be manipulated through the `apt-key` command. | ||
apt_key { '4BD6EC30': | ||
source => 'http://apt.puppetlabs.com/pubkey.gpg' | ||
} | ||
**Autorequires**: | ||
If Puppet is given the location of a key file which looks like an absolute | ||
path this type will autorequire that file. | ||
EOS | ||
|
||
ensurable | ||
|
||
validate do | ||
if self[:content] and self[:source] | ||
fail('The properties content and source are mutually exclusive.') | ||
end | ||
end | ||
|
||
newparam(:id, :namevar => true) do | ||
desc 'The ID of the key you want to manage.' | ||
# GPG key ID's should be either 32-bit (short) or 64-bit (long) key ID's | ||
# and may start with the optional 0x | ||
newvalues(/\A(0x)?[0-9a-fA-F]{8}\Z/, /\A(0x)?[0-9a-fA-F]{16}\Z/) | ||
munge do |value| | ||
if value.start_with?('0x') | ||
id = value.partition('0x').last.upcase | ||
else | ||
id = value.upcase | ||
end | ||
if id.length == 16 | ||
id[8..-1] | ||
else | ||
id | ||
end | ||
end | ||
end | ||
|
||
newparam(:content) do | ||
desc 'The content of, or string representing, a GPG key.' | ||
end | ||
|
||
newparam(:source) do | ||
desc 'Location of a GPG key file, /path/to/file, http:// or https://' | ||
newvalues(/\Ahttps?:\/\//, /\A\/\w+/) | ||
end | ||
|
||
autorequire(:file) do | ||
if self[:source] and Pathname.new(self[:source]).absolute? | ||
self[:source] | ||
end | ||
end | ||
|
||
newparam(:server) do | ||
desc 'The key server to fetch the key from based on the ID.' | ||
defaultto :'keyserver.ubuntu.com' | ||
# Need to validate this, preferably through stdlib is_fqdn | ||
# but still working on getting to that. | ||
end | ||
|
||
newparam(:keyserver_options) do | ||
desc 'Additional options to pass to apt-key\'s --keyserver-options.' | ||
end | ||
|
||
newproperty(:expired) do | ||
desc <<-EOS | ||
Indicates if the key has expired. | ||
This property is read-only. | ||
EOS | ||
end | ||
|
||
newproperty(:expiry) do | ||
desc <<-EOS | ||
The date the key will expire, or nil if it has no expiry date. | ||
This property is read-only. | ||
EOS | ||
end | ||
|
||
newproperty(:size) do | ||
desc <<-EOS | ||
The key size, usually a multiple of 1024. | ||
This property is read-only. | ||
EOS | ||
end | ||
|
||
newproperty(:type) do | ||
desc <<-EOS | ||
The key type, either RSA or DSA. | ||
This property is read-only. | ||
EOS | ||
end | ||
|
||
newproperty(:created) do | ||
desc <<-EOS | ||
Date the key was created. | ||
This property is read-only. | ||
EOS | ||
end | ||
end |
Oops, something went wrong.