From a9224b1afa3b5f01663a27ad1f7895faacc39c48 Mon Sep 17 00:00:00 2001 From: scrungus Date: Thu, 13 Jul 2023 14:12:29 +0100 Subject: [PATCH] capi-image-templates review changes default to ovn dns unnecessary fields label format change dashes to underscores unnecessary underscores update requirements for new coe template ansible role default dns underscores init version of automated template generation init version of automated template generation init version of automated template generation make operation no-op when no new images are defined and stop new images being included in old image list list concat for images --- etc/openstack-config/openstack-config.yml | 6 +- examples/capi-templates-images.yml | 117 ++++++++++++++++++ examples/templates/capi-images-templates.j2 | 20 +++ examples/templates/images.j2 | 28 +++++ examples/templates/old-images.j2 | 21 ++++ examples/templates/old-templates.j2 | 26 ++++ examples/templates/templates.j2 | 36 ++++++ requirements.yml | 2 +- tools/merge_config/ansible.cfg | 2 + tools/merge_config/bin/activate | 22 ++++ tools/merge_config/bin/ensure_venv | 42 +++++++ tools/merge_config/bin/run | 9 ++ tools/merge_config/clouds.yaml | 14 +++ .../inventory/group_vars/all/variables.yml | 42 +++++++ tools/merge_config/inventory/hosts | 1 + tools/merge_config/merge_templates.yml | 46 +++++++ tools/merge_config/requirements.txt | 4 + 17 files changed, 435 insertions(+), 3 deletions(-) create mode 100644 examples/capi-templates-images.yml create mode 100644 examples/templates/capi-images-templates.j2 create mode 100644 examples/templates/images.j2 create mode 100644 examples/templates/old-images.j2 create mode 100644 examples/templates/old-templates.j2 create mode 100644 examples/templates/templates.j2 create mode 100644 tools/merge_config/ansible.cfg create mode 100755 tools/merge_config/bin/activate create mode 100755 tools/merge_config/bin/ensure_venv create mode 100755 tools/merge_config/bin/run create mode 100644 tools/merge_config/clouds.yaml create mode 100644 tools/merge_config/inventory/group_vars/all/variables.yml create mode 100644 tools/merge_config/inventory/hosts create mode 100644 tools/merge_config/merge_templates.yml create mode 100644 tools/merge_config/requirements.txt diff --git a/etc/openstack-config/openstack-config.yml b/etc/openstack-config/openstack-config.yml index fd88313..5760072 100644 --- a/etc/openstack-config/openstack-config.yml +++ b/etc/openstack-config/openstack-config.yml @@ -39,8 +39,10 @@ # Configuration of Glance software images. # List of Glance images. Format is as required by the stackhpc.os-images role. -#openstack_images: +#glance_images: +# Images to be uploaded +#openstack_images: "{{ glance_images + kubernetes_images }}" # List of Diskimage Builder (DIB) elements paths to include in image builds. #openstack_image_elements: @@ -57,4 +59,4 @@ ############################################################################### # Dummy variable to allow Ansible to accept this file. -workaround_ansible_issue_8743: yes +workaround_ansible_issue_8743: yes \ No newline at end of file diff --git a/examples/capi-templates-images.yml b/examples/capi-templates-images.yml new file mode 100644 index 0000000..750014e --- /dev/null +++ b/examples/capi-templates-images.yml @@ -0,0 +1,117 @@ +############################################################################### +# Configuration of Glance software images. + +# Flavor must have a minimum of 2 VCPUs +magnum_flavor: "m1.small" + +# Network to create tenant cluster FIPs on +magnum_external_network: "external" + +# Provider for cluster loadbalancers +magnum_octavia_provider: "ovn" + +# helm chart version to use for tenant clusters +magnum_helm_chart_version: "openstack-cluster-0.1.1-dev.0.main.221" + +ubuntu-focal-kube-v1_25_11: + name: "ubuntu-focal-kube-v1.25.11" + type: qcow2 + image_url: "https://object.arcus.openstack.hpc.cam.ac.uk/swift/v1/AUTH_f0dc9cb312144d0aa44037c9149d2513/azimuth-images/ubuntu-focal-kube-v1.25.11-230712-0939.qcow2" + is_public: True + properties: + os_distro: "ubuntu" + os_version: "20.04" + kube_version: "v1.25.11" + +ubuntu-focal-kube-v1_26_6: + name: "ubuntu-focal-kube-v1.26.6" + type: qcow2 + image_url: "https://object.arcus.openstack.hpc.cam.ac.uk/swift/v1/AUTH_f0dc9cb312144d0aa44037c9149d2513/azimuth-images/ubuntu-focal-kube-v1.26.6-230712-1010.qcow2" + is_public: True + properties: + os_distro: "ubuntu" + os_version: "20.04" + kube_version: "v1.26.6" + +ubuntu-focal-kube-v1_27_3: + name: "ubuntu-focal-kube-v1.27.3" + type: qcow2 + image_url: "https://object.arcus.openstack.hpc.cam.ac.uk/swift/v1/AUTH_f0dc9cb312144d0aa44037c9149d2513/azimuth-images/ubuntu-focal-kube-v1.27.3-230712-1021.qcow2" + is_public: True + properties: + os_distro: "ubuntu" + os_version: "20.04" + kube_version: "v1.27.3" + +# List of Glance images. Format is as required by the stackhpc.os-images role. +openstack_images: + - "{{ ubuntu-focal-kube-v1_25_11 }}" + - "{{ ubuntu-focal-kube-v1_26_6 }}" + - "{{ ubuntu-focal-kube-v1_27_3 }}" + +############################################################################### +# Configuration of Magnum container clusters. + +kube_v1_25_11: + labels: + monitoring_enabled: "false" + kube_dashboard_enabled: "true" + capi_helm_chart_version: "{{ magnum_helm_chart_version }}" + octavia_provider: "{{ magnum_octavia_provider }}" + external_network_id: "{{ magnum_external_network }}" + master_flavor: "{{ magnum_flavor }}" + flavor: "{{ magnum_flavor }}" + image: "ubuntu-focal-kube-v1.25.11" + name: "kubernetes-v1.25.11" + coe: "kubernetes" + network_driver: "calico" + master_lb_enabled: True + floating_ip_enabled: True + # Magnum’s default value for dns_nameserver is 8.8.8.8. + dns_nameserver: "1.1.1.1,8.8.8.8,8.8.4.4" + public: True + +kube_v1_26_6: + labels: + monitoring_enabled: "false" + kube_dashboard_enabled: "true" + capi_helm_chart_version: "{{ magnum_helm_chart_version }}" + octavia_provider: "{{ magnum_octavia_provider }}" + external_network_id: "{{ magnum_external_network }}" + master_flavor: "{{ magnum_flavor }}" + flavor: "{{ magnum_flavor }}" + image: "ubuntu-focal-kube-v1.26.6" + name: "kubernetes-v1.26.6" + coe: "kubernetes" + network_driver: "calico" + master_lb_enabled: True + floating_ip_enabled: True + # Magnum’s default value for dns_nameserver is 8.8.8.8. + dns_nameserver: "1.1.1.1,8.8.8.8,8.8.4.4" + public: True + +kube_v1_27_3: + labels: + monitoring_enabled: "false" + kube_dashboard_enabled: "true" + capi_helm_chart_version: "{{ magnum_helm_chart_version }}" + octavia_provider: "{{ magnum_octavia_provider }}" + external_network_id: "{{ magnum_external_network }}" + master_flavor: "{{ magnum_flavor }}" + flavor: "{{ magnum_flavor}}" + image: "ubuntu-focal-kube-v1.27.3" + name: "kubernetes-v1.27.3" + coe: "kubernetes" + network_driver: "calico" + master_lb_enabled: True + floating_ip_enabled: True + # Magnum’s default value for dns_nameserver is 8.8.8.8. + dns_nameserver: "1.1.1.1,8.8.8.8,8.8.4.4" + public: True + +# List of magnum cluster templates. Format is as required by the +# stackhpc.os-container-clusters role. +openstack_container_clusters_templates: + - "{{ kube_v1_25_11 }}" + - "{{ kube_v1_26_6 }}" + - "{{ kube_v1_27_3 }}" diff --git a/examples/templates/capi-images-templates.j2 b/examples/templates/capi-images-templates.j2 new file mode 100644 index 0000000..5bbd493 --- /dev/null +++ b/examples/templates/capi-images-templates.j2 @@ -0,0 +1,20 @@ +############################################################################### +# Magnum container clusters shared variables. + +# Flavor must have a minimum of 2 VCPUs +magnum_flavor: {{ magnum_flavor_name }} + +# Network to create tenant cluster FIPs on +magnum_external_network: {{ magnum_external_net_name }} + +# Provider for cluster loadbalancers +magnum_octavia_provider: {{ magnum_loadbalancer_provider }} + +# helm chart version to use for tenant clusters +magnum_helm_chart_version: {{ magnum_helm_chart_version }} + +{% include './old-images.j2' %} +{% include './images.j2' %} + +{% include './old-templates.j2' %} +{% include './templates.j2' %} diff --git a/examples/templates/images.j2 b/examples/templates/images.j2 new file mode 100644 index 0000000..d5e1cc8 --- /dev/null +++ b/examples/templates/images.j2 @@ -0,0 +1,28 @@ +############################################################################### +# Configuration of Glance software images. + +{% for item in new_template_data %} +# Image for {{ item.key }} +{{ item.value.name }}: + name: "{{ item.value.name }}" + type: qcow2 + image_url: "{{ item.value.url }}" + is_public: True + properties: + os_distro: "ubuntu" + os_version: "20.04" + kube_version: "{{ item.value.kubernetes_version }}" + +{% endfor %} +# List of Kubernetes images. Format is as required by the stackhpc.os-images role. +kubernetes_images: +{% if matching_images is defined and matching_temps | length > 0 %} +{% for item in matching_images %} +{% if item.value.name not in new_template_data | map(attribute='value.name') %} + - "{{ '{{ ' + item.key + ' }}' }}" +{% endif %} +{% endfor %} +{% endif %} +{% for item in new_template_data %} + - "{{ '{{ ' + item.value.name + ' }}' }}" +{% endfor %} \ No newline at end of file diff --git a/examples/templates/old-images.j2 b/examples/templates/old-images.j2 new file mode 100644 index 0000000..e0920cb --- /dev/null +++ b/examples/templates/old-images.j2 @@ -0,0 +1,21 @@ +{% if matching_images is defined and matching_temps | length > 0 %} +############################################################################### +# Old magnum images - hide until out of use + +{% for item in matching_images %} +{% if item.value.name not in new_template_data | map(attribute='value.name') %} +{{ item.key }}: +{% for key, value in item.value.items() %} +{% if value is mapping %} + {{ key }}: +{% for k, v in value.items() %} + {{ k }}: "{{ v }}" +{% endfor %} +{% else %} + {{ key }}: "{{ value }}" +{% endif %} +{% endfor %} + +{% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/examples/templates/old-templates.j2 b/examples/templates/old-templates.j2 new file mode 100644 index 0000000..a99ce5b --- /dev/null +++ b/examples/templates/old-templates.j2 @@ -0,0 +1,26 @@ +{% if matching_temps is defined and matching_temps | length > 0 %} +############################################################################### +# Old magnum templates - hide until out of use + +{% for item in matching_temps %} +{% if item.key not in new_template_data | map(attribute='key') %} +{{ item.key }}: +{% for key, value in item.value.items() %} +{% if key == 'is_hidden' %} + {{ key }}: {{ value }} +{% elif value is mapping %} + {{ key }}: +{% for k, v in value.items() %} + {{ k }}: "{{ v }}" +{% endfor %} +{% else %} + {{ key }}: "{{ value }}" +{% endif %} +{% endfor %} +{% if 'is_hidden' not in item.value %} +is_hidden: True +{% endif %} + +{% endif %} +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/examples/templates/templates.j2 b/examples/templates/templates.j2 new file mode 100644 index 0000000..f45870b --- /dev/null +++ b/examples/templates/templates.j2 @@ -0,0 +1,36 @@ +############################################################################### +# Configuration of Magnum container clusters. + +{% for item in new_template_data %} +{{ item.key }}: + labels: + monitoring_enabled: "true" + kube_dashboard_enabled: "true" + capi_helm_chart_version: "{{ magnum_helm_chart_version }}" + octavia_provider: {{ magnum_loadbalancer_provider }} + external_network_id: {{ magnum_external_net_name }} + master_flavor: {{ magnum_flavor_name }} + flavor: {{ magnum_flavor_name }} + image: "{{ item.value.name }}" + name: "{{ item.key }}" + coe: "kubernetes" + network_driver: "calico" + master_lb_enabled: True + floating_ip_enabled: True + dns_nameserver: "1.1.1.1,8.8.8.8,8.8.4.4" + public: True + +{% endfor %} +# List of magnum cluster templates. Format is as required by the +# stackhpc.os-container-clusters role. +openstack_container_clusters_templates: +{% if matching_temps is defined and matching_temps | length > 0 %} +{% for item in matching_temps %} +{% if item.key not in new_template_data | map(attribute='key') %} + - "{{ '{{ ' + item.key + ' }}' }}" +{% endif %} +{% endfor %} +{% endif %} +{% for item in new_template_data %} + - "{{ '{{ ' + item.key + ' }}' }}" +{% endfor %} \ No newline at end of file diff --git a/requirements.yml b/requirements.yml index fda082e..ed9b2fa 100644 --- a/requirements.yml +++ b/requirements.yml @@ -9,4 +9,4 @@ roles: collections: - name: openstack.cloud - version: '<2' + version: 2.1.0 diff --git a/tools/merge_config/ansible.cfg b/tools/merge_config/ansible.cfg new file mode 100644 index 0000000..154ac15 --- /dev/null +++ b/tools/merge_config/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +inventory = ./inventory \ No newline at end of file diff --git a/tools/merge_config/bin/activate b/tools/merge_config/bin/activate new file mode 100755 index 0000000..dd43fe7 --- /dev/null +++ b/tools/merge_config/bin/activate @@ -0,0 +1,22 @@ +##### +# This script activates the specified environment +# +# It needs to be sourced rather than just executed as it sets environment variables +# for the current shell +##### +export CONFIG_ROOT="$(dirname $(dirname $(dirname $(dirname $(realpath ${BASH_SOURCE[0]:-${(%):-%x}})))))" + +# If clouds.yaml provided in root dir, then prefer this +if [ -f "$CONFIG_ROOT/tools/merge_config/clouds.yaml" ]; then + export OS_CLOUD="${OS_CLOUD:-"openstack"}" + export OS_CLIENT_CONFIG_FILE="$CONFIG_ROOT/tools/merge_config/clouds.yaml" +fi + +# If a Python virtualenv exists, activate it +VENV="${VENV:-"$CONFIG_ROOT/tools/merge_config/.venv"}" +if [ -f "$VENV/bin/activate" ]; then + echo "Activating Python venv at $VENV" + source "$VENV/bin/activate" +fi + +echo "Activated environment" \ No newline at end of file diff --git a/tools/merge_config/bin/ensure_venv b/tools/merge_config/bin/ensure_venv new file mode 100755 index 0000000..8a09f09 --- /dev/null +++ b/tools/merge_config/bin/ensure_venv @@ -0,0 +1,42 @@ +##### +# This script creates a virtualenv (if not already in one) and installs the required dependencies +##### + +if [[ "$VIRTUAL_ENV" == "" ]]; then + # Check python version + # NOTE: Python 3.8 or newer is required for ansible 2.12 + # which is in turn required for the 'undef' ansible keyword + PY_MAJOR=3 + PY_MINOR=8 + version_check() { + python3 <&2 + echo "Please install a supported version then try again" 1>&2 + exit 1 + fi + + VENV="$CONFIG_ROOT/tools/merge_magnum_config/.venv" + if [ ! -d "$VENV" ]; then + echo "Creating virtual environment at $VENV" + python3 -m venv "$VENV" +fi + +else +VENV=$VIRTUAL_ENV +fi + +CONFIG_ROOT="$(dirname $(dirname $(dirname $(dirname $(realpath ${BASH_SOURCE[0]:-${(%):-%x}})))))" + +echo "Upgrading pip" +"$VENV/bin/python" -m pip install -U pip + +echo "Installing requirements" +"$VENV/bin/python" -m pip install -r "$CONFIG_ROOT/requirements.txt" +"$VENV/bin/python" -m pip install -r "$CONFIG_ROOT/tools/merge_config/requirements.txt" \ No newline at end of file diff --git a/tools/merge_config/bin/run b/tools/merge_config/bin/run new file mode 100755 index 0000000..804a4ff --- /dev/null +++ b/tools/merge_config/bin/run @@ -0,0 +1,9 @@ +#!/bin/bash + +CONFIG_ROOT="$(dirname $(dirname $(dirname $(dirname $(realpath ${BASH_SOURCE[0]:-${(%):-%x}})))))" + +source $CONFIG_ROOT/tools/merge_config/bin/activate + +export ANSIBLE_CONFIG=$CONFIG_ROOT/tools/merge_config/ansible.cfg + +ansible-playbook $CONFIG_ROOT/tools/merge_config/merge_templates.yml \ No newline at end of file diff --git a/tools/merge_config/clouds.yaml b/tools/merge_config/clouds.yaml new file mode 100644 index 0000000..a026cd3 --- /dev/null +++ b/tools/merge_config/clouds.yaml @@ -0,0 +1,14 @@ +# This clouds.yaml is used to connect to the OpenStack project for the environment +# It should contain an application credential +# +# WARNING: This file should be encrypted +clouds: + openstack: + auth: + auth_url: https://auth.os-api.cci1.ecmwf.int:443 + application_credential_id: "2351c754c2684860beb4e8dbdcf63f37" + application_credential_secret: "MhssM5w-n2u_YvSI9c2L52u3bZ1kcSE9MZZoiZ-7v1FflhMizSzAxch3HCNKZ3gEOJzRuqsodP6KHszU5znMmw" + region_name: "RegionOne" + interface: "public" + identity_api_version: 3 + auth_type: "v3applicationcredential" \ No newline at end of file diff --git a/tools/merge_config/inventory/group_vars/all/variables.yml b/tools/merge_config/inventory/group_vars/all/variables.yml new file mode 100644 index 0000000..703f142 --- /dev/null +++ b/tools/merge_config/inventory/group_vars/all/variables.yml @@ -0,0 +1,42 @@ + +_magnum_flavor_name: >- + {{ + lookup('pipe', 'openstack flavor list -f json') | + from_json | + selectattr('Disk', '>=', 20) | + selectattr('VCPUs', '>=', 2) | + selectattr('VCPUs', '<=', 8) | + selectattr('RAM','>=',2048) | + selectattr('RAM','<=',8192) | + first | + json_query('Name') + }} + +magnum_flavor_name: "{{ _magnum_flavor_name }}" + +_magnum_external_net_name: >- + {{ + lookup('pipe', 'openstack network list --external -f json') | + from_json | + reject('search','^ceph$') | + first | + default(undef(hint = 'Unable to find external network')) | + json_query('Name') + }} + +magnum_external_net_name: "{{ _magnum_external_net_name }}" + +_magnum_loadbalancer_provider: >- + {{- + lookup('pipe', 'openstack loadbalancer provider list -f json') | + from_json | + map(attribute = 'name') | + reject('equalto', 'octavia') | + select('match','ovn') | + default('amphora') | + first + }} + +magnum_loadbalancer_provider: "{{ _magnum_loadbalancer_provider }}" + +magnum_helm_chart_version: "openstack-cluster-0.1.1-dev.0.main.221" \ No newline at end of file diff --git a/tools/merge_config/inventory/hosts b/tools/merge_config/inventory/hosts new file mode 100644 index 0000000..4cf0cae --- /dev/null +++ b/tools/merge_config/inventory/hosts @@ -0,0 +1 @@ +localhost ansible_connection=local ansible_python_interpreter="{{ ansible_playbook_python }}" \ No newline at end of file diff --git a/tools/merge_config/merge_templates.yml b/tools/merge_config/merge_templates.yml new file mode 100644 index 0000000..528e69b --- /dev/null +++ b/tools/merge_config/merge_templates.yml @@ -0,0 +1,46 @@ +--- +- hosts: localhost + vars: + root_dir: "{{ lookup('env','CONFIG_ROOT') }}" + site_vars_file: "{{ root_dir }}/etc/openstack-config/container-clusters.yml" + + tasks: + - name: Check if cluster containers file exists + stat: + path: "{{ site_vars_file }}" + register: file_stat + + - name: Load site_vars from file if it exists, otherwise set to an empty dictionary + set_fact: + site_vars: "{{ lookup('file', site_vars_file) | from_yaml }}" + when: file_stat.stat.exists + + - name: Set site_vars to an empty dictionary if the file doesn't exist + set_fact: + site_vars: {} + when: not file_stat.stat.exists + + - name: Find old templates + set_fact: + matching_temps: "{{ site_vars | dict2items | selectattr('key', 'match', 'kube*') | list }}" + when: site_vars is defined and site_vars | length > 0 + + - name: Find old images + set_fact: + matching_images: "{{ site_vars | dict2items | selectattr('key', 'match', 'ubuntu*') | list }}" + when: site_vars is defined and site_vars | length > 0 + + - name: Fetch manifest.json using wget + shell: "wget -O - 'https://github.com/stackhpc/azimuth-images/releases/download/0.1.2/manifest.json'" + register: manifest_response + changed_when: false + + - name: Parse JSON response + set_fact: + new_template_data: "{{ manifest_response.stdout | from_json | dict2items | selectattr('key', 'match', 'kubernetes*') | list }}" + + - name: Template images & templates + template: + src: "{{ root_dir }}/examples/templates/capi-images-templates.j2" + dest: "{{ root_dir }}/etc/openstack-config/container-clusters.yml" + diff --git a/tools/merge_config/requirements.txt b/tools/merge_config/requirements.txt new file mode 100644 index 0000000..6b0d995 --- /dev/null +++ b/tools/merge_config/requirements.txt @@ -0,0 +1,4 @@ +jmespath +python-openstackclient +python-octaviaclient +munch \ No newline at end of file