From 22f0cafdd29a738d9828006b165597d5722c4d91 Mon Sep 17 00:00:00 2001
From: Krish Moodbidri <krish94@uab.edu>
Date: Wed, 9 Oct 2024 12:53:21 -0500
Subject: [PATCH] reused code from other stages to deploy ood_proxy_node

---
 .gitlab-ci.yml | 556 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 520 insertions(+), 36 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cff10d7..e2e2faa 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -36,13 +36,218 @@ variables:
   PROXY_IP: ${PROXY_IP}
   OOD_PROXY_NETWORK: "proxy-net"
 
+
 stages:
+  - pre-build
+  - build
+  - test
   - deploy
+  - cleanup
 
 workflow:
   rules:
     - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
     - if: $CI_PIPELINE_SOURCE == 'schedule'
+    - if: $CI_PIPELINE_SOURCE == 'manual'
+
+.get_build_date: &get_build_date
+  - export BUILD_DATE=$(TZ=America/Chicago date +%Y-%m-%dT%H%M%S)
+  - echo BUILD_DATE=${BUILD_DATE}
+
+.update_ansible_repo: &update_ansible_repo
+  - *get_build_date
+  - |
+    if [ ! -d $CI_PROJECT_DIR/CRI_XCBC ]; then
+      git clone https://github.com/uabrc/CRI_XCBC.git
+      cd CRI_XCBC
+      git remote add upstream https://github.com/jprorama/CRI_XCBC.git
+      cd ..
+    fi
+  - cd CRI_XCBC
+  - git config user.name "${GIT_AUTHOR_NAME}"
+  - git config user.email "${GIT_AUTHOR_EMAIL}"
+  - git fetch origin uab-prod
+  - git fetch upstream dev
+  - git checkout uab-prod
+  - git merge origin/uab-prod
+  - git checkout -b integration
+  - git merge upstream/dev
+  - export CRI_XCBC_HEAD=$(git rev-parse --short HEAD)
+  - export CRI_XCBC_dev=$(git rev-parse --short upstream/dev)
+  - export CRI_XCBC_prod=$(git rev-parse --short origin/uab-prod)
+  - cd ..
+  - export PACKER_IMAGE_HEAD=$(git rev-parse --short HEAD)
+  - echo CRI_XCBC_HEAD=${CRI_XCBC_HEAD} | tee -a $CI_PROJECT_DIR/image.env
+  - echo CRI_XCBC_dev=${CRI_XCBC_dev} | tee -a $CI_PROJECT_DIR/image.env
+  - echo CRI_XCBC_prod=${CRI_XCBC_prod} | tee -a $CI_PROJECT_DIR/image.env
+  - echo PACKER_IMAGE_HEAD=${PACKER_IMAGE_HEAD} | tee -a $CI_PROJECT_DIR/image.env
+
+.get_ansible_files: &get_ansible_files
+  - s3cmd get --force -r --host=$AWS_HOST --host-bucket=$AWS_HOST s3://cheaha-cloud-ansible-files/ ansible/files/
+
+build_docker_image:
+  image: docker:20.10.17
+  stage: pre-build
+  services:
+    - docker:20.10.16-dind
+  tags:
+    - dind
+  before_script:
+    - *get_build_date
+    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+  script:
+    - docker build -t $CI_REGISTRY_IMAGE:$BUILD_DATE -t $CI_REGISTRY_IMAGE:latest .
+    - >
+      docker run --rm $CI_REGISTRY_IMAGE bash -c
+      'ansible --version &&
+      openstack --version &&
+      packer version &&
+      s3cmd --version &&
+      terraform --version'
+    - docker push --all-tags $CI_REGISTRY_IMAGE
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+      changes:
+        - Dockerfile
+      allow_failure: true
+
+build_base_image:
+  stage: build
+  tags:
+    - build
+  script:
+    - |
+      if [ -n "${BUILT_BASE_IMAGE_ID}" ]; then
+        exit 0
+      fi
+    - *update_ansible_repo
+    - *get_ansible_files
+    - export REPO_HEAD=$(git rev-parse --short HEAD)
+    - export PKR_VAR_flavor="${BASE_BUILD_FLAVOR:-$PKR_VAR_flavor}"
+    - export PKR_VAR_build_instance_name="base-${REPO_HEAD}"
+    - export PKR_VAR_image_date_suffix=false
+    - |
+      if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ]; then
+        export PKR_VAR_image_name="base-PR-${CI_MERGE_REQUEST_IID}"
+      elif [ $CI_PIPELINE_SOURCE == 'schedule' ]; then
+        export PKR_VAR_image_name="base-${BUILD_DATE}"
+      fi
+    - packer init openstack
+    - packer validate openstack
+    - packer build -machine-readable openstack | tee base_build.log
+    - export BUILT_BASE_IMAGE_ID=$(grep 'Image:' base_build.log | awk '{print $4}')
+    - echo BUILT_BASE_IMAGE_ID=${BUILT_BASE_IMAGE_ID} | tee -a $CI_PROJECT_DIR/image.env
+    - openstack image unset --property signature_verified $BUILT_BASE_IMAGE_ID
+  artifacts:
+    reports:
+      dotenv: image.env
+    expire_in: 30 days
+
+build_compute_image:
+  stage: build
+  needs: [build_base_image]
+  tags:
+    - build
+  script:
+    - *update_ansible_repo
+    - *get_ansible_files
+    - export PKR_VAR_source_image=${BUILT_BASE_IMAGE_ID}
+    - export REPO_HEAD=$(git rev-parse --short HEAD)
+    - export PKR_VAR_flavor="${COMPUTE_BUILD_FLAVOR:-$PKR_VAR_flavor}"
+    - export PKR_VAR_build_instance_name="compute-${REPO_HEAD}"
+    - export PKR_VAR_image_date_suffix=false
+    - |
+      if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ]; then
+        export PKR_VAR_image_name="compute-PR-${CI_MERGE_REQUEST_IID}"
+      elif [ $CI_PIPELINE_SOURCE == 'schedule' ]; then
+        export PKR_VAR_image_name="compute-${BUILD_DATE}"
+      fi
+    - packer init openstack-compute
+    - packer validate openstack-compute
+    - packer build -machine-readable openstack-compute | tee compute_build.log
+
+build_gpu_image:
+  stage: build
+  needs: [build_base_image]
+  tags:
+    - build
+  script:
+    - *update_ansible_repo
+    - *get_ansible_files
+    - FAILED=false
+    - export GPU_PLACEHOLDER_NAME="gpu1-placeholder"
+    - export GPU_PLACEHOLDER_FLAVOR="gpu1.medium"
+    - export GPU_PLACEHOLDER_IMAGE="CentOS-7-x86_64-GenericCloud-2009"
+    - export PKR_VAR_source_image=${BUILT_BASE_IMAGE_ID}
+    - export REPO_HEAD=$(git rev-parse --short HEAD)
+    - export PKR_VAR_flavor="${GPU_BUILD_FLAVOR:-gpu1.medium}"
+    - export PKR_VAR_build_instance_name="gpu-${REPO_HEAD}"
+    - export PKR_VAR_image_date_suffix=false
+    - |
+      if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ]; then
+        export PKR_VAR_image_name="gpu-PR-${CI_MERGE_REQUEST_IID}"
+      elif [ $CI_PIPELINE_SOURCE == 'schedule' ]; then
+        export PKR_VAR_image_name="gpu-${BUILD_DATE}"
+      fi
+    - packer init openstack-gpu
+    - packer validate openstack-gpu
+    - openstack server delete --wait $GPU_PLACEHOLDER_NAME
+    - packer build -machine-readable openstack-gpu | tee gpu_build.log || FAILED=true
+    - openstack server create --image $GPU_PLACEHOLDER_IMAGE --network cicd-net --flavor $GPU_PLACEHOLDER_FLAVOR $GPU_PLACEHOLDER_NAME
+    - |
+      if [ "$FAILED" = true ]; then
+        exit 1
+      fi
+  rules:
+    - if: $SKIP_GPU_BUILD == "true"
+      when: never
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
+
+build_ood_image:
+  stage: build
+  tags:
+    - build
+  script:
+    - *update_ansible_repo
+    - *get_ansible_files
+    - >
+      curl --header "PRIVATE-TOKEN: ${ANSIBLE_VAR_TOKEN}"
+      "${CI_API_V4_URL}/projects/2836/repository/files/knightly/raw?ref=main"
+      -o CRI_XCBC/group_vars/knightly
+    - 'sed -i -E "s/(lts_access_key: ).*/\1\"${AWS_ACCESS_KEY_ID}\"/" CRI_XCBC/group_vars/knightly'
+    - 'sed -i -E "s/(lts_secret_key: ).*/\1\"${AWS_SECRET_ACCESS_KEY}\"/" CRI_XCBC/group_vars/knightly'
+    - 'sed -i -E "s/(user_register_app_key: ).*/\1\"${SELF_REG_APP_KEY}\"/" CRI_XCBC/group_vars/knightly'
+    - 'sed -i -E "s/(celery_user_password: ).*/\1\"${CELERY_PASSWD}\"/" CRI_XCBC/group_vars/knightly'
+    - 'sed -i -E "s|(ssh_pub_key: ).*|\1\"{{ lookup(''file'', ''${SSH_PUB_KEY}'') }}\"|" CRI_XCBC/group_vars/knightly'
+    - export PKR_VAR_flavor="${OOD_BUILD_FLAVOR:-$PKR_VAR_flavor}"
+    - packer init openstack-ood
+    - packer validate openstack-ood
+    - |
+      if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ]; then
+        export PKR_VAR_image_name="ood-PR-${CI_MERGE_REQUEST_IID}"
+        echo INSTANCE_FLAVOR="${PKR_VAR_flavor}" | tee -a $CI_PROJECT_DIR/image.env
+        echo OOD_INSTANCE_NAME="ood-PR-${CI_MERGE_REQUEST_IID}" | tee -a $CI_PROJECT_DIR/image.env
+        export FLOATING_IP=$(openstack floating ip create uab-campus -f value -c floating_ip_address)
+        echo FLOATING_IP=$FLOATING_IP | tee -a $CI_PROJECT_DIR/image.env
+        sed -i -E "s/(ood_servername: ).*/\1\"$CI_COMMIT_REF_SLUG.$FLOATING_IP.nip.io\"/" CRI_XCBC/group_vars/knightly
+      elif [ $CI_PIPELINE_SOURCE == 'schedule' ]; then
+        export PKR_VAR_image_name="ood-${BUILD_DATE}"
+        echo INSTANCE_FLAVOR="${OOD_INSTANCE_FLAVOR:-cpu16-64g}" | tee -a $CI_PROJECT_DIR/image.env
+        echo OOD_INSTANCE_NAME="ood-knightly" | tee -a $CI_PROJECT_DIR/image.env
+        echo FLOATING_IP=$TEST_IP | tee -a $CI_PROJECT_DIR/image.env
+      fi
+    - >
+      PKR_VAR_build_instance_name="ood-${CRI_XCBC_HEAD}"
+      PKR_VAR_image_date_suffix=false
+      packer build -machine-readable openstack-ood | tee ood_build.log
+    - export BUILT_OOD_IMAGE_ID=$(grep 'Image:' ood_build.log | awk '{print $4}')
+    - echo BUILT_OOD_IMAGE_ID=${BUILT_OOD_IMAGE_ID} | tee -a $CI_PROJECT_DIR/image.env
+    - openstack image set --property CRI_XCBC_prod=${CRI_XCBC_prod} --property CRI_XCBC_dev=${CRI_XCBC_dev} --property PACKER_IMAGE_HEAD=${PACKER_IMAGE_HEAD} ${BUILT_OOD_IMAGE_ID}
+  artifacts:
+    reports:
+      dotenv: image.env
+
 
 deploy_ood_proxy_node:
   stage: deploy
@@ -51,52 +256,331 @@ deploy_ood_proxy_node:
   tags:
     - build
   script:
+    - openstack image set --accept $PROXY_OOD_IMAGE_ID
+    - FAILED=false
+    - |
+      cat > user_data.txt << 
+      echo "$DEV_KEY" >> /root/.ssh/authorized_keys
+    - |
+      export NEW_INSTANCE_ID=$(openstack server create
+      -c id -f value --image $PROXY_OOD_IMAGE_ID
+      --network $OOD_PROXY_NETWORK
+      --security-group ood-https-ports
+      --security-group node-exporter
+      --security-group allow-ssh
+      --user-data user_data.txt
+      --flavor $INSTANCE_FLAVOR
+      --wait
+      $OOD_PROXY_INSTANCE_NAME)
+    - openstack server add floating ip $OOD_PROXY_INSTANCE_NAME $FLOATING_IP
+  artifacts:
+    reports:
+      dotenv: instance.env
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "schedule"
+      when: always
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
+  rules:
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+    - if: $CI_PIPELINE_SOURCE == 'schedule'
+    - when: manual
+
+
+test_ood_image:
+  stage: test
+  needs: [build_ood_image]
+  environment:
+    name: knightly
+  tags:
+    - build
+  script:
+    - openstack image set --accept $BUILT_OOD_IMAGE_ID
+    - FAILED=false
+    - |
+      eval $(ssh-agent -s)
+      chmod 400 "$SSH_PRIV_KEY"
+      ssh-add "$SSH_PRIV_KEY"
+      mkdir ~/.ssh
+      chmod 700 ~/.ssh
+    - OLD_INSTANCE_IP=$(openstack floating ip list --floating-ip-address $CHEAHA_IP -c "Fixed IP Address" -f value)
+    - echo $OLD_INSTANCE_IP
+    - |
+      if [ ! -z $OLD_INSTANCE_IP ]; then
+        export OLD_INSTANCE_ID=$(openstack server list --name $OOD_INSTANCE_NAME --ip $OLD_INSTANCE_IP -c ID -f value)
+      fi
+    - echo OLD_INSTANCE_ID=$OLD_INSTANCE_ID | tee -a instance.env
     - |
       cat > user_data.txt << OEOF
       #!/bin/bash
+      echo "Starting user_data: \$(date)"
+      cat > /etc/resolv.conf << EOF
+      search openstack.internal cm.cluster rc.uab.edu ib.cluster drac.cluster eth.cluster ib-hdr.cluster
+      nameserver 172.20.0.25
+      EOF
       echo "$DEV_KEY" >> /root/.ssh/authorized_keys
-      yum update -y
-      yum install -y git ansible
-      git clone https://github.com/jprorama/CRI_XCBC.git
-      cd CRI_XCBC
-      ansible localhost -m import_role -a name=ood_proxy
+      mkdir -p /run/shibboleth
+      chown shibd:shibd /run/shibboleth
+      echo "Installing s3cmd: \$(date)"
+      pip3 install s3cmd
+      echo "Downloading hostkey via s3cmd: \$(date)"
+      s3cmd get --force -r --access_key=$AWS_ACCESS_KEY_ID --secret_key=$AWS_SECRET_ACCESS_KEY --host=$AWS_HOST --host-bucket=$AWS_HOST s3://knightly-key/ /etc/ssh/
+      echo "Download completed: \$(date)"
+      OEOF
+    - >
+      export NEW_INSTANCE_ID=$(openstack server create
+      -c id -f value --image $BUILT_OOD_IMAGE_ID
+      --network $OOD_INSTANCE_NETWORK
+      --security-group ood-https-ports
+      --security-group node-exporter
+      --security-group allow-ssh
+      --user-data user_data.txt
+      --flavor $INSTANCE_FLAVOR
+      --wait
+      $OOD_INSTANCE_NAME)
+    - echo NEW_INSTANCE_ID=$NEW_INSTANCE_ID | tee -a instance.env
+    - openstack server add floating ip $NEW_INSTANCE_ID $FLOATING_IP
+    - >
+      curl --retry 10 --retry-delay 20 --retry-connrefused https://knightly.rc.uab.edu/Shibboleth.sso/Metadata --resolve knightly.rc.uab.edu:443:$FLOATING_IP -kf
+      || FAILED=true
+    - |
+      cp "$SSH_KNOWN_HOSTS" ~/.ssh/known_hosts
+      chmod 644 ~/.ssh/known_hosts
+      until ssh acctsvc@$FLOATING_IP hostname; do sleep 5; done
+      ssh acctsvc@$FLOATING_IP '[ $(mount | grep "etc/auto" | wc -l) -eq 6 ]' || FAILED=true
+    - |
+      if [ "$FAILED" = true ]; then
+        if [ "${DELETE_WHEN_FAILED-true}" = true ]; then
+          openstack server delete $NEW_INSTANCE_ID
+          echo "DELETE_BUILT_IMAGE=true" | tee -a instance.env
+        fi
+        false
+      fi
+    - openstack server remove floating ip $NEW_INSTANCE_ID $FLOATING_IP
+  artifacts:
+    reports:
+      dotenv: instance.env
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "schedule"
+      when: always
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
+
+test_ood_image_mr:
+  stage: test
+  needs: [build_ood_image]
+  tags:
+    - build
+  script:
+    - export OOD_INSTANCE_NETWORK="cicd-net"
+    - FAILED=false
+    - |
+      eval $(ssh-agent -s)
+      chmod 400 "$SSH_PRIV_KEY"
+      ssh-add "$SSH_PRIV_KEY"
+      mkdir ~/.ssh
+      chmod 700 ~/.ssh
+    - |
+      cat > user_data.txt << OEOF
+      #!/bin/bash
+      cat > /etc/resolv.conf << EOF
+      search openstack.internal cm.cluster rc.uab.edu ib.cluster drac.cluster eth.cluster ib-hdr.cluster
+      nameserver 172.20.0.25
+      EOF
+      echo "$DEV_KEY" >> /root/.ssh/authorized_keys
+      mkdir -p /run/shibboleth
+      chown shibd:shibd /run/shibboleth
       OEOF
+    - >
+      export NEW_INSTANCE_ID=$(openstack server create
+      -c id -f value --image $BUILT_OOD_IMAGE_ID
+      --network $OOD_INSTANCE_NETWORK
+      --security-group ood-https-ports
+      --security-group allow-ssh
+      --user-data user_data.txt
+      --flavor $INSTANCE_FLAVOR
+      --wait
+      $OOD_INSTANCE_NAME)
+    - echo NEW_INSTANCE_ID=$NEW_INSTANCE_ID | tee -a instance.env
+    - openstack server add floating ip $NEW_INSTANCE_ID $FLOATING_IP
+    - >
+      curl --retry 10 --retry-delay 20 --retry-connrefused https://knightly.rc.uab.edu/Shibboleth.sso/Metadata --resolve knightly.rc.uab.edu:443:$FLOATING_IP -kf
+      || FAILED=true
+    - ssh -o StrictHostKeyChecking=no acctsvc@$FLOATING_IP '[ $(mount | grep "etc/auto" | wc -l) -eq 6 ]' || FAILED=true
+    - |
+      if [ "$FAILED" = true ]; then
+        if [ "${DELETE_WHEN_FAILED-true}" = true ]; then
+          openstack server delete $NEW_INSTANCE_ID
+          openstack image delete $BUILT_OOD_IMAGE_ID
+        fi
+        false
+      fi
+  artifacts:
+    reports:
+      dotenv: instance.env
+  rules:
+    - if: $CI_MERGE_REQUEST_ID
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
+
+deploy_review:
+  stage: deploy
+  script:
+    - echo "Deploy Review App"
+  environment:
+    name: review/$CI_COMMIT_REF_SLUG
+    url: https://$CI_COMMIT_REF_SLUG.$FLOATING_IP.nip.io
+    on_stop: stop_review
+    auto_stop_in: 2 days
+  tags:
+    - build
+  rules:
+    - if: $CI_MERGE_REQUEST_ID
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
+
+stop_review:
+  stage: deploy
+  script:
+    - openstack server delete $NEW_INSTANCE_ID
+    - openstack image delete $BUILT_OOD_IMAGE_ID
+    - openstack floating ip delete $FLOATING_IP
+  environment:
+    name: review/$CI_COMMIT_REF_SLUG
+    action: stop
+  tags:
+    - build
+  rules:
+    - if: $CI_MERGE_REQUEST_ID
+      when: manual
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
 
+deploy_knightly:
+  stage: deploy
+  environment:
+    name: knightly
+  tags:
+    - build
+  script:
     - |
-      PROXY_INSTANCE_ID=$(openstack server create \
-        --image "$PKR_VAR_source_image" \
-        --flavor "$PKR_VAR_flavor" \
-        --network "$OOD_PROXY_NETWORK" \
-        --security-group ood-https-ports \
-        --security-group port80 \
-        --security-group port22 \
-        --user-data user_data.txt \
-        --wait \
-        --format value \
-        --column id \
-        "$OOD_PROXY_NAME")
-
-      
-      echo "Created PROXY_INSTANCE_ID: $PROXY_INSTANCE_ID"
-
-      # Check if the PROXY_IP is set and exists
-      if [ -z "$PROXY_IP" ]; then
-        echo "ERROR: PROXY_IP variable is not set"
-        exit 1
+      if [ ! -z $OLD_INSTANCE_ID ]; then
+        openstack server remove floating ip $OLD_INSTANCE_ID $CAMPUS_IP
+        openstack server remove floating ip $OLD_INSTANCE_ID $CHEAHA_IP
+      fi
+    - |
+      if [ ! -z $NEW_INSTANCE_ID ]; then
+        openstack server add floating ip $NEW_INSTANCE_ID $CAMPUS_IP
+        openstack server add floating ip $NEW_INSTANCE_ID $CHEAHA_IP
       fi
-    
+  only:
+    - schedules
 
+deploy_cheaha:
+  stage: deploy
+  environment:
+    name: cheaha
+  tags:
+    - build
+  script:
+    - echo "Job placeholder to deploy to Cheaha"
+  when: manual
+  only:
+    - main
 
-      # Create and assign a floating IP
-      FLOATING_IP=$(openstack floating ip create $PKR_VAR_floating_ip_network -f value -c floating_ip_address)
-      echo "Created FLOATING_IP: $FLOATING_IP"
+cleanup_knightly:
+  stage: cleanup
+  environment:
+    name: knightly
+  tags:
+    - build
+  script:
+    - >
+      SERVER_TO_BE_DELETE=($(openstack server list --name $OOD_INSTANCE_NAME --sort-column Image --sort-descending -f value -c ID
+      | awk -v NSTK=$NUM_SERVER_TO_KEEP -v OID=$OLD_INSTANCE_ID '$0 != OID {count++}
+      $0 != OID && count>NSTK {print}'))
+    - |
+      for svr in ${SERVER_TO_BE_DELETE[@]}; do
+        echo "Deleting server $svr"
+        openstack server delete ${svr}
+      done
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "schedule"
+      when: always
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
 
-      # Associate the floating IP with the proxy instance
-      openstack server add floating ip $PROXY_INSTANCE_ID $FLOATING_IP
-      echo "Associated FLOATING_IP $FLOATING_IP with PROXY_INSTANCE_ID $PROXY_INSTANCE_ID"
-      
+cleanup_integration:
+  stage: cleanup
+  tags:
+    - build
+  script:
+    - OS_PROJECT_ID=$(openstack application credential show $OS_APPLICATION_CREDENTIAL_ID -f value -c project_id)
+    - openstack image list --sort-column Name --sort-descending -f value -c Name -c ID --property owner=$OS_PROJECT_ID > images.txt
+    - |
+      if [ "${DELETE_BUILT_IMAGE-false}" = true ]; then
+        openstack image delete $BUILT_OOD_IMAGE_ID
+      fi
+    - >
+      OOD_IMAGE_TO_BE_DELETE=($(cat images.txt
+      | awk -v NITK=$NUM_IMAGE_TO_KEEP -v REGEX=ood-$TIMESTAMP_REGEX
+      '{if ($0 ~ REGEX) result[count++] = $1}
+      END {for(i=NITK;i<count;i++) print result[i]}'))
+    - >
+      BASE_IMAGE_TO_BE_DELETE=($(cat images.txt
+      | awk -v NITK=$NUM_IMAGE_TO_KEEP -v REGEX=base-$TIMESTAMP_REGEX
+      '{if ($0 ~ REGEX) result[count++] = $1}
+      END {for(i=NITK;i<count;i++) print result[i]}'))
+    - >
+      COMPUTE_IMAGE_TO_BE_DELETE=($(cat images.txt
+      | awk -v NITK=$NUM_IMAGE_TO_KEEP -v REGEX=compute-$TIMESTAMP_REGEX
+      '{if ($0 ~ REGEX) result[count++] = $1}
+      END {for(i=NITK;i<count;i++) print result[i]}'))
+    - >
+      GPU_IMAGE_TO_BE_DELETE=($(cat images.txt
+      | awk -v NITK=$NUM_IMAGE_TO_KEEP -v REGEX=gpu-$TIMESTAMP_REGEX
+      '{if ($0 ~ REGEX) result[count++] = $1}
+      END {for(i=NITK;i<count;i++) print result[i]}'))
+    - |
+      for img in ${OOD_IMAGE_TO_BE_DELETE[@]}; do
+        echo "Deleting image $img"
+        openstack image delete ${img}
+      done
+    - |
+      for img in ${BASE_IMAGE_TO_BE_DELETE[@]}; do
+        echo "Deleting image $img"
+        openstack image delete ${img}
+      done
+    - |
+      for img in ${COMPUTE_IMAGE_TO_BE_DELETE[@]}; do
+        echo "Deleting image $img"
+        openstack image delete ${img}
+      done
+    - |
+      for img in ${GPU_IMAGE_TO_BE_DELETE[@]}; do
+        echo "Deleting image $img"
+        openstack image delete ${img}
+      done
   rules:
-    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
-    - if: $CI_PIPELINE_SOURCE == 'schedule'
-    - when: manual
+    - if: $CI_PIPELINE_SOURCE == "schedule"
+      when: always
+    - if: $CI_PIPELINE_SOURCE == "manual"
+      when: manual
 
+cleanup_mr:
+  stage: cleanup
+  tags:
+    - build
+  script:
+    - OS_PROJECT_ID=$(openstack application credential show $OS_APPLICATION_CREDENTIAL_ID -f value -c project_id)
+    - >
+      IMAGE_TO_BE_DELETE=($(openstack image list --sort-column Name --sort-descending -f value -c Name -c ID --property owner=$OS_PROJECT_ID
+      | awk -v REGEX="(ood|base|compute|gpu)-PR-$CI_MERGE_REQUEST_IID" '{if ($0 ~ REGEX) print $1}'))
+    - |
+      for img in ${IMAGE_TO_BE_DELETE[@]}; do
+        echo "Deleting image $img"
+        openstack image delete ${img}
+      done
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+      when: always
-- 
GitLab