From 5120f8e90c0178ac7f6d911159ceb278dd87b4c9 Mon Sep 17 00:00:00 2001
From: Michael Gugino <mgugino@redhat.com>
Date: Thu, 16 Nov 2017 14:56:14 -0500
Subject: Implement container runtime role

---
 roles/container_runtime/tasks/crio_firewall.yml    |  40 +++++
 roles/container_runtime/tasks/main.yml             |  85 +++++++++++
 roles/container_runtime/tasks/package_docker.yml   | 167 +++++++++++++++++++++
 roles/container_runtime/tasks/registry_auth.yml    |  32 ++++
 .../tasks/systemcontainer_crio.yml                 | 164 ++++++++++++++++++++
 .../tasks/systemcontainer_docker.yml               | 163 ++++++++++++++++++++
 roles/container_runtime/tasks/udev_workaround.yml  |  24 +++
 7 files changed, 675 insertions(+)
 create mode 100644 roles/container_runtime/tasks/crio_firewall.yml
 create mode 100644 roles/container_runtime/tasks/main.yml
 create mode 100644 roles/container_runtime/tasks/package_docker.yml
 create mode 100644 roles/container_runtime/tasks/registry_auth.yml
 create mode 100644 roles/container_runtime/tasks/systemcontainer_crio.yml
 create mode 100644 roles/container_runtime/tasks/systemcontainer_docker.yml
 create mode 100644 roles/container_runtime/tasks/udev_workaround.yml

(limited to 'roles/container_runtime/tasks')

diff --git a/roles/container_runtime/tasks/crio_firewall.yml b/roles/container_runtime/tasks/crio_firewall.yml
new file mode 100644
index 000000000..fbd1ff515
--- /dev/null
+++ b/roles/container_runtime/tasks/crio_firewall.yml
@@ -0,0 +1,40 @@
+---
+- when: r_crio_firewall_enabled | bool and not r_crio_use_firewalld | bool
+  block:
+  - name: Add iptables allow rules
+    os_firewall_manage_iptables:
+      name: "{{ item.service }}"
+      action: add
+      protocol: "{{ item.port.split('/')[1] }}"
+      port: "{{ item.port.split('/')[0] }}"
+    when: item.cond | default(True)
+    with_items: "{{ r_crio_os_firewall_allow }}"
+
+  - name: Remove iptables rules
+    os_firewall_manage_iptables:
+      name: "{{ item.service }}"
+      action: remove
+      protocol: "{{ item.port.split('/')[1] }}"
+      port: "{{ item.port.split('/')[0] }}"
+    when: item.cond | default(True)
+    with_items: "{{ r_crio_os_firewall_deny }}"
+
+- when: r_crio_firewall_enabled | bool and r_crio_use_firewalld | bool
+  block:
+  - name: Add firewalld allow rules
+    firewalld:
+      port: "{{ item.port }}"
+      permanent: true
+      immediate: true
+      state: enabled
+    when: item.cond | default(True)
+    with_items: "{{ r_crio_os_firewall_allow }}"
+
+  - name: Remove firewalld allow rules
+    firewalld:
+      port: "{{ item.port }}"
+      permanent: true
+      immediate: true
+      state: disabled
+    when: item.cond | default(True)
+    with_items: "{{ r_crio_os_firewall_deny }}"
diff --git a/roles/container_runtime/tasks/main.yml b/roles/container_runtime/tasks/main.yml
new file mode 100644
index 000000000..6d68082b1
--- /dev/null
+++ b/roles/container_runtime/tasks/main.yml
@@ -0,0 +1,85 @@
+---
+- include_tasks: udev_workaround.yml
+  when: docker_udev_workaround | default(False) | bool
+
+- name: Add enterprise registry, if necessary
+  set_fact:
+    l2_docker_additional_registries: "{{ l2_docker_additional_registries + [openshift_docker_ent_reg] }}"
+  when:
+    - openshift.common.deployment_type == 'openshift-enterprise'
+    - openshift_docker_ent_reg != ''
+    - openshift_docker_ent_reg not in l2_docker_additional_registries
+    - not openshift_use_crio_only | bool
+
+- name: Use Package Docker if Requested
+  include_tasks: package_docker.yml
+  when:
+    - not openshift_docker_use_system_container
+    - not openshift_use_crio_only
+
+- name: Ensure /var/lib/containers exists
+  file:
+    path: /var/lib/containers
+    state: directory
+
+- name: Fix SELinux Permissions on /var/lib/containers
+  command: "restorecon -R /var/lib/containers/"
+  changed_when: false
+
+- name: Use System Container Docker if Requested
+  include_tasks: systemcontainer_docker.yml
+  when:
+    - openshift_docker_use_system_container
+    - not openshift_use_crio_only
+
+- name: Add CRI-O usage Requested
+  include_tasks: systemcontainer_crio.yml
+  when:
+    - openshift_use_crio
+    - openshift_docker_is_node_or_master | bool
+
+- name: stat the docker data dir
+  stat:
+    path: "{{ docker_default_storage_path }}"
+  register: dockerstat
+
+- when:
+    - openshift_use_crio
+    - dockerstat.stat.islnk is defined and not (dockerstat.stat.islnk | bool)
+  block:
+    - name: stop the current running docker
+      systemd:
+        state: stopped
+        name: "{{ openshift_docker_service_name }}"
+
+    - name: copy "{{ docker_default_storage_path }}" to "{{ docker_alt_storage_path }}"
+      command: "cp -r {{ docker_default_storage_path }} {{ docker_alt_storage_path }}"
+      register: results
+      failed_when:
+        - results.rc != 0
+
+    - name: "Set the selinux context on {{ docker_alt_storage_path }}"
+      command: "semanage fcontext -a -e {{ docker_default_storage_path }} {{ docker_alt_storage_path }}"
+      register: results
+      failed_when:
+        - results.rc == 1
+        - "'already exists' not in results.stderr"
+
+    - name: "restorecon the {{ docker_alt_storage_path }}"
+      command: "restorecon -r {{ docker_alt_storage_path }}"
+
+    - name: Remove the old docker location
+      file:
+        state: absent
+        path: "{{ docker_default_storage_path }}"
+
+    - name: Setup the link
+      file:
+        state: link
+        src: "{{ docker_alt_storage_path }}"
+        path: "{{ docker_default_storage_path }}"
+
+    - name: start docker
+      systemd:
+        state: started
+        name: "{{ openshift_docker_service_name }}"
diff --git a/roles/container_runtime/tasks/package_docker.yml b/roles/container_runtime/tasks/package_docker.yml
new file mode 100644
index 000000000..40ab75a25
--- /dev/null
+++ b/roles/container_runtime/tasks/package_docker.yml
@@ -0,0 +1,167 @@
+---
+- name: Get current installed Docker version
+  command: "{{ repoquery_installed }} --qf '%{version}' docker"
+  when: not openshift.common.is_atomic | bool
+  register: curr_docker_version
+  retries: 4
+  until: curr_docker_version | succeeded
+  changed_when: false
+
+- name: Error out if Docker pre-installed but too old
+  fail:
+    msg: "Docker {{ curr_docker_version.stdout }} is installed, but >= 1.9.1 is required."
+  when: not curr_docker_version | skipped and curr_docker_version.stdout != '' and curr_docker_version.stdout | version_compare('1.9.1', '<') and not docker_version is defined
+
+- name: Error out if requested Docker is too old
+  fail:
+    msg: "Docker {{ docker_version }} requested, but >= 1.9.1 is required."
+  when: docker_version is defined and docker_version | version_compare('1.9.1', '<')
+
+# If a docker_version was requested, sanity check that we can install or upgrade to it, and
+# no downgrade is required.
+- name: Fail if Docker version requested but downgrade is required
+  fail:
+    msg: "Docker {{ curr_docker_version.stdout }} is installed, but version {{ docker_version }} was requested."
+  when: not curr_docker_version | skipped and curr_docker_version.stdout != '' and docker_version is defined and curr_docker_version.stdout | version_compare(docker_version, '>')
+
+# This involves an extremely slow migration process, users should instead run the
+# Docker 1.10 upgrade playbook to accomplish this.
+- name: Error out if attempting to upgrade Docker across the 1.10 boundary
+  fail:
+    msg: "Cannot upgrade Docker to >= 1.10, please upgrade or remove Docker manually, or use the Docker upgrade playbook if OpenShift is already installed."
+  when: not curr_docker_version | skipped and curr_docker_version.stdout != '' and curr_docker_version.stdout | version_compare('1.10', '<') and docker_version is defined and docker_version | version_compare('1.10', '>=')
+
+# Make sure Docker is installed, but does not update a running version.
+# Docker upgrades are handled by a separate playbook.
+# Note: The curr_docker_version.stdout check can be removed when https://github.com/ansible/ansible/issues/33187 gets fixed.
+- name: Install Docker
+  package: name=docker{{ '-' + docker_version if docker_version is defined else '' }} state=present
+  when: not openshift.common.is_atomic | bool and not curr_docker_version | skipped and not curr_docker_version.stdout != ''
+  register: result
+  until: result | success
+
+- block:
+  # Extend the default Docker service unit file when using iptables-services
+  - name: Ensure docker.service.d directory exists
+    file:
+      path: "{{ docker_systemd_dir }}"
+      state: directory
+
+  - name: Configure Docker service unit file
+    template:
+      dest: "{{ docker_systemd_dir }}/custom.conf"
+      src: custom.conf.j2
+    notify:
+    - restart container runtime
+  when: not (os_firewall_use_firewalld | default(False)) | bool
+
+- stat: path=/etc/sysconfig/docker
+  register: docker_check
+
+- name: Set registry params
+  lineinfile:
+    dest: /etc/sysconfig/docker
+    regexp: '^{{ item.reg_conf_var }}=.*$'
+    line: "{{ item.reg_conf_var }}='{{ item.reg_fact_val | oo_prepend_strings_in_list(item.reg_flag ~ ' ') | join(' ') }}'"
+  when:
+  - item.reg_fact_val != []
+  - docker_check.stat.isreg is defined
+  - docker_check.stat.isreg
+  with_items:
+  - reg_conf_var: ADD_REGISTRY
+    reg_fact_val: "{{ l2_docker_additional_registries }}"
+    reg_flag: --add-registry
+  - reg_conf_var: BLOCK_REGISTRY
+    reg_fact_val: "{{ l2_docker_blocked_registries }}"
+    reg_flag: --block-registry
+  - reg_conf_var: INSECURE_REGISTRY
+    reg_fact_val: "{{ l2_docker_insecure_registries }}"
+    reg_flag: --insecure-registry
+  notify:
+  - restart container runtime
+
+- name: Place additional/blocked/insecure registries in /etc/containers/registries.conf
+  template:
+    dest: "{{ containers_registries_conf_path }}"
+    src: registries.conf
+  when: openshift_docker_use_etc_containers | bool
+  notify:
+  - restart container runtime
+
+- name: Set Proxy Settings
+  lineinfile:
+    dest: /etc/sysconfig/docker
+    regexp: '^{{ item.reg_conf_var }}=.*$'
+    line: "{{ item.reg_conf_var }}='{{ item.reg_fact_val }}'"
+    state: "{{ 'present' if item.reg_fact_val != '' else 'absent'}}"
+  with_items:
+  - reg_conf_var: HTTP_PROXY
+    reg_fact_val: "{{ docker_http_proxy }}"
+  - reg_conf_var: HTTPS_PROXY
+    reg_fact_val: "{{ docker_https_proxy }}"
+  - reg_conf_var: NO_PROXY
+    reg_fact_val: "{{ docker_no_proxy }}"
+  notify:
+  - restart container runtime
+  when:
+  - docker_check.stat.isreg is defined
+  - docker_check.stat.isreg
+  - docker_http_proxy != '' or docker_https_proxy != ''
+
+- name: Set various Docker options
+  lineinfile:
+    dest: /etc/sysconfig/docker
+    regexp: '^OPTIONS=.*$'
+    line: "OPTIONS='\
+      {% if ansible_selinux.status | default(None) == 'enabled' and openshift_docker_selinux_enabled | default(true) | bool %} --selinux-enabled {% endif %} \
+      {% if openshift_docker_log_driver | bool %} --log-driver {{ openshift_docker_log_driver }}{% endif %} \
+      {% if l2_docker_log_options != [] %} {{ l2_docker_log_options |  oo_split() | oo_prepend_strings_in_list('--log-opt ') | join(' ')}}{% endif %} \
+      {% if openshift_docker_hosted_registry_insecure and (openshift_docker_hosted_registry_network | bool) %} --insecure-registry={{ openshift_docker_hosted_registry_network }} {% endif %} \
+      {% if docker_options is defined %} {{ docker_options }}{% endif %} \
+      {% if openshift_docker_options %} {{ openshift_docker_options }}{% endif %} \
+      {% if openshift_docker_disable_push_dockerhub %} --confirm-def-push={{ openshift_docker_disable_push_dockerhub | bool }}{% endif %} \
+      --signature-verification={{ openshift_docker_signature_verification | bool }}'"
+  when: docker_check.stat.isreg is defined and docker_check.stat.isreg
+  notify:
+  - restart container runtime
+
+- stat: path=/etc/sysconfig/docker-network
+  register: sysconfig_docker_network_check
+
+- name: Configure Docker Network OPTIONS
+  lineinfile:
+    dest: /etc/sysconfig/docker-network
+    regexp: '^DOCKER_NETWORK_OPTIONS=.*$'
+    line: "DOCKER_NETWORK_OPTIONS='\
+      {% if openshift.node is defined and openshift.node.sdn_mtu is defined %} --mtu={{ openshift.node.sdn_mtu }}{% endif %}'"
+  when:
+  - sysconfig_docker_network_check.stat.isreg is defined
+  - sysconfig_docker_network_check.stat.isreg
+  notify:
+  - restart container runtime
+
+# The following task is needed as the systemd module may report a change in
+# state even though docker is already running.
+- name: Detect if docker is already started
+  command: "systemctl show docker -p ActiveState"
+  changed_when: False
+  register: r_docker_already_running_result
+
+- name: Start the Docker service
+  systemd:
+    name: docker
+    enabled: yes
+    state: started
+    daemon_reload: yes
+  register: r_docker_package_docker_start_result
+  until: not r_docker_package_docker_start_result | failed
+  retries: 3
+  delay: 30
+
+- set_fact:
+    docker_service_status_changed: "{{ (r_docker_package_docker_start_result | changed) and (r_docker_already_running_result.stdout != 'ActiveState=active' ) }}"
+
+- meta: flush_handlers
+
+# This needs to run after docker is restarted to account for proxy settings.
+- include_tasks: registry_auth.yml
diff --git a/roles/container_runtime/tasks/registry_auth.yml b/roles/container_runtime/tasks/registry_auth.yml
new file mode 100644
index 000000000..2c7bc5711
--- /dev/null
+++ b/roles/container_runtime/tasks/registry_auth.yml
@@ -0,0 +1,32 @@
+---
+- name: Check for credentials file for registry auth
+  stat:
+    path: "{{ docker_cli_auth_config_path }}/config.json"
+  when: oreg_auth_user is defined
+  register: docker_cli_auth_credentials_stat
+
+- name: Create credentials for docker cli registry auth
+  command: "docker --config={{ docker_cli_auth_config_path }} login -u {{ oreg_auth_user }} -p {{ oreg_auth_password }} {{ oreg_host }}"
+  register: openshift_docker_credentials_create_res
+  retries: 3
+  delay: 5
+  until: openshift_docker_credentials_create_res.rc == 0
+  when:
+  - not openshift_docker_alternative_creds | bool
+  - oreg_auth_user is defined
+  - (not docker_cli_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool
+
+# docker_creds is a custom module from lib_utils
+# 'docker login' requires a docker.service running on the local host, this is an
+# alternative implementation for non-docker hosts.  This implementation does not
+# check the registry to determine whether or not the credentials will work.
+- name: Create credentials for docker cli registry auth (alternative)
+  docker_creds:
+    path: "{{ docker_cli_auth_config_path }}"
+    registry: "{{ oreg_host }}"
+    username: "{{ oreg_auth_user }}"
+    password: "{{ oreg_auth_password }}"
+  when:
+  - openshift_docker_alternative_creds | bool
+  - oreg_auth_user is defined
+  - (not docker_cli_auth_credentials_stat.stat.exists or oreg_auth_credentials_replace) | bool
diff --git a/roles/container_runtime/tasks/systemcontainer_crio.yml b/roles/container_runtime/tasks/systemcontainer_crio.yml
new file mode 100644
index 000000000..8dcfe60ef
--- /dev/null
+++ b/roles/container_runtime/tasks/systemcontainer_crio.yml
@@ -0,0 +1,164 @@
+---
+# TODO: Much of this file is shared with container engine tasks
+
+- name: Ensure container-selinux is installed
+  package:
+    name: container-selinux
+    state: present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+- name: Check we are not using node as a Docker container with CRI-O
+  fail: msg='Cannot use CRI-O with node configured as a Docker container'
+  when:
+    - openshift.common.is_containerized | bool
+    - not openshift.common.is_node_system_container | bool
+
+# Used to pull and install the system container
+- name: Ensure atomic is installed
+  package:
+    name: atomic
+    state: present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+# At the time of writing the atomic command requires runc for it's own use. This
+# task is here in the even that the atomic package ever removes the dependency.
+- name: Ensure runc is installed
+  package:
+    name: runc
+    state: present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+
+- name: Check that overlay is in the kernel
+  shell: lsmod | grep overlay
+  register: l_has_overlay_in_kernel
+  ignore_errors: yes
+  failed_when: false
+
+- when: l_has_overlay_in_kernel.rc != 0
+  block:
+
+    - name: Add overlay to modprobe.d
+      template:
+        dest: /etc/modules-load.d/overlay.conf
+        src: overlay.conf.j2
+        backup: yes
+
+    - name: Manually modprobe overlay into the kernel
+      command: modprobe overlay
+
+    - name: Enable and start systemd-modules-load
+      service:
+        name: systemd-modules-load
+        enabled: yes
+        state: restarted
+
+- name: Ensure proxies are in the atomic.conf
+  include_role:
+    name: openshift_atomic
+    tasks_from: proxy
+
+- block:
+
+    - name: Set CRI-O image defaults
+      set_fact:
+        l_crio_image_prepend: "docker.io/gscrivano"
+        l_crio_image_name: "cri-o-fedora"
+        l_crio_image_tag: "latest"
+
+    - name: Use Centos based image when distribution is CentOS
+      set_fact:
+        l_crio_image_name: "cri-o-centos"
+      when: ansible_distribution == "CentOS"
+
+    - name: Set CRI-O image tag
+      set_fact:
+        l_crio_image_tag: "{{ l_openshift_image_tag }}"
+      when:
+        - openshift_deployment_type == 'openshift-enterprise'
+
+    - name: Use RHEL based image when distribution is Red Hat
+      set_fact:
+        l_crio_image_prepend: "registry.access.redhat.com/openshift3"
+        l_crio_image_name: "cri-o"
+      when: ansible_distribution == "RedHat"
+
+    - name: Set the full image name
+      set_fact:
+        l_crio_image: "{{ l_crio_image_prepend }}/{{ l_crio_image_name }}:{{ l_crio_image_tag }}"
+
+    # For https://github.com/openshift/aos-cd-jobs/pull/624#pullrequestreview-61816548
+    - name: Use a specific image if requested
+      set_fact:
+        l_crio_image: "{{ openshift_crio_systemcontainer_image_override }}"
+      when:
+        - openshift_crio_systemcontainer_image_override is defined
+        - openshift_crio_systemcontainer_image_override != ""
+
+    # Be nice and let the user see the variable result
+    - debug:
+        var: l_crio_image
+
+# NOTE: no_proxy added as a workaround until https://github.com/projectatomic/atomic/pull/999 is released
+- name: Pre-pull CRI-O System Container image
+  command: "atomic pull --storage ostree {{ l_crio_image }}"
+  changed_when: false
+  environment:
+    NO_PROXY: "{{ openshift.common.no_proxy | default('') }}"
+
+
+- name: Install CRI-O System Container
+  oc_atomic_container:
+    name: "cri-o"
+    image: "{{ l_crio_image }}"
+    state: latest
+
+- name: Remove CRI-O default configuration files
+  file:
+    path: "{{ item }}"
+    state: absent
+  with_items:
+    - /etc/cni/net.d/200-loopback.conf
+    - /etc/cni/net.d/100-crio-bridge.conf
+
+- name: Create the CRI-O configuration
+  template:
+    dest: /etc/crio/crio.conf
+    src: crio.conf.j2
+    backup: yes
+
+- name: Ensure CNI configuration directory exists
+  file:
+    path: /etc/cni/net.d/
+    state: directory
+
+- name: setup firewall for CRI-O
+  include_tasks: crio_firewall.yml
+  static: yes
+
+- name: Configure the CNI network
+  template:
+    dest: /etc/cni/net.d/openshift-sdn.conf
+    src: 80-openshift-sdn.conf.j2
+
+- name: Start the CRI-O service
+  systemd:
+    name: "cri-o"
+    enabled: yes
+    state: started
+    daemon_reload: yes
+  register: start_result
+
+- meta: flush_handlers
+
+# If we are using crio only, docker.service might not be available for
+# 'docker login'
+- include_tasks: registry_auth.yml
+  vars:
+    openshift_docker_alternative_creds: "{{ openshift_use_crio_only }}"
diff --git a/roles/container_runtime/tasks/systemcontainer_docker.yml b/roles/container_runtime/tasks/systemcontainer_docker.yml
new file mode 100644
index 000000000..84217e50c
--- /dev/null
+++ b/roles/container_runtime/tasks/systemcontainer_docker.yml
@@ -0,0 +1,163 @@
+---
+# If docker_options are provided we should fail. We should not install docker and ignore
+# the users configuration. NOTE: docker_options == inventory:openshift_docker_options
+- name: Fail quickly if openshift_docker_options are set
+  assert:
+    that:
+      - "{% if not openshift_docker_options %}1{% else %}0{% endif %}"
+    msg: |
+      Docker via System Container does not allow for the use of the openshift_docker_options
+      variable. If you want to use openshift_docker_options you will need to use the
+      traditional docker package install. Otherwise, comment out openshift_docker_options
+      in your inventory file.
+
+- name: Ensure container-selinux is installed
+  package:
+    name: container-selinux
+    state: present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+# Used to pull and install the system container
+- name: Ensure atomic is installed
+  package:
+    name: atomic
+    state: present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+# At the time of writing the atomic command requires runc for it's own use. This
+# task is here in the even that the atomic package ever removes the dependency.
+- name: Ensure runc is installed
+  package:
+    name: runc
+    state: present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+# Make sure Docker is installed so we are able to use the client
+- name: Install Docker so we can use the client
+  package: name=docker{{ '-' + docker_version if docker_version is defined else '' }} state=present
+  when: not openshift.common.is_atomic | bool
+  register: result
+  until: result | success
+
+# Make sure docker is disabled. Errors are ignored.
+- name: Disable Docker
+  systemd:
+    name: docker
+    enabled: no
+    state: stopped
+    daemon_reload: yes
+  ignore_errors: True
+  register: r_docker_systemcontainer_docker_stop_result
+  until: not r_docker_systemcontainer_docker_stop_result | failed
+  retries: 3
+  delay: 30
+
+- name: Ensure proxies are in the atomic.conf
+  include_role:
+    name: openshift_atomic
+    tasks_from: proxy
+
+- block:
+
+    - name: Set to default prepend
+      set_fact:
+        l_docker_image_prepend: "gscrivano"
+        l_docker_image_tag: "latest"
+
+    - name: Set container engine image tag
+      set_fact:
+        l_docker_image_tag: "{{ l_openshift_image_tag }}"
+      when:
+        - openshift_deployment_type == 'openshift-enterprise'
+
+    - name: Use Red Hat Registry for image when distribution is Red Hat
+      set_fact:
+        l_docker_image_prepend: "registry.access.redhat.com/openshift3"
+      when: ansible_distribution == 'RedHat'
+
+    - name: Use Fedora Registry for image when distribution is Fedora
+      set_fact:
+        l_docker_image_prepend: "registry.fedoraproject.org/f25"
+      when: ansible_distribution == 'Fedora'
+
+    - name: Set the full image name
+      set_fact:
+        l_docker_image: "{{ l_docker_image_prepend }}/{{ openshift_docker_service_name }}:{{ l_docker_image_tag }}"
+
+    # For https://github.com/openshift/openshift-ansible/pull/5354#issuecomment-328552959
+    - name: Use a specific image if requested
+      set_fact:
+        l_docker_image: "{{ openshift_docker_systemcontainer_image_override }}"
+      when:
+        - openshift_docker_systemcontainer_image_override is defined
+        - openshift_docker_systemcontainer_image_override != ""
+
+    # Be nice and let the user see the variable result
+    - debug:
+        var: l_docker_image
+
+# NOTE: no_proxy added as a workaround until https://github.com/projectatomic/atomic/pull/999 is released
+- name: Pre-pull Container Engine System Container image
+  command: "atomic pull --storage ostree {{ l_docker_image }}"
+  changed_when: false
+  environment:
+    NO_PROXY: "{{ docker_no_proxy }}"
+
+
+- name: Ensure container-engine.service.d directory exists
+  file:
+    path: "{{ container_engine_systemd_dir }}"
+    state: directory
+
+- name: Ensure /etc/docker directory exists
+  file:
+    path: "{{ docker_conf_dir }}"
+    state: directory
+
+- name: Install Container Engine System Container
+  oc_atomic_container:
+    name: "{{ openshift_docker_service_name }}"
+    image: "{{ l_docker_image }}"
+    state: latest
+
+- name: Configure Container Engine Service File
+  template:
+    dest: "{{ container_engine_systemd_dir }}/custom.conf"
+    src: systemcontainercustom.conf.j2
+
+# Configure container-engine using the container-daemon.json file
+# NOTE: daemon.json and container-daemon.json have been seperated to avoid
+#       collision.
+- name: Configure Container Engine
+  template:
+    dest: "{{ docker_conf_dir }}/container-daemon.json"
+    src: daemon.json
+
+# Enable and start the container-engine service
+- name: Start the Container Engine service
+  systemd:
+    name: "{{ openshift_docker_service_name }}"
+    enabled: yes
+    state: started
+    daemon_reload: yes
+  register: r_docker_systemcontainer_docker_start_result
+  until: not r_docker_systemcontainer_docker_start_result | failed
+  retries: 3
+  delay: 30
+
+- set_fact:
+    docker_service_status_changed: "{{ r_docker_systemcontainer_docker_start_result | changed }}"
+
+- meta: flush_handlers
+
+# Since docker is running as a system container, docker login will fail to create
+# credentials.  Use alternate method if requiring authenticated registries.
+- include_tasks: registry_auth.yml
+  vars:
+    openshift_docker_alternative_creds: True
diff --git a/roles/container_runtime/tasks/udev_workaround.yml b/roles/container_runtime/tasks/udev_workaround.yml
new file mode 100644
index 000000000..257c3123d
--- /dev/null
+++ b/roles/container_runtime/tasks/udev_workaround.yml
@@ -0,0 +1,24 @@
+---
+
+- name: Getting current systemd-udevd exec command
+  command: grep -e "^ExecStart=" /lib/systemd/system/systemd-udevd.service
+  changed_when: false
+  register: udevw_udev_start_cmd
+
+- name: Assure systemd-udevd.service.d directory exists
+  file:
+    path: "{{ udevw_udevd_dir }}"
+    state: directory
+
+- name: Create systemd-udevd override file
+  copy:
+    content: |
+      [Service]
+      #Need blank ExecStart to "clear" pre-existing one
+      ExecStart=
+      {{ udevw_udev_start_cmd.stdout }} --event-timeout=300
+    dest: "{{ udevw_udevd_dir }}/override.conf"
+    owner: root
+    mode: "0644"
+  notify:
+    - restart udev
-- 
cgit v1.2.3