From ca7767eab6674737a117a09f7f456b7918cffecf Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Mon, 18 Jul 2016 12:45:35 -0300 Subject: Copy openshift binaries instead of using wrapper script. For containerized masters, we previously create a wrapper script to run the docker CLI image and clean up afterward, but this approach is much slower than having the binary on the native system. Instead we now use an ansible module to handle the logic of syncing the various OpenShift binaries and symlinks for client tools out onto the host. The module will correctly report changed if modifications were needed. Substantial speed improvement for containerized installs which requires many openshift/oc commands. --- .../library/openshift_container_binary_sync.py | 131 +++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 roles/openshift_cli/library/openshift_container_binary_sync.py (limited to 'roles/openshift_cli/library/openshift_container_binary_sync.py') diff --git a/roles/openshift_cli/library/openshift_container_binary_sync.py b/roles/openshift_cli/library/openshift_container_binary_sync.py new file mode 100644 index 000000000..fd290c6fc --- /dev/null +++ b/roles/openshift_cli/library/openshift_container_binary_sync.py @@ -0,0 +1,131 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vim: expandtab:tabstop=4:shiftwidth=4 +# pylint: disable=missing-docstring,invalid-name +# + +import random +import tempfile +import shutil +import os.path + +# pylint: disable=redefined-builtin,wildcard-import,unused-wildcard-import +from ansible.module_utils.basic import * + + +DOCUMENTATION = ''' +--- +module: openshift_container_binary_sync +short_description: Copies OpenShift binaries out of the given image tag to host system. +''' + + +class BinarySyncError(Exception): + def __init__(self, msg): + super(BinarySyncError, self).__init__(msg) + self.msg = msg + + +# pylint: disable=too-few-public-methods +class BinarySyncer(object): + """ + Syncs the openshift, oc, oadm, and kubectl binaries/symlinks out of + a container onto the host system. + """ + + def __init__(self, module, image, tag): + self.module = module + self.changed = False + self.output = [] + self.bin_dir = '/usr/local/bin' + self.image = image + self.tag = tag + self.temp_dir = None # TBD + + def sync(self): + container_name = "openshift-cli-%s" % random.randint(1, 100000) + rc, stdout, stderr = self.module.run_command(['docker', 'create', '--name', + container_name, '%s:%s' % (self.image, self.tag)]) + if rc: + raise BinarySyncError("Error creating temporary docker container. stdout=%s, stderr=%s" % + (stdout, stderr)) + self.output.append(stdout) + try: + self.temp_dir = tempfile.mkdtemp() + self.output.append("Using temp dir: %s" % self.temp_dir) + + rc, stdout, stderr = self.module.run_command(['docker', 'cp', "%s:/usr/bin/openshift" % container_name, + self.temp_dir]) + if rc: + raise BinarySyncError("Error copying file from docker container: stdout=%s, stderr=%s" % + (stdout, stderr)) + + rc, stdout, stderr = self.module.run_command(['docker', 'cp', "%s:/usr/bin/oc" % container_name, + self.temp_dir]) + if rc: + raise BinarySyncError("Error copying file from docker container: stdout=%s, stderr=%s" % + (stdout, stderr)) + + self._sync_binary('openshift') + + # In older versions, oc was a symlink to openshift: + if os.path.islink(os.path.join(self.temp_dir, 'oc')): + self._sync_symlink('oc', 'openshift') + else: + self._sync_binary('oc') + + # Ensure correct symlinks created: + self._sync_symlink('kubectl', 'openshift') + self._sync_symlink('oadm', 'openshift') + finally: + shutil.rmtree(self.temp_dir) + self.module.run_command(['docker', 'rm', container_name]) + + def _sync_symlink(self, binary_name, link_to): + """ Ensure the given binary name exists and links to the expected binary. """ + link_path = os.path.join(self.bin_dir, binary_name) + link_dest = os.path.join(self.bin_dir, binary_name) + if not os.path.exists(link_path) or \ + not os.path.islink(link_path) or \ + os.path.realpath(link_path) != os.path.realpath(link_dest): + if os.path.exists(link_path): + os.remove(link_path) + os.symlink(link_to, os.path.join(self.bin_dir, binary_name)) + self.output.append("Symlinked %s to %s." % (link_path, link_dest)) + self.changed = True + + def _sync_binary(self, binary_name): + src_path = os.path.join(self.temp_dir, binary_name) + dest_path = os.path.join(self.bin_dir, binary_name) + incoming_checksum = self.module.run_command(['sha256sum', src_path])[1] + if not os.path.exists(dest_path) or self.module.run_command(['sha256sum', dest_path])[1] != incoming_checksum: + shutil.move(src_path, dest_path) + self.output.append("Moved %s to %s." % (src_path, dest_path)) + self.changed = True + + +def main(): + module = AnsibleModule( + argument_spec=dict( + image=dict(required=True), + tag=dict(required=True), + ), + supports_check_mode=True + ) + + image = module.params['image'] + tag = module.params['tag'] + + binary_syncer = BinarySyncer(module, image, tag) + + try: + binary_syncer.sync() + except BinarySyncError as ex: + module.fail_json(msg=ex.msg) + + return module.exit_json(changed=binary_syncer.changed, + output=binary_syncer.output) + + +if __name__ == '__main__': + main() -- cgit v1.2.3