From c1ce4d2942ff4a733df4734d7ff9163890755611 Mon Sep 17 00:00:00 2001 From: kaiyou <dev@kaiyou.fr> Date: Fri, 1 Dec 2023 15:01:06 +0100 Subject: [PATCH] Prepare for more versatile CI jobs --- ansible/bootstrap.yaml | 3 +- ansible/ciupload.yaml | 42 +++++++++++++++++++ ansible/cleanup.yaml | 7 ++++ ansible/cloud.yaml | 4 +- ansible/deploy.yaml | 13 +++++- .../roles/cloud/tasks/cleanup_scaleway.yaml | 33 ++++++++------- ansible/roles/cloud/tasks/hcloud.yaml | 5 +++ ansible/roles/cloud/tasks/scaleway.yaml | 37 ++++++++-------- ansible/roles/hepto/tasks/main.yaml | 2 +- ansible/test_podinfo.yaml | 18 ++++---- 10 files changed, 115 insertions(+), 49 deletions(-) create mode 100644 ansible/ciupload.yaml create mode 100644 ansible/cleanup.yaml diff --git a/ansible/bootstrap.yaml b/ansible/bootstrap.yaml index d9a805c..92dcb5b 100644 --- a/ansible/bootstrap.yaml +++ b/ansible/bootstrap.yaml @@ -10,7 +10,7 @@ environment: KUBECONFIG: "{{ kubeconfig }}" retries: 10 - delay: 15 + delay: 5 - name: Dump cluster info ansible.builtin.shell: | @@ -27,3 +27,4 @@ helm upgrade --install hepto /tmp/hepto-bootstrap -f /tmp/cluster_info environment: KUBECONFIG: "{{ kubeconfig }}" + diff --git a/ansible/ciupload.yaml b/ansible/ciupload.yaml new file mode 100644 index 0000000..9df744b --- /dev/null +++ b/ansible/ciupload.yaml @@ -0,0 +1,42 @@ +--- +# These tasks uploads the build artifact from CI to some S# +# bucket, for two main reasons: +# - it is complex and unsupported to download the artifact of a current build directly from Gitlab +# - uploading from the CI to many cloud providers can become costly + +- name: Try and get the url + amazon.aws.s3_object: + endpoint_url: "{{ s3_endpoint }}" + bucket: "{{ s3_bucket }}" + region: "{{ s3_region }}" + access_key: "{{ s3_access_key }}" + secret_key: "{{ s3_secret_key }}" + object: "hepto.{{ lookup('env', 'CI_PIPELINE_ID') }}" + mode: geturl + register: get + ignore_errors: true + +- name: Upload the file when necessary + when: get.failed + amazon.aws.s3_object: + endpoint_url: "{{ s3_endpoint }}" + bucket: "{{ s3_bucket }}" + region: "{{ s3_region }}" + access_key: "{{ s3_access_key }}" + secret_key: "{{ s3_secret_key }}" + object: "hepto.{{ lookup('env', 'CI_PIPELINE_ID') }}" + src: "{{ lookup('env', 'PWD') }}/hepto" + mode: put + encrypt: false + register: put + +# This is hacky as hell, yet required for the fact to be properly altered in +# all hosts. The when clause makes it possible to call this outsite the playbook +# during CI warmup +- name: Set the hepto download url for nodes + delegate_to: "{{ item }}" + delegate_facts: true + when: "'nodes' in groups" + with_items: "{{ groups['nodes'] }}" + set_fact: + hepto_url: "{{ put.url if put.changed else get.url }}" diff --git a/ansible/cleanup.yaml b/ansible/cleanup.yaml new file mode 100644 index 0000000..7160246 --- /dev/null +++ b/ansible/cleanup.yaml @@ -0,0 +1,7 @@ +--- +- hosts: localhost + tasks: + - name: Cleanup cloud deployment + include_role: + name: cloud + tasks_from: cleanup.yaml diff --git a/ansible/cloud.yaml b/ansible/cloud.yaml index 178c945..01a7666 100644 --- a/ansible/cloud.yaml +++ b/ansible/cloud.yaml @@ -1,6 +1,6 @@ --- +# This play merely creates nodes and/or probes them, for inclusion +# when deploying or using the cluster - hosts: localhost roles: - cloud - -- import_playbook: deploy.yaml diff --git a/ansible/deploy.yaml b/ansible/deploy.yaml index 6fe2efd..1f84669 100644 --- a/ansible/deploy.yaml +++ b/ansible/deploy.yaml @@ -1,6 +1,17 @@ --- +# This play will do nothing if no cloud deploying is specified +- import_playbook: cloud.yaml + +# If this is a CI deployment, upload hepto to a cloud URL +- hosts: localhost + tasks: + - when: "lookup('env', 'CI_PIPELINE_ID') != ''" + include_tasks: ./ciupload.yaml + +# Deploy the nodes, either epxlicitely declared or deployed to cloud - hosts: nodes roles: - hepto -- ansible.builtin.import_playbook: bootstrap.yaml +# Bootstrap the cluster +- import_playbook: bootstrap.yaml diff --git a/ansible/roles/cloud/tasks/cleanup_scaleway.yaml b/ansible/roles/cloud/tasks/cleanup_scaleway.yaml index 17114c1..ea5ced3 100644 --- a/ansible/roles/cloud/tasks/cleanup_scaleway.yaml +++ b/ansible/roles/cloud/tasks/cleanup_scaleway.yaml @@ -1,16 +1,3 @@ -- name: "Get servers information" - community.general.scaleway_server_info: - api_token: "{{ scaleway_token }}" - region: "{{ scaleway_region }}" - register: raw_servers - -- name: "Index servers information" - ansible.builtin.set_fact: - servers: "{{ raw_servers['scaleway_server_info'] - | map(attribute='name') - | zip(raw_servers['scaleway_server_info']) - | community.general.dict }}" - - name: "Delete nodes" community.general.scaleway_compute: api_token: "{{ scaleway_token }}" @@ -20,14 +7,28 @@ project: "{{ scaleway_project }}" region: "{{ scaleway_region }}" state: absent - register: deleted + register: servers with_dict: "{{ nodes }}" +- name: Debug + debug: + msg: "{{ servers }}" + +# Scaleway module does not offer to delete volumes when deleting nodes, +# so we loop and try to delete all unattached volumes + +- name: "Get volume infos" + community.general.scaleway_volume_info: + api_token: "{{ scaleway_token }}" + region: "{{ scaleway_region }}" + register: volumes + - name: "Delete volumes" community.general.scaleway_volume: api_token: "{{ scaleway_token }}" - name: "{{ servers[item.invocation.module_args.name].volumes[0].name }}" + name: "{{ item.name }}" project: "{{ scaleway_project }}" region: "{{ scaleway_region }}" state: absent - with_dict: "{{ deleted.results }}" + with_items: "{{ volumes.scaleway_volume_info }}" + when: item.state == "available" diff --git a/ansible/roles/cloud/tasks/hcloud.yaml b/ansible/roles/cloud/tasks/hcloud.yaml index 0cdddbf..5736f3e 100644 --- a/ansible/roles/cloud/tasks/hcloud.yaml +++ b/ansible/roles/cloud/tasks/hcloud.yaml @@ -24,10 +24,15 @@ add_host: name: "{{ item.item.key }}" groups: "{{ ['nodes'] + (nodes[item.item.key]|d([])) }}" + # Hcloud does not return the node ip, it is always ::1 in the prefix however ansible_host: "{{ item.hcloud_server.ipv6 | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" ansible_user: root + # Hcloud provides a generic ip for the v6 gateway node_gw: "fe80::1" + # Use the ::2 address inside allocated prefix for hepto node_ip: "{{ item.hcloud_server.ipv6 | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('2') }}" + # Hcloud overrides the default interface to eth0 on every OS + node_iface: eth0 ansible_ssh_extra_args: "-o StrictHostKeyChecking=no" with_items: "{{ servers.results }}" diff --git a/ansible/roles/cloud/tasks/scaleway.yaml b/ansible/roles/cloud/tasks/scaleway.yaml index 2c5c507..a4408cc 100644 --- a/ansible/roles/cloud/tasks/scaleway.yaml +++ b/ansible/roles/cloud/tasks/scaleway.yaml @@ -8,37 +8,40 @@ region: "{{ scaleway_region }}" enable_ipv6: true state: running - register: created with_dict: "{{ nodes }}" -- name: "Get servers information" - community.general.scaleway_server_info: +# We start nodes again so we get their IP address, which is +# not yet available at creation time +- name: "Probe nodes" + community.general.scaleway_compute: api_token: "{{ scaleway_token }}" + name: "{{ node_prefix }}-{{ item.key }}" + commercial_type: "{{ scaleway_type }}" + image: "{{ scaleway_image }}" + project: "{{ scaleway_project }}" region: "{{ scaleway_region }}" - register: raw_servers - -- name: "Index servers information" - ansible.builtin.set_fact: - servers: "{{ raw_servers['scaleway_server_info'] - | map(attribute='name') - | zip(raw_servers['scaleway_server_info']) - | community.general.dict }}" + state: running + register: servers + with_dict: "{{ nodes }}" - name: Wait for nodes to be ready ansible.builtin.wait_for: port: 22 - host: "{{ servers[item.invocation.module_args.name].ipv6.address }}" + host: "{{ item.msg.ipv6.address }}" delay: 2 - with_items: "{{ created.results }}" + with_items: "{{ servers.results }}" - name: "Add nodes to inventory" add_host: name: "{{ item.item.key }}" groups: "{{ ['nodes'] + (nodes[item.item.key]|d([])) }}" - ansible_host: "{{ servers[item.invocation.module_args.name].ipv6.address }}" + ansible_host: "{{ item.msg.ipv6.address }}" ansible_user: root - node_gw: "{{ servers[item.invocation.module_args.name].ipv6.gateway }}" - node_ip: "{{ servers[item.invocation.module_args.name].ipv6.address | ansible.utils.ipmath(1) }}/{{ servers[item.invocation.module_args.name].ipv6.netmask }}" + node_gw: "{{ item.msg.ipv6.gateway }}" + # We use the next (usually ::2) available ip for hepto + node_ip: "{{ item.msg.ipv6.address | ansible.utils.ipmath(1) }}/{{ item.msg.ipv6.netmask }}" + # This is specific to scaleway + node_iface: ens2 ansible_ssh_extra_args: "-o StrictHostKeyChecking=no" - with_items: "{{ created.results }}" + with_items: "{{ servers.results }}" diff --git a/ansible/roles/hepto/tasks/main.yaml b/ansible/roles/hepto/tasks/main.yaml index c2e027d..1e3e091 100644 --- a/ansible/roles/hepto/tasks/main.yaml +++ b/ansible/roles/hepto/tasks/main.yaml @@ -11,7 +11,7 @@ stat: path: "{{ hepto_bin }}" register: hepto_exists - + - name: Download hepto binary for amd64 get_url: url: "{{ hepto_url }}" diff --git a/ansible/test_podinfo.yaml b/ansible/test_podinfo.yaml index 9561408..5b4fb47 100644 --- a/ansible/test_podinfo.yaml +++ b/ansible/test_podinfo.yaml @@ -1,13 +1,15 @@ --- -#- ansible.builtin.import_playbook: cloud.yaml +# Import the cloud playbook to populate inventory +- import_playbook: cloud.yaml -- hosts: mastere - tasks: - +# Do the actual testing from master +- hosts: master + tasks: - name: Deploy podinfo ansible.builtin.shell: | helm repo add --force-update podinfo https://stefanprodan.github.io/podinfo helm repo update + # Podinfo default repository does not expose ipv6, switch to docker.io helm upgrade --install podinfo podinfo/podinfo --set image.repository=docker.io/stefanprodan/podinfo environment: KUBECONFIG: "{{ kubeconfig }}" @@ -18,16 +20,10 @@ environment: KUBECONFIG: "{{ kubeconfig }}" + # This is run from master for now, running from localhost is too complex - name: Try and access the public URL ansible.builtin.get_url: url: "http://[{{ external_ips | first }}]:9898" dest: /tmp retries: 100 delay: 30 - -- hosts: localhost - tasks: - - name: Cleanup cloud deployment - include_role: - name: cloud - tasks_from: cleanup.yaml -- GitLab