Skip to content
Merged
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
64 changes: 64 additions & 0 deletions .containerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Build artifacts
build/
dist/

# IDE and editor files
.idea/
.vscode/
*.swp
*.swo
*~

# Git files
.git/
.gitignore
.gitattributes

# Documentation (not needed in container)
docs/
*.md
!README.md

# Test files and test data
test/
*_test.go
testdata/

# Development and CI files
hack/
.github/
.gitlab-ci.yml
.travis.yml
.circleci/

# Python virtual environments
.venv/
venv/
__pycache__/
*.pyc

# Log files
*.log
opct.log

# Generated files
docs/CHANGELOG.md
docs/CHANGELOG_commits.md
docs/CHANGELOG_summary.md

# Configuration files not needed in container
kubeconfig
*.kubeconfig

# OS files
.DS_Store
Thumbs.db

# MkDocs build files
site/
.mkdocs/

# Temporary files
tmp/
temp/
*.tmp
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ build/
# See the make commands: 'build-changelog' and 'build-changelog-commmits'
docs/CHANGELOG.md
docs/CHANGELOG_commits.md
opct.log
101 changes: 97 additions & 4 deletions data/templates/plugins/openshift-kube-conformance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,91 @@ podSpec:
volumeMounts:
- mountPath: /tmp/shared
name: shared
- name: extract-k8s-conformance-tests
image: "{{ .OpenshiftTestsImage }}"
imagePullPolicy: Always
command:
- "/bin/bash"
- "-ec"
- |
set -o pipefail

# We want to skip the extraction on OCP early 4.20 releases,
# so that we can rely on the default suite.
DEFAULT_SUITE_NAME="${DEFAULT_SUITE_NAME:-kubernetes/conformance}"
if [ "${DEFAULT_SUITE_NAME}" == "kubernetes/conformance" ]; then
echo "Skipping extraction of Kubernetes conformance test list" \
"from OTE binary..."
exit 0
fi

echo "Extracting Kubernetes conformance test list from OTE binary..."

# Get the hyperkube image from the release
TESTS_IMAGE_K8S=$(
oc adm release info --image-for=hyperkube 2>/dev/null || echo ""
)

if [ -z "$TESTS_IMAGE_K8S" ]; then
echo "Warning: Unable to get hyperkube image"
echo " Will rely on default suite"
exit 0
fi

echo "Hyperkube image: $TESTS_IMAGE_K8S"

# Extract k8s-tests-ext binary
K8S_EXT_FILE="/usr/bin/k8s-tests-ext.gz"
K8S_EXT_PATH="$K8S_EXT_FILE:/tmp/shared/"
if ! oc image extract "$TESTS_IMAGE_K8S" \
--file="$K8S_EXT_FILE" \
--path="$K8S_EXT_PATH" 2>/dev/null; then
echo "Warning: Failed to extract k8s-tests-ext.gz"
echo " Will rely on default suite"
exit 0
fi

# Decompress and make executable
if [ -f /tmp/shared/k8s-tests-ext.gz ]; then
gunzip /tmp/shared/k8s-tests-ext.gz
chmod u+x /tmp/shared/k8s-tests-ext

# Extract conformance test list and save to file
echo "Extracting conformance tests list..."
OUT_FILE="/tmp/shared/k8s-conformance-tests.list"
JQ_FILTER='.[] | select(.name | contains("[Conformance]")).name'
/tmp/shared/k8s-tests-ext list \
| jq -r "$JQ_FILTER" > "$OUT_FILE" 2>/dev/null || {
echo "Warning: Failed to extract with jq, trying grep..."
JSON_FILE="/tmp/shared/k8s-conformance-tests.json"
/tmp/shared/k8s-tests-ext list > "$JSON_FILE"
GREP_PATTERN='"name":"[^"]*\[Conformance\][^"]*"'
grep -o "$GREP_PATTERN" "$JSON_FILE" \
| sed 's/"name":"//;s/"$//' > "$OUT_FILE" || {
echo "Warning: Failed to extract conformance tests"
echo " Will rely on default suite"
exit 0
}
}

TEST_COUNT=$(wc -l < /tmp/shared/k8s-conformance-tests.list)
echo "Extracted $TEST_COUNT conformance tests"

if [ "$TEST_COUNT" -gt 0 ]; then
echo "Kubernetes conformance test extraction successful"
fi
fi
env:
- name: KUBECONFIG
value: "/tmp/shared/kubeconfig"
- name: DEFAULT_SUITE_NAME
valueFrom:
configMapKeyRef:
name: plugins-config
key: suiteNameKubernetesConformance
volumeMounts:
- mountPath: /tmp/shared
name: shared
containers:
- name: tests
image: "{{ .OpenshiftTestsImage }}"
Expand All @@ -51,7 +136,10 @@ podSpec:
- name: KUBECONFIG
value: /tmp/shared/kubeconfig
- name: DEFAULT_SUITE_NAME
value: "kubernetes/conformance"
valueFrom:
configMapKeyRef:
name: plugins-config
key: suiteNameKubernetesConformance
- name: OT_RUN_COMMAND
value: "run"
- name: PLUGIN_NAME
Expand All @@ -64,9 +152,9 @@ sonobuoy-config:
description: |
OPCT plugin to schedule e2e tests using openshift-tests tool to validate
an OpenShift Container Platform cluster installed in a specific provider.
source-url:
"https://github.com/redhat-openshift-ecosystem/opct/\
blob/main/manifests/openshift-kube-conformance.yaml"
source-url: >-
https://github.com/redhat-openshift-ecosystem/opct/
blob/main/manifests/openshift-kube-conformance.yaml
skipCleanup: true
spec:
name: plugin
Expand Down Expand Up @@ -116,3 +204,8 @@ spec:
name: plugins-config
key: mirror-registry
optional: true
- name: DEFAULT_SUITE_NAME
valueFrom:
configMapKeyRef:
name: plugins-config
key: suiteNameKubernetesConformance
65 changes: 39 additions & 26 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,58 @@ import (
"k8s.io/client-go/tools/clientcmd"
)

func CreateRestConfig() (*rest.Config, error) {
kubeconfig := os.Getenv("KUBECONFIG")
if len(kubeconfig) == 0 {
kubeconfig = viper.GetString("kubeconfig")
if kubeconfig == "" {
return nil, fmt.Errorf("--kubeconfig or KUBECONFIG environment variable must be set")
}

// Check kubeconfig exists
if _, err := os.Stat(kubeconfig); err != nil {
return nil, fmt.Errorf("kubeconfig %q does not exists: %v", kubeconfig, err)
}
}

clientConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
return clientConfig, err
// Client is the interface to store kubernetes and sonobuoy client instances.
type Client struct {
// KClient is the kubernetes client instance.
KClient kubernetes.Interface
// SClient is the sonobuoy client instance.
SClient client.Interface
// RestConfig is the rest config for the kubernetes client.
RestConfig *rest.Config
}

// CreateClients creates kubernetes and sonobuoy client instances
func CreateClients() (kubernetes.Interface, client.Interface, error) {
clientConfig, err := CreateRestConfig()
// NewClient creates a new client instance.
func NewClient() (*Client, error) {
clientConfig, err := createRestConfig()
if err != nil {
return nil, nil, fmt.Errorf("error creating kube client config: %v", err)
return nil, fmt.Errorf("error creating rest config: %v", err)
}
cli := &Client{
RestConfig: clientConfig,
}

clientset, err := kubernetes.NewForConfig(clientConfig)
cli.KClient, err = kubernetes.NewForConfig(clientConfig)
if err != nil {
return nil, nil, fmt.Errorf("error creating kube client: %v", err)
return cli, fmt.Errorf("error creating kube client: %v", err)
}

skc, err := sonodynamic.NewAPIHelperFromRESTConfig(clientConfig)
if err != nil {
return nil, nil, fmt.Errorf("error creating sonobuoy rest helper: %v", err)
return cli, fmt.Errorf("error creating sonobuoy rest helper: %v", err)
}

sonobuoyClient, err := client.NewSonobuoyClient(clientConfig, skc)
cli.SClient, err = client.NewSonobuoyClient(clientConfig, skc)
if err != nil {
return nil, nil, fmt.Errorf("error creating sonobuoy client: %v", err)
return cli, fmt.Errorf("error creating sonobuoy client: %v", err)
}

return clientset, sonobuoyClient, nil
return cli, nil
}

func createRestConfig() (*rest.Config, error) {
kubeconfig := os.Getenv("KUBECONFIG")
if len(kubeconfig) == 0 {
kubeconfig = viper.GetString("kubeconfig")
if kubeconfig == "" {
return nil, fmt.Errorf("--kubeconfig or KUBECONFIG environment variable must be set")
}

// Check kubeconfig exists
if _, err := os.Stat(kubeconfig); err != nil {
return nil, fmt.Errorf("kubeconfig %q does not exists: %v", kubeconfig, err)
}
}

clientConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
return clientConfig, err
}
Loading