---
# Update master config when ca-bundle not referenced. Services will be
# restarted below after new CA certificate has been distributed.
- name: Ensure ca-bundle.crt is referenced in master configuration
  hosts: oo_masters_to_config
  tasks:
  - slurp:
      src: "{{ openshift.common.config_base }}/master/master-config.yaml"
    register: g_master_config_output
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: kubeletClientInfo.ca
      yaml_value: ca-bundle.crt
    when: (g_master_config_output.content|b64decode|from_yaml).kubeletClientInfo.ca != 'ca-bundle.crt'
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: serviceAccountConfig.masterCA
      yaml_value: ca-bundle.crt
    when: (g_master_config_output.content|b64decode|from_yaml).serviceAccountConfig.masterCA != 'ca-bundle.crt'
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: oauthConfig.masterCA
      yaml_value: ca-bundle.crt
    when: (g_master_config_output.content|b64decode|from_yaml).oauthConfig.masterCA != 'ca-bundle.crt'
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: etcdClientInfo.ca
      yaml_value: ca-bundle.crt
    when:
    - groups.oo_etcd_to_config | default([]) | length == 0
    - (g_master_config_output.content|b64decode|from_yaml).etcdClientInfo.ca != 'ca-bundle.crt'
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: etcdConfig.peerServingInfo.clientCA
      yaml_value: ca-bundle.crt
    when:
    - groups.oo_etcd_to_config | default([]) | length == 0
    - (g_master_config_output.content|b64decode|from_yaml).etcdConfig.peerServingInfo.clientCA != 'ca-bundle.crt'
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: etcdConfig.servingInfo.clientCA
      yaml_value: ca-bundle.crt
    when:
    - groups.oo_etcd_to_config | default([]) | length == 0
    - (g_master_config_output.content|b64decode|from_yaml).etcdConfig.servingInfo.clientCA != 'ca-bundle.crt'
  # Set servingInfo.clientCA to client-ca-bundle.crt in order to roll the CA certificate.
  # This change will be reverted in playbooks/redeploy-certificates.yml
  - modify_yaml:
      dest: "{{ openshift.common.config_base }}/master/master-config.yaml"
      yaml_key: servingInfo.clientCA
      yaml_value: client-ca-bundle.crt
    when: (g_master_config_output.content|b64decode|from_yaml).servingInfo.clientCA != 'client-ca-bundle.crt'

- name: Copy current OpenShift CA to legacy directory
  hosts: oo_masters_to_config
  pre_tasks:
  - name: Create legacy-ca directory
    file:
      path: "{{ openshift.common.config_base }}/master/legacy-ca"
      state: directory
      mode: 0700
      owner: root
      group: root
  - command: mktemp -u XXXXXX
    register: g_legacy_ca_mktemp
    changed_when: false
  # Copy CA certificate, key, serial and bundle to legacy-ca with a
  # prefix generated by mktemp, ie. XXXXXX-ca.crt.
  #
  # The following roles will pick up all CA certificates matching
  # /.*-ca.crt/ in the legacy-ca directory and ensure they are present
  # in the OpenShift CA bundle.
  # - openshift_ca
  # - openshift_master_certificates
  # - openshift_node_certificates
  - name: Copy current OpenShift CA to legacy directory
    copy:
      src: "{{ openshift.common.config_base }}/master/{{ item }}"
      dest: "{{ openshift.common.config_base }}/master/legacy-ca/{{ g_legacy_ca_mktemp.stdout }}-{{ item }}"
      remote_src: true
    # It is possible that redeploying failed and files may be missing.
    # Ignore errors in this case. Files should have been copied to
    # legacy-ca directory in previous run.
    ignore_errors: true
    with_items:
    - "ca.crt"
    - "ca.key"
    - "ca.serial.txt"
    - "ca-bundle.crt"

- name: Create temporary directory for creating new CA certificate
  hosts: oo_first_master
  tasks:
  - name: Create temporary directory for creating new CA certificate
    command: >
      mktemp -d /tmp/openshift-ansible-XXXXXXX
    register: g_new_openshift_ca_mktemp
    changed_when: false

- name: Create OpenShift CA
  hosts: oo_first_master
  vars:
    # Set openshift_ca_config_dir to a temporary directory where CA
    # will be created. We'll replace the existing CA with the CA
    # created in the temporary directory.
    openshift_ca_config_dir: "{{ hostvars[groups.oo_first_master.0].g_new_openshift_ca_mktemp.stdout }}"
  roles:
  - role: openshift_master_facts
  - role: openshift_named_certificates
  - role: openshift_ca

- name: Create temp directory for syncing certs
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
  - name: Create local temp directory for syncing certs
    local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX
    register: g_master_mktemp
    changed_when: false

  - name: Chmod local temp directory for syncing certs
    local_action: file path="{{ g_master_mktemp.stdout }}" mode=0777
    changed_when: false

- name: Retrieve OpenShift CA
  hosts: oo_first_master
  roles:
  - openshift_facts
  tasks:
  - name: Retrieve CA certificate, key, bundle and serial
    fetch:
      src: "{{ hostvars[openshift_ca_host].g_new_openshift_ca_mktemp.stdout }}/{{ item }}"
      dest: "{{ hostvars['localhost'].g_master_mktemp.stdout }}/"
      flat: yes
      fail_on_missing: yes
      validate_checksum: yes
    with_items:
    - ca.crt
    - ca.key
    - ca-bundle.crt
    - ca.serial.txt
    - client-ca-bundle.crt
    delegate_to: "{{ openshift_ca_host }}"
    run_once: true
    changed_when: false

- name: Distribute OpenShift CA to masters
  hosts: oo_masters_to_config
  roles:
  - openshift_facts
  tasks:
  - name: Deploy CA certificate, key, bundle and serial
    copy:
      src: "{{ hostvars['localhost'].g_master_mktemp.stdout }}/{{ item }}"
      dest: "{{ openshift.common.config_base }}/master/"
    with_items:
    - ca.crt
    - ca.key
    - ca-bundle.crt
    - ca.serial.txt
    - client-ca-bundle.crt
  - name: Update master client kubeconfig CA data
    kubeclient_ca:
      client_path: "{{ openshift.common.config_base }}/master/openshift-master.kubeconfig"
      ca_path: "{{ openshift.common.config_base }}/master/ca-bundle.crt"
  - name: Update admin client kubeconfig CA data
    kubeclient_ca:
      client_path: "{{ openshift.common.config_base }}/master/admin.kubeconfig"
      ca_path: "{{ openshift.common.config_base }}/master/ca-bundle.crt"
  - name: Lookup default group for ansible_ssh_user
    command: "/usr/bin/id -g {{ ansible_ssh_user | quote }}"
    changed_when: false
    register: _ansible_ssh_user_gid
  - set_fact:
      client_users: "{{ [ansible_ssh_user, 'root'] | unique }}"
  - name: Create the client config dir(s)
    file:
      path: "~{{ item }}/.kube"
      state: directory
      mode: 0700
      owner: "{{ item }}"
      group: "{{ 'root' if item == 'root' else _ansible_ssh_user_gid.stdout  }}"
    with_items: "{{ client_users }}"
  - name: Copy the admin client config(s)
    copy:
      src: "{{ openshift.common.config_base }}/master/admin.kubeconfig"
      dest: "~{{ item }}/.kube/config"
      remote_src: yes
    with_items: "{{ client_users }}"
  - name: Update the permissions on the admin client config(s)
    file:
      path: "~{{ item }}/.kube/config"
      state: file
      mode: 0700
      owner: "{{ item }}"
      group: "{{ 'root' if item == 'root' else _ansible_ssh_user_gid.stdout  }}"
    with_items: "{{ client_users }}"

- import_playbook: restart.yml
  # Do not restart masters when master or etcd certificates were previously expired.
  when:
  # masters
  - ('expired' not in hostvars
      | lib_utils_oo_select_keys(groups['oo_masters_to_config'])
      | lib_utils_oo_collect('check_results.check_results.ocp_certs')
      | lib_utils_oo_collect('health', {'path':hostvars[groups.oo_first_master.0].openshift.common.config_base ~ "/master/master.server.crt"}))
  - ('expired' not in hostvars
      | lib_utils_oo_select_keys(groups['oo_masters_to_config'])
      | lib_utils_oo_collect('check_results.check_results.ocp_certs')
      | lib_utils_oo_collect('health', {'path':hostvars[groups.oo_first_master.0].openshift.common.config_base ~ "/master/ca-bundle.crt"}))
  # etcd
  - ('expired' not in (hostvars
      | lib_utils_oo_select_keys(groups['etcd'])
      | lib_utils_oo_collect('check_results.check_results.etcd')
      | lib_utils_oo_collect('health')))

- name: Distribute OpenShift CA certificate to nodes
  hosts: oo_nodes_to_config
  roles:
  - openshift_facts
  tasks:
  - copy:
      src: "{{ hostvars['localhost'].g_master_mktemp.stdout }}/ca-bundle.crt"
      dest: "{{ openshift.common.config_base }}/node/client-ca.crt"
  - name: Copy OpenShift CA to system CA trust
    copy:
      src: "{{ item.cert }}"
      dest: "/etc/pki/ca-trust/source/anchors/{{ item.id }}-{{ item.cert | basename }}"
      remote_src: yes
    with_items:
    - id: openshift
      cert: "{{ openshift.common.config_base }}/node/client-ca.crt"
    notify:
    - update ca trust
  - name: Update node client kubeconfig CA data
    kubeclient_ca:
      client_path: "{{ openshift.common.config_base }}/node/node.kubeconfig"
      ca_path: "{{ openshift.common.config_base }}/node/client-ca.crt"
  handlers:
  # Normally this handler would restart docker after updating ca
  # trust. We'll do that when we restart nodes to avoid restarting
  # docker on all nodes in parallel.
  - name: update ca trust
    command: update-ca-trust

- name: Delete temporary directory on CA host
  hosts: oo_first_master
  tasks:
  - file:
      path: "{{ g_new_openshift_ca_mktemp.stdout }}"
      state: absent

- name: Delete temporary directory on localhost
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
  - file:
      name: "{{ g_master_mktemp.stdout }}"
      state: absent
    changed_when: false

- import_playbook: ../../openshift-node/private/restart.yml
  # Do not restart nodes when node, master or etcd certificates were previously expired.
  when:
  # nodes
  - ('expired' not in hostvars
      | lib_utils_oo_select_keys(groups['oo_nodes_to_config'])
      | lib_utils_oo_collect('check_results.check_results.ocp_certs')
      | lib_utils_oo_collect('health', {'path':hostvars[groups.oo_nodes_to_config.0].openshift.common.config_base ~ "/node/server.crt"}))
  - ('expired' not in hostvars
      | lib_utils_oo_select_keys(groups['oo_nodes_to_config'])
      | lib_utils_oo_collect('check_results.check_results.ocp_certs')
      | lib_utils_oo_collect('health', {'path':hostvars[groups.oo_nodes_to_config.0].openshift.common.config_base ~ "/node/client-ca.crt"}))
  # masters
  - ('expired' not in hostvars
      | lib_utils_oo_select_keys(groups['oo_masters_to_config'])
      | lib_utils_oo_collect('check_results.check_results.ocp_certs')
      | lib_utils_oo_collect('health', {'path':hostvars[groups.oo_first_master.0].openshift.common.config_base ~ "/master/master.server.crt"}))
  - ('expired' not in hostvars
      | lib_utils_oo_select_keys(groups['oo_masters_to_config'])
      | lib_utils_oo_collect('check_results.check_results.ocp_certs')
      | lib_utils_oo_collect('health', {'path':hostvars[groups.oo_first_master.0].openshift.common.config_base ~ "/master/ca-bundle.crt"}))
  # etcd
  - ('expired' not in (hostvars
      | lib_utils_oo_select_keys(groups['etcd'])
      | lib_utils_oo_collect('check_results.check_results.etcd')
      | lib_utils_oo_collect('health')))
