Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,59 @@ jobs:
with:
name: karmada_operator_kind_log_${{ matrix.k8s }}
path: /tmp/karmada/

e2e-init:
name: init 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.31.0, v1.32.0, v1.33.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@v5
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 init e2e test environment
run: |
export CLUSTER_VERSION=kindest/node:${{ matrix.k8s }}
hack/init-e2e-environment.sh
- name: run e2e
run: |
export ARTIFACTS_PATH=${{ github.workspace }}/karmada-init-e2e-logs/${{ matrix.k8s }}/
hack/run-e2e-init.sh
- name: upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: karmada_init_e2e_log_${{ matrix.k8s }}
path: ${{ github.workspace }}/karmada-init-e2e-logs/${{ matrix.k8s }}/
- name: upload kind logs
if: always()
uses: actions/upload-artifact@v4
with:
name: karmada_init_kind_log_${{ matrix.k8s }}
path: /tmp/karmada/
76 changes: 76 additions & 0 deletions hack/init-e2e-environment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Copyright 2021 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 to create a blank cluster for karmadactl init e2e testing.
# It creates a host cluster and prepares necessary components for testing.
# This script depends on utils in: ${REPO_ROOT}/hack/util.sh
# 1. Used by developers to test karmadactl init with custom control plane setup

function usage() {
echo "Usage:"
echo " hack/init-e2e-environment.sh [-h]"
echo " h: print help information"
}

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

# 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: prepare and copy the newest crds for karmadactl init
# step2.1: prepare the newest crds for karmadactl init
echo "Prepare the newest crds for karmadactl init"
cd charts/karmada/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For robustness, it's better to use an absolute path constructed from ${REPO_ROOT} to avoid issues with the script's execution directory. This makes the script less dependent on the current working directory.

Suggested change
cd charts/karmada/
cd "${REPO_ROOT}"/charts/karmada/

cp -r _crds crds
tar -zcvf ../../crds.tar.gz crds

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The temporary crds directory created by cp -r _crds crds is not removed after the tarball is created. This leaves artifacts in the source tree. It's good practice to clean up temporary files and directories.

Suggested change
tar -zcvf ../../crds.tar.gz crds
tar -zcvf ../../crds.tar.gz crds
rm -rf crds

cd -

# step2.2: Verify CRDs package is created successfully
if [ ! -f "./crds.tar.gz" ]; then
echo "ERROR: Failed to create CRDs package at ./crds.tar.gz"
exit 1
fi
echo "CRDs package created successfully: ./crds.tar.gz"

# step2.3: Copy the local crds.tar.gz file to the specified path
DATA_DIR="${HOME}/karmada-data"
mkdir -p "${DATA_DIR}"
cp ./crds.tar.gz "${DATA_DIR}/crds.tar.gz"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The crds.tar.gz file is left in the repository root after being copied. It should be cleaned up to avoid polluting the source tree.

Suggested change
cp ./crds.tar.gz "${DATA_DIR}/crds.tar.gz"
cp ./crds.tar.gz "${DATA_DIR}/crds.tar.gz"
rm ./crds.tar.gz


echo "Environment is ready for running karmadactl init e2e tests."
145 changes: 145 additions & 0 deletions hack/run-e2e-init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/usr/bin/env bash
# Copyright 2020 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 init e2e test against a blank cluster to test karmadactl init functionality.
# You should prepare your environment in advance and following environment may be you need to set or use default one.
# - HOST_CLUSTER_KUBECONFIG: absolute path of host cluster KUBECONFIG file.
#
# Usage: hack/run-e2e-init.sh
# Example 1: hack/run-e2e-init.sh (run init e2e with default config)
# Example 2: export HOST_CLUSTER_KUBECONFIG=<KUBECONFIG PATH> hack/run-e2e-init.sh (run init e2e with your KUBECONFIG)


KUBECONFIG_PATH=${KUBECONFIG_PATH:-"${HOME}/.kube"}
HOST_CLUSTER_KUBECONFIG=${HOST_CLUSTER_KUBECONFIG:-"$KUBECONFIG_PATH/karmada.config"}
DATA_DIR=${DATA_DIR:-"${HOME}/karmada-data"}
VERSION="latest"
REGISTRY="docker.io/karmada"

# KARMADA_RUNNING_ON_KIND indicates if current testing against on karmada that installed on a kind cluster.
# Defaults to true.
# For kind cluster, the kind related logs will be collected after the testing.
KARMADA_RUNNING_ON_KIND=${KARMADA_RUNNING_ON_KIND:-true}

KARMADA_HOST_CLUSTER_NAME=${KARMADA_HOST_CLUSTER_NAME:-"karmada-host"}

ARTIFACTS_PATH=${ARTIFACTS_PATH:-"${HOME}/karmada-e2e-init-logs"}
mkdir -p "$ARTIFACTS_PATH"

# Install ginkgo
GO111MODULE=on go install github.com/onsi/ginkgo/v2/ginkgo

# Run init e2e
export KUBECONFIG=${HOST_CLUSTER_KUBECONFIG}
export CRDs_PATH=${CRDs_PATH:-"${DATA_DIR}/crds.tar.gz"}
export KARMADA_AGGREGATED_APISERVER_IMAGE=${KARMADA_AGGREGATED_APISERVER_IMAGE:-"${REGISTRY}/karmada-aggregated-apiserver:${VERSION}"}
export KARMADA_CONTROLLER_MANAGER_IMAGE=${KARMADA_CONTROLLER_MANAGER_IMAGE:-"${REGISTRY}/karmada-controller-manager:${VERSION}"}
export KARMADA_SCHEDULER_IMAGE=${KARMADA_SCHEDULER_IMAGE:-"${REGISTRY}/karmada-scheduler:${VERSION}"}
export KARMADA_WEBHOOK_IMAGE=${KARMADA_WEBHOOK_IMAGE:-"${REGISTRY}/karmada-webhook:${VERSION}"}
set +e
ginkgo -v --race --trace --fail-fast -p --randomize-all ./test/e2e/suites/init -- --host-context=${KARMADA_HOST_CLUSTER_NAME}
TESTING_RESULT=$?

# Collect logs
echo "Collect logs to $ARTIFACTS_PATH..."
cp "$HOST_CLUSTER_KUBECONFIG" "$ARTIFACTS_PATH"

if [ "$KARMADA_RUNNING_ON_KIND" = true ]; then
echo "Collecting $KARMADA_HOST_CLUSTER_NAME logs..."
mkdir -p "$ARTIFACTS_PATH/$KARMADA_HOST_CLUSTER_NAME"
kind export logs --name="$KARMADA_HOST_CLUSTER_NAME" "$ARTIFACTS_PATH/$KARMADA_HOST_CLUSTER_NAME"
fi

echo "Collected logs at $ARTIFACTS_PATH:"
ls -al "$ARTIFACTS_PATH"

# If E2E test failed, exit directly with the test result
if [ $TESTING_RESULT -ne 0 ]; then
echo "Init E2E test failed with exit code $TESTING_RESULT, skipping component restart check."
exit $TESTING_RESULT
fi

# Check if Karmada components have restarted, if any has, it means that OOM or panic has occurred
# due to memory modification, and needs to be investigated.
echo "Init E2E run successfully."
echo "Checking if Karmada components have restarted after init..."

# Function to check pod restart count for a given component
check_component_restart() {
local component_label=$1
local component_name=$2

echo "Checking ${component_name} pods..."

# Get pod information in a single call, including both name and restart count
# Use a template that handles missing containerStatuses gracefully
local pod_info
pod_info=$(kubectl --context="${KARMADA_HOST_CLUSTER_NAME}" get pod -n karmada-system -l "${component_label}" \
-o go-template='{{range .items}}{{.metadata.name}}:{{if .status.containerStatuses}}{{(index .status.containerStatuses 0).restartCount}}{{else}}0{{end}}{{"\n"}}{{end}}' 2>/dev/null)

if [ -z "$pod_info" ]; then
echo "No pods found for ${component_name}, skipping..."
return 0
fi

# Process each pod's information
while IFS=: read -r pod_name restart_count; do
# Skip empty lines
[ -z "$pod_name" ] && continue

# Ensure restart_count is a number (default to 0 if empty or invalid)
if ! [[ "$restart_count" =~ ^[0-9]+$ ]]; then
echo "Warning: Unable to get restart count for pod $pod_name, assuming 0"
restart_count=0
fi

if [ "$restart_count" -gt 0 ]; then
echo "ERROR: ${component_name} pod $pod_name has restarted $restart_count times."
echo "This indicates OOM or panic occurred and needs to be investigated."
return 1 # Return failure to stop checking
else
echo "${component_name} pod $pod_name: no restarts"
fi
done <<< "$pod_info"

return 0
}

# List of basic components that should be running after karmadactl init
components=(
"app=etcd:etcd"
"app=karmada-apiserver:karmada-apiserver"
"app=karmada-aggregated-apiserver:karmada-aggregated-apiserver"
"app=kube-controller-manager:kube-controller-manager"
"app=karmada-controller-manager:karmada-controller-manager"
"app=karmada-scheduler:karmada-scheduler"
"app=karmada-webhook:karmada-webhook"
)

# Check each component, stop at first failure
for component in "${components[@]}"; do
IFS=':' read -r label name <<< "$component"
if ! check_component_restart "$label" "$name"; then
echo "COMPONENT RESTART CHECK FAILED: Component $name has restarted, stopping further checks."
exit 1
fi
done

echo "All component restart checks passed."
exit $TESTING_RESULT
1 change: 0 additions & 1 deletion hack/run-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
# Run e2e
export KUBECONFIG=${KARMADA_APISERVER_KUBECONFIG}
export PULL_BASED_CLUSTERS=${PULL_BASED_CLUSTERS}

set +e
ginkgo -v --race --trace --fail-fast -p --randomize-all ./test/e2e/suites/base -- --karmada-context=karmada-apiserver
TESTING_RESULT=$?
Expand Down
44 changes: 43 additions & 1 deletion pkg/karmadactl/cmdinit/cmdinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,42 @@ var (
%[1]s init --cert-external-ip 10.235.1.2 --cert-external-dns www.karmada.io

# Install Karmada using a configuration file
%[1]s init --config /path/to/your/config/file.yaml`)
%[1]s init --config /path/to/your/config/file.yaml

# Pass extra arguments to Local Etcd. (Parameters are separated by commas)
%[1]s init --etcd-extra-args="--snapshot-count=5000,--heartbeat-interval=100"
# Or write them separately.
%[1]s init --etcd-extra-args="--snapshot-count=5000" --etcd-extra-args="--heartbeat-interval=100"

# Pass extra arguments to Karmada API Server. (Parameters are separated by commas)
%[1]s init --karmada-apiserver-extra-args="--tls-min-version=VersionTLS12,--audit-log-path=-"
# Or write them separately.
%[1]s init --karmada-apiserver-extra-args="--tls-min-version=VersionTLS12" --karmada-apiserver-extra-args="--audit-log-path=-"

# Pass extra arguments to Karmada Scheduler. (Parameters are separated by commas)
%[1]s init --karmada-scheduler-extra-args="--scheduler-name=test-scheduler,--enable-pprof"
# Or write them separately.
%[1]s init --karmada-scheduler-extra-args="--scheduler-name=test-scheduler" --karmada-scheduler-extra-args="--enable-pprof"

# Pass extra arguments to Kube Controller Manager. (Parameters are separated by commas)
%[1]s init --kube-controller-manager-extra-args="--node-monitor-grace-period=50s,--node-monitor-period=5s"
# Or write them separately.
%[1]s init --kube-controller-manager-extra-args="--node-monitor-grace-period=50s" --kube-controller-manager-extra-args="--node-monitor-period=5s"

# Pass extra arguments to Karmada Controller Manager. (Parameters are separated by commas)
%[1]s init --karmada-controller-manager-extra-args="--v=2,--enable-pprof"
# Or write them separately.
%[1]s init --karmada-controller-manager-extra-args="--v=2" --karmada-controller-manager-extra-args="--enable-pprof"

# Pass extra arguments to Karmada Webhook. (Parameters are separated by commas)
%[1]s init --karmada-webhook-extra-args="--v=2,--enable-pprof"
# Or write them separately.
%[1]s init --karmada-webhook-extra-args="--v=2" --karmada-webhook-extra-args="--enable-pprof"

# Pass extra arguments to Karmada Aggregated API Server. (Parameters are separated by commas)
%[1]s init --karmada-aggregated-apiserver-extra-args="--v=4,--enable-pprof"
# Or write them separately.
%[1]s init --karmada-aggregated-apiserver-extra-args="--v=4" --karmada-aggregated-apiserver-extra-args="--enable-pprof"`)
)

// NewCmdInit install Karmada on Kubernetes
Expand Down Expand Up @@ -151,6 +186,7 @@ func NewCmdInit(parentCommand string) *cobra.Command {
flags.StringVar(&opts.ExternalEtcdServers, "external-etcd-servers", "", "The server urls of external etcd cluster, to be used by kube-apiserver through --etcd-servers.")
flags.StringVar(&opts.ExternalEtcdKeyPrefix, "external-etcd-key-prefix", "", "The key prefix to be configured to kube-apiserver through --etcd-prefix.")
flags.StringVar(&opts.EtcdPriorityClass, "etcd-priority-class", "system-node-critical", "The priority class name for the component etcd.")
flags.StringSliceVar(&opts.EtcdExtraArgs, "etcd-extra-args", nil, "Additional command line arguments to pass to the etcd component. Can be specified multiple times or as comma-separated values (e.g., '--snapshot-count=5000,--heartbeat-interval=100')")
// karmada
flags.StringVar(&opts.CRDs, "crds", kubernetes.DefaultCrdURL, "Karmada crds resource.(local file e.g. --crds /root/crds.tar.gz)")
flags.StringVar(&opts.KarmadaInitFilePath, "config", "", "Karmada init file path")
Expand All @@ -163,26 +199,32 @@ func NewCmdInit(parentCommand string) *cobra.Command {
flags.StringVarP(&opts.KarmadaAPIServerImage, "karmada-apiserver-image", "", "", "Kubernetes apiserver image")
flags.Int32VarP(&opts.KarmadaAPIServerReplicas, "karmada-apiserver-replicas", "", 1, "Karmada apiserver replica set")
flags.StringVar(&opts.KarmadaAPIServerPriorityClass, "karmada-apiserver-priority-class", "system-node-critical", "The priority class name for the component karmada-apiserver.")
flags.StringSliceVar(&opts.KarmadaAPIServerExtraArgs, "karmada-apiserver-extra-args", nil, "Additional command line arguments to pass to the karmada-apiserver component. Can be specified multiple times or as comma-separated values (e.g., '--tls-min-version=VersionTLS12,--audit-log-path=-')")
// karmada-scheduler
flags.StringVarP(&opts.KarmadaSchedulerImage, "karmada-scheduler-image", "", kubernetes.DefaultKarmadaSchedulerImage, "Karmada scheduler image")
flags.Int32VarP(&opts.KarmadaSchedulerReplicas, "karmada-scheduler-replicas", "", 1, "Karmada scheduler replica set")
flags.StringVar(&opts.KarmadaSchedulerPriorityClass, "karmada-scheduler-priority-class", "system-node-critical", "The priority class name for the component karmada-scheduler.")
flags.StringSliceVar(&opts.KarmadaSchedulerExtraArgs, "karmada-scheduler-extra-args", nil, "Additional command line arguments to pass to the karmada-scheduler component. Can be specified multiple times or as comma-separated values (e.g., '--scheduler-name=test-scheduler,--enable-pprof')")
// karmada-kube-controller-manager
flags.StringVarP(&opts.KubeControllerManagerImage, "karmada-kube-controller-manager-image", "", "", "Kubernetes controller manager image")
flags.Int32VarP(&opts.KubeControllerManagerReplicas, "karmada-kube-controller-manager-replicas", "", 1, "Karmada kube controller manager replica set")
flags.StringVar(&opts.KubeControllerManagerPriorityClass, "karmada-kube-controller-manager-priority-class", "system-node-critical", "The priority class name for the component karmada-kube-controller-manager.")
flags.StringSliceVar(&opts.KubeControllerManagerExtraArgs, "kube-controller-manager-extra-args", nil, "Additional command line arguments to pass to the kube-controller-manager component. Can be specified multiple times or as comma-separated values (e.g., '--node-monitor-grace-period=50s,--node-monitor-period=5s')")
// karamda-controller-manager
flags.StringVarP(&opts.KarmadaControllerManagerImage, "karmada-controller-manager-image", "", kubernetes.DefaultKarmadaControllerManagerImage, "Karmada controller manager image")
flags.Int32VarP(&opts.KarmadaControllerManagerReplicas, "karmada-controller-manager-replicas", "", 1, "Karmada controller manager replica set")
flags.StringVar(&opts.KarmadaControllerManagerPriorityClass, "karmada-controller-manager-priority-class", "system-node-critical", "The priority class name for the component karmada-controller-manager.")
flags.StringSliceVar(&opts.KarmadaControllerManagerExtraArgs, "karmada-controller-manager-extra-args", nil, "Additional command line arguments to pass to the karmada-controller-manager component. Can be specified multiple times or as comma-separated values (e.g., '--v=2,--enable-pprof')")
// karmada-webhook
flags.StringVarP(&opts.KarmadaWebhookImage, "karmada-webhook-image", "", kubernetes.DefaultKarmadaWebhookImage, "Karmada webhook image")
flags.Int32VarP(&opts.KarmadaWebhookReplicas, "karmada-webhook-replicas", "", 1, "Karmada webhook replica set")
flags.StringVar(&opts.KarmadaWebhookPriorityClass, "karmada-webhook-priority-class", "system-node-critical", "The priority class name for the component karmada-webhook.")
flags.StringSliceVar(&opts.KarmadaWebhookExtraArgs, "karmada-webhook-extra-args", nil, "Additional command line arguments to pass to the karmada-webhook component. Can be specified multiple times or as comma-separated values (e.g., '--v=2,--enable-pprof')")
// karmada-aggregated-apiserver
flags.StringVarP(&opts.KarmadaAggregatedAPIServerImage, "karmada-aggregated-apiserver-image", "", kubernetes.DefaultKarmadaAggregatedAPIServerImage, "Karmada aggregated apiserver image")
flags.Int32VarP(&opts.KarmadaAggregatedAPIServerReplicas, "karmada-aggregated-apiserver-replicas", "", 1, "Karmada aggregated apiserver replica set")
flags.StringVar(&opts.KarmadaAggregatedAPIServerPriorityClass, "karmada-aggregated-apiserver-priority-class", "system-node-critical", "The priority class name for the component karmada-aggregated-apiserver.")
flags.StringSliceVar(&opts.KarmadaAggregatedAPIServerExtraArgs, "karmada-aggregated-apiserver-extra-args", nil, "Additional command line arguments to pass to the karmada-aggregated-apiserver component. Can be specified multiple times or as comma-separated values (e.g., '--v=4,--enable-pprof')")

return cmd
}
Expand Down
Loading