Feat: Add Job template to deploy ODL on K8S Magnum 50/99150/8
authorAnil Belur <abelur@linuxfoundation.org>
Fri, 24 Dec 2021 04:47:46 +0000 (14:47 +1000)
committerAnil Belur <abelur@linuxfoundation.org>
Tue, 4 Jan 2022 12:49:38 +0000 (22:49 +1000)
The template allows users to create a K8S cluster on Openstack Magnum
and deploy ODL SDNC on the cluster. Once deployed the Jenkins node
verifies the deployment by listing the restconf modules.

The JJB templates uses pre-existing K8s cluster templates provided
by the cloud provider. (v1.16.0)

The job templates are created in generic manner such that users can
pass a script to test the SDNC setup from the project definition.

The cluster is configured on a private network using internal IP's
and the Jenkins executor node IP is added to the network to allow
kubectl commands to be run directly the Jenkins instance.

Issue-ID: https://jira.linuxfoundation.org/browse/RELENG-3644
Change-Id: Ie17340da5677bb26b0cb0f673b90018b7033fa60
Signed-off-by: Anil Belur <abelur@linuxfoundation.org>
jjb/packaging/openstack-k8s-cluster-delete.sh [new file with mode: 0644]
jjb/packaging/openstack-k8s-config-export.sh [new file with mode: 0644]
jjb/packaging/openstack-k8s-create-with-template.sh [new file with mode: 0644]
jjb/packaging/openstack-k8s-deploy-helm.sh [new file with mode: 0644]
jjb/packaging/openstack-k8s-template.yaml [new file with mode: 0644]
jjb/packaging/openstack-k8s.yaml [new file with mode: 0644]

diff --git a/jjb/packaging/openstack-k8s-cluster-delete.sh b/jjb/packaging/openstack-k8s-cluster-delete.sh
new file mode 100644 (file)
index 0000000..7550ded
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2021 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# shellcheck disable=SC2153,SC2034
+echo "---> Delete K8S cluster"
+
+set -eux -o pipefail
+# shellcheck disable=SC1090
+source ~/lf-env.sh
+
+os_cloud="${OS_CLOUD:-vex}"
+cluster_name="${CLUSTER_NAME}"
+
+cluster_delete_status="$(openstack --os-cloud "$OS_CLOUD" coe cluster delete "${CLUSTER_NAME}")"
+if [[ -z "$cluster_delete_status" ]]; then
+    echo "ERROR: Failed to delete coe cluster ${cluster_name}"
+    exit 1
+elif [[ "${cluster_delete_status}" =~ .*accepted.* ]]; then
+    echo "Cluster ${CLUSTER_NAME} delete in progress ..."
+    echo "${cluster_delete_status}"
+fi
diff --git a/jjb/packaging/openstack-k8s-config-export.sh b/jjb/packaging/openstack-k8s-config-export.sh
new file mode 100644 (file)
index 0000000..883df00
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2021 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# shellcheck disable=SC2153,SC2034
+echo "---> Export K8S cluster config and view nodes"
+set -eux -o pipefail
+
+# shellcheck disable=SC1090
+source ~/lf-env.sh
+
+OS_TIMEOUT=5             # Wait time in minutes for OpenStack cluster nodes to come up.
+CLUSTER_NODE_RETRIES=15  # Number of times to retry waiting for a cluster nodes.
+CLUSTER_NODE_SUCCESSFUL=false
+
+os_cloud="${OS_CLOUD:-vex}"
+cluster_name="${CLUSTER_NAME}"
+node_count="${NODE_COUNT:-2}"
+
+echo "INFO: Wait for the ${CLUSTER_NODE_RETRIES} nodes to come up ...."
+for try in $(seq $CLUSTER_NODE_RETRIES); do
+    sleep 30
+    mapfile -t OS_NODES < <(openstack --os-cloud "$os_cloud" server list -f value -c "Name" | grep -E ".*k8s.*")
+    if (( ${#OS_NODES[@]} == $((node_count+1)) )); then
+        break
+    fi
+done
+
+echo "INFO: Wait until K8S Cluster nodes are active."
+for node in "${OS_NODES[@]}"; do
+    echo "node: $node"
+    # Get the main node name
+    if [[ "$node" =~ .*k8s.*master.* ]]; then
+        MAIN_NODE="${node}"
+    elif [[ "$node" =~ .*k8s.*node.* ]]; then
+        K8S_NODE="${node}"
+    else
+        echo "ERROR: K8S nodes not online."
+        exit 1
+    fi
+done
+
+# Get Internal IP of master and update ${KUBECONFIG}
+if [[ -n "${MAIN_NODE}" ]]; then
+    # Add a network for allowing Jenkins node to connect with the K8S nodes
+    JOB_SUM=$(echo "$JOB_NAME" | sum | awk '{ print $1 }')
+    VM_NAME="$JOB_NAME-$BUILD_NUMBER"
+    SERVER_ID="$(openstack --os-cloud vex server show -f value -c id "$(hostname -s)")"
+    NETWORK_ID="$(openstack --os-cloud vex network show -f value -c id "$SILO-$VM_NAME")"
+    openstack --os-cloud vex server add network "$SERVER_ID" "$NETWORK_ID"
+
+    FACTER_OS=$(/usr/bin/facter operatingsystem | tr '[:upper:]' '[:lower:]')
+    FACTER_OSVER=$(/usr/bin/facter operatingsystemrelease)
+    if [ "$FACTER_OS" == "centos" ]; then
+        ETH1_MAC=$(ip address show eth1 | grep ether | awk -F' ' '{print $2}')
+        ETH1_SCRIPT="/etc/sysconfig/network-scripts/ifcfg-eth1"
+        sudo cp /etc/sysconfig/network-scripts/ifcfg-eth0 "$ETH1_SCRIPT"
+        sudo sed -i "s/eth0/eth1/; s/^HWADDR=.*/HWADDR=$ETH1_MAC/" "$ETH1_SCRIPT"
+        sudo echo 'PEERDNS=no' | sudo tee -a "$ETH1_SCRIPT"
+        sudo echo 'DEFROUTE=no' | sudo tee -a "$ETH1_SCRIPT"
+        cat "$ETH1_SCRIPT"
+        sudo ifup eth1
+
+    elif [ "$FACTER_OS" == "ubuntu" ]; then
+        case "$FACTER_OSVER" in
+            18.04)
+                ENS3_MAC=$(ip address show ens3 | grep ether | awk -F' ' '{print $2}')
+                ENS7_MAC=$(ip address show ens7 | grep ether | awk -F' ' '{print $2}')
+                ENS3_SCRIPT="/etc/netplan/50-cloud-init.yaml"
+                ENS7_SCRIPT="/etc/netplan/51-cloud-init.yaml"
+                sudo cp "$ENS3_SCRIPT" "$ENS7_SCRIPT"
+                sudo sed -i "s/ens3/ens7/; s/macaddress: $ENS3_MAC/macaddress: $ENS7_MAC/" "$ENS7_SCRIPT"
+                sudo sed -i "s/dhcp: true/d" "$ENS7_SCRIPT"
+                cat "$ENS7_SCRIPT"
+                sudo netplan apply
+            ;;
+            *)
+                echo "---> Unknown Ubuntu version $FACTER_OSVER"
+                exit 1
+            ;;
+        esac
+    else
+        echo "---> Unknown OS $FACTER_OS"
+        exit 1
+    fi
+
+    # print network interfaces
+    ip address show
+
+    # Get internal IP of main node
+    MAIN_IP=$(openstack --os-cloud "${os_cloud}" server list -f value -c Networks -c Name --name "${SILO}-.*k8s.*-master" | awk -F"'" '{print $4}')
+
+    # Get internal IP of worker node in the cluster
+    mapfile -t NODE_IPS < <(openstack --os-cloud "${os_cloud}" server list -f value -c Networks -c Name --name "${SILO}-.*k8s.*-node" | awk -F"'" '{print $4}')
+    if (( ${#NODE_IPS[@]} != $((node_count)) )); then
+        echo "ERROR: Cluster nodes disappered."
+        exit 1
+    fi
+
+    echo "INFO: Testing Connectivity between the main and Jenkins minon"
+    ping -c3 "$MAIN_IP"
+    echo "INFO: Testing Connectivity between the nodes and Jenkins minon"
+    for nip in "${NODE_IPS[@]}"; do
+        if [[ -n "${nip}" ]]; then
+            echo "Ping Node IP Address: $nip"
+            ping -c3 "${nip}"
+        fi
+    done
+else
+    echo "ERROR: Main node did not come up."
+    exit 1
+fi
+
+# Export cluster config.
+openstack --os-cloud "$os_cloud" coe cluster config "${cluster_name}"
+KUBECONFIG="${WORKSPACE}/config"
+export KUBECONFIG
+
+# Update main node IP in KUBECONFIG
+if [[ -n ${MAIN_IP} ]]; then
+    sed -i "s#server:.*#server: https://${MAIN_IP}:6443#" "$KUBECONFIG"
+    cat "${KUBECONFIG}"
+fi
+
+# Print helm and kubectl version
+echo "INFO: helm version:"
+helm3.7 version
+echo "INFO: kubectl version:"
+kubectl version
diff --git a/jjb/packaging/openstack-k8s-create-with-template.sh b/jjb/packaging/openstack-k8s-create-with-template.sh
new file mode 100644 (file)
index 0000000..b066750
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2021 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# shellcheck disable=SC2153,SC2034
+echo "---> Create K8S cluster with pre-existing template"
+
+set -eux -o pipefail
+# shellcheck disable=SC1090
+source ~/lf-env.sh
+lf-activate-venv python-openstackclient python-magnumclient
+
+OS_TIMEOUT=12       # Wait time in minutes for OpenStack cluster to come up.
+CLUSTER_RETRIES=3   # Number of times to retry creating a cluster.
+CLUSTER_SUCCESSFUL=false
+
+mkdir -p "$WORKSPACE/archives"
+
+boot_volume_size="${BOOT_VOLUME_SIZE}"
+cluster_name="${CLUSTER_NAME}"
+cluster_settle_time="${CLUSTER_SETTLE_TIME:-1m}"
+cluster_template_name="${CLUSTER_TEMPLATE_NAME}"
+cloud_provider_tag="${CLOUD_PROVIDER_TAG}"
+container_infra_prefix="${CONTAINER_INFRA_PREFIX}"
+etcd_volume_size="${ETCD_VOLUME_SIZE}"
+k8s_version="${K8S_VERSION}"
+keypair="${KEYPAIR}"
+kube_tag="${KUBE_TAG}"
+helm_client_url="${HELM_CLIENT_URL}"
+helm_sha256="${HELM_SHA256}"
+helm_version="${HELM_VERSION}"
+master_count="${MASTER_COUNT:-1}"
+master_flavor="${MASTER_FLAVOR}"
+master_lb_floating_ip_enabled="${MASTER_LB_FLOATING_IP_ENABLED:-false}"
+node_count="${NODE_COUNT:-2}"
+node_flavor="${NODE_FLAVOR}"
+os_cloud="${OS_CLOUD:-vex}"
+
+echo "INFO: Create a Cluster:${CLUSTER_NAME} for attempts:${CLUSTER_RETRIES}."
+for try in $(seq $CLUSTER_RETRIES); do
+    # shellcheck disable=SC1083
+
+    # Create the cluster using pre-defined template. Returns the status which includes the $cluster_uuid
+    cluster_status=$(openstack --os-cloud "${os_cloud}" coe cluster create "${cluster_name}" \
+        --cluster-template "${cluster_template_name}" \
+        --keypair "${keypair}" \
+        --master-count "${master_count}" \
+        --node-count "${node_count}" \
+        --master-flavor "${master_flavor}" \
+        --flavor "${node_flavor}" \
+        --labels \
+boot_volume_size="${boot_volume_size}",\
+container_infra_prefix="${container_infra_prefix}",\
+cloud_provider_tag="${cloud_provider_tag}",\
+helm_client_sha256="${helm_sha256}",\
+helm_client_tag="${helm_version}",\
+etcd_volume_size="${etcd_volume_size}",\
+kube_tag="${kube_tag}",\
+master_lb_floating_ip_enabled=false,\
+helm_client_url="${helm_client_url}" \
+        --floating-ip-disabled)
+
+    # Check return status and extract the $cluster_uuid from return status
+    if [[ -z "$cluster_status" ]]; then
+        echo "ERROR: Failed to create coe cluster ${cluster_name}"
+        exit 1
+    elif [[ "${cluster_status}" =~ .*accepted.* ]]; then
+        cluster_uuid=$(echo "${cluster_status}" | awk -F' ' '{print $5}')
+    fi
+
+    echo "INFO $try: Wait until ${OS_TIMEOUT} (in minutes) to rollout ${cluster_name}."
+    for i in $(seq $OS_TIMEOUT); do
+        sleep 60
+        CLUSTER_STATUS=$(openstack --os-cloud "$os_cloud" coe cluster show "$cluster_uuid" -c status -f value)
+        echo "$i: ${CLUSTER_STATUS}"
+
+        case "${CLUSTER_STATUS}" in
+            CREATE_COMPLETE)
+                echo "INFO: Cluster ${cluster_name} initialized on infrastructure successful."
+                CLUSTER_SUCCESSFUL=true
+                break
+            ;;
+            CREATE_FAILED)
+                reason=$(openstack coe cluster show "${cluster_name}" -f value -c health_status_reason)
+                echo "ERROR: Failed to initialize infrastructure. Reason: ${reason}"
+                openstack ceo cluster show "${cluster_name}"
+
+                echo "INFO: Deleting cluster and re-try to create the cluster again ..."
+                openstack coe cluster delete "${cluster_name}"
+
+                # Post delete, poll for 5m to learn if cluster is fully removed
+                for j in $(seq 20); do
+                    sleep 30
+                    delete_status=$(openstack coe cluster show "${cluster_name}" -f value -c status)
+                    echo "$j: ${delete_status}"
+                    if [[ ${delete_status} == "DELETE_FAILED" ]]; then
+                        reason=$(openstack coe cluster show "${cluster_name}" -f value -c health_status_reason)
+                        echo "ERROR: Failed to delete ${cluster_name}. Reason: ${reason}"
+
+                        echo "INFO: Deleting failed cluster again: ${cluster_name}"
+                        openstack coe cluster delete "${cluster_name}"
+                    fi
+
+                    if ! openstack coe cluster show "${cluster_name}" -f value -c status; then
+                        echo "INFO: Cluster show on ${cluster_name} came back empty. Assuming successful delete"
+                        break
+                    fi
+                done
+
+                # If we still see $CLUSTER_NAME in `openstack coe cluster show` this infers the delete hasn't fully
+                # worked and we can exit forcefully
+                if openstack coe cluster show "${cluster_name}" -f value -c stack_status; then
+                    echo "ERROR: Cluster ${cluster_name} still in cloud output after polling. Quitting!"
+                    exit 1
+                fi
+                break
+            ;;
+            CREATE_IN_PROGRESS)
+                echo "INFO: Waiting to initialize cluster infrastructure ..."
+                continue
+            ;;
+            *)
+                echo "ERROR: Unexpected status: ${OS_STATUS}"
+                # DO NOT exit on unexpected status. Openstack cluster sometimes returns unexpected status
+                # before returning an expected status. Just print the message and loop until we have
+                # a confirmed state or timeout.
+                # exit 1
+            ;;
+        esac
+    done
+    if $CLUSTER_SUCCESSFUL; then
+        break
+    fi
+done
diff --git a/jjb/packaging/openstack-k8s-deploy-helm.sh b/jjb/packaging/openstack-k8s-deploy-helm.sh
new file mode 100644 (file)
index 0000000..d418168
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/bash -l
+# SPDX-License-Identifier: EPL-1.0
+##############################################################################
+# Copyright (c) 2021 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+# shellcheck disable=SC2153,SC2034
+echo "---> Deploy Opendaylight Helm charts on K8S cluster and verify deployment"
+set -eux -o pipefail
+
+set -x
+
+# shellcheck disable=SC1090
+source ~/lf-env.sh
+
+K8S_DEPLOY_LOG="$WORKSPACE/archives/k8s-kubectl-file.log"
+mkdir -p "$WORKSPACE/archives"
+
+KUBECONFIG="${WORKSPACE}/config"
+export KUBECONFIG
+
+# Deploy helm charts after dry run.
+cd "$WORKSPACE/helm"
+echo "INFO: ODL Helm Charts install --dry-run"
+helm3.7 install sdnc opendaylight --dry-run
+echo "INFO: ODL Helm Charts install"
+helm3.7 install sdnc opendaylight
+
+POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=opendaylight,app.kubernetes.io/instance=sdnc" -o jsonpath="{.items[0].metadata.name}")
+CONTAINER_PORT=$(kubectl get pod --namespace default "$POD_NAME" -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+echo "Visit http://127.0.0.1:8080 to use your application"
+
+export POD_NAME
+export CONTAINER_PORT
+
+# wait for the pod to become ready
+for i in $(seq 10); do
+    sleep 50
+    # Verify K8S pods are running state before starting port forwarding
+    echo "DEBUG: Verify ${KUBECONFIG} is valid and nodes are accessable through kubectl:"
+    kubectl describe nodes | tee -a "${K8S_DEPLOY_LOG}"
+    kubectl get po -A -o wide | tee -a "${K8S_DEPLOY_LOG}"
+    # kubectl get events --sort-by='.metadata.creationTimestamp'
+    kubectl get nodes --show-labels
+
+    pod_status=$(kubectl get pods -n default -o jsonpath="{.items[0].status.phase}")
+    if [[ "$pod_status" =~ .*Running.* ]]; then
+        echo "INFO: SNDC runing on the pod"
+        kubectl --namespace default port-forward "$POD_NAME" 8080:"$CONTAINER_PORT" &
+        sleep 30
+        break
+    elif [[ "$pod_status" =~ .*Pending.* ]]; then
+        echo "INFO: SNDC pod status: ${pod_status}, creation in progress ..."
+        continue
+    else
+        echo "ERROR: Error in deploying pod"
+        kubectl describe pods | tee -a "${K8S_DEPLOY_LOG}"
+    fi
+    kubectl get pods -n default -o wide
+done
+
+# Test SDNC setup by listing restconf modules
+SDNC_URL="http://127.0.0.1:8080/restconf/modules"
+resp=$(curl -u admin:admin -w "\\n\\n%{http_code}" --globoff -H "Content-Type:application/json" "$SDNC_URL")
+json_data=$(echo "$resp" | head -n1)
+status=$(echo "$resp" | awk 'END {print $NF}')
+
+if [ "$status" != 200 ]; then
+    >&2 echo "ERROR: Failed to fetch data from $SDNC_URL with status code $status"
+    >&2 echo "$resp"
+    exit 1
+else
+    echo "INFO: Successfully deploy Opendaylight SND on K8S pod:"
+    echo "${json_data}" | jq
+fi
diff --git a/jjb/packaging/openstack-k8s-template.yaml b/jjb/packaging/openstack-k8s-template.yaml
new file mode 100644 (file)
index 0000000..21e94e0
--- /dev/null
@@ -0,0 +1,274 @@
+---
+- parameter:
+    name: lf-k8s-params
+    parameters:
+      - string:
+          name: BOOT_VOLUME_SIZE
+          default: "{boot-volume-size}"
+      - string:
+          name: CLUSTER_SETTLE_TIME
+          default: "{cluster-settle-time}"
+      - string:
+          name: CLUSTER_NAME
+          default: "$SILO-$JOB_NAME-$BUILD_NUMBER"
+      - string:
+          name: CLUSTER_TEMPLATE_NAME
+          default: "{cluster-template-name}"
+      - string:
+          name: DOCKER_VOLUME_SIZE
+          default: "{docker-volume-size}"
+      - string:
+          name: KEYPAIR
+          default: "$SILO"
+      - string:
+          name: K8S_VERSION
+          default: "{k8s-version}"
+      - string:
+          name: MASTER_COUNT
+          default: "{master-count}"
+      - string:
+          name: MASTER_FLAVOR
+          default: "{master-flavor}"
+      - string:
+          name: NODE_COUNT
+          default: "{node-count}"
+      - string:
+          name: NODE_FLAVOR
+          default: "{node-flavor}"
+      - string:
+          name: OS_CLOUD
+          default: "{openstack-cloud}"
+      - string:
+          name: HELM_VERSION
+          default: "{helm-version}"
+      - string:
+          name: HELM_SHA256
+          default: "{helm-sha256}"
+      - string:
+          name: HELM_CLIENT_URL
+          default: "{helm-client-url}"
+      - string:
+          name: CLOUD_PROVIDER_TAG
+          default: "{cloud-provider-tag}"
+      - string:
+          name: CONTAINER_INFRA_PREFIX
+          default: "{container-infra-prefix}"
+      - string:
+          name: ETCD_VOLUME_SIZE
+          default: "{etcd-volume-size}"
+      - string:
+          name: KUBE_TAG
+          default: "{kube-tag}"
+      - string:
+          name: MASTER_LB_FLOATING_IP_ENABLED
+          default: "{master-lb-floating-ip-enabled}"
+
+- builder:
+    name: lf-k8s-cluster-create-with-template
+    builders:
+      - inject:
+          properties-content: |
+            BOOT_VOLUME_SIZE={boot-volume-size}
+            CLOUD_PROVIDER_TAG={cloud-provider-tag}
+            CLUSTER_NAME={cluster-name}
+            CLUSTER_SETTLE_TIME={cluster-settle-time}
+            CLUSTER_TEMPLATE_NAME={cluster-template-name}
+            CONTAINER_INFRA_PREFIX={container-infra-prefix}
+            ETCD_VOLUME_SIZE={etcd-volume-size}
+            HELM_VERSION={helm-version}
+            HELM_SHA256={helm-sha256}
+            HELM_CLIENT_URL={helm-client-url}
+            K8S_VERSION={k8s-version}
+            KEYPAIR={keypair}
+            KUBE_TAG={kube-tag}
+            MASTER_COUNT={master-count}
+            MASTER_FLAVOR={master-flavor}
+            MASTER_LB_FLOATING_IP_ENABLED={master-lb-floating-ip-enabled}
+            NODE_COUNT={node-count}
+            NODE_FLAVOR={node-flavor}
+            OS_CLOUD={openstack-cloud}
+      - config-file-provider:
+          files:
+            - file-id: clouds-yaml
+              target: "$HOME/.config/openstack/clouds.yaml"
+      - shell: !include-raw-escape: openstack-k8s-create-with-template.sh
+      - shell: !include-raw-escape: openstack-k8s-config-export.sh
+
+- builder:
+    name: lf-k8s-cluster-deploy
+    builders:
+      - shell: "{obj:deploy_script}"
+
+- publisher:
+    name: lf-k8s-cluster-delete
+    publishers:
+      - postbuildscript:
+          builders:
+            - role: BOTH
+              build-on:
+                - ABORTED
+                - FAILURE
+                - SUCCESS
+                - UNSTABLE
+              build-steps:
+                - inject:
+                    properties-content: |
+                      CLUSTER_NAME={cluster-name}
+                      OS_CLOUD={openstack-cloud}
+                - config-file-provider:
+                    files:
+                      - file-id: clouds-yaml
+                        target: "$HOME/.config/openstack/clouds.yaml"
+                - shell: !include-raw-escape: openstack-k8s-cluster-delete.sh
+          mark-unstable-if-failed: false
+
+- trigger:
+    name: gerrit-trigger-patch-submitted-k8s-deploy
+    triggers:
+      - gerrit:
+          server-name: "{gerrit-server-name}"
+          trigger-on:
+            - patchset-created-event:
+                exclude-drafts: true
+                exclude-trivial-rebase: false
+                exclude-no-code-change: false
+            - draft-published-event
+            - comment-added-contains-event:
+                comment-contains-value: '^Patch Set[ ]+[0-9]+:([ ]+|[\n]+)(recheck|reverify)$'
+          projects:
+            - project-compare-type: ANT
+              project-pattern: "{project}"
+              branches:
+                - branch-compare-type: ANT
+                  branch-pattern: "**/{branch}"
+              file-paths:
+                - compare-type: ANT
+                  pattern: "{files}"
+              forbidden-file-paths:
+                - compare-type: ANT
+                  pattern: "{forbidden-files}"
+
+- job-template:
+    name: "{project-name}-k8s-odl-deploy-test"
+
+    #####################
+    # Default variables #
+    #####################
+
+    deploy_script: ""
+    boot-volume-size: { boot-volume-size }
+    cluster-settle-time: { cluster-settle-time }
+    cluster-name: "$SILO-$JOB_NAME-$BUILD_NUMBER"
+    cloud-provider-tag: "{cloud-provider-tag}"
+    container-infra-prefix: "{container-infra-prefix}"
+    etcd-volume-size: "{etcd-volume-size}"
+    docker-volume-size: { docker-volume-size }
+    helm-client-url: "{helm-client-url}"
+    helm-sha256: "{helm-sha256}"
+    helm-version: "{helm-version}"
+    keypair: { keypair }
+    k8s-version: { k8s-version }
+    kube-tag: "{kube-tag}"
+    master-count: { master-count }
+    master-flavor: { master-flavor }
+    master-lb-floating-ip-enabled: "{master-lb-floating-ip-enabled}"
+    node-count: { node-count }
+    node-flavor: { node-flavor }
+    openstack-cloud: { openstack-cloud }
+
+    mvn-version: mvn35
+    disable-job: false
+
+    #####################
+    # Job Configuration #
+    #####################
+
+    project-type: freestyle
+    node: "{build-node}"
+
+    properties:
+      - lf-infra-properties:
+          build-days-to-keep: "{build-days-to-keep}"
+
+    parameters:
+      - lf-k8s-params:
+          boot-volume-size: "{boot-volume-size}"
+          cloud-provider-tag: "{cloud-provider-tag}"
+          container-infra-prefix: "{container-infra-prefix}"
+          cluster-settle-time: "{cluster-settle-time}"
+          cluster-template-name: "{cluster-template-name}"
+          cluster-name: "{cluster-name}"
+          docker-volume-size: "{docker-volume-size}"
+          etcd-volume-size: "{etcd-volume-size}"
+          helm-version: "{helm-version}"
+          helm-sha256: "{helm-sha256}"
+          helm-client-url: "{helm-client-url}"
+          keypair: "{keypair}"
+          k8s-version: "{k8s-version}"
+          kube-tag: "{kube-tag}"
+          master-count: "{master-count}"
+          master-flavor: "{master-flavor}"
+          master-lb-floating-ip-enabled: "{master-lb-floating-ip-enabled}"
+          node-count: "{node-count}"
+          node-flavor: "{node-flavor}"
+          openstack-cloud: "{openstack-cloud}"
+      - opendaylight-infra-parameters:
+          os-cloud: "{os-cloud}"
+          project: "{project}"
+          branch: "{branch}"
+          refspec: "refs/heads/{branch}"
+          artifacts: "{archive-artifacts}"
+
+    scm:
+      - gerrit-trigger-scm:
+          refspec: "$GERRIT_REFSPEC"
+          choosing-strategy: "default"
+          submodule-recursive: "false"
+
+    triggers:
+      - timed: "@weekly"
+      - gerrit-trigger-patch-submitted-k8s-deploy:
+          gerrit-server-name: "{gerrit-server-name}"
+          project: "{project}"
+          branch: "{branch}"
+          files: "helm/**"
+          forbidden-files: ""
+
+    builders:
+      - lf-infra-pre-build
+      - lf-k8s-cluster-create-with-template:
+          boot-volume-size: "{boot-volume-size}"
+          cloud-provider-tag: "{cloud-provider-tag}"
+          container-infra-prefix: "{container-infra-prefix}"
+          cluster-settle-time: "{cluster-settle-time}"
+          cluster-template-name: "{cluster-template-name}"
+          cluster-name: "{cluster-name}"
+          docker-volume-size: "{docker-volume-size}"
+          etcd-volume-size: "{etcd-volume-size}"
+          helm-version: "{helm-version}"
+          helm-sha256: "{helm-sha256}"
+          helm-client-url: "{helm-client-url}"
+          k8s-version: "{k8s-version}"
+          keypair: "{keypair}"
+          kube-tag: "{kube-tag}"
+          master-count: "{master-count}"
+          master-flavor: "{master-flavor}"
+          master-lb-floating-ip-enabled: "{master-lb-floating-ip-enabled}"
+          node-count: "{node-count}"
+          node-flavor: "{node-flavor}"
+          openstack-cloud: "{openstack-cloud}"
+      - lf-k8s-cluster-deploy:
+          deploy_script: "{openstack-k8s-deploy-script}"
+
+    wrappers:
+      - opendaylight-infra-wrappers:
+          build-timeout: "360"
+      - lf-infra-wrappers:
+          build-timeout: "{build-timeout}"
+          jenkins-ssh-credential: "{jenkins-ssh-credential}"
+
+    publishers:
+      - lf-k8s-cluster-delete:
+          cluster-name: "{cluster-name}"
+          openstack-cloud: "{openstack-cloud}"
+      - lf-infra-publish
diff --git a/jjb/packaging/openstack-k8s.yaml b/jjb/packaging/openstack-k8s.yaml
new file mode 100644 (file)
index 0000000..9f48c79
--- /dev/null
@@ -0,0 +1,26 @@
+---
+- project:
+    name: packaging-k8s
+    project: integration/packaging
+    project-name: packaging
+    container-infra-prefix: "registry.public.yul1.vexxhost.net/magnum/"
+    cloud-provider-tag: "v1.18.0"
+    etcd-volume-size: "20"
+    build-node: centos7-helm-4c-4g
+    boot-volume-size: 40
+    cluster-settle-time: 1m
+    cluster-template-name: "k8s-1.21.1"
+    helm-client-url: "https://get.helm.sh/helm-v3.7.1-linux-amd64.tar.gz"
+    helm-sha256: "6cd6cad4b97e10c33c978ff3ac97bb42b68f79766f1d2284cfd62ec04cd177f4"
+    helm-version: "v3.7.1"
+    k8s-version: v1.16.0
+    kube-tag: "v1.21.1"
+    master-count: 1
+    master-flavor: v3-standard-8
+    node-count: 2
+    node-flavor: v3-standard-8
+    openstack-cloud: vex
+    master-lb-floating-ip-enabled: "false"
+    openstack-k8s-deploy-script: "!include-raw-escape: openstack-k8s-deploy-helm.sh"
+    jobs:
+      - "{project-name}-k8s-odl-deploy-test"