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  | 
