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
7 changes: 7 additions & 0 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,18 @@ jobs:
- name: Install helm
uses: azure/setup-helm@v4.3.0

# func CLI is needed in some e2e tests ATM
- name: Install func cli
uses: functions-dev/action@main

- name: Setup KinD cluster
run: make create-kind-cluster

- name: Install func-operator
run: make docker-build docker-push deploy

- name: Running Test e2e
env:
REGISTRY_INSECURE: true
REGISTRY: kind-registry:5000
run: make test-e2e
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,7 @@ go.work.sum
.idea/
.vscode/

bin/
bin/

# Local registry certificates
hack/registry-certs/
35 changes: 32 additions & 3 deletions hack/create-kind-cluster.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,31 @@ function setup_local_registry() {
fi

if [ "$(docker inspect -f '{{.State.Running}}' "${REGISTRY_NAME}" 2>/dev/null || true)" != 'true' ]; then
header_text "create registry container for port ${REGISTRY_PORT}"
docker run -d --restart=always -p "127.0.0.1:${REGISTRY_PORT}:5000" --name "${REGISTRY_NAME}" docker.io/registry:2
header_text "create registry container for port ${REGISTRY_PORT} with HTTPS"

# Create persistent directory for registry certs in project
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REGISTRY_CERTS_DIR="${SCRIPT_DIR}/registry-certs"
mkdir -p "${REGISTRY_CERTS_DIR}"

# Generate self-signed certificate if it doesn't exist
if [ ! -f "${REGISTRY_CERTS_DIR}/registry.crt" ]; then
header_text "Generating self-signed certificate for registry"
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout "${REGISTRY_CERTS_DIR}/registry.key" \
-x509 -days 365 -out "${REGISTRY_CERTS_DIR}/registry.crt" \
-subj "/CN=${REGISTRY_NAME}" \
-addext "subjectAltName=DNS:kind-registry,DNS:localhost,IP:127.0.0.1"
fi

# Run registry with HTTPS
docker run -d --restart=always \
-p "127.0.0.1:${REGISTRY_PORT}:5000" \
-v "${REGISTRY_CERTS_DIR}:/certs" \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/registry.key \
--name "${REGISTRY_NAME}" \
docker.io/registry:2
fi
}

Expand All @@ -61,7 +84,7 @@ nodes:
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:$REGISTRY_PORT"]
endpoint = ["http://$REGISTRY_NAME:5000"]
endpoint = ["https://$REGISTRY_NAME:5000"]
EOF
}

Expand All @@ -84,6 +107,12 @@ data:
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF

# Install registry certificate on all nodes
header_text "Installing registry certificate on cluster nodes"
for node in $(kind get nodes --name "$CLUSTER_NAME"); do
docker exec "$REGISTRY_NAME" cat /certs/registry.crt | docker exec -i "$node" bash -c 'mkdir -p /usr/local/share/ca-certificates && cat > /usr/local/share/ca-certificates/kind-registry.crt && update-ca-certificates'
docker exec "$node" systemctl restart containerd
done
}

function install_tekton() {
Expand Down
7 changes: 5 additions & 2 deletions internal/funccli/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,14 @@ func (m *managerImpl) Deploy(ctx context.Context, repoPath string, namespace str
"--registry", opts.Registry,
"--git-url", opts.GitUrl,
"--builder", opts.Builder,
"--registry-authfile", opts.RegistryAuthFile,
}

if opts.RegistryAuthFile != "" {
deployArgs = append(deployArgs, "--registry-authfile", opts.RegistryAuthFile)
}

if opts.InsecureRegistry {
deployArgs = append(deployArgs, "--insecure-registry")
deployArgs = append(deployArgs, "--registry-insecure")
}

out, err := m.Run(ctx, repoPath, deployArgs...)
Expand Down
47 changes: 47 additions & 0 deletions test/e2e/e2e_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,27 @@ limitations under the License.
package e2e

import (
"context"
"fmt"
"os"
"strings"
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"

functionsdevv1alpha1 "github.com/functions-dev/func-operator/api/v1alpha1"
)

var (
k8sClient client.Client
ctx context.Context

registry string
registryInsecure bool
)

// TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated,
Expand All @@ -33,3 +49,34 @@ func TestE2E(t *testing.T) {
_, _ = fmt.Fprintf(GinkgoWriter, "Starting func-operator integration test suite\n")
RunSpecs(t, "e2e suite")
}

var _ = BeforeSuite(func() {
ctx = context.Background()

// Register the Function API scheme
err := functionsdevv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())

// Load kubeconfig and create client
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
configOverrides := &clientcmd.ConfigOverrides{}
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)

cfg, err := kubeConfig.ClientConfig()
Expect(err).NotTo(HaveOccurred())

k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())

// Setup vars from env
registry = os.Getenv("REGISTRY")
if registry == "" {
registry = "kind-registry:5000"
}

registryInsecure = false
if sec := os.Getenv("REGISTRY_INSECURE"); strings.ToLower(sec) == "true" {
registryInsecure = true
}
})
119 changes: 60 additions & 59 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,37 +121,46 @@ var _ = Describe("Manager", Ordered, func() {
Eventually(verifyControllerUp).Should(Succeed())
})

It("should ensure the metrics endpoint is serving metrics", func() {
By("validating that the metrics service is available")
cmd := exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace)
_, err := utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Metrics service should exist")

By("waiting for the metrics endpoint to be ready")
verifyMetricsEndpointReady := func(g Gomega) {
cmd := exec.Command("kubectl", "get", "endpoints", metricsServiceName, "-n", namespace)
output, err := utils.Run(cmd)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(ContainSubstring(metricsPort), "Metrics endpoint is not ready")
}
Eventually(verifyMetricsEndpointReady).Should(Succeed())

By("verifying that the controller manager is serving the metrics server")
verifyMetricsServerStarted := func(g Gomega) {
cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace)
output, err := utils.Run(cmd)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(ContainSubstring("controller-runtime.metrics\tServing metrics server"),
"Metrics server not yet started")
}
Eventually(verifyMetricsServerStarted).Should(Succeed())

By("creating the curl-metrics pod to access the metrics endpoint")
cmd = exec.Command("kubectl", "run", "curl-metrics", "--restart=Never",
"--namespace", namespace,
"--image=curlimages/curl:latest",
"--overrides",
fmt.Sprintf(`{
Context("with curl-metrics-pod", func() {
curlMetricPodName := "curl-metrics"

AfterEach(func() {
cmd := exec.Command("kubectl", "delete", "pod", curlMetricPodName, "-n", namespace, "--ignore-not-found")
_, err := utils.Run(cmd)
Expect(err).NotTo(HaveOccurred())
})

It("should ensure the metrics endpoint is serving metrics", func() {
By("validating that the metrics service is available")
cmd := exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace)
_, err := utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Metrics service should exist")

By("waiting for the metrics endpoint to be ready")
verifyMetricsEndpointReady := func(g Gomega) {
cmd := exec.Command("kubectl", "get", "endpoints", metricsServiceName, "-n", namespace)
output, err := utils.Run(cmd)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(ContainSubstring(metricsPort), "Metrics endpoint is not ready")
}
Eventually(verifyMetricsEndpointReady).Should(Succeed())

By("verifying that the controller manager is serving the metrics server")
verifyMetricsServerStarted := func(g Gomega) {
cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace)
output, err := utils.Run(cmd)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(ContainSubstring("controller-runtime.metrics\tServing metrics server"),
"Metrics server not yet started")
}
Eventually(verifyMetricsServerStarted).Should(Succeed())

By("creating the curl-metrics pod to access the metrics endpoint")
cmd = exec.Command("kubectl", "run", curlMetricPodName, "--restart=Never",
"--namespace", namespace,
"--image=curlimages/curl:latest",
"--overrides",
fmt.Sprintf(`{
"spec": {
"containers": [{
"name": "curl",
Expand All @@ -173,37 +182,29 @@ var _ = Describe("Manager", Ordered, func() {
"serviceAccount": "%s"
}
}`, metricsServiceName, namespace, metricsPort, serviceAccountName))
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to create curl-metrics pod")

By("waiting for the curl-metrics pod to complete.")
verifyCurlUp := func(g Gomega) {
cmd := exec.Command("kubectl", "get", "pods", "curl-metrics",
"-o", "jsonpath={.status.phase}",
"-n", namespace)
output, err := utils.Run(cmd)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(Equal("Succeeded"), "curl pod in wrong status")
}
Eventually(verifyCurlUp, 5*time.Minute).Should(Succeed())

By("getting the metrics by checking curl-metrics logs")
metricsOutput := getMetricsOutput()
Expect(metricsOutput).To(ContainSubstring(
"controller_runtime_reconcile_total",
))
_, err = utils.Run(cmd)
Expect(err).NotTo(HaveOccurred(), "Failed to create curl-metrics pod")

By("waiting for the curl-metrics pod to complete.")
verifyCurlUp := func(g Gomega) {
cmd := exec.Command("kubectl", "get", "pods", curlMetricPodName,
"-o", "jsonpath={.status.phase}",
"-n", namespace)
output, err := utils.Run(cmd)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(output).To(Equal("Succeeded"), "curl pod in wrong status")
}
Eventually(verifyCurlUp, 5*time.Minute).Should(Succeed())

By("getting the metrics by checking curl-metrics logs")
metricsOutput := getMetricsOutput()
Expect(metricsOutput).To(ContainSubstring(
"controller_runtime_reconcile_total",
))
})
})

// +kubebuilder:scaffold:e2e-webhooks-checks

// TODO: Customize the e2e test suite with scenarios specific to your project.
// Consider applying sample/CR(s) and check their status and/or verifying
// the reconciliation by using the metrics, i.e.:
// metricsOutput := getMetricsOutput()
// Expect(metricsOutput).To(ContainSubstring(
// fmt.Sprintf(`controller_runtime_reconcile_total{controller="%s",result="success"} 1`,
// strings.ToLower(<Kind>),
// ))
})
})

Expand Down
Loading
Loading