From a0c4ddee5f1f2552481f685fb7d16d9349c12820 Mon Sep 17 00:00:00 2001 From: Katia Aresti Date: Wed, 2 Oct 2024 11:33:44 +0200 Subject: [PATCH] Sets EXPOSE_SERVICE_HOST env variable Closes #2164 --- README.md | 191 ++++++++++++++++++++--------------- api/v1/types_util.go | 4 + infinispanOperator.png | Bin 0 -> 39843 bytes test/e2e/utils/common.go | 8 ++ test/e2e/utils/constants.go | 6 +- test/e2e/utils/kubernetes.go | 9 +- 6 files changed, 130 insertions(+), 88 deletions(-) create mode 100644 infinispanOperator.png diff --git a/README.md b/README.md index 163363b79..0583cf06a 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,58 @@ -# Infinispan Operator +# ![Infinispan Operator](./infinispanOperator.png) +[![License](https://img.shields.io/github/license/infinispan/infinispan?style=for-the-badge&logo=apache)](https://www.apache.org/licenses/LICENSE-2.0) +[![Project Chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg?style=for-the-badge&logo=zulip)](https://infinispan.zulipchat.com/) -This is a Kubernetes operator to manage Infinispan clusters. + +The **Infinispan Operator** is the official Kubernetes operator for managing Infinispan clusters. +It automates the deployment, scaling, and lifecycle management of Infinispan instances using Custom Resource Definitions (CRDs). +With the Infinispan Operator, users can easily create, configure, and monitor Infinispan distributed in-memory database in a +Kubernetes environment, ensuring high availability and resilience for their applications. ## System Requirements -* [go 1.21](https://github.com/golang/go) or higher. -* Docker | Podman +* [Golang 1.21](https://github.com/golang/go) or higher. +* [Docker](https://www.docker.com/) or [Podman](https://podman.io/) * [Operator SDK 1.24.1](https://github.com/operator-framework/operator-sdk/releases/tag/v1.24.1) -* A running Kubernetes cluster - -# Usage +* A running [Kubernetes](https://kubernetes.io/) cluster -For details on how to use the operator, please read the [official operator documentation](https://infinispan.org/docs/infinispan-operator/main/operator.html). +## Usage Documentation +For details on **how to use** the operator, please read the **[official Infinispan Operator documentation](https://infinispan.org/docs/infinispan-operator/main/operator.html)**. -# Getting Started -You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. -**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows). +# Developer Guide +This guide is intended for developers who wish to build and contribute to the Operator. -We utilise [Skaffold](https://skaffold.dev/) to drive CI/CD, so you will need to download the latest binary in order to -follow the steps below: +## Kubernetes +A Kubernetes cluster is necessary to develop and run the Operator. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for +testing, or run against a remote cluster. -## Setup a Kind (Kubernetes) Cluster +**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows). -Create a local kind cluster backed by a local docker repository, with [OLM](https://olm.operatorframework.io/) +### Setting a Local Kubernetes Cluster using Docker and Kind +In the scripts folder, you will find scripts to create a local KIND cluster backed by a local [Docker](https://www.docker.com/) +repository and integrated with the Operator Lifecycle Manager ([OLM](https://olm.operatorframework.io/)). +First run ```sh ./scripts/ci/kind-with-olm.sh ``` -and install [cert-manager](https://cert-manager.io) on it: +Then install [cert-manager](https://cert-manager.io) on it: ```sh make deploy-cert-manager ``` +### Podman and Podman Desktop +If you are using Windows or Mac, you can use [Podman](https://podman.io/) and [Podman Desktop](https://podman-desktop.io/) +as alternative tools to create a local Kubernetes cluster for development purposes, allowing you to set up a Kind, +Microshift, or OpenShift Kubernetes cluster. + +## Skaffold +We utilise [Skaffold](https://skaffold.dev/) to drive CI/CD, so you will need to download the latest binary in order to +follow the steps below. + ## Development -Build the Operator image and deploy to a cluster: +Build the Operator image and deploy it to a cluster: ```sh skaffold dev @@ -47,6 +64,69 @@ See more on [Skaffold Documentation](https://skaffold.dev/docs/). Changes to the local `**/*.go` files will result in the image being rebuilt and the Operator deployment updated. +## Testing + +### Unit Tests +Run all the unit tests by calling: + +```sh +make test +``` + +### Integration Tests + +The different categories of integration tests can be executed with the following commands: + +- `make infinispan-test` +- `make cache-test` +- `make batch-test` +- `make multinamespace-test` +- `make backuprestore-test` + +The target cluster should be specified by exporting or explicitly providing `KUBECONFIG`, e.g. `make infinispan-test KUBECONFIG=/path/to/admin.kubeconfig`. + +#### Env Variables +The following variables can be exported or provided as part of the `make *test` call. + +| Variable | Purpose | +|-----------------------|------------------------------------------------------------------------------------| +| `TEST_NAME` | Specify a single test to run | +| `TESTING_NAMESPACE` | Specify the namespace/project for running test | +| `RUN_LOCAL_OPERATOR` | Specify whether run operator locally or use the predefined installation | +| `EXPOSE_SERVICE_TYPE` | Specify expose service type. `NodePort \| LoadBalancer \| Route`. | +| `EXPOSE_SERVICE_HOST` | Specify the service host. Useful to pass `localhost`. | +| `PARALLEL_COUNT` | Specify parallel test running count. Default is one, i.e. no parallel tests enabled. | + +The following command runs a single integration test called `TestBaseFunctionality`: + +```sh + make infinispan-test TEST_NAME=TestBaseFunctionality +```` + +### Xsite +Cross-Site tests require you to create two k8s Kind clusters or utilize already prepared OKD clusters: +``` +$ source scripts/ci/configure-xsite.sh $KIND_VERSION $METALLB_VERSION +``` + +To test locally in running Kind clusters, run: +``` +$ go test -v ./test/e2e/xsite/ -timeout 30m +``` + +## Arm Support +In order to test on ARM machines locally, it's necessary for a few changes to be made. + +1. `scripts/ci/kind.sh` needs to be executed with the following env variables: + +```bash +DOCKER_REGISTRY_IMAGE="registry:2" +KINDEST_IMAGE="kindest/node" +KINDEST_NODE_VERSION="v1.28.7" # Must be >= 1.28.x to ensure ARM support works as expected +``` + +2. When executing `make infinispan-test`, set `TEST_NGINX_IMAGE="nginx"` so a multi-arch nginx container is used. + ## Debugging Build the Operator image with [dlv](https://github.com/go-delve/delve) so that a remote debugger can be attached to the Operator deployment from your IDE. @@ -74,7 +154,7 @@ on the cluster. To build and push the operator images to a remote repository, ad skaffold run --default-repo ``` -# OLM Bundle +## OLM Bundle The OLM bundle manifests are created by executing `make bundle VERSION=`. This will create a `bundle/` dir in your local repository containing the bundle metadata and manifests, as well as a @@ -86,17 +166,18 @@ The bundle image can be created and pushed to a repository with: make bundle-build bundle-push VERSION= IMG= BUNDLE_IMG= ``` -# Operator Version -The next version of the Operator to be released is stored in the `./version.txt` at the root of the project. The content -of this file are used to control the generation of documentation and other resources. This file must be updated after an -Operator release. +## Operator Version +The next version of the Operator to be released is stored in the `./version.txt` file at the root of +the project. The contents of this file are used to control the generation of documentation and +other resources. **Update this file after each Operator release**. -# Add a new Infinispan Operand +## Add a new Infinispan Operand 1. Call the "Add Operand" GitHub Action # Release -To create an Operator release perform the following: -1. Tag the release `git tag ` and push to GitHub +Follow these steps to release the Infinispan Operator: + +1. Tag the release `git tag ` and push to GitHub 2. Create and push the multi-arch image using the created tag via the "Image Release" GitHub Action 3. Remove the old bundle from local `rm -rf bundle` 4. Create OLM bundle `make bundle VERSION= CHANNELS=stable DEFAULT_CHANNEL=stable IMG=quay.io/infinispan/operator:.Final` @@ -105,63 +186,7 @@ To create an Operator release perform the following: - https://github.com/redhat-openshift-ecosystem/community-operators-prod 6. Once PR in 5 has been merged and Operator has been released to OperatorHub, update the "replaces" field in `config/manifests/bases/infinispan-operator.clusterserviceversion.yaml` to `replaces: infinispan-operator.v` -7. Update the `version.txt` file to the next release version +7. **Update the `version.txt` file to the next release version** 8. Update `scripts/ci/install-catalog-source.sh` `VERSION` field to the next release version 9. Update `scripts/create-olm-catalog.sh` to include the just released version in `BUNDLE_IMGS` and the next release version in the update graph -10. Commit changes with appropriate commit message, e.g "Next Version " - -# Testing - -## Unit Tests - -`make test` - -## Go Integration Tests - -The different categories of integration tests can be executed with the following commands: - -- `make infinispan-test` -- `make cache-test` -- `make batch-test` -- `make multinamespace-test` -- `make backuprestore-test` - -The target cluster should be specified by exporting or explicitly providing `KUBECONFIG`, e.g. `make infinispan-test KUBECONFIG=/path/to/admin.kubeconfig`. - -### Env Variables -The following variables can be exported or provided as part of the `make *test` call. - -| Variable | Purpose | -|-----------------------|--------------------------------------------------------------------------------------| -| `TEST_NAME` | Specify a single test to run | -| `TESTING_NAMESPACE` | Specify the namespace/project for running test | -| `RUN_LOCAL_OPERATOR` | Specify whether run operator locally or use the predefined installation | -| `EXPOSE_SERVICE_TYPE` | Specify expose service type. `NodePort \| LoadBalancer \| Route`. | -| `PARALLEL_COUNT` | Specify parallel test running count. Default is one, i.e. no parallel tests enabled. | - -### Xsite -Cross-Site tests require you to create two k8s Kind clusters or utilize already prepared OKD clusters: -``` -$ source scripts/ci/configure-xsite.sh $KIND_VERSION $METALLB_VERSION -``` - -To test locally in running Kind clusters, run: -``` -$ go test -v ./test/e2e/xsite/ -timeout 30m -``` - -## Arm Support -In order to test on ARM machines locally, it's necessary for a few changes to be made. - -1. `scripts/ci/kind.sh` needs to be executed with the following env variables: - -```bash -DOCKER_REGISTRY_IMAGE="registry:2" -KINDEST_IMAGE="kindest/node" -KINDEST_NODE_VERSION="v1.28.7" # Must be >= 1.28.x to ensure ARM support works as expected -``` - -2. When executing `make infinispan-test`, set `TEST_NGINX_IMAGE="nginx"` so a multi-arch nginx container is used. - -## Java Integration Tests -TODO +10. Commit changes with appropriate commit message, e.g "Next Version " \ No newline at end of file diff --git a/api/v1/types_util.go b/api/v1/types_util.go index cc47c4e70..4ff148443 100644 --- a/api/v1/types_util.go +++ b/api/v1/types_util.go @@ -305,6 +305,10 @@ func (ispn *Infinispan) IsExposed() bool { return ispn.Spec.Expose != nil && ispn.Spec.Expose.Type != "" } +func (ispn *Infinispan) GetExposeHost() string { + return ispn.Spec.Expose.Host +} + func (ispn *Infinispan) GetExposeType() ExposeType { return ispn.Spec.Expose.Type } diff --git a/infinispanOperator.png b/infinispanOperator.png new file mode 100644 index 0000000000000000000000000000000000000000..926ec37c94cef3d83f4ab07f92d84fcec2ac9225 GIT binary patch literal 39843 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 literal 0 HcmV?d00001 diff --git a/test/e2e/utils/common.go b/test/e2e/utils/common.go index d9524aa9d..8f530ac6c 100644 --- a/test/e2e/utils/common.go +++ b/test/e2e/utils/common.go @@ -347,9 +347,17 @@ func WebServerService(name, namespace string) *corev1.Service { func ExposeServiceSpec(testKube *TestKubernetes) *ispnv1.ExposeSpec { return &ispnv1.ExposeSpec{ Type: exposeServiceType(testKube), + Host: exposeServiceHost(), } } +func exposeServiceHost() string { + if ExposeServiceHost != "" { + return ExposeServiceHost + } + return "" +} + func exposeServiceType(testKube *TestKubernetes) ispnv1.ExposeType { switch ispnv1.ExposeType(ExposeServiceType) { case ispnv1.ExposeTypeNodePort, ispnv1.ExposeTypeLoadBalancer: diff --git a/test/e2e/utils/constants.go b/test/e2e/utils/constants.go index 923bfe5ed..e62fcb217 100644 --- a/test/e2e/utils/constants.go +++ b/test/e2e/utils/constants.go @@ -36,9 +36,9 @@ var ( CleanupInfinispan = strings.ToUpper(constants.GetEnvWithDefault("CLEANUP_INFINISPAN_ON_FINISH", "true")) SuiteMode, _ = strconv.ParseBool(constants.GetEnvWithDefault("SUITE_MODE", "false")) ExposeServiceType = constants.GetEnvWithDefault("EXPOSE_SERVICE_TYPE", string(ispnv1.ExposeTypeNodePort)) - - Infrastructure = os.Getenv("TESTING_INFRASTRUCTURE") - Platform = os.Getenv("TESTING_PLATFORM") + ExposeServiceHost = constants.GetEnvWithDefault("EXPOSE_SERVICE_HOST", "") + Infrastructure = os.Getenv("TESTING_INFRASTRUCTURE") + Platform = os.Getenv("TESTING_PLATFORM") WebServerName = "external-libs-web-server" WebServerImageName = constants.GetEnvWithDefault("TEST_NGINX_IMAGE", "quay.io/openshift-scale/nginx") diff --git a/test/e2e/utils/kubernetes.go b/test/e2e/utils/kubernetes.go index ae32a7315..d1f328689 100644 --- a/test/e2e/utils/kubernetes.go +++ b/test/e2e/utils/kubernetes.go @@ -508,8 +508,13 @@ func (k TestKubernetes) WaitForExternalService(ispn *ispnv1.Infinispan, timeout if len(routeList.Items) > 0 { switch ispn.GetExposeType() { case ispnv1.ExposeTypeNodePort: - host, err := k.Kubernetes.GetNodeHost(log, context.TODO()) - ExpectNoError(err) + var host string + if ispn.GetExposeHost() != "" { + host = ispn.GetExposeHost() + } else { + host, err = k.Kubernetes.GetNodeHost(log, context.TODO()) + ExpectNoError(err) + } hostAndPort = fmt.Sprintf("%s:%d", host, getNodePort(&routeList.Items[0])) case ispnv1.ExposeTypeLoadBalancer: hostAndPort = k.Kubernetes.GetExternalAddress(&routeList.Items[0])