diff --git a/.zuul.yaml b/.zuul.yaml
index bf1d39eb..246cf0a4 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -26,7 +26,7 @@
         - airship-shipyard-chart-build-latest-htk
         - airship-shipyard-whitespace-lint-gate
         - airship-shipyard-airskiff-deployment-focal
-        - airship-shipyard-image-gate-ubuntu_focal
+        - shipyard-airskiff-deployment-focal-kubeadm
     gate:
       jobs:
         - airship-shipyard-openstack-tox-pep8-focal
@@ -34,7 +34,6 @@
         - airship-shipyard-chart-build-gate
         - airship-shipyard-whitespace-lint-gate
         - airship-shipyard-airskiff-deployment-focal
-        - airship-shipyard-image-gate-ubuntu_focal
     post:
       jobs:
         - airship-shipyard-docker-build-publish-ubuntu_focal
@@ -116,30 +115,113 @@
         dynamic:
           patch_set: true
 
+# - job:
+#     name: airship-shipyard-airskiff-deployment-focal
+#     nodeset: airship-shipyard-single-node-focal
+#     description: |
+#       Deploy Memcached using Airskiff and submitted Armada changes.
+#     timeout: 9600
+#     voting: true
+#     pre-run:
+#       - tools/gate/playbooks/airskiff-reduce-site.yaml
+#       - tools/gate/playbooks/git-config.yaml
+#     run: tools/gate/playbooks/airskiff-deploy.yaml
+#     post-run: tools/gate/playbooks/debug-report.yaml
+#     required-projects:
+#       - airship/treasuremap
+#     vars:
+#       CLONE_SHIPYARD: false
+#       SHIPYARD_IMAGE_DISTRO: ubuntu_focal
+#       HELM_ARTIFACT_URL: https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz
+#       HTK_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
+#       OSH_INFRA_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
+#       OSH_COMMIT: 2d9457e34ca4200ed631466bd87569b0214c92e7
+#     irrelevant-files: *irrelevant-files
+
 - job:
-    name: airship-shipyard-airskiff-deployment-focal
-    nodeset: airship-shipyard-single-node-focal
-    description: |
-      Deploy Memcached using Airskiff and submitted Armada changes.
-    timeout: 9600
-    voting: true
-    pre-run:
-      - tools/gate/playbooks/airskiff-reduce-site.yaml
-      - tools/gate/playbooks/git-config.yaml
-    run: tools/gate/playbooks/airskiff-deploy.yaml
-    post-run: tools/gate/playbooks/debug-report.yaml
+    name: shipyard-base
+    abstract: true
+    roles:
+      - zuul: openstack/openstack-helm-infra
+      - zuul: zuul/zuul-jobs
     required-projects:
-      - airship/treasuremap
+      - name: openstack/openstack-helm
+      - name: openstack/openstack-helm-infra
+      - name: airship/treasuremap
+        override-checkout: v1.9
+    irrelevant-files: *irrelevant-files
+    timeout: 10800
+    pre-run:
+      - tools/gate/playbooks/prepare-hosts.yaml
+      - tools/gate/playbooks/mount-volumes.yaml
+      - tools/gate/playbooks/deploy-env.yaml
+    run:
+      - tools/gate/playbooks/airship-run-scripts.yaml
+    post-run:
+      - tools/gate/playbooks/osh-infra-collect-logs.yaml
     vars:
-      CLONE_SHIPYARD: false
-      SHIPYARD_IMAGE_DISTRO: ubuntu_focal
+      extra_volume:
+        size: 80G
+        type: Linux
+        mount_point: /opt/ext_vol
+      docker:
+        root_path: "/opt/ext_vol/docker"
+      containerd:
+        root_path: "/opt/ext_vol/containerd"
+      kubeadm:
+        pod_network_cidr: "10.244.0.0/24"
+        service_cidr: "10.96.0.0/16"
+      loopback_setup: true
+      loopback_device: /dev/loop100
+      loopback_image: "/opt/ext_vol/openstack-helm/ceph-loop.img"
+      ceph_osd_data_device: /dev/loop100
+      kube_version_repo: "v1.29"
+      # the list of k8s package versions are available here
+      # https://pkgs.k8s.io/core:/stable:/{{ kube_version_repo }}/deb/Packages
+      kube_version: "1.29.2-1.1"
+      calico_version: "v3.27.0"
+      coredns_version: "v1.11.1"
+      helm_version: "v3.13.2"
+      yq_version: "v4.6.0"
+      crictl_version: "v1.26.1"
+      zuul_osh_relative_path: ../../openstack/openstack-helm
+      zuul_osh_infra_relative_path: ../../openstack/openstack-helm-infra
+      zuul_treasuremap_relative_path: ../../airship/treasuremap
+      gate_scripts_relative_path: ../../openstack/openstack-helm-infra
+      run_helm_tests: "no"
+
+- job:
+    name: shipyard-airskiff-deployment-focal-kubeadm
+    nodeset: treasuremap-airskiff-1node-ubuntu_focal
+    description: |
+      Deploy Memcached using Airskiff and submitted Shipyard changes.
+    parent: shipyard-base
+    vars:
+      site: airskiff
       HELM_ARTIFACT_URL: https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz
       HTK_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
       OSH_INFRA_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
       OSH_COMMIT: 2d9457e34ca4200ed631466bd87569b0214c92e7
+      CLONE_SHIPYARD: false
+      DISTRO: ubuntu_focal
+      DOCKER_REGISTRY: localhost:5000
+      MAKE_SHIPYARD_IMAGES: true
+      gate_scripts_relative_path: ../../airship/treasuremap
+      gate_scripts:
+        - ./tools/deployment/airskiff/developer/000-prepare-k8s.sh
+        - ./tools/deployment/airskiff/developer/009-setup-apparmor.sh
+        - ./tools/deployment/airskiff/developer/000-clone-dependencies.sh
+        - ./tools/deployment/airskiff/developer/020-setup-client.sh
+        - ./tools/deployment/airskiff/developer/015-make-all-charts.sh
+        - ./tools/deployment/airskiff/developer/017-make-all-images.sh
+        - ./tools/deployment/airskiff/developer/025-start-artifactory.sh
+        - ./tools/deployment/airskiff/developer/026-reduce-site.sh
+        - ./tools/deployment/airskiff/developer/030-armada-bootstrap.sh
+        - ./tools/deployment/airskiff/developer/100-deploy-osh.sh
+        - ./tools/deployment/airskiff/common/os-env.sh
+        - ./tools/gate/wait-for-shipyard.sh
     irrelevant-files: *irrelevant-files
 
-
 - job:
     name: airship-shipyard-docker-build-publish-ubuntu_focal
     timeout: 3600
diff --git a/tools/gate/playbooks/airship-run-scripts.yaml b/tools/gate/playbooks/airship-run-scripts.yaml
new file mode 100644
index 00000000..6e29edc0
--- /dev/null
+++ b/tools/gate/playbooks/airship-run-scripts.yaml
@@ -0,0 +1,75 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- hosts: primary
+  tasks:
+    - name: Override images
+      when: buildset_registry is defined
+      vars:
+        work_dir: "{{ zuul.project.src_dir }}"
+      block:
+        - name: Buildset registry alias
+          include_role:
+            name: deploy-env
+            tasks_from: buildset_registry_alias
+
+        - name: Print zuul
+          debug:
+            var: zuul
+
+        - name: Override proposed images from artifacts
+          shell: >
+            find {{ override_paths | join(" ") }} -type f -exec sed -Ei
+            "s#['\"]?docker\.io/({{ repo }}):({{ tag }})['\"]?\$#{{ buildset_registry_alias }}:{{ buildset_registry.port }}/\1:\2#g" {} +
+          loop: "{{ zuul.artifacts | default([]) }}"
+          args:
+            chdir: "{{ work_dir }}"
+          loop_control:
+            loop_var: zj_zuul_artifact
+          when: "'metadata' in zj_zuul_artifact and zj_zuul_artifact.metadata.type | default('') == 'container_image'"
+          vars:
+            tag: "{{ zj_zuul_artifact.metadata.tag }}"
+            repo: "{{ zj_zuul_artifact.metadata.repository }}"
+            override_paths:
+              - ../openstack-helm*/*/values*
+              - ../openstack-helm-infra/tools/deployment/
+
+        - name: Diff
+          shell: |
+              set -ex;
+              for dir in openstack-helm openstack-helm-infra; do
+                path="{{ work_dir }}/../${dir}/"
+                if [ ! -d "${path}" ]; then continue; fi
+                echo "${dir} diff"
+                cd "${path}"; git diff; cd -;
+              done
+
+    - name: "creating directory for run artifacts"
+      file:
+        path: "/tmp/artifacts"
+        state: directory
+
+    - name: Run gate scripts
+      include_role:
+        name: "{{ ([item] | flatten | length == 1) | ternary('airship-run-script', 'airship-run-script-set') }}"
+      vars:
+        workload: "{{ [item] | flatten }}"
+      loop: "{{ gate_scripts }}"
+
+    - name: "Downloads artifacts to executor"
+      synchronize:
+        src: "/tmp/artifacts"
+        dest: "{{ zuul.executor.log_root }}/{{ inventory_hostname }}"
+        mode: pull
+      ignore_errors: True
+...
diff --git a/tools/gate/playbooks/deploy-env.yaml b/tools/gate/playbooks/deploy-env.yaml
new file mode 100644
index 00000000..39b4acfc
--- /dev/null
+++ b/tools/gate/playbooks/deploy-env.yaml
@@ -0,0 +1,36 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- hosts: all
+  become: true
+  gather_facts: true
+
+  roles:
+    - ensure-python
+    - ensure-pip
+    - ensure-tox
+    - clear-firewall
+    - deploy-apparmor
+    - deploy-selenium
+    - deploy-env
+
+  tasks:
+    - name: Install Packaging python module for tools/airship
+      block:
+        - pip:
+            name: packaging
+            version: 23.1
+            executable: pip3
+      become: True
+
+...
diff --git a/tools/gate/playbooks/mount-volumes.yaml b/tools/gate/playbooks/mount-volumes.yaml
new file mode 100644
index 00000000..0049da19
--- /dev/null
+++ b/tools/gate/playbooks/mount-volumes.yaml
@@ -0,0 +1,17 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- hosts: all
+  roles:
+    - mount-extra-volume
+...
diff --git a/tools/gate/playbooks/osh-infra-build.yaml b/tools/gate/playbooks/osh-infra-build.yaml
new file mode 100644
index 00000000..5bd40932
--- /dev/null
+++ b/tools/gate/playbooks/osh-infra-build.yaml
@@ -0,0 +1,36 @@
+# Copyright 2017 The Openstack-Helm Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- hosts: primary
+
+  vars:
+    work_dir: "{{ zuul.project.src_dir }}/{{ zuul_osh_infra_relative_path | default('') }}"
+  gather_facts: True
+  roles:
+    - build-helm-packages
+  tags:
+    - build-helm-packages
+
+- hosts: all
+
+  vars:
+    work_dir: "{{ zuul.project.src_dir }}/{{ zuul_osh_infra_relative_path | default('') }}"
+  gather_facts: False
+  become: yes
+  roles:
+    - bindep
+    - build-images
+  tags:
+    - bindep
+    - build-images
diff --git a/tools/gate/playbooks/osh-infra-collect-logs.yaml b/tools/gate/playbooks/osh-infra-collect-logs.yaml
new file mode 100644
index 00000000..83e76887
--- /dev/null
+++ b/tools/gate/playbooks/osh-infra-collect-logs.yaml
@@ -0,0 +1,43 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- hosts: all
+  vars_files:
+    - vars.yaml
+  vars:
+    work_dir: "{{ zuul.project.src_dir }}/{{ zuul_osh_infra_relative_path | default('') }}"
+    logs_dir: "/tmp/logs"
+  roles:
+    - gather-host-logs
+  tags:
+    - gather-host-logs
+
+- hosts: primary
+  vars_files:
+    - vars.yaml
+  vars:
+    work_dir: "{{ zuul.project.src_dir }}/{{ zuul_osh_infra_relative_path | default('') }}"
+    logs_dir: "/tmp/logs"
+  roles:
+    - helm-release-status
+    - describe-kubernetes-objects
+    - gather-pod-logs
+    - gather-prom-metrics
+    - gather-selenium-data
+  tags:
+    - helm-release-status
+    - describe-kubernetes-objects
+    - gather-pod-logs
+    - gather-prom-metrics
+    - gather-selenium-data
+...
diff --git a/tools/gate/playbooks/prepare-hosts.yaml b/tools/gate/playbooks/prepare-hosts.yaml
new file mode 100644
index 00000000..e7e3d9c9
--- /dev/null
+++ b/tools/gate/playbooks/prepare-hosts.yaml
@@ -0,0 +1,18 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- hosts: all
+  roles:
+    - bindep
+    - start-zuul-console
+...
diff --git a/tools/gate/roles/airship-run-script-set/defaults/main.yaml b/tools/gate/roles/airship-run-script-set/defaults/main.yaml
new file mode 100644
index 00000000..725f4b23
--- /dev/null
+++ b/tools/gate/roles/airship-run-script-set/defaults/main.yaml
@@ -0,0 +1,47 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+ceph_osd_data_device: "/dev/loop0"
+kubeadm:
+  pod_network_cidr: "10.244.0.0/24"
+osh_params:
+  container_distro_name: ubuntu
+  container_distro_version: focal
+  # feature_gates:
+site: airskiff
+HELM_ARTIFACT_URL: https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz
+HTK_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
+OSH_INFRA_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
+OSH_COMMIT: 2d9457e34ca4200ed631466bd87569b0214c92e7
+COREDNS_VERSION: v1.11.1
+DISTRO: ubuntu_focal
+DOCKER_REGISTRY: quay.io
+MAKE_ARMADA_IMAGES: false
+MAKE_DECKHAND_IMAGES: false
+MAKE_SHIPYARD_IMAGES: false
+MAKE_PORTHOLE_IMAGES: false
+MAKE_PROMENADE_IMAGES: false
+CLONE_ARMADA: true
+CLONE_DECKHAND: true
+CLONE_SHIPYARD: true
+CLONE_PORTHOLE: true
+CLONE_PROMENADE: true
+CLONE_MAAS: true
+CLONE_OSH: true
+MAKE_ARMADA_IMAGES: false
+MAKE_DECKHAND_IMAGES: false
+MAKE_SHIPYARD_IMAGES: false
+MAKE_DECKHAND_IMAGES: false
+MAKE_PORTHOLE_IMAGES: false
+MAKE_PROMENADE_IMAGES: false
+...
diff --git a/tools/gate/roles/airship-run-script-set/tasks/main.yaml b/tools/gate/roles/airship-run-script-set/tasks/main.yaml
new file mode 100644
index 00000000..4129a2c1
--- /dev/null
+++ b/tools/gate/roles/airship-run-script-set/tasks/main.yaml
@@ -0,0 +1,84 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- block:
+    - name: "Run script set {{ workload }}"
+      shell: |
+        set -xe;
+        {{ gate_script_path }}
+      loop: "{{ workload }}"
+      loop_control:
+        loop_var: gate_script_path
+        pause: 5
+      args:
+        chdir: "{{ zuul.project.src_dir }}/{{ gate_scripts_relative_path }}"
+      environment:
+        CEPH_OSD_DATA_DEVICE: "{{ ceph_osd_data_device }}"
+        POD_NETWORK_CIDR: "{{ kubeadm.pod_network_cidr }}"
+        zuul_site_mirror_fqdn: "{{ zuul_site_mirror_fqdn }}"
+        OSH_EXTRA_HELM_ARGS: "{{ zuul_osh_extra_helm_args_relative_path | default('') }}"
+        OSH_PATH: "{{ zuul_osh_relative_path | default('../openstack-helm/') }}"
+        OSH_INFRA_PATH: "{{ zuul_osh_infra_relative_path | default('../openstack-helm-infra/') }}"
+        OPENSTACK_RELEASE: "{{ osh_params.openstack_release | default('') }}"
+        CONTAINER_DISTRO_NAME: "{{ osh_params.container_distro_name | default('') }}"
+        CONTAINER_DISTRO_VERSION: "{{ osh_params.container_distro_version | default('') }}"
+        FEATURE_GATES: "{{ osh_params.feature_gates | default('') }}"
+        RUN_HELM_TESTS: "{{ run_helm_tests | default('yes') }}"
+        PL_SITE: "{{ site | default('airskiff') }}"
+        HELM_ARTIFACT_URL: "{{ HELM_ARTIFACT_URL | default('https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz') }}"
+        HTK_COMMIT: "{{ HTK_COMMIT | default('cfff60ec10a6c386f38db79bb9f59a552c2b032f') }}"
+        OSH_INFRA_COMMIT: "{{ OSH_INFRA_COMMIT | default('cfff60ec10a6c386f38db79bb9f59a552c2b032f') }}"
+        OSH_COMMIT: "{{ OSH_COMMIT | default('2d9457e34ca4200ed631466bd87569b0214c92e7') }}"
+        COREDNS_VERSION: "{{ coredns_version | default('v1.11.1') }}"
+        DISTRO: "{{ DISTRO | default('ubuntu_focal') }}"
+        DOCKER_REGISTRY: "{{ DOCKER_REGISTRY | default('quay.io') }}"
+        MAKE_ARMADA_IMAGES: "{{ MAKE_ARMADA_IMAGES | default('false') }}"
+        MAKE_DECKHAND_IMAGES: "{{ MAKE_DECKHAND_IMAGES | default('false') }}"
+        MAKE_SHIPYARD_IMAGES: "{{ MAKE_SHIPYARD_IMAGES | default('false') }}"
+        MAKE_PORTHOLE_IMAGES: "{{ MAKE_PORTHOLE_IMAGES | default('false') }}"
+        MAKE_PROMENADE_IMAGES: "{{ MAKE_PROMENADE_IMAGES | default('false') }}"
+        CLONE_ARMADA: "{{ CLONE_ARMADA | default('true') }}"
+        CLONE_DECKHAND: "{{ CLONE_DECKHAND | default('true') }}"
+        CLONE_SHIPYARD: "{{ CLONE_SHIPYARD | default('true') }}"
+        CLONE_PORTHOLE: "{{ CLONE_PORTHOLE | default('true') }}"
+        CLONE_PROMENADE: "{{ CLONE_PROMENADE | default('true') }}"
+        CLONE_MAAS: "{{ CLONE_MAAS | default('true') }}"
+        CLONE_OSH: "{{ CLONE_OSH | default('true') }}"
+        MAKE_ARMADA_IMAGES: "{{ MAKE_ARMADA_IMAGES | default('false') }}"
+        MAKE_DECKHAND_IMAGES: "{{ MAKE_DECKHAND_IMAGES | default('false') }}"
+        MAKE_SHIPYARD_IMAGES: "{{ MAKE_SHIPYARD_IMAGES | default('false') }}"
+        MAKE_DECKHAND_IMAGES: "{{ MAKE_DECKHAND_IMAGES | default('false') }}"
+        MAKE_PORTHOLE_IMAGES: "{{ MAKE_PORTHOLE_IMAGES | default('false') }}"
+        MAKE_PROMENADE_IMAGES: "{{ MAKE_PROMENADE_IMAGES | default('false') }}"
+      # NOTE(aostapenko) using bigger than async_status timeout due to async_status issue with
+      # not recognizing timed out jobs: https://github.com/ansible/ansible/issues/25637
+      async: 3600
+      poll: 0
+      register: async_results
+
+    - name: Wait for script set to finish
+      async_status:
+        jid: '{{ item.ansible_job_id }}'
+      register: jobs
+      until: jobs.finished
+      delay: 5
+      retries: 360
+      loop: "{{ async_results.results }}"
+
+  always:
+    - name: Print script set output
+      shell: |
+          # NOTE(aostapenko) safely retrieving items for the unlikely case if jobs timed out in async_status
+          echo 'STDOUT:\n{{ item.get("stdout") | regex_replace("\'", "") }}\nSTDERR:\n{{ item.get("stderr") | regex_replace("\'", "") }}'
+      loop: "{{ jobs.results }}"
+...
diff --git a/tools/gate/roles/airship-run-script/defaults/main.yaml b/tools/gate/roles/airship-run-script/defaults/main.yaml
new file mode 100644
index 00000000..725f4b23
--- /dev/null
+++ b/tools/gate/roles/airship-run-script/defaults/main.yaml
@@ -0,0 +1,47 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+ceph_osd_data_device: "/dev/loop0"
+kubeadm:
+  pod_network_cidr: "10.244.0.0/24"
+osh_params:
+  container_distro_name: ubuntu
+  container_distro_version: focal
+  # feature_gates:
+site: airskiff
+HELM_ARTIFACT_URL: https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz
+HTK_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
+OSH_INFRA_COMMIT: cfff60ec10a6c386f38db79bb9f59a552c2b032f
+OSH_COMMIT: 2d9457e34ca4200ed631466bd87569b0214c92e7
+COREDNS_VERSION: v1.11.1
+DISTRO: ubuntu_focal
+DOCKER_REGISTRY: quay.io
+MAKE_ARMADA_IMAGES: false
+MAKE_DECKHAND_IMAGES: false
+MAKE_SHIPYARD_IMAGES: false
+MAKE_PORTHOLE_IMAGES: false
+MAKE_PROMENADE_IMAGES: false
+CLONE_ARMADA: true
+CLONE_DECKHAND: true
+CLONE_SHIPYARD: true
+CLONE_PORTHOLE: true
+CLONE_PROMENADE: true
+CLONE_MAAS: true
+CLONE_OSH: true
+MAKE_ARMADA_IMAGES: false
+MAKE_DECKHAND_IMAGES: false
+MAKE_SHIPYARD_IMAGES: false
+MAKE_DECKHAND_IMAGES: false
+MAKE_PORTHOLE_IMAGES: false
+MAKE_PROMENADE_IMAGES: false
+...
diff --git a/tools/gate/roles/airship-run-script/tasks/main.yaml b/tools/gate/roles/airship-run-script/tasks/main.yaml
new file mode 100644
index 00000000..006106b3
--- /dev/null
+++ b/tools/gate/roles/airship-run-script/tasks/main.yaml
@@ -0,0 +1,61 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- name: "Run script {{ workload[0] }}"
+  shell: |
+    set -xe;
+    {{ gate_script_path }}
+  vars:
+    gate_script_path: "{{ workload[0] }}"
+  args:
+    chdir: "{{ zuul.project.src_dir }}/{{ gate_scripts_relative_path }}"
+  environment:
+    CEPH_OSD_DATA_DEVICE: "{{ ceph_osd_data_device }}"
+    POD_NETWORK_CIDR: "{{ kubeadm.pod_network_cidr }}"
+    zuul_site_mirror_fqdn: "{{ zuul_site_mirror_fqdn }}"
+    OSH_EXTRA_HELM_ARGS: "{{ zuul_osh_extra_helm_args_relative_path | default('') }}"
+    OSH_PATH: "{{ zuul_osh_relative_path | default('../openstack-helm/') }}"
+    OSH_INFRA_PATH: "{{ zuul_osh_infra_relative_path | default('../openstack-helm-infra/') }}"
+    OPENSTACK_RELEASE: "{{ osh_params.openstack_release | default('') }}"
+    CONTAINER_DISTRO_NAME: "{{ osh_params.container_distro_name | default('') }}"
+    CONTAINER_DISTRO_VERSION: "{{ osh_params.container_distro_version | default('') }}"
+    FEATURE_GATES: "{{ osh_params.feature_gates | default('') }}"
+    RUN_HELM_TESTS: "{{ run_helm_tests | default('yes') }}"
+    PL_SITE: "{{ site | default('airskiff') }}"
+    HELM_ARTIFACT_URL: "{{ HELM_ARTIFACT_URL | default('https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz') }}"
+    HTK_COMMIT: "{{ HTK_COMMIT | default('cfff60ec10a6c386f38db79bb9f59a552c2b032f') }}"
+    OSH_INFRA_COMMIT: "{{ OSH_INFRA_COMMIT | default('cfff60ec10a6c386f38db79bb9f59a552c2b032f') }}"
+    OSH_COMMIT: "{{ OSH_COMMIT | default('2d9457e34ca4200ed631466bd87569b0214c92e7') }}"
+    COREDNS_VERSION: "{{ coredns_version | default('v1.11.1') }}"
+    DISTRO: "{{ DISTRO | default('ubuntu_focal') }}"
+    DOCKER_REGISTRY: "{{ DOCKER_REGISTRY | default('quay.io') }}"
+    MAKE_ARMADA_IMAGES: "{{ MAKE_ARMADA_IMAGES | default('false') }}"
+    MAKE_DECKHAND_IMAGES: "{{ MAKE_DECKHAND_IMAGES | default('false') }}"
+    MAKE_SHIPYARD_IMAGES: "{{ MAKE_SHIPYARD_IMAGES | default('false') }}"
+    MAKE_PORTHOLE_IMAGES: "{{ MAKE_PORTHOLE_IMAGES | default('false') }}"
+    MAKE_PROMENADE_IMAGES: "{{ MAKE_PROMENADE_IMAGES | default('false') }}"
+    CLONE_ARMADA: "{{ CLONE_ARMADA | default('true') }}"
+    CLONE_DECKHAND: "{{ CLONE_DECKHAND | default('true') }}"
+    CLONE_SHIPYARD: "{{ CLONE_SHIPYARD | default('true') }}"
+    CLONE_PORTHOLE: "{{ CLONE_PORTHOLE | default('true') }}"
+    CLONE_PROMENADE: "{{ CLONE_PROMENADE | default('true') }}"
+    CLONE_MAAS: "{{ CLONE_MAAS | default('true') }}"
+    CLONE_OSH: "{{ CLONE_OSH | default('true') }}"
+    MAKE_ARMADA_IMAGES: "{{ MAKE_ARMADA_IMAGES | default('false') }}"
+    MAKE_DECKHAND_IMAGES: "{{ MAKE_DECKHAND_IMAGES | default('false') }}"
+    MAKE_SHIPYARD_IMAGES: "{{ MAKE_SHIPYARD_IMAGES | default('false') }}"
+    MAKE_DECKHAND_IMAGES: "{{ MAKE_DECKHAND_IMAGES | default('false') }}"
+    MAKE_PORTHOLE_IMAGES: "{{ MAKE_PORTHOLE_IMAGES | default('false') }}"
+    MAKE_PROMENADE_IMAGES: "{{ MAKE_PROMENADE_IMAGES | default('false') }}"
+
+...