Browse Source

Refactor openshift certificates roles.

Andrew Butcher 8 years ago
parent
commit
f64635beea

+ 12 - 88
playbooks/common/openshift-master/config.yml

@@ -156,79 +156,6 @@
     - master.etcd-ca.crt
     when: etcd_client_certs_missing is defined and etcd_client_certs_missing
 
-- name: Determine if master certificates need to be generated
-  hosts: oo_first_master:oo_masters_to_config
-  tasks:
-  - set_fact:
-      openshift_master_certs_no_etcd:
-      - admin.crt
-      - master.kubelet-client.crt
-      - "{{ 'master.proxy-client.crt' if openshift.common.version_gte_3_1_or_1_1 else omit }}"
-      - master.server.crt
-      - openshift-master.crt
-      - openshift-registry.crt
-      - openshift-router.crt
-      - etcd.server.crt
-      openshift_master_certs_etcd:
-      - master.etcd-client.crt
-
-  - set_fact:
-      openshift_master_certs: "{{ (openshift_master_certs_no_etcd | union(openshift_master_certs_etcd)) if (groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config) else openshift_master_certs_no_etcd }}"
-
-  - name: Check status of master certificates
-    stat:
-      path: "{{ openshift.common.config_base }}/master/{{ item }}"
-    with_items: "{{ openshift_master_certs }}"
-    register: g_master_cert_stat_result
-  - set_fact:
-      master_certs_missing: "{{ False in (g_master_cert_stat_result.results
-                                | oo_collect(attribute='stat.exists')
-                                | list ) }}"
-      master_cert_subdir: master-{{ openshift.common.hostname }}
-      master_cert_config_dir: "{{ openshift.common.config_base }}/master"
-
-- name: Configure master certificates
-  hosts: oo_first_master
-  vars:
-    master_generated_certs_dir: "{{ openshift.common.config_base }}/generated-configs"
-    masters_needing_certs: "{{ hostvars
-                               | oo_select_keys(groups['oo_masters_to_config'] | difference(groups['oo_first_master']))
-                               | oo_filter_list(filter_attr='master_certs_missing') }}"
-    master_hostnames: "{{ hostvars
-                               | oo_select_keys(groups['oo_masters_to_config'])
-                               | oo_collect('openshift.common.all_hostnames')
-                               | oo_flatten | unique }}"
-    sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}"
-  roles:
-  - openshift_master_certificates
-  post_tasks:
-  - name: Remove generated etcd client certs when using external etcd
-    file:
-      path: "{{ master_generated_certs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}"
-      state: absent
-    when: groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config
-    with_nested:
-    - "{{ masters_needing_certs | default([]) }}"
-    - - master.etcd-client.crt
-      - master.etcd-client.key
-
-  - name: Create a tarball of the master certs
-    command: >
-      tar -czvf {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz
-        -C {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }} .
-    args:
-      creates: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz"
-    with_items: "{{ masters_needing_certs | default([]) }}"
-
-  - name: Retrieve the master cert tarball from the master
-    fetch:
-      src: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz"
-      dest: "{{ sync_tmpdir }}/"
-      flat: yes
-      fail_on_missing: yes
-      validate_checksum: yes
-    with_items: "{{ masters_needing_certs | default([]) }}"
-
 - name: Check for cached session secrets
   hosts: oo_first_master
   roles:
@@ -243,7 +170,7 @@
 - name: Generate master session secrets
   hosts: oo_first_master
   vars:
-    g_session_secrets_present: "{{ (openshift.master.session_auth_secrets | default([]) and openshift.master.session_encryption_secrets | default([])) | length > 0 }}"
+    g_session_secrets_present: "{{ (openshift.master.session_auth_secrets | default([])) | length > 0 and (openshift.master.session_encryption_secrets | default([])) | length > 0 }}"
     g_session_auth_secrets: "{{ [ 24 | oo_generate_secret ] }}"
     g_session_encryption_secrets: "{{ [ 24 | oo_generate_secret ] }}"
   roles:
@@ -263,7 +190,7 @@
   vars:
     internal_hostnames: "{{ hostvars[groups.oo_first_master.0].openshift.common.internal_hostnames }}"
     named_certificates: "{{ hostvars[groups.oo_first_master.0].openshift_master_named_certificates | default([]) }}"
-    named_certificates_dir: "{{ hostvars[groups.oo_first_master.0].master_cert_config_dir }}/named_certificates/"
+    named_certificates_dir: "{{ hostvars[groups.oo_first_master.0].openshift.common.config_base }}/master/named_certificates/"
   tasks:
   - set_fact:
       parsed_named_certificates: "{{ named_certificates | oo_parse_named_certificates(named_certificates_dir, internal_hostnames) }}"
@@ -307,7 +234,6 @@
 - name: Configure masters
   hosts: oo_masters_to_config
   any_errors_fatal: true
-  serial: 1
   vars:
     sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}"
     openshift_master_ha: "{{ openshift.master.ha }}"
@@ -321,19 +247,17 @@
                                                 }}"
     when: "{{ (openshift_http_proxy is defined or openshift_https_proxy is defined) and
             openshift_generate_no_proxy_hosts | default(True) | bool }}"
-  pre_tasks:
-  - name: Ensure certificate directory exists
-    file:
-      path: "{{ openshift.common.config_base }}/master"
-      state: directory
-    when: master_certs_missing | bool and 'oo_first_master' not in group_names
-  - name: Unarchive the tarball on the master
-    unarchive:
-      src: "{{ sync_tmpdir }}/{{ master_cert_subdir }}.tgz"
-      dest: "{{ master_cert_config_dir }}"
-    when: master_certs_missing | bool and 'oo_first_master' not in group_names
   roles:
-  - openshift_master
+  - role: openshift_master
+    openshift_ca_host: "{{ groups.oo_first_master.0 }}"
+    openshift_master_etcd_hosts: "{{ hostvars
+                                     | oo_select_keys(groups['oo_etcd_to_config'] | default([]))
+                                     | oo_collect('openshift.common.hostname')
+                                     | default(none, true) }}"
+    openshift_master_hostnames: "{{ hostvars
+                                    | oo_select_keys(groups['oo_masters_to_config'] | default([]))
+                                    | oo_collect('openshift.common.all_hostnames')
+                                    | oo_flatten | unique }}"
   - role: nickhammond.logrotate
   - role: nuage_master
     when: openshift.common.use_nuage | bool

+ 4 - 66
playbooks/common/openshift-node/config.yml

@@ -19,23 +19,6 @@
         labels: "{{ openshift_node_labels | default(None) }}"
         annotations: "{{ openshift_node_annotations | default(None) }}"
         schedulable: "{{ openshift_schedulable | default(openshift_scheduleable) | default(None) }}"
-  - name: Check status of node certificates
-    stat:
-      path: "{{ openshift.common.config_base }}/node/{{ item }}"
-    with_items:
-    - "system:node:{{ openshift.common.hostname }}.crt"
-    - "system:node:{{ openshift.common.hostname }}.key"
-    - "system:node:{{ openshift.common.hostname }}.kubeconfig"
-    - ca.crt
-    - server.key
-    - server.crt
-    register: stat_result
-  - set_fact:
-      certs_missing: "{{ stat_result.results | oo_collect(attribute='stat.exists')
-                         | list | intersect([false])}}"
-      node_subdir: node-{{ openshift.common.hostname }}
-      config_dir: "{{ openshift.common.config_base }}/generated-configs/node-{{ openshift.common.hostname }}"
-      node_cert_dir: "{{ openshift.common.config_base }}/node"
 
 - name: Create temp directory for syncing certs
   hosts: localhost
@@ -48,53 +31,6 @@
     register: mktemp
     changed_when: False
 
-- name: Create node certificates
-  hosts: oo_first_master
-  vars:
-    nodes_needing_certs: "{{ hostvars
-                             | oo_select_keys(groups['oo_nodes_to_config']
-                                              | default([]))
-                             | oo_filter_list(filter_attr='certs_missing') }}"
-    sync_tmpdir: "{{ hostvars.localhost.mktemp.stdout }}"
-  roles:
-  - openshift_node_certificates
-  post_tasks:
-  - name: Create a tarball of the node config directories
-    command: >
-      tar -czvf {{ item.config_dir }}.tgz
-        --transform 's|system:{{ item.node_subdir }}|node|'
-        -C {{ item.config_dir }} .
-    args:
-      creates: "{{ item.config_dir }}.tgz"
-    with_items: "{{ nodes_needing_certs | default([]) }}"
-
-  - name: Retrieve the node config tarballs from the master
-    fetch:
-      src: "{{ item.config_dir }}.tgz"
-      dest: "{{ sync_tmpdir }}/"
-      flat: yes
-      fail_on_missing: yes
-      validate_checksum: yes
-    with_items: "{{ nodes_needing_certs | default([]) }}"
-
-- name: Deploy node certificates
-  hosts: oo_nodes_to_config
-  vars:
-    sync_tmpdir: "{{ hostvars.localhost.mktemp.stdout }}"
-  tasks:
-  - name: Ensure certificate directory exists
-    file:
-      path: "{{ node_cert_dir }}"
-      state: directory
-  # TODO: notify restart node
-  # possibly test service started time against certificate/config file
-  # timestamps in node to trigger notify
-  - name: Unarchive the tarball on the node
-    unarchive:
-      src: "{{ sync_tmpdir }}/{{ node_subdir }}.tgz"
-      dest: "{{ node_cert_dir }}"
-    when: certs_missing
-
 - name: Evaluate node groups
   hosts: localhost
   become: no
@@ -124,7 +60,8 @@
     when: "{{ (openshift_http_proxy is defined or openshift_https_proxy is defined) and
             openshift_generate_no_proxy_hosts | default(True) | bool }}"
   roles:
-  - openshift_node
+  - role: openshift_node
+    openshift_ca_host: "{{ groups.oo_first_master.0 }}"
 
 - name: Configure node instances
   hosts: oo_nodes_to_config:!oo_containerized_master_nodes
@@ -140,7 +77,8 @@
     when: "{{ (openshift_http_proxy is defined or openshift_https_proxy is defined) and
             openshift_generate_no_proxy_hosts | default(True) | bool }}"
   roles:
-  - openshift_node
+  - role: openshift_node
+    openshift_ca_host: "{{ groups.oo_first_master.0 }}"
 
 - name: Gather and set facts for flannel certificatess
   hosts: oo_nodes_to_config

+ 48 - 0
roles/openshift_ca/README.md

@@ -0,0 +1,48 @@
+OpenShift CA
+============
+
+This role delegates all tasks to the `openshift_ca_host` such that this role can be depended on by other OpenShift certificate roles.
+
+Requirements
+------------
+
+Role Variables
+--------------
+
+From this role:
+
+| Name                    | Default value                                 | Description                                                                 |
+|-------------------------|-----------------------------------------------|-----------------------------------------------------------------------------|
+| openshift_ca_host       | None (Required)                               | The hostname of the system where the OpenShift CA will be created.          |
+| openshift_ca_config_dir | `{{ openshift.common.config_base }}/master`   | CA certificate directory.                                                   |
+| openshift_ca_cert       | `{{ openshift_ca_config_dir }}/ca.crt`        | CA certificate path including CA certificate filename.                      |
+| openshift_ca_key        | `{{ openshift_ca_config_dir }}/ca.key`        | CA key path including CA key filename.                                      |
+| openshift_ca_serial     | `{{ openshift_ca_config_dir }}/ca.serial.txt` | CA serial path including CA serial filename.                                |
+| openshift_version       | `{{ openshift_pkg_version }}`                 | OpenShift package version.                                                  |
+
+Dependencies
+------------
+
+* openshift_repos
+* openshift_cli
+
+Example Playbook
+----------------
+
+```
+- name: Create OpenShift CA
+  hosts: localhost
+  roles:
+  - role: openshift_ca
+    openshift_ca_host: master1.example.com
+```
+
+License
+-------
+
+Apache License Version 2.0
+
+Author Information
+------------------
+
+Jason DeTiberus (jdetiber@redhat.com)

+ 4 - 4
roles/openshift_master_ca/meta/main.yml

@@ -1,10 +1,10 @@
 ---
 galaxy_info:
   author: Jason DeTiberus
-  description:
+  description: OpenShift CA
   company: Red Hat, Inc.
   license: Apache License, Version 2.0
-  min_ansible_version: 1.8
+  min_ansible_version: 2.1
   platforms:
   - name: EL
     versions:
@@ -13,5 +13,5 @@ galaxy_info:
   - cloud
   - system
 dependencies:
-- { role: openshift_repos }
-- { role: openshift_cli }
+- role: openshift_repos
+- role: openshift_cli

+ 6 - 0
roles/openshift_ca/vars/main.yml

@@ -0,0 +1,6 @@
+---
+openshift_ca_config_dir: "{{ openshift.common.config_base }}/master"
+openshift_ca_cert: "{{ openshift_ca_config_dir }}/ca.crt"
+openshift_ca_key: "{{ openshift_ca_config_dir }}/ca.key"
+openshift_ca_serial: "{{ openshift_ca_config_dir }}/ca.serial.txt"
+openshift_version: "{{ openshift_pkg_version | default('') }}"

+ 2 - 1
roles/openshift_master/meta/main.yml

@@ -4,7 +4,7 @@ galaxy_info:
   description: Master
   company: Red Hat, Inc.
   license: Apache License, Version 2.0
-  min_ansible_version: 1.7
+  min_ansible_version: 2.1
   platforms:
   - name: EL
     versions:
@@ -15,6 +15,7 @@ dependencies:
 - role: openshift_clock
 - role: openshift_docker
 - role: openshift_cli
+- role: openshift_master_certificates
 - role: openshift_cloud_provider
 - role: openshift_builddefaults
 - role: openshift_master_facts

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

@@ -210,6 +210,7 @@
   until: api_available_output.stdout == 'ok'
   retries: 120
   delay: 1
+  run_once: true
   changed_when: false
   when: openshift_master_ha | bool and openshift.master.cluster_method == 'native' and master_api_service_status_changed | bool
 

+ 0 - 34
roles/openshift_master_ca/README.md

@@ -1,34 +0,0 @@
-OpenShift Master CA
-========================
-
-TODO
-
-Requirements
-------------
-
-TODO
-
-Role Variables
---------------
-
-TODO
-
-Dependencies
-------------
-
-TODO
-
-Example Playbook
-----------------
-
-TODO
-
-License
--------
-
-Apache License Version 2.0
-
-Author Information
-------------------
-
-Jason DeTiberus (jdetiber@redhat.com)

+ 0 - 24
roles/openshift_master_ca/tasks/main.yml

@@ -1,24 +0,0 @@
----
-
-- name: Install the base package for admin tooling
-  action: "{{ ansible_pkg_mgr }} name={{ openshift.common.service_type }}{{ openshift_pkg_version | default('') | oo_image_tag_to_rpm_version(include_dash=True) }} state=present"
-  when: not openshift.common.is_containerized | bool
-  register: install_result
-
-- name: Reload generated facts
-  openshift_facts:
-  when: install_result | changed
-
-- name: Create openshift_master_config_dir if it doesn't exist
-  file:
-    path: "{{ openshift_master_config_dir }}"
-    state: directory
-
-- name: Create the master certificates if they do not already exist
-  command: >
-    {{ openshift.common.admin_binary }} create-master-certs
-      --hostnames={{ master_hostnames | join(',') }}
-      --master={{ openshift.master.api_url }}
-      --public-master={{ openshift.master.public_api_url }}
-      --cert-dir={{ openshift_master_config_dir }} --overwrite=false
-  when: master_certs_missing | bool

+ 0 - 5
roles/openshift_master_ca/vars/main.yml

@@ -1,5 +0,0 @@
----
-openshift_master_config_dir: "{{ openshift.common.config_base }}/master"
-openshift_master_ca_cert: "{{ openshift_master_config_dir }}/ca.crt"
-openshift_master_ca_key: "{{ openshift_master_config_dir }}/ca.key"
-openshift_master_ca_serial: "{{ openshift_master_config_dir }}/ca.serial.txt"

+ 23 - 6
roles/openshift_master_certificates/README.md

@@ -1,27 +1,44 @@
 OpenShift Master Certificates
 ========================
 
-TODO
+This role determines if OpenShift master certificates must be created, delegates certificate creation to the `openshift_ca_host` and then deploys those certificates to master hosts which this role is being applied to. If this role is applied to the `openshift_ca_host`, certificate deployment will be skipped.
 
 Requirements
 ------------
 
-TODO
-
 Role Variables
 --------------
 
-TODO
+From `openshift_ca`:
+
+| Name                                  | Default value                                                             | Description                                                                                                                   |
+|---------------------------------------|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
+| openshift_ca_host                     | None (Required)                                                           | The hostname of the system where the OpenShift CA will be (or has been) created.                                              |
+
+From this role:
+
+| Name                                  | Default value                                                             | Description                                                                                                                   |
+|---------------------------------------|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
+| openshift_generated_configs_dir       | `{{ openshift.common.config_base }}/generated-configs`                    | Directory in which per-master generated config directories will be created on the `openshift_ca_host`.                        |
+| openshift_master_cert_subdir          | `master-{{ openshift.common.hostname }}`                                  | Directory within `openshift_generated_configs_dir` where per-master configurations will be placed on the `openshift_ca_host`. |
+| openshift_master_config_dir           | `{{ openshift.common.config_base }}/master`                               | Master configuration directory in which certificates will be deployed on masters.                                             |
+| openshift_master_generated_config_dir | `{{ openshift_generated_configs_dir }}/{{ openshift_master_cert_subdir }` | Full path to the per-master generated config directory.                                                                       |
 
 Dependencies
 ------------
 
-TODO
+* openshift_ca
 
 Example Playbook
 ----------------
 
-TODO
+```
+- name: Create OpenShift Master Certificates
+  hosts: masters
+  roles:
+  - role: openshift_master_certificates
+    openshift_ca_host: master1.example.com
+```
 
 License
 -------

+ 3 - 3
roles/openshift_master_certificates/meta/main.yml

@@ -1,10 +1,10 @@
 ---
 galaxy_info:
   author: Jason DeTiberus
-  description:
+  description: OpenShift Master Certificates
   company: Red Hat, Inc.
   license: Apache License, Version 2.0
-  min_ansible_version: 1.8
+  min_ansible_version: 2.1
   platforms:
   - name: EL
     versions:
@@ -13,4 +13,4 @@ galaxy_info:
   - cloud
   - system
 dependencies:
-- { role: openshift_master_ca }
+- role: openshift_ca

+ 105 - 20
roles/openshift_master_certificates/tasks/main.yml

@@ -1,38 +1,123 @@
 ---
+- set_fact:
+    openshift_master_certs_no_etcd:
+    - admin.crt
+    - master.kubelet-client.crt
+    - "{{ 'master.proxy-client.crt' if openshift.common.version_gte_3_1_or_1_1 else omit }}"
+    - master.server.crt
+    - openshift-master.crt
+    - openshift-registry.crt
+    - openshift-router.crt
+    - etcd.server.crt
+    openshift_master_certs_etcd:
+    - master.etcd-client.crt
+
+- set_fact:
+    openshift_master_certs: "{{ (openshift_master_certs_no_etcd | union(openshift_master_certs_etcd )) if openshift_master_etcd_hosts | length > 0 else openshift_master_certs_no_etcd }}"
+
+- name: Check status of master certificates
+  stat:
+    path: "{{ openshift_master_config_dir }}/{{ item }}"
+  with_items:
+  - "{{ openshift_master_certs }}"
+  register: g_master_cert_stat_result
+
+- set_fact:
+    master_certs_missing: "{{ False in (g_master_cert_stat_result.results
+                              | oo_collect(attribute='stat.exists')
+                              | list) }}"
+
 - name: Ensure the generated_configs directory present
   file:
-    path: "{{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}"
+    path: "{{ openshift_master_generated_config_dir }}"
     state: directory
     mode: 0700
-  with_items: "{{ masters_needing_certs | default([]) }}"
+  when: master_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
 
 - file:
-    src: "{{ openshift_master_config_dir }}/{{ item.1 }}"
-    dest: "{{ openshift_generated_configs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}"
+    src: "{{ openshift_master_config_dir }}/{{ item }}"
+    dest: "{{ openshift_master_generated_config_dir }}/{{ item }}"
     state: hard
-  with_nested:
-  - "{{ masters_needing_certs | default([]) }}"
-  -
-    - ca.crt
-    - ca.key
-    - ca.serial.txt
+  with_items:
+  - ca.crt
+  - ca.key
+  - ca.serial.txt
+  when: master_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
 
 - name: Create the master certificates if they do not already exist
   command: >
     {{ openshift.common.admin_binary }} create-master-certs
-      --hostnames={{ item.openshift.common.all_hostnames | join(',') }}
-      --master={{ item.openshift.master.api_url }}
-      --public-master={{ item.openshift.master.public_api_url }}
-      --cert-dir={{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}
+      --hostnames={{ openshift.common.all_hostnames | join(',') }}
+      --master={{ openshift.master.api_url }}
+      --public-master={{ openshift.master.public_api_url }}
+      --cert-dir={{ openshift_master_generated_config_dir }}
       --overwrite=false
-  when: item.master_certs_missing | bool
-  with_items: "{{ masters_needing_certs | default([]) }}"
+  when: master_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
 
 - file:
-    src: "{{ openshift_master_config_dir }}/{{ item.1 }}"
-    dest: "{{ openshift_generated_configs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}"
+    src: "{{ openshift_master_config_dir }}/{{ item }}"
+    dest: "{{ openshift_master_generated_config_dir }}/{{ item }}"
     state: hard
     force: true
-  with_nested:
-  - "{{ masters_needing_certs | default([]) }}"
+  with_items:
   - "{{ hostvars[inventory_hostname] | certificates_to_synchronize }}"
+  when: master_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
+
+- name: Remove generated etcd client certs when using external etcd
+  file:
+    path: "{{ openshift_master_generated_config_dir }}/{{ item }}"
+    state: absent
+  when: openshift_master_etcd_hosts | length > 0
+  with_items:
+  - master.etcd-client.crt
+  - master.etcd-client.key
+  delegate_to: "{{ openshift_ca_host }}"
+
+- name: Create local temp directory for syncing certs
+  local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX
+  register: g_master_mktemp
+  changed_when: False
+  when: master_certs_missing | bool
+  delegate_to: localhost
+  become: no
+
+- name: Create a tarball of the master certs
+  command: >
+    tar -czvf {{ openshift_master_generated_config_dir }}.tgz
+      -C {{ openshift_master_generated_config_dir }} .
+  args:
+    creates: "{{ openshift_master_generated_config_dir }}.tgz"
+  when: master_certs_missing | bool and inventory_hostname != openshift_ca_host
+  delegate_to: "{{ openshift_ca_host }}"
+
+- name: Retrieve the master cert tarball from the master
+  fetch:
+    src: "{{ openshift_master_generated_config_dir }}.tgz"
+    dest: "{{ g_master_mktemp.stdout }}/"
+    flat: yes
+    fail_on_missing: yes
+    validate_checksum: yes
+  when: master_certs_missing | bool and inventory_hostname != openshift_ca_host
+  delegate_to: "{{ openshift_ca_host }}"
+
+- name: Ensure certificate directory exists
+  file:
+    path: "{{ openshift_master_config_dir }}"
+    state: directory
+  when: master_certs_missing | bool and inventory_hostname != openshift_ca_host
+
+- name: Unarchive the tarball on the master
+  unarchive:
+    src: "{{ g_master_mktemp.stdout }}/{{ openshift_master_cert_subdir }}.tgz"
+    dest: "{{ openshift_master_config_dir }}"
+  when: master_certs_missing | bool and inventory_hostname != openshift_ca_host
+
+- file: name={{ g_master_mktemp.stdout }} state=absent
+  changed_when: False
+  when: master_certs_missing | bool
+  delegate_to: localhost
+  become: no

+ 2 - 0
roles/openshift_master_certificates/vars/main.yml

@@ -1,3 +1,5 @@
 ---
 openshift_generated_configs_dir: "{{ openshift.common.config_base }}/generated-configs"
+openshift_master_cert_subdir: "master-{{ openshift.common.hostname }}"
 openshift_master_config_dir: "{{ openshift.common.config_base }}/master"
+openshift_master_generated_config_dir: "{{ openshift_generated_configs_dir }}/{{ openshift_master_cert_subdir }}"

+ 2 - 1
roles/openshift_node/meta/main.yml

@@ -4,7 +4,7 @@ galaxy_info:
   description: OpenShift Node
   company: Red Hat, Inc.
   license: Apache License, Version 2.0
-  min_ansible_version: 1.7
+  min_ansible_version: 2.1
   platforms:
   - name: EL
     versions:
@@ -14,6 +14,7 @@ galaxy_info:
 dependencies:
 - role: openshift_clock
 - role: openshift_docker
+- role: openshift_node_certificates
 - role: openshift_cloud_provider
 - role: openshift_common
 - role: openshift_node_dnsmasq

+ 25 - 8
roles/openshift_node_certificates/README.md

@@ -1,27 +1,44 @@
-OpenShift/Atomic Enterprise Node Certificates
-=============================================
+OpenShift Node Certificates
+===========================
 
-TODO
+This role determines if OpenShift node certificates must be created, delegates certificate creation to the `openshift_ca_host` and then deploys those certificates to node hosts which this role is being applied to.
 
 Requirements
 ------------
 
-TODO
-
 Role Variables
 --------------
 
-TODO
+From `openshift_ca`:
+
+| Name                                | Default value                                                           | Description                                                                                                               |
+|-------------------------------------|-------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
+| openshift_ca_host                   | None (Required)                                                         | The hostname of the system where the OpenShift CA will be (or has been) created.                                          |
+
+From this role:
+
+| Name                                | Default value                                                           | Description                                                                                                               |
+|-------------------------------------|-------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
+| openshift_generated_configs_dir     | `{{ openshift.common.config_base }}/generated-configs`                  | Directory in which per-node generated config directories will be created on the `openshift_ca_host`.                      |
+| openshift_node_cert_subdir          | `node-{{ openshift.common.hostname }}`                                  | Directory within `openshift_generated_configs_dir` where per-node certificates will be placed on the `openshift_ca_host`. |
+| openshift_node_config_dir           | `{{ openshift.common.config_base }}/node`                               | Node configuration directory in which certificates will be deployed on nodes.                                             |
+| openshift_node_generated_config_dir | `{{ openshift_generated_configs_dir }}/{{ openshift_node_cert_subdir }` | Full path to the per-node generated config directory.                                                                     |
 
 Dependencies
 ------------
 
-TODO
+* openshift_ca
 
 Example Playbook
 ----------------
 
-TODO
+```
+- name: Create OpenShift Node Certificates
+  hosts: nodes
+  roles:
+  - role: openshift_node_certificates
+    openshift_ca_host: master1.example.com
+```
 
 License
 -------

+ 3 - 3
roles/openshift_node_certificates/meta/main.yml

@@ -1,10 +1,10 @@
 ---
 galaxy_info:
   author: Jason DeTiberus
-  description:
+  description: OpenShift Node Certificates
   company: Red Hat, Inc.
   license: Apache License, Version 2.0
-  min_ansible_version: 1.8
+  min_ansible_version: 2.1
   platforms:
   - name: EL
     versions:
@@ -13,4 +13,4 @@ galaxy_info:
   - cloud
   - system
 dependencies:
-- { role: openshift_facts }
+- role: openshift_ca

+ 85 - 19
roles/openshift_node_certificates/tasks/main.yml

@@ -1,36 +1,102 @@
 ---
-- name: Create openshift_generated_configs_dir if it doesn\'t exist
+- name: Check status of node certificates
+  stat:
+    path: "{{ openshift.common.config_base }}/node/{{ item }}"
+  with_items:
+  - "system:node:{{ openshift.common.hostname }}.crt"
+  - "system:node:{{ openshift.common.hostname }}.key"
+  - "system:node:{{ openshift.common.hostname }}.kubeconfig"
+  - ca.crt
+  - server.key
+  - server.crt
+  register: g_node_cert_stat_result
+
+- set_fact:
+    node_certs_missing: "{{ False in (g_node_cert_stat_result.results
+                            | oo_collect(attribute='stat.exists')
+                            | list) }}"
+
+- name: Create openshift_generated_configs_dir if it does not exist
   file:
     path: "{{ openshift_generated_configs_dir }}"
     state: directory
     mode: 0700
-  when: nodes_needing_certs | length > 0
+  when: node_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
 
 - name: Generate the node client config
   command: >
     {{ openshift.common.admin_binary }} create-api-client-config
-      --certificate-authority={{ openshift_master_ca_cert }}
-      --client-dir={{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}
+      --certificate-authority={{ openshift_ca_cert }}
+      --client-dir={{ openshift_node_generated_config_dir }}
       --groups=system:nodes
-      --master={{ openshift.master.api_url }}
-      --signer-cert={{ openshift_master_ca_cert }}
-      --signer-key={{ openshift_master_ca_key }}
-      --signer-serial={{ openshift_master_ca_serial }}
-      --user=system:node:{{ item.openshift.common.hostname }}
+      --master={{ hostvars[openshift_ca_host].openshift.master.api_url }}
+      --signer-cert={{ openshift_ca_cert }}
+      --signer-key={{ openshift_ca_key }}
+      --signer-serial={{ openshift_ca_serial }}
+      --user=system:node:{{ openshift.common.hostname }}
   args:
-    creates: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}"
-  with_items: "{{ nodes_needing_certs | default([]) }}"
+    creates: "{{ openshift_node_generated_config_dir }}"
+  when: node_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
 
 - name: Generate the node server certificate
   command: >
     {{ openshift.common.admin_binary }} ca create-server-cert
-      --cert={{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}/server.crt
-      --key={{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}/server.key
+      --cert={{ openshift_node_generated_config_dir }}/server.crt
+      --key={{ openshift_generated_configs_dir }}/node-{{ openshift.common.hostname }}/server.key
       --overwrite=true
-      --hostnames={{ item.openshift.common.all_hostnames |join(",") }}
-      --signer-cert={{ openshift_master_ca_cert }}
-      --signer-key={{ openshift_master_ca_key }}
-      --signer-serial={{ openshift_master_ca_serial }}
+      --hostnames={{ openshift.common.all_hostnames |join(",") }}
+      --signer-cert={{ openshift_ca_cert }}
+      --signer-key={{ openshift_ca_key }}
+      --signer-serial={{ openshift_ca_serial }}
+  args:
+    creates: "{{ openshift_node_generated_config_dir }}/server.crt"
+  when: node_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host}}"
+
+- name: Create local temp directory for syncing certs
+  local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX
+  register: node_cert_mktemp
+  changed_when: False
+  when: node_certs_missing | bool
+  delegate_to: localhost
+  become: no
+
+- name: Create a tarball of the node config directories
+  command: >
+    tar -czvf {{ openshift_node_generated_config_dir }}.tgz
+    --transform 's|system:{{ openshift_node_cert_subdir }}|node|'
+    -C {{ openshift_node_generated_config_dir }} .
   args:
-    creates: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}/server.crt"
-  with_items: "{{ nodes_needing_certs | default([]) }}"
+    creates: "{{ openshift_node_generated_config_dir }}.tgz"
+  when: node_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
+
+- name: Retrieve the node config tarballs from the master
+  fetch:
+    src: "{{ openshift_node_generated_config_dir }}.tgz"
+    dest: "{{ node_cert_mktemp.stdout }}/"
+    flat: yes
+    fail_on_missing: yes
+    validate_checksum: yes
+  when: node_certs_missing | bool
+  delegate_to: "{{ openshift_ca_host }}"
+
+- name: Ensure certificate directory exists
+  file:
+    path: "{{ openshift_node_cert_dir }}"
+    state: directory
+  when: node_certs_missing | bool
+
+- name: Unarchive the tarball on the node
+  unarchive:
+    src: "{{ node_cert_mktemp.stdout }}/{{ openshift_node_cert_subdir }}.tgz"
+    dest: "{{ openshift_node_cert_dir }}"
+  when: node_certs_missing | bool
+
+- file: name={{ node_cert_mktemp.stdout }} state=absent
+  changed_when: False
+  when: node_certs_missing | bool
+  delegate_to: localhost
+  become: no

+ 4 - 5
roles/openshift_node_certificates/vars/main.yml

@@ -1,7 +1,6 @@
 ---
-openshift_node_config_dir: "{{ openshift.common.config_base }}/node"
-openshift_master_config_dir: "{{ openshift.common.config_base }}/master"
 openshift_generated_configs_dir: "{{ openshift.common.config_base }}/generated-configs"
-openshift_master_ca_cert: "{{ openshift_master_config_dir }}/ca.crt"
-openshift_master_ca_key: "{{ openshift_master_config_dir }}/ca.key"
-openshift_master_ca_serial: "{{ openshift_master_config_dir }}/ca.serial.txt"
+openshift_node_cert_dir: "{{ openshift.common.config_base }}/node"
+openshift_node_cert_subdir: "node-{{ openshift.common.hostname }}"
+openshift_node_config_dir: "{{ openshift.common.config_base }}/node"
+openshift_node_generated_config_dir: "{{ openshift_generated_configs_dir }}/{{ openshift_node_cert_subdir }}"