Skip to content

Commit

Permalink
Add e2e tests
Browse files Browse the repository at this point in the history
This adds a test suite for e2e tests. So far there is only a few tests
related to inspection, but it should be enough to validate the approach.

My hope is that this framework will be flexible enough to allow tests
both in CI, using VMs, and on actual hardware. The tests can be
configured through a config file. They can run on an existing cluster or
set up a temporary kind cluster automatically. Similarly, BMO, Ironic
and Cert-manager can all be deployed or not depending on configuration.

Logs are collected for BMO and Ironic when deployed automatically, even
in existing clusters.
  • Loading branch information
lentzi90 committed Sep 20, 2023
1 parent c8d5941 commit ab47a4b
Show file tree
Hide file tree
Showing 25 changed files with 2,057 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Temporary Build Files
# Temporary Build/Output Files
bin
build/_output
build/_test
_artifacts
# Created by https://www.gitignore.io/api/go
### Go ###
# Binaries for programs and plugins
Expand Down
12 changes: 12 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ issues:
- linters:
- staticcheck
text: "SA1019:"
# Dot imports for gomega and ginkgo are allowed
# within test files and test utils.
- linters:
- revive
- stylecheck
path: _test\.go
text: should not use dot imports
- linters:
- revive
- stylecheck
path: (e2e)/.*.go
text: should not use dot imports
50 changes: 49 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ DEBUG = --debug
COVER_PROFILE = cover.out
GO_VERSION ?= 1.20.6

ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

# CRD Generation Options
#
# allowDangerousTypes=true lets use the float64 field for clock speeds
Expand All @@ -19,6 +21,8 @@ BIN_DIR := bin
CRD_OPTIONS ?= "crd:allowDangerousTypes=true,crdVersions=v1"
KUSTOMIZE = tools/bin/kustomize
CONTROLLER_GEN = tools/bin/controller-gen
GINKGO = tools/bin/ginkgo
GINKGO_VER = v2.11.0

# See pkg/version.go for details
SOURCE_GIT_COMMIT ?= $(shell git rev-parse --short HEAD)
Expand All @@ -38,6 +42,25 @@ export IRONIC_INSPECTOR_ENDPOINT=http://localhost:5050/v1/
export GO111MODULE=on
export GOFLAGS=

#
# Ginkgo configuration.
#
GINKGO_FOCUS ?=
GINKGO_SKIP ?=
GINKGO_NODES ?= 1
GINKGO_TIMEOUT ?= 2h
GINKGO_POLL_PROGRESS_AFTER ?= 60m
GINKGO_POLL_PROGRESS_INTERVAL ?= 5m
E2E_CONF_FILE ?= $(ROOT_DIR)/test/e2e/config/ironic.yaml
USE_EXISTING_CLUSTER ?= true
SKIP_RESOURCE_CLEANUP ?= false
GINKGO_NOCOLOR ?= false

# to set multiple ginkgo skip flags, if any
ifneq ($(strip $(GINKGO_SKIP)),)
_SKIP_ARGS := $(foreach arg,$(strip $(GINKGO_SKIP)),-skip="$(arg)")
endif

.PHONY: help
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
Expand Down Expand Up @@ -80,6 +103,17 @@ unit-cover: ## Run unit tests with code coverage
unit-verbose: ## Run unit tests with verbose output
TEST_FLAGS=-v make unit

ARTIFACTS ?= ${ROOT_DIR}/test/e2e/_artifacts

.PHONY: test-e2e
test-e2e: $(GINKGO) ## Run the end-to-end tests
$(GINKGO) -v --trace -poll-progress-after=$(GINKGO_POLL_PROGRESS_AFTER) \
-poll-progress-interval=$(GINKGO_POLL_PROGRESS_INTERVAL) --tags=e2e --focus="$(GINKGO_FOCUS)" \
$(_SKIP_ARGS) --nodes=$(GINKGO_NODES) --timeout=$(GINKGO_TIMEOUT) --no-color=$(GINKGO_NOCOLOR) \
--output-dir="$(ARTIFACTS)" --junit-report="junit.e2e_suite.1.xml" $(GINKGO_ARGS) test/e2e -- \
-e2e.config="$(E2E_CONF_FILE)" -e2e.use-existing-cluster=$(USE_EXISTING_CLUSTER) \
-e2e.skip-resource-cleanup=$(SKIP_RESOURCE_CLEANUP) -e2e.artifacts-folder="$(ARTIFACTS)"

## --------------------------------------
## Linter Targets
## --------------------------------------
Expand All @@ -93,6 +127,7 @@ tools/bin/golangci-lint: hack/tools/go.mod
.PHONY: lint
lint: tools/bin/golangci-lint
$< run
cd test; ../$< run

.PHONY: manifest-lint
manifest-lint: ## Run manifest validation
Expand All @@ -103,7 +138,7 @@ manifest-lint: ## Run manifest validation
## --------------------------------------

.PHONY: build
build: generate manifests manager tools ## Build everything
build: generate manifests manager tools build-e2e ## Build everything

.PHONY: manager
manager: generate lint ## Build manager binary
Expand Down Expand Up @@ -140,6 +175,10 @@ $(CONTROLLER_GEN): hack/tools/go.mod
$(KUSTOMIZE): hack/tools/go.mod
cd hack/tools; go build -o $(abspath $@) sigs.k8s.io/kustomize/kustomize/v4

.PHONY: build-e2e
build-e2e:
cd test; go build ./...

.PHONY: manifests
manifests: manifests-generate manifests-kustomize ## Generate manifests e.g. CRD, RBAC etc.

Expand Down Expand Up @@ -235,6 +274,9 @@ tools:
go build -o bin/make-bm-worker cmd/make-bm-worker/main.go
go build -o bin/make-virt-host cmd/make-virt-host/main.go

$(GINKGO): ## Install ginkgo in tools/bin
GOBIN=$(abspath tools/bin) go install github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VER)

## --------------------------------------
## Tilt / Kind
## --------------------------------------
Expand Down Expand Up @@ -265,6 +307,8 @@ mod: ## Clean up go module settings
cd pkg/hardwareutils; go mod verify
cd hack/tools; go mod tidy
cd hack/tools; go mod verify
cd test; go mod tidy
cd test; go mod verify

## --------------------------------------
## Release
Expand All @@ -290,3 +334,7 @@ go-version: ## Print the go version we use to compile our binaries and images
.PHONY: clean
clean: ## Remove all temporary files and folders
rm -rf ironic-deployment/overlays/temp

.PHONY: clean-e2e
clean-e2e: ## Remove everything related to e2e tests
./hack/clean-e2e.sh
10 changes: 10 additions & 0 deletions config/overlays/e2e/ironic.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP_PORT=6180
PROVISIONING_IP=192.168.222.199
DEPLOY_KERNEL_URL=http://192.168.222.199:6180/images/ironic-python-agent.kernel
DEPLOY_RAMDISK_URL=http://192.168.222.199:6180/images/ironic-python-agent.initramfs
IRONIC_ENDPOINT=http://192.168.222.199:6385/v1/
IRONIC_INSPECTOR_ENDPOINT=http://192.168.222.199:5050/v1/
CACHEURL=http://192.168.222.199/images
IRONIC_FAST_TRACK=true
IRONIC_KERNEL_PARAMS=console=ttyS0
IRONIC_INSPECTOR_VLAN_INTERFACES=all
26 changes: 26 additions & 0 deletions config/overlays/e2e/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../namespace
- ../../default

configMapGenerator:
- behavior: replace
envs:
- ironic.env
name: ironic

patches:
- patch: |
# Don't try to pull again the pre-loaded image
- op: replace
path: /spec/template/spec/containers/0/imagePullPolicy
value: IfNotPresent
target:
kind: Deployment
name: controller-manager

images:
- name: quay.io/metal3-io/baremetal-operator
newTag: e2e
24 changes: 24 additions & 0 deletions config/overlays/fixture/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../namespace
- ../../default

patches:
- patch: |
# Enable test mode (fixture provider instead of ironic)
- op: add
path: /spec/template/spec/containers/0/args/-
value: --test-mode
# Don't try to pull again the pre-loaded image
- op: replace
path: /spec/template/spec/containers/0/imagePullPolicy
value: IfNotPresent
target:
kind: Deployment
name: controller-manager

images:
- name: quay.io/metal3-io/baremetal-operator
newTag: e2e
2 changes: 1 addition & 1 deletion docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ We also need to create one or more tags for the Go modules ecosystem:
- For any subdirectory with `go.mod` in it (excluding `hack/tools`), create
another Git tag with directory prefix, ie.
`git tag -s apis/v0.x.y -m apis/v0.x.y`.
For BMO, these directories are `apis` and `pkg/hardwareutils`. This enables
For BMO, these directories are `apis`, `test` and `pkg/hardwareutils`. This enables
the tags to be used as a Go module version for any downstream users.
**NOTE**: Do not create annotated tags for Go modules. Release notes expects
only the main tag to be annotated, otherwise it might create incorrect
Expand Down
70 changes: 70 additions & 0 deletions hack/ci-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash

set -x
set -o nounset
set -o pipefail

REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
cd "${REPO_ROOT}" || exit 1

# Ensure requirements are installed
"${REPO_ROOT}/hack/e2e/ensure_go.sh"
export PATH=$PATH:/usr/local/go/bin
"${REPO_ROOT}/hack/e2e/ensure_minikube.sh"
"${REPO_ROOT}/hack/e2e/ensure_kubectl.sh"
"${REPO_ROOT}/hack/e2e/ensure_cmctl.sh"

# Build the container image with e2e tag (used in tests)
IMG=quay.io/metal3-io/baremetal-operator:e2e make docker

# Set up minikube
minikube start --driver=kvm2

virsh -c qemu:///system net-destroy baremetal-e2e
virsh -c qemu:///system net-define ${REPO_ROOT}/hack/e2e/net.xml
virsh -c qemu:///system net-start baremetal-e2e
# Attach baremetal-e2e interface to minikube with specific mac.
# This will give minikube a known reserved IP address that we can use for Ironic
virsh -c qemu:///system attach-interface --domain minikube --mac="52:54:00:6c:3c:01" \
--model virtio --source baremetal-e2e --type network --config

# Restart minikube to apply the changes
minikube stop
minikube start

# Load the BMO e2e image into it
minikube image load quay.io/metal3-io/baremetal-operator:e2e

# Start VBMC
docker run --name vbmc --network host -d \
-v /var/run/libvirt/libvirt-sock:/var/run/libvirt/libvirt-sock \
-v /var/run/libvirt/libvirt-sock-ro:/var/run/libvirt/libvirt-sock-ro \
quay.io/metal3-io/vbmc

# Create libvirt domain
NAME="bmo-e2e-0"
BOOT_MAC_ADDRESS="00:60:2f:31:81:01"
VBMC_PORT="16230"
virt-install --connect qemu:///system -n "${NAME}" --description "Virtualized BareMetalHost" --osinfo=ubuntu-lts-latest \
--ram=4096 --vcpus=2 --disk size=20 --graphics=none --console pty --serial pty --pxe \
--network network=baremetal-e2e,mac="${BOOT_MAC_ADDRESS}" --noautoconsole

# Add BMH VM to VBMC
docker exec vbmc vbmc add "${NAME}" --port "${VBMC_PORT}"
docker exec vbmc vbmc start "${NAME}"
docker exec vbmc vbmc list

# These variables are used by the tests. They override variables in the config file.
# This IP is defined by the network we created above.
# Together with the VBMC_PORT this becomes the BMC_ADDRESS used by the BMH in the test.
export BMC_ADDRESS="ipmi://192.168.222.1:${VBMC_PORT}"
export BOOT_MAC_ADDRESS
# These are the VBMC defaults (used since we did not specify anything else for `vbmc add`).
export BMC_USER=admin
export BMC_PASSWORD=password

# Run the e2e tests
make test-e2e

# Collect all artifacts
tar --directory test/e2e/ -czf artifacts.tar.gz _artifacts
13 changes: 13 additions & 0 deletions hack/clean-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
cd "${REPO_ROOT}" || exit 1

minikube delete
docker stop vbmc
docker rm vbmc
virsh destroy --domain bmo-e2e-0
virsh undefine --domain bmo-e2e-0 --remove-all-storage
virsh net-undefine baremetal-e2e

rm -rf "${REPO_ROOT}/test/e2e/_artifacts"
42 changes: 42 additions & 0 deletions hack/e2e/ensure_cmctl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

# GOPATH_BIN="$(go env GOPATH)/bin/"
GOPATH_BIN="/usr/local/bin/"
OS=$(go env GOOS)
ARCH=$(go env GOARCH)
MINIMUM_CMCTL_VERSION=v1.13.0

verify_cmctl_version() {
if ! [ -x "$(command -v cmctl)" ]; then
if [[ "${OSTYPE}" == "linux-gnu" ]]; then
if ! [ -d "${GOPATH_BIN}" ]; then
mkdir -p "${GOPATH_BIN}"
fi
echo 'cmctl not found, installing'
curl -fsSL -o cmctl.tar.gz https://github.com/cert-manager/cert-manager/releases/download/${MINIMUM_CMCTL_VERSION}/cmctl-${OS}-${ARCH}.tar.gz
tar xzf cmctl.tar.gz
sudo mv cmctl "${GOPATH_BIN}/cmctl"
rm cmctl.tar.gz
else
echo "Missing required binary in path: cmctl"
return 2
fi
fi

local cmctl_version
IFS=" " read -ra cmctl_version <<< "$(cmctl version --client --short)"
if [[ "${MINIMUM_CMCTL_VERSION}" != $(echo -e "${MINIMUM_CMCTL_VERSION}\n${cmctl_version[2]}" | sort -s -t. -k 1,1 -k 2,2n -k 3,3n | head -n1) ]]; then
cat << EOF
Detected cmctl version: ${cmctl_version[2]}.
Requires ${MINIMUM_CMCTL_VERSION} or greater.
Please install ${MINIMUM_CMCTL_VERSION} or later.
EOF
return 2
fi
}

verify_cmctl_version
38 changes: 38 additions & 0 deletions hack/e2e/ensure_go.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

MINIMUM_GO_VERSION=go1.20.8

# Ensure the go tool exists and is a viable version, or installs it
verify_go_version()
{
# If go is not available on the path, get it
if ! [ -x "$(command -v go)" ]; then
if [[ "${OSTYPE}" == "linux-gnu" ]]; then
echo 'go not found, installing'
curl -sLo "/tmp/${MINIMUM_GO_VERSION}.linux-amd64.tar.gz" "https://go.dev/dl/${MINIMUM_GO_VERSION}.linux-amd64.tar.gz"
sudo tar -C /usr/local -xzf "/tmp/${MINIMUM_GO_VERSION}.linux-amd64.tar.gz"
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
export PATH=$PATH:/usr/local/go/bin
else
echo "Missing required binary in path: go"
return 2
fi
fi

local go_version
IFS=" " read -ra go_version <<< "$(go version)"
if ! [[ "${MINIMUM_GO_VERSION}" =~ .*"${go_version[2]}".* ]]; then
cat << EOF
Detected go version: ${go_version[2]}.
Requires ${MINIMUM_GO_VERSION} or greater.
Please install ${MINIMUM_GO_VERSION} or later.
EOF
return 2
fi
}

verify_go_version
Loading

0 comments on commit ab47a4b

Please sign in to comment.