You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by mb...@apache.org on 2022/11/30 11:59:06 UTC

[flink-kubernetes-operator] branch main updated: [FLINK-30199] Script for running Kubernetes Operator e2e tests manually

This is an automated email from the ASF dual-hosted git repository.

mbalassi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-kubernetes-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new f033976f [FLINK-30199] Script for running Kubernetes Operator e2e tests manually
f033976f is described below

commit f033976f2f225e8b5b869b0e523624230a2540eb
Author: pvary <pe...@gmail.com>
AuthorDate: Wed Nov 30 12:59:01 2022 +0100

    [FLINK-30199] Script for running Kubernetes Operator e2e tests manually
    
    Co-authored-by: Peter Vary <pe...@apple.com>
---
 .github/workflows/ci.yml               |  63 +-------
 docs/content/docs/development/guide.md |  33 +++++
 e2e-tests/run_tests.sh                 | 253 +++++++++++++++++++++++++++++++++
 e2e-tests/utils.sh                     |  81 ++++++++++-
 4 files changed, 371 insertions(+), 59 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c48b631c..7d5fd0b6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,9 +59,8 @@ jobs:
           start_minikube
       - name: Install cert-manager
         run: |
-          kubectl get pods -A
-          kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.2/cert-manager.yaml
-          kubectl -n cert-manager wait --all=true --for=condition=Available --timeout=300s deploy
+          source e2e-tests/utils.sh
+          install_cert_manager
       - name: Build image
         run: |
           export SHELL=/bin/bash
@@ -95,29 +94,8 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        version: ["v1_16","v1_15","v1_14","v1_13"]
-        namespace: ["default","flink"]
-        mode: ["native", "standalone"]
-        test:
-          - test_application_kubernetes_ha.sh
-          - test_application_operations.sh
-          - test_sessionjob_kubernetes_ha.sh
-          - test_sessionjob_operations.sh
-          - test_multi_sessionjob.sh
-        include:
-          - namespace: flink
-            extraArgs: '--create-namespace --set "watchNamespaces={default,flink}"'
-          - version: v1_16
-            image: flink:1.16
-          - version: v1_15
-            image: flink:1.15
-          - version: v1_14
-            image: flink:1.14
-          - version: v1_13
-            image: flink:1.13
-        exclude:
-          - namespace: default
-            test: test_multi_sessionjob.sh
+        version: [ "v1_16","v1_15","v1_14","v1_13" ]
+        namespace: [ "default","flink" ]
     name: e2e_ci
     steps:
       - uses: actions/checkout@v2
@@ -133,39 +111,10 @@ jobs:
           key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
           restore-keys: |
             ${{ runner.os }}-maven-
-      - name: Start minikube
+      - name: Run the tests
         run: |
           source e2e-tests/utils.sh
-          start_minikube
-      - name: Install cert-manager
-        run: |
-          kubectl get pods -A
-          kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.2/cert-manager.yaml
-          kubectl -n cert-manager wait --all=true --for=condition=Available --timeout=300s deploy
-      - name: Build image
-        run: |
-          export SHELL=/bin/bash
-          export DOCKER_BUILDKIT=1
-          eval $(minikube -p minikube docker-env)
-          docker build --progress=plain --no-cache -f ./Dockerfile -t flink-kubernetes-operator:ci-latest --progress plain .
-          docker images
-      - name: Start the operator
-        run: |
-          helm --debug install flink-kubernetes-operator -n ${{ matrix.namespace }} helm/flink-kubernetes-operator --set image.repository=flink-kubernetes-operator --set image.tag=ci-latest ${{ matrix.extraArgs }}
-          kubectl wait --for=condition=Available --timeout=120s -n ${{ matrix.namespace }} deploy/flink-kubernetes-operator
-          kubectl get pods
-      - name: Run Flink e2e tests
-        run: |
-          sed -i "s/image: flink:.*/image: ${{ matrix.image }}/" e2e-tests/data/*.yaml
-          sed -i "s/flinkVersion: .*/flinkVersion: ${{ matrix.version }}/" e2e-tests/data/*.yaml
-          sed -i "s/mode: .*/mode: ${{ matrix.mode }}/" e2e-tests/data/*.yaml
-          git diff HEAD
-          echo "Running e2e-tests/$test"
-          bash e2e-tests/${{ matrix.test }} || exit 1
-          git reset --hard
-      - name: Stop the operator
-        run: |
-          helm uninstall -n ${{ matrix.namespace }} flink-kubernetes-operator
+          bash e2e-tests/run_tests.sh -f ${{ matrix.version }} -n ${{ matrix.namespace }} -m native,standalone -d test_multi_sessionjob.sh test_application_operations.sh test_application_kubernetes_ha.sh test_sessionjob_kubernetes_ha.sh test_sessionjob_operations.sh || exit 1
       - name: Stop minikube
         run: |
           source e2e-tests/utils.sh
diff --git a/docs/content/docs/development/guide.md b/docs/content/docs/development/guide.md
index 402a5f71..d786aeb6 100644
--- a/docs/content/docs/development/guide.md
+++ b/docs/content/docs/development/guide.md
@@ -82,6 +82,28 @@ To uninstall you can simply call:
 helm uninstall flink-kubernetes-operator
 ```
 
+### Installing the operator locally using the e2e test scripts
+
+Alternatively you can skip [Building docker images](#building-docker-images) and
+[Installing the operator locally](#installing-the-operator-locally) altogether and with the
+use of the e2e test scripts you can install the Flink Kubernetes Operator from the local codebase.
+
+You still need to install [Docker Desktop](https://www.docker.com/products/docker-desktop),
+[minikube](https://minikube.sigs.k8s.io/docs/start/) and [helm](https://helm.sh/docs/intro/quickstart/) locally.
+
+The e2e test scripts automate the following steps:
+- Starting minikube (if needed)
+- Installing the Certification Manager (overwriting the existing one if already installed)
+- Compiling the Flink Kubernetes Operator binary from the local codebase
+- Building the Flink Kubernetes Operator Docker image using the previously compiled binary
+- Installing the freshly created Kubernetes Operator to the specified namespace
+- Run a single test to check if the operator is working as expected
+
+It could be done simplz by calling the following script:
+```bash
+./e2e-tests/run_tests.sh -k
+```
+
 ### Running the operator from the IDE
 
 You can run or debug the `FlinkOperator` from your preferred IDE. The operator itself is accessing the deployed Flink clusters through the REST interface. When running locally the `rest.port`, `rest.address` and `kubernetes.rest-service.exposed.type` Flink configuration parameters must be modified.
@@ -152,3 +174,14 @@ Considering the cost of running the builds, the stability, and the maintainabili
 All the unit tests, integration tests, and the end-to-end tests will be triggered for each PR.
 
 Note: Please make sure the CI passed before merging.
+
+## Running the e2e tests locally
+
+After installing [Docker Desktop](https://www.docker.com/products/docker-desktop),
+[minikube](https://minikube.sigs.k8s.io/docs/start/) and [helm](https://helm.sh/docs/intro/quickstart/) locally
+you will be able to run the end-to-end tests locally using the `e2e-tests/run_tests.sh` script.
+
+For usage examples, please execute it with the following command:
+```bash
+./e2e-tests/run_tests.sh -h
+```
diff --git a/e2e-tests/run_tests.sh b/e2e-tests/run_tests.sh
new file mode 100755
index 00000000..a888168e
--- /dev/null
+++ b/e2e-tests/run_tests.sh
@@ -0,0 +1,253 @@
+#!/usr/bin/env bash
+################################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+################################################################################
+
+
+readlink -f "$0" 2>/dev/null
+if [[ $? -ne 0 ]]; then
+  echo
+  echo "-----------------------------------"
+  echo "Please make sure that 'readlink -f \"$0\"' works."
+  echo "Maybe:"
+  echo " brew install coreutils"
+  echo " alias readlink=greadlink"
+  echo "-----------------------------------"
+  echo
+  exit 1
+fi
+
+ROOT_DIR=$(dirname $(dirname "$(readlink -f "$0")"))
+source "${ROOT_DIR}/e2e-tests/utils.sh"
+
+function help() {
+  # Display Help
+  echo "Script to run the flink kubernetes operator e2e tests."
+  echo
+  echo "Syntax: run_tests.sh [-i|-f|-m|-n|-s|-c|-h] scripts"
+  echo
+  echo "Options:"
+  echo " -i     The Flink image to use (eg. flink:1.16 / flink:1.15 / flink:1.14). Only needed if the default docker image for the Flink version need to be changed."
+  echo " -f     The Flink version(s) to use (eg. v1_16 / v1_15 / v1_14). Could contain multiple values separated by ','"
+  echo " -m     The run mode(s) to use (eg. native / standalone). Could contain multiple values separated by ','"
+  echo " -n     The namespace(s) to install the operator to. Could contain multiple values separated by ','"
+  echo " -s     If set then skips the operator build (Make sure that minikube already has a version of the operator with the name of 'flink-kubernetes-operator:ci-latest')."
+  echo " -k     After the test run the operator is not uninstalled. Will exit after the first test run."
+  echo " -d     If set then the script will print debug logs."
+  echo " -h     Print this help."
+  echo
+  echo "On MAC do not forget to start the 'minikube tunnel' in a different terminal."
+  echo "Visit this terminal from time to time, as it will ask you for root password."
+  echo "This is needed to forward the rest endpoint requests to port 80."
+  echo
+  echo "Examples:"
+  echo "  Start the test_application_operations.sh (default) test on a newly built and deployed operator."
+  echo "  The test will use the default settings for every config value:"
+  echo "    ./run_tests.sh"
+  echo
+  echo "  Start a single test using the currently compiled docker image of the operator which should be available on the minikube."
+  echo "  The operator will be deployed in the 'flink' namespace:"
+  echo "    ./run_tests.sh -s -namespace flink"
+  echo
+  echo "  Run multiple tests:"
+  echo "    ./run_tests.sh test_application_operations.sh test_sessionjob_operations.sh"
+  echo
+  echo "  Run a single test and show debug logs:"
+  echo "    ./run_tests.sh -d"
+  echo
+  echo "  Use every possible configuration:"
+  echo "    ./run_tests.sh -i 'flink:1.15' -f 'v1_15' -m standalone -n flink -s -k test_sessionjob_operations.sh"
+  echo
+  echo "  Run every possible test configuration:"
+  echo "    ./run_tests.sh -f v1_16,v1_15,v1_14,v1_13 -m native,standalone -n flink,default -d test_multi_sessionjob.sh test_application_operations.sh test_application_kubernetes_ha.sh test_sessionjob_kubernetes_ha.sh test_sessionjob_operations.sh"
+  echo
+  echo
+  echo "  Use the script to compile and deploy the current version of the operator, and check the deployment:"
+  echo "    ./run_tests.sh -k"
+  echo
+}
+
+# Default values
+image=""
+flink_versions="v1_16"
+modes="native"
+namespaces="default"
+skip_operator="false"
+keep_operator="false"
+
+# Flink version to Flink docker image mapping. Add new version and image here if it is supported.
+versions=("v1_16" "v1_15" "v1_14" "v1_13")
+images=("flink:1.16" "flink:1.15" "flink:1.14" "flink:1.13")
+
+while getopts "i:f:m:n:hsdk" option; do
+   case $option in
+      i) image=$OPTARG;;
+      f) flink_versions=$OPTARG;;
+      m) modes=$OPTARG;;
+      n) namespaces=$OPTARG;;
+      s) skip_operator="true";;
+      k) keep_operator="true";;
+      d) DEBUG="true";;
+      h) # display Help
+         help
+         exit;;
+     \?) # Invalid option
+         echo "Error: Invalid option"
+         exit;;
+   esac
+done
+
+scripts=${@:$OPTIND}
+if [[ -z "${scripts}" ]]; then
+  scripts="test_application_operations.sh"
+fi
+
+echo
+echo "-----------------------------------"
+echo "Start testing with the following parameters:"
+echo " Image:                  ${image}"
+echo " Flink version(s):       ${flink_versions}"
+echo " Mode(s):                ${modes}"
+echo " Operator namespace(s):  ${namespaces}"
+echo " Skip operator build:    ${skip_operator}"
+echo " Script() to run:        ${scripts}"
+echo "-----------------------------------"
+
+pushd $ROOT_DIR
+echo
+echo "-----------------------------------"
+echo "Starting minikube"
+echo "-----------------------------------"
+echo
+time start_minikube
+
+echo
+echo "-----------------------------------"
+echo "Installing certificate manager"
+echo "-----------------------------------"
+echo
+time install_cert_manager
+
+if [[ "$skip_operator" = true ]]; then
+  echo
+  echo "-----------------------------------"
+  echo "Skipping operator build"
+  echo "-----------------------------------"
+else
+  echo
+  echo "-----------------------------------"
+  echo "Building operator"
+  echo "-----------------------------------"
+  echo
+  time build_image
+fi
+
+if [[ ! -z $(get_operator_pod_name 2>/dev/null) ]]; then
+  operator_pod_namespace=$(get_operator_pod_namespace)
+  echo
+  echo "-----------------------------------"
+  echo "Found existing operator. Please remove and restart the script. The following commands could be used:"
+  echo " helm delete flink-kubernetes-operator -n ${operator_pod_namespace}"
+  echo " kubectl delete namespace flink"
+  echo " kubectl delete serviceaccount flink"
+  echo " kubectl delete role flink"
+  echo " kubectl delete rolebinding flink-role-binding"
+  echo "-----------------------------------"
+  echo
+  exit 1;
+fi
+
+IFS=',' read -ra flink_version_list <<< "${flink_versions}"
+IFS=',' read -ra mode_list <<< "${modes}"
+IFS=',' read -ra namespace_list <<< "${namespaces}"
+
+for flink_version in ${flink_version_list[@]}; do
+  test_image=${image}
+  if [[ -z ${test_image} ]]; then
+    position=$(get_position ${flink_version} ${versions[@]})
+    if [[ -z ${position} ]]; then
+      echo
+      echo "-----------------------------------"
+      echo "Unknown Flink version ${flink_version}, please provide an image or a known Flink version"
+      echo "-----------------------------------"
+      echo
+      exit 1;
+    fi
+    test_image=${images[${position}]};
+  fi
+
+  for mode in ${mode_list[@]}; do
+    prepare_tests ${test_image} ${flink_version} ${mode}
+    for namespace in ${namespace_list[@]}; do
+      for script in ${scripts}; do
+        if [[ ${script} = "test_multi_sessionjob.sh" && ${namespace} = "default" ]]; then
+          echo
+          echo "-----------------------------------"
+          echo "Skipping ${script} on 'default' namespace, since an equivalent test will/should run on the 'flink' namespace and we want to save CPU time"
+          echo "-----------------------------------"
+          echo
+          continue
+        fi
+        echo
+        echo "-----------------------------------"
+        echo "Installing operator to '${namespace}' namespace"
+        echo "-----------------------------------"
+        echo
+        install_operator $namespace
+        echo
+        echo "-----------------------------------"
+        echo "Running test:"
+        echo " Namespace:      ${namespace}"
+        echo " Flink version:  ${flink_version}"
+        echo " Flink image:    ${test_image}"
+        echo " Mode:           ${mode}"
+        echo " Script:         ${script}"
+        echo "-----------------------------------"
+        echo
+        time bash $ROOT_DIR/e2e-tests/${script}
+        if [[ $? -ne 0 ]]; then
+          echo
+          echo "-----------------------------------"
+          echo "Test failed: $ROOT_DIR/e2e-tests/${script}"
+          echo "-----------------------------------"
+          echo
+          exit 1
+        fi
+        echo
+        echo "-----------------------------------"
+        echo "Test succeeded: $ROOT_DIR/e2e-tests/${script}"
+        echo "-----------------------------------"
+        if [[ "$keep_operator" = true ]]; then
+          echo
+          echo "-----------------------------------"
+          echo "Keeping operator and exiting"
+          echo "-----------------------------------"
+          echo
+          exit 0
+        fi
+        echo
+        echo "-----------------------------------"
+        echo "Removing operator from '${namespace}' namespace"
+        echo "-----------------------------------"
+        echo
+        uninstall_operator $namespace
+      done
+    done
+    revert_tests
+  done
+done
+popd
diff --git a/e2e-tests/utils.sh b/e2e-tests/utils.sh
index e38f9631..a7726234 100755
--- a/e2e-tests/utils.sh
+++ b/e2e-tests/utils.sh
@@ -60,7 +60,12 @@ function wait_for_status {
 function assert_available_slots() {
   expected=$1
   CLUSTER_ID=$2
-  ip=$(minikube ip)
+  if [[ $OSTYPE == 'darwin'* ]]; then
+    # docker ingress forwards the ports to the localhost instead of the minikube ip on MacOS
+    ip="localhost"
+  else
+    ip=$(minikube ip)
+  fi
   actual=$(curl "http://$ip/default/${CLUSTER_ID}/overview" 2>/dev/null | grep -E -o '"slots-available":[0-9]+' | awk -F':' '{print $2}')
   if [[ "${expected}" != "${actual}" ]]; then
     echo "Expected available slots: ${expected}, actual: ${actual}"
@@ -212,7 +217,7 @@ function stop_minikube {
 }
 
 function cleanup_and_exit() {
-    if [ $TRAPPED_EXIT_CODE != 0 ];then
+    if [[ $TRAPPED_EXIT_CODE != 0 && -n $DEBUG ]]; then
       debug_and_show_logs
     fi
 
@@ -265,3 +270,75 @@ function create_namespace() {
   fi;
 
 }
+
+function install_cert_manager() {
+  if [[ -n ${DEBUG} ]]; then
+    kubectl get pods -A
+  fi
+  kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.8.2/cert-manager.yaml
+  kubectl -n cert-manager wait --all=true --for=condition=Available --timeout=300s deploy
+}
+
+function build_image() {
+  export SHELL=/bin/bash
+  export DOCKER_BUILDKIT=1
+  eval $(minikube docker-env)
+  docker build --progress=plain --no-cache -f ./Dockerfile -t flink-kubernetes-operator:ci-latest --progress plain .
+  if [[ -n ${DEBUG} ]]; then
+    docker images
+  fi
+}
+
+function install_operator() {
+  local namespace=$1
+
+  create_namespace flink
+  if [[ -n ${DEBUG} ]]; then
+    debug="--debug"
+  fi
+  helm ${debug} install flink-kubernetes-operator -n ${namespace} helm/flink-kubernetes-operator --set image.repository=flink-kubernetes-operator --set image.tag=ci-latest --create-namespace --set 'watchNamespaces={default,flink}'
+  kubectl wait --for=condition=Available --timeout=120s -n ${namespace} deploy/flink-kubernetes-operator
+  if [[ -n ${DEBUG} ]]; then
+    kubectl get pods
+  fi
+}
+
+function uninstall_operator() {
+  local namespace=$1
+
+  helm uninstall -n ${namespace} flink-kubernetes-operator
+  kubectl delete namespace flink
+  kubectl delete serviceaccount flink
+  kubectl delete role flink
+  kubectl delete rolebinding flink-role-binding
+}
+
+function prepare_tests() {
+  local image=$1
+  local flink_version=$2
+  local mode="$3"
+
+  sed -i -e "s/image: flink:.*/image: ${image}/" e2e-tests/data/*.yaml
+  sed -i -e "s/flinkVersion: .*/flinkVersion: ${flink_version}/" e2e-tests/data/*.yaml
+  sed -i -e "s/mode: .*/mode: ${mode}/" e2e-tests/data/*.yaml
+  if [[ -n ${DEBUG} ]]; then
+    git --no-pager diff HEAD
+  fi
+}
+
+function revert_tests() {
+  git checkout e2e-tests/data
+  rm e2e-tests/data/*.yaml-e
+}
+
+function get_position() {
+  local input_value=$1
+  shift
+  local input_array=("$@")
+
+  for i in "${!input_array[@]}"; do
+     if [[ "${input_array[$i]}" = "${input_value}" ]]; then
+         echo "${i}";
+     fi
+  done
+}