Browse Source

Merge pull request #2168 from dgoodwin/container-cli-speed

Copy openshift binary instead of using wrapper script.
Scott Dodson 8 years ago
parent
commit
d0c75ba21b

+ 2 - 0
playbooks/common/openshift-cluster/upgrades/v3_1_to_v3_2/pre.yml

@@ -163,6 +163,8 @@
   - name: Verify containers are available for upgrade
     command: >
       docker pull {{ openshift.common.cli_image }}:{{ openshift_image_tag }}
+    register: pull_result
+    changed_when: "'Downloaded newer image' in pull_result.stdout"
     when: openshift.common.is_containerized | bool
 
   - name: Check latest available OpenShift RPM version

+ 2 - 0
roles/etcd/tasks/main.yml

@@ -12,6 +12,8 @@
 
 - name: Pull etcd container
   command: docker pull {{ openshift.etcd.etcd_image }}
+  register: pull_result
+  changed_when: "'Downloaded newer image' in pull_result.stdout"
   when: etcd_is_containerized | bool
 
 - name: Install etcd container service file

+ 131 - 0
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()

+ 6 - 16
roles/openshift_cli/tasks/main.yml

@@ -6,24 +6,14 @@
 - name: Pull CLI Image
   command: >
     docker pull {{ openshift.common.cli_image }}:{{ openshift_image_tag }}
+  register: pull_result
+  changed_when: "'Downloaded newer image' in pull_result.stdout"
   when: openshift.common.is_containerized | bool
 
-- name: Create /usr/local/bin/openshift cli wrapper
-  template:
-    src: openshift.j2
-    dest: /usr/local/bin/openshift
-    mode: 0755
-  when: openshift.common.is_containerized | bool
-
-- name: Create client symlinks
-  file:
-    path: "{{ item }}"
-    state: link
-    src: /usr/local/bin/openshift
-  with_items:
-    - /usr/local/bin/oadm
-    - /usr/local/bin/oc
-    - /usr/local/bin/kubectl
+- name: Copy client binaries/symlinks out of CLI image for use on the host
+  openshift_container_binary_sync:
+    image: "{{ openshift.common.cli_image }}"
+    tag: "{{ openshift_image_tag }}"
   when: openshift.common.is_containerized | bool
 
 - name: Reload facts to pick up installed OpenShift version

+ 0 - 28
roles/openshift_cli/templates/openshift.j2

@@ -1,28 +0,0 @@
-#!/bin/bash
-if [ ! -d ~/.kube ]; then
-   mkdir -m 0700 ~/.kube
-fi
-cmd=`basename $0`
-user=`id -u`
-group=`id -g`
-image_tag="{{ openshift_image_tag }}"
-
->&2 echo """
-================================================================================
-ATTENTION: You are running ${cmd} via a wrapper around 'docker run {{ openshift.common.cli_image }}:${image_tag}'.
-This wrapper is intended only to be used to bootstrap an environment. Please
-install client tools on another host once you have granted cluster-admin
-privileges to a user.
-{% if openshift.common.deployment_type in ['openshift-enterprise','atomic-enterprise'] %}
-See https://docs.openshift.com/enterprise/latest/cli_reference/get_started_cli.html
-{% else %}
-See https://docs.openshift.org/latest/cli_reference/get_started_cli.html
-{% endif %}
-=================================================================================
-"""
-
-if [ -n "$image_tag" ]; then
-    image_tag=":$image_tag"
-fi
-
-docker run -i --privileged --net=host --user=${user}:${group} -v ~/.kube:/root/.kube -v /tmp:/tmp -v {{ openshift.common.config_base}}:{{ openshift.common.config_base }} -e KUBECONFIG=/root/.kube/config --entrypoint ${cmd} --rm {{ openshift.common.cli_image }}${image_tag} "${@}"

+ 2 - 0
roles/openshift_master/tasks/main.yml

@@ -30,6 +30,8 @@
 - name: Pull master image
   command: >
     docker pull {{ openshift.master.master_image }}:{{ openshift_image_tag }}
+  register: pull_result
+  changed_when: "'Downloaded newer image' in pull_result.stdout"
   when: openshift.common.is_containerized | bool
 
 - name: Create openshift.common.data_dir

+ 6 - 2
roles/openshift_node/tasks/main.yml

@@ -41,11 +41,15 @@
 - name: Pull node image
   command: >
     docker pull {{ openshift.node.node_image }}:{{ openshift_image_tag }}
+  register: pull_result
+  changed_when: "'Downloaded newer image' in pull_result.stdout"
   when: openshift.common.is_containerized | bool
 
 - name: Pull OpenVSwitch image
   command: >
     docker pull {{ openshift.node.ovs_image }}:{{ openshift_image_tag }}
+  register: pull_result
+  changed_when: "'Downloaded newer image' in pull_result.stdout"
   when: openshift.common.is_containerized | bool and openshift.common.use_openshift_sdn | bool
 
 - name: Install the systemd units
@@ -129,12 +133,12 @@
   service: name={{ openshift.common.service_type }}-node enabled=yes state=started
   register: node_start_result
   ignore_errors: yes
-  
+
 - name: Wait 30 seconds for docker initialization whenever node has failed
   pause:
     seconds: 30
   when: node_start_result | failed
-  
+
 - name: Start and enable node again
   service: name={{ openshift.common.service_type }}-node enabled=yes state=started
   register: node_start_result