From 5e5396758212b9f63c01be029e8c732ab687e1f0 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 15:48:50 +0200 Subject: [PATCH 1/9] add TUBITAK as cloud provider for testing --- builder/clouds.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/builder/clouds.yaml b/builder/clouds.yaml index b303de97..ca7b2310 100644 --- a/builder/clouds.yaml +++ b/builder/clouds.yaml @@ -24,3 +24,11 @@ clouds: auth_url: https://api.cloud.ifca.es:5000/v3 token: project_id: 999f045cb1ff4684a15ebb338af69460 + tests: + site: TR-FC1-ULAKBIM + vo: vo.access.egi.eu + auth_type: token + auth: + auth_url: https://bulut.truba.gov.tr:5000/v3 + token: + project_id: 2fa316a05d364de9b5a55ac78a45f8bf From d24e18b38474eed5f5ab279186c9e27603a0ca62 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 15:49:23 +0200 Subject: [PATCH 2/9] launch test VM at TUBITAK to check that the VMI is working --- builder/build-image.sh | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/builder/build-image.sh b/builder/build-image.sh index ddc40f8f..5a4f153a 100755 --- a/builder/build-image.sh +++ b/builder/build-image.sh @@ -17,7 +17,12 @@ FEDCLOUD_SECRET_LOCKER="$2" # create a virtual env for fedcloudclient python3 -m venv "$PWD/.venv" export PATH="$PWD/.venv/bin:$PATH" -pip install fedcloudclient simplejson yq python-hcl2 +pip install fedcloudclient simplejson yq python-hcl2 IM-client + +# work with IGTF certificates +# https://fedcloudclient.fedcloud.eu/install.html#installing-egi-core-trust-anchor-certificates +wget https://raw.githubusercontent.com/tdviet/python-requests-bundle-certs/main/scripts/install_certs.sh +bash install_certs.sh # Get openstack ready mkdir -p /etc/openstack/ @@ -46,8 +51,37 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then builder/refresh.sh vo.access.egi.eu "$(cat /var/tmp/egi/.refresh_token)" images OS_TOKEN="$(yq -r '.clouds.images.auth.token' /etc/openstack/clouds.yaml)" OUTPUT_DIR="$(dirname "$IMAGE")/output-$QEMU_SOURCE_ID" - cd "$OUTPUT_DIR" + pushd "$OUTPUT_DIR" qemu-img convert -O qcow2 -c "$VM_NAME" "$QCOW_FILE" + + # test the resulting image + # 1. upload VMI to cloud provider + builder/refresh.sh vo.access.egi.eu "$(cat /var/tmp/egi/.refresh_token)" tests + OS_TOKEN="$(yq -r '.clouds.tests.auth.token' /etc/openstack/clouds.yaml)" + IMAGE_ID=$(openstack --os-cloud tests --os-token "$OS_TOKEN" \ + image create --disk-format qcow2 --file "$QCOW_FILE" \ + --column id --format value "$VM_NAME") + + # 2. use IM-client to launch the test VM + popd + pushd builder + sed -i -e "s/%TOKEN%/$(cat .oidc_token)/" auth.dat + sed -i -e "s/%IMAGE%/$IMAGE_ID/" vm.yaml + im_client.py create vm.yaml + IM_INFRA_ID=$(im_client.py list | egrep -v 'im.egi.eu|ID') + # get SSH command to connect to the VM + # do pay attention to the "1" parameter, it corresponds to the "show_only" flag + SSH_CMD=$(im_client.py ssh 1 | grep -v 'im.egi.eu') + # this is a placeholder for the tests we want to run via SSH + $SSH_CMD "hosname" + # delete test VM + im_client.py destroy $IM_INFRA_ID + # delete test VMI + openstack --os-cloud tests --os-token "$OS_TOKEN" image delete "$IMAGE_ID" + + # All going well, upload the VMI for sharing in AppDB + popd + pushd "$OUTPUT_DIR" openstack --os-cloud images --os-token "$OS_TOKEN" \ object create egi_endorsed_vas "$QCOW_FILE" ls -lh "$QCOW_FILE" From ad74ff4f5bc45f468a842148e693798f4eb2fba8 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 16:10:42 +0200 Subject: [PATCH 3/9] improve comments --- builder/build-image.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builder/build-image.sh b/builder/build-image.sh index 5a4f153a..2c7a662f 100755 --- a/builder/build-image.sh +++ b/builder/build-image.sh @@ -55,14 +55,14 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then qemu-img convert -O qcow2 -c "$VM_NAME" "$QCOW_FILE" # test the resulting image - # 1. upload VMI to cloud provider + # test step 1/2: upload VMI to cloud provider builder/refresh.sh vo.access.egi.eu "$(cat /var/tmp/egi/.refresh_token)" tests OS_TOKEN="$(yq -r '.clouds.tests.auth.token' /etc/openstack/clouds.yaml)" IMAGE_ID=$(openstack --os-cloud tests --os-token "$OS_TOKEN" \ image create --disk-format qcow2 --file "$QCOW_FILE" \ --column id --format value "$VM_NAME") - # 2. use IM-client to launch the test VM + # test step 2/2. use IM-client to launch the test VM popd pushd builder sed -i -e "s/%TOKEN%/$(cat .oidc_token)/" auth.dat From b4cda9a5bb1521f7abc162d48fee646e60dcb9f6 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 16:14:29 +0200 Subject: [PATCH 4/9] use IM_INFRA_ID --- builder/build-image.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builder/build-image.sh b/builder/build-image.sh index 2c7a662f..76ff6bba 100755 --- a/builder/build-image.sh +++ b/builder/build-image.sh @@ -62,7 +62,7 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then image create --disk-format qcow2 --file "$QCOW_FILE" \ --column id --format value "$VM_NAME") - # test step 2/2. use IM-client to launch the test VM + # test step 2/2: use IM-client to launch the test VM popd pushd builder sed -i -e "s/%TOKEN%/$(cat .oidc_token)/" auth.dat @@ -71,11 +71,11 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then IM_INFRA_ID=$(im_client.py list | egrep -v 'im.egi.eu|ID') # get SSH command to connect to the VM # do pay attention to the "1" parameter, it corresponds to the "show_only" flag - SSH_CMD=$(im_client.py ssh 1 | grep -v 'im.egi.eu') + SSH_CMD=$(im_client.py ssh "$IM_INFRA_ID" 1 | grep -v 'im.egi.eu') # this is a placeholder for the tests we want to run via SSH $SSH_CMD "hosname" # delete test VM - im_client.py destroy $IM_INFRA_ID + im_client.py destroy "$IM_INFRA_ID" # delete test VMI openstack --os-cloud tests --os-token "$OS_TOKEN" image delete "$IMAGE_ID" From 90d287e027f9e1e878ddb0ef3f3f3297767ecd30 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 16:16:57 +0200 Subject: [PATCH 5/9] improve comments --- builder/build-image.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builder/build-image.sh b/builder/build-image.sh index 76ff6bba..1b2c549f 100755 --- a/builder/build-image.sh +++ b/builder/build-image.sh @@ -72,8 +72,9 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then # get SSH command to connect to the VM # do pay attention to the "1" parameter, it corresponds to the "show_only" flag SSH_CMD=$(im_client.py ssh "$IM_INFRA_ID" 1 | grep -v 'im.egi.eu') - # this is a placeholder for the tests we want to run via SSH + # if the below works, the VM is up and running and responds to SSH $SSH_CMD "hosname" + # at this point we may want to run more sophisticated tests # delete test VM im_client.py destroy "$IM_INFRA_ID" # delete test VMI From d4d6654f81839713fd4ab82e761639801a023135 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 16:18:37 +0200 Subject: [PATCH 6/9] add config files for IM-client --- builder/auth.dat | 2 + builder/im_client.cfg | 3 + builder/vm.yaml | 203 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 builder/auth.dat create mode 100644 builder/im_client.cfg create mode 100644 builder/vm.yaml diff --git a/builder/auth.dat b/builder/auth.dat new file mode 100644 index 00000000..52fee43b --- /dev/null +++ b/builder/auth.dat @@ -0,0 +1,2 @@ +id = im; type = InfrastructureManager; token = "%TOKEN%" +id = vo.access.egi.eu-TR-FC1-ULAKBIM; type = EGI; host = TR-FC1-ULAKBIM; vo = vo.access.egi.eu; token = "%TOKEN%" diff --git a/builder/im_client.cfg b/builder/im_client.cfg new file mode 100644 index 00000000..c190e6f6 --- /dev/null +++ b/builder/im_client.cfg @@ -0,0 +1,3 @@ +[im_client] +restapi_url=https://im.egi.eu/im +auth_file=auth.dat diff --git a/builder/vm.yaml b/builder/vm.yaml new file mode 100644 index 00000000..a6d14f2b --- /dev/null +++ b/builder/vm.yaml @@ -0,0 +1,203 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: 'Deploy a compute node getting the IP and SSH credentials to access via + ssh with an extra HD disk.' + +imports: +- grycap_custom_types: https://raw.githubusercontent.com/grycap/tosca/main/custom_types.yaml +metadata: + childs: [] + filename: simple-node-disk.yml + icon: images/vm-icon-disk.png + infra_name: im-client + order: 1 + tabs: + GPU Data: .*gpu.* + VM Data: + - num_cpus + - mem_size + - disk_size + - instance_type + - num_instances + - storage_size + - mount_path + - ports + tag: VM + template_author: Miguel Caballer + template_name: VM + template_version: 1.1.0 +topology_template: + inputs: + disk_size: + constraints: + - valid_values: + - 20 GB + - 50 GB + - 100 GB + - 200 GB + - 0 GB + default: 200 GB + description: Size of the root disk of the VM (in case of 0 disk will no be resized) + type: scalar-unit.size + gpu_model: + default: '' + description: GPU Model + type: string + gpu_vendor: + constraints: + - valid_values: + - '' + - NVIDIA + - AMD + default: '' + description: GPU Vendor + type: string + instance_type: + default: '' + description: Flavor name of the instance + type: string + mem_size: + constraints: + - valid_values: + - 2 GB + - 4 GB + - 8 GB + - 16 GB + - 32 GB + - 64 GB + - 128 GB + - 256 GB + - 512 GB + default: 8 GB + description: Amount of memory for the VM + type: scalar-unit.size + mount_path: + default: /mnt/disk + description: Path to mount the extra disk + type: string + num_cpus: + constraints: + - valid_values: + - 1 + - 2 + - 4 + - 8 + - 16 + - 32 + - 64 + default: 4 + description: Number of virtual cpus for the VM + type: integer + num_gpus: + constraints: + - valid_values: + - 0 + - 1 + - 2 + - 3 + - 4 + default: 0 + description: Number of GPUs to assing to this VM + type: integer + num_instances: + default: 1 + description: Number of VMs to be spawned + type: integer + ports: + default: + port_22: + protocol: tcp + source: 22 + description: 'List of ports to be Opened in the Cloud site (eg. 22,80,443,2000:2100). + You can also include the remote CIDR (eg. 8.8.0.0/24). + ' + entry_schema: + type: PortSpec + type: map + storage_size: + constraints: + - valid_values: + - 0 GB + - 10 GB + - 20 GB + - 50 GB + - 100 GB + - 200 GB + - 500 GB + - 1 TB + - 2 TB + - 10 TB + - 20 TB + - 40 TB + - 100 TB + default: 0 GB + description: Size of the extra HD added to the instance (Set 0 if disk is not + needed) + type: scalar-unit.size + node_templates: + my_block_storage: + properties: + size: + get_input: storage_size + type: tosca.nodes.BlockStorage + simple_node: + capabilities: + endpoint: + properties: + network_name: PUBLIC + ports: + get_input: ports + host: + properties: + disk_size: + get_input: disk_size + gpu_model: + get_input: gpu_model + gpu_vendor: + get_input: gpu_vendor + instance_type: + get_input: instance_type + mem_size: + get_input: mem_size + num_cpus: + get_input: num_cpus + num_gpus: + get_input: num_gpus + os: + properties: + image: ost://bulut.truba.gov.tr/%IMAGE% + type: linux + scalable: + properties: + count: + get_input: num_instances + interfaces: + Standard: + configure: + implementation: https://raw.githubusercontent.com/grycap/tosca/main/artifacts/dummy.yml + properties: + instance_name: im-client_simple_node + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: my_block_storage + relationship: + properties: + location: + get_input: mount_path + type: tosca.relationships.AttachesTo + type: tosca.nodes.indigo.Compute + outputs: + node_creds: + value: + get_attribute: + - simple_node + - endpoint + - credential + - 0 + node_ip: + value: + get_attribute: + - simple_node + - public_address + - 0 From 2f4d2488a75a5bc535e58f1bf7dd56f9bd116005 Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 16:38:54 +0200 Subject: [PATCH 7/9] simplify TOSCA template --- builder/vm.yaml | 192 ++---------------------------------------------- 1 file changed, 7 insertions(+), 185 deletions(-) diff --git a/builder/vm.yaml b/builder/vm.yaml index a6d14f2b..1b5a50b1 100644 --- a/builder/vm.yaml +++ b/builder/vm.yaml @@ -1,203 +1,25 @@ tosca_definitions_version: tosca_simple_yaml_1_0 -description: 'Deploy a compute node getting the IP and SSH credentials to access via - ssh with an extra HD disk.' - imports: - grycap_custom_types: https://raw.githubusercontent.com/grycap/tosca/main/custom_types.yaml -metadata: - childs: [] - filename: simple-node-disk.yml - icon: images/vm-icon-disk.png - infra_name: im-client - order: 1 - tabs: - GPU Data: .*gpu.* - VM Data: - - num_cpus - - mem_size - - disk_size - - instance_type - - num_instances - - storage_size - - mount_path - - ports - tag: VM - template_author: Miguel Caballer - template_name: VM - template_version: 1.1.0 + topology_template: - inputs: - disk_size: - constraints: - - valid_values: - - 20 GB - - 50 GB - - 100 GB - - 200 GB - - 0 GB - default: 200 GB - description: Size of the root disk of the VM (in case of 0 disk will no be resized) - type: scalar-unit.size - gpu_model: - default: '' - description: GPU Model - type: string - gpu_vendor: - constraints: - - valid_values: - - '' - - NVIDIA - - AMD - default: '' - description: GPU Vendor - type: string - instance_type: - default: '' - description: Flavor name of the instance - type: string - mem_size: - constraints: - - valid_values: - - 2 GB - - 4 GB - - 8 GB - - 16 GB - - 32 GB - - 64 GB - - 128 GB - - 256 GB - - 512 GB - default: 8 GB - description: Amount of memory for the VM - type: scalar-unit.size - mount_path: - default: /mnt/disk - description: Path to mount the extra disk - type: string - num_cpus: - constraints: - - valid_values: - - 1 - - 2 - - 4 - - 8 - - 16 - - 32 - - 64 - default: 4 - description: Number of virtual cpus for the VM - type: integer - num_gpus: - constraints: - - valid_values: - - 0 - - 1 - - 2 - - 3 - - 4 - default: 0 - description: Number of GPUs to assing to this VM - type: integer - num_instances: - default: 1 - description: Number of VMs to be spawned - type: integer - ports: - default: - port_22: - protocol: tcp - source: 22 - description: 'List of ports to be Opened in the Cloud site (eg. 22,80,443,2000:2100). - You can also include the remote CIDR (eg. 8.8.0.0/24). - ' - entry_schema: - type: PortSpec - type: map - storage_size: - constraints: - - valid_values: - - 0 GB - - 10 GB - - 20 GB - - 50 GB - - 100 GB - - 200 GB - - 500 GB - - 1 TB - - 2 TB - - 10 TB - - 20 TB - - 40 TB - - 100 TB - default: 0 GB - description: Size of the extra HD added to the instance (Set 0 if disk is not - needed) - type: scalar-unit.size node_templates: - my_block_storage: - properties: - size: - get_input: storage_size - type: tosca.nodes.BlockStorage simple_node: + type: tosca.nodes.indigo.Compute capabilities: endpoint: properties: network_name: PUBLIC - ports: - get_input: ports host: properties: - disk_size: - get_input: disk_size - gpu_model: - get_input: gpu_model - gpu_vendor: - get_input: gpu_vendor - instance_type: - get_input: instance_type - mem_size: - get_input: mem_size - num_cpus: - get_input: num_cpus - num_gpus: - get_input: num_gpus + num_cpus: 2 + mem_size: 4 GB os: properties: image: ost://bulut.truba.gov.tr/%IMAGE% - type: linux - scalable: - properties: - count: - get_input: num_instances - interfaces: - Standard: - configure: - implementation: https://raw.githubusercontent.com/grycap/tosca/main/artifacts/dummy.yml - properties: - instance_name: im-client_simple_node - requirements: - - local_storage: - capability: tosca.capabilities.Attachment - node: my_block_storage - relationship: - properties: - location: - get_input: mount_path - type: tosca.relationships.AttachesTo - type: tosca.nodes.indigo.Compute outputs: - node_creds: - value: - get_attribute: - - simple_node - - endpoint - - credential - - 0 node_ip: - value: - get_attribute: - - simple_node - - public_address - - 0 + value: { get_attribute: [ simple_node, public_address, 0 ] } + node_creds: + value: { get_attribute: [ simple_node, endpoint, credential, 0 ] } From 1fe53645a14293827f5b270c5ac403ae953fbffd Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Fri, 6 Sep 2024 16:51:57 +0200 Subject: [PATCH 8/9] do not cd --- builder/build-image.sh | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/builder/build-image.sh b/builder/build-image.sh index 1b2c549f..6ff6fc63 100755 --- a/builder/build-image.sh +++ b/builder/build-image.sh @@ -48,23 +48,18 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then QEMU_SOURCE_ID=$(hcl2tojson "$IMAGE" | jq -r '.source[0].qemu | keys[]') VM_NAME=$(hcl2tojson "$IMAGE" | jq -r '.source[0].qemu.'"$QEMU_SOURCE_ID"'.vm_name') QCOW_FILE="$VM_NAME.qcow2" - builder/refresh.sh vo.access.egi.eu "$(cat /var/tmp/egi/.refresh_token)" images - OS_TOKEN="$(yq -r '.clouds.images.auth.token' /etc/openstack/clouds.yaml)" OUTPUT_DIR="$(dirname "$IMAGE")/output-$QEMU_SOURCE_ID" - pushd "$OUTPUT_DIR" - qemu-img convert -O qcow2 -c "$VM_NAME" "$QCOW_FILE" + qemu-img convert -O qcow2 -c "$OUTPUT_DIR/$VM_NAME" "$OUTPUT_DIR/$QCOW_FILE" # test the resulting image # test step 1/2: upload VMI to cloud provider builder/refresh.sh vo.access.egi.eu "$(cat /var/tmp/egi/.refresh_token)" tests OS_TOKEN="$(yq -r '.clouds.tests.auth.token' /etc/openstack/clouds.yaml)" IMAGE_ID=$(openstack --os-cloud tests --os-token "$OS_TOKEN" \ - image create --disk-format qcow2 --file "$QCOW_FILE" \ + image create --disk-format qcow2 --file "$OUTPUT_DIR/$QCOW_FILE" \ --column id --format value "$VM_NAME") # test step 2/2: use IM-client to launch the test VM - popd - pushd builder sed -i -e "s/%TOKEN%/$(cat .oidc_token)/" auth.dat sed -i -e "s/%IMAGE%/$IMAGE_ID/" vm.yaml im_client.py create vm.yaml @@ -73,7 +68,7 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then # do pay attention to the "1" parameter, it corresponds to the "show_only" flag SSH_CMD=$(im_client.py ssh "$IM_INFRA_ID" 1 | grep -v 'im.egi.eu') # if the below works, the VM is up and running and responds to SSH - $SSH_CMD "hosname" + "$SSH_CMD hosname" # at this point we may want to run more sophisticated tests # delete test VM im_client.py destroy "$IM_INFRA_ID" @@ -81,12 +76,12 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then openstack --os-cloud tests --os-token "$OS_TOKEN" image delete "$IMAGE_ID" # All going well, upload the VMI for sharing in AppDB - popd - pushd "$OUTPUT_DIR" + builder/refresh.sh vo.access.egi.eu "$(cat /var/tmp/egi/.refresh_token)" images + OS_TOKEN="$(yq -r '.clouds.images.auth.token' /etc/openstack/clouds.yaml)" openstack --os-cloud images --os-token "$OS_TOKEN" \ - object create egi_endorsed_vas "$QCOW_FILE" - ls -lh "$QCOW_FILE" - SHA="$(sha512sum -z "$QCOW_FILE" | cut -f1 -d" ")" + object create egi_endorsed_vas "$OUTPUT_DIR/$QCOW_FILE" + ls -lh "$OUTPUT_DIR/$QCOW_FILE" + SHA="$(sha512sum -z "$OUTPUT_DIR/$QCOW_FILE" | cut -f1 -d" ")" echo "SUCCESSFUL BUILD - $QCOW_FILE - $SHA" >>/var/log/image-build.log fi From 1978942641aaedec1c258700d0c85401fc9e269b Mon Sep 17 00:00:00 2001 From: Sebastian Luna-Valero Date: Tue, 10 Sep 2024 16:04:30 +0200 Subject: [PATCH 9/9] linting --- builder/build-image.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builder/build-image.sh b/builder/build-image.sh index 6ff6fc63..83a7b2e2 100755 --- a/builder/build-image.sh +++ b/builder/build-image.sh @@ -63,10 +63,10 @@ if tools/build.sh "$IMAGE" >/var/log/image-build.log 2>&1; then sed -i -e "s/%TOKEN%/$(cat .oidc_token)/" auth.dat sed -i -e "s/%IMAGE%/$IMAGE_ID/" vm.yaml im_client.py create vm.yaml - IM_INFRA_ID=$(im_client.py list | egrep -v 'im.egi.eu|ID') + IM_INFRA_ID=$(im_client.py list | grep --extended-regexp --invert-match 'im.egi.eu|ID') # get SSH command to connect to the VM # do pay attention to the "1" parameter, it corresponds to the "show_only" flag - SSH_CMD=$(im_client.py ssh "$IM_INFRA_ID" 1 | grep -v 'im.egi.eu') + SSH_CMD=$(im_client.py ssh "$IM_INFRA_ID" 1 | grep --invert-match 'im.egi.eu') # if the below works, the VM is up and running and responds to SSH "$SSH_CMD hosname" # at this point we may want to run more sophisticated tests