Add 'aptkey' state module
There is only 'added' function which ensures that given key is added
to apt's key storage. It does nothing if key is already in apt's key
storage.
A key can be provided either as plain text or base64 encoded string,
or by URL.
Change-Id: I210728caffc75ac11f50029fa0e63d6af70e2e32
Related: (PROD-26981)
diff --git a/.kitchen.yml b/.kitchen.yml
index 9901242..eeaf317 100644
--- a/.kitchen.yml
+++ b/.kitchen.yml
@@ -33,16 +33,10 @@
sudo: true
docker_images:
- - &xenial-20163 <%=ENV['IMAGE_XENIAL_20163'] || 'docker-dev-local.docker.mirantis.net/epcim/salt/saltstack-ubuntu-xenial-salt-2016.3/salt:2018_11_19'%>
- &xenial-20177 <%=ENV['IMAGE_XENIAL_20177'] || 'docker-dev-local.docker.mirantis.net/epcim/salt/saltstack-ubuntu-xenial-salt-2017.7/salt:2018_11_19'%>
- &xenial-stable <%=ENV['IMAGE_XENIAL_STABLE'] || 'docker-dev-local.docker.mirantis.net/epcim/salt/saltstack-ubuntu-xenial-salt-stable/salt:2018_11_19'%>
platforms:
- - name: xenial-2016.3
- driver_config:
- image: *xenial-20163
- platform: ubuntu
-
- name: xenial-2017.7
driver_config:
image: *xenial-20177
diff --git a/_states/aptkey.py b/_states/aptkey.py
new file mode 100644
index 0000000..8d12829
--- /dev/null
+++ b/_states/aptkey.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+# _state/aptkey.py
+"""
+Manage apt keys
+"""
+from __future__ import absolute_import, print_function, unicode_literals
+
+from base64 import b64encode, b64decode
+from binascii import Error as binasciiError
+
+def __virtual__():
+ """Only load if 'pkg' (aptpkg) module has necessary functions"""
+
+ if not 'pkg.add_repo_key' in __salt__ or not 'pkg.get_repo_keys' in __salt__:
+ return False, "'pkg.add_repo_key' and 'pkg.get_repo_keys' functions are required"
+ return True
+
+def _get_fingerprints(input_text):
+ """Get fingerprint(s) for given text
+
+ :param str input_text: text to get fingerprint(s) from it
+
+ :return:
+ A list of found fingerprint(s)
+ :rtype list:
+
+ """
+ fingerprints = []
+ cmd = 'apt-key adv --with-fingerprint --with-colons --dry-run -'
+ out = __salt__['cmd.run_stdout'](cmd, stdin=input_text, python_shell=False)
+ for line in out.split('\n'):
+ line = line.split(':')
+ if line[0] == 'fpr':
+ fingerprints.append(line[-2])
+ return fingerprints
+
+
+def added(name, key_text=None, key_url=None):
+ """Ensure that given key added to APT's key storage
+
+ :param str name:
+ Just an ID, it does not used at all.
+ :param str key_text:
+ Key to add as a plain text or base64-encoded.
+ :param str key_url:
+ URL from which key should be fetched. Supported URLs: salt://, http://,
+ https:// and file://.
+
+ Examples:
+
+ .. code-block:: yaml
+
+ # Base64 encoded key
+ {% set repo_key = salt['hashutil.base64_b64encode'](repo.key) %}
+ linux_repo_ubuntu_key:
+ aptkey.added:
+ - key_text: {{ repo_key }}
+
+ .. code-block:: yaml
+
+ # Plaintext key
+ linux_repo_ubuntu_key:
+ aptkey.added:
+ - key_text: '{{ repo.key | replace("\n", "\\n") }}'
+
+ .. code-block:: yaml
+
+ linux_repo_ubuntu_key:
+ aptkey.added:
+ - key_url: 'https://example.com/key.asc'
+ """
+ ret = {'name': name,
+ 'result': None if __opts__['test'] else True,
+ 'changes': {},
+ 'comment': ''}
+
+ if not key_text and not key_url:
+ ret['result'] = False,
+ ret['comment'] = 'No key to add provided'
+ return ret
+ if key_text and key_url:
+ ret['result'] = False
+ ret['comment'] = 'Only one of key_text or key_url is permitted'
+ return ret
+
+ # If key_url provided fetch it before proceeding
+ if key_url:
+ # This only supports salt://, http://, https:// and file:// URLs
+ key_text = __salt__['cp.get_url'](key_url, dest=None)
+
+ # Try to apply base64 decoding to key_text, just in case...
+ try:
+ # Decode key_text if it is base64 encoded string
+ decoded_key_text = b64decode(key_text)
+ # the simplest available check that given string was base64 encoded
+ if b64encode(decoded_key_text) == key_text:
+ key_text = decoded_key_text
+ except TypeError, binasciiError: # the first is for py2, the second for py3
+ pass
+
+ # Get apt's keys and their fingerprints
+ apt_keys = __salt__['pkg.get_repo_keys']()
+ apt_fingerprints = [key.get('fingerprint') for _, key in apt_keys.items()]
+
+ key_fingerprints = _get_fingerprints(key_text)
+ # If any of given fingerprints does not present in apt keys
+ # then add all of them
+ if not set(key_fingerprints).issubset(set(apt_fingerprints)):
+ if __opts__['test']:
+ ret['result'] = None
+ ret['changes'] = {'key': key_text}
+ return ret
+
+ success = __salt__['pkg.add_repo_key'](text=key_text)
+ if success:
+ ret['result'] = True
+ ret['changes'] = {'key': key_text}
+ else:
+ ret['result'] = False
+ ret['comment'] = 'Key was not added because of errors'
+ return ret