diff options
Diffstat (limited to 'roles/etcd')
32 files changed, 611 insertions, 18 deletions
| diff --git a/roles/etcd/defaults/main.yaml b/roles/etcd/defaults/main.yaml index 3cc2bbb18..18164050a 100644 --- a/roles/etcd/defaults/main.yaml +++ b/roles/etcd/defaults/main.yaml @@ -1,6 +1,66 @@  --- -r_etcd_firewall_enabled: "{{ os_firewall_enabled | default(True) }}" -r_etcd_use_firewalld: "{{ os_firewall_use_firewalld | default(Falsel) }}" +r_etcd_common_backup_tag: '' +r_etcd_common_backup_sufix_name: '' + +# runc, docker, host +r_etcd_common_etcd_runtime: "docker" +r_etcd_common_embedded_etcd: false + +# etcd run on a host => use etcdctl command directly +# etcd run as a docker container => use docker exec +# etcd run as a runc container => use runc exec +r_etcd_common_etcdctl_command: "{{ 'etcdctl' if r_etcd_common_etcd_runtime == 'host' or r_etcd_common_embedded_etcd | bool else 'docker exec etcd_container etcdctl' if r_etcd_common_etcd_runtime == 'docker' else 'runc exec etcd etcdctl' }}" + +# etcd server vars +etcd_conf_dir: '/etc/etcd' +r_etcd_common_system_container_host_dir: /var/lib/etcd/etcd.etcd +etcd_system_container_conf_dir: /var/lib/etcd/etc +etcd_conf_file: "{{ etcd_conf_dir }}/etcd.conf" +etcd_ca_file: "{{ etcd_conf_dir }}/ca.crt" +etcd_cert_file: "{{ etcd_conf_dir }}/server.crt" +etcd_key_file: "{{ etcd_conf_dir }}/server.key" +etcd_peer_ca_file: "{{ etcd_conf_dir }}/ca.crt" +etcd_peer_cert_file: "{{ etcd_conf_dir }}/peer.crt" +etcd_peer_key_file: "{{ etcd_conf_dir }}/peer.key" + +# etcd ca vars +etcd_ca_dir: "{{ etcd_conf_dir}}/ca" +etcd_generated_certs_dir: "{{ etcd_conf_dir }}/generated_certs" +etcd_ca_cert: "{{ etcd_ca_dir }}/ca.crt" +etcd_ca_key: "{{ etcd_ca_dir }}/ca.key" +etcd_openssl_conf: "{{ etcd_ca_dir }}/openssl.cnf" +etcd_ca_name: etcd_ca +etcd_req_ext: etcd_v3_req +etcd_ca_exts_peer: etcd_v3_ca_peer +etcd_ca_exts_server: etcd_v3_ca_server +etcd_ca_exts_self: etcd_v3_ca_self +etcd_ca_exts_client: etcd_v3_ca_client +etcd_ca_crl_dir: "{{ etcd_ca_dir }}/crl" +etcd_ca_new_certs_dir: "{{ etcd_ca_dir }}/certs" +etcd_ca_db: "{{ etcd_ca_dir }}/index.txt" +etcd_ca_serial: "{{ etcd_ca_dir }}/serial" +etcd_ca_crl_number: "{{ etcd_ca_dir }}/crlnumber" +etcd_ca_default_days: 1825 + +r_etcd_common_master_peer_cert_file: /etc/origin/master/master.etcd-client.crt +r_etcd_common_master_peer_key_file: /etc/origin/master/master.etcd-client.key +r_etcd_common_master_peer_ca_file: /etc/origin/master/master.etcd-ca.crt + +# etcd server & certificate vars +etcd_hostname: "{{ inventory_hostname }}" +etcd_ip: "{{ ansible_default_ipv4.address }}" +etcd_is_atomic: False +etcd_is_containerized: False +etcd_is_thirdparty: False + +# etcd dir vars +etcd_data_dir: "{{ '/var/lib/origin/openshift.local.etcd' if r_etcd_common_embedded_etcd | bool else '/var/lib/etcd/' if r_etcd_common_etcd_runtime != 'runc' else '/var/lib/etcd/etcd.etcd/' }}" + +# etcd ports and protocols +etcd_client_port: 2379 +etcd_peer_port: 2380 +etcd_url_scheme: http +etcd_peer_url_scheme: http  etcd_initial_cluster_state: new  etcd_initial_cluster_token: etcd-cluster-1 @@ -10,8 +70,15 @@ etcd_listen_peer_urls: "{{ etcd_peer_url_scheme }}://{{ etcd_ip }}:{{ etcd_peer_  etcd_advertise_client_urls: "{{ etcd_url_scheme }}://{{ etcd_ip }}:{{ etcd_client_port }}"  etcd_listen_client_urls: "{{ etcd_url_scheme }}://{{ etcd_ip }}:{{ etcd_client_port }}" -etcd_client_port: 2379 -etcd_peer_port: 2380 +etcd_peer: 127.0.0.1 +etcdctlv2: "etcdctl --cert-file {{ etcd_peer_cert_file }} --key-file {{ etcd_peer_key_file }} --ca-file {{ etcd_peer_ca_file }} -C https://{{ etcd_peer }}:{{ etcd_client_port }}" + +etcd_service: "{{ 'etcd_container' if r_etcd_common_etcd_runtime == 'docker' else 'etcd' }}" +# Location of the service file is fixed and not meant to be changed +etcd_service_file: "/etc/systemd/system/{{ etcd_service }}.service" + +r_etcd_firewall_enabled: "{{ os_firewall_enabled | default(True) }}" +r_etcd_use_firewalld: "{{ os_firewall_use_firewalld | default(Falsel) }}"  etcd_systemd_dir: "/etc/systemd/system/{{ etcd_service }}.service.d"  r_etcd_os_firewall_deny: [] @@ -20,3 +87,6 @@ r_etcd_os_firewall_allow:    port: "{{etcd_client_port}}/tcp"  - service: etcd peering    port: "{{ etcd_peer_port }}/tcp" + +# set the backend quota to 4GB by default +etcd_quota_backend_bytes: 4294967296 diff --git a/roles/etcd/library/delegated_serial_command.py b/roles/etcd/library/delegated_serial_command.py new file mode 100755 index 000000000..0cab1ca88 --- /dev/null +++ b/roles/etcd/library/delegated_serial_command.py @@ -0,0 +1,274 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>, and others +# (c) 2016, Andrew Butcher <abutcher@redhat.com> +# +# This module is derrived from the Ansible command module. +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible.  If not, see <http://www.gnu.org/licenses/>. + + +# pylint: disable=unused-wildcard-import,wildcard-import,unused-import,redefined-builtin + +''' delegated_serial_command ''' + +import datetime +import errno +import glob +import shlex +import os +import fcntl +import time + +DOCUMENTATION = ''' +--- +module: delegated_serial_command +short_description: Executes a command on a remote node +version_added: historical +description: +     - The M(command) module takes the command name followed by a list +       of space-delimited arguments. +     - The given command will be executed on all selected nodes. It +       will not be processed through the shell, so variables like +       C($HOME) and operations like C("<"), C(">"), C("|"), and C("&") +       will not work (use the M(shell) module if you need these +       features). +     - Creates and maintains a lockfile such that this module will +       wait for other invocations to proceed. +options: +  command: +    description: +      - the command to run +    required: true +    default: null +  creates: +    description: +      - a filename or (since 2.0) glob pattern, when it already +        exists, this step will B(not) be run. +    required: no +    default: null +  removes: +    description: +      - a filename or (since 2.0) glob pattern, when it does not +        exist, this step will B(not) be run. +    version_added: "0.8" +    required: no +    default: null +  chdir: +    description: +      - cd into this directory before running the command +    version_added: "0.6" +    required: false +    default: null +  executable: +    description: +      - change the shell used to execute the command. Should be an +        absolute path to the executable. +    required: false +    default: null +    version_added: "0.9" +  warn: +    version_added: "1.8" +    default: yes +    description: +      - if command warnings are on in ansible.cfg, do not warn about +        this particular line if set to no/false. +    required: false +  lockfile: +    default: yes +    description: +      - the lockfile that will be created +  timeout: +    default: yes +    description: +      - time in milliseconds to wait to obtain the lock +notes: +    -  If you want to run a command through the shell (say you are using C(<), +       C(>), C(|), etc), you actually want the M(shell) module instead. The +       M(command) module is much more secure as it's not affected by the user's +       environment. +    - " C(creates), C(removes), and C(chdir) can be specified after +       the command. For instance, if you only want to run a command if +       a certain file does not exist, use this." +author: +    - Ansible Core Team +    - Michael DeHaan +    - Andrew Butcher +''' + +EXAMPLES = ''' +# Example from Ansible Playbooks. +- delegated_serial_command: +    command: /sbin/shutdown -t now + +# Run the command if the specified file does not exist. +- delegated_serial_command: +    command: /usr/bin/make_database.sh arg1 arg2 +    creates: /path/to/database +''' + +# Dict of options and their defaults +OPTIONS = {'chdir': None, +           'creates': None, +           'command': None, +           'executable': None, +           'NO_LOG': None, +           'removes': None, +           'warn': True, +           'lockfile': None, +           'timeout': None} + + +def check_command(commandline): +    ''' Check provided command ''' +    arguments = {'chown': 'owner', 'chmod': 'mode', 'chgrp': 'group', +                 'ln': 'state=link', 'mkdir': 'state=directory', +                 'rmdir': 'state=absent', 'rm': 'state=absent', 'touch': 'state=touch'} +    commands = {'git': 'git', 'hg': 'hg', 'curl': 'get_url or uri', 'wget': 'get_url or uri', +                'svn': 'subversion', 'service': 'service', +                'mount': 'mount', 'rpm': 'yum, dnf or zypper', 'yum': 'yum', 'apt-get': 'apt', +                'tar': 'unarchive', 'unzip': 'unarchive', 'sed': 'template or lineinfile', +                'rsync': 'synchronize', 'dnf': 'dnf', 'zypper': 'zypper'} +    become = ['sudo', 'su', 'pbrun', 'pfexec', 'runas'] +    warnings = list() +    command = os.path.basename(commandline.split()[0]) +    # pylint: disable=line-too-long +    if command in arguments: +        warnings.append("Consider using file module with {0} rather than running {1}".format(arguments[command], command)) +    if command in commands: +        warnings.append("Consider using {0} module rather than running {1}".format(commands[command], command)) +    if command in become: +        warnings.append( +            "Consider using 'become', 'become_method', and 'become_user' rather than running {0}".format(command,)) +    return warnings + + +# pylint: disable=too-many-statements,too-many-branches,too-many-locals +def main(): +    ''' Main module function ''' +    module = AnsibleModule(  # noqa: F405 +        argument_spec=dict( +            _uses_shell=dict(type='bool', default=False), +            command=dict(required=True), +            chdir=dict(), +            executable=dict(), +            creates=dict(), +            removes=dict(), +            warn=dict(type='bool', default=True), +            lockfile=dict(default='/tmp/delegated_serial_command.lock'), +            timeout=dict(type='int', default=30) +        ) +    ) + +    shell = module.params['_uses_shell'] +    chdir = module.params['chdir'] +    executable = module.params['executable'] +    command = module.params['command'] +    creates = module.params['creates'] +    removes = module.params['removes'] +    warn = module.params['warn'] +    lockfile = module.params['lockfile'] +    timeout = module.params['timeout'] + +    if command.strip() == '': +        module.fail_json(rc=256, msg="no command given") + +    iterated = 0 +    lockfd = open(lockfile, 'w+') +    while iterated < timeout: +        try: +            fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB) +            break +        # pylint: disable=invalid-name +        except IOError as e: +            if e.errno != errno.EAGAIN: +                module.fail_json(msg="I/O Error {0}: {1}".format(e.errno, e.strerror)) +            else: +                iterated += 1 +                time.sleep(0.1) + +    if chdir: +        chdir = os.path.abspath(os.path.expanduser(chdir)) +        os.chdir(chdir) + +    if creates: +        # do not run the command if the line contains creates=filename +        # and the filename already exists.  This allows idempotence +        # of command executions. +        path = os.path.expanduser(creates) +        if glob.glob(path): +            module.exit_json( +                cmd=command, +                stdout="skipped, since %s exists" % path, +                changed=False, +                stderr=False, +                rc=0 +            ) + +    if removes: +        # do not run the command if the line contains removes=filename +        # and the filename does not exist.  This allows idempotence +        # of command executions. +        path = os.path.expanduser(removes) +        if not glob.glob(path): +            module.exit_json( +                cmd=command, +                stdout="skipped, since %s does not exist" % path, +                changed=False, +                stderr=False, +                rc=0 +            ) + +    warnings = list() +    if warn: +        warnings = check_command(command) + +    if not shell: +        command = shlex.split(command) +    startd = datetime.datetime.now() + +    # pylint: disable=invalid-name +    rc, out, err = module.run_command(command, executable=executable, use_unsafe_shell=shell) + +    fcntl.flock(lockfd, fcntl.LOCK_UN) +    lockfd.close() + +    endd = datetime.datetime.now() +    delta = endd - startd + +    if out is None: +        out = '' +    if err is None: +        err = '' + +    module.exit_json( +        cmd=command, +        stdout=out.rstrip("\r\n"), +        stderr=err.rstrip("\r\n"), +        rc=rc, +        start=str(startd), +        end=str(endd), +        delta=str(delta), +        changed=True, +        warnings=warnings, +        iterated=iterated +    ) + + +# import module snippets +# pylint: disable=wrong-import-position +from ansible.module_utils.basic import *  # noqa: F402,F403 + +main() diff --git a/roles/etcd/meta/main.yml b/roles/etcd/meta/main.yml index 537c01c0e..879ca4f4e 100644 --- a/roles/etcd/meta/main.yml +++ b/roles/etcd/meta/main.yml @@ -19,4 +19,3 @@ dependencies:  - role: lib_openshift  - role: lib_os_firewall  - role: lib_utils -- role: etcd_common diff --git a/roles/etcd/tasks/auxiliary/drop_etcdctl.yml b/roles/etcd/tasks/auxiliary/drop_etcdctl.yml new file mode 100644 index 000000000..11bd2310e --- /dev/null +++ b/roles/etcd/tasks/auxiliary/drop_etcdctl.yml @@ -0,0 +1,12 @@ +--- +- name: Install etcd for etcdctl +  package: name=etcd{{ '-' + etcd_version if etcd_version is defined else '' }} state=present +  when: not openshift.common.is_atomic | bool + +- name: Configure etcd profile.d aliases +  template: +    dest: "/etc/profile.d/etcdctl.sh" +    src: etcdctl.sh.j2 +    mode: 0755 +    owner: root +    group: root diff --git a/roles/etcd/tasks/backup.yml b/roles/etcd/tasks/backup.yml new file mode 100644 index 000000000..c0538e596 --- /dev/null +++ b/roles/etcd/tasks/backup.yml @@ -0,0 +1,2 @@ +--- +- include: backup/backup.yml diff --git a/roles/etcd/tasks/backup/backup.yml b/roles/etcd/tasks/backup/backup.yml new file mode 100644 index 000000000..42d27c081 --- /dev/null +++ b/roles/etcd/tasks/backup/backup.yml @@ -0,0 +1,101 @@ +--- +# set the etcd backup directory name here in case the tag or sufix consists of dynamic value that changes over time +# e.g. openshift-backup-{{ lookup('pipe', 'date +%Y%m%d%H%M%S') }} value will change every second so if the date changes +# right after setting l_etcd_incontainer_backup_dir and before l_etcd_backup_dir facts, the backup directory name is different +- set_fact: +    l_backup_dir_name: "openshift-backup-{{ r_etcd_common_backup_tag }}{{ r_etcd_common_backup_sufix_name }}" + +- set_fact: +    l_etcd_data_dir: "{{ etcd_data_dir }}{{ '/etcd.etcd' if r_etcd_common_etcd_runtime == 'runc' else '' }}" + +- set_fact: +    l_etcd_incontainer_data_dir: "{{ etcd_data_dir }}" + +- set_fact: +    l_etcd_incontainer_backup_dir: "{{ l_etcd_incontainer_data_dir }}/{{ l_backup_dir_name }}" + +- set_fact: +    l_etcd_backup_dir: "{{ l_etcd_data_dir }}/{{ l_backup_dir_name }}" + +# TODO: replace shell module with command and update later checks +- name: Check available disk space for etcd backup +  shell: df --output=avail -k {{ l_etcd_data_dir }} | tail -n 1 +  register: l_avail_disk +  # AUDIT:changed_when: `false` because we are only inspecting +  # state, not manipulating anything +  changed_when: false + +# TODO: replace shell module with command and update later checks +- name: Check current etcd disk usage +  shell: du --exclude='*openshift-backup*' -k {{ l_etcd_data_dir }} | tail -n 1 | cut -f1 +  register: l_etcd_disk_usage +  # AUDIT:changed_when: `false` because we are only inspecting +  # state, not manipulating anything +  changed_when: false + +- name: Abort if insufficient disk space for etcd backup +  fail: +    msg: > +      {{ l_etcd_disk_usage.stdout|int*2 }} Kb disk space required for etcd backup, +      {{ l_avail_disk.stdout }} Kb available. +  when: l_etcd_disk_usage.stdout|int*2 > l_avail_disk.stdout|int + +# For non containerized and non embedded we should have the correct version of +# etcd installed already. So don't do anything. +# +# For containerized installs we now exec into etcd_container +# +# For embedded non containerized we need to ensure we have the latest version +# etcd on the host. +- name: Detecting Atomic Host Operating System +  stat: +    path: /run/ostree-booted +  register: l_ostree_booted + +- name: Install latest etcd for embedded +  package: +    name: etcd +    state: latest +  when: +  - r_etcd_common_embedded_etcd | bool +  - not l_ostree_booted.stat.exists | bool + +- name: Check selinux label of '{{ l_etcd_data_dir }}' +  command: > +    stat -c '%C' {{ l_etcd_data_dir }} +  register: l_etcd_selinux_labels + +- debug: +    msg: "{{ l_etcd_selinux_labels }}" + +- name: Make sure the '{{ l_etcd_data_dir }}' has the proper label +  command: > +    chcon -t svirt_sandbox_file_t  "{{ l_etcd_data_dir }}" +  when: +  - l_etcd_selinux_labels.rc == 0 +  - "'svirt_sandbox_file_t' not in l_etcd_selinux_labels.stdout" + +- name: Generate etcd backup +  command: > +    {{ r_etcd_common_etcdctl_command }} backup --data-dir={{ l_etcd_incontainer_data_dir }} +    --backup-dir={{ l_etcd_incontainer_backup_dir }} + +# According to the docs change you can simply copy snap/db +# https://github.com/openshift/openshift-docs/commit/b38042de02d9780842dce95cfa0ef45d53b58bc6 +- name: Check for v3 data store +  stat: +    path: "{{ l_etcd_data_dir }}/member/snap/db" +  register: l_v3_db + +- name: Copy etcd v3 data store +  command: > +    cp -a {{ l_etcd_data_dir }}/member/snap/db +    {{ l_etcd_backup_dir }}/member/snap/ +  when: l_v3_db.stat.exists + +- set_fact: +    r_etcd_common_backup_complete: True + +- name: Display location of etcd backup +  debug: +    msg: "Etcd backup created in {{ l_etcd_backup_dir }}" diff --git a/roles/etcd/tasks/backup_ca_certificates.yml b/roles/etcd/tasks/backup_ca_certificates.yml new file mode 100644 index 000000000..a41b032f3 --- /dev/null +++ b/roles/etcd/tasks/backup_ca_certificates.yml @@ -0,0 +1,2 @@ +--- +- include: certificates/backup_ca_certificates.yml diff --git a/roles/etcd/tasks/backup_generated_certificates.yml b/roles/etcd/tasks/backup_generated_certificates.yml new file mode 100644 index 000000000..8cf2a10cc --- /dev/null +++ b/roles/etcd/tasks/backup_generated_certificates.yml @@ -0,0 +1,2 @@ +--- +- include: certificates/backup_generated_certificates.yml diff --git a/roles/etcd/tasks/backup_server_certificates.yml b/roles/etcd/tasks/backup_server_certificates.yml new file mode 100644 index 000000000..267ffeb4d --- /dev/null +++ b/roles/etcd/tasks/backup_server_certificates.yml @@ -0,0 +1,2 @@ +--- +- include: certificates/backup_server_certificates.yml diff --git a/roles/etcd/tasks/ca.yml b/roles/etcd/tasks/ca.yml index 7cda49069..cca1e9ad7 100644 --- a/roles/etcd/tasks/ca.yml +++ b/roles/etcd/tasks/ca.yml @@ -1,2 +1,2 @@  --- -- include: ca/deploy.yml +- include: certificates/deploy_ca.yml diff --git a/roles/etcd/tasks/certificates/backup_ca_certificates.yml b/roles/etcd/tasks/certificates/backup_ca_certificates.yml new file mode 100644 index 000000000..f60eb82ef --- /dev/null +++ b/roles/etcd/tasks/certificates/backup_ca_certificates.yml @@ -0,0 +1,12 @@ +--- +- name: Determine if CA certificate directory exists +  stat: +    path: "{{ etcd_ca_dir }}" +  register: etcd_ca_certs_dir_stat +- name: Backup generated etcd certificates +  command: > +    tar -czf {{ etcd_conf_dir }}/etcd-ca-certificate-backup-{{ ansible_date_time.epoch }}.tgz +    {{ etcd_ca_dir }} +  args: +    warn: no +  when: etcd_ca_certs_dir_stat.stat.exists | bool diff --git a/roles/etcd/tasks/certificates/backup_generated_certificates.yml b/roles/etcd/tasks/certificates/backup_generated_certificates.yml new file mode 100644 index 000000000..6a24cfcb3 --- /dev/null +++ b/roles/etcd/tasks/certificates/backup_generated_certificates.yml @@ -0,0 +1,13 @@ +--- +- name: Determine if generated etcd certificates exist +  stat: +    path: "{{ etcd_conf_dir }}/generated_certs" +  register: etcd_generated_certs_dir_stat + +- name: Backup generated etcd certificates +  command: > +    tar -czf {{ etcd_conf_dir }}/etcd-generated-certificate-backup-{{ ansible_date_time.epoch }}.tgz +    {{ etcd_conf_dir }}/generated_certs +  args: +    warn: no +  when: etcd_generated_certs_dir_stat.stat.exists | bool diff --git a/roles/etcd/tasks/certificates/backup_server_certificates.yml b/roles/etcd/tasks/certificates/backup_server_certificates.yml new file mode 100644 index 000000000..8e6cc6965 --- /dev/null +++ b/roles/etcd/tasks/certificates/backup_server_certificates.yml @@ -0,0 +1,11 @@ +--- +- name: Backup etcd certificates +  command: > +    tar -czvf /etc/etcd/etcd-server-certificate-backup-{{ ansible_date_time.epoch }}.tgz +    {{ etcd_conf_dir }}/ca.crt +    {{ etcd_conf_dir }}/server.crt +    {{ etcd_conf_dir }}/server.key +    {{ etcd_conf_dir }}/peer.crt +    {{ etcd_conf_dir }}/peer.key +  args: +    warn: no diff --git a/roles/etcd/tasks/ca/deploy.yml b/roles/etcd/tasks/certificates/deploy_ca.yml index 3d32290a2..3d32290a2 100644 --- a/roles/etcd/tasks/ca/deploy.yml +++ b/roles/etcd/tasks/certificates/deploy_ca.yml diff --git a/roles/etcd/tasks/certificates/distribute_ca.yml b/roles/etcd/tasks/certificates/distribute_ca.yml new file mode 100644 index 000000000..632ac15dd --- /dev/null +++ b/roles/etcd/tasks/certificates/distribute_ca.yml @@ -0,0 +1,47 @@ +--- +- name: Create a tarball of the etcd ca certs +  command: > +    tar -czvf {{ etcd_conf_dir }}/{{ etcd_ca_name }}.tgz +      -C {{ etcd_ca_dir }} . +  args: +    creates: "{{ etcd_conf_dir }}/{{ etcd_ca_name }}.tgz" +    warn: no +  delegate_to: "{{ etcd_ca_host }}" +  run_once: true + +- name: Retrieve etcd ca cert tarball +  fetch: +    src: "{{ etcd_conf_dir }}/{{ etcd_ca_name }}.tgz" +    dest: "{{ etcd_sync_cert_dir }}/" +    flat: yes +    fail_on_missing: yes +    validate_checksum: yes +  delegate_to: "{{ etcd_ca_host }}" +  run_once: true + +- name: Ensure ca directory exists +  file: +    path: "{{ etcd_ca_dir }}" +    state: directory + +- name: Unarchive etcd ca cert tarballs +  unarchive: +    src: "{{ etcd_sync_cert_dir }}/{{ etcd_ca_name }}.tgz" +    dest: "{{ etcd_ca_dir }}" + +- name: Read current etcd CA +  slurp: +    src: "{{ etcd_conf_dir }}/ca.crt" +  register: g_current_etcd_ca_output + +- name: Read new etcd CA +  slurp: +    src: "{{ etcd_ca_dir }}/ca.crt" +  register: g_new_etcd_ca_output + +- copy: +    content: "{{ (g_new_etcd_ca_output.content|b64decode) + (g_current_etcd_ca_output.content|b64decode) }}" +    dest: "{{ item }}/ca.crt" +  with_items: +  - "{{ etcd_conf_dir }}" +  - "{{ etcd_ca_dir }}" diff --git a/roles/etcd/tasks/client_certificates/fetch_from_ca.yml b/roles/etcd/tasks/certificates/fetch_client_certificates_from_ca.yml index 119071a72..119071a72 100644 --- a/roles/etcd/tasks/client_certificates/fetch_from_ca.yml +++ b/roles/etcd/tasks/certificates/fetch_client_certificates_from_ca.yml diff --git a/roles/etcd/tasks/server_certificates/fetch_from_ca.yml b/roles/etcd/tasks/certificates/fetch_server_certificates_from_ca.yml index 064fe1952..26492fb3c 100644 --- a/roles/etcd/tasks/server_certificates/fetch_from_ca.yml +++ b/roles/etcd/tasks/certificates/fetch_server_certificates_from_ca.yml @@ -1,8 +1,4 @@  --- -- include: ../ca/deploy.yml -  when: -  - etcd_ca_setup | default(True) | bool -  - name: Install etcd    package:      name: "etcd{{ '-' + etcd_version if etcd_version is defined else '' }}" diff --git a/roles/etcd/tasks/certificates/remove_ca_certificates.yml b/roles/etcd/tasks/certificates/remove_ca_certificates.yml new file mode 100644 index 000000000..4a86eb60d --- /dev/null +++ b/roles/etcd/tasks/certificates/remove_ca_certificates.yml @@ -0,0 +1,5 @@ +--- +- name: Remove CA certificate directory +  file: +    path: "{{ etcd_ca_dir }}" +    state: absent diff --git a/roles/etcd/tasks/certificates/remove_generated_certificates.yml b/roles/etcd/tasks/certificates/remove_generated_certificates.yml new file mode 100644 index 000000000..993b18de2 --- /dev/null +++ b/roles/etcd/tasks/certificates/remove_generated_certificates.yml @@ -0,0 +1,5 @@ +--- +- name: Remove generated etcd certificates +  file: +    path: "{{ etcd_conf_dir }}/generated_certs" +    state: absent diff --git a/roles/etcd/tasks/certificates/retrieve_ca_certificates.yml b/roles/etcd/tasks/certificates/retrieve_ca_certificates.yml new file mode 100644 index 000000000..70b5c6523 --- /dev/null +++ b/roles/etcd/tasks/certificates/retrieve_ca_certificates.yml @@ -0,0 +1,8 @@ +--- +- name: Retrieve etcd CA certificate +  fetch: +    src: "{{ etcd_conf_dir }}/ca.crt" +    dest: "{{ etcd_sync_cert_dir }}/" +    flat: yes +    fail_on_missing: yes +    validate_checksum: yes diff --git a/roles/etcd/tasks/client_certificates.yml b/roles/etcd/tasks/client_certificates.yml index 2e9c078b9..2f4108a0d 100644 --- a/roles/etcd/tasks/client_certificates.yml +++ b/roles/etcd/tasks/client_certificates.yml @@ -1,2 +1,2 @@  --- -- include: client_certificates/fetch_from_ca.yml +- include: certificates/fetch_client_certificates_from_ca.yml diff --git a/roles/etcd/tasks/distribute_ca b/roles/etcd/tasks/distribute_ca new file mode 100644 index 000000000..040c5f7af --- /dev/null +++ b/roles/etcd/tasks/distribute_ca @@ -0,0 +1,2 @@ +--- +- include: certificates/distribute_ca.yml diff --git a/roles/etcd/tasks/drop_etcdctl.yml b/roles/etcd/tasks/drop_etcdctl.yml new file mode 100644 index 000000000..4c1f609f7 --- /dev/null +++ b/roles/etcd/tasks/drop_etcdctl.yml @@ -0,0 +1,2 @@ +--- +- include: auxiliary/drop_etcdctl.yml diff --git a/roles/etcd/tasks/main.yml b/roles/etcd/tasks/main.yml index 870c11ad4..3e69af314 100644 --- a/roles/etcd/tasks/main.yml +++ b/roles/etcd/tasks/main.yml @@ -1,6 +1,4 @@  --- -- include: server_certificates.yml -  - name: Set hostname and ip facts    set_fact:      # Store etcd_hostname and etcd_ip such that they will be available @@ -16,10 +14,7 @@    package: name=etcd{{ '-' + etcd_version if etcd_version is defined else '' }} state=present    when: not etcd_is_containerized | bool -- include_role: -    name: etcd_common -  vars: -    r_etcd_common_action: drop_etcdctl +- include: drop_etcdctl.yml    when:    - openshift_etcd_etcdctl_profile | default(true) | bool diff --git a/roles/etcd/tasks/remove_ca_certificates.yml b/roles/etcd/tasks/remove_ca_certificates.yml new file mode 100644 index 000000000..36df1a1cc --- /dev/null +++ b/roles/etcd/tasks/remove_ca_certificates.yml @@ -0,0 +1,2 @@ +--- +- include: certificates/remove_ca_certificates.yml diff --git a/roles/etcd/tasks/remove_generated_certificates.yml b/roles/etcd/tasks/remove_generated_certificates.yml new file mode 100644 index 000000000..b10a4b32d --- /dev/null +++ b/roles/etcd/tasks/remove_generated_certificates.yml @@ -0,0 +1,2 @@ +--- +- include: certificates/remove_generated_certificates.yml diff --git a/roles/etcd/tasks/retrieve_ca_certificates.yml b/roles/etcd/tasks/retrieve_ca_certificates.yml new file mode 100644 index 000000000..bd6c4ec85 --- /dev/null +++ b/roles/etcd/tasks/retrieve_ca_certificates.yml @@ -0,0 +1,2 @@ +--- +- include: certificates/retrieve_ca_certificates.yml diff --git a/roles/etcd/tasks/server_certificates.yml b/roles/etcd/tasks/server_certificates.yml index f0ba58b6e..ae26079f9 100644 --- a/roles/etcd/tasks/server_certificates.yml +++ b/roles/etcd/tasks/server_certificates.yml @@ -1,2 +1,6 @@  --- -- include: server_certificates/fetch_from_ca.yml +- include: ca.yml +  when: +  - etcd_ca_setup | default(True) | bool + +- include: certificates/fetch_server_certificates_from_ca.yml diff --git a/roles/etcd/tasks/upgrade/upgrade_image.yml b/roles/etcd/tasks/upgrade/upgrade_image.yml index cea95a1b3..24071f9ad 100644 --- a/roles/etcd/tasks/upgrade/upgrade_image.yml +++ b/roles/etcd/tasks/upgrade/upgrade_image.yml @@ -20,6 +20,11 @@      regexp: "{{ current_image.stdout }}$"      replace: "{{ new_etcd_image }}" +- lineinfile: +    destfile: "{{ etcd_conf_file }}" +    regexp: '^ETCD_QUOTA_BACKEND_BYTES=' +    line: "ETCD_QUOTA_BACKEND_BYTES={{ etcd_quota_backend_bytes }}" +  - name: Restart etcd_container    systemd:      name: "{{ etcd_service }}" diff --git a/roles/etcd/tasks/upgrade/upgrade_rpm.yml b/roles/etcd/tasks/upgrade/upgrade_rpm.yml index 324b69605..505e28afb 100644 --- a/roles/etcd/tasks/upgrade/upgrade_rpm.yml +++ b/roles/etcd/tasks/upgrade/upgrade_rpm.yml @@ -19,6 +19,11 @@      name: "{{ l_etcd_target_package }}"      state: latest +- lineinfile: +    destfile: "{{ etcd_conf_file }}" +    regexp: '^ETCD_QUOTA_BACKEND_BYTES=' +    line: "ETCD_QUOTA_BACKEND_BYTES={{ etcd_quota_backend_bytes }}" +  - name: Restart etcd    service:      name: "{{ etcd_service }}" diff --git a/roles/etcd/templates/etcd.conf.j2 b/roles/etcd/templates/etcd.conf.j2 index 2c2803aee..8462bb4c8 100644 --- a/roles/etcd/templates/etcd.conf.j2 +++ b/roles/etcd/templates/etcd.conf.j2 @@ -45,6 +45,7 @@ ETCD_ADVERTISE_CLIENT_URLS={{ etcd_advertise_client_urls }}  #ETCD_STRICT_RECONFIG_CHECK="false"  #ETCD_AUTO_COMPACTION_RETENTION="0"  #ETCD_ENABLE_V2="true" +ETCD_QUOTA_BACKEND_BYTES={{ etcd_quota_backend_bytes }}  #[proxy]  #ETCD_PROXY=off diff --git a/roles/etcd/templates/etcdctl.sh.j2 b/roles/etcd/templates/etcdctl.sh.j2 new file mode 100644 index 000000000..ac7d9c72f --- /dev/null +++ b/roles/etcd/templates/etcdctl.sh.j2 @@ -0,0 +1,12 @@ +#!/bin/bash +# Sets up handy aliases for etcd, need etcdctl2 and etcdctl3 because +# command flags are different between the two. Should work on stand +# alone etcd hosts and master + etcd hosts too because we use the peer keys. +etcdctl2() { + /usr/bin/etcdctl --cert-file {{ etcd_peer_cert_file }} --key-file {{ etcd_peer_key_file }} --ca-file {{ etcd_peer_ca_file }} -C https://`hostname`:2379 ${@} + +} + +etcdctl3() { + ETCDCTL_API=3 /usr/bin/etcdctl --cert {{ etcd_peer_cert_file }} --key {{ etcd_peer_key_file }} --cacert {{ etcd_peer_ca_file }} --endpoints https://`hostname`:2379 ${@} +} | 
