add operator e2e suites
Signed-off-by: zhzhuang-zju <m17799853869@163.com>
This commit is contained in:
parent
00f936b565
commit
4e592c1bee
|
@ -161,3 +161,59 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: karmada_kind_log_${{ matrix.k8s }}
|
name: karmada_kind_log_${{ matrix.k8s }}
|
||||||
path: /tmp/karmada/
|
path: /tmp/karmada/
|
||||||
|
|
||||||
|
e2e-operator:
|
||||||
|
name: operator e2e test
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Here support the latest three minor releases of Kubernetes, this can be considered to be roughly
|
||||||
|
# the same as the End of Life of the Kubernetes release: https://kubernetes.io/releases/
|
||||||
|
# Please remember to update the CI Schedule Workflow when we add a new version.
|
||||||
|
k8s: [ v1.29.0, v1.30.0, v1.31.0 ]
|
||||||
|
steps:
|
||||||
|
# Free up disk space on Ubuntu
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@main
|
||||||
|
with:
|
||||||
|
# this might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: false
|
||||||
|
# all of these default to true, but feel free to set to "false" if necessary for your workflow
|
||||||
|
android: true
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
large-packages: false
|
||||||
|
docker-images: false
|
||||||
|
swap-storage: false
|
||||||
|
- name: checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# Number of commits to fetch. 0 indicates all history for all branches and tags.
|
||||||
|
# We need to guess version via git tags.
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: install Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- name: setup operator e2e test environment
|
||||||
|
run: |
|
||||||
|
export CLUSTER_VERSION=kindest/node:${{ matrix.k8s }}
|
||||||
|
hack/operator-e2e-environment.sh
|
||||||
|
- name: run e2e
|
||||||
|
run: |
|
||||||
|
export ARTIFACTS_PATH=${{ github.workspace }}/karmada-operator-e2e-logs/${{ matrix.k8s }}/
|
||||||
|
hack/run-e2e-operator.sh
|
||||||
|
- name: upload logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: karmada_operator_e2e_log_${{ matrix.k8s }}
|
||||||
|
path: ${{ github.workspace }}/karmada-operator-e2e-logs/${{ matrix.k8s }}/
|
||||||
|
- name: upload kind logs
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: karmada_operator_kind_log_${{ matrix.k8s }}
|
||||||
|
path: /tmp/karmada/
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright 2025 The Karmada 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.
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# This script is used in workflow to set up a local karmada-operator e2e testing environment.
|
||||||
|
# It deploys karmada-operator and related resources to the host cluster.
|
||||||
|
# This script depends on utils in: ${REPO_ROOT}/hack/util.sh.
|
||||||
|
|
||||||
|
function usage() {
|
||||||
|
echo "Usage:"
|
||||||
|
echo " hack/operator-e2e-environment.sh [-h]"
|
||||||
|
echo " h: print help information"
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCrdsDir() {
|
||||||
|
local path=$1
|
||||||
|
local url=$2
|
||||||
|
local key=$(echo "$url" | xargs) # Trim whitespace using xargs
|
||||||
|
local hash=$(echo -n "$key" | sha256sum | awk '{print $1}') # Calculate SHA256 hash
|
||||||
|
local hashedKey=${hash:0:64} # Take the first 64 characters of the hash
|
||||||
|
echo "${path}/cache/${hashedKey}"
|
||||||
|
}
|
||||||
|
|
||||||
|
while getopts 'h' OPT; do
|
||||||
|
case $OPT in
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
?)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
||||||
|
source "${REPO_ROOT}"/hack/util.sh
|
||||||
|
KARMADA_SYSTEM_NAMESPACE="karmada-system"
|
||||||
|
|
||||||
|
# variable define
|
||||||
|
export KUBECONFIG_PATH=${KUBECONFIG_PATH:-"${HOME}/.kube"}
|
||||||
|
export MAIN_KUBECONFIG=${MAIN_KUBECONFIG:-"${KUBECONFIG_PATH}/karmada.config"}
|
||||||
|
export HOST_CLUSTER_NAME=${HOST_CLUSTER_NAME:-"karmada-host"}
|
||||||
|
|
||||||
|
# step1. set up a base development environment
|
||||||
|
"${REPO_ROOT}"/hack/setup-dev-base.sh
|
||||||
|
export KUBECONFIG="${MAIN_KUBECONFIG}"
|
||||||
|
|
||||||
|
# step2. deploy karmada-operator
|
||||||
|
"${REPO_ROOT}"/hack/deploy-karmada-operator.sh "${MAIN_KUBECONFIG}" "${HOST_CLUSTER_NAME}"
|
||||||
|
|
||||||
|
# step3. install karmada instance by karmada-operator
|
||||||
|
# step3.1 prepare the local crds
|
||||||
|
echo "Prepare the local crds"
|
||||||
|
cd ${REPO_ROOT}/charts/karmada/
|
||||||
|
cp -r _crds crds
|
||||||
|
tar -zcvf ../../crds.tar.gz crds
|
||||||
|
cd -
|
||||||
|
|
||||||
|
# step3.2 copy the local crds.tar.gz file to the specified path of the karmada-operator, so that the karmada-operator will skip the step of downloading CRDs.
|
||||||
|
CRDTARBALL_URL="http://local"
|
||||||
|
DATA_DIR="/var/lib/karmada"
|
||||||
|
CRD_CACHE_DIR=$(getCrdsDir "${DATA_DIR}" "${CRDTARBALL_URL}")
|
||||||
|
OPERATOR_POD_NAME=$(kubectl --kubeconfig="${MAIN_KUBECONFIG}" --context="${HOST_CLUSTER_NAME}" get pods -n ${KARMADA_SYSTEM_NAMESPACE} -l karmada-app=karmada-operator -o custom-columns=NAME:.metadata.name --no-headers)
|
||||||
|
kubectl --kubeconfig="${MAIN_KUBECONFIG}" --context="${HOST_CLUSTER_NAME}" exec -i ${OPERATOR_POD_NAME} -n ${KARMADA_SYSTEM_NAMESPACE} -- mkdir -p ${CRD_CACHE_DIR}
|
||||||
|
kubectl --kubeconfig="${MAIN_KUBECONFIG}" --context="${HOST_CLUSTER_NAME}" cp ${REPO_ROOT}/crds.tar.gz ${KARMADA_SYSTEM_NAMESPACE}/${OPERATOR_POD_NAME}:${CRD_CACHE_DIR}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright 2025 The Karmada 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.
|
||||||
|
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# This script runs e2e test against on a kubernetes cluster which deployed karmada operator.
|
||||||
|
# You should prepare your environment in advance, for example, use hack/operator-e2e-environment.sh to set up the environment.
|
||||||
|
#
|
||||||
|
# Usage: hack/run-e2e-operator.sh
|
||||||
|
# Example 1: hack/run-e2e-operator.sh (run operator e2e with default config)
|
||||||
|
|
||||||
|
KUBECONFIG_PATH=${KUBECONFIG_PATH:-"${HOME}/.kube"}
|
||||||
|
HOST_KUBECONFIG=${HOST_KUBECONFIG:-"$KUBECONFIG_PATH/karmada.config"}
|
||||||
|
|
||||||
|
# RUNNING_ON_KIND indicates if current testing against on a kind cluster.
|
||||||
|
# Defaults to true.
|
||||||
|
# For kind cluster, the kind related logs will be collected after the testing.
|
||||||
|
RUNNING_ON_KIND=${RUNNING_ON_KIND:-true}
|
||||||
|
|
||||||
|
HOST_CLUSTER_NAME=${HOST_CLUSTER_NAME:-"karmada-host"}
|
||||||
|
|
||||||
|
ARTIFACTS_PATH=${ARTIFACTS_PATH:-"${HOME}/karmada-operator-e2e-logs"}
|
||||||
|
mkdir -p "$ARTIFACTS_PATH"
|
||||||
|
|
||||||
|
# Install ginkgo
|
||||||
|
GO111MODULE=on go install github.com/onsi/ginkgo/v2/ginkgo
|
||||||
|
|
||||||
|
# Run e2e
|
||||||
|
export KUBECONFIG=${HOST_KUBECONFIG}
|
||||||
|
|
||||||
|
set +e
|
||||||
|
ginkgo -v --race --trace --fail-fast -p --randomize-all ./test/e2e/suites/operator
|
||||||
|
TESTING_RESULT=$?
|
||||||
|
|
||||||
|
# Collect logs
|
||||||
|
echo "Collect logs to $ARTIFACTS_PATH..."
|
||||||
|
cp "$HOST_KUBECONFIG" "$ARTIFACTS_PATH"
|
||||||
|
|
||||||
|
if [ "$RUNNING_ON_KIND" = true ]; then
|
||||||
|
echo "Collecting $HOST_CLUSTER_NAME logs..."
|
||||||
|
mkdir -p "$ARTIFACTS_PATH/$HOST_CLUSTER_NAME"
|
||||||
|
kind export logs --name="$HOST_CLUSTER_NAME" "$ARTIFACTS_PATH/$HOST_CLUSTER_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Collected logs at $ARTIFACTS_PATH:"
|
||||||
|
ls -al "$ARTIFACTS_PATH"
|
||||||
|
|
||||||
|
exit $TESTING_RESULT
|
|
@ -264,7 +264,7 @@ func UpdateClusterLabels(client karmada.Interface, clusterName string, labels ma
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteClusterLabels deletes cluster labels if it exists.
|
// DeleteClusterLabels deletes cluster labels if it exists.
|
||||||
|
@ -286,7 +286,7 @@ func DeleteClusterLabels(client karmada.Interface, clusterName string, labels ma
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClusterNamesFromClusters will get Clusters' names form Clusters Object.
|
// GetClusterNamesFromClusters will get Clusters' names form Clusters Object.
|
||||||
|
@ -306,7 +306,7 @@ func WaitClusterFitWith(c client.Client, clusterName string, fit func(cluster *c
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return fit(currentCluster), nil
|
return fit(currentCluster), nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadRESTClientConfig creates a rest.Config using the passed kubeconfig. If context is empty, current context in kubeconfig will be used.
|
// LoadRESTClientConfig creates a rest.Config using the passed kubeconfig. If context is empty, current context in kubeconfig will be used.
|
||||||
|
@ -363,5 +363,5 @@ func UpdateClusterStatusCondition(client karmada.Interface, clusterName string,
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,5 +34,5 @@ func WaitClusterResourceBindingFitWith(client karmada.Interface, name string, fi
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(clusterResourceBinding)
|
return fit(clusterResourceBinding)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ func WaitConfigMapPresentOnClusterFitWith(cluster, namespace, name string, fit f
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(configmap)
|
return fit(configmap)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateConfigMapWithPatch update configmap with patch bytes.
|
// UpdateConfigMapWithPatch update configmap with patch bytes.
|
||||||
|
@ -99,7 +99,7 @@ func WaitConfigMapDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get configmap(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get configmap(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitConfigMapDisappearOnClusters wait configmap disappear on member clusters until timeout.
|
// WaitConfigMapDisappearOnClusters wait configmap disappear on member clusters until timeout.
|
||||||
|
|
|
@ -19,10 +19,10 @@ package framework
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// pollInterval defines the interval time for a poll operation.
|
// PollInterval defines the interval time for a poll operation.
|
||||||
pollInterval = 5 * time.Second
|
PollInterval = 5 * time.Second
|
||||||
// pollTimeout defines the time after which the poll operation times out.
|
// PollTimeout defines the time after which the poll operation times out.
|
||||||
pollTimeout = 420 * time.Second
|
PollTimeout = 420 * time.Second
|
||||||
// metricsCreationDelay defines the maximum time metrics not yet available for pod.
|
// metricsCreationDelay defines the maximum time metrics not yet available for pod.
|
||||||
metricsCreationDelay = 2 * time.Minute
|
metricsCreationDelay = 2 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
|
@ -74,7 +74,7 @@ func WaitCRDPresentOnClusters(client karmada.Interface, clusters []string, crdAP
|
||||||
cluster, err := FetchCluster(client, clusterName)
|
cluster, err := FetchCluster(client, clusterName)
|
||||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return helper.IsAPIEnabled(cluster.Status.APIEnablements, crdAPIVersion, crdKind), nil
|
return helper.IsAPIEnabled(cluster.Status.APIEnablements, crdAPIVersion, crdKind), nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ func WaitCRDDisappearedOnClusters(clusters []string, crdName string) {
|
||||||
gomega.Eventually(func() bool {
|
gomega.Eventually(func() bool {
|
||||||
_, err := clusterDynamicClient.Resource(crdGVR).Get(context.TODO(), crdName, metav1.GetOptions{})
|
_, err := clusterDynamicClient.Resource(crdGVR).Get(context.TODO(), crdName, metav1.GetOptions{})
|
||||||
return apierrors.IsNotFound(err)
|
return apierrors.IsNotFound(err)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -108,5 +108,5 @@ func WaitCRDFitWith(client dynamic.Interface, crdName string, fit func(crd *apie
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(crd)
|
return fit(crd)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func UpdateDeploymentPaused(client kubernetes.Interface, deployment *appsv1.Depl
|
||||||
deploy.Spec.Paused = paused
|
deploy.Spec.Paused = paused
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ func WaitDeploymentPresentOnClusterFitWith(cluster, namespace, name string, fit
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(dep)
|
return fit(dep)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitDeploymentFitWith wait deployment sync with fit func.
|
// WaitDeploymentFitWith wait deployment sync with fit func.
|
||||||
|
@ -90,7 +90,7 @@ func WaitDeploymentFitWith(client kubernetes.Interface, namespace, name string,
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(dep)
|
return fit(dep)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitDeploymentPresentOnClustersFitWith wait deployment present on cluster sync with fit func.
|
// WaitDeploymentPresentOnClustersFitWith wait deployment present on cluster sync with fit func.
|
||||||
|
@ -111,7 +111,7 @@ func WaitDeploymentStatus(client kubernetes.Interface, deployment *appsv1.Deploy
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return CheckDeploymentReadyStatus(deploy, replicas)
|
return CheckDeploymentReadyStatus(deploy, replicas)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ func WaitDeploymentDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get deployment(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get deployment(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitDeploymentDisappearOnClusters wait deployment disappear on member clusters until timeout.
|
// WaitDeploymentDisappearOnClusters wait deployment disappear on member clusters until timeout.
|
||||||
|
@ -155,7 +155,7 @@ func UpdateDeploymentReplicas(client kubernetes.Interface, deployment *appsv1.De
|
||||||
deploy.Spec.Replicas = &replicas
|
deploy.Spec.Replicas = &replicas
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ func UpdateDeploymentAnnotations(client kubernetes.Interface, deployment *appsv1
|
||||||
deploy.Annotations = annotations
|
deploy.Annotations = annotations
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ func AppendDeploymentAnnotations(client kubernetes.Interface, deployment *appsv1
|
||||||
}
|
}
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ func UpdateDeploymentLabels(client kubernetes.Interface, deployment *appsv1.Depl
|
||||||
deploy.Labels = labels
|
deploy.Labels = labels
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ func UpdateDeploymentVolumes(client kubernetes.Interface, deployment *appsv1.Dep
|
||||||
deploy.Spec.Template.Spec.Volumes = volumes
|
deploy.Spec.Template.Spec.Volumes = volumes
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ func UpdateDeploymentServiceAccountName(client kubernetes.Interface, deployment
|
||||||
deploy.Spec.Template.Spec.ServiceAccountName = serviceAccountName
|
deploy.Spec.Template.Spec.ServiceAccountName = serviceAccountName
|
||||||
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
_, err = client.AppsV1().Deployments(deploy.Namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ func ExtractTargetClustersFrom(c client.Client, deployment *appsv1.Deployment) [
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
|
|
||||||
targetClusterNames := make([]string, 0, len(binding.Spec.Clusters))
|
targetClusterNames := make([]string, 0, len(binding.Spec.Clusters))
|
||||||
for _, cluster := range binding.Spec.Clusters {
|
for _, cluster := range binding.Spec.Clusters {
|
||||||
|
@ -282,7 +282,7 @@ func WaitDeploymentGetByClientFitWith(client kubernetes.Interface, namespace, na
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(dep)
|
return fit(dep)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +305,6 @@ func WaitDeploymentReplicasFitWith(clusters []string, namespace, name string, ex
|
||||||
}
|
}
|
||||||
klog.Infof("The total replicas of deployment(%s/%s) is %d", namespace, name, totalReplicas)
|
klog.Infof("The total replicas of deployment(%s/%s) is %d", namespace, name, totalReplicas)
|
||||||
return totalReplicas == expectReplicas
|
return totalReplicas == expectReplicas
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,5 +35,5 @@ func WaitEventFitWith(kubeClient kubernetes.Interface, namespace string, involve
|
||||||
})
|
})
|
||||||
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
return slices.ContainsFunc(eventList.Items, fit)
|
return slices.ContainsFunc(eventList.Items, fit)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,6 @@ func WaitFederatedResourceQuotaCollectStatus(client karmada.Interface, namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ func WaitJobPresentOnClusterFitWith(cluster, namespace, name string, fit func(jo
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(dep)
|
return fit(dep)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitJobPresentOnClustersFitWith wait job present on cluster sync with fit func.
|
// WaitJobPresentOnClustersFitWith wait job present on cluster sync with fit func.
|
||||||
|
@ -96,7 +96,7 @@ func WaitJobDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get job(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get job(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitJobDisappearOnClusters wait job disappear on member clusters until timeout.
|
// WaitJobDisappearOnClusters wait job disappear on member clusters until timeout.
|
||||||
|
|
|
@ -48,7 +48,7 @@ func UpdateMultiClusterService(client karmada.Interface, mcs *networkingv1alpha1
|
||||||
mcsExist.Spec = mcs.Spec
|
mcsExist.Spec = mcs.Spec
|
||||||
_, err = client.NetworkingV1alpha1().MultiClusterServices(mcsExist.Namespace).Update(context.TODO(), mcsExist, metav1.UpdateOptions{})
|
_, err = client.NetworkingV1alpha1().MultiClusterServices(mcsExist.Namespace).Update(context.TODO(), mcsExist, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,5 +68,5 @@ func WaitMultiClusterServicePresentOnClustersFitWith(client karmada.Interface, n
|
||||||
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
return fit(mcs)
|
return fit(mcs)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ func WaitNamespacePresentOnClusterByClient(client kubernetes.Interface, name str
|
||||||
_, err := client.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
|
_, err := client.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitNamespacePresentOnCluster wait namespace present on cluster until timeout.
|
// WaitNamespacePresentOnCluster wait namespace present on cluster until timeout.
|
||||||
|
@ -65,7 +65,7 @@ func WaitNamespacePresentOnCluster(cluster, name string) {
|
||||||
_, err := clusterClient.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
|
_, err := clusterClient.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitNamespacePresentOnClusters wait namespace present on clusters until timeout.
|
// WaitNamespacePresentOnClusters wait namespace present on clusters until timeout.
|
||||||
|
@ -94,7 +94,7 @@ func WaitNamespaceDisappearOnCluster(cluster, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get namespace(%s) on cluster(%s), err: %v", name, cluster, err)
|
klog.Errorf("Failed to get namespace(%s) on cluster(%s), err: %v", name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitNamespaceDisappearOnClusters wait namespace disappear on clusters until timeout.
|
// WaitNamespaceDisappearOnClusters wait namespace disappear on clusters until timeout.
|
||||||
|
@ -117,6 +117,6 @@ func UpdateNamespaceLabels(client kubernetes.Interface, namespace *corev1.Namesp
|
||||||
ns.Labels = labels
|
ns.Labels = labels
|
||||||
_, err = client.CoreV1().Namespaces().Update(context.TODO(), ns, metav1.UpdateOptions{})
|
_, err = client.CoreV1().Namespaces().Update(context.TODO(), ns, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func WaitPVCPresentOnClusterFitWith(cluster, namespace, name string, fit func(pv
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(pvc)
|
return fit(pvc)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitPVCDisappearOnCluster wait PersistentVolumeClaim disappear on cluster until timeout.
|
// WaitPVCDisappearOnCluster wait PersistentVolumeClaim disappear on cluster until timeout.
|
||||||
|
@ -86,7 +86,7 @@ func WaitPVCDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get PersistentVolumeClaim(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get PersistentVolumeClaim(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitPVCDisappearOnClusters Wait for the PersistentVolumeClaim to disappear on member clusters until timeout.
|
// WaitPVCDisappearOnClusters Wait for the PersistentVolumeClaim to disappear on member clusters until timeout.
|
||||||
|
|
|
@ -64,7 +64,7 @@ func WaitPodPresentOnClusterFitWith(cluster, namespace, name string, fit func(po
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(pod)
|
return fit(pod)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitPodMetricsReady wait podMetrics to be ready.
|
// WaitPodMetricsReady wait podMetrics to be ready.
|
||||||
|
@ -90,7 +90,7 @@ func WaitPodMetricsReady(kubeClient kubernetes.Interface, karmadaClient karmada.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}, metricsCreationDelay, pollInterval).Should(gomega.Equal(true))
|
}, metricsCreationDelay, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitPodPresentOnClustersFitWith wait pod present on cluster sync with fit func.
|
// WaitPodPresentOnClustersFitWith wait pod present on cluster sync with fit func.
|
||||||
|
@ -119,7 +119,7 @@ func WaitPodDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get pod(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get pod(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitPodDisappearOnClusters wait pod disappear on member clusters until timeout.
|
// WaitPodDisappearOnClusters wait pod disappear on member clusters until timeout.
|
||||||
|
|
|
@ -94,5 +94,5 @@ func WaitPropagationPolicyFitWith(client karmada.Interface, namespace, name stri
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(policy)
|
return fit(policy)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ func WaitRolePresentOnClusterFitWith(cluster, namespace, name string, fit func(r
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(role)
|
return fit(role)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitRoleDisappearOnClusters wait role disappear on member clusters until timeout.
|
// WaitRoleDisappearOnClusters wait role disappear on member clusters until timeout.
|
||||||
|
@ -99,7 +99,7 @@ func WaitRoleDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get role(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get role(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateClusterRole create clusterRole.
|
// CreateClusterRole create clusterRole.
|
||||||
|
@ -142,7 +142,7 @@ func WaitClusterRolePresentOnClusterFitWith(cluster, name string, fit func(clust
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(clusterRole)
|
return fit(clusterRole)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitClusterRoleDisappearOnClusters wait clusterRole disappear on member clusters until timeout.
|
// WaitClusterRoleDisappearOnClusters wait clusterRole disappear on member clusters until timeout.
|
||||||
|
@ -171,7 +171,7 @@ func WaitClusterRoleDisappearOnCluster(cluster, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get clusterRole(%s) on cluster(%s), err: %v", name, cluster, err)
|
klog.Errorf("Failed to get clusterRole(%s) on cluster(%s), err: %v", name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitClusterRoleGetByClientFitWith wait clusterRole get by client fit with func.
|
// WaitClusterRoleGetByClientFitWith wait clusterRole get by client fit with func.
|
||||||
|
@ -183,7 +183,7 @@ func WaitClusterRoleGetByClientFitWith(client kubernetes.Interface, name string,
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(clusterRole)
|
return fit(clusterRole)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ func WaitRoleBindingPresentOnClusterFitWith(cluster, namespace, name string, fit
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(roleBinding)
|
return fit(roleBinding)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitRoleBindingDisappearOnClusters wait roleBinding disappear on member clusters until timeout.
|
// WaitRoleBindingDisappearOnClusters wait roleBinding disappear on member clusters until timeout.
|
||||||
|
@ -256,7 +256,7 @@ func WaitRoleBindingDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get roleBinding(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get roleBinding(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateClusterRoleBinding create clusterRoleBinding.
|
// CreateClusterRoleBinding create clusterRoleBinding.
|
||||||
|
@ -299,7 +299,7 @@ func WaitClusterRoleBindingPresentOnClusterFitWith(cluster, name string, fit fun
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(clusterRoleBinding)
|
return fit(clusterRoleBinding)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitClusterRoleBindingDisappearOnClusters wait clusterRoleBinding disappear on member clusters until timeout.
|
// WaitClusterRoleBindingDisappearOnClusters wait clusterRoleBinding disappear on member clusters until timeout.
|
||||||
|
@ -328,7 +328,7 @@ func WaitClusterRoleBindingDisappearOnCluster(cluster, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get clusterRoleBinding(%s) on cluster(%s), err: %v", name, cluster, err)
|
klog.Errorf("Failed to get clusterRoleBinding(%s) on cluster(%s), err: %v", name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateServiceAccount create serviceaccount.
|
// CreateServiceAccount create serviceaccount.
|
||||||
|
@ -362,7 +362,7 @@ func WaitServiceAccountPresentOnClusterFitWith(cluster, namespace, name string,
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(sa)
|
return fit(sa)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitServiceAccountPresentOnClustersFitWith wait sa present on cluster sync with fit func.
|
// WaitServiceAccountPresentOnClustersFitWith wait sa present on cluster sync with fit func.
|
||||||
|
@ -391,7 +391,7 @@ func WaitServiceAccountDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get sa(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get sa(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitServiceAccountDisappearOnClusters wait sa disappear on member clusters until timeout.
|
// WaitServiceAccountDisappearOnClusters wait sa disappear on member clusters until timeout.
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Karmada 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package operator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
|
operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1"
|
||||||
|
operator "github.com/karmada-io/karmada/operator/pkg/generated/clientset/versioned"
|
||||||
|
"github.com/karmada-io/karmada/test/e2e/framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaitKarmadaReady wait karmada instance ready until timeout.
|
||||||
|
// Since the karmada-operator updates the `karmada.spec` first and then the `karmada.status`, in order to ensure that the `ready` condition indicates
|
||||||
|
// that the `karmada.spec` has been applied correctly, it will check the `lastTransitionTime` of the `ready` condition.
|
||||||
|
func WaitKarmadaReady(client operator.Interface, namespace, name string, lastTransitionTime time.Time) {
|
||||||
|
klog.Infof("Waiting for karmada instance %s/%s ready", namespace, name)
|
||||||
|
ginkgo.By(fmt.Sprintf("Waiting for karmada instance %s/%s ready", namespace, name), func() {
|
||||||
|
gomega.Eventually(func(g gomega.Gomega) bool {
|
||||||
|
karmada, err := client.OperatorV1alpha1().Karmadas(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
|
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
for _, condition := range karmada.Status.Conditions {
|
||||||
|
if condition.Type == "Ready" && condition.Status == "True" && condition.LastTransitionTime.After(lastTransitionTime) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, framework.PollTimeout, framework.PollInterval).Should(gomega.Equal(true))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateKarmadaInstance creates a karmada instance.
|
||||||
|
func CreateKarmadaInstance(operatorClient operator.Interface, karmada *operatorv1alpha1.Karmada) error {
|
||||||
|
_, err := operatorClient.OperatorV1alpha1().Karmadas(karmada.GetNamespace()).Create(context.TODO(), karmada, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if apierrors.IsAlreadyExists(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateKarmadaInstanceWithSpec updates karmada instance with spec.
|
||||||
|
func UpdateKarmadaInstanceWithSpec(client operator.Interface, namespace, name string, karmadaSpec operatorv1alpha1.KarmadaSpec) {
|
||||||
|
ginkgo.By(fmt.Sprintf("Updating Karmada(%s/%s) spec", namespace, name), func() {
|
||||||
|
karmada, err := client.OperatorV1alpha1().Karmadas(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
karmada.Spec = karmadaSpec
|
||||||
|
_, err = client.OperatorV1alpha1().Karmadas(namespace).Update(context.TODO(), karmada, metav1.UpdateOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLastTransitionTime gets the last transition time of the condition, return time.Now() if not found.
|
||||||
|
func GetLastTransitionTime(karmada *operatorv1alpha1.Karmada, conditionType operatorv1alpha1.ConditionType) time.Time {
|
||||||
|
for _, condition := range karmada.Status.Conditions {
|
||||||
|
if condition.Type == string(conditionType) {
|
||||||
|
return condition.LastTransitionTime.Time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return time.Now()
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ func WaitResourceBindingFitWith(client karmada.Interface, namespace, name string
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(resourceBinding)
|
return fit(resourceBinding)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertBindingScheduledClusters wait deployment present on member clusters sync with fit func.
|
// AssertBindingScheduledClusters wait deployment present on member clusters sync with fit func.
|
||||||
|
@ -61,7 +61,7 @@ func AssertBindingScheduledClusters(client karmada.Interface, namespace, name st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("scheduled clusters: %+v, expected possible results: %+v", scheduledClusters, expectedResults)
|
return fmt.Errorf("scheduled clusters: %+v, expected possible results: %+v", scheduledClusters, expectedResults)
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,6 @@ func WaitGracefulEvictionTasksDone(client karmada.Interface, namespace, name str
|
||||||
return fmt.Errorf("%d GracefulEvictionTasks is being processing", len(binding.Spec.GracefulEvictionTasks))
|
return fmt.Errorf("%d GracefulEvictionTasks is being processing", len(binding.Spec.GracefulEvictionTasks))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func WaitResourceQuotaPresentOnCluster(cluster, namespace, name string) {
|
||||||
_, err := clusterClient.CoreV1().ResourceQuotas(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
_, err := clusterClient.CoreV1().ResourceQuotas(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return true, nil
|
return true, nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitResourceQuotaDisappearOnClusters wait resourceQuota disappear on clusters until timeout.
|
// WaitResourceQuotaDisappearOnClusters wait resourceQuota disappear on clusters until timeout.
|
||||||
|
@ -75,5 +75,5 @@ func WaitResourceQuotaDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get resourceQuota(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get resourceQuota(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func WaitSecretPresentOnClusterFitWith(cluster, namespace, name string, fit func
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(secret)
|
return fit(secret)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitSecretDisappearOnCluster wait secret disappear on cluster until timeout.
|
// WaitSecretDisappearOnCluster wait secret disappear on cluster until timeout.
|
||||||
|
@ -86,7 +86,7 @@ func WaitSecretDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get secret(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get secret(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitSecretDisappearOnClusters wait service disappear on member clusters until timeout.
|
// WaitSecretDisappearOnClusters wait service disappear on member clusters until timeout.
|
||||||
|
|
|
@ -59,7 +59,7 @@ func WaitServicePresentOnClusterFitWith(cluster, namespace, name string, fit fun
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fit(svc)
|
return fit(svc)
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitServicePresentOnClustersFitWith wait service present on cluster sync with fit func.
|
// WaitServicePresentOnClustersFitWith wait service present on cluster sync with fit func.
|
||||||
|
@ -88,7 +88,7 @@ func WaitServiceDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get service(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get service(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitServiceDisappearOnClusters wait service disappear on member clusters until timeout.
|
// WaitServiceDisappearOnClusters wait service disappear on member clusters until timeout.
|
||||||
|
|
|
@ -50,6 +50,6 @@ func UpdateStatefulSetReplicas(client kubernetes.Interface, statefulSet *appsv1.
|
||||||
gomega.Eventually(func() error {
|
gomega.Eventually(func() error {
|
||||||
_, err := client.AppsV1().StatefulSets(statefulSet.Namespace).Update(context.TODO(), statefulSet, metav1.UpdateOptions{})
|
_, err := client.AppsV1().StatefulSets(statefulSet.Namespace).Update(context.TODO(), statefulSet, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,5 +40,5 @@ func WaitForWorkToDisappear(client karmada.Interface, namespace, name string) {
|
||||||
return fmt.Errorf("failed to get work(%s/%s), err: %w", namespace, name, err)
|
return fmt.Errorf("failed to get work(%s/%s), err: %w", namespace, name, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func UpdateWorkload(client dynamic.Interface, workload *workloadv1alpha1.Workloa
|
||||||
gomega.Eventually(func() error {
|
gomega.Eventually(func() error {
|
||||||
_, err = client.Resource(workloadGVR).Namespace(workload.Namespace).Update(context.TODO(), newUnstructuredObj, metav1.UpdateOptions{}, subresources...)
|
_, err = client.Resource(workloadGVR).Namespace(workload.Namespace).Update(context.TODO(), newUnstructuredObj, metav1.UpdateOptions{}, subresources...)
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func GetWorkload(client dynamic.Interface, namespace, name string) *workloadv1al
|
||||||
gomega.Eventually(func() error {
|
gomega.Eventually(func() error {
|
||||||
unstructuredObj, err = client.Resource(workloadGVR).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
unstructuredObj, err = client.Resource(workloadGVR).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObj.UnstructuredContent(), workload)
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObj.UnstructuredContent(), workload)
|
||||||
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
@ -101,7 +101,7 @@ func WaitWorkloadPresentOnClusterFitWith(cluster, namespace, name string, fit fu
|
||||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(workload.UnstructuredContent(), typedObj)
|
err = runtime.DefaultUnstructuredConverter.FromUnstructured(workload.UnstructuredContent(), typedObj)
|
||||||
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
g.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
return fit(typedObj), nil
|
return fit(typedObj), nil
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitWorkloadPresentOnClustersFitWith waits workload present on member clusters sync with fit func.
|
// WaitWorkloadPresentOnClustersFitWith waits workload present on member clusters sync with fit func.
|
||||||
|
@ -130,7 +130,7 @@ func WaitWorkloadDisappearOnCluster(cluster, namespace, name string) {
|
||||||
|
|
||||||
klog.Errorf("Failed to get workload(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
klog.Errorf("Failed to get workload(%s/%s) on cluster(%s), err: %v", namespace, name, cluster, err)
|
||||||
return false
|
return false
|
||||||
}, pollTimeout, pollInterval).Should(gomega.Equal(true))
|
}, PollTimeout, PollInterval).Should(gomega.Equal(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitWorkloadDisappearOnClusters wait workload disappear on member clusters until timeout.
|
// WaitWorkloadDisappearOnClusters wait workload disappear on member clusters until timeout.
|
||||||
|
|
|
@ -64,7 +64,7 @@ func UpdateWorkloadRebalancer(client karmada.Interface, name string, workloads *
|
||||||
}
|
}
|
||||||
_, err = client.AppsV1alpha1().WorkloadRebalancers().Update(context.TODO(), rebalancer, metav1.UpdateOptions{})
|
_, err = client.AppsV1alpha1().WorkloadRebalancers().Update(context.TODO(), rebalancer, metav1.UpdateOptions{})
|
||||||
return err
|
return err
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ func WaitRebalancerObservedWorkloads(client karmada.Interface, name string, expe
|
||||||
return fmt.Errorf("observedWorkloads: %+v, expectedWorkloads: %+v", rebalancer.Status.ObservedWorkloads, expectedWorkloads)
|
return fmt.Errorf("observedWorkloads: %+v, expectedWorkloads: %+v", rebalancer.Status.ObservedWorkloads, expectedWorkloads)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,6 @@ func WaitRebalancerDisappear(client karmada.Interface, name string) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fmt.Errorf("WorkloadRebalancer %s still exist: %+v", name, rebalancer)
|
return fmt.Errorf("WorkloadRebalancer %s still exist: %+v", name, rebalancer)
|
||||||
}, pollTimeout, pollInterval).ShouldNot(gomega.HaveOccurred())
|
}, PollTimeout, PollInterval).ShouldNot(gomega.HaveOccurred())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Karmada 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
|
|
||||||
|
operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1"
|
||||||
|
"github.com/karmada-io/karmada/test/e2e/framework/resource/operator"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = ginkgo.Describe("PriorityClass configuration testing", func() {
|
||||||
|
var karmadaName string
|
||||||
|
var karmadaObject *operatorv1alpha1.Karmada
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ginkgo.Context("PriorityClass configuration testing", func() {
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
karmadaName = KarmadaInstanceNamePrefix + rand.String(RandomStrLength)
|
||||||
|
InitializeKarmadaInstance(operatorClient, testNamespace, karmadaName)
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.AfterEach(func() {
|
||||||
|
err = operatorClient.OperatorV1alpha1().Karmadas(testNamespace).Delete(context.TODO(), karmadaName, metav1.DeleteOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("Custom priorityClass configuration", func() {
|
||||||
|
ginkgo.By("Check if default value is system-node-critical", func() {
|
||||||
|
// take etcd as a representative of StatefulSet.
|
||||||
|
etcd, err := kubeClient.AppsV1().StatefulSets(testNamespace).Get(context.TODO(), karmadaName+"-etcd", metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
gomega.Expect(etcd.Spec.Template.Spec.PriorityClassName).Should(gomega.Equal("system-node-critical"))
|
||||||
|
|
||||||
|
// take karmada-apiserver as a representative of Deployment.
|
||||||
|
karmadaApiserver, err := kubeClient.AppsV1().Deployments(testNamespace).Get(context.TODO(), karmadaName+"-apiserver", metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
gomega.Expect(karmadaApiserver.Spec.Template.Spec.PriorityClassName).Should(gomega.Equal("system-node-critical"))
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Set priorityClass to system-cluster-critical", func() {
|
||||||
|
karmadaObject, err = operatorClient.OperatorV1alpha1().Karmadas(testNamespace).Get(context.TODO(), karmadaName, metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
karmadaObject.Spec.Components.Etcd.Local.PriorityClassName = "system-cluster-critical"
|
||||||
|
karmadaObject.Spec.Components.KarmadaAPIServer.PriorityClassName = "system-cluster-critical"
|
||||||
|
operator.UpdateKarmadaInstanceWithSpec(operatorClient, testNamespace, karmadaName, karmadaObject.Spec)
|
||||||
|
operator.WaitKarmadaReady(operatorClient, testNamespace, karmadaName, operator.GetLastTransitionTime(karmadaObject, operatorv1alpha1.Ready))
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Check if the PriorityClass is applied correctly", func() {
|
||||||
|
// take etcd as a representative of StatefulSet.
|
||||||
|
etcd, err := kubeClient.AppsV1().StatefulSets(testNamespace).Get(context.TODO(), karmadaName+"-etcd", metav1.GetOptions{ResourceVersion: "0"})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
gomega.Expect(etcd.Spec.Template.Spec.PriorityClassName).Should(gomega.Equal("system-cluster-critical"))
|
||||||
|
|
||||||
|
// take karmada-apiserver as a representative of Deployment.
|
||||||
|
karmadaApiserver, err := kubeClient.AppsV1().Deployments(testNamespace).Get(context.TODO(), karmadaName+"-apiserver", metav1.GetOptions{ResourceVersion: "0"})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
gomega.Expect(karmadaApiserver.Spec.Template.Spec.PriorityClassName).Should(gomega.Equal("system-cluster-critical"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Karmada 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
|
|
||||||
|
operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1"
|
||||||
|
operatorutil "github.com/karmada-io/karmada/operator/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = ginkgo.Describe("Status testing", func() {
|
||||||
|
var karmadaName string
|
||||||
|
var karmadaObject *operatorv1alpha1.Karmada
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ginkgo.Context("Karmada instance status testing", func() {
|
||||||
|
ginkgo.BeforeEach(func() {
|
||||||
|
karmadaName = KarmadaInstanceNamePrefix + rand.String(RandomStrLength)
|
||||||
|
InitializeKarmadaInstance(operatorClient, testNamespace, karmadaName)
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.AfterEach(func() {
|
||||||
|
err = operatorClient.OperatorV1alpha1().Karmadas(testNamespace).Delete(context.TODO(), karmadaName, metav1.DeleteOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("Check if the karmada status meets the expectations", func() {
|
||||||
|
ginkgo.By("Get the latest karmada instance", func() {
|
||||||
|
karmadaObject, err = operatorClient.OperatorV1alpha1().Karmadas(testNamespace).Get(context.TODO(), karmadaName, metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Check if status.conditions meets the expectations", func() {
|
||||||
|
conditions := karmadaObject.Status.Conditions
|
||||||
|
gomega.Expect(len(conditions)).Should(gomega.BeNumerically(">", 0))
|
||||||
|
// check if the Ready condition is true
|
||||||
|
hasReadyCondition := false
|
||||||
|
for i := range karmadaObject.Status.Conditions {
|
||||||
|
switch karmadaObject.Status.Conditions[i].Type {
|
||||||
|
case string(operatorv1alpha1.Ready):
|
||||||
|
gomega.Expect(karmadaObject.Status.Conditions[i].Status).Should(gomega.Equal(metav1.ConditionTrue))
|
||||||
|
hasReadyCondition = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gomega.Expect(hasReadyCondition).Should(gomega.BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Check if the status.SecretRef can ref to the right secret", func() {
|
||||||
|
secretRef := karmadaObject.Status.SecretRef
|
||||||
|
gomega.Expect(secretRef).ShouldNot(gomega.BeNil())
|
||||||
|
gomega.Expect(secretRef.Namespace).Should(gomega.Equal(karmadaObject.GetNamespace()))
|
||||||
|
gomega.Expect(secretRef.Name).Should(gomega.Equal(operatorutil.AdminKarmadaConfigSecretName(karmadaObject.GetName())))
|
||||||
|
_, err := kubeClient.CoreV1().Secrets(secretRef.Namespace).Get(context.TODO(), secretRef.Name, metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.By("Check if the status.apiServerService can ref to the right service", func() {
|
||||||
|
apiServerService := karmadaObject.Status.APIServerService
|
||||||
|
gomega.Expect(apiServerService).ShouldNot(gomega.BeNil())
|
||||||
|
gomega.Expect(apiServerService.Name).Should(gomega.Equal(operatorutil.KarmadaAPIServerName(karmadaObject.GetName())))
|
||||||
|
_, err := kubeClient.CoreV1().Services(karmadaObject.GetNamespace()).Get(context.TODO(), apiServerService.Name, metav1.GetOptions{})
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Karmada 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/onsi/ginkgo/v2"
|
||||||
|
"github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/util/rand"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
|
||||||
|
operator "github.com/karmada-io/karmada/operator/pkg/generated/clientset/versioned"
|
||||||
|
"github.com/karmada-io/karmada/pkg/util"
|
||||||
|
"github.com/karmada-io/karmada/test/e2e/framework"
|
||||||
|
operatorresource "github.com/karmada-io/karmada/test/e2e/framework/resource/operator"
|
||||||
|
"github.com/karmada-io/karmada/test/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RandomStrLength represents the random string length to combine names.
|
||||||
|
RandomStrLength = 5
|
||||||
|
// KarmadaInstanceNamePrefix the prefix of the karmada instance name.
|
||||||
|
KarmadaInstanceNamePrefix = "karmadatest-"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// pollInterval defines the interval time for a poll operation.
|
||||||
|
pollInterval time.Duration
|
||||||
|
// pollTimeout defines the time after which the poll operation times out.
|
||||||
|
pollTimeout time.Duration
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
hostContext string
|
||||||
|
kubeconfig string
|
||||||
|
karmadactlPath string
|
||||||
|
restConfig *rest.Config
|
||||||
|
kubeClient kubernetes.Interface
|
||||||
|
testNamespace string
|
||||||
|
operatorClient operator.Interface
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// usage ginkgo -- --poll-interval=5s --poll-timeout=5m
|
||||||
|
// eg. ginkgo -v --race --trace --fail-fast -p --randomize-all ./test/e2e/ -- --poll-interval=5s --poll-timeout=5m
|
||||||
|
flag.DurationVar(&pollInterval, "poll-interval", 5*time.Second, "poll-interval defines the interval time for a poll operation")
|
||||||
|
flag.DurationVar(&pollTimeout, "poll-timeout", 300*time.Second, "poll-timeout defines the time which the poll operation times out")
|
||||||
|
flag.StringVar(&hostContext, "host-context", "karmada-host", "Name of the host cluster context in control plane kubeconfig file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestE2E(t *testing.T) {
|
||||||
|
gomega.RegisterFailHandler(ginkgo.Fail)
|
||||||
|
ginkgo.RunSpecs(t, "E2E Operator Suite")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
|
||||||
|
return nil
|
||||||
|
}, func([]byte) {
|
||||||
|
kubeconfig = os.Getenv("KUBECONFIG")
|
||||||
|
gomega.Expect(kubeconfig).ShouldNot(gomega.BeEmpty())
|
||||||
|
|
||||||
|
goPathCmd := exec.Command("go", "env", "GOPATH")
|
||||||
|
goPath, err := goPathCmd.CombinedOutput()
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
formatGoPath := strings.Trim(string(goPath), "\n")
|
||||||
|
karmadactlPath = formatGoPath + "/bin/karmadactl"
|
||||||
|
gomega.Expect(karmadactlPath).ShouldNot(gomega.BeEmpty())
|
||||||
|
|
||||||
|
restConfig, err = framework.LoadRESTClientConfig(kubeconfig, hostContext)
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
kubeClient, err = kubernetes.NewForConfig(restConfig)
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
testNamespace = fmt.Sprintf("operatortest-%s", rand.String(RandomStrLength))
|
||||||
|
err = setupTestNamespace(testNamespace, kubeClient)
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
||||||
|
operatorClient, err = operator.NewForConfig(restConfig)
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
var _ = ginkgo.SynchronizedAfterSuite(func() {
|
||||||
|
// cleanup all namespaces we created both in control plane and member clusters.
|
||||||
|
// It will not return error even if there is no such namespace in there that may happen in case setup failed.
|
||||||
|
err := cleanupTestNamespace(testNamespace, kubeClient)
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
}, func() {})
|
||||||
|
|
||||||
|
// setupTestNamespace will create a namespace in control plane and all member clusters, most of cases will run against it.
|
||||||
|
// The reason why we need a separated namespace is it will make it easier to cleanup resources deployed by the testing.
|
||||||
|
func setupTestNamespace(namespace string, kubeClient kubernetes.Interface) error {
|
||||||
|
namespaceObj := helper.NewNamespace(namespace)
|
||||||
|
_, err := util.CreateNamespace(kubeClient, namespaceObj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupTestNamespace will remove the namespace we set up before for the whole testing.
|
||||||
|
func cleanupTestNamespace(namespace string, kubeClient kubernetes.Interface) error {
|
||||||
|
err := util.DeleteNamespace(kubeClient, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitializeKarmadaInstance initializes a karmada instance.
|
||||||
|
func InitializeKarmadaInstance(client operator.Interface, namespace, name string) {
|
||||||
|
karmada := helper.NewKarmada(namespace, name)
|
||||||
|
now := time.Now()
|
||||||
|
err := operatorresource.CreateKarmadaInstance(client, karmada)
|
||||||
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
operatorresource.WaitKarmadaReady(client, namespace, name, now)
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 The Karmada 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
|
||||||
|
operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewKarmada returns a new Karmada instance.
|
||||||
|
func NewKarmada(namespace string, name string) *operatorv1alpha1.Karmada {
|
||||||
|
return &operatorv1alpha1.Karmada{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Spec: operatorv1alpha1.KarmadaSpec{
|
||||||
|
CRDTarball: &operatorv1alpha1.CRDTarball{
|
||||||
|
HTTPSource: &operatorv1alpha1.HTTPSource{URL: "http://local"},
|
||||||
|
},
|
||||||
|
Components: &operatorv1alpha1.KarmadaComponents{
|
||||||
|
Etcd: &operatorv1alpha1.Etcd{},
|
||||||
|
KarmadaAggregatedAPIServer: &operatorv1alpha1.KarmadaAggregatedAPIServer{
|
||||||
|
CommonSettings: operatorv1alpha1.CommonSettings{
|
||||||
|
Image: operatorv1alpha1.Image{
|
||||||
|
ImageRepository: "docker.io/karmada/karmada-aggregated-apiserver",
|
||||||
|
ImageTag: "latest",
|
||||||
|
},
|
||||||
|
Replicas: ptr.To[int32](1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KarmadaControllerManager: &operatorv1alpha1.KarmadaControllerManager{
|
||||||
|
CommonSettings: operatorv1alpha1.CommonSettings{
|
||||||
|
Image: operatorv1alpha1.Image{
|
||||||
|
ImageRepository: "docker.io/karmada/karmada-controller-manager",
|
||||||
|
ImageTag: "latest",
|
||||||
|
},
|
||||||
|
Replicas: ptr.To[int32](1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KarmadaScheduler: &operatorv1alpha1.KarmadaScheduler{
|
||||||
|
CommonSettings: operatorv1alpha1.CommonSettings{
|
||||||
|
Image: operatorv1alpha1.Image{
|
||||||
|
ImageRepository: "docker.io/karmada/karmada-scheduler",
|
||||||
|
ImageTag: "latest",
|
||||||
|
},
|
||||||
|
Replicas: ptr.To[int32](1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KarmadaWebhook: &operatorv1alpha1.KarmadaWebhook{
|
||||||
|
CommonSettings: operatorv1alpha1.CommonSettings{
|
||||||
|
Image: operatorv1alpha1.Image{
|
||||||
|
ImageRepository: "docker.io/karmada/karmada-webhook",
|
||||||
|
ImageTag: "latest",
|
||||||
|
},
|
||||||
|
Replicas: ptr.To[int32](1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KarmadaMetricsAdapter: &operatorv1alpha1.KarmadaMetricsAdapter{
|
||||||
|
CommonSettings: operatorv1alpha1.CommonSettings{
|
||||||
|
Image: operatorv1alpha1.Image{
|
||||||
|
ImageRepository: "docker.io/karmada/karmada-metrics-adapter",
|
||||||
|
ImageTag: "latest",
|
||||||
|
},
|
||||||
|
Replicas: ptr.To[int32](1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue