diff options
author | Thomas Wiest <twiest@users.noreply.github.com> | 2015-07-16 12:15:51 -0400 |
---|---|---|
committer | Thomas Wiest <twiest@users.noreply.github.com> | 2015-07-16 12:15:51 -0400 |
commit | 68d6fdf1c1c8244b3bd2ccdf77499d9127592368 (patch) | |
tree | 0e28786664b825c97b33188bf36c42387fe59a51 /roles | |
parent | a1fe1b25b588ba995192b99e44a7950ee0c6e032 (diff) | |
parent | f831779404b0147d6a92935cd8b77de3e25f2bec (diff) | |
download | openshift-68d6fdf1c1c8244b3bd2ccdf77499d9127592368.tar.gz openshift-68d6fdf1c1c8244b3bd2ccdf77499d9127592368.tar.bz2 openshift-68d6fdf1c1c8244b3bd2ccdf77499d9127592368.tar.xz openshift-68d6fdf1c1c8244b3bd2ccdf77499d9127592368.zip |
Merge pull request #341 from detiber/sdodson-etcd-playbook
External clustered etcd support
Diffstat (limited to 'roles')
35 files changed, 698 insertions, 623 deletions
diff --git a/roles/etcd/README.md b/roles/etcd/README.md new file mode 100644 index 000000000..49207c428 --- /dev/null +++ b/roles/etcd/README.md @@ -0,0 +1,39 @@ +Role Name +========= + +Configures an etcd cluster for an arbitrary number of hosts + +Requirements +------------ + +This role assumes it's being deployed on a RHEL/Fedora based host with package +named 'etcd' available via yum. + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +None + +Example Playbook +---------------- + + - hosts: etcd + roles: + - { etcd } + +License +------- + +MIT + +Author Information +------------------ + +Scott Dodson <sdodson@redhat.com> +Adapted from https://github.com/retr0h/ansible-etcd for use on RHEL/Fedora. We +should at some point submit a PR to merge this with that module. diff --git a/roles/etcd/defaults/main.yaml b/roles/etcd/defaults/main.yaml new file mode 100644 index 000000000..0fb45f37c --- /dev/null +++ b/roles/etcd/defaults/main.yaml @@ -0,0 +1,31 @@ +--- +etcd_interface: eth0 +etcd_client_port: 2379 +etcd_peer_port: 2380 +etcd_peers_group: etcd +etcd_url_scheme: http +etcd_peer_url_scheme: http +etcd_conf_dir: /etc/etcd +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_initial_cluster_state: new +etcd_initial_cluster_token: etcd-cluster-1 + +etcd_initial_advertise_peer_urls: "{{ etcd_peer_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }}" +etcd_listen_peer_urls: "{{ etcd_peer_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }}" +etcd_advertise_client_urls: "{{ etcd_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_client_port }}" +etcd_listen_client_urls: "{{ etcd_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_client_port }}" + +etcd_data_dir: /var/lib/etcd/ + +os_firewall_use_firewalld: False +os_firewall_allow: +- service: etcd + port: "{{etcd_client_port}}/tcp" +- service: etcd peering + port: "{{ etcd_peer_port }}/tcp" diff --git a/roles/etcd/handlers/main.yml b/roles/etcd/handlers/main.yml new file mode 100644 index 000000000..b897913f9 --- /dev/null +++ b/roles/etcd/handlers/main.yml @@ -0,0 +1,3 @@ +--- +- name: restart etcd + service: name=etcd state=restarted diff --git a/roles/etcd/meta/main.yml b/roles/etcd/meta/main.yml new file mode 100644 index 000000000..82b1a62b8 --- /dev/null +++ b/roles/etcd/meta/main.yml @@ -0,0 +1,19 @@ +--- +# This module is based on https://github.com/retr0h/ansible-etcd with most +# changes centered around installing from a pre-existing rpm +# TODO: Extend https://github.com/retr0h/ansible-etcd rather than forking +galaxy_info: + author: Scott Dodson + description: etcd management + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.2 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: os_firewall } diff --git a/roles/etcd/tasks/main.yml b/roles/etcd/tasks/main.yml new file mode 100644 index 000000000..79a91dfde --- /dev/null +++ b/roles/etcd/tasks/main.yml @@ -0,0 +1,52 @@ +--- +- name: Install etcd + yum: pkg=etcd state=present + +- name: Validate permissions on the config dir + file: + path: "{{ etcd_conf_dir }}" + state: directory + owner: etcd + group: etcd + mode: 0700 + +- name: Validate permissions on certificate files + file: + path: "{{ item }}" + mode: 0600 + group: etcd + owner: etcd + when: etcd_url_scheme == 'https' + with_items: + - "{{ etcd_ca_file }}" + - "{{ etcd_cert_file }}" + - "{{ etcd_key_file }}" + +- name: Validate permissions on peer certificate files + file: + path: "{{ item }}" + mode: 0600 + group: etcd + owner: etcd + when: etcd_peer_url_scheme == 'https' + with_items: + - "{{ etcd_peer_ca_file }}" + - "{{ etcd_peer_cert_file }}" + - "{{ etcd_peer_key_file }}" + +- name: Write etcd global config file + template: + src: etcd.conf.j2 + dest: /etc/etcd/etcd.conf + notify: + - restart etcd + +- name: Enable etcd + service: + name: etcd + state: started + enabled: yes + register: start_result + +- pause: seconds=30 + when: start_result | changed diff --git a/roles/etcd/templates/etcd.conf.j2 b/roles/etcd/templates/etcd.conf.j2 new file mode 100644 index 000000000..801be2c97 --- /dev/null +++ b/roles/etcd/templates/etcd.conf.j2 @@ -0,0 +1,52 @@ +{% macro initial_cluster() -%} +{% for host in groups[etcd_peers_group] -%} +{% if loop.last -%} +{{ host }}={{ etcd_peer_url_scheme }}://{{ hostvars[host]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }} +{%- else -%} +{{ host }}={{ etcd_peer_url_scheme }}://{{ hostvars[host]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }}, +{%- endif -%} +{% endfor -%} +{% endmacro -%} + +{% if groups[etcd_peers_group] and groups[etcd_peers_group] | length > 1 %} +ETCD_NAME={{ inventory_hostname }} +ETCD_LISTEN_PEER_URLS={{ etcd_listen_peer_urls }} +{% else %} +ETCD_NAME=default +{% endif %} +ETCD_DATA_DIR={{ etcd_data_dir }} +#ETCD_SNAPSHOT_COUNTER="10000" +#ETCD_HEARTBEAT_INTERVAL="100" +#ETCD_ELECTION_TIMEOUT="1000" +ETCD_LISTEN_CLIENT_URLS={{ etcd_listen_client_urls }} +#ETCD_MAX_SNAPSHOTS="5" +#ETCD_MAX_WALS="5" +#ETCD_CORS="" + +{% if groups[etcd_peers_group] and groups[etcd_peers_group] | length > 1 %} +#[cluster] +ETCD_INITIAL_ADVERTISE_PEER_URLS={{ etcd_initial_advertise_peer_urls }} +ETCD_INITIAL_CLUSTER={{ initial_cluster() }} +ETCD_INITIAL_CLUSTER_STATE={{ etcd_initial_cluster_state }} +ETCD_INITIAL_CLUSTER_TOKEN={{ etcd_initial_cluster_token }} +#ETCD_DISCOVERY="" +#ETCD_DISCOVERY_SRV="" +#ETCD_DISCOVERY_FALLBACK="proxy" +#ETCD_DISCOVERY_PROXY="" +{% endif %} +ETCD_ADVERTISE_CLIENT_URLS={{ etcd_advertise_client_urls }} + +#[proxy] +#ETCD_PROXY="off" + +#[security] +{% if etcd_url_scheme == 'https' -%} +ETCD_CA_FILE={{ etcd_ca_file }} +ETCD_CERT_FILE={{ etcd_cert_file }} +ETCD_KEY_FILE={{ etcd_key_file }} +{% endif -%} +{% if etcd_peer_url_scheme == 'https' -%} +ETCD_PEER_CA_FILE={{ etcd_peer_ca_file }} +ETCD_PEER_CERT_FILE={{ etcd_peer_cert_file }} +ETCD_PEER_KEY_FILE={{ etcd_peer_key_file }} +{% endif -%} diff --git a/roles/etcd_ca/README.md b/roles/etcd_ca/README.md new file mode 100644 index 000000000..60a880e30 --- /dev/null +++ b/roles/etcd_ca/README.md @@ -0,0 +1,34 @@ +etcd_ca +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Scott Dodson (sdodson@redhat.com) diff --git a/roles/etcd_ca/meta/main.yml b/roles/etcd_ca/meta/main.yml new file mode 100644 index 000000000..ce909b992 --- /dev/null +++ b/roles/etcd_ca/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.9 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: openshift_facts } diff --git a/roles/etcd_ca/tasks/main.yml b/roles/etcd_ca/tasks/main.yml new file mode 100644 index 000000000..ab151fe5b --- /dev/null +++ b/roles/etcd_ca/tasks/main.yml @@ -0,0 +1,44 @@ +--- +- file: + path: "{{ etcd_ca_dir }}/{{ item }}" + state: directory + mode: 0700 + owner: root + group: root + with_items: + - certs + - crl + - fragments + +- command: cp /etc/pki/tls/openssl.cnf ./ + args: + chdir: "{{ etcd_ca_dir }}/fragments" + creates: "{{ etcd_ca_dir }}/fragments/openssl.cnf" + +- template: + dest: "{{ etcd_ca_dir }}/fragments/openssl_append.cnf" + src: openssl_append.j2 + +- assemble: + src: "{{ etcd_ca_dir }}/fragments" + dest: "{{ etcd_ca_dir }}/openssl.cnf" + +- command: touch index.txt + args: + chdir: "{{ etcd_ca_dir }}" + creates: "{{ etcd_ca_dir }}/index.txt" + +- copy: + dest: "{{ etcd_ca_dir }}/serial" + content: "01" + force: no + +- command: > + openssl req -config openssl.cnf -newkey rsa:4096 + -keyout ca.key -new -out ca.crt -x509 -extensions etcd_v3_ca_self + -batch -nodes -subj /CN=etcd-signer@{{ ansible_date_time.epoch }} + args: + chdir: "{{ etcd_ca_dir }}" + creates: "{{ etcd_ca_dir }}/ca.crt" + environment: + SAN: '' diff --git a/roles/etcd_ca/templates/openssl_append.j2 b/roles/etcd_ca/templates/openssl_append.j2 new file mode 100644 index 000000000..de2adaead --- /dev/null +++ b/roles/etcd_ca/templates/openssl_append.j2 @@ -0,0 +1,51 @@ + +[ etcd_v3_req ] +basicConstraints = critical,CA:FALSE +keyUsage = digitalSignature,keyEncipherment +subjectAltName = ${ENV::SAN} + +[ etcd_ca ] +dir = {{ etcd_ca_dir }} +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir/certs +certificate = $dir/ca.crt +serial = $dir/serial +private_key = $dir/ca.key +crl_number = $dir/crlnumber +x509_extensions = etcd_v3_ca_client +default_days = 365 +default_md = sha256 +preserve = no +name_opt = ca_default +cert_opt = ca_default +policy = policy_anything +unique_subject = no +copy_extensions = copy + +[ etcd_v3_ca_self ] +authorityKeyIdentifier = keyid,issuer +basicConstraints = critical,CA:TRUE,pathlen:0 +keyUsage = critical,digitalSignature,keyEncipherment,keyCertSign +subjectKeyIdentifier = hash + +[ etcd_v3_ca_peer ] +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = critical,CA:FALSE +extendedKeyUsage = clientAuth,serverAuth +keyUsage = digitalSignature,keyEncipherment +subjectKeyIdentifier = hash + +[ etcd_v3_ca_server ] +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = critical,CA:FALSE +extendedKeyUsage = serverAuth +keyUsage = digitalSignature,keyEncipherment +subjectKeyIdentifier = hash + +[ etcd_v3_ca_client ] +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = critical,CA:FALSE +extendedKeyUsage = clientAuth +keyUsage = digitalSignature,keyEncipherment +subjectKeyIdentifier = hash diff --git a/roles/etcd_ca/vars/main.yml b/roles/etcd_ca/vars/main.yml new file mode 100644 index 000000000..901e95027 --- /dev/null +++ b/roles/etcd_ca/vars/main.yml @@ -0,0 +1,3 @@ +--- +etcd_conf_dir: /etc/etcd +etcd_ca_dir: /etc/etcd/ca diff --git a/roles/etcd_certificates/README.md b/roles/etcd_certificates/README.md new file mode 100644 index 000000000..95f8f8aab --- /dev/null +++ b/roles/etcd_certificates/README.md @@ -0,0 +1,34 @@ +OpenShift etcd certificates +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Scott Dodson (sdodson@redhat.com) diff --git a/roles/etcd_certificates/meta/main.yml b/roles/etcd_certificates/meta/main.yml new file mode 100644 index 000000000..41370fab4 --- /dev/null +++ b/roles/etcd_certificates/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.8 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: etcd_ca } diff --git a/roles/etcd_certificates/tasks/client.yml b/roles/etcd_certificates/tasks/client.yml new file mode 100644 index 000000000..28f33f442 --- /dev/null +++ b/roles/etcd_certificates/tasks/client.yml @@ -0,0 +1,42 @@ +--- +- name: Ensure generated_certs directory present + file: + path: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + state: directory + mode: 0700 + with_items: etcd_needing_client_certs + +- name: Create the client csr + command: > + openssl req -new -keyout {{ item.etcd_cert_prefix }}client.key + -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}client.csr + -reqexts {{ etcd_req_ext }} -batch -nodes + -subj /CN={{ item.openshift.common.hostname }} + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'client.csr' }}" + environment: + SAN: "IP:{{ item.openshift.common.ip }}" + with_items: etcd_needing_client_certs + +- name: Sign and create the client crt + command: > + openssl ca -name {{ etcd_ca_name }} -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}client.crt + -in {{ item.etcd_cert_prefix }}client.csr + -batch + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'client.crt' }}" + environment: + SAN: '' + with_items: etcd_needing_client_certs + +- file: + src: "{{ etcd_ca_cert }}" + dest: "{{ etcd_generated_certs_dir}}/{{ item.etcd_cert_subdir }}/{{ item.etcd_cert_prefix }}ca.crt" + state: hard + with_items: etcd_needing_client_certs diff --git a/roles/etcd_certificates/tasks/main.yml b/roles/etcd_certificates/tasks/main.yml new file mode 100644 index 000000000..da875e8ea --- /dev/null +++ b/roles/etcd_certificates/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- include: client.yml + when: etcd_needing_client_certs is defined and etcd_needing_client_certs + +- include: server.yml + when: etcd_needing_server_certs is defined and etcd_needing_server_certs + + + diff --git a/roles/etcd_certificates/tasks/server.yml b/roles/etcd_certificates/tasks/server.yml new file mode 100644 index 000000000..727b7fa2c --- /dev/null +++ b/roles/etcd_certificates/tasks/server.yml @@ -0,0 +1,73 @@ +--- +- name: Ensure generated_certs directory present + file: + path: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + state: directory + mode: 0700 + with_items: etcd_needing_server_certs + +- name: Create the server csr + command: > + openssl req -new -keyout {{ item.etcd_cert_prefix }}server.key + -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}server.csr + -reqexts {{ etcd_req_ext }} -batch -nodes + -subj /CN={{ item.openshift.common.hostname }} + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'server.csr' }}" + environment: + SAN: "IP:{{ item.openshift.common.ip }}" + with_items: etcd_needing_server_certs + +- name: Sign and create the server crt + command: > + openssl ca -name {{ etcd_ca_name }} -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}server.crt + -in {{ item.etcd_cert_prefix }}server.csr + -extensions {{ etcd_ca_exts_server }} -batch + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'server.crt' }}" + environment: + SAN: '' + with_items: etcd_needing_server_certs + +- name: Create the peer csr + command: > + openssl req -new -keyout {{ item.etcd_cert_prefix }}peer.key + -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}peer.csr + -reqexts {{ etcd_req_ext }} -batch -nodes + -subj /CN={{ item.openshift.common.hostname }} + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'peer.csr' }}" + environment: + SAN: "IP:{{ item.openshift.common.ip }}" + with_items: etcd_needing_server_certs + +- name: Sign and create the peer crt + command: > + openssl ca -name {{ etcd_ca_name }} -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}peer.crt + -in {{ item.etcd_cert_prefix }}peer.csr + -extensions {{ etcd_ca_exts_peer }} -batch + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'peer.crt' }}" + environment: + SAN: '' + with_items: etcd_needing_server_certs + +- file: + src: "{{ etcd_ca_cert }}" + dest: "{{ etcd_generated_certs_dir}}/{{ item.etcd_cert_subdir }}/{{ item.etcd_cert_prefix }}ca.crt" + state: hard + with_items: etcd_needing_server_certs + + diff --git a/roles/etcd_certificates/vars/main.yml b/roles/etcd_certificates/vars/main.yml new file mode 100644 index 000000000..0eaeeb82b --- /dev/null +++ b/roles/etcd_certificates/vars/main.yml @@ -0,0 +1,11 @@ +--- +etcd_conf_dir: /etc/etcd +etcd_ca_dir: /etc/etcd/ca +etcd_generated_certs_dir: /etc/etcd/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 diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index ca5ea1da0..aff822a23 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -366,13 +366,23 @@ def set_url_facts_if_unset(facts): console_port = facts['master']['console_port'] console_path = facts['master']['console_path'] etcd_use_ssl = facts['master']['etcd_use_ssl'] + etcd_hosts = facts['master']['etcd_hosts'] etcd_port = facts['master']['etcd_port'], hostname = facts['common']['hostname'] public_hostname = facts['common']['public_hostname'] if 'etcd_urls' not in facts['master']: - facts['master']['etcd_urls'] = [format_url(etcd_use_ssl, hostname, - etcd_port)] + etcd_urls = [] + if etcd_hosts != '': + facts['master']['etcd_port'] = etcd_port + facts['master']['embedded_etcd'] = False + for host in etcd_hosts: + etcd_urls.append(format_url(etcd_use_ssl, host, + etcd_port)) + else: + etcd_urls = [format_url(etcd_use_ssl, hostname, + etcd_port)] + facts['master']['etcd_urls'] = etcd_urls if 'api_url' not in facts['master']: facts['master']['api_url'] = format_url(api_use_ssl, hostname, api_port) @@ -695,7 +705,7 @@ class OpenShiftFacts(object): if 'master' in roles: master = dict(api_use_ssl=True, api_port='8443', console_use_ssl=True, console_path='/console', - console_port='8443', etcd_use_ssl=True, + console_port='8443', etcd_use_ssl=True, etcd_hosts='', etcd_port='4001', portal_net='172.30.0.0/16', embedded_etcd=True, embedded_kube=True, embedded_dns=True, dns_port='53', @@ -707,11 +717,7 @@ class OpenShiftFacts(object): defaults['master'] = master if 'node' in roles: - node = dict(pod_cidr='', labels={}, annotations={}, portal_net='172.30.0.0/16') - node['resources_cpu'] = self.system_facts['processor_cores'] - node['resources_memory'] = int( - int(self.system_facts['memtotal_mb']) * 1024 * 1024 * 0.75 - ) + node = dict(labels={}, annotations={}, portal_net='172.30.0.0/16') defaults['node'] = node return defaults diff --git a/roles/openshift_master/tasks/main.yml b/roles/openshift_master/tasks/main.yml index da0a663ec..02905f32d 100644 --- a/roles/openshift_master/tasks/main.yml +++ b/roles/openshift_master/tasks/main.yml @@ -12,11 +12,6 @@ yum: pkg=openshift-master state=present register: install_result -# TODO: Is this necessary or was this a workaround for an old bug in packaging? -- name: Reload systemd units - command: systemctl daemon-reload - when: install_result | changed - - name: Set master OpenShift facts openshift_facts: role: master @@ -31,6 +26,7 @@ console_url: "{{ openshift_master_console_url | default(None) }}" console_use_ssl: "{{ openshift_master_console_use_ssl | default(None) }}" public_console_url: "{{ openshift_master_public_console_url | default(None) }}" + etcd_hosts: "{{ openshift_master_etcd_hosts | default(None)}}" etcd_port: "{{ openshift_master_etcd_port | default(None) }}" etcd_use_ssl: "{{ openshift_master_etcd_use_ssl | default(None) }}" etcd_urls: "{{ openshift_master_etcd_urls | default(None) }}" @@ -65,16 +61,6 @@ 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={{ openshift.common.hostname }},{{ openshift.common.public_hostname }} - --master={{ openshift.master.api_url }} - --public-master={{ openshift.master.public_api_url }} - --cert-dir={{ openshift_master_config_dir }} --overwrite=false - args: - creates: "{{ openshift_master_config_dir }}/master.server.key" - - name: Create the policy file if it does not already exist command: > {{ openshift.common.admin_binary }} create-bootstrap-policy-file @@ -128,6 +114,11 @@ - name: Start and enable openshift-master service: name=openshift-master enabled=yes state=started + register: start_result + +- name: pause to prevent service restart from interfering with bootstrapping + pause: seconds=30 + when: start_result | changed - name: Create the OpenShift client config dir(s) file: diff --git a/roles/openshift_master/templates/master.yaml.v1.j2 b/roles/openshift_master/templates/master.yaml.v1.j2 index 3b8b18c39..bc766ec9b 100644 --- a/roles/openshift_master/templates/master.yaml.v1.j2 +++ b/roles/openshift_master/templates/master.yaml.v1.j2 @@ -18,19 +18,19 @@ corsAllowedOrigins: {% for origin in ['127.0.0.1', 'localhost', openshift.common.hostname, openshift.common.ip, openshift.common.public_hostname, openshift.common.public_ip] %} - {{ origin }} {% endfor %} -{% if openshift.master.embedded_dns %} +{% if openshift.master.embedded_dns | bool %} dnsConfig: bindAddress: {{ openshift.master.bind_addr }}:{{ openshift.master.dns_port }} {% endif %} etcdClientInfo: - ca: ca.crt + ca: {{ "ca.crt" if (openshift.master.embedded_etcd | bool) else "master.etcd-ca.crt" }} certFile: master.etcd-client.crt keyFile: master.etcd-client.key urls: {% for etcd_url in openshift.master.etcd_urls %} - {{ etcd_url }} {% endfor %} -{% if openshift.master.embedded_etcd %} +{% if openshift.master.embedded_etcd | bool %} etcdConfig: address: {{ openshift.common.hostname }}:{{ openshift.master.etcd_port }} peerAddress: {{ openshift.common.hostname }}:7001 @@ -61,7 +61,7 @@ kubeletClientInfo: certFile: master.kubelet-client.crt keyFile: master.kubelet-client.key port: 10250 -{% if openshift.master.embedded_kube %} +{% if openshift.master.embedded_kube | bool %} kubernetesMasterConfig: apiLevels: - v1beta3 diff --git a/roles/openshift_master_ca/README.md b/roles/openshift_master_ca/README.md new file mode 100644 index 000000000..5b2d3601b --- /dev/null +++ b/roles/openshift_master_ca/README.md @@ -0,0 +1,34 @@ +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) diff --git a/roles/openshift_register_nodes/meta/main.yml b/roles/openshift_master_ca/meta/main.yml index e40a152c1..f3236e850 100644 --- a/roles/openshift_register_nodes/meta/main.yml +++ b/roles/openshift_master_ca/meta/main.yml @@ -14,4 +14,3 @@ galaxy_info: - system dependencies: - { role: openshift_facts } - diff --git a/roles/openshift_master_ca/tasks/main.yml b/roles/openshift_master_ca/tasks/main.yml new file mode 100644 index 000000000..8163ecd7f --- /dev/null +++ b/roles/openshift_master_ca/tasks/main.yml @@ -0,0 +1,22 @@ +--- +- name: Install the OpenShift package for admin tooling + yum: pkg=openshift state=present + register: install_result + +- name: Reload generated facts + openshift_facts: + +- 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={{ openshift.common.hostname }},{{ openshift.common.public_hostname }} + --master={{ openshift.master.api_url }} + --public-master={{ openshift.master.public_api_url }} + --cert-dir={{ openshift_master_config_dir }} --overwrite=false + args: + creates: "{{ openshift_master_config_dir }}/master.server.key" diff --git a/roles/openshift_master_ca/vars/main.yml b/roles/openshift_master_ca/vars/main.yml new file mode 100644 index 000000000..2925680bb --- /dev/null +++ b/roles/openshift_master_ca/vars/main.yml @@ -0,0 +1,5 @@ +--- +openshift_master_config_dir: /etc/openshift/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" diff --git a/roles/openshift_master_certificates/README.md b/roles/openshift_master_certificates/README.md new file mode 100644 index 000000000..ba3d5f28c --- /dev/null +++ b/roles/openshift_master_certificates/README.md @@ -0,0 +1,34 @@ +OpenShift Master Certificates +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Jason DeTiberus (jdetiber@redhat.com) diff --git a/roles/openshift_master_certificates/meta/main.yml b/roles/openshift_master_certificates/meta/main.yml new file mode 100644 index 000000000..fd7b73b0f --- /dev/null +++ b/roles/openshift_master_certificates/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.8 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: openshift_master_ca } diff --git a/roles/openshift_master_certificates/tasks/main.yml b/roles/openshift_master_certificates/tasks/main.yml new file mode 100644 index 000000000..b5a3f8e40 --- /dev/null +++ b/roles/openshift_master_certificates/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Ensure the generated_configs directory present + file: + path: "{{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}" + state: directory + mode: 0700 + with_items: masters_needing_certs + +- file: + src: "{{ openshift_master_ca_cert }}" + dest: "{{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}/ca.crt" + with_items: masters_needing_certs + +- name: Create the master certificates if they do not already exist + command: > + {{ openshift.common.admin_binary }} create-master-certs + --hostnames={{ item.openshift.common.hostname }},{{ item.openshift.common.public_hostname }} + --master={{ item.openshift.master.api_url }} + --public-master={{ item.openshift.master.public_api_url }} + --cert-dir={{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }} + --overwrite=false + args: + creates: "{{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}/master.server.crt" + with_items: masters_needing_certs diff --git a/roles/openshift_register_nodes/vars/main.yml b/roles/openshift_master_certificates/vars/main.yml index 3801b8427..6e577b13b 100644 --- a/roles/openshift_register_nodes/vars/main.yml +++ b/roles/openshift_master_certificates/vars/main.yml @@ -1,8 +1,6 @@ --- -openshift_node_config_dir: /etc/openshift/node -openshift_master_config_dir: /etc/openshift/master openshift_generated_configs_dir: /etc/openshift/generated-configs +openshift_master_config_dir: /etc/openshift/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" -openshift_kube_api_version: v1beta3 diff --git a/roles/openshift_node/tasks/main.yml b/roles/openshift_node/tasks/main.yml index 770b55351..e18846db8 100644 --- a/roles/openshift_node/tasks/main.yml +++ b/roles/openshift_node/tasks/main.yml @@ -1,5 +1,11 @@ --- # TODO: allow for overriding default ports where possible +- fail: + msg: This role requres that osn_cluster_dns_domain is set + when: osn_cluster_dns_domain is not defined or not osn_cluster_dns_domain +- fail: + msg: This role requres that osn_cluster_dns_ip is set + when: osn_cluster_dns_ip is not defined or not osn_cluster_dns_ip - name: Install OpenShift Node package yum: pkg=openshift-node state=present @@ -10,11 +16,6 @@ register: sdn_install_result when: openshift.common.use_openshift_sdn -- name: Reload systemd units - command: systemctl daemon-reload - when: (node_install_result | changed or (openshift.common.use_openshift_sdn - and sdn_install_result | changed)) - - name: Set node OpenShift facts openshift_facts: role: "{{ item.role }}" @@ -27,9 +28,6 @@ deployment_type: "{{ openshift_deployment_type }}" - role: node local_facts: - resources_cpu: "{{ openshift_node_resources_cpu | default(none) }}" - resources_memory: "{{ openshift_node_resources_memory | default(none) }}" - pod_cidr: "{{ openshift_node_pod_cidr | default(none) }}" labels: "{{ openshift_node_labels | default(none) }}" annotations: "{{ openshift_node_annotations | default(none) }}" registry_url: "{{ oreg_url | default(none) }}" diff --git a/roles/openshift_node/templates/node.yaml.v1.j2 b/roles/openshift_node/templates/node.yaml.v1.j2 index f313f6a4b..7778a2a61 100644 --- a/roles/openshift_node/templates/node.yaml.v1.j2 +++ b/roles/openshift_node/templates/node.yaml.v1.j2 @@ -1,7 +1,7 @@ allowDisabledDocker: false apiVersion: v1 -dnsDomain: {{ hostvars[openshift_first_master].openshift.dns.domain }} -dnsIP: {{ hostvars[openshift_first_master].openshift.dns.ip }} +dnsDomain: {{ osn_cluster_dns_domain }} +dnsIP: {{ osn_cluster_dns_ip }} dockerConfig: execHandlerName: "" imageConfig: diff --git a/roles/openshift_node_certificates/tasks/main.yml b/roles/openshift_node_certificates/tasks/main.yml index 949afc5eb..64a799dfb 100644 --- a/roles/openshift_node_certificates/tasks/main.yml +++ b/roles/openshift_node_certificates/tasks/main.yml @@ -3,6 +3,7 @@ file: path: "{{ openshift_generated_configs_dir }}" state: directory + when: nodes_needing_certs | length > 0 - name: Generate the node client config command: > diff --git a/roles/openshift_node_certificates/vars/main.yml b/roles/openshift_node_certificates/vars/main.yml index 3801b8427..a018bb0f9 100644 --- a/roles/openshift_node_certificates/vars/main.yml +++ b/roles/openshift_node_certificates/vars/main.yml @@ -5,4 +5,3 @@ openshift_generated_configs_dir: /etc/openshift/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_kube_api_version: v1beta3 diff --git a/roles/openshift_register_nodes/README.md b/roles/openshift_register_nodes/README.md deleted file mode 100644 index b1d2000f1..000000000 --- a/roles/openshift_register_nodes/README.md +++ /dev/null @@ -1,15 +0,0 @@ -OpenShift Register Nodes -======================== - -DEPRECATED!!! -Nodes should now auto register themselves. Use openshift_node_certificates role instead. - -License -------- - -Apache License Version 2.0 - -Author Information ------------------- - -Jason DeTiberus (jdetiber@redhat.com) diff --git a/roles/openshift_register_nodes/library/kubernetes_register_node.py b/roles/openshift_register_nodes/library/kubernetes_register_node.py deleted file mode 100755 index a8c38627b..000000000 --- a/roles/openshift_register_nodes/library/kubernetes_register_node.py +++ /dev/null @@ -1,513 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim: expandtab:tabstop=4:shiftwidth=4 -# -# disable pylint checks -# permanently disabled unless someone wants to refactor the object model: -# too-few-public-methods -# no-self-use -# too-many-arguments -# too-many-locals -# too-many-branches -# pylint:disable=too-many-arguments, no-self-use -# pylint:disable=too-many-locals, too-many-branches, too-few-public-methods -"""Ansible module to register a kubernetes node to the cluster""" - -import os - -DOCUMENTATION = ''' ---- -module: kubernetes_register_node -short_description: Registers a kubernetes node with a master -description: - - Registers a kubernetes node with a master -options: - name: - default: null - description: - - Identifier for this node (usually the node fqdn). - required: true - api_verison: - choices: ['v1beta1', 'v1beta3'] - default: 'v1beta1' - description: - - Kubernetes API version to use - required: true - host_ip: - default: null - description: - - IP Address to associate with the node when registering. - Available in the following API versions: v1beta1. - required: false - cpu: - default: null - description: - - Number of CPUs to allocate for this node. When using the v1beta1 - API, you must specify the CPU count as a floating point number - with no more than 3 decimal places. API version v1beta3 and newer - accepts arbitrary float values. - required: false - memory: - default: null - description: - - Memory available for this node. When using the v1beta1 API, you - must specify the memory size in bytes. API version v1beta3 and - newer accepts binary SI and decimal SI values. - required: false -''' -EXAMPLES = ''' -# Minimal node registration -- openshift_register_node: name=ose3.node.example.com - -# Node registration using the v1beta1 API and assigning 1 CPU core and 10 GB of -# Memory -- openshift_register_node: - name: ose3.node.example.com - api_version: v1beta1 - hostIP: 192.168.1.1 - cpu: 1 - memory: 500000000 -''' - - -class ClientConfigException(Exception): - """Client Configuration Exception""" - pass - -class ClientConfig(object): - """ Representation of a client config - - Attributes: - config (dict): dictionary representing the client configuration - - Args: - client_opts (list of str): client options to use - module (AnsibleModule): - - Raises: - ClientConfigException: - """ - def __init__(self, client_opts, module): - kubectl = module.params['kubectl_cmd'] - _, output, _ = module.run_command((kubectl + - ["config", "view", "-o", "json"] + - client_opts), check_rc=True) - self.config = json.loads(output) - - if not (bool(self.config['clusters']) or - bool(self.config['contexts']) or - bool(self.config['current-context']) or - bool(self.config['users'])): - raise ClientConfigException( - "Client config missing required values: %s" % output - ) - - def current_context(self): - """ Gets the current context for the client config - - Returns: - str: The current context as set in the config - """ - return self.config['current-context'] - - def section_has_value(self, section_name, value): - """ Test if specified section contains a value - - Args: - section_name (str): config section to test - value (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - section = self.config[section_name] - if isinstance(section, dict): - return value in section - else: - val = next((item for item in section - if item['name'] == value), None) - return val is not None - - def has_context(self, context): - """ Test if specified context exists in config - - Args: - context (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - return self.section_has_value('contexts', context) - - def has_user(self, user): - """ Test if specified user exists in config - - Args: - context (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - return self.section_has_value('users', user) - - def has_cluster(self, cluster): - """ Test if specified cluster exists in config - - Args: - context (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - return self.section_has_value('clusters', cluster) - - def get_value_for_context(self, context, attribute): - """ Get the value of attribute in context - - Args: - context (str): context to search - attribute (str): attribute wanted - Returns: - str: The value for attribute in context - """ - contexts = self.config['contexts'] - if isinstance(contexts, dict): - return contexts[context][attribute] - else: - return next((c['context'][attribute] for c in contexts - if c['name'] == context), None) - - def get_user_for_context(self, context): - """ Get the user attribute in context - - Args: - context (str): context to search - Returns: - str: The value for the attribute in context - """ - return self.get_value_for_context(context, 'user') - - def get_cluster_for_context(self, context): - """ Get the cluster attribute in context - - Args: - context (str): context to search - Returns: - str: The value for the attribute in context - """ - return self.get_value_for_context(context, 'cluster') - - def get_namespace_for_context(self, context): - """ Get the namespace attribute in context - - Args: - context (str): context to search - Returns: - str: The value for the attribute in context - """ - return self.get_value_for_context(context, 'namespace') - -class Util(object): - """Utility methods""" - @staticmethod - def remove_empty_elements(mapping): - """ Recursively removes empty elements from a dict - - Args: - mapping (dict): dict to remove empty attributes from - Returns: - dict: A copy of the dict with empty elements removed - """ - if isinstance(mapping, dict): - copy = mapping.copy() - for key, val in mapping.iteritems(): - if not val: - del copy[key] - return copy - else: - return mapping - -class NodeResources(object): - """ Kubernetes Node Resources - - Attributes: - resources (dict): A dictionary representing the node resources - - Args: - version (str): kubernetes api version - cpu (str): string representation of the cpu resources for the node - memory (str): string representation of the memory resources for the - node - """ - def __init__(self, version, cpu=None, memory=None): - if version == 'v1beta1': - self.resources = dict(capacity=dict()) - self.resources['capacity']['cpu'] = cpu - self.resources['capacity']['memory'] = memory - - def get_resources(self): - """ Get the dict representing the node resources - - Returns: - dict: representation of the node resources with any empty - elements removed - """ - return Util.remove_empty_elements(self.resources) - -class NodeSpec(object): - """ Kubernetes Node Spec - - Attributes: - spec (dict): A dictionary representing the node resources - - Args: - version (str): kubernetes api version - cpu (str): string representation of the cpu resources for the node - memory (str): string representation of the memory resources for the - node - cidr (str): string representation of the cidr block available for - the node - externalID (str): The external id of the node - """ - def __init__(self, version, cpu=None, memory=None, cidr=None, - externalID=None): - if version == 'v1beta3': - self.spec = dict(podCIDR=cidr, externalID=externalID, - capacity=dict()) - self.spec['capacity']['cpu'] = cpu - self.spec['capacity']['memory'] = memory - - def get_spec(self): - """ Get the dict representing the node spec - - Returns: - dict: representation of the node spec with any empty elements - removed - """ - return Util.remove_empty_elements(self.spec) - -class Node(object): - """ Kubernetes Node - - Attributes: - node (dict): A dictionary representing the node - - Args: - module (AnsibleModule): - client_opts (list): client connection options - version (str, optional): kubernetes api version - node_name (str, optional): name for node - hostIP (str, optional): node host ip - cpu (str, optional): cpu resources for the node - memory (str, optional): memory resources for the node - labels (list, optional): labels for the node - annotations (list, optional): annotations for the node - podCIDR (list, optional): cidr block to use for pods - externalID (str, optional): external id of the node - """ - def __init__(self, module, client_opts, version='v1beta1', node_name=None, - hostIP=None, cpu=None, memory=None, labels=None, - annotations=None, podCIDR=None, externalID=None): - self.module = module - self.client_opts = client_opts - if version == 'v1beta1': - self.node = dict(id=node_name, - kind='Node', - apiVersion=version, - hostIP=hostIP, - resources=NodeResources(version, cpu, memory), - cidr=podCIDR, - labels=labels, - annotations=annotations, - externalID=externalID) - elif version == 'v1beta3': - metadata = dict(name=node_name, - labels=labels, - annotations=annotations) - self.node = dict(kind='Node', - apiVersion=version, - metadata=metadata, - spec=NodeSpec(version, cpu, memory, podCIDR, - externalID)) - - def get_name(self): - """ Get the name for the node - - Returns: - str: node name - """ - if self.node['apiVersion'] == 'v1beta1': - return self.node['id'] - elif self.node['apiVersion'] == 'v1beta3': - return self.node['metadata']['name'] - - def get_node(self): - """ Get the dict representing the node - - Returns: - dict: representation of the node with any empty elements - removed - """ - node = self.node.copy() - if self.node['apiVersion'] == 'v1beta1': - node['resources'] = self.node['resources'].get_resources() - elif self.node['apiVersion'] == 'v1beta3': - node['spec'] = self.node['spec'].get_spec() - return Util.remove_empty_elements(node) - - def exists(self): - """ Tests if the node already exists - - Returns: - bool: True if node exists, otherwise False - """ - kubectl = self.module.params['kubectl_cmd'] - _, output, _ = self.module.run_command((kubectl + ["get", "nodes"] + - self.client_opts), - check_rc=True) - if re.search(self.module.params['name'], output, re.MULTILINE): - return True - return False - - def create(self): - """ Creates the node - - Returns: - bool: True if node creation successful - """ - kubectl = self.module.params['kubectl_cmd'] - cmd = kubectl + self.client_opts + ['create', '-f', '-'] - exit_code, output, error = self.module.run_command( - cmd, data=self.module.jsonify(self.get_node()) - ) - if exit_code != 0: - if re.search("minion \"%s\" already exists" % self.get_name(), - error): - self.module.exit_json(msg="node definition already exists", - changed=False, node=self.get_node()) - else: - self.module.fail_json(msg="Node creation failed.", - exit_code=exit_code, - output=output, error=error, - node=self.get_node()) - else: - return True - -def generate_client_opts(module): - """ Generates the client options - - Args: - module(AnsibleModule) - - Returns: - str: client options - """ - client_config = '~/.kube/.kubeconfig' - if 'default_client_config' in module.params: - client_config = module.params['default_client_config'] - user_has_client_config = os.path.exists(os.path.expanduser(client_config)) - if not (user_has_client_config or module.params['client_config']): - module.fail_json(msg="Could not locate client configuration, " - "client_config must be specified if " - "~/.kube/.kubeconfig is not present") - - client_opts = [] - if module.params['client_config']: - kubeconfig_flag = '--kubeconfig' - if 'kubeconfig_flag' in module.params: - kubeconfig_flag = module.params['kubeconfig_flag'] - client_opts.append(kubeconfig_flag + '=' + os.path.expanduser(module.params['client_config'])) - - try: - config = ClientConfig(client_opts, module) - except ClientConfigException as ex: - module.fail_json(msg="Failed to get client configuration", - exception=str(ex)) - - client_context = module.params['client_context'] - if config.has_context(client_context): - if client_context != config.current_context(): - client_opts.append("--context=%s" % client_context) - else: - module.fail_json(msg="Context %s not found in client config" % client_context) - - client_user = module.params['client_user'] - if config.has_user(client_user): - if client_user != config.get_user_for_context(client_context): - client_opts.append("--user=%s" % client_user) - else: - module.fail_json(msg="User %s not found in client config" % client_user) - - client_cluster = module.params['client_cluster'] - if config.has_cluster(client_cluster): - if client_cluster != config.get_cluster_for_context(client_context): - client_opts.append("--cluster=%s" % client_cluster) - else: - module.fail_json(msg="Cluster %s not found in client config" % client_cluster) - - client_namespace = module.params['client_namespace'] - if client_namespace != config.get_namespace_for_context(client_context): - client_opts.append("--namespace=%s" % client_namespace) - - return client_opts - - -def main(): - """ main """ - module = AnsibleModule( - argument_spec=dict( - name=dict(required=True, type='str'), - host_ip=dict(type='str'), - api_version=dict(type='str', default='v1beta1', - choices=['v1beta1', 'v1beta3']), - cpu=dict(type='str'), - memory=dict(type='str'), - # TODO: needs documented - labels=dict(type='dict', default={}), - # TODO: needs documented - annotations=dict(type='dict', default={}), - # TODO: needs documented - pod_cidr=dict(type='str'), - # TODO: needs documented - client_config=dict(type='str'), - # TODO: needs documented - client_cluster=dict(type='str', default='master'), - # TODO: needs documented - client_context=dict(type='str', default='default'), - # TODO: needs documented - client_namespace=dict(type='str', default='default'), - # TODO: needs documented - client_user=dict(type='str', default='system:admin'), - # TODO: needs documented - kubectl_cmd=dict(type='list', default=['kubectl']), - # TODO: needs documented - kubeconfig_flag=dict(type='str'), - # TODO: needs documented - default_client_config=dict(type='str') - ), - supports_check_mode=True - ) - - labels = module.params['labels'] - kube_hostname_label = 'kubernetes.io/hostname' - if kube_hostname_label not in labels: - labels[kube_hostname_label] = module.params['name'] - - node = Node(module, generate_client_opts(module), - module.params['api_version'], module.params['name'], - module.params['host_ip'], module.params['cpu'], - module.params['memory'], labels, module.params['annotations'], - module.params['pod_cidr']) - - if node.exists(): - module.exit_json(changed=False, node=node.get_node()) - elif module.check_mode: - module.exit_json(changed=True, node=node.get_node()) - elif node.create(): - module.exit_json(changed=True, msg="Node created successfully", - node=node.get_node()) - else: - module.fail_json(msg="Unknown error creating node", node=node.get_node()) - -# ignore pylint errors related to the module_utils import -# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import -# import module snippets -from ansible.module_utils.basic import * -if __name__ == '__main__': - main() diff --git a/roles/openshift_register_nodes/tasks/main.yml b/roles/openshift_register_nodes/tasks/main.yml deleted file mode 100644 index 502dffc26..000000000 --- a/roles/openshift_register_nodes/tasks/main.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -- name: Create openshift_generated_configs_dir if it doesn't exist - file: - path: "{{ openshift_generated_configs_dir }}" - state: directory - -- 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 }} - --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 }} - args: - chdir: "{{ openshift_generated_configs_dir }}" - creates: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}" - with_items: nodes_needing_certs - -- name: Generate the node server certificate - delegate_to: "{{ openshift_first_master }}" - command: > - {{ openshift.common.admin_binary }} create-server-cert - --cert=server.crt --key=server.key --overwrite=true - --hostnames={{ [item.openshift.common.hostname, item.openshift.common.public_hostname]|unique|join(",") }} - --signer-cert={{ openshift_master_ca_cert }} - --signer-key={{ openshift_master_ca_key }} - --signer-serial={{ openshift_master_ca_serial }} - args: - chdir: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}" - creates: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}/server.crt" - with_items: nodes_needing_certs - -- name: Register unregistered nodes - kubernetes_register_node: - kubectl_cmd: "{{ [openshift.common.client_binary] }}" - default_client_config: '~/.kube/config' - name: "{{ item.openshift.common.hostname }}" - api_version: "{{ openshift_kube_api_version }}" - cpu: "{{ item.openshift.node.resources_cpu | default(None) }}" - memory: "{{ item.openshift.node.resources_memory | default(None) }}" - pod_cidr: "{{ item.openshift.node.pod_cidr | default(None) }}" - host_ip: "{{ item.openshift.common.ip }}" - labels: "{{ item.openshift.node.labels | default({}) }}" - annotations: "{{ item.openshift.node.annotations | default({}) }}" - client_context: default/ose3-master-example-com:8443/system:openshift-master - client_user: system:openshift-master/ose3-master-example-com:8443 - client_cluster: ose3-master-example-com:8443 - with_items: openshift_nodes - register: register_result |