From e2c7b1305ca8495065dcf40fd2092d7c698dd6ea Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Tue, 20 Mar 2018 15:47:51 +0100 Subject: Local volumes and StatefulSet to provision Master/Slave MySQL and Galera cluster --- roles/ands_facts/tasks/main.yml | 8 ++ roles/ands_facts/tasks/node.yml | 5 + roles/ands_facts/tasks/nodes.yml | 10 ++ roles/ands_facts/tasks/volume.yml | 8 ++ roles/ands_facts/tasks/volumes.yml | 7 ++ roles/ands_facts/tasks/volumes_iterate.yml | 13 +++ roles/ands_kaas/00-local-volumes.yml.j2 | 67 +++++++++++++ roles/ands_kaas/tasks/do_apps.yml | 18 ++-- roles/ands_kaas/tasks/do_keys.yml | 6 ++ roles/ands_kaas/tasks/do_project.yml | 77 +++----------- roles/ands_kaas/tasks/do_storage.yml | 14 ++- roles/ands_kaas/tasks/ocitem.yml | 28 +++++- roles/ands_kaas/tasks/project.yml | 17 ++-- roles/ands_kaas/tasks/template.yml | 11 +- roles/ands_kaas/templates/00-local-volumes.yml.j2 | 50 ++++++++++ roles/ands_kaas/templates/50-kaas-pods.yml.j2 | 111 +++++++++++++++++---- roles/ands_network/defaults/main.yml | 2 + roles/ands_network/files/galera.xml | 10 ++ roles/ands_network/files/netpipe.xml | 6 ++ roles/ands_network/tasks/add_names.yml | 28 ++++++ roles/ands_network/tasks/common.yml | 1 - roles/ands_network/tasks/firewall.yml | 32 ++++++ roles/ands_network/tasks/firewall_service.yml | 13 +++ roles/ands_network/tasks/nm_configure.yml | 15 ++- .../ands_network/tasks/nm_configure_connection.yml | 31 ++++-- roles/openshift_resource/tasks/template.yml | 9 +- 26 files changed, 477 insertions(+), 120 deletions(-) create mode 100644 roles/ands_facts/tasks/node.yml create mode 100644 roles/ands_facts/tasks/nodes.yml create mode 100644 roles/ands_facts/tasks/volume.yml create mode 100644 roles/ands_facts/tasks/volumes.yml create mode 100644 roles/ands_facts/tasks/volumes_iterate.yml create mode 100644 roles/ands_kaas/00-local-volumes.yml.j2 create mode 100644 roles/ands_kaas/tasks/do_keys.yml create mode 100644 roles/ands_kaas/templates/00-local-volumes.yml.j2 create mode 100644 roles/ands_network/files/galera.xml create mode 100644 roles/ands_network/files/netpipe.xml create mode 100644 roles/ands_network/tasks/add_names.yml create mode 100644 roles/ands_network/tasks/firewall.yml create mode 100644 roles/ands_network/tasks/firewall_service.yml (limited to 'roles') diff --git a/roles/ands_facts/tasks/main.yml b/roles/ands_facts/tasks/main.yml index ce5dd23..54c800a 100644 --- a/roles/ands_facts/tasks/main.yml +++ b/roles/ands_facts/tasks/main.yml @@ -13,7 +13,15 @@ - name: "Configuring storage facts" include_tasks: "storage.yml" +- name: "Configuring ands nodes" + include_tasks: "nodes.yml" + +- name: "Configuring ands volumes" + include_tasks: "volumes.yml" + - name: "Confirm that ands facts are configured" set_fact: ands_none: "{{ ands_none }}" ands_facts_configured: true + +#- debug: msg="{{ ands_volume_hostraid_servers }}" diff --git a/roles/ands_facts/tasks/node.yml b/roles/ands_facts/tasks/node.yml new file mode 100644 index 0000000..e30442c --- /dev/null +++ b/roles/ands_facts/tasks/node.yml @@ -0,0 +1,5 @@ +- name: "Associating public host names with ids" + set_fact: "ands_host_{{ host_id }}_public_hostname={{ host.value['ands_openshift_public_hostname'] }}" + +- name: "Associating openshift fqdn with ids" + set_fact: "ands_host_{{ host_id }}_openshift_fqdn={{ host.value['ands_openshift_fqdn'] }}" diff --git a/roles/ands_facts/tasks/nodes.yml b/roles/ands_facts/tasks/nodes.yml new file mode 100644 index 0000000..ebe8091 --- /dev/null +++ b/roles/ands_facts/tasks/nodes.yml @@ -0,0 +1,10 @@ +- name: Process all nodes + include_tasks: "node.yml" + run_once: true + delegate_to: "{{ groups['masters'][0] }}" + with_dict: "{{ hostvars }}" + vars: + host_id: "{{ host.value['ands_host_id'] }}" + host_name: "{{ host.value['ansible_hostname'] }}" + loop_control: + loop_var: host diff --git a/roles/ands_facts/tasks/volume.yml b/roles/ands_facts/tasks/volume.yml new file mode 100644 index 0000000..5ac4af3 --- /dev/null +++ b/roles/ands_facts/tasks/volume.yml @@ -0,0 +1,8 @@ +- name: "Associating volumes with domains" + set_fact: "ands_volume_{{ name }}_domain={{ domain }}" + +- name: "Associating volumes with servers" + set_fact: "ands_volume_{{ name }}_servers={{ domain_servers }}" + +- name: "Associating volumes with servers" + set_fact: "ands_volume_{{ name }}_server_ids={{ domain_server_ids }}" diff --git a/roles/ands_facts/tasks/volumes.yml b/roles/ands_facts/tasks/volumes.yml new file mode 100644 index 0000000..616202c --- /dev/null +++ b/roles/ands_facts/tasks/volumes.yml @@ -0,0 +1,7 @@ +- name: Process all storage domains + include_tasks: "volumes_iterate.yml" + run_once: true + delegate_to: "{{ groups[domain.servers][0] }}" + with_items: "{{ ands_local_storage_domains | default([]) | union(ands_storage_domains) }}" + loop_control: + loop_var: domain diff --git a/roles/ands_facts/tasks/volumes_iterate.yml b/roles/ands_facts/tasks/volumes_iterate.yml new file mode 100644 index 0000000..979e12f --- /dev/null +++ b/roles/ands_facts/tasks/volumes_iterate.yml @@ -0,0 +1,13 @@ +--- +- name: Iterate volumes + include_tasks: "volume.yml" + with_dict: "{{ domain.volumes }}" + vars: + name: "{{ volume.key }}" + path: "{{ volume.value.mount }}" + server_group: "{{ domain.servers }}" + domain_servers: "{{ groups[domain.servers] | map('extract', hostvars, 'ands_storage_hostname') | list }}" + domain_server_ids: "{{ groups[domain.servers] | map('extract', hostvars, 'ands_host_id') | list }}" + when: volume.value.mount is defined + loop_control: + loop_var: volume diff --git a/roles/ands_kaas/00-local-volumes.yml.j2 b/roles/ands_kaas/00-local-volumes.yml.j2 new file mode 100644 index 0000000..8d1a1c8 --- /dev/null +++ b/roles/ands_kaas/00-local-volumes.yml.j2 @@ -0,0 +1,67 @@ +--- +apiVersion: v1 +kind: Template +metadata: + name: {{ kaas_project }}-local-volumes + annotations: + descriptions: "{{ kaas_project }} local volumes" +objects: +{% for name, vol in kaas_project_local_volumes.iteritems() %} +{% set voltypes = kaas_storage_domains | json_query("[*].volumes." + vol.volume + ".type") %} +{% set voltype = voltypes[0] | default('host') %} +{% set mntpaths = kaas_storage_domains | json_query("[*].volumes." + vol.volume + ".mount") %} +{% set mntpath = mntpaths[0] | default('') %} +{% set oc_name = vol.name | default(name) | regex_replace('_','-') %} +{% set cfgpath = vol.path | default("") %} +{% set path = cfgpath if cfgpath[:1] == "/" else "/" + kaas_project + "/" + cfgpath %} +{% if oc_name | regex_search("^" + kaas_project) %} +{% set pvprefix = oc_name %} +{% else %} +{% set pvprefix = (kaas_project + "-" + oc_name) | regex_replace('_','-') %} +{% endif %} +{% set i = 0 %} +{% for id in vol.nodes | default(hostvars[inventory_hostname]['ands_volume_' + vol.volume + '_server_ids']) %} +{% set srvid = (id | string) %} +{% set server_name = hostvars[inventory_hostname]['ands_host_' + srvid + '_public_hostname'] %} +{% set openshift_name = hostvars[inventory_hostname]['ands_host_' + srvid + '_openshift_fqdn'] %} +{% set pvname = pvprefix + '-' + server_name %} +{% set pvcname = oc_name + '-' + (i|string) %} + - apiVersion: v1 + kind: PersistentVolume + metadata: + name: {{ pvname }} + annotations: + "volume.alpha.kubernetes.io/node-affinity": '{ + "requiredDuringSchedulingIgnoredDuringExecution": { + "nodeSelectorTerms": [ + { "matchExpressions": [ { "key": "kubernetes.io/hostname", "operator": "In", "values": ["{{ openshift_name }}"] } ]} + ] + } + }' + spec: + storageClassName: kaas-local-storage + persistentVolumeReclaimPolicy: Retain + local: + path: "{{ mntpath }}{{ path }}" + readOnly: {{ not (vol.write | default(false)) }} + accessModes: + - ReadWriteOnce + capacity: + storage: {{ vol.capacity | default(kaas_default_volume_capacity) }} + claimRef: + name: {{ pvcname }} + namespace: {{ kaas_project }} + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: {{ pvcname }} + spec: + volumeName: {{ pvname }} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ vol.capacity | default(kaas_default_volume_capacity) }} +{% set i = i + 1 %} +{% endfor %} +{% endfor %} diff --git a/roles/ands_kaas/tasks/do_apps.yml b/roles/ands_kaas/tasks/do_apps.yml index 6738b7f..39283b4 100644 --- a/roles/ands_kaas/tasks/do_apps.yml +++ b/roles/ands_kaas/tasks/do_apps.yml @@ -1,16 +1,20 @@ - name: "Process KaaS apps" include_tasks: "template.yml" run_once: true - with_items: "{{ kaas_project_apps }}" + with_dict: "{{ kaas_project_apps }}" loop_control: - loop_var: appname + loop_var: appitem when: - - app.provision | default(true) - - (ands_configure_app == ands_none) or (app.name == ands_configure_app) + - appitem.value.provision | default(true) + - (ands_configure_app == ands_none) or (appname == ands_configure_app) + - appname | match(kaas_app_regexp | default(.*)) vars: - app: "{{ kaas_project_config[appname] }}" - name: "{{ app.name | default((app.pods.keys() | list)[0]) }}" - instantiate: "{{ app.instantiate | default(false) }}" + app: "{{ kaas_project_config[appitem.key] }}" + appname: "{{ app.name | default(appitem.key) | regex_replace('_','-') }}" +# appname: "{{ app.name | default((app.pods.keys() | list)[0]) }}" + options: "{{ app.options | default({}) }}" + delete: "{{ options.delete | default(true) }}" + instantiate: "{{ appitem.value.instantiate | default(false) }}" load: "{{ app.load | default(false) }}" pods: "{{ app.pods }}" tmpl_name: "50-kaas-pods.yml.j2" diff --git a/roles/ands_kaas/tasks/do_keys.yml b/roles/ands_kaas/tasks/do_keys.yml new file mode 100644 index 0000000..391392e --- /dev/null +++ b/roles/ands_kaas/tasks/do_keys.yml @@ -0,0 +1,6 @@ +- name: Load OpenSSL keys + include_tasks: keys.yml + run_once: true + with_dict: "{{ kaas_project_pods }}" + loop_control: + loop_var: pod diff --git a/roles/ands_kaas/tasks/do_project.yml b/roles/ands_kaas/tasks/do_project.yml index f5b3276..71a54ad 100644 --- a/roles/ands_kaas/tasks/do_project.yml +++ b/roles/ands_kaas/tasks/do_project.yml @@ -2,77 +2,24 @@ - name: Ensure OpenShift template directory exists file: path="{{ kaas_template_path }}" state="directory" mode=0755 owner=root group=root -- name: Configure KaaS volumes - include_tasks: volume.yml - run_once: true -# delegate_to: "{{ groups.masters[0] }}" - with_dict: "{{ kaas_project_volumes }}" - loop_control: - loop_var: osv - vars: - vt_query: "[*].volumes.{{osv.value.volume}}.type" - voltype: "{{ (kaas_storage_domains | json_query(vt_query)) }}" - mp_query: "[*].volumes.{{osv.value.volume}}.mount" - mntpath: "{{ (kaas_storage_domains | json_query(mp_query)) }}" - rp_query: "[*].volumes.{{osv.value.volume}}.path" - realpath: "{{ (kaas_storage_domains | json_query(rp_query)) }}" - osvpath: "{{ osv.value.path | default('') }}" - prefix: "{{ ( osvpath[:1] == '/' ) | ternary('', '/' ~ kaas_project ~ '/') }}" - path: "{{ mntpath[0] ~ prefix ~ osvpath }}" - hostpath: "{{ realpath[0] is defined | ternary((realpath[0] | default('')) ~ prefix ~ osvpath, '') }}" - name: "{{osv.key}}" - volume: "{{osv.value}}" - when: ( mntpath | length ) > 0 - -- name: Check if static configuration exists - local_action: stat path="{{ kaas_project_path }}/files/" - register: result - -- name: Search static configuration - include_tasks: search.yml - when: result.stat.exists - -- name: Configure KaaS files - include_tasks: file.yml - run_once: true -# delegate_to: "{{ groups.masters[0] }}" - with_items: "{{ kaas_project_config.files | default(kaas_openshift_files) | default([]) }}" - loop_control: - loop_var: file - vars: - osv: "{{ kaas_project_volumes[file.osv] }}" - vt_query: "[*].volumes.{{osv.volume}}.type" - voltype: "{{ (kaas_storage_domains | json_query(vt_query)) }}" - mp_query: "[*].volumes.{{osv.volume}}.mount" - mntpath: "{{ (kaas_storage_domains | json_query(mp_query)) }}" - rp_query: "[*].volumes.{{osv.volume}}.path" - realpath: "{{ (kaas_storage_domains | json_query(rp_query)) }}" - pvar: "kaas_{{ file.osv }}_path" - path: "{{ hostvars[inventory_hostname][pvar] }}/{{ file.path }}" - hvar: "kaas_{{ file.osv }}_hostpath" - hostpath: "{{ hostvars[inventory_hostname][hvar] }}/{{ file.path }}" - when: file.osv in kaas_project_volumes - -- name: Load OpenSSL keys - include_tasks: keys.yml -# delegate_to: "{{ groups.masters[0] }}" - run_once: true - with_dict: "{{ kaas_project_pods }}" - loop_control: - loop_var: pod - - name: "Run OC script" include_tasks: ocscript.yml -# delegate_to: "{{ groups.masters[0] }}" run_once: true when: kaas_project_config.oc is defined -- name: "Configure all templates" - include_tasks: templates.yml -# delegate_to: "{{ groups.masters[0] }}" +- block: + - name: Configure storage + include_tasks: do_storage.yml + + - name: Configure SSL keys + include_tasks: do_keys.yml + + - name: Configure all templates + include_tasks: templates.yml + + - name: Install Applications + include_tasks: do_apps.yml run_once: true when: - kaas_project_config.oc is undefined -- name: Install Applications - include_tasks: do_apps.yml diff --git a/roles/ands_kaas/tasks/do_storage.yml b/roles/ands_kaas/tasks/do_storage.yml index ee118fd..e79db56 100644 --- a/roles/ands_kaas/tasks/do_storage.yml +++ b/roles/ands_kaas/tasks/do_storage.yml @@ -18,8 +18,18 @@ volume: "{{osv.value}}" when: - ( mntpath | length ) > 0 - - (osv.type | default("host")) in [ "host" ] + - (kaas_storage_types is not defined) or ((osv.type | default("host")) in kaas_storage_types) +- name: Check if static configuration exists + local_action: stat path="{{ kaas_project_path }}/files/" + register: result + +# Executed only if complete project is provisioned (not if we just care to provision per-node storage) +- name: Search static configuration + include_tasks: search.yml + when: + - result.stat.exists + - kaas_storage_types is not defined - name: Configure KaaS files include_tasks: file.yml @@ -40,4 +50,4 @@ hostpath: "{{ hostvars[inventory_hostname][hvar] }}/{{ file.path }}" when: - file.osv in kaas_project_volumes - - (osv.type | default("host")) in [ "host" ] + - (kaas_storage_types is not defined) or ((osv.type | default("host")) in kaas_storage_types) diff --git a/roles/ands_kaas/tasks/ocitem.yml b/roles/ands_kaas/tasks/ocitem.yml index addb249..758cdaf 100644 --- a/roles/ands_kaas/tasks/ocitem.yml +++ b/roles/ands_kaas/tasks/ocitem.yml @@ -1,13 +1,35 @@ --- +- name: Storage + include_tasks: do_storage.yml + run_once: true + vars: + kaas_storage_regexp: "{{ ocitem.storage }}" + when: ocitem.storage is defined + +- name: Keys + include_tasks: do_keys.yml + run_once: true + vars: + kaas_keys_regexp: "{{ ocitem.keys }}" + when: ocitem.keys is defined + - name: OpenShift templates include_tasks: templates.yml run_once: true vars: - kaas_template_glob: "{{ ocitem.template }}" - when: ocitem.template is defined + kaas_template_glob: "{{ ocitem.templates }}" + when: ocitem.templates is defined + +- name: OpenShift apps + include_tasks: do_apps.yml + run_once: true + vars: + kaas_app_regexp: "{{ ocitem.apps }}" + when: ocitem.apps is defined - name: OpenShift commands include_tasks: oc.yml -# delegate_to: "{{ groups.masters[0] }}" run_once: true when: ocitem.oc is defined + + diff --git a/roles/ands_kaas/tasks/project.yml b/roles/ands_kaas/tasks/project.yml index ecb2035..26bd0cc 100644 --- a/roles/ands_kaas/tasks/project.yml +++ b/roles/ands_kaas/tasks/project.yml @@ -26,7 +26,7 @@ with_dict: "{{ kaas_block_volumes }}" when: item.value.project == kaas_project -- name: Get information about block volumes +- name: Get more information about block volumes delegate_to: "{{ groups.masters[0] }}" shell: gluster-block info {{ item.value.volume }}/{{ item.key }} | grep -oP '^EXPORTED NODE.*:\s*\K.*' | tr ' ' '\n' register: portal_info @@ -55,11 +55,12 @@ - include_tasks: "do_{{ do_subrole | default('project') }}.yml" vars: var_name: "var_{{kaas_project}}_config" - kaas_project_config: "{{ hostvars[inventory_hostname][var_name] }}" - kaas_project_volumes: "{{ kaas_project_config.volumes | default(kaas_project_config.extra_volumes | default({}) | combine(kaas_openshift_volumes)) }}" - kaas_project_pods: "{{ kaas_project_config.pods | default({}) }}" - kaas_project_apps: "{{ kaas_project_config.apps | default([]) }}" - kaas_project_gids: "{{ kaas_project_config.gids | default(kaas_openshift_gids) }}" - kaas_project_uids: "{{ kaas_project_config.uids | default(kaas_openshift_uids) }}" - kaas_blockvol_info: "{{ block_info }}" + kaas_project_config: "{{ hostvars[inventory_hostname][var_name] }}" + kaas_project_volumes: "{{ kaas_project_config.volumes | default(kaas_project_config.extra_volumes | default({}) | combine(kaas_openshift_volumes)) }}" + kaas_project_local_volumes: "{{ kaas_project_config.local_volumes | default({}) }}" + kaas_project_pods: "{{ kaas_project_config.pods | default({}) }}" + kaas_project_apps: "{{ kaas_project_config.apps | default([]) }}" + kaas_project_gids: "{{ kaas_project_config.gids | default(kaas_openshift_gids) }}" + kaas_project_uids: "{{ kaas_project_config.uids | default(kaas_openshift_uids) }}" + kaas_blockvol_info: "{{ block_info }}" \ No newline at end of file diff --git a/roles/ands_kaas/tasks/template.yml b/roles/ands_kaas/tasks/template.yml index 418331a..87e45a6 100644 --- a/roles/ands_kaas/tasks/template.yml +++ b/roles/ands_kaas/tasks/template.yml @@ -1,9 +1,9 @@ -- name: "Populate template {{ tmpl_name }}" +- name: "Populate template '{{ tmpl_name }}' in project '{{ kaas_project }}' for application '{{ appname | default('kaas') }}'" template: src="{{ item }}" dest="{{ kaas_template_path }}/{{ dest_name }}" owner=root group=root mode="0644" register: result vars: default_name: "{{ item | basename | regex_replace('\\.j2','') }}" - dest_name: "{{ (name is defined) | ternary ( (name | default('')) + '.yml', default_name ) }}" + dest_name: "{{ (appname is defined) | ternary ( '90-' + (appname | default('')) + '.yml', default_name ) }}" with_first_found: - paths: - "{{ role_path }}/templates/" @@ -15,10 +15,13 @@ include_role: name="openshift_resource" when: instantiate == true vars: - template: "{{ tmpl_name | basename | regex_replace('\\.j2','') }}" + default_name: "{{ tmpl_name | basename | regex_replace('\\.j2','') }}" + dest_name: "{{ (appname is defined) | ternary ( '90-' + (appname | default('')) + '.yml', default_name ) }}" + template: "{{ dest_name }}" template_path: "{{ kaas_template_path }}" project: "{{ kaas_project }}" - recreate: "{{ result | changed | ternary (true, false) }}" + recreate: "{{ result | changed | ternary (delete | ternary(true, false), false) }}" + replace: "{{ result | changed | ternary (delete | ternary(false, true), false) }}" # alternatively load template # TODO diff --git a/roles/ands_kaas/templates/00-local-volumes.yml.j2 b/roles/ands_kaas/templates/00-local-volumes.yml.j2 new file mode 100644 index 0000000..a97ffae --- /dev/null +++ b/roles/ands_kaas/templates/00-local-volumes.yml.j2 @@ -0,0 +1,50 @@ +--- +apiVersion: v1 +kind: Template +metadata: + name: {{ kaas_project }}-local-volumes + annotations: + descriptions: "{{ kaas_project }} local volumes" +objects: +{% for name, vol in kaas_project_local_volumes.iteritems() %} +{% set voltypes = kaas_storage_domains | json_query("[*].volumes." + vol.volume + ".type") %} +{% set voltype = voltypes[0] | default('host') %} +{% set mntpaths = kaas_storage_domains | json_query("[*].volumes." + vol.volume + ".mount") %} +{% set mntpath = mntpaths[0] | default('') %} +{% set oc_name = vol.name | default(name) | regex_replace('_','-') %} +{% set cfgpath = vol.path | default("") %} +{% set path = cfgpath if cfgpath[:1] == "/" else "/" + kaas_project + "/" + cfgpath %} +{% if oc_name | regex_search("^" + kaas_project) %} +{% set pvprefix = oc_name %} +{% else %} +{% set pvprefix = (kaas_project + "-" + oc_name) | regex_replace('_','-') %} +{% endif %} +{% for id in vol.nodes | default(hostvars[inventory_hostname]['ands_volume_' + vol.volume + '_server_ids']) %} +{% set srvid = (id | string) %} +{% set server_name = hostvars[inventory_hostname]['ands_host_' + srvid + '_public_hostname'] %} +{% set openshift_name = hostvars[inventory_hostname]['ands_host_' + srvid + '_openshift_fqdn'] %} +{% set pvname = pvprefix + '-' + server_name %} + - apiVersion: v1 + kind: PersistentVolume + metadata: + name: {{ pvname }} + annotations: + "volume.alpha.kubernetes.io/node-affinity": '{ + "requiredDuringSchedulingIgnoredDuringExecution": { + "nodeSelectorTerms": [ + { "matchExpressions": [ { "key": "kubernetes.io/hostname", "operator": "In", "values": ["{{ openshift_name }}"] } ]} + ] + } + }' + spec: + storageClassName: {{ vol.sc | default('kaas-lst-' + pvprefix) }} + persistentVolumeReclaimPolicy: Retain + local: + path: "{{ mntpath }}{{ path }}" + readOnly: {{ not (vol.write | default(false)) }} + accessModes: + - ReadWriteOnce + capacity: + storage: {{ vol.capacity | default(kaas_default_volume_capacity) }} +{% endfor %} +{% endfor %} diff --git a/roles/ands_kaas/templates/50-kaas-pods.yml.j2 b/roles/ands_kaas/templates/50-kaas-pods.yml.j2 index 761004d..8c7fe85 100644 --- a/roles/ands_kaas/templates/50-kaas-pods.yml.j2 +++ b/roles/ands_kaas/templates/50-kaas-pods.yml.j2 @@ -1,14 +1,20 @@ #jinja2: trim_blocks: "true", lstrip_blocks: "false" --- +{% set app = app | default('{}') %} apiVersion: v1 kind: Template metadata: - name: {{ name | default(kaas_project) }}-pods + name: {{ appname | default(kaas_project) }}-pods annotations: - descriptions: {{ kaas_project_config.description | default(name | default(kaas_project) ~ " auto-generated pod template") }} + descriptions: {{ kaas_project_config.description | default(appname | default(kaas_project) ~ " auto-generated pod template") }} +{% set applabels = ( app.labels | default({}) | combine( { 'app': appname }) ) if appname is defined else (app.labels | default({})) %} +{% if applabels | length > 0 %} + labels: {{ applabels | to_json }} +{% endif %} objects: {% for name, pod in pods.iteritems() %} {% set kind = pod.kind | default('DeploymentConfig') %} + {% set podname = pod.name | default(name) | regex_replace('_','-') %} {% if pod.enabled | default(true) %} {% set pubkey = "kaas_" ~ name ~ "_pubkey" %} {% set privkey = "kaas_" ~ name ~ "_privkey" %} @@ -17,19 +23,27 @@ objects: {% set pod = pod[pod.variant] %} {% endif %} {% set sched = pod.sched | default({}) %} + {% set service = pod.service | default({}) %} + {% set headless = (service.headles | default(false)) if kind == 'StatefulSet' else false %} + {% set network = pod.network | default({}) %} + {% set hostnet = network.host | default(false) %} {% set node_selector = (sched.selector is defined) | ternary(sched.selector, ands_default_node_selector | combine(sched.restrict | default({}))) %} + {% set labels = pod.general_labels | default({}) | combine(applabels) %} {% if pod.service is defined %} - {% if kind == 'StatefulSet' and pod.service.ports is defined %} + {% if headless and pod.service.ports is defined %} - apiVersion: v1 kind: Service metadata: - name: {{ pod.name | default(name) }}-ss + name: {{ podname }}-ss annotations: {{ pod.service.annotations | default({}) | combine({"service.alpha.kubernetes.io/tolerate-unready-endpoints": "true" }) | to_json }} + {% if labels | length > 0 %} + labels: {{ labels | to_json }} + {% endif %} spec: clusterIP: None publishNotReadyAddresses: True selector: - name: {{ pod.name | default(name) }} + name: {{ podname }} ports: {% for port in pod.service.ports %} {% set portmap = (port | string).split('/') %} @@ -41,13 +55,16 @@ objects: - apiVersion: v1 kind: Service metadata: - name: {{ pod.name | default(name) }} + name: {{ podname }} {% if pod.service.annotations is defined %} annotations: {{ pod.service.annotations | to_json }} {% endif %} + {% if labels | length > 0 %} + labels: {{ labels | to_json }} + {% endif %} spec: selector: - name: {{ pod.name | default(name) }} + name: {{ podname }} {% if pod.service.ip is defined %} clusterIP: {{ pod.service.ip }} {% endif %} @@ -65,12 +82,15 @@ objects: - apiVersion: v1 kind: Route metadata: - name: {{ pod.name | default(name) }} + name: {{ podname }} + {% if labels | length > 0 %} + labels: {{ labels | to_json }} + {% endif %} spec: host: {{ pod.service.host }} to: kind: Service - name: {{ pod.name | default(name) }} + name: {{ podname }} port: targetPort: {{ (first_port[1] is defined) | ternary(first_port[1], first_port[0]) }} {% if (first_port[0] == "80") %} @@ -95,7 +115,10 @@ objects: - apiVersion: {{ kaas_openshift_api_versions[kind] | default('v1') }} kind: {{ kind }} metadata: - name: {{ pod.name | default(name) }} + name: {{ podname }} + {% if labels | length > 0 %} + labels: {{ labels | to_json }} + {% endif %} spec: replicas: {{ ( sched | default({})).replicas | default(1) }} revisionHistoryLimit: 2 @@ -111,25 +134,59 @@ objects: triggers: - type: ConfigChange {% if kind == 'StatefulSet' %} - serviceName: {{ pod.name | default(name) }}-ss + {% if headless %} + serviceName: {{ podname }}-ss + {% else %} + serviceName: {{ podname }} + {% endif %} selector: matchLabels: - name: {{ pod.name | default(name) }} + name: {{ podname }} {% else %} selector: - name: {{ pod.name | default(name) }} + name: {{ podname }} {% endif %} + {% if pod.pvc is defined %} + volumeClaimTemplates: + {% for name, pvc in pod.pvc.iteritems() %} + {% set pvcname = name | regex_replace('_','-') %} + {% set pv = kaas_project_local_volumes[pvcname] | default({}) %} + {% set oc_name = pv.name | default(pvcname) | regex_replace('_','-') %} + {% if oc_name | regex_search("^" + kaas_project) %} + {% set pvname = oc_name %} + {% else %} + {% set pvname = (kaas_project + "-" + oc_name) | regex_replace('_','-') %} + {% endif %} + - metadata: + name: {{ pvcname }} + spec: + storageClassName: {{ pvc.sc | default(pv.sc | default('kaas-lst-' + pvname)) }} + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ pvc.capacity | default(pv.capacity | default(kaas_default_volume_capacity)) }} + {% endfor %} + {% endif %} template: metadata: - name: {{ pod.name | default(name) }} - {% if kind == 'StatefulSet' %} + name: {{ podname }} + {% if headless %} annotations: {{ pod.annotations | default({}) | combine({"pod.alpha.kubernetes.io/initialized": "true"}) | to_json }} {% elif pod.annotations is defined %} annotations: {{ pod.annotations | to_json }} {% endif %} - labels: - name: {{ pod.name | default(name) }} + labels: {{ pod.labels | default({}) | combine(labels) | combine({'name': podname, 'app': (appname | default('kaas'))}) | to_json }} spec: + {% if pod.sa is defined %} + serviceAccountName: {{ pod.sa }} + {% endif %} + hostNetwork: {{ hostnet }} + {% if (headless) and (hostnet) %} + dnsPolicy: {{ network.dns_policy | default('ClusterFirstWithHostNet') }} + {% elif network.dns_policy is defined %} + dnsPolicy: {{ network.dns_policy }} + {% endif %} {% if node_selector | length > 0 %} nodeSelector: {{ node_selector | to_json }} {% endif %} @@ -140,10 +197,12 @@ objects: {% for img in pod.images %} {% set imgidx = loop.index %} {% for vol in (img.mappings | default([])) %} - {% set oc_name = vol.name | default(name) | regex_replace('_','-') %} + {% if (vol.name | default(name)) in kaas_project_volumes.keys() %} + {% set oc_name = vol.name | default(name) | regex_replace('_','-') %} - name: vol-{{imgidx}}-{{loop.index}} persistentVolumeClaim: claimName: {{ oc_name }} + {% endif %} {% endfor %} {% for vol in (img.hostpath | default([])) %} - name: host-{{imgidx}}-{{loop.index}} @@ -170,7 +229,7 @@ objects: containers: {% for img in pod.images %} {% set imgidx = loop.index %} - - name: {{ img.name | default(pod.name) | default(name) }} + - name: {{ img.name | default(podname) }} image: {{ img.image }} imagePullPolicy: {{ img.pull | default('Always') }} {% if (img.command is defined) %} @@ -179,13 +238,22 @@ objects: {% if img.ports is defined %} ports: {% for port in img.ports %} + {% if hostnet %} + {% set portmap = (port | string).split('/') %} + - containerPort: {{ (portmap[1] is defined) | ternary(portmap[1], portmap[0]) }} + hostPort: {{ portmap[0] }} + {% else %} - containerPort: {{ port }} + {% endif %} {% endfor %} {% elif pod.service.ports is defined %} ports: {% for port in pod.service.ports %} {% set portmap = (port | string).split('/') %} - containerPort: {{ (portmap[1] is defined) | ternary(portmap[1], portmap[0]) }} + {% if hostnet %} + hostPort: {{ portmap[0] }} + {% endif %} {% endfor %} {% endif %} {% if kind == 'StatefulSet' %} @@ -226,7 +294,12 @@ objects: {% if img.mappings is defined or img.hostpath is defined %} volumeMounts: {% for vol in (img.mappings | default([])) %} + {% if vol.name in kaas_project_volumes.keys() %} - name: vol-{{imgidx}}-{{loop.index}} + {% elif vol.name in kaas_project_local_volumes.keys() %} + {% set pvcname = vol.name | regex_replace('_','-') %} + - name: {{ pvcname }} + {% endif %} subPath: {{ vol.path | default("") }} mountPath: {{ vol.mount }} {% endfor %} diff --git a/roles/ands_network/defaults/main.yml b/roles/ands_network/defaults/main.yml index 139e8b3..0170370 100644 --- a/roles/ands_network/defaults/main.yml +++ b/roles/ands_network/defaults/main.yml @@ -1 +1,3 @@ configure_network: "{{ ands_configure_network | default(false) }}" +firewall_template_path: "{{ ands_paths.provision }}/firewall/{{ ansible_hostname }}" +firewall_services: [ 'galera', 'netpipe' ] \ No newline at end of file diff --git a/roles/ands_network/files/galera.xml b/roles/ands_network/files/galera.xml new file mode 100644 index 0000000..15f908b --- /dev/null +++ b/roles/ands_network/files/galera.xml @@ -0,0 +1,10 @@ + + + MySQL/Galera + MySQL/Galera Database Server + + + + + + diff --git a/roles/ands_network/files/netpipe.xml b/roles/ands_network/files/netpipe.xml new file mode 100644 index 0000000..0e7f355 --- /dev/null +++ b/roles/ands_network/files/netpipe.xml @@ -0,0 +1,6 @@ + + + NetPIPE + NetPIPE network benchmark + + diff --git a/roles/ands_network/tasks/add_names.yml b/roles/ands_network/tasks/add_names.yml new file mode 100644 index 0000000..3edde38 --- /dev/null +++ b/roles/ands_network/tasks/add_names.yml @@ -0,0 +1,28 @@ +# Currently EXCLUDED +# Kind of post-install. We can include this in maitain later. + +# We should not do it before Gluster peers are probed, otherwise everything will fail. +# Some peers will have names and others IPs. +- name: Configure all storage hostnames in /etc/hosts + lineinfile: dest="/etc/hosts" line="{{ ip }} {{ fqdn }} {{ hostname }}" regexp="{{ fqdn }}" state="present" + when: + - hostvars[item]['ands_facts_configured'] is defined + vars: + ip: "{{ hostvars[item]['ands_storage_ip'] }}" + hostname: "{{ hostvars[item]['ands_hostname_storage'] }}" + fqdn: "{{ hostvars[item]['ands_hostname_storage'] ~ ands_inner_dot_domain }}" + with_inventory_hostnames: + - nodes + - new_nodes + +- name: Configure all public hostnames in /etc/hosts + lineinfile: dest="/etc/hosts" line="{{ ip }} {{ fqdn }} {{ hostname }}" regexp="{{ fqdn }}" state="present" + when: + - hostvars[item]['ands_facts_configured'] is defined + vars: + ip: "{{ hostvars[item]['ands_openshift_public_ip'] }}" + hostname: "{{ hostvars[item]['ands_hostname_public'] }}" + fqdn: "{{ hostvars[item]['ands_hostname_public'] ~ ands_inner_dot_domain }}" + with_inventory_hostnames: + - nodes + - new_nodes diff --git a/roles/ands_network/tasks/common.yml b/roles/ands_network/tasks/common.yml index f2fda00..940cde7 100644 --- a/roles/ands_network/tasks/common.yml +++ b/roles/ands_network/tasks/common.yml @@ -7,7 +7,6 @@ # - nodes # - new_nodes - # This will not work properly unless 'ands_facts' are executed on all nodes.... This is checked by evaluating if 'ands_openshift_fqdn' is defined - name: Configure all cluster hostnames in /etc/hosts lineinfile: dest="/etc/hosts" line="{{ ip }} {{ fqdn }} {{ hostname }}" regexp="{{ fqdn }}" state="present" diff --git a/roles/ands_network/tasks/firewall.yml b/roles/ands_network/tasks/firewall.yml new file mode 100644 index 0000000..d5ba5f3 --- /dev/null +++ b/roles/ands_network/tasks/firewall.yml @@ -0,0 +1,32 @@ +- name: Ensure firewall template directory exists + file: path="{{ firewall_template_path }}" state="directory" mode=0644 owner=root group=root + +#Just in case we already added but not reloaded yet +#- name: Reload firewalld rules +# shell: firewall-cmd --reload + +- name: Get list of existing firewalld services + shell: "firewall-cmd --get-services | tr ' ' '\n'" + changed_when: false + register: services + +- name: Configure missing firewalld services + include_tasks: firewall_service.yml + with_items: "{{ firewall_services }}" + vars: + servicelist: "{{ services.stdout_lines }}" + loop_control: + loop_var: service + +- name: Reload firewalld rules + shell: firewall-cmd --reload + +- name: Enable MySQL and Galera services if ands_hostnet_db is enabled + firewalld: service="{{ item }}" state="enabled" permanent="true" immediate="true" + when: ands_hostnet_db | default(false) + with_items: + - mysql + - galera + +- name: Reload firewalld rules + shell: firewall-cmd --reload diff --git a/roles/ands_network/tasks/firewall_service.yml b/roles/ands_network/tasks/firewall_service.yml new file mode 100644 index 0000000..98bc866 --- /dev/null +++ b/roles/ands_network/tasks/firewall_service.yml @@ -0,0 +1,13 @@ +- name: "Copy firewalld service '{{ service }}'" + copy: src="{{ service }}.xml" dest="{{ firewall_template_path }}/{{ service }}.xml" owner=root group=root mode="0644" + register: result + +- name: "Delete old version of firewalld service '{{ service }}'" + command: "firewall-offline-cmd --remove-service={{ service }}" + when: + - service in servicelist + - result | changed + +- name: "Create firewalld service '{{ service }}'" + command: "firewall-offline-cmd --new-service-from-file='{{ firewall_template_path }}/{{ service }}.xml' --name={{ service }}" + when: (service not in servicelist) or (result | changed) diff --git a/roles/ands_network/tasks/nm_configure.yml b/roles/ands_network/tasks/nm_configure.yml index 4482705..57e40ca 100644 --- a/roles/ands_network/tasks/nm_configure.yml +++ b/roles/ands_network/tasks/nm_configure.yml @@ -1,4 +1,3 @@ - - name: install needed network manager libs yum: name='{{ item }}' state=installed with_items: @@ -21,6 +20,16 @@ cidr: "{{ ands_storage_cidr }}" force: true +- name: configure bridged openshift nework + include_tasks: nm_configure_connection.yml + vars: + bridge: "{{ ands_bridge }}" + name: "openshift" + iface: "{{ ands_inner_interface }}" + cidr: "{{ ands_openshift_cidr }}" + force: true + when: ands_enable_cnr | default(false) + - name: configure openshift nework include_tasks: nm_configure_connection.yml vars: @@ -28,6 +37,8 @@ iface: "{{ ands_inner_interface }}" cidr: "{{ ands_openshift_cidr }}" force: true + when: not (ands_enable_cnr | default(false)) + - name: configure public nework include_tasks: nm_configure_connection.yml @@ -37,3 +48,5 @@ cidr: "{{ ands_openshift_public_cidr }}" alias: true +- name: Configure firewall + include_tasks: firewall.yml diff --git a/roles/ands_network/tasks/nm_configure_connection.yml b/roles/ands_network/tasks/nm_configure_connection.yml index 18fc91e..9354fbf 100644 --- a/roles/ands_network/tasks/nm_configure_connection.yml +++ b/roles/ands_network/tasks/nm_configure_connection.yml @@ -1,15 +1,16 @@ -- name: "detect nm connection corresponding to interface '{{ iface }}'" +- name: "detect nm connection corresponding to interface '{{ bridge | default(iface) }}'" shell: "nmcli d show {{ iface | quote }} | grep CONNECTION | cut -d ':' -f 2- | sed -E -e 's/^[[:space:]]+//' | grep '^[[:alpha:]]'" register: conres failed_when: false changed_when: false -- name: "check if the requested ip '{{ cidr }}' is present on the interface '{{ iface }}'" +- name: "check if the requested ip '{{ cidr }}' is present on the interface '{{ biface }}'" set_fact: ip_present: "{{ cidr | ipaddr('address') in ips }}" vars: - eth: "{{ hostvars[inventory_hostname]['ansible_' + iface] | default({}) }}" + biface: "{{ bridge | default(iface) }}" + eth: "{{ hostvars[inventory_hostname]['ansible_' + biface] | default({}) }}" ipv4: "{{ eth['ipv4'] | default({}) }}" q: "{{ eth | json_query('ipv4_secondaries[*].address') }}" sec: "{{ ((q == ands_none) or (q == '')) | ternary([], q) }}" @@ -27,9 +28,24 @@ - not (alias | default(false)) - not ip_present -- name: "configure storage network interface '{{ iface }}' to '{{ cidr }}'" +- name: "create bridge '{{ bridge }}' with cidr '{{ cidr }}'" + command: "nmcli connection add type bridge ifname {{ bridge | quote }} con-name {{ name }} ip4 {{ cidr }}" + when: + - bridge is defined + - (conres.rc != 0) or (not (delres | skipped)) + - (conres.rc != 0) or (not (alias | default(false))) + +- name: "connect bridge '{{ bridge }}' to interface '{{ iface }}'" + command: "nmcli connection add type bridge-slave ifname {{ iface | quote }} master {{ bridge | quote }}" + when: + - bridge is defined + - (conres.rc != 0) or (not (delres | skipped)) + - (conres.rc != 0) or (not (alias | default(false))) + +- name: "configure network interface '{{ iface }}' to '{{ cidr }}'" command: "nmcli connection add type infiniband ifname {{ iface | quote }} con-name {{ name }} ip4 {{ cidr }}" when: + - bridge is not defined - (conres.rc != 0) or (not (delres | skipped)) - (conres.rc != 0) or (not (alias | default(false))) @@ -41,10 +57,11 @@ - conres.rc == 0 - not ip_present - -- name: "add ip alias '{{ cidr }}' to network interface '{{ iface }}'" - command: "nmcli connection up {{ conres.stdout | quote }}" +- name: "start connection {{ cname }}" + command: "nmcli connection up {{ cname | quote }}" register: alres + vars: + cname: "{{ (conres.stdout == '') | ternary(name, conres.stdout) }}" when: - not(alres | skipped) - alres | succeeded diff --git a/roles/openshift_resource/tasks/template.yml b/roles/openshift_resource/tasks/template.yml index 188599f..3469464 100644 --- a/roles/openshift_resource/tasks/template.yml +++ b/roles/openshift_resource/tasks/template.yml @@ -21,10 +21,13 @@ with_sequence: start=0 count="{{resources | default([]) | length}}" when: ((recreate|default(false)) or (results | changed)) and (results.results[item|int].rc == 0) - - name: "{{ template }}: Populate resources to {{project}}" - shell: "oc process -n {{project}} -f '{{ template_path }}/{{template}}' {{ template_args | default('') }} | oc create -n {{project}} -f - {{ create_args | default('') }}" +# Replace often complains on various immutable variables it can't change. We ignore. + - name: "{{ template }}: Populate resources to {{project}} ({{ replace | ternary('replace', 'create') }})" + shell: "oc process -n {{project}} -f '{{ template_path }}/{{template}}' {{ template_args | default('') }} | oc {{ replace | ternary('replace', 'create') }} -n {{project}} -f - {{ create_args | default('') }}" + register: status + failed_when: (status.rc != 0) and not (replace | default(false)) when: - - (recreate|default(false)) or (results | changed) + - (recreate | default(false)) or (replace | default(false)) or (results | changed) - resources | length > 0 run_once: true -- cgit v1.2.1