apt_key: Add 'keyring' parameter

The apt-key command takes an optional --keyring parameter representing
the path to a specific GPG keyring to operate on. If it's not given,
the command operates on all keyring files, i.e., /etc/apt/trusted.gpg
and /etc/apt/trusted.gpg.d/*.gpg.

This change adds a 'keyring' parameter to the apt_key module and
propagates it down to the apt-key command line. The main use case this
supports is organizing keys for third-party repos into individual
keyrings in /etc/apt/trusted.gpg.d, rather than putting them all in
the default keyring.
This commit is contained in:
Alan Grosskurth 2013-07-24 18:10:17 -07:00
parent 2da5dc7886
commit 5700970e05

View file

@ -47,6 +47,11 @@ options:
default: none default: none
description: description:
- keyfile path - keyfile path
keyring:
required: false
default: none
description:
- path to specific keyring file in /etc/apt/trusted.gpg.d
url: url:
required: false required: false
default: none default: none
@ -75,6 +80,9 @@ EXAMPLES = '''
# Add a key from a file on the Ansible server # Add a key from a file on the Ansible server
- apt_key: data="{{ lookup('file', 'apt.gpg') }}" state=present - apt_key: data="{{ lookup('file', 'apt.gpg') }}" state=present
# Add an Apt signing key to a specific keyring file
- apt_key: id=473041FA url=https://ftp-master.debian.org/keys/archive-key-6.0.asc keyring=/etc/apt/trusted.gpg.d/debian.gpg state=present
''' '''
@ -98,8 +106,12 @@ def check_missing_binaries(module):
if len(missing): if len(missing):
module.fail_json(msg="binaries are missing", names=all) module.fail_json(msg="binaries are missing", names=all)
def all_keys(module): def all_keys(module, keyring):
(rc, out, err) = module.run_command("apt-key list") if keyring:
cmd = "apt-key --keyring %s list" % keyring
else:
cmd = "apt-key list"
(rc, out, err) = module.run_command(cmd)
results = [] results = []
lines = out.split('\n') lines = out.split('\n')
for line in lines: for line in lines:
@ -129,18 +141,27 @@ def download_key(module, url):
module.fail_json(msg="error getting key id from url", traceback=format_exc()) module.fail_json(msg="error getting key id from url", traceback=format_exc())
def add_key(module, keyfile, data=None): def add_key(module, keyfile, keyring, data=None):
if data is not None: if data is not None:
cmd = "apt-key add -" if keyring:
cmd = "apt-key --keyring %s add -" % keyring
else:
cmd = "apt-key add -"
(rc, out, err) = module.run_command(cmd, data=data, check_rc=True, binary_data=True) (rc, out, err) = module.run_command(cmd, data=data, check_rc=True, binary_data=True)
else: else:
cmd = "apt-key add %s" % (keyfile) if keyring:
cmd = "apt-key --keyring %s add %s" % (keyring, keyfile)
else:
cmd = "apt-key add %s" % (keyfile)
(rc, out, err) = module.run_command(cmd, check_rc=True) (rc, out, err) = module.run_command(cmd, check_rc=True)
return True return True
def remove_key(module, key_id): def remove_key(module, key_id, keyring):
# FIXME: use module.run_command, fail at point of error and don't discard useful stdin/stdout # FIXME: use module.run_command, fail at point of error and don't discard useful stdin/stdout
cmd = 'apt-key del %s' % key_id if keyring:
cmd = 'apt-key --keyring %s del %s' % (keyring, key_id)
else:
cmd = 'apt-key del %s' % key_id
(rc, out, err) = module.run_command(cmd, check_rc=True) (rc, out, err) = module.run_command(cmd, check_rc=True)
return True return True
@ -152,6 +173,7 @@ def main():
data=dict(required=False), data=dict(required=False),
file=dict(required=False), file=dict(required=False),
key=dict(required=False), key=dict(required=False),
keyring=dict(required=False),
state=dict(required=False, choices=['present', 'absent'], default='present') state=dict(required=False, choices=['present', 'absent'], default='present')
), ),
supports_check_mode=True supports_check_mode=True
@ -161,13 +183,14 @@ def main():
url = module.params['url'] url = module.params['url']
data = module.params['data'] data = module.params['data']
filename = module.params['file'] filename = module.params['file']
keyring = module.params['keyring']
state = module.params['state'] state = module.params['state']
changed = False changed = False
# FIXME: I think we have a common facility for this, if not, want # FIXME: I think we have a common facility for this, if not, want
check_missing_binaries(module) check_missing_binaries(module)
keys = all_keys(module) keys = all_keys(module, keyring)
return_values = {} return_values = {}
if state == 'present': if state == 'present':
@ -182,11 +205,11 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True) module.exit_json(changed=True)
if filename: if filename:
add_key(module, filename) add_key(module, filename, keyring)
else: else:
add_key(module, "-", data) add_key(module, "-", keyring, data)
changed=False changed=False
keys2 = all_keys(module) keys2 = all_keys(module, keyring)
if len(keys) != len(keys2): if len(keys) != len(keys2):
changed=True changed=True
if key_id and not key_id in keys2: if key_id and not key_id in keys2:
@ -198,7 +221,7 @@ def main():
if key_id in keys: if key_id in keys:
if module.check_mode: if module.check_mode:
module.exit_json(changed=True) module.exit_json(changed=True)
if remove_key(module, key_id): if remove_key(module, key_id, keyring):
changed=True changed=True
else: else:
# FIXME: module.fail_json or exit-json immediately at point of failure # FIXME: module.fail_json or exit-json immediately at point of failure