diff --git a/.github/workflows/coherence-matrix.yaml b/.github/workflows/coherence-matrix.yaml index d91b9d879..aeef3e190 100644 --- a/.github/workflows/coherence-matrix.yaml +++ b/.github/workflows/coherence-matrix.yaml @@ -51,35 +51,41 @@ jobs: coherenceVersion: "15.1.1-0-0-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:15.1.1-0-0-SNAPSHOT-java17" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "15.1.1-0-SNAPSHOT-Graal" coherenceVersion: "15.1.1-0-0-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:15.1.1-0-0-SNAPSHOT-graal" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "24.09" coherenceVersion: "24.09" coherenceImage: "ghcr.io/oracle/coherence-ce:24.09" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "24.09-Graal" coherenceVersion: "24.09" coherenceImage: "ghcr.io/oracle/coherence-ce:24.09-graal" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "14.1.2-0-SNAPSHOT" coherenceVersion: "14.1.2-0-1-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:14.1.2-0-1-SNAPSHOT" javaVersion: 17 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java17-debian12" - matrixName: "14.1.2-0" coherenceVersion: "14.1.2-0-0" - javaVersion: 8 + javaVersion: 17 + coherenceIsJava8: false coherenceImage: "ghcr.io/oracle/coherence-ce:14.1.2-0-0" baseImage: "gcr.io/distroless/java17-debian12" @@ -87,23 +93,27 @@ jobs: coherenceVersion: "22.06.10" coherenceImage: "ghcr.io/oracle/coherence-ce:22.06.10" javaVersion: 11 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "14.1.1-2206-SNAPSHOT" coherenceVersion: "14.1.1-2206-11-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:14.1.1-2206-11-SNAPSHOT" javaVersion: 11 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "14.1.1-0-SNAPSHOT" coherenceVersion: "14.1.1-0-20-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:14.1.1-0-20-SNAPSHOT" - javaVersion: 8 + javaVersion: 11 + coherenceIsJava8: false baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "14.1.1-0" coherenceVersion: "14.1.1-0-19" - javaVersion: 8 + javaVersion: 11 + coherenceIsJava8: false coherenceImage: "ghcr.io/oracle/coherence-ce:14.1.1-0-19" baseImage: "gcr.io/distroless/java11-debian11" @@ -111,18 +121,21 @@ jobs: coherenceVersion: "14.1.1.0.0" coherenceImage: "container-registry.oracle.com/middleware/coherence:14.1.1.0.0" javaVersion: 8 + coherenceIsJava8: true baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "12.2.1.4.0" coherenceVersion: "12.2.1.4.0" coherenceImage: "container-registry.oracle.com/middleware/coherence:12.2.1.4.0" javaVersion: 8 + coherenceIsJava8: true baseImage: "gcr.io/distroless/java11-debian11" - matrixName: "12.2.1-4-SNAPSHOT" coherenceVersion: "12.2.1-4-24-SNAPSHOT" coherenceImage: "iad.ocir.io/odx-stateservice/test/coherence:12.2.1-4-24-SNAPSHOT" javaVersion: 8 + coherenceIsJava8: true baseImage: "gcr.io/distroless/java11-debian11" steps: @@ -209,6 +222,7 @@ jobs: echo "BUILD_JAVA_VERSION=${BUILD_JAVA_VERSION}" export COHERENCE_TEST_BASE_IMAGE=${{ matrix.baseImage }} echo "COHERENCE_TEST_BASE_IMAGE=${COHERENCE_TEST_BASE_IMAGE}" + export OPERATOR_COHERENCE_JAVA_8=${{ matrix.coherenceIsJava8 }} make clean echo "Building Operator Image" make build-operator-images diff --git a/.golangci.yml b/.golangci.yml index f2e6cf90a..46dddb4fb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,22 +3,24 @@ run: # include test files or not, default is true tests: true - # which dirs to skip: they won't be analyzed; - # can use regexp here: generated.*, regexp is applied on full path; - # default value is empty list, but next dirs are always skipped independently - # of this option's value: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs: -# - .*/fakes - linters: - -enable-all: true + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - gocritic + - gofmt issues: # Excluding configuration per-path, per-linter, per-text and per-source exclude-rules: + # Exclude some linters from running on data files. + - path: pkg/data + linters: + - gofmt # Exclude some linters from running on tests files. - - path: _test\.go + - path: test\.go linters: - gosec + - bodyclose diff --git a/Makefile b/Makefile index e8c63ac02..74da346e9 100644 --- a/Makefile +++ b/Makefile @@ -273,7 +273,8 @@ endif IMAGE_PULL_POLICY ?= IfNotPresent # Env variable used by the kubectl test framework to locate the kubectl binary -TEST_ASSET_KUBECTL ?= $(shell which kubectl) +KUBECTL_CMD ?= kubectl +TEST_ASSET_KUBECTL ?= $(shell which $(KUBECTL_CMD)) # ---------------------------------------------------------------------------------------------------------------------- # Build output directories @@ -800,7 +801,7 @@ code-review: $(BUILD_TARGETS)/generate golangci copyright ## Full code review a # ---------------------------------------------------------------------------------------------------------------------- .PHONY: golangci golangci: $(TOOLS_BIN)/golangci-lint ## Go code review - $(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G402:' --exclude='G101:' --exclude='G114:' --skip-dirs=.*/fakes --skip-files=zz_.*,generated/*,pkg/data/assets... ./api/... ./controllers/... ./pkg/... ./runner/... + $(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G402:' --exclude='G101:' --exclude='G114:' --exclude-dirs=.*/fakes --exclude-files=zz_.*,generated/*,pkg/data/assets... ./api/... ./controllers/... ./pkg/... ./runner/... $(TOOLS_BIN)/golangci-lint run -v --timeout=5m --exclude='G107:' --exclude='G101:' --exclude='G112:' --exclude='SA4005:' --exclude='should not use dot imports' ./test/... ./pkg/fakes/... @@ -1030,30 +1031,30 @@ olm-deploy-catalog: ## Deploy the Operator Catalog into OLM mkdir -p $(BUILD_OUTPUT)/catalog || true cp $(SCRIPTS_DIR)/operator-catalog-source.yaml $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml $(SED) -e 's^IMAGE_NAME_PLACEHOLDER^$(CATALOG_IMAGE)^g' $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml - kubectl apply -f $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml - kubectl -n olm get catalogsource + $(KUBECTL_CMD) apply -f $(BUILD_OUTPUT)/catalog/operator-catalog-source.yaml + $(KUBECTL_CMD) -n olm get catalogsource .PHONY: wait-for-olm-deploy -wait-for-olm-deploy: export POD=$(shell kubectl -n olm get pod -l olm.catalogSource=coherence-operator-catalog -o name) +wait-for-olm-deploy: export POD=$(shell $(KUBECTL_CMD) -n olm get pod -l olm.catalogSource=coherence-operator-catalog -o name) wait-for-olm-deploy: ## Wait for the Operator Catalog to be deployed into OLM echo "Operator Catalog Source Pods:" - kubectl -n olm get pod -l olm.catalogSource=coherence-operator-catalog + $(KUBECTL_CMD) -n olm get pod -l olm.catalogSource=coherence-operator-catalog echo "Waiting for Operator Catalog Source to be ready. Pod: $(POD)" - kubectl -n olm wait --for condition=ready --timeout 480s $(POD) + $(KUBECTL_CMD) -n olm wait --for condition=ready --timeout 480s $(POD) .PHONY: olm-deploy olm-deploy: ## Deploy the Operator into the coherence namespace using OLM - kubectl create ns coherence || true - kubectl -n coherence apply -f $(SCRIPTS_DIR)/operator-group.yaml - kubectl -n coherence apply -f $(SCRIPTS_DIR)/operator-subscription.yaml + $(KUBECTL_CMD) create ns coherence || true + $(KUBECTL_CMD) -n coherence apply -f $(SCRIPTS_DIR)/operator-group.yaml + $(KUBECTL_CMD) -n coherence apply -f $(SCRIPTS_DIR)/operator-subscription.yaml sleep 10 - kubectl -n coherence get ip - kubectl -n coherence get csv - kubectl -n coherence wait --for condition=available deployment/coherence-operator-controller-manager -timeout 480s + $(KUBECTL_CMD) -n coherence get ip + $(KUBECTL_CMD) -n coherence get csv + $(KUBECTL_CMD) -n coherence wait --for condition=available deployment/coherence-operator-controller-manager -timeout 480s .PHONY: olm-undeploy olm-undeploy: ## Undeploy the Operator that was installed with OLM - kubectl -n coherence delete csv coherence-operator.v$(VERSION) + $(KUBECTL_CMD) -n coherence delete csv coherence-operator.v$(VERSION) # ====================================================================================================================== # Targets to run a local container registry @@ -1229,7 +1230,7 @@ e2e-local-test: export TEST_APPLICATION_IMAGE_SPRING_FAT_2 := $(TEST_APPLICATION e2e-local-test: export TEST_APPLICATION_IMAGE_SPRING_CNBP_2 := $(TEST_APPLICATION_IMAGE_SPRING_CNBP_2) e2e-local-test: export TEST_COHERENCE_IMAGE := $(TEST_COHERENCE_IMAGE) e2e-local-test: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) -e2e-local-test: export COH_SKIP_SITE := true +e2e-local-test: export COHERENCE_OPERATOR_SKIP_SITE := true e2e-local-test: export TEST_IMAGE_PULL_POLICY := $(IMAGE_PULL_POLICY) e2e-local-test: export TEST_STORAGE_CLASS := $(TEST_STORAGE_CLASS) e2e-local-test: export GO_TEST_FLAGS_E2E := $(strip $(GO_TEST_FLAGS_E2E)) @@ -1315,7 +1316,7 @@ e2e-k3d-test: export TEST_APPLICATION_IMAGE_SPRING_FAT_2 := $(TEST_APPLICATION_I e2e-k3d-test: export TEST_APPLICATION_IMAGE_SPRING_CNBP_2 := $(TEST_APPLICATION_IMAGE_SPRING_CNBP_2) e2e-k3d-test: export TEST_COHERENCE_IMAGE := $(TEST_COHERENCE_IMAGE) e2e-k3d-test: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) -e2e-k3d-test: export COH_SKIP_SITE := true +e2e-k3d-test: export COHERENCE_OPERATOR_SKIP_SITE := true e2e-k3d-test: export TEST_IMAGE_PULL_POLICY := $(IMAGE_PULL_POLICY) e2e-k3d-test: export TEST_STORAGE_CLASS := $(TEST_STORAGE_CLASS) e2e-k3d-test: export GO_TEST_FLAGS_E2E := $(strip $(GO_TEST_FLAGS_E2E)) @@ -1341,7 +1342,7 @@ e2e-client-test: export TEST_APPLICATION_IMAGE := $(TEST_APPLICATION_IMAGE) e2e-client-test: export TEST_APPLICATION_IMAGE_CLIENT := $(TEST_APPLICATION_IMAGE_CLIENT) e2e-client-test: export TEST_COHERENCE_IMAGE := $(TEST_COHERENCE_IMAGE) e2e-client-test: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) -e2e-client-test: export COH_SKIP_SITE := true +e2e-client-test: export COHERENCE_OPERATOR_SKIP_SITE := true e2e-client-test: export TEST_IMAGE_PULL_POLICY := $(IMAGE_PULL_POLICY) e2e-client-test: export GO_TEST_FLAGS_E2E := $(strip $(GO_TEST_FLAGS_E2E)) e2e-client-test: export VERSION := $(VERSION) @@ -1545,20 +1546,20 @@ install-network-policy-tests: $(BUILD_TARGETS)/build-operator reset-namespace in .PHONY: install-network-policies install-network-policies: install-operator-network-policies install-coherence-network-policies @echo "API Server info" - kubectl get svc -o wide - kubectl get endpoints kubernetes + $(KUBECTL_CMD) get svc -o wide + $(KUBECTL_CMD) get endpoints kubernetes @echo "Network policies installed in $(OPERATOR_NAMESPACE)" - kubectl get networkpolicy -n $(OPERATOR_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(OPERATOR_NAMESPACE) @echo "Network policies installed in $(CLUSTER_NAMESPACE)" - kubectl get networkpolicy -n $(CLUSTER_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(CLUSTER_NAMESPACE) # ---------------------------------------------------------------------------------------------------------------------- # Prepare a copy of the example network policies # ---------------------------------------------------------------------------------------------------------------------- .PHONY: prepare-network-policies -prepare-network-policies: export IP1=$(shell kubectl -n default get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}') -prepare-network-policies: export IP2=$(shell kubectl -n default get svc kubernetes -o jsonpath='{.spec.clusterIP}') -prepare-network-policies: export API_PORT=$(shell kubectl -n default get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}') +prepare-network-policies: export IP1=$(shell $(KUBECTL_CMD) -n default get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}') +prepare-network-policies: export IP2=$(shell $(KUBECTL_CMD) -n default get svc kubernetes -o jsonpath='{.spec.clusterIP}') +prepare-network-policies: export API_PORT=$(shell $(KUBECTL_CMD) -n default get endpoints kubernetes -o jsonpath='{.subsets[0].ports[0].port}') prepare-network-policies: mkdir -p $(BUILD_OUTPUT)/network-policies cp $(EXAMPLES_DIR)/095_network_policies/*.sh $(BUILD_OUTPUT)/network-policies @@ -1575,9 +1576,9 @@ prepare-network-policies: .PHONY: uninstall-network-policies uninstall-network-policies: uninstall-operator-network-policies uninstall-coherence-network-policies @echo "Network policies installed in $(OPERATOR_NAMESPACE)" - kubectl get networkpolicy -n $(OPERATOR_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(OPERATOR_NAMESPACE) @echo "Network policies installed in $(CLUSTER_NAMESPACE)" - kubectl get networkpolicy -n $(CLUSTER_NAMESPACE) + $(KUBECTL_CMD) get networkpolicy -n $(CLUSTER_NAMESPACE) # ---------------------------------------------------------------------------------------------------------------------- # Install the Operator network policies from the examples @@ -1671,7 +1672,7 @@ cleanup-coherence-compatibility: undeploy uninstall-crds clean-namespace # ---------------------------------------------------------------------------------------------------------------------- .PHONY: install-crds install-crds: prepare-deploy uninstall-crds ## Install the CRDs - $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | kubectl create -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | $(KUBECTL_CMD) create -f - # ---------------------------------------------------------------------------------------------------------------------- # Uninstall CRDs from Kubernetes. @@ -1683,7 +1684,7 @@ uninstall-crds: $(BUILD_TARGETS)/manifests ## Uninstall the CRDs @echo "Uninstalling CRDs - calling prepare_deploy" $(call prepare_deploy,$(OPERATOR_IMAGE),$(OPERATOR_NAMESPACE)) @echo "Uninstalling CRDs - executing deletion" - $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | kubectl delete --force -f - || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | $(KUBECTL_CMD) delete --force -f - || true @echo "Uninstall CRDs completed" # ---------------------------------------------------------------------------------------------------------------------- @@ -1726,11 +1727,11 @@ endif ifeq (false,$(OPERATOR_HA)) cd $(BUILD_DEPLOY)/manager && $(KUSTOMIZE) edit add patch --kind Deployment --name controller-manager --path single-replica-patch.yaml endif - kubectl -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true ifeq ("$(OPERATOR_IMAGE_REGISTRY)","$(ORACLE_REGISTRY)") - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) apply -f - else - $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | $(KUBECTL_CMD) apply -f - endif sleep 5 @@ -1739,20 +1740,20 @@ endif just-deploy: ensure-pull-secret ## Deploy the Coherence Operator without rebuilding anything $(call prepare_deploy,$(OPERATOR_IMAGE),$(OPERATOR_NAMESPACE)) ifeq ("$(OPERATOR_IMAGE_REGISTRY)","$(ORACLE_REGISTRY)") - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) apply -f - else - $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | kubectl apply -f - + $(KUSTOMIZE) build $(BUILD_DEPLOY)/overlays/ci | $(KUBECTL_CMD) apply -f - endif .PHONY: ensure-pull-secret ensure-pull-secret: ifneq ("$(DEPLOY_REGISTRY_CONFIG_PATH)","") - kubectl -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true - kubectl -n $(OPERATOR_NAMESPACE) create secret generic coherence-operator-pull-secret \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) create secret generic coherence-operator-pull-secret \ --from-file=.dockerconfigjson=$(DEPLOY_REGISTRY_CONFIG_PATH) \ --type=kubernetes.io/dockerconfigjson - kubectl -n $(OPERATOR_NAMESPACE) patch serviceaccount default -p '{"imagePullSecrets": [{"name": "coherence-operator-pull-secret"}]}' + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) patch serviceaccount default -p '{"imagePullSecrets": [{"name": "coherence-operator-pull-secret"}]}' endif @@ -1765,8 +1766,8 @@ deploy-debug: prepare-deploy-debug create-namespace $(TOOLS_BIN)/kustomize ## ifneq (,$(WATCH_NAMESPACE)) cd $(BUILD_DEPLOY)/manager && $(KUSTOMIZE) edit add configmap env-vars --from-literal WATCH_NAMESPACE=$(WATCH_NAMESPACE) endif - kubectl -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl apply -f - + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) create secret generic coherence-webhook-server-cert || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) apply -f - sleep 5 @echo "" @echo "Deployed a debug enabled Operator." @@ -1782,26 +1783,26 @@ endif .PHONY: port-forward-debug -port-forward-debug: export POD=$(shell kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) +port-forward-debug: export POD=$(shell $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) port-forward-debug: ## Run a port-forward process to forward localhost:2345 to port 2345 in the Operator Pod @echo "Starting port-forward to the Operator Pod on port 2345 - DO NOT stop this process until debugging is finished!" @echo "Connect your IDE debugger to localhost:2345 (which is the default remote debug setting in IDEs like Goland)" @echo "If your IDE immediately disconnects it may be that the Operator Pod was not yet started, so try again." @echo "" - kubectl -n $(OPERATOR_NAMESPACE) port-forward $(POD) 2345:2345 || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) port-forward $(POD) 2345:2345 || true .PHONY: prepare-deploy-debug prepare-deploy-debug: $(BUILD_TARGETS)/manifests build-operator-debug $(TOOLS_BIN)/kustomize $(call prepare_deploy,$(OPERATOR_IMAGE_DEBUG),$(OPERATOR_NAMESPACE)) .PHONY: wait-for-deploy -wait-for-deploy: export POD=$(shell kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) +wait-for-deploy: export POD=$(shell $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) wait-for-deploy: sleep 30 echo "Operator Pods:" - kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence echo "Waiting for Operator to be ready. Pod: $(POD)" - kubectl -n $(OPERATOR_NAMESPACE) wait --for condition=ready --timeout 480s $(POD) + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) wait --for condition=ready --timeout 480s $(POD) # ---------------------------------------------------------------------------------------------------------------------- # Prepare the deployment manifests - this is called by a number of other targets. @@ -1826,14 +1827,14 @@ endef undeploy: $(BUILD_PROPS) $(BUILD_TARGETS)/manifests $(TOOLS_BIN)/kustomize ## Undeploy the Coherence Operator @echo "Undeploy Coherence Operator..." $(call prepare_deploy,$(OPERATOR_IMAGE),$(OPERATOR_NAMESPACE)) - $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | kubectl delete -f - || true - kubectl -n $(OPERATOR_NAMESPACE) delete secret coherence-webhook-server-cert || true - kubectl delete mutatingwebhookconfiguration coherence-operator-mutating-webhook-configuration || true - kubectl delete validatingwebhookconfiguration coherence-operator-validating-webhook-configuration || true - kubectl -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/default | $(KUBECTL_CMD) delete -f - || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete secret coherence-webhook-server-cert || true + $(KUBECTL_CMD) delete mutatingwebhookconfiguration coherence-operator-mutating-webhook-configuration || true + $(KUBECTL_CMD) delete validatingwebhookconfiguration coherence-operator-validating-webhook-configuration || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete secret coherence-operator-pull-secret || true @echo "Undeploy Coherence Operator completed" @echo "Uninstalling CRDs - executing deletion" - $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | kubectl delete --force -f - || true + $(KUSTOMIZE) build $(BUILD_DEPLOY)/crd | $(KUBECTL_CMD) delete --force -f - || true @echo "Uninstall CRDs completed" @@ -1841,9 +1842,9 @@ undeploy: $(BUILD_PROPS) $(BUILD_TARGETS)/manifests $(TOOLS_BIN)/kustomize ## U # Tail the deployed operator logs. # ---------------------------------------------------------------------------------------------------------------------- .PHONY: tail-logs -tail-logs: export POD=$(shell kubectl -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) +tail-logs: export POD=$(shell $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get pod -l control-plane=coherence -o name) tail-logs: ## Tail the Coherence Operator Pod logs (with follow) - kubectl -n $(OPERATOR_NAMESPACE) logs $(POD) -c manager -f + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) logs $(POD) -c manager -f $(BUILD_MANIFESTS_PKG): $(TOOLS_BIN)/kustomize $(TOOLS_BIN)/yq $(MANIFEST_FILES) @@ -1883,13 +1884,13 @@ $(BUILD_MANIFESTS_PKG): $(TOOLS_BIN)/kustomize $(TOOLS_BIN)/yq $(MANIFEST_FILES) create-namespace: export KUBECONFIG_PATH := $(KUBECONFIG_PATH) create-namespace: ## Create the test namespace ifeq ($(CREATE_OPERATOR_NAMESPACE),true) - kubectl get ns $(OPERATOR_NAMESPACE) -o name > /dev/null 2>&1 || kubectl create namespace $(OPERATOR_NAMESPACE) - kubectl get ns $(OPERATOR_NAMESPACE_CLIENT) -o name > /dev/null 2>&1 || kubectl create namespace $(OPERATOR_NAMESPACE_CLIENT) - kubectl get ns $(CLUSTER_NAMESPACE) -o name > /dev/null 2>&1 || kubectl create namespace $(CLUSTER_NAMESPACE) + $(KUBECTL_CMD) get ns $(OPERATOR_NAMESPACE) -o name > /dev/null 2>&1 || $(KUBECTL_CMD) create namespace $(OPERATOR_NAMESPACE) + $(KUBECTL_CMD) get ns $(OPERATOR_NAMESPACE_CLIENT) -o name > /dev/null 2>&1 || $(KUBECTL_CMD) create namespace $(OPERATOR_NAMESPACE_CLIENT) + $(KUBECTL_CMD) get ns $(CLUSTER_NAMESPACE) -o name > /dev/null 2>&1 || $(KUBECTL_CMD) create namespace $(CLUSTER_NAMESPACE) endif - kubectl label namespace $(OPERATOR_NAMESPACE) coherence.oracle.com/test=true --overwrite - kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) coherence.oracle.com/test=true --overwrite - kubectl label namespace $(CLUSTER_NAMESPACE) coherence.oracle.com/test=true --overwrite + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE) coherence.oracle.com/test=true --overwrite + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE_CLIENT) coherence.oracle.com/test=true --overwrite + $(KUBECTL_CMD) label namespace $(CLUSTER_NAMESPACE) coherence.oracle.com/test=true --overwrite # ---------------------------------------------------------------------------------------------------------------------- # Delete and re-create the test namespace @@ -1904,7 +1905,7 @@ reset-namespace: export OCR_DOCKER_PASSWORD := $(OCR_DOCKER_PASSWORD) reset-namespace: delete-namespace create-namespace ensure-pull-secret ## Reset the test namespace ifneq ($(DOCKER_SERVER),) @echo "Creating pull secrets for $(DOCKER_SERVER)" - kubectl create secret docker-registry coherence-k8s-operator-development-secret \ + $(KUBECTL_CMD) create secret docker-registry coherence-k8s-operator-development-secret \ --namespace $(OPERATOR_NAMESPACE) \ --docker-server "$(DOCKER_SERVER)" \ --docker-username "$(DOCKER_USERNAME)" \ @@ -1913,7 +1914,7 @@ ifneq ($(DOCKER_SERVER),) endif ifneq ("$(or $(OCR_DOCKER_USERNAME),$(OCR_DOCKER_PASSWORD))","") @echo "Creating pull secrets for container-registry.oracle.com" - kubectl create secret docker-registry ocr-k8s-operator-development-secret \ + $(KUBECTL_CMD) create secret docker-registry ocr-k8s-operator-development-secret \ --namespace $(OPERATOR_NAMESPACE) \ --docker-server container-registry.oracle.com \ --docker-username "$(OCR_DOCKER_USERNAME)" \ @@ -1931,13 +1932,13 @@ ifeq ($(CREATE_OPERATOR_NAMESPACE),true) $(call delete_ns,$(OPERATOR_NAMESPACE_CLIENT)) $(call delete_ns,$(CLUSTER_NAMESPACE)) endif - kubectl delete clusterrole operator-test-coherence-operator --force --ignore-not-found=true --grace-period=0 && echo "deleted namespace" || true - kubectl delete clusterrolebinding operator-test-coherence-operator --ignore-not-found=true --force --grace-period=0 && echo "deleted namespace" || true + $(KUBECTL_CMD) delete clusterrole operator-test-coherence-operator --force --ignore-not-found=true --grace-period=0 && echo "deleted namespace" || true + $(KUBECTL_CMD) delete clusterrolebinding operator-test-coherence-operator --ignore-not-found=true --force --grace-period=0 && echo "deleted namespace" || true define delete_ns - if kubectl get ns $(1); then \ + if $(KUBECTL_CMD) get ns $(1); then \ echo "Deleting test namespace $(1)" ;\ - kubectl delete namespace $(1) --force --ignore-not-found=true --grace-period=0 --timeout=600s ;\ + $(KUBECTL_CMD) delete namespace $(1) --force --ignore-not-found=true --grace-period=0 --timeout=600s ;\ echo "deleted namespace $(1)" || true ;\ fi endef @@ -1947,21 +1948,21 @@ endef # ---------------------------------------------------------------------------------------------------------------------- .PHONY: delete-coherence-clusters delete-coherence-clusters: ## Delete all running Coherence clusters in the test namespace - for i in $$(kubectl -n $(OPERATOR_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ - kubectl -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(OPERATOR_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(CLUSTER_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ - kubectl -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(CLUSTER_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) get coherencejob.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(OPERATOR_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ - kubectl -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(OPERATOR_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(CLUSTER_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ - kubectl -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ - kubectl -n $(CLUSTER_NAMESPACE) delete $${i}; \ + for i in $$($(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) get coherence.coherence.oracle.com -o name); do \ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) patch $${i} -p '{"metadata":{"finalizers":[]}}' --type=merge || true ;\ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) delete $${i}; \ done # ---------------------------------------------------------------------------------------------------------------------- @@ -1970,15 +1971,15 @@ delete-coherence-clusters: ## Delete all running Coherence clusters in the test .PHONY: clean-namespace clean-namespace: delete-coherence-clusters ## Clean-up deployments in the test namespace @echo "Cleaning Namespaces..." - kubectl delete --all networkpolicy --namespace=$(OPERATOR_NAMESPACE) || true - kubectl delete --all networkpolicy --namespace=$(CLUSTER_NAMESPACE) || true - for i in $$(kubectl -n $(OPERATOR_NAMESPACE) get all -o name); do \ + $(KUBECTL_CMD) delete --all networkpolicy --namespace=$(OPERATOR_NAMESPACE) || true + $(KUBECTL_CMD) delete --all networkpolicy --namespace=$(CLUSTER_NAMESPACE) || true + for i in $$($(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) get all -o name); do \ echo "Deleting $${i} from test namespace $(OPERATOR_NAMESPACE)" \ - kubectl -n $(OPERATOR_NAMESPACE) delete $${i}; \ + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete $${i}; \ done - for i in $$(kubectl -n $(CLUSTER_NAMESPACE) get all -o name); do \ + for i in $$($(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) get all -o name); do \ echo "Deleting $${i} from test namespace $(CLUSTER_NAMESPACE)" \ - kubectl -n $(CLUSTER_NAMESPACE) delete $${i}; \ + $(KUBECTL_CMD) -n $(CLUSTER_NAMESPACE) delete $${i}; \ done @echo "Cleaning Namespaces completed" @@ -1988,9 +1989,9 @@ clean-namespace: delete-coherence-clusters ## Clean-up deployments in the test .PHONY: create-ssl-secrets create-ssl-secrets: $(BUILD_OUTPUT)/certs @echo "Deleting SSL secret $(TEST_SSL_SECRET)" - kubectl --namespace $(OPERATOR_NAMESPACE) delete secret $(TEST_SSL_SECRET) && echo "secret deleted" || true + $(KUBECTL_CMD) --namespace $(OPERATOR_NAMESPACE) delete secret $(TEST_SSL_SECRET) && echo "secret deleted" || true @echo "Creating SSL secret $(TEST_SSL_SECRET)" - kubectl create secret generic $(TEST_SSL_SECRET) \ + $(KUBECTL_CMD) create secret generic $(TEST_SSL_SECRET) \ --namespace $(OPERATOR_NAMESPACE) \ --from-file=keystore.jks=build/_output/certs/icarus.jks \ --from-file=storepass.txt=build/_output/certs/storepassword.txt \ @@ -2042,11 +2043,11 @@ kind-calico: export KIND_CONFIG=$(SCRIPTS_DIR)/kind-config-calico.yaml kind-calico: ## Run a KinD cluster with Calico kind create cluster --name $(KIND_CLUSTER) --config $(SCRIPTS_DIR)/kind-config-calico.yaml --image $(KIND_IMAGE) $(SCRIPTS_DIR)/kind-label-node.sh - kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/$(CALICO_VERSION)/manifests/calico.yaml - kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true + $(KUBECTL_CMD) apply -f https://raw.githubusercontent.com/projectcalico/calico/$(CALICO_VERSION)/manifests/calico.yaml + $(KUBECTL_CMD) -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true sleep 30 - kubectl -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=calico-node pod - kubectl -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=kube-dns pod + $(KUBECTL_CMD) -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=calico-node pod + $(KUBECTL_CMD) -n kube-system wait --for condition=ready --timeout=$(CALICO_TIMEOUT) -l k8s-app=kube-dns pod # ---------------------------------------------------------------------------------------------------------------------- # Stop and delete the Kind cluster @@ -2152,7 +2153,7 @@ MINIKUBE_K8S ?= 1.25.8 minikube: minikube-install ## Run a default minikube cluster with Calico $(MINIKUBE) start --driver docker --cni calico --kubernetes-version $(MINIKUBE_K8S) $(MINIKUBE) status - kubectl get nodes + $(KUBECTL_CMD) get nodes # ---------------------------------------------------------------------------------------------------------------------- # Stop Minikube @@ -2235,12 +2236,12 @@ $(TOOLS_BIN)/cmctl: .PHONY: install-cert-manager install-cert-manager: $(TOOLS_BIN)/cmctl ## Install Cert manager into the Kubernetes cluster - kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yam + $(KUBECTL_CMD) apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yam $(CMCTL) check api --wait=10m .PHONY: uninstall-cert-manager uninstall-cert-manager: ## Uninstall Cert manager from the Kubernetes cluster - kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yam + $(KUBECTL_CMD) delete -f https://github.com/cert-manager/cert-manager/releases/download/$(CERT_MANAGER_VERSION)/cert-manager.yam # ====================================================================================================================== @@ -2414,6 +2415,32 @@ $(BUILD_BIN_ARM64)/cohctl: ./hack/install-cli.sh chmod +x $(BUILD_BIN_ARM64)/cohctl +# ---------------------------------------------------------------------------------------------------------------------- +# Download the OpenShift CLI (oc) into build/tools/bin +# ---------------------------------------------------------------------------------------------------------------------- +.PHONY: oc +oc: $(TOOLS_BIN)/oc + +$(TOOLS_BIN)/oc: ## Download OpenShift oc CLI + mkdir -p oc-tmp || true + mkdir -p $(TOOLS_BIN) || true +ifeq (Darwin, $(UNAME_S)) +ifeq (x86_64, $(UNAME_M)) + curl -Ls https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/openshift-client-mac.tar.gz -o oc-tmp/openshift-client.tar.gz +else + curl -Ls https://mirror.openshift.com/pub/openshift-v4/aarch64/clients/ocp/stable/openshift-client-mac-arm64.tar.gz -o oc-tmp/openshift-client.tar.gz +endif +else +ifeq (x86_64, $(UNAME_M)) + curl -Ls https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/openshift-client-linux.tar.gz -o oc-tmp/openshift-client.tar.gz +else + curl -Ls https://mirror.openshift.com/pub/openshift-v4/aarch64/clients/ocp/stable/openshift-client-linux.tar.gz -o oc-tmp/openshift-client.tar.gz +endif +endif + cd oc-tmp && tar -xvf openshift-client.tar.gz + mv oc-tmp/oc $(TOOLS_BIN)/oc + chmod +x $(TOOLS_BIN)/oc + # ---------------------------------------------------------------------------------------------------------------------- # find or download gotestsum # ---------------------------------------------------------------------------------------------------------------------- @@ -2586,37 +2613,37 @@ endif .PHONY: install-prometheus install-prometheus: get-prometheus ## Install Prometheus and Grafana - kubectl create -f $(PROMETHEUS_HOME)/manifests/setup + $(KUBECTL_CMD) create -f $(PROMETHEUS_HOME)/manifests/setup sleep 10 - until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done + until $(KUBECTL_CMD) get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done # We create additional custom RBAC rules because the defaults do not work # in an RBAC enabled cluster such as KinD # See: https://prometheus-operator.dev/docs/operator/rbac/ - kubectl create -f hack/prometheus-rbac.yaml - kubectl create -f $(PROMETHEUS_HOME)/manifests + $(KUBECTL_CMD) create -f hack/prometheus-rbac.yaml + $(KUBECTL_CMD) create -f $(PROMETHEUS_HOME)/manifests sleep 10 - kubectl -n monitoring get all + $(KUBECTL_CMD) -n monitoring get all @echo "Waiting for Prometheus StatefulSet to be ready" - until kubectl -n monitoring get statefulset/prometheus-k8s ; do date; sleep 1; echo ""; done - kubectl -n monitoring rollout status statefulset/prometheus-k8s --timeout=5m + until $(KUBECTL_CMD) -n monitoring get statefulset/prometheus-k8s ; do date; sleep 1; echo ""; done + $(KUBECTL_CMD) -n monitoring rollout status statefulset/prometheus-k8s --timeout=5m @echo "Waiting for Grafana Deployment to be ready" - kubectl -n monitoring rollout status deployment/grafana --timeout=5m + $(KUBECTL_CMD) -n monitoring rollout status deployment/grafana --timeout=5m # ---------------------------------------------------------------------------------------------------------------------- # Uninstall Prometheus # ---------------------------------------------------------------------------------------------------------------------- .PHONY: uninstall-prometheus uninstall-prometheus: get-prometheus ## Uninstall Prometheus and Grafana - kubectl delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests || true - kubectl delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests/setup || true - kubectl delete --ignore-not-found=true -f hack/prometheus-rbac.yaml + $(KUBECTL_CMD) delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests || true + $(KUBECTL_CMD) delete --ignore-not-found=true -f $(PROMETHEUS_HOME)/manifests/setup || true + $(KUBECTL_CMD) delete --ignore-not-found=true -f hack/prometheus-rbac.yaml # ---------------------------------------------------------------------------------------------------------------------- # Install Prometheus Adapter used for k8s metrics and Horizontal Pod Autoscaler # ---------------------------------------------------------------------------------------------------------------------- .PHONY: install-prometheus-adapter install-prometheus-adapter: - kubectl create ns $(OPERATOR_NAMESPACE) || true + $(KUBECTL_CMD) create ns $(OPERATOR_NAMESPACE) || true helm repo add stable https://kubernetes-charts.storage.googleapis.com/ || true helm install --atomic --namespace $(OPERATOR_NAMESPACE) --version $(PROMETHEUS_ADAPTER_VERSION) --wait \ --set prometheus.url=http://prometheus.$(OPERATOR_NAMESPACE).svc \ @@ -2636,25 +2663,25 @@ uninstall-prometheus-adapter: port-forward-grafana: ## Run a port-forward to Grafana on http://127.0.0.1:3000 @echo "Reach Grafana on http://127.0.0.1:3000" @echo "User: admin Password: admin" - kubectl --namespace monitoring port-forward svc/grafana 3000 + $(KUBECTL_CMD) --namespace monitoring port-forward svc/grafana 3000 # ---------------------------------------------------------------------------------------------------------------------- # Install MetalLB # ---------------------------------------------------------------------------------------------------------------------- .PHONY: install-metallb install-metallb: ## Install MetalLB to allow services of type LoadBalancer - kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml - kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml - kubectl apply -f hack/metallb-config.yaml + $(KUBECTL_CMD) apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml + $(KUBECTL_CMD) apply -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml + $(KUBECTL_CMD) apply -f hack/metallb-config.yaml # ---------------------------------------------------------------------------------------------------------------------- # Uninstall MetalLB # ---------------------------------------------------------------------------------------------------------------------- .PHONY: uninstall-metallb uninstall-metallb: ## Uninstall MetalLB - kubectl delete -f hack/metallb-config.yaml || true - kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml || true - kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml || true + $(KUBECTL_CMD) delete -f hack/metallb-config.yaml || true + $(KUBECTL_CMD) delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/metallb.yaml || true + $(KUBECTL_CMD) delete -f https://raw.githubusercontent.com/metallb/metallb/$(METALLB_VERSION)/manifests/namespace.yaml || true # ---------------------------------------------------------------------------------------------------------------------- @@ -2664,23 +2691,23 @@ uninstall-metallb: ## Uninstall MetalLB install-istio: delete-istio-config get-istio ## Install the latest version of Istio into k8s (or override the version using the ISTIO_VERSION env var) ifeq (true,$(ISTIO_USE_CONFIG)) $(ISTIO_HOME)/bin/istioctl install -f $(BUILD_OUTPUT)/istio-config.yaml -y - kubectl -n istio-system wait --for condition=available deployment.apps/istiod-$(ISTIO_REVISION) + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istiod-$(ISTIO_REVISION) $(ISTIO_HOME)/bin/istioctl tag set default --revision $(ISTIO_REVISION) else $(ISTIO_HOME)/bin/istioctl install --set profile=demo -y - kubectl -n istio-system wait --for condition=available deployment.apps/istiod + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istiod endif - kubectl -n istio-system wait --for condition=available deployment.apps/istio-ingressgateway - kubectl -n istio-system wait --for condition=available deployment.apps/istio-egressgateway - kubectl apply -f $(SCRIPTS_DIR)/istio-strict.yaml - kubectl -n $(OPERATOR_NAMESPACE) apply -f $(SCRIPTS_DIR)/istio-operator.yaml - kubectl label namespace $(OPERATOR_NAMESPACE) istio-injection=enabled --overwrite=true - kubectl label namespace $(OPERATOR_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true - kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) istio-injection=enabled --overwrite=true - kubectl label namespace $(OPERATOR_NAMESPACE_CLIENT) istio.io/rev=$(ISTIO_REVISION) --overwrite=true - kubectl label namespace $(CLUSTER_NAMESPACE) istio-injection=enabled --overwrite=true - kubectl label namespace $(CLUSTER_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true - kubectl apply -f $(ISTIO_HOME)/samples/addons + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istio-ingressgateway + $(KUBECTL_CMD) -n istio-system wait --for condition=available deployment.apps/istio-egressgateway + $(KUBECTL_CMD) apply -f $(SCRIPTS_DIR)/istio-strict.yaml + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) apply -f $(SCRIPTS_DIR)/istio-operator.yaml + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE) istio-injection=enabled --overwrite=true + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE_CLIENT) istio-injection=enabled --overwrite=true + $(KUBECTL_CMD) label namespace $(OPERATOR_NAMESPACE_CLIENT) istio.io/rev=$(ISTIO_REVISION) --overwrite=true + $(KUBECTL_CMD) label namespace $(CLUSTER_NAMESPACE) istio-injection=enabled --overwrite=true + $(KUBECTL_CMD) label namespace $(CLUSTER_NAMESPACE) istio.io/rev=$(ISTIO_REVISION) --overwrite=true + $(KUBECTL_CMD) apply -f $(ISTIO_HOME)/samples/addons # ---------------------------------------------------------------------------------------------------------------------- # Upgrade Istio @@ -2694,8 +2721,8 @@ upgrade-istio: delete-istio-config $(BUILD_OUTPUT)/istio-config.yaml ## Upgrade # ---------------------------------------------------------------------------------------------------------------------- .PHONY: uninstall-istio uninstall-istio: delete-istio-config get-istio ## Uninstall Istio from k8s - kubectl -n $(OPERATOR_NAMESPACE) delete -f $(SCRIPTS_DIR)/istio-operator.yaml || true - kubectl delete -f ./hack/istio-strict.yaml || true + $(KUBECTL_CMD) -n $(OPERATOR_NAMESPACE) delete -f $(SCRIPTS_DIR)/istio-operator.yaml || true + $(KUBECTL_CMD) delete -f ./hack/istio-strict.yaml || true $(ISTIO_HOME)/bin/istioctl uninstall --purge -y $(BUILD_OUTPUT)/istio-config.yaml: $(BUILD_PROPS) @@ -2722,7 +2749,7 @@ get-istio: $(BUILD_PROPS) $(BUILD_OUTPUT)/istio-config.yaml ## Download Istio to # ---------------------------------------------------------------------------------------------------------------------- $(TOOLS_BIN)/golangci-lint: @mkdir -p $(TOOLS_BIN) - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh --header $(GH_AUTH) | sh -s -- -b $(TOOLS_BIN) v1.63.1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh --header $(GH_AUTH) | sh -s -- -b $(TOOLS_BIN) v1.64.7 # ---------------------------------------------------------------------------------------------------------------------- # Display the full version string for the artifacts that would be built. @@ -2802,9 +2829,9 @@ release-dashboards: @echo "Releasing Dashboards $(VERSION)" mkdir -p $(BUILD_OUTPUT)/dashboards/$(VERSION) || true tar -czvf $(BUILD_OUTPUT)/dashboards/$(VERSION)/coherence-dashboards.tar.gz dashboards/ - kubectl create configmap coherence-grafana-dashboards --from-file=dashboards/grafana \ + $(KUBECTL_CMD) create configmap coherence-grafana-dashboards --from-file=dashboards/grafana \ --dry-run=client -o yaml > $(BUILD_OUTPUT)/dashboards/$(VERSION)/coherence-grafana-dashboards.yaml - kubectl create configmap coherence-kibana-dashboards --from-file=dashboards/kibana \ + $(KUBECTL_CMD) create configmap coherence-kibana-dashboards --from-file=dashboards/kibana \ --dry-run=client -o yaml > $(BUILD_OUTPUT)/dashboards/$(VERSION)/coherence-kibana-dashboards.yaml # ---------------------------------------------------------------------------------------------------------------------- diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 49d732022..a99bec183 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/ptr" + "os" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -206,14 +207,22 @@ type ApplicationSpec struct { // runnable, for example if the application type is "node" the main may be a Javascript file. // +optional Main *string `json:"main,omitempty"` - // Args is the optional arguments to pass to the main class. + // Entrypoint array that will override the "java" entry point configured by the Operator or + // and any container entry point. This is an advanced use case, specifying an incorrect value here can + // cause the container not to start. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. Cannot be updated. + // +optional + // +listType=atomic + EntryPoint []string `json:"entryPoint,omitempty"` + // Args is the optional arguments to pass to the main class or the container entry point. // +listType=atomic // +optional Args []string `json:"args,omitempty"` - // The application folder in the custom artifacts Docker image containing - // application artifacts. - // This will effectively become the working directory of the Coherence container. - // If not set the application directory default value is "/app". + // WorkingDir sets the working directory of the Coherence container. // +optional WorkingDir *string `json:"workingDir,omitempty"` // Optional settings that may be configured if using a Cloud Native Buildpack Image. @@ -227,42 +236,133 @@ type ApplicationSpec struct { // For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" // +optional SpringBootFatJar *string `json:"springBootFatJar,omitempty"` + // UseImageEntryPoint is a flag to indicate that the Coherence container in the Pods + // should just execute the image entry point and not configure a custom command line. + // If this flag is set to true any arguments in the Args field are passed as container arguments + // to the entry point. + // +optional + UseImageEntryPoint *bool `json:"useImageEntryPoint,omitempty"` + // UseJdkJavaOptions is a flag to indicate that the `JDK_JAVA_OPTIONS` environment variable + // should be set in the Coherence container to contain the JVM arguments configured by + // the Operator. + // Setting `JDK_JAVA_OPTIONS` defaults to true and only applies if UseImageEntryPoint is set to true. + // +optional + UseJdkJavaOptions *bool `json:"useJdkJavaOptions,omitempty"` + // AlternateJdkJavaOptions specifies an alternative environment variable name to use instead of + // `JDK_JAVA_OPTIONS` for the command line options. + // If an application does not want to use the `JDK_JAVA_OPTIONS` environment variable but still + // wants access to the options the operator would have configured, this field can be set to an + // environment variable that an application can then access in the container at runtime. + // The value of the environment variable specified here will be set even if `UseJdkJavaOptions` + // is set to false. + // Setting the alternate JVM options environment variable only applies if UseImageEntryPoint is set to true. + // +optional + AlternateJdkJavaOptions *string `json:"alternateJdkJavaOptions,omitempty"` } // UpdateCoherenceContainer updates the Coherence container with the relevant settings. func (in *ApplicationSpec) UpdateCoherenceContainer(c *corev1.Container) { - if in == nil { - return - } + useImageEntryPoint := false + useJdkJavaOptions := true - if in.Type != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppType, Value: *in.Type}) - } - if in.Main != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainClass, Value: *in.Main}) - } - if in.WorkingDir != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohAppDir, Value: *in.WorkingDir}) - } - if len(in.Args) > 0 { - args := strings.Join(in.Args, " ") - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainArgs, Value: args}) - } - if in.CloudNativeBuildPack != nil { - if in.CloudNativeBuildPack.Enabled != nil { - if *in.CloudNativeBuildPack.Enabled { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "true"}) + if in != nil { + if len(in.EntryPoint) > 0 { + c.Command = in.EntryPoint + } + + if in.Type != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppType, Value: *in.Type}) + } + if in.Main != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainClass, Value: *in.Main}) + } + if in.WorkingDir != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohAppDir, Value: *in.WorkingDir}) + c.WorkingDir = *in.WorkingDir + } + if len(in.Args) > 0 { + args := strings.Join(in.Args, " ") + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarAppMainArgs, Value: args}) + } + if in.CloudNativeBuildPack != nil { + if in.CloudNativeBuildPack.Enabled != nil { + if *in.CloudNativeBuildPack.Enabled { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "true"}) + useImageEntryPoint = true + } else { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "false"}) + } + } + if in.CloudNativeBuildPack.Launcher != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpLauncher, Value: *in.CloudNativeBuildPack.Launcher}) + } + } + if in.SpringBootFatJar != nil { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarSpringBootFatJar, Value: *in.SpringBootFatJar}) + } + useImageEntryPoint = useImageEntryPoint || (in.UseImageEntryPoint != nil && *in.UseImageEntryPoint) + useJdkJavaOptions = useImageEntryPoint && (in.UseJdkJavaOptions == nil || *in.UseJdkJavaOptions) + } + + if useImageEntryPoint { + // we are configured to use the image's entry point + // in cannot be nil if we get here + argsFile := fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorEntryPointArgsFile) + + if useJdkJavaOptions { + // find any existing JDK_JAVA_OPTION env var so we do not loose its value + existingJdkOpts := "" + jdkOptsIdx := -1 + for i, ev := range c.Env { + if ev.Name == EnvVarJdkOptions { + existingJdkOpts = ev.Value + jdkOptsIdx = i + break + } + } + + jdkOptsEV := corev1.EnvVar{ + Name: EnvVarJdkOptions, + Value: strings.TrimSpace(existingJdkOpts + " " + argsFile), + } + + if jdkOptsIdx >= 0 { + c.Env[jdkOptsIdx] = jdkOptsEV } else { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpEnabled, Value: "false"}) + c.Env = append(c.Env, jdkOptsEV) } } - if in.CloudNativeBuildPack.Launcher != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCnbpLauncher, Value: *in.CloudNativeBuildPack.Launcher}) + + if in.AlternateJdkJavaOptions != nil && *in.AlternateJdkJavaOptions != "" { + c.Env = append(c.Env, corev1.EnvVar{ + Name: *in.AlternateJdkJavaOptions, + Value: strings.TrimSpace(argsFile), + }) } + + // Use the application args as container args + c.Args = in.Args + } else if c.Command == nil { + argsFile := fmt.Sprintf(ArgumentFileNamePattern, VolumeMountPathUtils, os.PathSeparator, OperatorCoherenceArgsFile) + c.Command = []string{"java", argsFile} + } +} + +// IsSpringBoot returns true if this is a Spring Boot application +func (in *ApplicationSpec) IsSpringBoot() bool { + if in == nil { + return false } - if in.SpringBootFatJar != nil { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarSpringBootFatJar, Value: *in.SpringBootFatJar}) + app := in.GetApplicationType() + return app == AppTypeSpring2 || app == AppTypeSpring3 +} + +// GetApplicationType returns the configured application type +func (in *ApplicationSpec) GetApplicationType() string { + if in != nil && in.Type != nil { + return strings.ToLower(*in.Type) } + return AppTypeNone } // ----- CloudNativeBuildPackSpec struct ------------------------------------ @@ -466,6 +566,7 @@ func (in *CoherenceSpec) UpdatePodTemplateSpec(podTemplate *corev1.PodTemplateSp c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCoherenceLocalPort, Value: localPort}) c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCoherenceLocalPortAdjust, Value: localPortAdjust}) + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarIPMonitorPingTimeout, Value: "0"}) return } @@ -487,11 +588,9 @@ func (in *CoherenceSpec) UpdatePodTemplateSpec(podTemplate *corev1.PodTemplateSp if in.StorageEnabled != nil { c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohStorage, Value: BoolPtrToString(in.StorageEnabled)}) - } else { + } else if deployment.GetType() == CoherenceTypeJob { // StorageEnabled is nil, so if this is a CoherenceJob default to false - if deployment.GetType() == CoherenceTypeJob { - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohStorage, Value: "false"}) - } + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohStorage, Value: "false"}) } if in.SkipVersionCheck != nil { @@ -508,6 +607,8 @@ func (in *CoherenceSpec) UpdatePodTemplateSpec(podTemplate *corev1.PodTemplateSp if in.EnableIPMonitor != nil && *in.EnableIPMonitor { c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarEnableIPMonitor, Value: "TRUE"}) + } else { + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarIPMonitorPingTimeout, Value: "0"}) } in.Management.AddSSLVolumesForPod(podTemplate, c, VolumeNameManagementSSL, VolumeMountPathManagementCerts) @@ -678,6 +779,14 @@ type JVMSpec struct { // The default value fif not specified is true. // +optional UseJibClasspath *bool `json:"useJibClasspath,omitempty"` + // Java8 is a flag to indicate that a Coherence container is + // running on Java 8 and must use the legacy Operator container + // entry point. This would only apply to applications using + // older Coherence 12.2.1-4-* or 14.1.1-0-* versions. + // The default value for this field is false, if this field is not set to + // true when Java 8 is used the container will fail to start. + // +optional + Java8 *bool `json:"java8,omitempty"` } // UpdatePodTemplate updates the StatefulSet with any JVM specific settings @@ -711,6 +820,11 @@ func (in *JVMSpec) UpdatePodTemplate(podTemplate *corev1.PodTemplateSpec) { if in.Gc != nil { gc = in.Gc } + + if in.Java8 != nil && *in.Java8 { + c.Command = []string{RunnerCommand, "server"} + c.Args = []string{} + } } //goland:noinspection GoNilness @@ -755,9 +869,21 @@ type ImageSpec struct { ImagePullPolicy *corev1.PullPolicy `json:"imagePullPolicy,omitempty"` } +// ----- ImageSpec struct --------------------------------------------------- + +// CoherenceUtilsSpec defines the settings for the Coherence Operator utilities image +// +k8s:openapi-gen=true +type CoherenceUtilsSpec struct { + // Image pull policy. + // One of Always, Never, IfNotPresent. + // More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + // +optional + ImagePullPolicy *corev1.PullPolicy `json:"imagePullPolicy,omitempty"` +} + // EnsureImage ensures that the image value is set. func (in *ImageSpec) EnsureImage(image *string) bool { - if in != nil && in.Image == nil { + if in != nil && (in.Image == nil || *in.Image != *image) { in.Image = image return true } @@ -836,7 +962,10 @@ func (in *PersistenceSpec) AddVolumeMounts(c *corev1.Container) { if in.Volume != nil || in.PersistentVolumeClaim != nil { // Set the persistence location environment variable - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohPersistenceDir, Value: VolumeMountPathPersistence}) + if c.Name == ContainerNameCoherence { + // only do this for the Coherence container as it's env-vars are copied to the other containers + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohPersistenceDir, Value: VolumeMountPathPersistence}) + } // Add the persistence volume mount c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{ Name: VolumeNamePersistence, @@ -845,9 +974,12 @@ func (in *PersistenceSpec) AddVolumeMounts(c *corev1.Container) { } // Add the snapshot volume mount if required - if in != nil && in.Snapshots != nil && (in.Snapshots.Volume != nil || in.Snapshots.PersistentVolumeClaim != nil) { + if in.Snapshots != nil && (in.Snapshots.Volume != nil || in.Snapshots.PersistentVolumeClaim != nil) { // Set the snapshot location environment variable - c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohSnapshotDir, Value: VolumeMountPathSnapshots}) + if c.Name == ContainerNameCoherence { + // only do this for the Coherence container as it's env-vars are copied to the other containers + c.Env = append(c.Env, corev1.EnvVar{Name: EnvVarCohSnapshotDir, Value: VolumeMountPathSnapshots}) + } // Add the snapshot volume mount c.VolumeMounts = append(c.VolumeMounts, corev1.VolumeMount{ Name: VolumeNameSnapshots, @@ -1276,7 +1408,7 @@ func (in *NamedPortSpec) GetServicePort(d CoherenceResource) int32 { switch { case in == nil: return 0 - case in != nil && in.Service != nil && in.Service.Port != nil: + case in.Service != nil && in.Service.Port != nil: return *in.Service.Port case in.Port == 0 && strings.ToLower(in.Name) == PortNameMetrics: // special case for well known port - metrics @@ -1511,11 +1643,11 @@ func (in *JvmDebugSpec) CreateEnvVars() []corev1.EnvVar { corev1.EnvVar{Name: EnvVarJvmDebugPort, Value: p}, ) - if in != nil && in.Suspend != nil && *in.Suspend { + if in.Suspend != nil && *in.Suspend { envVars = append(envVars, corev1.EnvVar{Name: EnvVarJvmDebugSuspended, Value: "true"}) } - if in != nil && in.Attach != nil { + if in.Attach != nil { envVars = append(envVars, corev1.EnvVar{Name: EnvVarJvmDebugAttach, Value: *in.Attach}) } @@ -2736,14 +2868,16 @@ func (in *Resource) IsPresent() bool { return in.Spec != nil } +var errCannotConvert = errors.New("cannot convert to runtime.Object") + // As converts the Spec to the specified value. // This is done by serializing the Spec to json and deserializing into the specified object. func (in *Resource) As(o runtime.Object) error { if in == nil { - return fmt.Errorf("cannot convert to runtime.Object - resource is nil") + return errors.Wrap(errCannotConvert, "resource is nil") } if in.Spec == nil { - return fmt.Errorf("cannot convert resource - spec is nil") + return errors.Wrap(errCannotConvert, "spec is nil") } data, err := json.Marshal(in.Spec) diff --git a/api/v1/coherence_webhook.go b/api/v1/coherence_webhook.go index 52f51faea..5535f15dd 100644 --- a/api/v1/coherence_webhook.go +++ b/api/v1/coherence_webhook.go @@ -123,8 +123,6 @@ func SetCommonDefaults(in CoherenceResource) { // only set defaults for image names in new Coherence instances coherenceImage := operator.GetDefaultCoherenceImage() spec.EnsureCoherenceImage(&coherenceImage) - operatorImage := operator.GetDefaultOperatorImage() - spec.EnsureCoherenceOperatorImage(&operatorImage) // Set the features supported by this version in.AddAnnotation(AnnotationFeatureSuspend, "true") @@ -278,13 +276,6 @@ func (in *CommonWebHook) validateImages(c CoherenceResource) error { return errors.Errorf("invalid spec.image field, %s", err.Error()) } } - img = spec.GetCoherenceOperatorImage() - if img != nil { - _, err = reference.Parse(*img) - if err != nil { - return errors.Errorf("invalid spec.coherenceUtils.image field, %s", err.Error()) - } - } for _, c := range spec.InitContainers { _, err = reference.Parse(c.Image) if err != nil { diff --git a/api/v1/coherence_webhook_image_test.go b/api/v1/coherence_webhook_image_test.go index a3f7d0cb5..0aa76693a 100644 --- a/api/v1/coherence_webhook_image_test.go +++ b/api/v1/coherence_webhook_image_test.go @@ -66,38 +66,6 @@ func TestCoherenceCreateWithImageNameWithTrailingSpace(t *testing.T) { g.Expect(err).To(HaveOccurred()) } -func TestCoherenceCreateWithValidOperatorImageName(t *testing.T) { - g := NewGomegaWithT(t) - - c := coh.Coherence{ - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("test/coherence:1.0"), - }, - }, - }, - } - _, err := c.ValidateCreate(context.Background(), &c) - g.Expect(err).NotTo(HaveOccurred()) -} - -func TestCoherenceCreateWithInvalidOperatorImageName(t *testing.T) { - g := NewGomegaWithT(t) - - c := coh.Coherence{ - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("test/bad image name:1.0"), - }, - }, - }, - } - _, err := c.ValidateCreate(context.Background(), &c) - g.Expect(err).To(HaveOccurred()) -} - func TestCoherenceUpdateWithInvalidImageName(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1/coherence_webhook_job_test.go b/api/v1/coherence_webhook_job_test.go index 9eb2cf582..46558bce1 100644 --- a/api/v1/coherence_webhook_job_test.go +++ b/api/v1/coherence_webhook_job_test.go @@ -213,41 +213,6 @@ func TestJobCoherenceImageIsNotOverriddenWhenAlreadySet(t *testing.T) { g.Expect(*c.Spec.Image).To(Equal(image)) } -func TestJobUtilsImageIsSet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - - c := coh.CoherenceJob{} - err := c.Default(context.Background(), &c) - g.Expect(err).To(BeNil()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal("foo")) -} - -func TestJobUtilsImageIsNotOverriddenWhenAlreadySet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - image := "bar" - c := coh.CoherenceJob{ - Spec: coh.CoherenceJobResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: &image, - }, - }, - }, - } - - err := c.Default(context.Background(), &c) - g.Expect(err).To(BeNil()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal(image)) -} - func TestJobPersistenceModeChangeNotAllowed(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1/coherence_webhook_test.go b/api/v1/coherence_webhook_test.go index 5adb1dd7d..2f6370aee 100644 --- a/api/v1/coherence_webhook_test.go +++ b/api/v1/coherence_webhook_test.go @@ -233,41 +233,6 @@ func TestCoherenceImageIsNotOverriddenWhenAlreadySet(t *testing.T) { g.Expect(*c.Spec.Image).To(Equal(image)) } -func TestUtilsImageIsSet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - - c := coh.Coherence{} - err := c.Default(context.Background(), &c) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal("foo")) -} - -func TestUtilsImageIsNotOverriddenWhenAlreadySet(t *testing.T) { - g := NewGomegaWithT(t) - - viper.Set(operator.FlagOperatorImage, "foo") - image := "bar" - c := coh.Coherence{ - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: &image, - }, - }, - }, - } - - err := c.Default(context.Background(), &c) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(c.Spec.CoherenceUtils).NotTo(BeNil()) - g.Expect(c.Spec.CoherenceUtils.Image).NotTo(BeNil()) - g.Expect(*c.Spec.CoherenceUtils.Image).To(Equal(image)) -} - func TestPersistenceModeChangeNotAllowed(t *testing.T) { g := NewGomegaWithT(t) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 6ae9372a6..ffd7d645a 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -215,7 +215,7 @@ type CoherenceResourceSpec struct { Network *NetworkSpec `json:"network,omitempty"` // The configuration for the Coherence operator image name // +optional - CoherenceUtils *ImageSpec `json:"coherenceUtils,omitempty"` + CoherenceUtils *CoherenceUtilsSpec `json:"coherenceUtils,omitempty"` // The name to use for the service account to use when RBAC is enabled // The role bindings must already have been created as this chart does not create them it just // sets the serviceAccountName value in the Pod spec. @@ -374,25 +374,6 @@ func (in *CoherenceResourceSpec) EnsureCoherenceImage(coherenceImage *string) bo return false } -// GetCoherenceOperatorImage returns the name of the Operator image to use. -func (in *CoherenceResourceSpec) GetCoherenceOperatorImage() *string { - if in != nil && in.CoherenceUtils != nil { - return in.CoherenceUtils.Image - } - return nil -} - -// EnsureCoherenceOperatorImage ensures that the Coherence Operator image is set for the deployment. -// This ensures that the image is fixed to either that specified in the cluster spec or to the current default -// and means that the Helm controller does not upgrade the images if the Operator is upgraded. -func (in *CoherenceResourceSpec) EnsureCoherenceOperatorImage(imageName *string) bool { - if in.CoherenceUtils == nil { - in.CoherenceUtils = &ImageSpec{} - } - - return in.CoherenceUtils.EnsureImage(imageName) -} - // GetHealthPort returns the port that the health check endpoint will bind to. func (in *CoherenceResourceSpec) GetHealthPort() int32 { if in == nil || in.HealthPort == nil || *in.HealthPort <= 0 { @@ -698,14 +679,33 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou } cohContainer := in.CreateCoherenceContainer(deployment) + // Save any existing JDK_JAVA_OPTIONS env var from the Coherence container + // before the Application spec has a chance to change it + var jdkOptEnv *corev1.EnvVar + for _, ev := range cohContainer.Env { + if ev.Name == EnvVarJdkOptions { + jdkOptEnv = &ev + break + } + } + // Update the Coherence container with the application settings + in.Application.UpdateCoherenceContainer(&cohContainer) // Add additional ports for _, p := range in.Ports { cohContainer.Ports = append(cohContainer.Ports, p.CreatePort(deployment)) } + // Create the Operator init-container + initContainer := in.CreateOperatorInitContainer(deployment) + + // Create the Operator config files init-container + configInitContainer := in.CreateOperatorConfigInitContainer(deployment) + // append any additional VolumeMounts cohContainer.VolumeMounts = append(cohContainer.VolumeMounts, in.VolumeMounts...) + initContainer.VolumeMounts = append(initContainer.VolumeMounts, in.VolumeMounts...) + configInitContainer.VolumeMounts = append(configInitContainer.VolumeMounts, in.VolumeMounts...) podTemplate := corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ @@ -730,16 +730,16 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou ShareProcessNamespace: in.ShareProcessNamespace, Tolerations: in.Tolerations, TopologySpreadConstraints: in.EnsureTopologySpreadConstraints(deployment), - InitContainers: []corev1.Container{ - in.CreateOperatorInitContainer(deployment), - }, - Containers: []corev1.Container{cohContainer}, Volumes: []corev1.Volume{ {Name: VolumeNameUtils, VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, }, } + // The order of this append is very important, the jvmArgs must come second + podTemplate.Spec.InitContainers = append(podTemplate.Spec.InitContainers, initContainer, configInitContainer) + podTemplate.Spec.Containers = append(podTemplate.Spec.Containers, cohContainer) + // Add any network settings in.Network.UpdatePodTemplate(&podTemplate) // Add any JVM settings @@ -768,9 +768,33 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou sv.AddVolumes(&podTemplate) } + // Set the init-container environment variables to match the Coherence container + podTemplate.Spec.InitContainers[0].Env = append(podTemplate.Spec.InitContainers[0].Env, podTemplate.Spec.Containers[0].Env...) + podTemplate.Spec.InitContainers[1].Env = append(podTemplate.Spec.InitContainers[1].Env, podTemplate.Spec.Containers[0].Env...) + // The Application spec may have applied the JDK_JAVA_OPTIONS env var to the Coherence container + // so we need to remove it from the init-containers + in.replaceEnvVar(&podTemplate.Spec.InitContainers[0], EnvVarJdkOptions, jdkOptEnv) + in.replaceEnvVar(&podTemplate.Spec.InitContainers[1], EnvVarJdkOptions, jdkOptEnv) + return podTemplate } +func (in *CoherenceResourceSpec) replaceEnvVar(c *corev1.Container, name string, ev *corev1.EnvVar) { + env := c.Env + for i, e := range env { + if e.Name == name { + if ev == nil { + c.Env = env[:i] + c.Env = append(c.Env, env[i+1:]...) + } else { + c.Env[i] = *ev + c.Env[i].Name = name + } + break + } + } +} + func (in *CoherenceResourceSpec) GetImagePullSecrets() []corev1.LocalObjectReference { var secrets []corev1.LocalObjectReference @@ -805,17 +829,9 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe vm := in.CreateCommonVolumeMounts() lp, _ := in.Coherence.GetLocalPorts() - cmd := []string{RunnerCommand} - if in.Application != nil && in.Application.Type != nil && *in.Application.Type == "operator" { - cmd = append(cmd, in.Application.Args...) - } else { - cmd = append(cmd, "server") - } - c := corev1.Container{ - Name: ContainerNameCoherence, - Image: cohImage, - Command: cmd, + Name: ContainerNameCoherence, + Image: cohImage, Ports: []corev1.ContainerPort{ { Name: PortNameCoherence, @@ -859,8 +875,6 @@ func (in *CoherenceResourceSpec) CreateCoherenceContainer(deployment CoherenceRe }) } - in.Application.UpdateCoherenceContainer(&c) - if in.Resources != nil { // set the container resources if specified c.Resources = *in.Resources @@ -980,6 +994,8 @@ func (in *CoherenceResourceSpec) CreateDefaultEnv(deployment CoherenceResource) corev1.EnvVar{Name: EnvVarCohUtilDir, Value: VolumeMountPathUtils}, corev1.EnvVar{Name: EnvVarOperatorTimeout, Value: Int32PtrToStringWithDefault(in.OperatorRequestTimeout, 120)}, corev1.EnvVar{Name: EnvVarCohHealthPort, Value: Int32ToString(in.GetHealthPort())}, + corev1.EnvVar{Name: EnvVarCoherenceTTL, Value: "0"}, + corev1.EnvVar{Name: EnvVarCohCtlHome, Value: VolumeMountPathUtils}, ) ann := deployment.GetAnnotations() @@ -1050,29 +1066,38 @@ func (in *CoherenceResourceSpec) UpdateDefaultLivenessProbeAction(probe *corev1. // CreateOperatorInitContainer creates the Operator init-container spec. func (in *CoherenceResourceSpec) CreateOperatorInitContainer(deployment CoherenceResource) corev1.Container { + image := operator.GetDefaultOperatorImage() + return in.createInitContainer(deployment, ContainerNameOperatorInit, image, []string{RunnerInitCommand, RunnerInit}) +} + +// CreateOperatorConfigInitContainer creates the JVM args file init-container spec. +func (in *CoherenceResourceSpec) CreateOperatorConfigInitContainer(deployment CoherenceResource) corev1.Container { var image string - if in.CoherenceUtils == nil || in.CoherenceUtils.Image == nil { - image = operator.GetDefaultOperatorImage() + + if in.Image == nil { + image = operator.GetDefaultCoherenceImage() } else { - image = *in.CoherenceUtils.Image + image = *in.Image } - vm := in.CreateCommonVolumeMounts() + c := in.createInitContainer(deployment, ContainerNameOperatorConfig, image, []string{RunnerCommand, RunnerConfig}) - env := []corev1.EnvVar{ - {Name: EnvVarCohUtilDir, Value: VolumeMountPathUtils}, + if in.Application != nil && in.Application.WorkingDir != nil { + c.WorkingDir = *in.Application.WorkingDir } - clusterName := deployment.GetCoherenceClusterName() - if clusterName != "" { - env = append(env, corev1.EnvVar{Name: EnvVarCohClusterName, Value: clusterName}) - } + return c +} + +// CreateOperatorInitContainer creates the Operator init-container spec. +func (in *CoherenceResourceSpec) createInitContainer(deployment CoherenceResource, name, image string, cmd []string) corev1.Container { + + vm := in.CreateCommonVolumeMounts() c := corev1.Container{ - Name: ContainerNameOperatorInit, + Name: name, Image: image, - Command: []string{RunnerInitCommand, RunnerInit}, - Env: env, + Command: cmd, SecurityContext: in.ContainerSecurityContext, VolumeMounts: vm, } diff --git a/api/v1/common_test.go b/api/v1/common_test.go index 42f01447c..8cbe5c9e1 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -29,6 +29,10 @@ import ( const ( testCoherenceImage = "oracle/coherence-ce:1.2.3" testOperatorImage = "oracle/operator:1.2.3" + + actualFilePattern = coh.FileNamePattern + "-Actual.json" + expectedFilePattern = coh.FileNamePattern + "-Expected.json" + diffFilePattern = coh.FileNamePattern + "-Diff.txt" ) // Returns a pointer to an int32 @@ -118,13 +122,13 @@ func assertStatefulSet(t *testing.T, res coh.Resource, stsExpected *appsv1.State // Dump the json for the actual StatefulSet for debugging failures jsonActual, err := json.MarshalIndent(stsActual, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Actual.json", dir, os.PathSeparator, stsActual.Name), jsonActual, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(actualFilePattern, dir, os.PathSeparator, stsActual.Name), jsonActual, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) // Dump the json for the expected StatefulSet for debugging failures jsonExpected, err := json.MarshalIndent(stsExpected, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Expected.json", dir, os.PathSeparator, stsActual.Name), jsonExpected, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(expectedFilePattern, dir, os.PathSeparator, stsActual.Name), jsonExpected, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) assertEnvironmentVariables(t, stsActual, stsExpected) @@ -134,7 +138,7 @@ func assertStatefulSet(t *testing.T, res coh.Resource, stsExpected *appsv1.State msg := "StatefulSets not equal:" if len(diffs) > 0 { // Dump the diffs - err = os.WriteFile(fmt.Sprintf("%s%c%s-Diff.txt", dir, os.PathSeparator, stsActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) + err = os.WriteFile(fmt.Sprintf(diffFilePattern, dir, os.PathSeparator, stsActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) for _, diff := range diffs { msg = msg + "\n" + diff @@ -173,23 +177,22 @@ func assertJob(t *testing.T, res coh.Resource, expected *batchv1.Job) { // Dump the json for the actual StatefulSet for debugging failures jsonActual, err := json.MarshalIndent(jobActual, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Actual.json", dir, os.PathSeparator, jobActual.Name), jsonActual, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(actualFilePattern, dir, os.PathSeparator, jobActual.Name), jsonActual, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) // Dump the json for the expected StatefulSet for debugging failures jsonExpected, err := json.MarshalIndent(expected, "", " ") g.Expect(err).NotTo(HaveOccurred()) - err = os.WriteFile(fmt.Sprintf("%s%c%s-Expected.json", dir, os.PathSeparator, jobActual.Name), jsonExpected, os.ModePerm) + err = os.WriteFile(fmt.Sprintf(expectedFilePattern, dir, os.PathSeparator, jobActual.Name), jsonExpected, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) - assertEnvironmentVariablesForJob(t, jobActual, expected) assertEnvironmentVariablesForJob(t, jobActual, expected) diffs := deep.Equal(*jobActual, *expected) msg := "Jobs not equal:" if len(diffs) > 0 { // Dump the diffs - err = os.WriteFile(fmt.Sprintf("%s%c%s-Diff.txt", dir, os.PathSeparator, jobActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) + err = os.WriteFile(fmt.Sprintf(diffFilePattern, dir, os.PathSeparator, jobActual.Name), []byte(strings.Join(diffs, "\n")), os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) for _, diff := range diffs { msg = msg + "\n" + diff @@ -269,7 +272,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe envVars := []corev1.EnvVar{ { - Name: "COH_CLUSTER_NAME", + Name: "COHERENCE_CLUSTER", Value: deployment.GetName(), }, { @@ -281,11 +284,11 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Value: fmt.Sprintf("%d", coh.DefaultUnicastPortAdjust), }, { - Name: "COH_HEALTH_PORT", + Name: "COHERENCE_HEALTH_HTTP_PORT", Value: fmt.Sprintf("%d", spec.GetHealthPort()), }, { - Name: "COH_MACHINE_NAME", + Name: "COHERENCE_MACHINE", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "spec.nodeName", @@ -293,7 +296,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "COH_MEMBER_NAME", + Name: "COHERENCE_MEMBER", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "metadata.name", @@ -301,15 +304,15 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "COH_METRICS_ENABLED", + Name: "COHERENCE_METRICS_ENABLED", Value: "false", }, { - Name: "COH_MGMT_ENABLED", + Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "false", }, { - Name: "COH_POD_UID", + Name: "COHERENCE_OPERATOR_POD_UID", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "metadata.uid", @@ -317,23 +320,23 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "COH_RACK_INFO_LOCATION", - Value: "http://$(OPERATOR_HOST)/rack/$(COH_MACHINE_NAME)", + Name: "COHERENCE_OPERATOR_RACK_INFO_LOCATION", + Value: "http://$(COHERENCE_OPERATOR_HOST)/rack/$(COHERENCE_MACHINE)", }, { - Name: "COH_ROLE", + Name: "COHERENCE_ROLE", Value: deployment.GetRoleName(), }, { - Name: "COH_SITE_INFO_LOCATION", - Value: "http://$(OPERATOR_HOST)/site/$(COH_MACHINE_NAME)", + Name: "COHERENCE_OPERATOR_SITE_INFO_LOCATION", + Value: "http://$(COHERENCE_OPERATOR_HOST)/site/$(COHERENCE_MACHINE)", }, { - Name: "COH_UTIL_DIR", + Name: "COHERENCE_OPERATOR_UTIL_DIR", Value: coh.VolumeMountPathUtils, }, { - Name: "COH_WKA", + Name: "COHERENCE_WKA", Value: deployment.GetWKA(), }, { @@ -345,7 +348,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Value: "true", }, { - Name: "OPERATOR_HOST", + Name: "COHERENCE_OPERATOR_HOST", ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{Name: coh.OperatorConfigName}, @@ -355,14 +358,26 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, }, { - Name: "OPERATOR_REQUEST_TIMEOUT", + Name: "COHERENCE_OPERATOR_REQUEST_TIMEOUT", Value: "120", }, + { + Name: "COHERENCE_TTL", + Value: "0", + }, + { + Name: "COHCTL_HOME", + Value: coh.VolumeMountPathUtils, + }, + { + Name: "COHERENCE_IPMONITOR_PINGTIMEOUT", + Value: "0", + }, } if deployment.GetType() == coh.CoherenceTypeJob { envVars = append(envVars, corev1.EnvVar{ - Name: "COH_STORAGE_ENABLED", + Name: "COHERENCE_DISTRIBUTED_LOCALSTORAGE", Value: "false", }) } @@ -373,7 +388,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe cohContainer := corev1.Container{ Name: coh.ContainerNameCoherence, Image: testCoherenceImage, - Command: []string{coh.RunnerCommand, "server"}, + Command: []string{"java", fmt.Sprintf("@%s/%s", coh.VolumeMountPathUtils, coh.OperatorCoherenceArgsFile)}, Ports: []corev1.ContainerPort{ { Name: coh.PortNameCoherence, @@ -410,7 +425,6 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe ReadOnly: false, }, }, - Env: envVars, } if cohImage := spec.GetCoherenceImage(); cohImage != nil { @@ -422,16 +436,25 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Name: coh.ContainerNameOperatorInit, Image: testOperatorImage, Command: []string{coh.RunnerInitCommand, coh.RunnerInit}, - Env: []corev1.EnvVar{ + VolumeMounts: []corev1.VolumeMount{ { - Name: "COH_CLUSTER_NAME", - Value: deployment.GetName(), + Name: coh.VolumeNameJVM, + MountPath: coh.VolumeMountPathJVM, + ReadOnly: false, }, { - Name: "COH_UTIL_DIR", - Value: coh.VolumeMountPathUtils, + Name: coh.VolumeNameUtils, + MountPath: coh.VolumeMountPathUtils, + ReadOnly: false, }, }, + } + + // The Operator JVM Args Init-Container + argsContainer := corev1.Container{ + Name: coh.ContainerNameOperatorConfig, + Image: testCoherenceImage, + Command: []string{coh.RunnerCommand, coh.RunnerConfig}, VolumeMounts: []corev1.VolumeMount{ { Name: coh.VolumeNameJVM, @@ -446,9 +469,9 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe }, } - if operatorImage := spec.GetCoherenceOperatorImage(); operatorImage != nil { - initContainer.Image = *operatorImage - } + cohContainer.Env = append(cohContainer.Env, envVars...) + initContainer.Env = append(initContainer.Env, envVars...) + argsContainer.Env = append(argsContainer.Env, envVars...) annotations := make(map[string]string) annotations[coh.AnnotationIstioConfig] = coh.DefaultIstioConfigAnnotationValue @@ -459,7 +482,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe Annotations: annotations, }, Spec: corev1.PodSpec{ - InitContainers: []corev1.Container{initContainer}, + InitContainers: []corev1.Container{initContainer, argsContainer}, Containers: []corev1.Container{cohContainer}, Volumes: []corev1.Volume{ { @@ -572,12 +595,24 @@ func sortPortsForPodTemplate(template *corev1.PodTemplateSpec) { } } +func addEnvVarsToAll(sts *appsv1.StatefulSet, envVars ...corev1.EnvVar) { + addEnvVars(sts, coh.ContainerNameCoherence, envVars...) + addEnvVars(sts, coh.ContainerNameOperatorInit, envVars...) + addEnvVars(sts, coh.ContainerNameOperatorConfig, envVars...) +} + func addEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...corev1.EnvVar) { if sts != nil { addEnvVarsToPodSpec(&sts.Spec.Template, containerName, envVars...) } } +func addEnvVarsToAllJobContainers(job *batchv1.Job, envVars ...corev1.EnvVar) { + addEnvVarsToJob(job, coh.ContainerNameCoherence, envVars...) + addEnvVarsToJob(job, coh.ContainerNameOperatorInit, envVars...) + addEnvVarsToJob(job, coh.ContainerNameOperatorConfig, envVars...) +} + func addEnvVarsToJob(job *batchv1.Job, containerName string, envVars ...corev1.EnvVar) { if job != nil { addEnvVarsToPodSpec(&job.Spec.Template, containerName, envVars...) @@ -617,6 +652,69 @@ func addEnvVarsToContainer(c *corev1.Container, envVars ...corev1.EnvVar) { } } +func removeEnvVarsFromAll(sts *appsv1.StatefulSet, envVars ...string) { + removeEnvVars(sts, coh.ContainerNameCoherence, envVars...) + removeEnvVars(sts, coh.ContainerNameOperatorInit, envVars...) + removeEnvVars(sts, coh.ContainerNameOperatorConfig, envVars...) +} + +func removeEnvVars(sts *appsv1.StatefulSet, containerName string, envVars ...string) { + if sts != nil { + removeEnvVarsFromPodSpec(&sts.Spec.Template, containerName, envVars...) + } +} + +func removeEnvVarsFromAllJobContainers(job *batchv1.Job, envVars ...string) { + removeEnvVarsFromJob(job, coh.ContainerNameCoherence, envVars...) + removeEnvVarsFromJob(job, coh.ContainerNameOperatorInit, envVars...) + removeEnvVarsFromJob(job, coh.ContainerNameOperatorConfig, envVars...) +} + +func removeEnvVarsFromJob(job *batchv1.Job, containerName string, envVars ...string) { + if job != nil { + removeEnvVarsFromPodSpec(&job.Spec.Template, containerName, envVars...) + } +} + +func removeEnvVarsFromPodSpec(template *corev1.PodTemplateSpec, containerName string, envVars ...string) { + for i, c := range template.Spec.InitContainers { + if c.Name == containerName { + removeEnvVarsFromContainer(&c, envVars...) + template.Spec.InitContainers[i] = c + } + } + for i, c := range template.Spec.Containers { + if c.Name == containerName { + removeEnvVarsFromContainer(&c, envVars...) + template.Spec.Containers[i] = c + } + } +} + +func removeEnvVarsFromContainer(c *corev1.Container, envVars ...string) { + env := c.Env + if c.Env == nil || len(env) == 0 { + return + } + + for _, name := range envVars { + for e, ev := range c.Env { + if ev.Name == name { + switch { + case e == 0: + env = env[:1] + case (e + 1) == len(env): + env = env[:e] + default: + env = append(env[:e], env[e+1:]...) + } + break + } + } + } + c.Env = env +} + func addEnvVarsFrom(sts *appsv1.StatefulSet, containerName string, envVars ...corev1.EnvFromSource) { if sts != nil { addEnvVarsFromToPodSpec(&sts.Spec.Template, containerName, envVars...) diff --git a/api/v1/constants.go b/api/v1/constants.go index 37ce40ef4..462be4d59 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -78,6 +78,8 @@ const ( ContainerNameCoherence = "coherence" // ContainerNameOperatorInit is the Operator init-container name ContainerNameOperatorInit = "coherence-k8s-utils" + // ContainerNameOperatorConfig is the Operator config files init-container name + ContainerNameOperatorConfig = "coherence-k8s-config" // VolumeNamePersistence is the name of the persistence volume VolumeNamePersistence = "persistence-volume" @@ -115,8 +117,10 @@ const ( // RunnerInitCommand is the start command for the Operator init-container RunnerInitCommand = "/files/runner" - // RunnerInit is the command line argument for the Operator init-container + // RunnerInit is the command line argument for the Operator intialize init-container RunnerInit = "init" + // RunnerConfig is the command line argument for the Operator config init-container + RunnerConfig = "config" // ServiceMonitorKind is the Prometheus ServiceMonitor resource API Kind ServiceMonitorKind = "ServiceMonitor" @@ -167,9 +171,33 @@ const ( // OperatorConfigKeyHost is the key used in the Operator configuration Secret OperatorConfigKeyHost = "operatorhost" // OperatorSiteURL is the default Operator site query URL - OperatorSiteURL = "http://$(OPERATOR_HOST)/site/$(COH_MACHINE_NAME)" + OperatorSiteURL = "http://$(COHERENCE_OPERATOR_HOST)/site/$(COHERENCE_MACHINE)" // OperatorRackURL is the default Operator rack query URL - OperatorRackURL = "http://$(OPERATOR_HOST)/rack/$(COH_MACHINE_NAME)" + OperatorRackURL = "http://$(COHERENCE_OPERATOR_HOST)/rack/$(COHERENCE_MACHINE)" + + // OperatorCoherenceArgsFile is the name of the file in the utils directory containing the full set of + // JVM arguments to run the Coherence container + OperatorCoherenceArgsFile = "coherence-container-args.txt" + // OperatorEntryPointArgsFile is the arguments file to add to the JDK_JAVA_OPTIONS environment variable + // when running the image entry point + OperatorEntryPointArgsFile = "coherence-entrypoint-args.txt" + // OperatorJvmArgsFile is the name of the file in the utils directory containing the JVM arguments + OperatorJvmArgsFile = "coherence-jvm-args.txt" + // OperatorClasspathFile is the name of the file in the utils directory containing the JVM class path + OperatorClasspathFile = "coherence-class-path.txt" + // OperatorMainClassFile is the name of the file in the utils directory containing the main class name + OperatorMainClassFile = "coherence-main-class.txt" + // OperatorSpringBootArgsFile is the name of the file in the utils directory containing the SpringBoot JVM args + OperatorSpringBootArgsFile = "coherence-spring-args.txt" + // OperatorJarFileSuffix is the suffix to append to the utils directory to locate the Operator jar file. + OperatorJarFileSuffix = "/lib/coherence-operator.jar" + // OperatorConfigDirSuffix is the suffix to append to the utils directory to locate the Operator config directory. + OperatorConfigDirSuffix = "/config" + + // FileNamePattern is a formatting pattern for a directory separator and file name + FileNamePattern = "%s%c%s" + // ArgumentFileNamePattern is a formatting pattern for a JDK argument fle name: directory separator and file name + ArgumentFileNamePattern = "@" + FileNamePattern // DefaultReadinessPath is the default readiness endpoint path DefaultReadinessPath = "/ready" @@ -179,50 +207,60 @@ const ( // DefaultCnbpLauncher is the Cloud Native Build Pack launcher executable DefaultCnbpLauncher = "/cnb/lifecycle/launcher" - EnvVarAppType = "COH_APP_TYPE" - EnvVarAppMainClass = "COH_MAIN_CLASS" - EnvVarAppMainArgs = "COH_MAIN_ARGS" - EnvVarOperatorHost = "OPERATOR_HOST" - EnvVarOperatorTimeout = "OPERATOR_REQUEST_TIMEOUT" - EnvVarOperatorAllowResume = "OPERATOR_ALLOW_RESUME" - EnvVarOperatorResumeServices = "OPERATOR_RESUME_SERVICES" - EnvVarUseOperatorHealthCheck = "OPERATOR_HEALTH_CHECK" - EnvVarCoherenceHome = "COHERENCE_HOME" - EnvVarCohDependencyModules = "DEPENDENCY_MODULES" - EnvVarCohSkipVersionCheck = "COH_SKIP_VERSION_CHECK" - EnvVarCohClusterName = "COH_CLUSTER_NAME" - EnvVarCohIdentity = "COH_IDENTITY" - EnvVarCohWka = "COH_WKA" - EnvVarCohAppDir = "COH_APP_DIR" - EnvVarCohMachineName = "COH_MACHINE_NAME" - EnvVarCohMemberName = "COH_MEMBER_NAME" - EnvVarCohPodUID = "COH_POD_UID" - EnvVarCohSkipSite = "COH_SKIP_SITE" - EnvVarCohSite = "COH_SITE_INFO_LOCATION" - EnvVarCoherenceSite = "COHERENCE_SITE" - EnvVarCohRack = "COH_RACK_INFO_LOCATION" - EnvVarCoherenceRack = "COHERENCE_RACK" - EnvVarCohRole = "COH_ROLE" - EnvVarCohUtilDir = "COH_UTIL_DIR" - EnvVarCohUtilLibDir = "COH_UTIL_LIB_DIR" - EnvVarCohHealthPort = "COH_HEALTH_PORT" - EnvVarCohCacheConfig = "COH_CACHE_CONFIG" - EnvVarCohOverride = "COH_OVERRIDE_CONFIG" - EnvVarCohLogLevel = "COH_LOG_LEVEL" - EnvVarCohStorage = "COH_STORAGE_ENABLED" - EnvVarCohPersistenceMode = "COH_PERSISTENCE_MODE" - EnvVarCohPersistenceDir = "COH_PERSISTENCE_DIR" - EnvVarCohSnapshotDir = "COH_SNAPSHOT_DIR" - EnvVarCohTracingRatio = "COH_TRACING_RATIO" - EnvVarCohAllowEndangered = "COH_ALLOW_ENDANGERED" - EnvVarCohMgmtPrefix = "COH_MGMT" - EnvVarCohMetricsPrefix = "COH_METRICS" + EnvVarAppType = "COHERENCE_OPERATOR_APP_TYPE" + EnvVarAppMainClass = "COHERENCE_OPERATOR_MAIN_CLASS" + EnvVarAppMainArgs = "COHERENCE_OPERATOR_MAIN_ARGS" + EnvVarOperatorHost = "COHERENCE_OPERATOR_HOST" + EnvVarOperatorTimeout = "COHERENCE_OPERATOR_REQUEST_TIMEOUT" + EnvVarOperatorAllowResume = "COHERENCE_OPERATOR_ALLOW_RESUME" + EnvVarOperatorResumeServices = "COHERENCE_OPERATOR_RESUME_SERVICES" + EnvVarUseOperatorHealthCheck = "COHERENCE_OPERATOR_HEALTH_CHECK" + EnvVarCohDependencyModules = "COHERENCE_OPERATOR_DEPENDENCY_MODULES" + EnvVarCohSkipVersionCheck = "COHERENCE_OPERATOR_SKIP_VERSION_CHECK" + EnvVarCohPodUID = "COHERENCE_OPERATOR_POD_UID" + EnvVarCohIdentity = "COHERENCE_OPERATOR_IDENTITY" + EnvVarCohAppDir = "COHERENCE_OPERATOR_APP_DIR" + EnvVarCohSkipSite = "COHERENCE_OPERATOR_SKIP_SITE" + EnvVarCohSite = "COHERENCE_OPERATOR_SITE_INFO_LOCATION" + EnvVarCohRack = "COHERENCE_OPERATOR_RACK_INFO_LOCATION" + EnvVarCohUtilDir = "COHERENCE_OPERATOR_UTIL_DIR" + EnvVarCohUtilLibDir = "COHERENCE_OPERATOR_UTIL_LIB_DIR" + EnvVarCohAllowEndangered = "COHERENCE_OPERATOR_ALLOW_ENDANGERED" + EnvVarSpringBootFatJar = "COHERENCE_OPERATOR_SPRING_BOOT_FAT_JAR" + EnvVarCnbpEnabled = "COHERENCE_OPERATOR_CNBP_ENABLED" + EnvVarCnbpLauncher = "COHERENCE_OPERATOR_CNBP_LAUNCHER" + EnvVarCohForceExit = "COHERENCE_OPERATOR_FORCE_EXIT" + EnvVarCohCliProtocol = "COHERENCE_OPERATOR_CLI_PROTOCOL" + + EnvVarCoherenceHome = "COHERENCE_HOME" + EnvVarCohClusterName = "COHERENCE_CLUSTER" + EnvVarCohWka = "COHERENCE_WKA" + EnvVarCohMachineName = "COHERENCE_MACHINE" + EnvVarCohMemberName = "COHERENCE_MEMBER" + EnvVarCoherenceSite = "COHERENCE_SITE" + EnvVarCoherenceRack = "COHERENCE_RACK" + EnvVarCohRole = "COHERENCE_ROLE" + EnvVarCohHealthPort = "COHERENCE_HEALTH_HTTP_PORT" + EnvVarCohCacheConfig = "COHERENCE_CACHECONFIG" + EnvVarCohOverride = "COHERENCE_OVERRIDE" + EnvVarCohLogLevel = "COHERENCE_LOG_LEVEL" + EnvVarCohStorage = "COHERENCE_DISTRIBUTED_LOCALSTORAGE" + EnvVarCohPersistenceMode = "COHERENCE_DISTRIBUTED_PERSISTENCE_MODE" + EnvVarCohPersistenceDir = "COHERENCE_DISTRIBUTED_PERSISTENCE_BASE_DIR" + EnvVarCohSnapshotDir = "COHERENCE_DISTRIBUTED_PERSISTENCE_SNAPSHOT_DIR" + EnvVarCohTracingRatio = "COHERENCE_TRACING_RATIO" + EnvVarCohMgmtPrefix = "COHERENCE_MANAGEMENT" + EnvVarCohMetricsPrefix = "COHERENCE_METRICS" + EnvVarCoherenceLocalPort = "COHERENCE_LOCALPORT" + EnvVarCoherenceLocalPortAdjust = "COHERENCE_LOCALPORT_ADJUST" + EnvVarCoherenceTTL = "COHERENCE_TTL" + EnvVarEnableIPMonitor = "COHERENCE_ENABLE_IPMONITOR" + EnvVarIPMonitorPingTimeout = "COHERENCE_IPMONITOR_PINGTIMEOUT" + + EnvVarCohCtlHome = "COHCTL_HOME" + EnvVarCohEnabledSuffix = "_ENABLED" EnvVarCohPortSuffix = "_PORT" - EnvVarCohForceExit = "COH_FORCE_EXIT" - EnvVarCoherenceLocalPort = "COHERENCE_LOCALPORT" - EnvVarCoherenceLocalPortAdjust = "COHERENCE_LOCALPORT_ADJUST" - EnvVarEnableIPMonitor = "COH_ENABLE_IPMONITOR" EnvVarSuffixSSLEnabled = "_SSL_ENABLED" EnvVarSuffixSSLCerts = "_SSL_CERTS" EnvVarSuffixSSLKeyStore = "_SSL_KEYSTORE" @@ -237,37 +275,110 @@ const ( EnvVarSuffixSSLTrustStoreProvider = "_SSL_TRUSTSTORE_PROVIDER" EnvVarSuffixSSLTrustStoreType = "_SSL_TRUSTSTORE_TYPE" EnvVarSuffixSSLRequireClientCert = "_SSL_REQUIRE_CLIENT_CERT" - EnvVarJavaHome = "JAVA_HOME" - EnvVarJavaClasspath = "CLASSPATH" - EnvVarJvmClasspathJib = "JVM_USE_JIB_CLASSPATH" - EnvVarJvmExtraClasspath = "JVM_EXTRA_CLASSPATH" - EnvVarJvmArgs = "JVM_ARGS" - EnvVarJvmUseContainerLimits = "JVM_USE_CONTAINER_LIMITS" - EnvVarJvmShowSettings = "JVM_SHOW_SETTINGS" - EnvVarJvmDebugEnabled = "JVM_DEBUG_ENABLED" - EnvVarJvmDebugPort = "JVM_DEBUG_PORT" - EnvVarJvmDebugSuspended = "JVM_DEBUG_SUSPEND" - EnvVarJvmDebugAttach = "JVM_DEBUG_ATTACH" - EnvVarJvmGcArgs = "JVM_GC_ARGS" - EnvVarJvmGcCollector = "JVM_GC_COLLECTOR" - EnvVarJvmGcLogging = "JVM_GC_LOGGING" - EnvVarJvmMemoryHeap = "JVM_HEAP_SIZE" - EnvVarJvmMemoryInitialHeap = "JVM_INITIAL_HEAP_SIZE" - EnvVarJvmMemoryMaxHeap = "JVM_MAX_HEAP_SIZE" - EnvVarJvmMaxRAM = "JVM_MAX_RAM" - EnvVarJvmRAMPercentage = "JVM_RAM_PERCENTAGE" - EnvVarJvmInitialRAMPercentage = "JVM_INITIAL_RAM_PERCENTAGE" - EnvVarJvmMaxRAMPercentage = "JVM_MAX_RAM_PERCENTAGE" - EnvVarJvmMinRAMPercentage = "JVM_MIN_RAM_PERCENTAGE" - EnvVarJvmMemoryDirect = "JVM_DIRECT_MEMORY_SIZE" - EnvVarJvmMemoryStack = "JVM_STACK_SIZE" - EnvVarJvmMemoryMeta = "JVM_METASPACE_SIZE" - EnvVarJvmMemoryNativeTracking = "JVM_NATIVE_MEMORY_TRACKING" - EnvVarJvmOomExit = "JVM_OOM_EXIT" - EnvVarJvmOomHeapDump = "JVM_OOM_HEAP_DUMP" - EnvVarSpringBootFatJar = "COH_SPRING_BOOT_FAT_JAR" - EnvVarCnbpEnabled = "COH_CNBP_ENABLED" - EnvVarCnbpLauncher = "COH_CNBP_LAUNCHER" + + EnvVarJavaHome = "JAVA_HOME" + EnvVarJdkOptions = "JDK_JAVA_OPTIONS" + EnvVarJavaClasspath = "CLASSPATH" + EnvVarJvmClasspathJib = "JVM_USE_JIB_CLASSPATH" + EnvVarJvmExtraClasspath = "JVM_EXTRA_CLASSPATH" + EnvVarJvmArgs = "JVM_ARGS" + EnvVarJvmUseContainerLimits = "JVM_USE_CONTAINER_LIMITS" + EnvVarJvmShowSettings = "JVM_SHOW_SETTINGS" + EnvVarJvmDebugEnabled = "JVM_DEBUG_ENABLED" + EnvVarJvmDebugPort = "JVM_DEBUG_PORT" + EnvVarJvmDebugSuspended = "JVM_DEBUG_SUSPEND" + EnvVarJvmDebugAttach = "JVM_DEBUG_ATTACH" + EnvVarJvmGcArgs = "JVM_GC_ARGS" + EnvVarJvmGcCollector = "JVM_GC_COLLECTOR" + EnvVarJvmGcLogging = "JVM_GC_LOGGING" + EnvVarJvmMemoryHeap = "JVM_HEAP_SIZE" + EnvVarJvmMemoryInitialHeap = "JVM_INITIAL_HEAP_SIZE" + EnvVarJvmMemoryMaxHeap = "JVM_MAX_HEAP_SIZE" + EnvVarJvmMaxRAM = "JVM_MAX_RAM" + EnvVarJvmRAMPercentage = "JVM_RAM_PERCENTAGE" + EnvVarJvmInitialRAMPercentage = "JVM_INITIAL_RAM_PERCENTAGE" + EnvVarJvmMaxRAMPercentage = "JVM_MAX_RAM_PERCENTAGE" + EnvVarJvmMinRAMPercentage = "JVM_MIN_RAM_PERCENTAGE" + EnvVarJvmMemoryDirect = "JVM_DIRECT_MEMORY_SIZE" + EnvVarJvmMemoryStack = "JVM_STACK_SIZE" + EnvVarJvmMemoryMeta = "JVM_METASPACE_SIZE" + EnvVarJvmMemoryNativeTracking = "JVM_NATIVE_MEMORY_TRACKING" + EnvVarJvmOomExit = "JVM_OOM_EXIT" + EnvVarJvmOomHeapDump = "JVM_OOM_HEAP_DUMP" + + SystemPropertyPattern = "-D%s=%s" + + SysPropCoherenceCacheConfig = "coherence.cacheconfig" + SysPropCoherenceCluster = "coherence.cluster" + SysPropCoherenceDistributedLocalStorage = "coherence.distributed.localstorage" + SysPropCoherenceGrpcEnabled = "coherence.grpc.enabled" + SysPropCoherenceHealthHttpPort = "coherence.health.http.port" + SysPropCoherenceIpMonitor = "coherence.ipmonitor.pingtimeout" + SysPropCoherenceLocalPortAdjust = "coherence.localport.adjust" + SysPropCoherenceLogLevel = "coherence.log.level" + SysPropCoherenceMachine = "coherence.machine" + SysPropCoherenceManagementHttp = "coherence.management.http" + SysPropCoherenceManagementHttpPort = "coherence.management.http.port" + SysPropCoherenceMember = "coherence.member" + SysPropCoherenceMetricsHttpEnabled = "coherence.metrics.http.enabled" + SysPropCoherenceMetricsHttpPort = "coherence.metrics.http.port" + SysPropCoherenceOverride = "coherence.override" + SysPropCoherencePersistenceBaseDir = "coherence.distributed.persistence.base.dir" + SysPropCoherencePersistenceMode = "coherence.distributed.persistence-mode" + SysPropCoherencePersistenceSnapshotDir = "coherence.distributed.persistence.snapshot.dir" + SysPropCoherenceRole = "coherence.role" + SysPropCoherenceRack = "coherence.rack" + SysPropCoherenceSite = "coherence.site" + SysPropCoherenceTracingRatio = "coherence.tracing.ratio" + SysPropCoherenceTTL = "coherence.ttl" + SysPropCoherenceWKA = "coherence.wka" + + SysPropOperatorForceExit = "coherence.operator.force.exit" + SysPropOperatorHealthEnabled = "coherence.operator.health.enabled" + SysPropOperatorHealthPort = "coherence.operator.health.port" + SysPropOperatorIdentity = "coherence.operator.identity" + SysPropOperatorOverride = "coherence.k8s.override" + + SysPropSpringLoaderMain = "loader.main" + SysPropSpringLoaderPath = "loader.path" + + JvmOptClassPath = "-cp" + JvmOptUnlockDiagnosticVMOptions = "-XX:+UnlockDiagnosticVMOptions" + JvmOptNativeMemoryTracking = "-XX:NativeMemoryTracking" + + // AppTypeNone is the argument to specify no application type. + AppTypeNone = "" + // AppTypeJava is the argument to specify a Java application. + AppTypeJava = "java" + // AppTypeCoherence is the argument to specify a Coherence application. + AppTypeCoherence = "coherence" + // AppTypeHelidon is the argument to specify a Helidon application. + AppTypeHelidon = "helidon" + // AppTypeSpring2 is the argument to specify an exploded Spring Boot 2.x application. + AppTypeSpring2 = "spring" + // AppTypeSpring3 is the argument to specify an exploded Spring Boot 3.x application. + AppTypeSpring3 = "spring3" + // AppTypeOperator is the argument to specify running an Operator command. + AppTypeOperator = "operator" + // AppTypeJShell is the argument to specify a JShell application. + AppTypeJShell = "jshell" + + // DefaultMain is an indicator to run the default main class. + DefaultMain = "$DEFAULT$" + // HelidonMain is the default Helidon main class name. + HelidonMain = "io.helidon.microprofile.cdi.Main" + // ServerMain is the default server main class name. + ServerMain = "com.oracle.coherence.k8s.Main" + // SpringBootMain2 is the default Spring Boot 2.x main class name. + SpringBootMain2 = "org.springframework.boot.loader.PropertiesLauncher" + // SpringBootMain3 is the default Spring Boot 3.x main class name. + SpringBootMain3 = "org.springframework.boot.loader.launch.PropertiesLauncher" + // ConsoleMain is the Coherence console main class + ConsoleMain = "com.tangosol.net.CacheFactory" + // QueryPlusMain is the main class to run Coherence Query Plus + QueryPlusMain = "com.tangosol.coherence.dslquery.QueryPlus" + // SleepMain is the main class to run Operator sleep command + SleepMain = "com.oracle.coherence.k8s.Sleep" ) var ( diff --git a/api/v1/create_job_add_containers_test.go b/api/v1/create_job_add_containers_test.go index 0c64c1ca6..862ce8055 100644 --- a/api/v1/create_job_add_containers_test.go +++ b/api/v1/create_job_add_containers_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -245,6 +245,8 @@ func TestCreateJobWithExtraContainerAndVolume(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) jobExpected.Spec.Template.Spec.Volumes = append(jobExpected.Spec.Template.Spec.Volumes, vol) jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mount) + jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mount) + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mount) // Create expected container conExpected := corev1.Container{ diff --git a/api/v1/create_job_applicationspec_test.go b/api/v1/create_job_applicationspec_test.go index db67ee083..7d346c64e 100644 --- a/api/v1/create_job_applicationspec_test.go +++ b/api/v1/create_job_applicationspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package v1_test import ( coh "github.com/oracle/coherence-operator/api/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "testing" ) @@ -25,7 +26,7 @@ func TestCreateJobWithApplicationType(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -45,7 +46,7 @@ func TestCreateJobWithApplicationMain(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MAIN_CLASS", Value: mainClass}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -64,7 +65,7 @@ func TestCreateJobWithApplicationMainArgs(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -100,7 +101,147 @@ func TestCreateJobWithWorkingDirectory(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) + jobExpected.Spec.Template.Spec.Containers[0].WorkingDir = dir + jobExpected.Spec.Template.Spec.InitContainers[1].WorkingDir = dir + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPointAndUseJdkOptsFalse(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPointWithExistingJdkOpts(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarJdkOptions, + Value: "-Dfoo=bar", + }, + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-entrypoint-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobWithApplicationEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + EntryPoint: []string{"foo", "bar"}, + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = []string{"foo", "bar"} + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPointWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + + // assert that the Job is as expected + assertJobCreation(t, deployment, jobExpected) +} + +func TestCreateJobUseImageEntryPointAndUseJdkOptsFalseWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestCoherenceJob(spec) + // Create expected Job + jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.Containers[0].Command = nil + jobExpected.Spec.Template.Spec.Containers[0].Args = nil + jobExpected.Spec.Template.Spec.Containers[0].Env = append(jobExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[0].Env = append(jobExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + jobExpected.Spec.Template.Spec.InitContainers[1].Env = append(jobExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_job_coherencespec_management_test.go b/api/v1/create_job_coherencespec_management_test.go index 093a539e1..25feb090f 100644 --- a/api/v1/create_job_coherencespec_management_test.go +++ b/api/v1/create_job_coherencespec_management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateJobWithCoherenceManagementEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -102,8 +102,8 @@ func TestCreateJobWithCoherenceManagementEnabledWithPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -138,22 +138,22 @@ func TestCreateJobWithCoherenceManagementWithSSLEnabledWithoutSecret(t *testing. deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -191,23 +191,23 @@ func TestCreateJobWithCoherenceManagementWithSSLEnabledWithSecret(t *testing.T) deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the management ConfigMap volume mount jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_job_coherencespec_metrics_test.go b/api/v1/create_job_coherencespec_metrics_test.go index bedd60b24..60eef157c 100644 --- a/api/v1/create_job_coherencespec_metrics_test.go +++ b/api/v1/create_job_coherencespec_metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateJobWithCoherenceMetricsEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -102,8 +102,8 @@ func TestCreateJobWithCoherenceMetricsEnabledWithPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -138,22 +138,22 @@ func TestCreateJobWithCoherenceMetricsWithSSLEnabledWithoutSecret(t *testing.T) deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -191,23 +191,23 @@ func TestCreateJobWithCoherenceMetricsWithSSLEnabledWithSecret(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the metrics ConfigMap volume mount jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_job_coherencespec_persistence_test.go b/api/v1/create_job_coherencespec_persistence_test.go index 265f7b3ac..1c7118e99 100644 --- a/api/v1/create_job_coherencespec_persistence_test.go +++ b/api/v1/create_job_coherencespec_persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,7 +44,7 @@ func TestCreateJobWithPersistenceModeOnDemand(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -64,7 +64,7 @@ func TestCreateJobWithPersistenceModeActive(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -83,7 +83,7 @@ func TestCreateJobWithPersistenceModeActiveAsync(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -199,8 +199,7 @@ func TestCreateJobWithPersistenceSnapshotVolume(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -208,6 +207,12 @@ func TestCreateJobWithPersistenceSnapshotVolume(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -251,8 +256,7 @@ func TestCreateJobWithPersistenceSnapshotPVC(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -260,6 +264,12 @@ func TestCreateJobWithPersistenceSnapshotPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -302,8 +312,7 @@ func TestCreateJobWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -311,6 +320,12 @@ func TestCreateJobWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -352,16 +367,19 @@ func TestCreateJobWithPersistenceAndSnapshotVolume(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -417,16 +435,19 @@ func TestCreateJobWithPersistenceAndSnapshotPVC(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Add the expected environment variables - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -445,6 +466,7 @@ func createResourcesForJob(spec coh.CoherenceResourceSpec) (*batchv1.Job, *coh.C // Add the expected environment variables addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToJob(jobExpected, coh.ContainerNameOperatorConfig, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) // add the expected volume mount to the Operator init-container jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -452,6 +474,12 @@ func createResourcesForJob(spec coh.CoherenceResourceSpec) (*batchv1.Job, *coh.C MountPath: coh.VolumeMountPathPersistence, }) + // add the expected volume mount to the Operator JVM args init-container + jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(jobExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNamePersistence, + MountPath: coh.VolumeMountPathPersistence, + }) + // add the expected volume mount to the coherence container jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(jobExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNamePersistence, diff --git a/api/v1/create_job_coherencespec_test.go b/api/v1/create_job_coherencespec_test.go index fb8ec0094..71d35f6df 100644 --- a/api/v1/create_job_coherencespec_test.go +++ b/api/v1/create_job_coherencespec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -40,6 +40,7 @@ func TestCreateJobWithImage(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) + jobExpected.Spec.Template.Spec.InitContainers[1].Image = "coherence:1.0" jobExpected.Spec.Template.Spec.Containers[0].Image = "coherence:1.0" // assert that the Job is as expected @@ -74,7 +75,7 @@ func TestCreateJobWithCoherenceSpecWithStorageEnabledTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -92,7 +93,7 @@ func TestCreateJobWithCoherenceLocalPort(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -110,7 +111,7 @@ func TestCreateJobWithCoherenceLocalPortAdjustTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -128,7 +129,7 @@ func TestCreateJobWithCoherenceLocalPortAdjustFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -146,7 +147,7 @@ func TestCreateJobWithCoherenceLocalPortAdjust(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -164,7 +165,7 @@ func TestCreateJobWithCoherenceSpecWithStorageEnabledFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -182,7 +183,7 @@ func TestCreateJobWithCoherenceSpecWithCacheConfig(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -200,7 +201,7 @@ func TestCreateJobWithCoherenceSpecWithOverrideConfig(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -218,7 +219,7 @@ func TestCreateJobWithCoherenceSpecWithLogLevel(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -275,7 +276,7 @@ func TestCreateJobWithCoherenceSpecWithTracingRatio(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -327,7 +328,8 @@ func TestCreateJobWithCoherenceSpecWithIpMonitorEnabled(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + removeEnvVarsFromAllJobContainers(jobExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -348,7 +350,7 @@ func TestCreateJobWithCoherenceSpecWithWkaSameNamespace(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected @@ -372,7 +374,7 @@ func TestCreateJobWithCoherenceSpecWithWkaDifferentNamespace(t *testing.T) { // Create expected Job jobExpected := createMinimalExpectedJob(deployment) expectedWka := deployment.GetWKA() - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected @@ -398,7 +400,7 @@ func TestCreateJobWithCoherenceSpecWithWkaAddress(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) expectedWka := "storage.foo.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected @@ -424,7 +426,7 @@ func TestCreateJobWithCoherenceSpecWithMultipleWkaAddresses(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) expectedWka := "storage.one.bar.local,storage.two.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) jobExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the Job is as expected diff --git a/api/v1/create_job_coherenceutils_test.go b/api/v1/create_job_coherenceutils_test.go index c71254fea..88e31a5c6 100644 --- a/api/v1/create_job_coherenceutils_test.go +++ b/api/v1/create_job_coherenceutils_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -15,7 +15,7 @@ import ( func TestCreateJobWithCoherenceUtilsEmpty(t *testing.T) { spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{}, + CoherenceUtils: &coh.CoherenceUtilsSpec{}, } // Create the test deployment @@ -27,29 +27,10 @@ func TestCreateJobWithCoherenceUtilsEmpty(t *testing.T) { assertJobCreation(t, deployment, jobExpected) } -func TestCreateJobWithCoherenceUtilsWithImage(t *testing.T) { - - spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("utils:1.0"), - }, - } - - // Create the test deployment - deployment := createTestCoherenceJob(spec) - // Create expected Job - jobExpected := createMinimalExpectedJob(deployment) - // Set the expected Operator image name - jobExpected.Spec.Template.Spec.InitContainers[0].Image = "utils:1.0" - - // assert that the Job is as expected - assertJobCreation(t, deployment, jobExpected) -} - func TestCreateJobWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { policy := corev1.PullAlways spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ + CoherenceUtils: &coh.CoherenceUtilsSpec{ ImagePullPolicy: &policy, }, } @@ -60,6 +41,7 @@ func TestCreateJobWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { jobExpected := createMinimalExpectedJob(deployment) // Set the expected Operator image pull policy jobExpected.Spec.Template.Spec.InitContainers[0].ImagePullPolicy = policy + jobExpected.Spec.Template.Spec.InitContainers[1].ImagePullPolicy = policy // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_job_jvmspec_test.go b/api/v1/create_job_jvmspec_test.go index d81af7122..474e821b1 100644 --- a/api/v1/create_job_jvmspec_test.go +++ b/api/v1/create_job_jvmspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -56,7 +56,7 @@ func TestCreateJobWithJvmSpecWithArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -91,7 +91,7 @@ func TestCreateJobWithJvmSpecWithClasspath(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -109,7 +109,7 @@ func TestCreateJobWithJvmSpecWithUseContainerLimitsTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -127,7 +127,7 @@ func TestCreateJobWithJvmSpecWithUseContainerLimitsFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -172,10 +172,10 @@ func TestCreateJobWithJvmSpecWithDebugEnabledTrueSuspendTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPortsForJob(jobExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -203,9 +203,9 @@ func TestCreateJobWithJvmSpecWithDebugEnabledTrueSuspendFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPortsForJob(jobExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -230,7 +230,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollector(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -251,7 +251,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollectorArgs(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -271,7 +271,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollectorLoggingFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -291,7 +291,7 @@ func TestCreateJobWithJvmSpecWithGarbageCollectorLoggingTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -341,11 +341,11 @@ func TestCreateJobWithJvmSpecWithMemorySettings(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -368,7 +368,7 @@ func TestCreateJobWithJvmSpecWithExitOnOomTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -391,7 +391,7 @@ func TestCreateJobWithJvmSpecWithExitOnOomFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -413,7 +413,7 @@ func TestCreateJobWithJvmSpecWithHeapDumpOnOomTrue(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) @@ -435,7 +435,7 @@ func TestCreateJobWithJvmSpecWithHeapDumpOnOomFalse(t *testing.T) { deployment := createTestCoherenceJob(spec) // Create expected Job jobExpected := createMinimalExpectedJob(deployment) - addEnvVarsToJob(jobExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) + addEnvVarsToAllJobContainers(jobExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) // assert that the Job is as expected assertJobCreation(t, deployment, jobExpected) diff --git a/api/v1/create_job_volumemounts_test.go b/api/v1/create_job_volumemounts_test.go index 9551ffeeb..26db8170e 100644 --- a/api/v1/create_job_volumemounts_test.go +++ b/api/v1/create_job_volumemounts_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,6 +44,8 @@ func TestCreateJobWithOneVolumeMount(t *testing.T) { // Create expected Job stsExpected := createMinimalExpectedJob(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne) // assert that the Job is as expected assertJobCreation(t, deployment, stsExpected) @@ -71,6 +73,8 @@ func TestCreateJobWithTwoVolumeMounts(t *testing.T) { // Create expected Job stsExpected := createMinimalExpectedJob(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne, mountTwo) // assert that the Job is as expected assertJobCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_add_containers_test.go b/api/v1/create_statefulset_add_containers_test.go index 5ee81f1dd..d3b903128 100644 --- a/api/v1/create_statefulset_add_containers_test.go +++ b/api/v1/create_statefulset_add_containers_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -245,6 +245,8 @@ func TestCreateStatefulSetWithExtraContainerAndVolume(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Volumes = append(stsExpected.Spec.Template.Spec.Volumes, vol) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mount) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mount) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mount) // Create expected container conExpected := corev1.Container{ diff --git a/api/v1/create_statefulset_applicationspec_test.go b/api/v1/create_statefulset_applicationspec_test.go index dd9bfe4db..30f02995d 100644 --- a/api/v1/create_statefulset_applicationspec_test.go +++ b/api/v1/create_statefulset_applicationspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package v1_test import ( coh "github.com/oracle/coherence-operator/api/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "testing" ) @@ -25,7 +26,7 @@ func TestCreateStatefulSetWithApplicationType(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppType, Value: "foo"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -45,7 +46,7 @@ func TestCreateStatefulSetWithApplicationMain(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MAIN_CLASS", Value: mainClass}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_OPERATOR_MAIN_CLASS", Value: mainClass}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -64,7 +65,7 @@ func TestCreateStatefulSetWithApplicationMainArgs(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarAppMainArgs, Value: "arg1 arg2"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -100,7 +101,147 @@ func TestCreateStatefulSetWithWorkingDirectory(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) + stsExpected.Spec.Template.Spec.Containers[0].WorkingDir = dir + stsExpected.Spec.Template.Spec.InitContainers[1].WorkingDir = dir + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohAppDir, Value: dir}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointAndUseJdkOptsFalse(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointWithExistingJdkOpts(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + }, + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarJdkOptions, + Value: "-Dfoo=bar", + }, + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar @/coherence-operator/utils/coherence-entrypoint-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "-Dfoo=bar"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetWithApplicationEntryPoint(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + EntryPoint: []string{"foo", "bar"}, + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = []string{"foo", "bar"} + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: coh.EnvVarJdkOptions, Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetUseImageEntryPointAndUseJdkOptsFalseWithAltJavaOptEnvVar(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + Application: &coh.ApplicationSpec{ + UseImageEntryPoint: ptr.To(true), + UseJdkJavaOptions: ptr.To(false), + AlternateJdkJavaOptions: ptr.To("ALT_OPTS"), + }, + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = nil + stsExpected.Spec.Template.Spec.Containers[0].Args = nil + stsExpected.Spec.Template.Spec.Containers[0].Env = append(stsExpected.Spec.Template.Spec.Containers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[0].Env = append(stsExpected.Spec.Template.Spec.InitContainers[0].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) + stsExpected.Spec.Template.Spec.InitContainers[1].Env = append(stsExpected.Spec.Template.Spec.InitContainers[1].Env, + corev1.EnvVar{Name: "ALT_OPTS", Value: "@/coherence-operator/utils/coherence-entrypoint-args.txt"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_coherencespec_management_test.go b/api/v1/create_statefulset_coherencespec_management_test.go index d2008e6e4..79bc170d6 100644 --- a/api/v1/create_statefulset_coherencespec_management_test.go +++ b/api/v1/create_statefulset_coherencespec_management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateStatefulSetWithCoherenceManagementEnabledTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -102,8 +102,8 @@ func TestCreateStatefulSetWithCoherenceManagementEnabledWithPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_MGMT_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -138,22 +138,22 @@ func TestCreateStatefulSetWithCoherenceManagementWithSSLEnabledWithoutSecret(t * deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAll(stsExpected, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -191,23 +191,23 @@ func TestCreateStatefulSetWithCoherenceManagementWithSSLEnabledWithSecret(t *tes deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_MGMT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, - corev1.EnvVar{Name: "COH_MGMT_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, - corev1.EnvVar{Name: "COH_MGMT_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_MGMT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAll(stsExpected, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_CERTS", Value: coh.VolumeMountPathManagementCerts}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_PORT", Value: strconv.FormatInt(int64(coh.DefaultManagementPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_MANAGEMENT_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the management ConfigMap volume mount stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_statefulset_coherencespec_metrics_test.go b/api/v1/create_statefulset_coherencespec_metrics_test.go index 29c1487c6..858c0838c 100644 --- a/api/v1/create_statefulset_coherencespec_metrics_test.go +++ b/api/v1/create_statefulset_coherencespec_metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,8 +80,8 @@ func TestCreateStatefulSetWithCoherenceMetricsEnabledTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -102,8 +102,8 @@ func TestCreateStatefulSetWithCoherenceMetricsEnabledWithPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "COH_METRICS_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -138,22 +138,22 @@ func TestCreateStatefulSetWithCoherenceMetricsWithSSLEnabledWithoutSecret(t *tes deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAll(stsExpected, + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -191,23 +191,23 @@ func TestCreateStatefulSetWithCoherenceMetricsWithSSLEnabledWithSecret(t *testin deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, - corev1.EnvVar{Name: "COH_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, - corev1.EnvVar{Name: "COH_METRICS_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, - corev1.EnvVar{Name: "COH_METRICS_SSL_ENABLED", Value: "true"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, - corev1.EnvVar{Name: "COH_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) + addEnvVarsToAll(stsExpected, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_CERTS", Value: coh.VolumeMountPathMetricsCerts}, + corev1.EnvVar{Name: "COHERENCE_METRICS_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_PORT", Value: strconv.FormatInt(int64(coh.DefaultMetricsPort), 10)}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_ENABLED", Value: "true"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE", Value: "ssl-keystore.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PASSWORD_FILE", Value: "ssl-key-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEY_PASSWORD_FILE", Value: "ssl-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_TYPE", Value: "ssl-key-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_ALGORITHM", Value: "ssl-key-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_KEYSTORE_PROVIDER", Value: "ssl-key-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE", Value: "ssl-trust.jks"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PASSWORD_FILE", Value: "ssl-trust-pass.txt"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_TYPE", Value: "ssl-trust-type"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_ALGORITHM", Value: "ssl-trust-algo"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_TRUSTSTORE_PROVIDER", Value: "ssl-trust-provider"}, + corev1.EnvVar{Name: "COHERENCE_METRICS_SSL_REQUIRE_CLIENT_CERT", Value: "true"}) // add the metrics ConfigMap volume mount stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ diff --git a/api/v1/create_statefulset_coherencespec_persistence_test.go b/api/v1/create_statefulset_coherencespec_persistence_test.go index 77c8b011e..e34a47ad9 100644 --- a/api/v1/create_statefulset_coherencespec_persistence_test.go +++ b/api/v1/create_statefulset_coherencespec_persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,7 +44,7 @@ func TestCreateStatefulSetWithPersistenceModeOnDemand(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "on-demand"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -64,7 +64,7 @@ func TestCreateStatefulSetWithPersistenceModeActive(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -83,7 +83,7 @@ func TestCreateStatefulSetWithPersistenceModeActiveAsync(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceMode, Value: "active-async"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -210,8 +210,7 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolume(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -219,6 +218,12 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolume(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -262,8 +267,7 @@ func TestCreateStatefulSetWithPersistenceSnapshotPVC(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -271,6 +275,12 @@ func TestCreateStatefulSetWithPersistenceSnapshotPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -324,8 +334,7 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -333,6 +342,12 @@ func TestCreateStatefulSetWithPersistenceSnapshotVolumeAndPVC(t *testing.T) { MountPath: coh.VolumeMountPathSnapshots, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNameSnapshots, + MountPath: coh.VolumeMountPathSnapshots, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNameSnapshots, @@ -374,16 +389,19 @@ func TestCreateStatefulSetWithPersistenceAndSnapshotVolume(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -439,16 +457,19 @@ func TestCreateStatefulSetWithPersistenceAndSnapshotPVC(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSnapshotDir, Value: coh.VolumeMountPathSnapshots}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, + corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, + corev1.VolumeMount{Name: coh.VolumeNameSnapshots, MountPath: coh.VolumeMountPathSnapshots}) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{Name: coh.VolumeNamePersistence, MountPath: coh.VolumeMountPathPersistence}, @@ -484,8 +505,7 @@ func createResources(spec coh.CoherenceResourceSpec) (*appsv1.StatefulSet, *coh. stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) - addEnvVars(stsExpected, coh.ContainerNameOperatorInit, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohPersistenceDir, Value: coh.VolumeMountPathPersistence}) // add the expected volume mount to the Operator init-container stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, corev1.VolumeMount{ @@ -493,6 +513,12 @@ func createResources(spec coh.CoherenceResourceSpec) (*appsv1.StatefulSet, *coh. MountPath: coh.VolumeMountPathPersistence, }) + // add the expected volume mount to the Operator init-container + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, corev1.VolumeMount{ + Name: coh.VolumeNamePersistence, + MountPath: coh.VolumeMountPathPersistence, + }) + // add the expected volume mount to the coherence container stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: coh.VolumeNamePersistence, diff --git a/api/v1/create_statefulset_coherencespec_test.go b/api/v1/create_statefulset_coherencespec_test.go index 4001ebb01..46009ddbe 100644 --- a/api/v1/create_statefulset_coherencespec_test.go +++ b/api/v1/create_statefulset_coherencespec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -40,6 +40,7 @@ func TestCreateStatefulSetWithImage(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.InitContainers[1].Image = "coherence:1.0" stsExpected.Spec.Template.Spec.Containers[0].Image = "coherence:1.0" // assert that the StatefulSet is as expected @@ -74,7 +75,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithStorageEnabledTrue(t *testing.T) deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -92,7 +93,7 @@ func TestCreateStatefulSetWithCoherenceLocalPort(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPort, Value: "1234"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -110,7 +111,7 @@ func TestCreateStatefulSetWithCoherenceLocalPortAdjustTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -128,7 +129,7 @@ func TestCreateStatefulSetWithCoherenceLocalPortAdjustFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -146,7 +147,7 @@ func TestCreateStatefulSetWithCoherenceLocalPortAdjust(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCoherenceLocalPortAdjust, Value: "9876"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -164,7 +165,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithStorageEnabledFalse(t *testing.T) deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohStorage, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -182,7 +183,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithCacheConfig(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohCacheConfig, Value: "test-config.xml"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -200,7 +201,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithOverrideConfig(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohOverride, Value: "test-override.xml"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -218,7 +219,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithLogLevel(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohLogLevel, Value: "9"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -275,7 +276,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithTracingRatio(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohTracingRatio, Value: "500u"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -327,7 +328,8 @@ func TestCreateStatefulSetWithCoherenceSpecWithIpMonitorEnabled(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarEnableIPMonitor, Value: "TRUE"}) + removeEnvVarsFromAll(stsExpected, coh.ContainerNameCoherence, coh.EnvVarIPMonitorPingTimeout) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -348,7 +350,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithWkaSameNamespace(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: deployment.GetWKA()}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -372,7 +374,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithWkaDifferentNamespace(t *testing. // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) expectedWka := deployment.GetWKA() - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -398,7 +400,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithWkaAddress(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) expectedWka := "storage.foo.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -424,7 +426,7 @@ func TestCreateStatefulSetWithCoherenceSpecWithMultipleWkaAddresses(t *testing.T stsExpected := createMinimalExpectedStatefulSet(deployment) expectedWka := "storage.one.bar.local,storage.two.bar.local" g.Expect(deployment.GetWKA()).To(Equal(expectedWka)) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohWka, Value: expectedWka}) stsExpected.Spec.Template.Labels[coh.LabelCoherenceWKAMember] = "false" // assert that the StatefulSet is as expected @@ -441,7 +443,7 @@ func TestCreateStatefulSetWithResumeServicesOnStartupTrue(t *testing.T) { deployment := createTestCoherenceDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -457,7 +459,7 @@ func TestCreateStatefulSetWithResumeServicesOnStartupFalse(t *testing.T) { deployment := createTestCoherenceDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarOperatorAllowResume, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_coherenceutils_test.go b/api/v1/create_statefulset_coherenceutils_test.go index 01390e26b..9f942a6f5 100644 --- a/api/v1/create_statefulset_coherenceutils_test.go +++ b/api/v1/create_statefulset_coherenceutils_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -15,7 +15,7 @@ import ( func TestCreateStatefulSetWithCoherenceUtilsEmpty(t *testing.T) { spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{}, + CoherenceUtils: &coh.CoherenceUtilsSpec{}, } // Create the test deployment @@ -27,29 +27,10 @@ func TestCreateStatefulSetWithCoherenceUtilsEmpty(t *testing.T) { assertStatefulSetCreation(t, deployment, stsExpected) } -func TestCreateStatefulSetWithCoherenceUtilsWithImage(t *testing.T) { - - spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ - Image: stringPtr("utils:1.0"), - }, - } - - // Create the test deployment - deployment := createTestDeployment(spec) - // Create expected StatefulSet - stsExpected := createMinimalExpectedStatefulSet(deployment) - // Set the expected Operator image name - stsExpected.Spec.Template.Spec.InitContainers[0].Image = "utils:1.0" - - // assert that the StatefulSet is as expected - assertStatefulSetCreation(t, deployment, stsExpected) -} - func TestCreateStatefulSetWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { policy := corev1.PullAlways spec := coh.CoherenceResourceSpec{ - CoherenceUtils: &coh.ImageSpec{ + CoherenceUtils: &coh.CoherenceUtilsSpec{ ImagePullPolicy: &policy, }, } @@ -60,6 +41,7 @@ func TestCreateStatefulSetWithCoherenceUtilsWithImagePullPolicy(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Set the expected Operator image pull policy stsExpected.Spec.Template.Spec.InitContainers[0].ImagePullPolicy = policy + stsExpected.Spec.Template.Spec.InitContainers[1].ImagePullPolicy = policy // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_jvmspec_test.go b/api/v1/create_statefulset_jvmspec_test.go index 3fa19cd96..05628c1c0 100644 --- a/api/v1/create_statefulset_jvmspec_test.go +++ b/api/v1/create_statefulset_jvmspec_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -56,7 +56,7 @@ func TestCreateStatefulSetWithJvmSpecWithArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmArgs, Value: "argOne argTwo"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -91,7 +91,7 @@ func TestCreateStatefulSetWithJvmSpecWithClasspath(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmExtraClasspath, Value: "/foo:/bar"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -109,7 +109,7 @@ func TestCreateStatefulSetWithJvmSpecWithUseContainerLimitsTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -127,7 +127,7 @@ func TestCreateStatefulSetWithJvmSpecWithUseContainerLimitsFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarJvmUseContainerLimits, Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -172,10 +172,10 @@ func TestCreateStatefulSetWithJvmSpecWithDebugEnabledTrueSuspendTrue(t *testing. deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_SUSPEND", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPorts(stsExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -203,9 +203,9 @@ func TestCreateStatefulSetWithJvmSpecWithDebugEnabledTrueSuspendFalse(t *testing deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ENABLED", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_ATTACH", Value: "10.10.10.10:5001"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DEBUG_PORT", Value: "1234"}) // add the expected debug port addPorts(stsExpected, coh.ContainerNameCoherence, corev1.ContainerPort{ Name: coh.PortNameDebug, @@ -230,7 +230,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollector(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -251,7 +251,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollectorArgs(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_ARGS", Value: "-XX:GC-ArgOne -XX:GC-ArgTwo"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -271,7 +271,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollectorLoggingFalse(t *testing deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -291,7 +291,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollectorLoggingTrue(t *testing. deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_LOGGING", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -341,11 +341,11 @@ func TestCreateStatefulSetWithJvmSpecWithMemorySettings(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_HEAP_SIZE", Value: "5g"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_STACK_SIZE", Value: "500m"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_METASPACE_SIZE", Value: "1g"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_DIRECT_MEMORY_SIZE", Value: "4g"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_NATIVE_MEMORY_TRACKING", Value: "detail"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -368,7 +368,7 @@ func TestCreateStatefulSetWithJvmSpecWithExitOnOomTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -391,7 +391,7 @@ func TestCreateStatefulSetWithJvmSpecWithExitOnOomFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_EXIT", Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -413,7 +413,7 @@ func TestCreateStatefulSetWithJvmSpecWithHeapDumpOnOomTrue(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "true"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -435,7 +435,7 @@ func TestCreateStatefulSetWithJvmSpecWithHeapDumpOnOomFalse(t *testing.T) { deployment := createTestDeployment(spec) // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_OOM_HEAP_DUMP", Value: "false"}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/create_statefulset_test.go b/api/v1/create_statefulset_test.go index d5740618c..d0298955e 100644 --- a/api/v1/create_statefulset_test.go +++ b/api/v1/create_statefulset_test.go @@ -71,7 +71,7 @@ func TestCreateStatefulSetWithRackLabel(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) url := fmt.Sprintf("%s?nodeLabel=%s", coh.OperatorRackURL, "coherence.oracle.com/test") - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohRack, Value: url}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohRack, Value: url}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -87,7 +87,7 @@ func TestCreateStatefulSetWithSiteLabel(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) url := fmt.Sprintf("%s?nodeLabel=%s", coh.OperatorSiteURL, "coherence.oracle.com/test") - addEnvVars(stsExpected, coh.ContainerNameCoherence, corev1.EnvVar{Name: coh.EnvVarCohSite, Value: url}) + addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: coh.EnvVarCohSite, Value: url}) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -107,7 +107,7 @@ func TestCreateStatefulSetWithEnvVars(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) // add the expected environment variables - addEnvVars(stsExpected, coh.ContainerNameCoherence, ev...) + addEnvVarsToAll(stsExpected, ev...) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -300,6 +300,7 @@ func TestCreateStatefulSetWithInitContainerResources(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.InitContainers[0].Resources = res + stsExpected.Spec.Template.Spec.InitContainers[1].Resources = res // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -441,6 +442,7 @@ func TestCreateStatefulSetWithContainerSecurityContext(t *testing.T) { stsExpected := createMinimalExpectedStatefulSet(deployment) // Add the expected security context to both the init-container and the Coherence container stsExpected.Spec.Template.Spec.InitContainers[0].SecurityContext = &ctx + stsExpected.Spec.Template.Spec.InitContainers[1].SecurityContext = &ctx stsExpected.Spec.Template.Spec.Containers[0].SecurityContext = &ctx // assert that the StatefulSet is as expected @@ -778,3 +780,20 @@ func TestAddLifecycleToStatefulSetCoherenceContainer(t *testing.T) { // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) } + +func TestCreateStatefulUsingJava8(t *testing.T) { + // Create minimal spec spec + spec := coh.CoherenceResourceSpec{ + JVM: &coh.JVMSpec{ + Java8: ptr.To(true), + }, + } + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.Containers[0].Command = []string{coh.RunnerCommand, "server"} + stsExpected.Spec.Template.Spec.Containers[0].Args = []string{} + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} diff --git a/api/v1/create_statefulset_volumemounts_test.go b/api/v1/create_statefulset_volumemounts_test.go index 32eea4e19..97e8fec8e 100644 --- a/api/v1/create_statefulset_volumemounts_test.go +++ b/api/v1/create_statefulset_volumemounts_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -44,6 +44,8 @@ func TestCreateStatefulSetWithOneVolumeMount(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) @@ -71,6 +73,8 @@ func TestCreateStatefulSetWithTwoVolumeMounts(t *testing.T) { // Create expected StatefulSet stsExpected := createMinimalExpectedStatefulSet(deployment) stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.Containers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[0].VolumeMounts, mountOne, mountTwo) + stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts = append(stsExpected.Spec.Template.Spec.InitContainers[1].VolumeMounts, mountOne, mountTwo) // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) diff --git a/api/v1/hasher_test.go b/api/v1/hasher_test.go index 22e39b847..d6498213e 100644 --- a/api/v1/hasher_test.go +++ b/api/v1/hasher_test.go @@ -31,6 +31,5 @@ func TestHash(t *testing.T) { // If this test fails you have probably added a new field to CoherenceResourceSpec // This will break backwards compatibility. This field needs to be added to // both CoherenceStatefulSetResourceSpec and CoherenceJobResourceSpec instead - //g.Expect(deployment.GetLabels()["coherence-hash"]).To(Equal("5cb9fd9f96")) g.Expect(deployment.GetLabels()["coherence-hash"]).To(Equal("5859f96865")) } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 177df9ee9..f136f37f7 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,7 +1,7 @@ //go:build !ignore_autogenerated /* - * Copyright (c) 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -86,6 +86,11 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { *out = new(string) **out = **in } + if in.EntryPoint != nil { + in, out := &in.EntryPoint, &out.EntryPoint + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Args != nil { in, out := &in.Args, &out.Args *out = make([]string, len(*in)) @@ -106,6 +111,21 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { *out = new(string) **out = **in } + if in.UseImageEntryPoint != nil { + in, out := &in.UseImageEntryPoint, &out.UseImageEntryPoint + *out = new(bool) + **out = **in + } + if in.UseJdkJavaOptions != nil { + in, out := &in.UseJdkJavaOptions, &out.UseJdkJavaOptions + *out = new(bool) + **out = **in + } + if in.AlternateJdkJavaOptions != nil { + in, out := &in.AlternateJdkJavaOptions, &out.AlternateJdkJavaOptions + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSpec. @@ -622,7 +642,7 @@ func (in *CoherenceResourceSpec) DeepCopyInto(out *CoherenceResourceSpec) { } if in.CoherenceUtils != nil { in, out := &in.CoherenceUtils, &out.CoherenceUtils - *out = new(ImageSpec) + *out = new(CoherenceUtilsSpec) (*in).DeepCopyInto(*out) } if in.AutomountServiceAccountToken != nil { @@ -959,6 +979,26 @@ func (in *CoherenceTracingSpec) DeepCopy() *CoherenceTracingSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CoherenceUtilsSpec) DeepCopyInto(out *CoherenceUtilsSpec) { + *out = *in + if in.ImagePullPolicy != nil { + in, out := &in.ImagePullPolicy, &out.ImagePullPolicy + *out = new(corev1.PullPolicy) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoherenceUtilsSpec. +func (in *CoherenceUtilsSpec) DeepCopy() *CoherenceUtilsSpec { + if in == nil { + return nil + } + out := new(CoherenceUtilsSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CoherenceWKASpec) DeepCopyInto(out *CoherenceWKASpec) { *out = *in @@ -1178,6 +1218,11 @@ func (in *JVMSpec) DeepCopyInto(out *JVMSpec) { *out = new(bool) **out = **in } + if in.Java8 != nil { + in, out := &in.Java8, &out.Java8 + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JVMSpec. diff --git a/controllers/coherencejob_controller.go b/controllers/coherencejob_controller.go index b84f4d503..38e836854 100644 --- a/controllers/coherencejob_controller.go +++ b/controllers/coherencejob_controller.go @@ -132,7 +132,6 @@ func (in *CoherenceJobReconciler) ReconcileDeployment(ctx context.Context, reque // Check whether the deployment has a replica count specified // Ideally we'd do this with a validating/defaulting web-hook but maybe in a later version. - //spec = deployment.GetSpec() if spec.Replicas == nil { // No replica count, so we patch the deployment to have the default replicas value. // The reason we do this, is because the kubectl scale command will fail if the replicas diff --git a/controllers/job/job_controller.go b/controllers/job/job_controller.go index 69c50018c..7ffbec07f 100644 --- a/controllers/job/job_controller.go +++ b/controllers/job/job_controller.go @@ -293,14 +293,6 @@ func (in *ReconcileJob) patchJob(ctx context.Context, deployment coh.CoherenceRe in.SetCoherenceImage(¤tPodSpec, cohImage) } - // ensure the Operator image is present so that we do not patch on a Coherence resource - // from pre-3.1.x that does not have images set - if spec.CoherenceUtils == nil || spec.CoherenceUtils.Image == nil { - operatorImage := in.GetOperatorImage(&desiredPodSpec) - in.SetOperatorImage(&originalPodSpec, operatorImage) - in.SetOperatorImage(¤tPodSpec, operatorImage) - } - // a callback function that the 3-way patch method will call just before it applies a patch // if there is any patch to apply, this will check StatusHA if required and update the deployment status callback := func() { diff --git a/controllers/reconciler/base_controller.go b/controllers/reconciler/base_controller.go index 0664f2d80..6c5eb30e6 100644 --- a/controllers/reconciler/base_controller.go +++ b/controllers/reconciler/base_controller.go @@ -649,14 +649,6 @@ func (in *CommonReconciler) BlankCoherenceContainerFields(template *corev1.PodTe // This is the Coherence Container // blank out the container command field c.Command = []string{} - // blank the WKA env var - for e := range c.Env { - ev := c.Env[e] - if ev.Name == coh.EnvVarCohWka { - ev.Value = "" - c.Env[e] = ev - } - } // set the updated container back into the StatefulSet template.Spec.Containers[i] = c } diff --git a/controllers/statefulset/statefulset_controller.go b/controllers/statefulset/statefulset_controller.go index edfdb3ae0..5f9cfabb0 100644 --- a/controllers/statefulset/statefulset_controller.go +++ b/controllers/statefulset/statefulset_controller.go @@ -433,6 +433,15 @@ func (in *ReconcileStatefulSet) patchStatefulSet(ctx context.Context, deployment current.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{} original.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{} + // K8s does not allow the entry point (command) and arguments cannot be patched + // So we ignore these even if they have been changed + desired.Spec.Template.Spec.Containers[0].Command = []string{} + current.Spec.Template.Spec.Containers[0].Command = []string{} + original.Spec.Template.Spec.Containers[0].Command = []string{} + desired.Spec.Template.Spec.Containers[0].Args = []string{} + current.Spec.Template.Spec.Containers[0].Args = []string{} + original.Spec.Template.Spec.Containers[0].Args = []string{} + desiredPodSpec := desired.Spec.Template currentPodSpec := current.Spec.Template originalPodSpec := original.Spec.Template @@ -458,14 +467,6 @@ func (in *ReconcileStatefulSet) patchStatefulSet(ctx context.Context, deployment in.SetCoherenceImage(¤tPodSpec, cohImage) } - // ensure the Operator image is present so that we do not patch on a Coherence resource - // from pre-3.1.x that does not have images set - if deploymentSpec.CoherenceUtils == nil || deploymentSpec.CoherenceUtils.Image == nil { - operatorImage := in.GetOperatorImage(&desiredPodSpec) - in.SetOperatorImage(&originalPodSpec, operatorImage) - in.SetOperatorImage(¤tPodSpec, operatorImage) - } - // a callback function that the 3-way patch method will call just before it applies a patch // if there is any patch to apply, this will check StatusHA if required and update the deployment status callback := func() { diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index 4743f9e28..aef2deb52 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -68,6 +68,7 @@ m| status |   m| <> | fals * <> * <> * <> +* <> * <> * <> * <> @@ -136,10 +137,14 @@ ApplicationSpec is the specification of the application deployed into the Cohere | Field | Description | Type | Required m| type | The application type to execute. This field would be set if using the Coherence Graal image and running a none-Java application. For example if the application was a Node application this field would be set to "node". The default is to run a plain Java application. m| *string | false m| main | Class is the Coherence container main class. The default value is com.tangosol.net.DefaultCacheServer. If the application type is non-Java this would be the name of the corresponding language specific runnable, for example if the application type is "node" the main may be a Javascript file. m| *string | false -m| args | Args is the optional arguments to pass to the main class. m| []string | false -m| workingDir | The application folder in the custom artifacts Docker image containing application artifacts. This will effectively become the working directory of the Coherence container. If not set the application directory default value is "/app". m| *string | false +m| entryPoint | Entrypoint array that will override the "java" entry point configured by the Operator or and any container entry point. This is an advanced use case, specifying an incorrect value here can cause the container not to start. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. m| []string | false +m| args | Args is the optional arguments to pass to the main class or the container entry point. m| []string | false +m| workingDir | WorkingDir sets the working directory of the Coherence container. m| *string | false m| cloudNativeBuildPack | Optional settings that may be configured if using a Cloud Native Buildpack Image. For example an image build with the Spring Boot Maven/Gradle plugin. See: https://github.com/paketo-buildpacks/spring-boot and https://buildpacks.io/ m| *<> | false m| springBootFatJar | SpringBootFatJar is the full path name to the Spring Boot fat jar if the application image has been built by just adding a Spring Boot fat jar to the image. If this field is set then the application will be run by executing this jar. For example, if this field is "/app/libs/foo.jar" the command line will be "java -jar app/libs/foo.jar" m| *string | false +m| useImageEntryPoint | UseImageEntryPoint is a flag to indicate that the Coherence container in the Pods should just execute the image entry point and not configure a custom command line. If this flag is set to true any arguments in the Args field are passed as container arguments to the entry point. m| *bool | false +m| useJdkJavaOptions | UseJdkJavaOptions is a flag to indicate that the `JDK_JAVA_OPTIONS` environment variable should be set in the Coherence container to contain the JVM arguments configured by the Operator. Setting `JDK_JAVA_OPTIONS` defaults to true and only applies if UseImageEntryPoint is set to true. m| *bool | false +m| alternateJdkJavaOptions | AlternateJdkJavaOptions specifies an alternative environment variable name to use instead of `JDK_JAVA_OPTIONS` for the command line options. If an application does not want to use the `JDK_JAVA_OPTIONS` environment variable but still wants access to the options the operator would have configured, this field can be set to an environment variable that an application can then access in the container at runtime. The value of the environment variable specified here will be set even if `UseJdkJavaOptions` is set to false. Setting the alternate JVM options environment variable only applies if UseImageEntryPoint is set to true. m| *string | false |=== <> @@ -332,7 +337,7 @@ m| containerSecurityContext | ContainerSecurityContext is the SecurityContext th m| shareProcessNamespace | Share a single process namespace between all the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. m| *bool | false m| hostIPC | Use the host's ipc namespace. Optional: Default to false. m| *bool | false m| network | Configure various networks and DNS settings for Pods in this role. m| *<> | false -m| coherenceUtils | The configuration for the Coherence operator image name m| *<> | false +m| coherenceUtils | The configuration for the Coherence operator image name m| *<> | false m| serviceAccountName | The name to use for the service account to use when RBAC is enabled The role bindings must already have been created as this chart does not create them it just sets the serviceAccountName value in the Pod spec. m| string | false m| automountServiceAccountToken | Whether to auto-mount the Kubernetes API credentials for a service account m| *bool | false m| operatorRequestTimeout | The timeout to apply to REST requests made back to the Operator from Coherence Pods. These requests are typically to obtain site and rack information for the Pod. m| *int32 | false @@ -474,6 +479,18 @@ NOTE: This field is a k8s resource.Quantity value as CRDs do not support decimal <
> +=== CoherenceUtilsSpec + +CoherenceUtilsSpec defines the settings for the Coherence Operator utilities image + +[cols="1,10,1,1"options="header"] +|=== +| Field | Description | Type | Required +m| imagePullPolicy | Image pull policy. One of Always, Never, IfNotPresent. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images m| *https://pkg.go.dev/k8s.io/api/core/v1#PullPolicy | false +|=== + +<
> + === CoherenceWKASpec CoherenceWKASpec configures Coherence well-known-addressing to use an existing Coherence deployment for WKA. @@ -554,6 +571,7 @@ m| gc | Set JVM garbage collector options. m| *<> | false m| useJibClasspath | A flag indicating whether to automatically add the default classpath for images created by the JIB tool https://github.com/GoogleContainerTools/jib If true then the /app/lib/* /app/classes and /app/resources entries are added to the JVM classpath. The default value fif not specified is true. m| *bool | false +m| java8 | Java8 is a flag to indicate that a Coherence container is running on Java 8 and must use the legacy Operator container entry point. This would only apply to applications using older Coherence 12.2.1-4-* or 14.1.1-0-* versions. The default value for this field is false, if this field is not set to true when Java 8 is used the container will fail to start. m| *bool | false |=== <
> diff --git a/docs/applications/020_build_application.adoc b/docs/applications/020_build_application.adoc index 8bbdd7844..faa20281b 100644 --- a/docs/applications/020_build_application.adoc +++ b/docs/applications/020_build_application.adoc @@ -46,30 +46,15 @@ Java executable location, in this example to `/usr/lib/jvm/java-11-openjdk/bin/j === Image `EntryPoint` - What Does the Operator Run? The image does not need to have an `EntryPoint` or command specified, it does not need to actually be executable. -If the image does have an `EntryPoint`, it will just be ignored. +The default behaviour of the Coherence operator it to configure its own entry point to execute the Coherence container, if the image does have an `EntryPoint`, it will just be ignored. -The Coherence Operator actually injects its own `runner` executable into the container which the container runs and which -in turn builds the Java command line to execute. The `runner` process looks at arguments and environment variables configured -for the Coherence container and from these constructs a Java command line that it then executes. - -The default command might look something like this: -[source,bash] ----- -java --class-path `/app/resources:/app/classes:/app/libs/*` \ - \ - \ - com.tangosol.net.Coherence ----- -The `runner` will work out the JVM's classpath, args and system properties to add to the command line -and execute the main class `com.tangosol.net.Coherence`. -All these are configurable in the `Coherence` resource spec. === Optional `CLASSPATH` Environment Variable If the `CLASSPATH` environment variable has been set in an image that classpath will be used when running the Coherence container. Other elements may also be added to the classpath depending on the configuration of the `Coherence` resource. -=== Setting the Classpath +==== Setting the Classpath An application image contains `.jar` files (at least `coherence.jar`), possibly Java class files, also possibly other ad-hoc files, all of which need to be on the application's classpath. @@ -127,20 +112,6 @@ The `JAVA_HOME` environment variable does not have to be set in the image. If it be used to run the application. If it is not set then the `java` executable *must* be on the `PATH` in the image. -=== Optional `COHERENCE_HOME` Environment Variable - -The `COHERENCE_HOME` environment variable does not have to be set in an image. -Typically, all the jar files, including `coherence.jar` would be packaged into a single directory which is then used as -the classpath. -It is possible to run official Coherence images published by Oracle, which have `COHERENCE_HOME` set, which is then used -by the Operator to set the classpath. - -If the `COHERENCE_HOME` environment variable is set in an image the following entries will be added to the end of the -classpath: - -* `$COHERENCE_HOME/lib/coherence.jar` -* `$COHERENCE_HOME/conf` - === Additional Data Volumes If the application requires access to external storage volumes in Kubernetes it is possible to add additional `Volumes` diff --git a/docs/applications/070_spring.adoc b/docs/applications/070_spring.adoc index 9719882dd..206b0306f 100644 --- a/docs/applications/070_spring.adoc +++ b/docs/applications/070_spring.adoc @@ -174,37 +174,22 @@ class as opposed to the `org.springframework.boot.loader.JarLauncher` that `java === Using Could Native Buildpacks If the Spring Boot Maven or Gradle plugin has been used to produce an image using -https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1[Cloud Native Buildpacks] +https://docs.spring.io/spring-boot/reference/packaging/container-images/cloud-native-buildpacks.html[Cloud Native Buildpacks] these images can work with the Coherence Operator. -[WARNING] +Images using Cloud Native Buildpacks contain a special launcher executable the runs the Java application. This makes it more complex than normal for the Operator to provide a custom Java command. +For images built using Cloud Native Buildpacks to work the `Coherence` resource must be configured to execute the images entry point instead of the Operator injecting a command line. + +[IMPORTANT] ==== -Due to limitation on the way that arguments can be passed to the JVM when using Buildpacks images the Coherence -operator will only work with images containing a JVM greater than Java 11. -Although the Buildpacks launcher will honour the `JAVA_OPTS` or `JAVA_TOOL_OPTIONS` environment variables there appear -to be size limitations for the values of these variables that make it impractical for the Operator to use them. -The Operator therefore creates a JVM arguments file to pass the arguments to the JVM. -At the time of writing these docs, Java 8 (which is the default version of Java used by the Spring Boot plugin) does not -support the use of argument files for the JVM. - -It is simple to configure the version of the JVM used by the Spring Boot plugin, for example in Maven: -[source,xml] ----- - - org.springframework.boot - spring-boot-maven-plugin - 2.3.4.RELEASE - - - - 11.* - - - - ----- +Due to the way that the Coherence Operator configures JVM arguments +when configured to use an image entry point, the image must be running +Java 11 or higher. ==== +Instead of building a custom command line, the Operator uses the `JDK_JAVA_OPTIONS` environment variable to pass and +configured JVM options and system properties to the Spring application. +This is a standard environment variable that the JVM will effectively use to pre-pend JVM arguments to its command line. When creating a `Coherence` deployment for a Spring Boot Buildpacks image The application type must be set to `spring`. The Operator's launcher will automatically detect that the image is a Buildpacks image and launch the application using @@ -220,80 +205,18 @@ spec: image: catalogue:1.0.0 application: type: spring # <1> + useImageEntryPoint: true # <2> ---- <1> The application type has been set to `spring` (for Spring Boot 2.x) or `spring3` (for Spring Boot 3.x) so that the operator knows that this is a Spring Boot application, and the fact that the image is a Buildpacks image will be auto-discovered. +<2> The Operator will run the image's entry point and set the `JDK_JAVA_OPTIONS` environment variable +to pass arguments to the JVM -When the Operator starts the application it will then run the buildpacks launcher with a command equivalent -to this: - -*Spring Boot 2.x* -[source,bash] ----- -/cnb/lifecycle/launcher java @jvm-args-file org.springframework.boot.loader.PropertiesLauncher ----- - -*Spring Boot 3.x* -[source,bash] ----- -/cnb/lifecycle/launcher java @jvm-args-file org.springframework.boot.loader.launch.PropertiesLauncher ----- - -==== Buildpacks Detection - -If for some reason buildpacks auto-detection does not work properly the `Coherence` -CRD contains a filed to force buildpacks to be enabled or disabled. - -The `boolean` field `spec.application.cloudNativeBuildPack.enabled` can be set to `true` to enable buildpacks or false -to disable buildpack. - -[source,yaml] ----- -apiVersion: coherence.oracle.com/v1 -kind: Coherence -metadata: - name: test -spec: - image: catalogue:1.0.0 - application: - type: spring # <1> - cloudNativeBuildPack: - enabled: true # <2> ----- - -<1> The application type has been set to `spring` so that the operator knows that this is a Spring Boot application -<2> The `cloudNativeBuildPack.enabled` field has been set to `true` to force the Operator to use the Buildpacks launcher. - -==== Specify the Buildpacks Launcher - -A Cloud Native Buildpacks image uses a launcher mechanism to run the executable(s) in the image. The Coherence Operator -launcher will configure the application and then invoke the same buildpacks launcher. -The Coherence Operator assumes that the buildpacks launcher is in the image in the location `/cnb/lifecycle/launcher`. -If a buildpacks image has been built with the launcher in a different location then the `Coherence` CRD contains -a field to set the new location. - -The `spec.application.cloudNativeBuildPack.enabled` field. - -[source,yaml] ----- -apiVersion: coherence.oracle.com/v1 -kind: Coherence -metadata: - name: test -spec: - image: catalogue:1.0.0 - application: - type: spring # <1> - cloudNativeBuildPack: - launcher: /buildpack/launcher # <2> ----- - -<1> The application type has been set to `spring` so that the operator knows that this is a Spring Boot application -<2> The buildpacks launcher that the Operator will invoke is located at `/buildpack/launcher`. - +For more information on using image entry points with the Coherence operator see the +<> documentation. -==== Buildpack JVM Arguments +==== Buildpacks JVM Arguments A typical Spring Boot buildpack launcher will attempt to configure options such as heap size based on the container resource limits configured, so this must be taken into account if using any of the memory options available in the diff --git a/docs/applications/080_entrypoint.adoc b/docs/applications/080_entrypoint.adoc new file mode 100644 index 000000000..9dc14ea2d --- /dev/null +++ b/docs/applications/080_entrypoint.adoc @@ -0,0 +1,174 @@ +/////////////////////////////////////////////////////////////////////////////// + + Copyright (c) 2025, Oracle and/or its affiliates. + Licensed under the Universal Permissive License v 1.0 as shown at + http://oss.oracle.com/licenses/upl. + +/////////////////////////////////////////////////////////////////////////////// + += Run an Image Entry Point + +== Run an Image Entry Point + +The default behaviour of the Coherence operator is to configure the entry point and arguments to +use to run the Coherence container. This command line is created from the various configuration +elements in the `Coherence` resource yaml. Any entry point and arguments actually configured in +the image being used will be ignored. +The behaviour can be changed so that the images own entry point is used for the container. +This could be useful for example when an image contains a shell script that performs initialisation +before running the Java Coherence application. + +[NOTE] +==== +Using an image entry point is only supported in images that use Java 11 or higher. +==== + +To use an image's entry point set the `spec.application.useImageEntryPoint` field in the `Coherence` +resource to `true`. + +For example: + +[source] +.storage.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: storage +spec: + replicas: 3 + image: container-registry.oracle.com/middleware/coherence-ce:14.1.2-0-1 + application: + useImageEntryPoint: true +---- + +=== How are the JVM and Coherence Configured + +When the operator builds the container command line it can pass all the required JVM options +and system properties to configure the application on the command line. +But, when the image entry point it being used the operator needs to pass configuration another way. + +All the Coherence configuration system properties can also be passed as environment variables, so +the operator configures the container to have all the required environment variables to configure +Coherence. For example, the `coherence.role` system property is used to configure the role name +of a Coherence process, but Coherence will also use the `COHERENCE_ROLE` environment variable for this. +If `spec.role` value is set in the `Coherence` resource, this is be used to set `COHERENCE_ROLE` +environment variable in the Coherence container configuration in the Pod. + +The operator then uses a combination of Java arguments files and the `JDK_JAVA_OPTIONS` environment +variable to configure the JVM. This means that most of the features of the `Coherence` CRD can be +used, even when running an image entry point. + + +==== Java Argument Files + +Various other environment variables are set by the Coherence operator to configure the container. +When the Pod starts an init-container that the operator has configured uses these environment +variables to produce a number of Java command line argument files. +These files contain all the JVM command line options that the operator would have used in its +custom command line if it was running the container. +For more information on argument files see the +https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#java-command-line-argument-files[ +Java Arguments Files] documentation. + +The operator creates multiple arguments files for different purposes. +The Java argument files are always created by the init-container as these are used in the command line +that the operator normally configures for container. +There will be a file for the class path, a file for JVM options, a file for Spring Boot options +if the application is Spring Boot, etc. + +=== The `JDK_JAVA_OPTIONS` Environment Variable + +The `JDK_JAVA_OPTIONS` is a special environment variable recognised by the JVM. +Any values in the `JDK_JAVA_OPTIONS` environment variable are effectively prepended to the JVM +command line. +It is described fully in the +https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html#using-the-jdk_java_options-launcher-environment-variable +[Java Command] documentation. + +There are limitations on the size of the value for an environment variable, so the operator could +not specify all the options it needs in the `JDK_JAVA_OPTIONS` environment variable. +This is why the operator uses argument files instead, so all it needs to set into the `JDK_JAVA_OPTIONS` environment +variable are the names of the argument files to load. + +==== What If The Application Already Sets `JDK_JAVA_OPTIONS` + +If the `JDK_JAVA_OPTIONS` environment variable is set in the `Coherence` resource then the operator +will append its additional configuration onto the existing value. + +==== Disabling Use of `JDK_JAVA_OPTIONS` + +There may be occasions that the operator should not configure the `JDK_JAVA_OPTIONS` environment variable. +For example, an image may run a shell script that runs various other Java commands before starting the +main Coherence application. If the `JDK_JAVA_OPTIONS` environment variable was set it would be applied +to all these Java processes too. + +Setting the `spec.application.useJdkJavaOptions` field to `false` in the Coherence resource will +disable the use of the `JDK_JAVA_OPTIONS` environment variable and the operator will not set it. + +For example, + +[source] +.storage.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: storage +spec: + replicas: 3 + image: container-registry.oracle.com/middleware/coherence-ce:14.1.2-0-1 + application: + useImageEntryPoint: true + useJdkJavaOptions: false +---- + +[NOTE] +==== +When the `spec.application.useJdkJavaOptions` field is set to false the operator has no way to pass +a number of configuration options to the JVM. Coherence configurations that are passed as environment +variables will still work. Anything passed as JVM options, such as memory configurations, system +properties, etc cannot be configured. + +As long as the application that the image runs is a Coherence application correctly configured +to run in Kubernetes with the options required by the operator then it should still work. +==== + +==== Using An Alternative To `JDK_JAVA_OPTIONS` + +In use cases where the `JDK_JAVA_OPTIONS` environment variable cannot be used and is disabled as +described above, an alternative environment variable name can be specified that the operator will +configure instead. This allows an application to use this alternative environment variable at runtime +to obtain all the configurations that the Operator would have applied to the JVM. + +The name of the alternative environment variable is set in the `spec.application.alternateJdkJavaOptions` +field of the `Coherence` resource. + +For example, using the the yaml below will cause the operator to set the Java options values +into the `ALT_JAVA_OPTS` environment variable. + +[source] +.storage.yaml +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: storage +spec: + replicas: 3 + image: container-registry.oracle.com/middleware/coherence-ce:14.1.2-0-1 + application: + useImageEntryPoint: true + useJdkJavaOptions: false + alternateJdkJavaOptions: "ALT_JAVA_OPTS" +---- + +In the Coherence container the application code can then access the The `ALT_JAVA_OPTS` environment variable +to obtain the JVM options the Operator configured. + +==== Use Java Argument Files Directly + +In use cases where the `JDK_JAVA_OPTIONS` environment variable has been disabled application code +could also directly access the Java argument files the operator configured and use those to +configure the Coherence JVM. + diff --git a/docs/jvm/030_jvm_args.adoc b/docs/jvm/030_jvm_args.adoc index 018b3a732..508ca6f83 100644 --- a/docs/jvm/030_jvm_args.adoc +++ b/docs/jvm/030_jvm_args.adoc @@ -69,7 +69,7 @@ The Coherence Operator will add the following JVM arguments by default: -Dcoherence.role= -Dcoherence.wka=-wka.svc -Dcoherence.cacheconfig=coherence-cache-config.xml --Dcoherence.k8s.operator.health.port=6676 +-Dcoherence.operator.health.port=6676 -Dcoherence.management.http.port=30000 -Dcoherence.metrics.http.port=9612 -Dcoherence.distributed.persistence-mode=on-demand diff --git a/docs/logging/020_logging.adoc b/docs/logging/020_logging.adoc index f8d886be6..875e381c7 100644 --- a/docs/logging/020_logging.adoc +++ b/docs/logging/020_logging.adoc @@ -212,10 +212,10 @@ data: # <3> @type record_transformer - cluster "#{ENV['COH_CLUSTER_NAME']}" - role "#{ENV['COH_ROLE']}" + cluster "#{ENV['COHERENCE_CLUSTER']}" + role "#{ENV['COHERENCE_ROLE']}" host "#{ENV['HOSTNAME']}" - pod-uid "#{ENV['COH_POD_UID']}" + pod-uid "#{ENV['COHERENCE_OPERATOR__POD_UID']}" diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index b4db25815..31b9ff299 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java index 7049d7090..6543e1283 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorLifecycleListener.java @@ -6,8 +6,6 @@ package com.oracle.coherence.k8s; -import java.io.File; -import java.io.PrintWriter; import java.util.Base64; import java.util.Collections; import java.util.HashMap; @@ -17,11 +15,7 @@ import com.tangosol.application.Context; import com.tangosol.application.LifecycleListener; import com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache; -import com.tangosol.coherence.config.Config; -import com.tangosol.net.CacheFactory; -import com.tangosol.net.Cluster; import com.tangosol.net.DistributedCacheService; -import com.tangosol.net.Member; import com.tangosol.net.PartitionedService; import com.tangosol.net.events.Event; import com.tangosol.net.events.EventDispatcher; @@ -49,12 +43,12 @@ public class CoherenceOperatorLifecycleListener /** * The system property to enable or disable the Operator resuming services. */ - public static final String PROP_CAN_RESUME = "coherence.k8s.operator.can.resume.services"; + public static final String PROP_CAN_RESUME = "coherence.operator.can.resume.services"; /** * The system property to enable or disable the Operator resuming individual services. */ - public static final String PROP_RESUME_SERVICES = "coherence.k8s.operator.resume.services"; + public static final String PROP_RESUME_SERVICES = "coherence.operator.resume.services"; /** * A flag that when {@code true}, allows the Operator to resume suspended services on start-up. @@ -163,7 +157,6 @@ public void preStart(Context context) { @Override public void postStart(Context context) { - initCohCtl(); } @Override @@ -271,136 +264,4 @@ static Map getResumeMap(String services) { return null; } } - - void initCohCtl() { - try { - Cluster cluster = CacheFactory.getCluster(); - Member member = cluster.getLocalMember(); - String clusterName = member.getClusterName(); - String port = Config.getProperty("coherence.management.http.port", "30000"); - String provider = Config.getProperty("coherence.management.http.provider"); - String defaultProtocol = provider == null || provider.isEmpty() ? "http" : "https"; - String protocol = Config.getProperty("coherence.operator.cli.protocol", defaultProtocol); - String connectionType = "http"; - - - // If COHCTL_HOME is set use that for the config location - String cohCtlHome = System.getenv("COHCTL_HOME"); - if (cohCtlHome == null || !cohCtlHome.isEmpty()) { - // Try corresponding system property - cohCtlHome = Config.getProperty("cohctl.home"); - } - - // If we have a COHCTL_HOME env var or property try to create the config there - if (cohCtlHome != null && !cohCtlHome.isEmpty() - && tryCreateConfig(new File(cohCtlHome), connectionType, protocol, port, clusterName)) { - return; - } - - // Either COHCTL_HOME was not set or we failed to create a config there, try ${user.home} - String userHome = System.getProperty("user.home"); - File fileUserHome = new File(userHome); - File fileCohCtlHome = null; - - if (fileUserHome.exists() && fileUserHome.isDirectory()) { - // use ${user.home}/.cohctl - fileCohCtlHome = new File(fileUserHome, ".cohctl"); - if (!fileCohCtlHome.exists()) { - try { - if (!fileCohCtlHome.mkdirs()) { - fileCohCtlHome = null; - } - } - catch (Exception e) { - LOGGER.error("CoherenceOperator: Failed to create cohctl home directory at " + fileCohCtlHome, e); - fileCohCtlHome = null; - } - } - } - - boolean success = false; - if (fileCohCtlHome != null) { - if (fileCohCtlHome.exists() && fileCohCtlHome.isDirectory()) { - success = tryCreateConfig(fileCohCtlHome, connectionType, protocol, port, clusterName); - } - else { - if (!fileCohCtlHome.exists()) { - LOGGER.error("CoherenceOperator: Cannot create cohctl config, directory " - + fileCohCtlHome + " does not exist"); - } - else { - LOGGER.error("CoherenceOperator: Cannot create cohctl config, location " - + fileCohCtlHome + " is not a directory"); - } - } - } - - if (!success) { - if (fileCohCtlHome != null) { - LOGGER.info("CoherenceOperator: unable to create cohctl config in \"" + fileCohCtlHome - + "\" creating cohctl config at /coherence-operator/utils"); - } - tryCreateConfig(new File("/coherence-operator/utils"), connectionType, protocol, port, clusterName); - } - } - catch (Exception e) { - LOGGER.error("Coherence Operator: Failed to create default cohctl config. " + e.getMessage()); - } - } - - /** - * Try to create the Coherence CLI configuration. - * - * @param home the location of the CLI home directory - * @param connectionType the type of the connection http or https - * @param protocol the protocol for the connection http or https - * @param port the management over REST port - * @param clusterName the cluster name - * - * @return {@code true} of the configuration was created - */ - protected boolean tryCreateConfig(File home, String connectionType, String protocol, String port, String clusterName) { - File configFile = new File(home, "cohctl.yaml"); - - if (configFile.exists()) { - return true; - } - - try { - LOGGER.info("CoherenceOperator: creating default cohctl config at " + configFile.getAbsolutePath()); - if (!home.exists()) { - home.mkdirs(); - } - try (PrintWriter out = new PrintWriter(configFile)) { - out.println("clusters:"); - out.println(" - name: default"); - out.println(" discoverytype: manual"); - out.println(" connectiontype: " + connectionType); - out.println(" connectionurl: " + protocol + "://127.0.0.1:" + port + "/management/coherence/cluster"); - out.println(" nameservicediscovery: \"\""); - out.println(" clusterversion: \"" + CacheFactory.VERSION + "\""); - out.println(" clustername: \"" + clusterName + "\""); - out.println(" clustertype: Standalone"); - out.println(" manuallycreated: false"); - out.println(" baseclasspath: \"\""); - out.println(" additionalclasspath: \"\""); - out.println(" arguments: \"\""); - out.println(" managementport: 0"); - out.println(" persistencemode: \"\""); - out.println(" loggingdestination: \"\""); - out.println(" managementavailable: false"); - out.println("color: \"on\""); - out.println("currentcontext: default"); - out.println("debug: false"); - out.println("defaultbytesformat: m"); - out.println("ignoreinvalidcerts: false"); - out.println("requesttimeout: 30"); - } - return true; - } - catch (Exception e) { - LOGGER.error("Coherence Operator: Failed to create default cohctl config. " + e.getMessage()); - return false; - } - } } diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java index 05a1e3e6d..398742f24 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceOperatorMBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -20,7 +20,7 @@ public interface CoherenceOperatorMBean { /** * The System property that is used to set this members identity. */ - String PROP_IDENTITY = "coherence.k8s.operator.identity"; + String PROP_IDENTITY = "coherence.operator.identity"; /** * The name of the Identity MBean attribute. diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java index 8a3ad34d6..71be0f414 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/CoherenceVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -29,10 +29,10 @@ private CoherenceVersion() { public static void main(String[] args) { int exitCode = 0; - String version = System.getenv().getOrDefault("COH_VERSION_CHECK", CacheFactory.VERSION); + String version = System.getenv().getOrDefault("COHERENCE_OPERATOR_VERSION_CHECK", CacheFactory.VERSION); if (args != null && args.length > 0) { - exitCode = versionCheck(version, args) ? 0 : 1; + exitCode = versionCheck(version, args) ? 0 : 99; } else { System.out.println(version); diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java index 5cbb1670c..bcdd81e5b 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -19,7 +19,7 @@ public class Main { private static final String DEFAULT_MAIN = "$DEFAULT$"; - private static final String PROP_FORCE_EXIT = "coherence.k8s.operator.force.exit"; + private static final String PROP_FORCE_EXIT = "coherence.operator.force.exit"; private static boolean initialised = false; diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java index 0541fc22d..c1632776d 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -21,7 +21,7 @@ public interface OperatorLogger { /** * The system property to use to set the health logging should use Java logger. */ - String PROP_LOGGER = "coherence.k8s.operator.health.logger"; + String PROP_LOGGER = "coherence.operator.health.logger"; /** * The {@link #PROP_LOGGER} value to log to std-err. diff --git a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java index de2172a6f..a2e59e8e9 100644 --- a/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java +++ b/java/coherence-operator/src/main/java/com/oracle/coherence/k8s/OperatorRestServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -61,7 +61,7 @@ public class OperatorRestServer implements AutoCloseable { /** * The system property to use to set the health logging. */ - public static final String PROP_HEALTH_LOG = "coherence.k8s.operator.health.logs"; + public static final String PROP_HEALTH_LOG = "coherence.operator.health.logs"; /** * A flag indicating whether debug logging is enabled. @@ -71,92 +71,92 @@ public class OperatorRestServer implements AutoCloseable { /** * The system property to use to enable the health server. */ - public static final String PROP_HEALTH_ENABLED = "coherence.k8s.operator.health.enabled"; + public static final String PROP_HEALTH_ENABLED = "coherence.operator.health.enabled"; /** * The system property to use to set the health port. */ - public static final String PROP_HEALTH_PORT = "coherence.k8s.operator.health.port"; + public static final String PROP_HEALTH_PORT = "coherence.operator.health.port"; /** * The system property to use to determine whether to wait for DCS to start. */ - public static final String PROP_WAIT_FOR_DCS = "coherence.k8s.operator.health.wait.dcs"; + public static final String PROP_WAIT_FOR_DCS = "coherence.operator.health.wait.dcs"; /** * The system property for the TLS keystore file name. */ - public static final String PROP_TLS_KEYSTORE = "coherence.k8s.operator.health.tls.keystore.file"; + public static final String PROP_TLS_KEYSTORE = "coherence.operator.health.tls.keystore.file"; /** * The system property for the TLS keystore type. */ - public static final String PROP_TLS_KEYSTORE_TYPE = "coherence.k8s.operator.health.tls.keystore.type"; + public static final String PROP_TLS_KEYSTORE_TYPE = "coherence.operator.health.tls.keystore.type"; /** * The system property for the TLS keystore algorithm. */ - public static final String PROP_TLS_KEYSTORE_ALGORITHM = "coherence.k8s.operator.health.tls.keystore.algorithm"; + public static final String PROP_TLS_KEYSTORE_ALGORITHM = "coherence.operator.health.tls.keystore.algorithm"; /** * The system property for the TLS keystore password. */ - public static final String PROP_TLS_KEYSTORE_PASSWORD = "coherence.k8s.operator.health.tls.keystore.password.plain"; + public static final String PROP_TLS_KEYSTORE_PASSWORD = "coherence.operator.health.tls.keystore.password.plain"; /** * The system property for the TLS keystore password file name. */ - public static final String PROP_TLS_KEYSTORE_PASSWORD_FILE = "coherence.k8s.operator.health.tls.keystore.password.file"; + public static final String PROP_TLS_KEYSTORE_PASSWORD_FILE = "coherence.operator.health.tls.keystore.password.file"; /** * The system property for the TLS keystore key password. */ - public static final String PROP_TLS_KEY_PASSWORD = "coherence.k8s.operator.health.tls.key.password.plain"; + public static final String PROP_TLS_KEY_PASSWORD = "coherence.operator.health.tls.key.password.plain"; /** * The system property for the TLS keystore key password file name. */ - public static final String PROP_TLS_KEY_PASSWORD_FILE = "coherence.k8s.operator.health.tls.key.password.file"; + public static final String PROP_TLS_KEY_PASSWORD_FILE = "coherence.operator.health.tls.key.password.file"; /** * The system property for the TLS trust store file name. */ - public static final String PROP_TLS_TRUSTSTORE = "coherence.k8s.operator.health.tls.truststore.file"; + public static final String PROP_TLS_TRUSTSTORE = "coherence.operator.health.tls.truststore.file"; /** * The system property for the TLS trust store type. */ - public static final String PROP_TLS_TRUSTSTORE_TYPE = "coherence.k8s.operator.health.tls.truststore.type"; + public static final String PROP_TLS_TRUSTSTORE_TYPE = "coherence.operator.health.tls.truststore.type"; /** * The system property for the TLS trust store algorithm. */ - public static final String PROP_TLS_TRUSTSTORE_ALGORITHM = "coherence.k8s.operator.health.tls.truststore.algorithm"; + public static final String PROP_TLS_TRUSTSTORE_ALGORITHM = "coherence.operator.health.tls.truststore.algorithm"; /** * The system property for the TLS trust store password. */ - public static final String PROP_TLS_TRUSTSTORE_PASSWORD = "coherence.k8s.operator.health.tls.truststore.password.plain"; + public static final String PROP_TLS_TRUSTSTORE_PASSWORD = "coherence.operator.health.tls.truststore.password.plain"; /** * The system property for the TLS trust store password file name. */ - public static final String PROP_TLS_TRUSTSTORE_PASSWORD_FILE = "coherence.k8s.operator.health.tls.truststore.password.file"; + public static final String PROP_TLS_TRUSTSTORE_PASSWORD_FILE = "coherence.operator.health.tls.truststore.password.file"; /** * The system property for the TLS protocol. */ - public static final String PROP_TLS_PROTOCOL = "coherence.k8s.operator.health.tls.protocol"; + public static final String PROP_TLS_PROTOCOL = "coherence.operator.health.tls.protocol"; /** * The system property to indicate whether TLS is 2-way. */ - public static final String PROP_TLS_TWO_WAY = "coherence.k8s.operator.health.tls.twoway"; + public static final String PROP_TLS_TWO_WAY = "coherence.operator.health.tls.twoway"; /** * The system property to enable or disable TLS. */ - public static final String PROP_INSECURE = "coherence.k8s.operator.health.insecure"; + public static final String PROP_INSECURE = "coherence.operator.health.insecure"; /** * The path to the ready endpoint. @@ -206,7 +206,7 @@ public class OperatorRestServer implements AutoCloseable { /** * System property to specify service names to be skipped in the StatusHA test. */ - public static final String PROP_ALLOW_ENDANGERED = "coherence.k8s.operator.statusha.allowendangered"; + public static final String PROP_ALLOW_ENDANGERED = "coherence.operator.statusha.allowendangered"; // ----- data members --------------------------------------------------- diff --git a/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java b/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java index 60a646fdb..ec87d4ee4 100644 --- a/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java +++ b/java/coherence-operator/src/test/java/com/oracle/coherence/k8s/OperatorRestServerIT.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -343,7 +343,7 @@ public void shouldBeStatusHAMultipleMembersStorageEnabledAndDisabledActivePersis DisplayName.of("storage"), SystemProperty.of("coherence.distributed.persistence-mode", "active"), SystemProperty.of("coherence.distributed.persistence.base.dir", activeDir.getAbsolutePath()), - SystemProperty.of("coherence.k8s.operator.health.logs", true), + SystemProperty.of("coherence.operator.health.logs", true), SystemProperty.of(OperatorRestServer.PROP_HEALTH_PORT, httpPort1))) { try (JavaApplication app2 = platform.launch(JavaApplication.class, ClassName.of(Main.class), @@ -354,7 +354,7 @@ public void shouldBeStatusHAMultipleMembersStorageEnabledAndDisabledActivePersis LocalHost.only(), testLogs.builder(), DisplayName.of("storage-disabled"), - SystemProperty.of("coherence.k8s.operator.health.logs", true), + SystemProperty.of("coherence.operator.health.logs", true), SystemProperty.of(OperatorRestServer.PROP_HEALTH_PORT, httpPort2))) { Eventually.assertDeferred(() -> this.isServiceOneRunning(app1), is(true)); diff --git a/pkg/management/coherence_management.go b/pkg/management/coherence_management.go index a1a8e9c0b..c5fa787d6 100644 --- a/pkg/management/coherence_management.go +++ b/pkg/management/coherence_management.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -147,6 +147,10 @@ func query(cl *http.Client, url string, v interface{}) (int, error) { time.Sleep(1 * time.Second) } + if response != nil { + defer response.Body.Close() + } + if err != nil { var status = http.StatusInternalServerError if response != nil { @@ -155,10 +159,11 @@ func query(cl *http.Client, url string, v interface{}) (int, error) { return status, err } - if response.StatusCode == http.StatusOK { - data, _ := io.ReadAll(response.Body) - - err = json.Unmarshal(data, v) + if response != nil { + if response.StatusCode == http.StatusOK { + data, _ := io.ReadAll(response.Body) + err = json.Unmarshal(data, v) + } } return response.StatusCode, err diff --git a/pkg/management/pod_exec.go b/pkg/management/pod_exec.go index c9c00922d..72f59f3e8 100644 --- a/pkg/management/pod_exec.go +++ b/pkg/management/pod_exec.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -80,10 +80,9 @@ func PodExec(ctx context.Context, req *ExecRequest, config *rest.Config) (int, s if err == nil { exitCode = 0 } else { - if exitErr, ok := err.(utilexec.ExitError); ok && exitErr.Exited() { + var exitErr utilexec.ExitError + if errors.As(err, &exitErr) && exitErr.Exited() { exitCode = exitErr.ExitStatus() - } else { - return 1, outStr, errStr, errors.New("failed to find exit code") } } diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index b6e045ba0..3b7e3e586 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -296,32 +296,6 @@ func SetupFlags(cmd *cobra.Command, v *viper.Viper) { v.AutomaticEnv() } -func ValidateFlags(v *viper.Viper) error { - var err error - certValidity := v.GetDuration(FlagCACertValidity) - certRotateBefore := v.GetDuration(FlagCACertRotateBefore) - if certRotateBefore > certValidity { - return fmt.Errorf("%s must be larger than %s", FlagCACertValidity, FlagCACertRotateBefore) - } - - certType := v.GetString(FlagCertType) - if certType != CertTypeSelfSigned && certType != CertTypeCertManager && certType != CertTypeManual { - return fmt.Errorf("%s parameter is invalid", FlagCertType) - } - - _, err = GetGlobalAnnotations(v) - if err != nil { - return err - } - - _, err = GetGlobalLabels(v) - if err != nil { - return err - } - - return err -} - func SetViper(v *viper.Viper) { currentViper = v } diff --git a/pkg/runner/cmd_config.go b/pkg/runner/cmd_config.go new file mode 100644 index 000000000..159a02b60 --- /dev/null +++ b/pkg/runner/cmd_config.go @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v 1.0 as shown at + * http://oss.oracle.com/licenses/upl. + */ + +package runner + +import ( + "bytes" + "fmt" + v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/api/resource" + "os" + "path/filepath" + ctrl "sigs.k8s.io/controller-runtime" + "strconv" + "strings" +) + +var configLog = ctrl.Log.WithName("config") + +// configCommand creates the corba "config" sub-command +func configCommand(env map[string]string) *cobra.Command { + cmd := &cobra.Command{ + Use: v1.RunnerConfig, + Short: "Create the Operator JVM args files a Coherence server", + Long: "Create the Operator JVM args files a Coherence server", + RunE: func(cmd *cobra.Command, args []string) error { + return maybeRun(cmd, createsFiles) + }, + } + + utilDir, found := env[v1.EnvVarCohUtilDir] + if !found || utilDir == "" { + utilDir = v1.VolumeMountPathUtils + } + + flagSet := cmd.Flags() + flagSet.String(ArgUtilsDir, utilDir, "The utils files root directory") + + return cmd +} + +// createsFiles will create the various config files +func createsFiles(details *run_details.RunDetails, _ *cobra.Command) (bool, error) { + var err error + + ma, found := details.LookupEnv(v1.EnvVarAppMainArgs) + if found { + if ma != "" { + for _, arg := range strings.Split(ma, " ") { + details.MainArgs = append(details.MainArgs, details.ExpandEnv(arg)) + } + } + } + + var cp string + var args string + var main string + var sb string + + populateMainClass(details) + populateServerDetails(details) + err = configureCommand(details) + if err != nil { + return false, errors.Wrap(err, "failed to configure server command") + } + + fileMap := make(map[string]string) + if cp, err = createClassPathFile(details); err != nil { + return false, err + } + fileMap[v1.OperatorClasspathFile] = cp + if args, err = createArgsFile(details); err != nil { + return false, err + } + fileMap[v1.OperatorJvmArgsFile] = args + if main, err = createMainClassFile(details); err != nil { + return false, err + } + fileMap[v1.OperatorMainClassFile] = main + if sb, err = createSpringBootFile(details); err != nil { + return false, err + } + fileMap[v1.OperatorSpringBootArgsFile] = sb + if err = createCliConfig(details); err != nil { + return false, err + } + + if err = createOperatorCoherenceArgsFile(details, fileMap); err != nil { + return false, err + } + if err = createOperatorEntryPointArgsFile(details, fileMap); err != nil { + return false, err + } + + return false, nil +} + +// createOperatorCoherenceArgsFile will create the full arguments file for the Coherence container. +// This file will contain the class path, all the JVM options, the main class and any main method arguments. +func createOperatorCoherenceArgsFile(details *run_details.RunDetails, files map[string]string) error { + return createFullArgsFile(details, files, v1.OperatorCoherenceArgsFile, true) +} + +// createOperatorCoherenceArgsFile will create the full arguments file for the Coherence container +// This file will contain the class path, all the JVM options, but not the main class or any main method arguments. +func createOperatorEntryPointArgsFile(details *run_details.RunDetails, files map[string]string) error { + return createFullArgsFile(details, files, v1.OperatorEntryPointArgsFile, false) +} + +// createOperatorCoherenceArgsFile will create the full arguments file of a specified name, +// optionally including the main class name and any main args +func createFullArgsFile(details *run_details.RunDetails, files map[string]string, fileName string, includeMain bool) error { + var buffer bytes.Buffer + buffer.WriteString("--class-path") + if cp, ok := files[v1.OperatorClasspathFile]; ok { + buffer.WriteString("\n") + buffer.WriteString(cp) + } + if args, ok := files[v1.OperatorJvmArgsFile]; ok { + buffer.WriteString("\n") + buffer.WriteString(args) + } + + if details.IsSpringBoot() { + if sb, ok := files[v1.OperatorSpringBootArgsFile]; ok { + buffer.WriteString("\n") + buffer.WriteString(sb) + } + } + + if includeMain { + main := files[v1.OperatorMainClassFile] + buffer.WriteString("\n") + buffer.WriteString(main) + if len(details.MainArgs) > 0 { + for _, arg := range details.MainArgs { + buffer.WriteString("\n") + buffer.WriteString(arg) + } + } + } + + path := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, fileName) + if err := os.WriteFile(path, buffer.Bytes(), os.ModePerm); err != nil { + return errors.Wrap(err, "failed to write coherence container args file") + } + configLog.Info("Created args file", "FileName", path, "Args", buffer.String()) + return nil +} + +// createClassPathFile will create the class path files for a Coherence Pod +func createClassPathFile(details *run_details.RunDetails) (string, error) { + var classpath string + var err error + if details.IsSpringBoot() { + if jar, _ := details.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { + classpath = jar + } else { + // no fat jar, so use the current directory + wd, err := os.Getwd() + if err != nil { + return "", errors.Wrap(err, "failed to get the current working directory") + } + classpath = fmt.Sprintf(v1.FileNamePattern, wd, os.PathSeparator, "*") + classpath = classpath + ":" + wd + } + } else { + classpath = details.GetClasspath() + } + cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + err = os.WriteFile(cpFile, []byte(classpath), os.ModePerm) + if err != nil { + return "", errors.Wrap(err, "failed to write coherence classpath file") + } + configLog.Info("Created class path file", "FileName", cpFile, "ClassPath", classpath) + return classpath, nil +} + +// createArgsFile will create the JVM args files for a Coherence Pod - typically this is run from an init-container +func createArgsFile(details *run_details.RunDetails) (string, error) { + args := details.GetAllArgs() + argFileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + data := strings.Join(args, "\n") + if err := os.WriteFile(argFileName, []byte(data), os.ModePerm); err != nil { + return "", errors.Wrap(err, "failed to write JVM args file "+argFileName) + } + + configLog.Info("Created JVM args file", "FileName", argFileName, "Args", data) + return data, nil +} + +// createSpringBootFile will create the SpringBoot JVM args files for a Coherence Pod - typically this is run from an init-container +func createSpringBootFile(details *run_details.RunDetails) (string, error) { + argsFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) + cp := strings.ReplaceAll(details.GetClasspath(), ":", ",") + + var args string + if details.InnerMainClass == "" || details.InnerMainClass == v1.DefaultMain { + args = fmt.Sprintf(v1.SystemPropertyPattern, v1.SysPropSpringLoaderPath, cp) + } else { + args = fmt.Sprintf(v1.SystemPropertyPattern, v1.SysPropSpringLoaderPath, cp) + args = args + "\n" + fmt.Sprintf(v1.SystemPropertyPattern, v1.SysPropSpringLoaderMain, details.InnerMainClass) + } + + err := os.WriteFile(argsFile, []byte(args), os.ModePerm) + if err != nil { + return "", errors.Wrap(err, "failed to write coherence classpath file") + } + configLog.Info("Created SpringBoot args file", "FileName", argsFile, "Args", args) + return args, nil +} + +// createMainClassFile will create the file containing the main class name for a Coherence Pod - typically this is run from an init-container +func createMainClassFile(details *run_details.RunDetails) (string, error) { + fileName := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorMainClassFile) + + var s string + if details.InnerMainClass == "" || details.IsSpringBoot() { + s = details.MainClass + } else { + s = fmt.Sprintf("%s\n%s", details.MainClass, details.InnerMainClass) + } + + if err := os.WriteFile(fileName, []byte(s), os.ModePerm); err != nil { + return "", errors.Wrap(err, "failed to write coherence classpath file") + } + configLog.Info("Created main class file", "FileName", fileName, "Content", s) + return s, nil +} + +func createCliConfig(details *run_details.RunDetails) error { + home := details.GetenvOrDefault(v1.EnvVarCohCtlHome, details.UtilsDir) + fileName := fmt.Sprintf(v1.FileNamePattern, home, os.PathSeparator, "cohctl.yaml") + + cluster := details.Getenv(v1.EnvVarCohClusterName) + port := details.Getenv(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohPortSuffix) + if port == "" { + port = fmt.Sprintf("%d", v1.DefaultManagementPort) + } + protocol := details.Getenv(v1.EnvVarCohCliProtocol) + if protocol == "" { + protocol = "http" + } + + var buffer bytes.Buffer + buffer.WriteString("clusters:\n") + buffer.WriteString(" - name: default\n") + buffer.WriteString(" discoverytype: manual\n") + buffer.WriteString(" connectiontype: " + protocol + "\n") + buffer.WriteString(" connectionurl: " + protocol + "://127.0.0.1:" + port + "/management/coherence/cluster\n") + buffer.WriteString(" nameservicediscovery: \"\"\n") + buffer.WriteString(" clusterversion: \"\"\n") + buffer.WriteString(" clustername: \"" + cluster + "\"\n") + buffer.WriteString(" clustertype: Standalone\n") + buffer.WriteString(" manuallycreated: true\n") + buffer.WriteString(" baseclasspath: \"\"\n") + buffer.WriteString(" additionalclasspath: \"\"\n") + buffer.WriteString(" arguments: \"\"\n") + buffer.WriteString(" managementport: " + port + "\n") + buffer.WriteString(" persistencemode: \"\"\n") + buffer.WriteString(" loggingdestination: \"\"\n") + buffer.WriteString(" managementavailable: false\n") + buffer.WriteString("color: \"on\"\n") + buffer.WriteString("currentcontext: default\n") + buffer.WriteString("debug: false\n") + buffer.WriteString("defaultbytesformat: m\n") + buffer.WriteString("ignoreinvalidcerts: false\n") + buffer.WriteString("requesttimeout: 30\n") + if err := os.WriteFile(fileName, buffer.Bytes(), os.ModePerm); err != nil { + configLog.Error(err, "Failed to write coherence CLI config file", "FileName", fileName) + return nil + } + + configLog.Info("Created CLI config file", "FileName", fileName, "Config", buffer.String()) + return nil +} + +// Configure the main class +func populateMainClass(details *run_details.RunDetails) { + details.MainClass = v1.ServerMain + + // If the main class environment variable is set then use that + // otherwise run Coherence DefaultMain. + mc, found := details.LookupEnv(v1.EnvVarAppMainClass) + + if !found || mc == "" { + // no custom mani set so check for a JIB main class file + appDir := details.GetenvOrDefault(v1.EnvVarCohAppDir, "/app") + jibMainClassFileName := filepath.Join(appDir, "jib-main-class-file") + fi, err := os.Stat(jibMainClassFileName) + if err != nil && appDir != "/app" { + // try /app dir + jibMainClassFileName = "/app/jib-main-class-file" + fi, err = os.Stat(jibMainClassFileName) + } + + if err == nil && (fi.Size() != 0) { + mainCls, _ := readFirstLineFromFile(jibMainClassFileName) + if len(mainCls) != 0 { + mc = mainCls + found = true + } + } + } + + isSpring := details.IsSpringBoot() + switch { + case found && !isSpring: + // we have a main class specified, and we're not a Spring Boot app + details.InnerMainClass = mc + case found && details.AppType == v1.AppTypeSpring2: + // we have a main class and the app is Spring Boot 2.x + // the main is PropertiesLauncher, + details.MainClass = v1.SpringBootMain2 + // the specified main class is set as a Spring loader property + details.InnerMainClass = mc + case found && details.AppType == v1.AppTypeSpring3: + // we have a main class and the app is Spring Boot 3.x + // the main is PropertiesLauncher, + details.MainClass = v1.SpringBootMain3 + // the specified main class is set as a Spring loader property + details.InnerMainClass = mc + case !found && details.AppType == v1.AppTypeSpring2: + // the app type is Spring Boot 2.x so main is PropertiesLauncher + details.MainClass = v1.SpringBootMain2 + case !found && details.AppType == v1.AppTypeSpring3: + // the app type is Spring Boot 3.x so main is PropertiesLauncher + details.MainClass = v1.SpringBootMain3 + case !found && details.AppType == v1.AppTypeCoherence: + // the app type is Coherence so main is DefaultMain + details.InnerMainClass = v1.DefaultMain + case !found && details.AppType == v1.AppTypeHelidon: + // the app type is Helidon so main is the Helidon CDI starter + details.InnerMainClass = v1.HelidonMain + default: + // no main or app type specified, use DefaultMain + details.InnerMainClass = v1.DefaultMain + } +} + +// Configure the runner to run a Coherence Server +func populateServerDetails(details *run_details.RunDetails) { + // Configure the Coherence member's role + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, v1.SysPropCoherenceRole, "storage") + // Configure whether this member is storage enabled + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohStorage, v1.SysPropCoherenceDistributedLocalStorage) + + // Configure Coherence Tracing + ratio := details.Getenv(v1.EnvVarCohTracingRatio) + if ratio != "" { + q, err := resource.ParseQuantity(ratio) + if err == nil { + d := q.AsDec() + details.AddSystemPropertyArg(v1.SysPropCoherenceTracingRatio, d.String()) + } else { + fmt.Printf("ERROR: Coherence tracing ratio \"%s\" is invalid - %s\n", ratio, err.Error()) + os.Exit(1) + } + } + + // Configure whether Coherence management is enabled + hasMgmt := details.IsEnvTrue(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohEnabledSuffix) + log.Info("Coherence Management over REST", "enabled", strconv.FormatBool(hasMgmt), "envVar", v1.EnvVarCohMgmtPrefix+v1.EnvVarCohEnabledSuffix) + if hasMgmt { + fmt.Println("INFO: Configuring Coherence Management over REST") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "all") + if details.CoherenceHome != "" { + // If management is enabled and the COHERENCE_HOME environment variable is set + // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath + // This is for legacy 14.1.1.0 and 12.2.1.4 images + details.AddClasspath(details.CoherenceHome + "/lib/coherence-management.jar") + } + } + + // Configure whether Coherence metrics is enabled + hasMetrics := details.IsEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) + log.Info("Coherence Metrics", "enabled", strconv.FormatBool(hasMetrics), "envVar", v1.EnvVarCohMetricsPrefix+v1.EnvVarCohEnabledSuffix) + if hasMetrics { + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "true") + fmt.Println("INFO: Configuring Coherence Metrics") + if details.CoherenceHome != "" { + // If metrics is enabled and the COHERENCE_HOME environment variable is set + // then $COHERENCE_HOME/lib/coherence-metrics.jar will be added to the classpath + // This is for legacy 14.1.1.0 and 12.2.1.4 images + details.AddClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") + } + } + + // Configure whether to add third-party modules to the classpath if management over rest + // or metrics are enabled and the directory pointed to by the DEPENDENCY_MODULES environment + // variable exists. + if hasMgmt || hasMetrics { + dm := details.Getenv(v1.EnvVarCohDependencyModules) + if dm != "" { + stat, err := os.Stat(dm) + if err == nil && stat.IsDir() { + // dependency modules directory exists + details.AddClasspath(dm + "/*") + } + } + } + + if details.IsEnvTrueOrBlank(v1.EnvVarJvmShowSettings) { + details.AddDiagnosticOption("-XshowSettings:all") + details.AddDiagnosticOption("-XX:+PrintCommandLineFlags") + details.AddDiagnosticOption("-XX:+PrintFlagsFinal") + } + + // Add GC logging parameters if required + if details.IsEnvTrue(v1.EnvVarJvmGcLogging) { + details.AddMemoryOption("-verbose:gc") + details.AddMemoryOption("-XX:+PrintGCDetails") + details.AddMemoryOption("-XX:+PrintGCTimeStamps") + details.AddMemoryOption("-XX:+PrintHeapAtGC") + details.AddMemoryOption("-XX:+PrintTenuringDistribution") + details.AddMemoryOption("-XX:+PrintGCApplicationStoppedTime") + details.AddMemoryOption("-XX:+PrintGCApplicationConcurrentTime") + } +} diff --git a/pkg/runner/cmd_console.go b/pkg/runner/cmd_console.go index 3d5128356..f945fe809 100644 --- a/pkg/runner/cmd_console.go +++ b/pkg/runner/cmd_console.go @@ -8,9 +8,9 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" - "strings" ) const ( @@ -25,7 +25,7 @@ func consoleCommand(v *viper.Viper) *cobra.Command { Short: "Start a Coherence interactive console", Long: "Starts a Coherence interactive console", RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { console(details, args, v) }) }, @@ -37,28 +37,27 @@ func consoleCommand(v *viper.Viper) *cobra.Command { } // Configure the runner to run a Coherence CacheFactory console -func console(details *RunDetails, args []string, v *viper.Viper) { - app := strings.ToLower(v.GetString(v1.EnvVarAppType)) - if app == AppTypeSpring2 { - details.AppType = AppTypeSpring2 - details.MainClass = SpringBootMain2 - details.addArg("-Dloader.main=" + ConsoleMain) +func console(details *run_details.RunDetails, args []string, v *viper.Viper) { + details.Command = CommandConsole + loadConfigFiles(details) + + if details.IsSpringBoot() { + details.AddSystemPropertyArg(v1.SysPropSpringLoaderMain, v1.ConsoleMain) } else { - details.AppType = AppTypeJava - details.MainClass = ConsoleMain + details.AppType = v1.AppTypeJava + details.MainClass = v1.ConsoleMain } - details.Command = CommandConsole - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") - details.addArg("-Dcoherence.health.http.port=0") - details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarCohRole, "console") - details.setenv(v1.EnvVarCohHealthPort, "0") + + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandConsole) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_initialise.go b/pkg/runner/cmd_initialise.go index 639bc6fb6..d5aa78f85 100644 --- a/pkg/runner/cmd_initialise.go +++ b/pkg/runner/cmd_initialise.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package runner import ( "fmt" v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/oracle/coherence-operator/pkg/utils" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -61,7 +62,7 @@ func initCommand(env map[string]string) *cobra.Command { } // initialise will initialise a Coherence Pod - typically this is run from an init-container -func initialise(details *RunDetails, cmd *cobra.Command) (bool, error) { +func initialise(details *run_details.RunDetails, cmd *cobra.Command) (bool, error) { return initialiseWithEnv(cmd, details.Getenv) } diff --git a/pkg/runner/cmd_jshell.go b/pkg/runner/cmd_jshell.go index 9875e56c3..182b2a15a 100644 --- a/pkg/runner/cmd_jshell.go +++ b/pkg/runner/cmd_jshell.go @@ -8,6 +8,7 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -25,7 +26,7 @@ func jShellCommand(v *viper.Viper) *cobra.Command { Long: "Starts a Coherence interactive JShell console", Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { jShell(details, args, v) }) }, @@ -37,21 +38,21 @@ func jShellCommand(v *viper.Viper) *cobra.Command { } // Configure the runner to run a Coherence JShell console -func jShell(details *RunDetails, args []string, v *viper.Viper) { - details.AppType = AppTypeJShell +func jShell(details *run_details.RunDetails, args []string, v *viper.Viper) { + details.AppType = v1.AppTypeJShell details.Command = CommandJShell - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarJvmUseContainerLimits, "false") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") - details.addArg("-Dcoherence.health.http.port=0") - details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarCohRole, "jshell") - details.setenv(v1.EnvVarCohHealthPort, "0") + loadConfigFiles(details) + + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandJShell) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_node_labels.go b/pkg/runner/cmd_node_labels.go index 99e3a1f17..532017ab8 100644 --- a/pkg/runner/cmd_node_labels.go +++ b/pkg/runner/cmd_node_labels.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package runner import ( "context" "fmt" + v1 "github.com/oracle/coherence-operator/api/v1" "github.com/pkg/errors" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -100,7 +101,7 @@ func executeNodeQuery(cmd *cobra.Command) error { } for label, value := range node.Labels { - fileName := fmt.Sprintf("%s%c%s", dir, sep, label) + fileName := fmt.Sprintf(v1.FileNamePattern, dir, sep, label) fileDir := filepath.Dir(fileName) err = os.MkdirAll(fileDir, 0755) diff --git a/pkg/runner/cmd_operator_test.go b/pkg/runner/cmd_operator_test.go index 4ead725e8..bad967317 100644 --- a/pkg/runner/cmd_operator_test.go +++ b/pkg/runner/cmd_operator_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -22,7 +22,7 @@ func TestBasicOperator(t *testing.T) { } args := []string{"operator", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -45,7 +45,7 @@ func TestOperatorWithSingleGlobalLabel(t *testing.T) { } args := []string{"operator", "--dry-run", "--global-label", "one=value-one"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -69,7 +69,7 @@ func TestOperatorWithMultipleGlobalLabels(t *testing.T) { "--global-label", "two=value-two", "--global-label", "three=value-three", } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -91,7 +91,7 @@ func TestOperatorWithSingleGlobalAnnotation(t *testing.T) { } args := []string{"operator", "--dry-run", "--global-annotation", "one=value-one"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -115,7 +115,7 @@ func TestOperatorWithMultipleGlobalAnnotations(t *testing.T) { "--global-annotation", "two=value-two", "--global-annotation", "three=value-three", } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/runner/cmd_query_plus.go b/pkg/runner/cmd_query_plus.go index 5b2313504..68da88ac2 100644 --- a/pkg/runner/cmd_query_plus.go +++ b/pkg/runner/cmd_query_plus.go @@ -8,9 +8,9 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" - "strings" ) const ( @@ -26,7 +26,7 @@ func queryPlusCommand(v *viper.Viper) *cobra.Command { Long: "Starts a Coherence interactive QueryPlus console", Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { queryPlus(details, args, v) }) }, @@ -38,28 +38,27 @@ func queryPlusCommand(v *viper.Viper) *cobra.Command { } // Configure the runner to run a Coherence Query Plus console -func queryPlus(details *RunDetails, args []string, v *viper.Viper) { - app := strings.ToLower(v.GetString(v1.EnvVarAppType)) - if app == AppTypeSpring2 { - details.AppType = AppTypeSpring2 - details.MainClass = SpringBootMain2 - details.addArg("-Dloader.main=" + QueryPlusMain) +func queryPlus(details *run_details.RunDetails, args []string, v *viper.Viper) { + details.Command = CommandQueryPlus + loadConfigFiles(details) + + if details.IsSpringBoot() { + details.AddSystemPropertyArg(v1.SysPropSpringLoaderMain, v1.QueryPlusMain) } else { - details.AppType = AppTypeJava - details.MainClass = QueryPlusMain + details.AppType = v1.AppTypeJava + details.MainClass = v1.QueryPlusMain } - details.Command = CommandQueryPlus - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") - details.addArg("-Dcoherence.health.http.port=0") - details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarCohRole, "queryPlus") - details.setenv(v1.EnvVarCohHealthPort, "0") + + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandQueryPlus) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=off") details.MainArgs = args } diff --git a/pkg/runner/cmd_server.go b/pkg/runner/cmd_server.go index b4fb196f8..a2b82c39c 100644 --- a/pkg/runner/cmd_server.go +++ b/pkg/runner/cmd_server.go @@ -7,13 +7,13 @@ package runner import ( + "bufio" "fmt" v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" + "github.com/pkg/errors" "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/api/resource" "os" - "path/filepath" - "strconv" "strings" ) @@ -37,60 +37,11 @@ func serverCommand() *cobra.Command { } // Configure the runner to run a Coherence Server -func server(details *RunDetails, _ *cobra.Command) { +func server(details *run_details.RunDetails, _ *cobra.Command) { details.Command = CommandServer - details.MainClass = ServerMain - - // If the main class environment variable is set then use that - // otherwise run Coherence DefaultMain. - mc, found := details.lookupEnv(v1.EnvVarAppMainClass) - appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") - jibMainClassFileName := filepath.Join(appDir, "jib-main-class-file") - fi, err := os.Stat(jibMainClassFileName) - mainCls := "" - if err == nil && (fi.Size() != 0) { - mainCls, _ = readFirstLineFromFile(jibMainClassFileName) - } - if !found && (len(mainCls) != 0) { - mc = mainCls - found = true - } - isSpring := details.IsSpringBoot() - switch { - case found && !isSpring: - // we have a main class specified, and we're not a Spring Boot app - details.MainArgs = []string{mc} - case found && details.AppType == AppTypeSpring2: - // we have a main class and the app is Spring Boot 2.x - // the main is PropertiesLauncher, - details.MainClass = SpringBootMain2 - // the specified main class is set as a Spring loader property - details.addArg("-Dloader.main=" + mc) - case found && details.AppType == AppTypeSpring3: - // we have a main class and the app is Spring Boot 3.x - // the main is PropertiesLauncher, - details.MainClass = SpringBootMain3 - // the specified main class is set as a Spring loader property - details.addArg("-Dloader.main=" + mc) - case !found && details.AppType == AppTypeSpring2: - // the app type is Spring Boot 2.x so main is PropertiesLauncher - details.MainClass = SpringBootMain2 - case !found && details.AppType == AppTypeSpring3: - // the app type is Spring Boot 3.x so main is PropertiesLauncher - details.MainClass = SpringBootMain3 - case !found && details.AppType == AppTypeCoherence: - // the app type is Coherence so main is DefaultMain - details.MainArgs = []string{DefaultMain} - case !found && details.AppType == AppTypeHelidon: - // the app type is Helidon so main is the Helidon CDI starter - details.MainArgs = []string{HelidonMain} - default: - // no main or app type specified, use DefaultMain - details.MainArgs = []string{DefaultMain} - } + loadConfigFiles(details) - // Check for any main class arguments - ma, found := details.lookupEnv(v1.EnvVarAppMainArgs) + ma, found := details.LookupEnv(v1.EnvVarAppMainArgs) if found { if ma != "" { for _, arg := range strings.Split(ma, " ") { @@ -98,79 +49,87 @@ func server(details *RunDetails, _ *cobra.Command) { } } } +} - // Configure the Coherence member's role - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohRole, "-Dcoherence.role", "storage") - // Configure whether this member is storage enabled - details.addArgFromEnvVar(v1.EnvVarCohStorage, "-Dcoherence.distributed.localstorage") - - // Configure Coherence Tracing - ratio := details.Getenv(v1.EnvVarCohTracingRatio) - if ratio != "" { - q, err := resource.ParseQuantity(ratio) - if err == nil { - d := q.AsDec() - details.addArg("-Dcoherence.tracing.ratio=" + d.String()) - } else { - fmt.Printf("ERROR: Coherence tracing ratio \"%s\" is invalid - %s\n", ratio, err.Error()) - os.Exit(1) - } +func loadConfigFiles(details *run_details.RunDetails) { + var err error + + if err = loadClassPathFile(details); err != nil { + fmt.Printf("Error loading class path file %v\n", err) } - // Configure whether Coherence management is enabled - hasMgmt := details.isEnvTrue(v1.EnvVarCohMgmtPrefix + v1.EnvVarCohEnabledSuffix) - log.Info("Coherence Management over REST", "enabled", strconv.FormatBool(hasMgmt), "envVar", v1.EnvVarCohMgmtPrefix+v1.EnvVarCohEnabledSuffix) - if hasMgmt { - fmt.Println("INFO: Configuring Coherence Management over REST") - details.addArg("-Dcoherence.management.http=all") - if details.CoherenceHome != "" { - // If management is enabled and the COHERENCE_HOME environment variable is set - // then $COHERENCE_HOME/lib/coherence-management.jar will be added to the classpath - details.addClasspath(details.CoherenceHome + "/lib/coherence-management.jar") - } + if err = loadJvmArgsFile(details); err != nil { + fmt.Printf("Error loading class path file %v\n", err) } - // Configure whether Coherence metrics is enabled - hasMetrics := details.isEnvTrue(v1.EnvVarCohMetricsPrefix + v1.EnvVarCohEnabledSuffix) - log.Info("Coherence Metrics", "enabled", strconv.FormatBool(hasMetrics), "envVar", v1.EnvVarCohMetricsPrefix+v1.EnvVarCohEnabledSuffix) - if hasMetrics { - details.addArg("-Dcoherence.metrics.http.enabled=true") - fmt.Println("INFO: Configuring Coherence Metrics") - if details.CoherenceHome != "" { - // If metrics is enabled and the COHERENCE_HOME environment variable is set - // then $COHERENCE_HOME/lib/coherence-metrics.jar will be added to the classpath - details.addClasspath(details.CoherenceHome + "/lib/coherence-metrics.jar") + if details.IsSpringBoot() { + if err = loadSpringBootArgsFile(details); err != nil { + fmt.Printf("Error loading main class file %v\n", err) } } - // Configure whether to add third-party modules to the classpath if management over rest - // or metrics are enabled and the directory pointed to by the DEPENDENCY_MODULES environment - // variable exists. - if hasMgmt || hasMetrics { - dm := details.Getenv(v1.EnvVarCohDependencyModules) - if dm != "" { - stat, err := os.Stat(dm) - if err == nil && stat.IsDir() { - // dependency modules directory exists - details.addClasspath(dm + "/*") - } + if err = loadMainClassFile(details); err != nil { + fmt.Printf("Error loading main class file %v\n", err) + } +} + +func loadClassPathFile(details *run_details.RunDetails) error { + file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + data, err := os.ReadFile(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) + } + details.Classpath = string(data) + return nil +} + +func loadJvmArgsFile(details *run_details.RunDetails) error { + file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + lines, err := readLines(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) + } + details.AddArgs(lines...) + return nil +} + +func loadMainClassFile(details *run_details.RunDetails) error { + dir := details.GetenvOrDefault(v1.EnvVarCohUtilDir, details.UtilsDir) + file := fmt.Sprintf(v1.FileNamePattern, dir, os.PathSeparator, v1.OperatorMainClassFile) + lines, err := readLines(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) + } + if len(lines) > 0 { + details.MainClass = lines[0] + if len(lines) > 1 { + details.MainArgs = append(details.MainArgs, lines[1:]...) } } + return nil +} + +func loadSpringBootArgsFile(details *run_details.RunDetails) error { + file := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorSpringBootArgsFile) + lines, err := readLines(file) + if err != nil { + return errors.Wrapf(err, "error reading %s", file) + } + details.AddArgs(lines...) + return nil +} - if details.isEnvTrueOrBlank(v1.EnvVarJvmShowSettings) { - details.addArg("-XshowSettings:all") - details.addArg("-XX:+PrintCommandLineFlags") - details.addArg("-XX:+PrintFlagsFinal") +func readLines(path string) ([]string, error) { + file, err := os.Open(path) + if err != nil { + return nil, err } + defer file.Close() - // Add GC logging parameters if required - if details.isEnvTrue(v1.EnvVarJvmGcLogging) { - details.addArg("-verbose:gc") - details.addArg("-XX:+PrintGCDetails") - details.addArg("-XX:+PrintGCTimeStamps") - details.addArg("-XX:+PrintHeapAtGC") - details.addArg("-XX:+PrintTenuringDistribution") - details.addArg("-XX:+PrintGCApplicationStoppedTime") - details.addArg("-XX:+PrintGCApplicationConcurrentTime") + var lines []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) } + return lines, scanner.Err() } diff --git a/pkg/runner/cmd_sleep.go b/pkg/runner/cmd_sleep.go index 72527eb0c..2d2b2e849 100644 --- a/pkg/runner/cmd_sleep.go +++ b/pkg/runner/cmd_sleep.go @@ -8,6 +8,7 @@ package runner import ( v1 "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/spf13/cobra" "github.com/spf13/viper" "strings" @@ -26,7 +27,7 @@ func sleepCommand(v *viper.Viper) *cobra.Command { Long: "Sleep for a number of seconds", Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { - return run(cmd, func(details *RunDetails, cmd *cobra.Command) { + return run(cmd, func(details *run_details.RunDetails, cmd *cobra.Command) { sleep(details, args, v) }) }, @@ -37,29 +38,31 @@ func sleepCommand(v *viper.Viper) *cobra.Command { return cmd } -func sleep(details *RunDetails, args []string, v *viper.Viper) { +func sleep(details *run_details.RunDetails, args []string, v *viper.Viper) { app := strings.ToLower(v.GetString(v1.EnvVarAppType)) - if app == AppTypeSpring2 { - details.AppType = AppTypeSpring2 - details.MainClass = SpringBootMain2 - details.addArg("-Dloader.main=com.oracle.coherence.k8s.Sleep") + if app == v1.AppTypeSpring2 { + details.AppType = v1.AppTypeSpring2 + details.MainClass = v1.SpringBootMain2 + details.AddSystemPropertyArg(v1.SysPropSpringLoaderMain, v1.SleepMain) } else { - details.AppType = AppTypeJava - details.MainClass = "com.oracle.coherence.k8s.Sleep" + details.AppType = v1.AppTypeJava + details.MainClass = v1.SleepMain } details.Command = CommandSleep details.MainArgs = args details.UseOperatorHealth = true - details.addArg("-Dcoherence.distributed.localstorage=false") - details.addArg("-Dcoherence.localport.adjust=true") - details.addArg("-Dcoherence.management.http=none") - details.addArg("-Dcoherence.management.http.port=0") - details.addArg("-Dcoherence.metrics.http.enabled=false") - details.addArg("-Dcoherence.metrics.http.port=0") - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") - details.addArg("-Dcoherence.grpc.enabled=false") - details.setenv(v1.EnvVarJvmMemoryNativeTracking, "off") - details.setenv(v1.EnvVarCohRole, "sleep") - details.setenv(v1.EnvVarCohHealthPort, "0") + + details.AddSystemPropertyArg(v1.SysPropCoherenceRole, CommandSleep) + details.AddSystemPropertyArg(v1.SysPropCoherenceDistributedLocalStorage, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceLocalPortAdjust, "true") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttp, "none") + details.AddSystemPropertyArg(v1.SysPropCoherenceManagementHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceMetricsHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.AddSystemPropertyArg(v1.SysPropCoherenceHealthHttpPort, "0") + details.AddSystemPropertyArg(v1.SysPropCoherenceGrpcEnabled, "false") + + details.Setenv(v1.EnvVarJvmMemoryNativeTracking, "off") details.MainArgs = args } diff --git a/pkg/runner/run_details.go b/pkg/runner/run_details/run_details.go similarity index 58% rename from pkg/runner/run_details.go rename to pkg/runner/run_details/run_details.go index e46fc06bb..c08618220 100644 --- a/pkg/runner/run_details.go +++ b/pkg/runner/run_details/run_details.go @@ -4,19 +4,21 @@ * http://oss.oracle.com/licenses/upl. */ -package runner +package run_details import ( "fmt" + "github.com/go-logr/logr" v1 "github.com/oracle/coherence-operator/api/v1" "github.com/spf13/viper" "os" "path/filepath" - "sort" "strings" ) -func NewRunDetails(v *viper.Viper) *RunDetails { +func NewRunDetails(v *viper.Viper, log logr.Logger) *RunDetails { + var err error + skipSiteVar := v.GetString(v1.EnvVarCohSkipSite) skipSite := strings.ToLower(skipSiteVar) != "true" @@ -27,13 +29,24 @@ func NewRunDetails(v *viper.Viper) *RunDetails { JavaHome: v.GetString(v1.EnvVarJavaHome), AppType: strings.ToLower(v.GetString(v1.EnvVarAppType)), Dir: v.GetString(v1.EnvVarCohAppDir), - MainClass: DefaultMain, + MainClass: v1.DefaultMain, GetSite: skipSite, + log: log, } // add any Classpath items - details.addClasspath(v.GetString(v1.EnvVarJvmExtraClasspath)) - details.addClasspath(v.GetString(v1.EnvVarJavaClasspath)) + details.AddClasspath(v.GetString(v1.EnvVarJvmExtraClasspath)) + details.AddClasspath(v.GetString(v1.EnvVarJavaClasspath)) + + cpFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorClasspathFile) + if _, err = os.Stat(cpFile); err == nil { + details.ClassPathFile = cpFile + } + + argFile := fmt.Sprintf(v1.FileNamePattern, details.UtilsDir, os.PathSeparator, v1.OperatorJvmArgsFile) + if _, err = os.Stat(argFile); err == nil { + details.JvmArgsFile = argFile + } return details } @@ -49,12 +62,44 @@ type RunDetails struct { UseOperatorHealth bool AppType string Classpath string - Args []string MainClass string + InnerMainClass string MainArgs []string BuildPacks *bool ExtraEnv []string + ClassPathFile string + JvmArgsFile string + args []string + vmOptions []string + memoryArgs []string + diagnosticArgs []string env *viper.Viper + log logr.Logger +} + +func (in *RunDetails) GetAllArgs() []string { + var args []string + args = append(args, in.vmOptions...) + args = append(args, in.memoryArgs...) + args = append(args, in.diagnosticArgs...) + args = append(args, in.args...) + return args +} + +func (in *RunDetails) GetArguments() []string { + return in.args +} + +func (in *RunDetails) GetMemoryOptions() []string { + return in.memoryArgs +} + +func (in *RunDetails) GetDiagnosticOptions() []string { + return in.diagnosticArgs +} + +func (in *RunDetails) GetVMOptions() []string { + return in.vmOptions } // IsSpringBoot returns true if this is a Spring Boot application @@ -62,7 +107,7 @@ func (in *RunDetails) IsSpringBoot() bool { if in.env == nil { return false } - return in.AppType == AppTypeSpring2 || in.AppType == AppTypeSpring3 + return in.AppType == v1.AppTypeSpring2 || in.AppType == v1.AppTypeSpring3 } // Getenv returns the value for the specified environment variable, or empty string if not set. @@ -92,7 +137,7 @@ func (in *RunDetails) Expand(s string, mapping func(string) string) string { buf = make([]byte, 0, 2*len(s)) } buf = append(buf, s[i:j]...) - name, w := in.getShellName(s[j+1:]) + name, w := in.GetShellName(s[j+1:]) switch { case name == "" && w > 0: // Encountered invalid syntax; eat the @@ -115,10 +160,10 @@ func (in *RunDetails) Expand(s string, mapping func(string) string) string { return string(buf) + s[i:] } -// getShellName returns the name that begins the string and the number of bytes +// GetShellName returns the name that begins the string and the number of bytes // consumed to extract it. If the name is enclosed in {}, it's part of a ${} // expansion and two more bytes are needed than the length of the name. -func (in *RunDetails) getShellName(s string) (string, int) { +func (in *RunDetails) GetShellName(s string) (string, int) { switch { case s[0] == '{': if len(s) > 2 && in.isShellSpecialVar(s[1]) && s[2] == '}' { @@ -174,55 +219,55 @@ func (in *RunDetails) isAlphaNum(c uint8) bool { return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' } -func (in *RunDetails) getenvOrDefault(name string, defaultValue string) string { +func (in *RunDetails) GetenvOrDefault(name string, defaultValue string) string { if in.env != nil && in.env.IsSet(name) { return in.env.GetString(name) } return defaultValue } -func (in *RunDetails) lookupEnv(name string) (string, bool) { +func (in *RunDetails) LookupEnv(name string) (string, bool) { if in.env != nil && in.env.IsSet(name) { return in.env.GetString(name), true } return "", false } -func (in *RunDetails) getenvWithPrefix(prefix, name string) string { +func (in *RunDetails) GetenvWithPrefix(prefix, name string) string { return in.Getenv(prefix + name) } -func (in *RunDetails) setenv(key, value string) { +func (in *RunDetails) Setenv(key, value string) { if in.env == nil { in.env = viper.New() } in.env.Set(key, value) } -func (in *RunDetails) isEnvTrue(name string) bool { +func (in *RunDetails) IsEnvTrue(name string) bool { value := in.Getenv(name) return strings.ToLower(value) == "true" } -func (in *RunDetails) isEnvTrueOrBlank(name string) bool { +func (in *RunDetails) IsEnvTrueOrBlank(name string) bool { value := in.Getenv(name) return value == "" || strings.ToLower(value) == "true" } -func (in *RunDetails) getCommand() []string { - return in.getCommandWithPrefix("", "") +func (in *RunDetails) GetCommand() []string { + return in.GetCommandWithPrefix("", "") } -func (in *RunDetails) getCommandWithPrefix(propPrefix, jvmPrefix string) []string { +func (in *RunDetails) GetCommandWithPrefix(propPrefix, jvmPrefix string) []string { var cmd []string - cp := in.getClasspath() + cp := in.GetClasspath() if cp != "" { - cmd = append(cmd, "--class-path", cp) + cmd = append(cmd, v1.JvmOptClassPath, cp) } if propPrefix == "" && jvmPrefix == "" { - cmd = append(cmd, in.Args...) + cmd = append(cmd, in.GetAllArgs()...) } else { - for _, arg := range in.Args { + for _, arg := range in.GetAllArgs() { if strings.HasPrefix(arg, "-D") && propPrefix != "" { cmd = append(cmd, propPrefix+arg) } else if jvmPrefix != "" { @@ -233,63 +278,57 @@ func (in *RunDetails) getCommandWithPrefix(propPrefix, jvmPrefix string) []strin return cmd } -func (in *RunDetails) getSpringBootCommand() []string { - return append(in.getSpringBootArgs(), in.MainClass) +func (in *RunDetails) GetSpringBootCommand() []string { + return append(in.GetSpringBootArgs(), in.MainClass) } -func (in *RunDetails) getSpringBootArgs() []string { +func (in *RunDetails) GetSpringBootArgs() []string { var cmd []string - cp := strings.ReplaceAll(in.getClasspath(), ":", ",") - if cp != "" { - cmd = append(cmd, "-Dloader.path="+cp) + // Are we using a Spring Boot fat jar + if jar, _ := in.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { + cmd = append(cmd, v1.JvmOptClassPath, jar) } + return append(cmd, in.GetAllArgs()...) +} - // Are we using a Spring Boot fat jar - if jar, _ := in.lookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { - cmd = append(cmd, "--class-path", jar) +func (in *RunDetails) AddArgs(args ...string) { + for _, a := range args { + in.AddArg(a) } - cmd = append(cmd, in.Args...) +} - return cmd +func (in *RunDetails) AddArg(arg string) { + if arg != "" { + in.args = append(in.args, in.ExpandEnv(arg)) + } } -/* -func (in *RunDetails) getGraalCommand() []string { - cmd := in.getCommand() - for i, c := range cmd { - switch { - case c == "-cp": - cmd[i] = "--vm.cp" - case strings.HasPrefix(c, "-D"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-XX"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-Xms"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-Xmx"): - cmd[i] = "--vm." + c[1:] - case strings.HasPrefix(c, "-Xss"): - cmd[i] = "--vm." + c[1:] - } +func (in *RunDetails) AddSystemPropertyArg(propName, value string) { + if propName != "" { + arg := fmt.Sprintf(v1.SystemPropertyPattern, propName, value) + in.args = append(in.args, in.ExpandEnv(arg)) } +} - return cmd +func (in *RunDetails) AddVMOption(arg string) { + if arg != "" { + in.vmOptions = append(in.vmOptions, in.ExpandEnv(arg)) + } } -*/ -func (in *RunDetails) addArgs(args ...string) { - for _, a := range args { - in.addArg(a) +func (in *RunDetails) AddMemoryOption(arg string) { + if arg != "" { + in.memoryArgs = append(in.memoryArgs, in.ExpandEnv(arg)) } } -func (in *RunDetails) addArg(arg string) { +func (in *RunDetails) AddDiagnosticOption(arg string) { if arg != "" { - in.Args = append(in.Args, in.ExpandEnv(arg)) + in.diagnosticArgs = append(in.diagnosticArgs, in.ExpandEnv(arg)) } } -func (in *RunDetails) addToFrontOfClasspath(path string) { +func (in *RunDetails) AddToFrontOfClasspath(path string) { if path != "" { if in.Classpath == "" { in.Classpath = in.ExpandEnv(path) @@ -300,7 +339,7 @@ func (in *RunDetails) addToFrontOfClasspath(path string) { } // addJarsToClasspath adds all jars in the specified directory to the classpath -func (in *RunDetails) addJarsToClasspath(dir string) { +func (in *RunDetails) AddJarsToClasspath(dir string) { path := in.ExpandEnv(dir) if _, err := os.Stat(path); err == nil { var jars []string @@ -312,20 +351,19 @@ func (in *RunDetails) addJarsToClasspath(dir string) { return nil }) - sort.Strings(jars) for _, jar := range jars { - in.addClasspath(jar) + in.AddClasspath(jar) } } } -func (in *RunDetails) addClasspathIfExists(path string) { +func (in *RunDetails) AddClasspathIfExists(path string) { if _, err := os.Stat(path); err == nil { - in.addClasspath(path) + in.AddClasspath(path) } } -func (in *RunDetails) addClasspath(path string) { +func (in *RunDetails) AddClasspath(path string) { if path != "" { if in.Classpath == "" { in.Classpath = in.ExpandEnv(path) @@ -335,80 +373,92 @@ func (in *RunDetails) addClasspath(path string) { } } -func (in *RunDetails) getClasspath() string { +func (in *RunDetails) GetClasspath() string { cp := in.Classpath // if ${COHERENCE_HOME} exists add coherence.jar to the classpath if in.CoherenceHome != "" { if _, err := os.Stat(in.CoherenceHome); err == nil { if _, err := os.Stat(in.CoherenceHome + "/conf"); err == nil { - cp = cp + ":" + in.CoherenceHome + "/conf" + cp += ":" + in.CoherenceHome + "/conf" } if _, err := os.Stat(in.CoherenceHome + "/lib/coherence.jar"); err == nil { - cp = cp + ":" + in.CoherenceHome + "/lib/coherence.jar" + cp += ":" + in.CoherenceHome + "/lib/coherence.jar" } } } return cp } -func (in *RunDetails) addArgFromEnvVar(name, property string) { +func (in *RunDetails) AddArgFromEnvVar(name, property string) { value := in.Getenv(name) if value != "" { s := fmt.Sprintf("%s=%s", property, value) - in.Args = append(in.Args, s) + in.AddArg(s) + } +} + +func (in *RunDetails) AddSystemPropertyFromEnvVar(name, property string) { + value := in.Getenv(name) + if value != "" { + in.AddSystemPropertyArg(property, value) } } -func (in *RunDetails) setSystemPropertyFromEnvVarOrDefault(name, property, dflt string) { +func (in *RunDetails) SetSystemPropertyFromEnvVarOrDefault(name, property, dflt string) { value := in.Getenv(name) - var s string if value != "" { - s = fmt.Sprintf("%s=%s", property, value) + in.AddSystemPropertyArg(property, value) } else { - s = fmt.Sprintf("%s=%s", property, dflt) + in.AddSystemPropertyArg(property, dflt) } - in.Args = append(in.Args, s) } -func (in *RunDetails) getJavaExecutable() string { +func (in *RunDetails) GetJavaExecutable() string { if in.JavaHome != "" { return in.JavaHome + "/bin/java" } return "java" } -func (in *RunDetails) getJShellExecutable() string { +func (in *RunDetails) GetJShellExecutable() string { if in.JavaHome != "" { return in.JavaHome + "/bin/jshell" } return "jshell" } -// isBuildPacks determines whether to run the application with the Cloud Native Buildpack launcher -func (in *RunDetails) isBuildPacks() bool { +// IsBuildPacks determines whether to run the application with the Cloud Native Buildpack launcher +func (in *RunDetails) IsBuildPacks() bool { if in.BuildPacks == nil { var bp bool detect := strings.ToLower(in.env.GetString(v1.EnvVarCnbpEnabled)) switch detect { case "true": - log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) + in.log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) bp = true case "false": - log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) + in.log.Info("Detecting Cloud Native Buildpacks", "envVar", v1.EnvVarCnbpEnabled, "value", detect) bp = false default: - log.Info("Auto-detecting Cloud Native Buildpacks") + in.log.Info("Auto-detecting Cloud Native Buildpacks") // else auto detect // look for the CNB API environment variable _, ok := os.LookupEnv("CNB_PLATFORM_API") - log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB_PLATFORM_API found=%t", ok)) + in.log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB_PLATFORM_API found=%t", ok)) // look for the CNB launcher - launcher := getBuildpackLauncher() + launcher := GetBuildpackLauncher() _, err := os.Stat(launcher) - log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB Launcher '%s' found=%t\n", launcher, err == nil)) + in.log.Info(fmt.Sprintf("Auto-detecting Cloud Native Buildpacks: CNB Launcher '%s' found=%t\n", launcher, err == nil)) bp = ok && err == nil } in.BuildPacks = &bp } return *in.BuildPacks } + +func GetBuildpackLauncher() string { + if launcher, ok := os.LookupEnv(v1.EnvVarCnbpLauncher); ok { + return launcher + } + return v1.DefaultCnbpLauncher +} diff --git a/pkg/runner/rundetails_test.go b/pkg/runner/run_details/rundetails_test.go similarity index 63% rename from pkg/runner/rundetails_test.go rename to pkg/runner/run_details/rundetails_test.go index 3681d9f86..342268892 100644 --- a/pkg/runner/rundetails_test.go +++ b/pkg/runner/run_details/rundetails_test.go @@ -1,17 +1,22 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -package runner +package run_details import ( . "github.com/onsi/gomega" "github.com/spf13/viper" + ctrl "sigs.k8s.io/controller-runtime" "testing" ) +var ( + testLog = ctrl.Log.WithName("test") +) + func TestRunDetailsGetenvWhenMissing(t *testing.T) { g := NewGomegaWithT(t) @@ -25,15 +30,15 @@ func TestRunDetailsGetenvWhenPresent(t *testing.T) { v := viper.New() v.Set("foo", "bar") - r := NewRunDetails(v) + r := NewRunDetails(v, testLog) g.Expect(r.Getenv("foo")).To(Equal("bar")) } func TestRunDetailsGetenvWithPrefixWhenMissing(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - g.Expect(r.getenvWithPrefix("foo", "_test")).To(Equal("")) + r := NewRunDetails(viper.New(), testLog) + g.Expect(r.GetenvWithPrefix("foo", "_test")).To(Equal("")) } func TestRunDetailsGetenvWithPrefixWhenPresent(t *testing.T) { @@ -42,15 +47,15 @@ func TestRunDetailsGetenvWithPrefixWhenPresent(t *testing.T) { v := viper.New() v.Set("foo_test", "bar") - r := NewRunDetails(v) - g.Expect(r.getenvWithPrefix("foo", "_test")).To(Equal("bar")) + r := NewRunDetails(v, testLog) + g.Expect(r.GetenvWithPrefix("foo", "_test")).To(Equal("bar")) } func TestRunDetailsAddClasspath(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") g.Expect(r.Classpath).To(Equal("foo")) } @@ -60,88 +65,88 @@ func TestRunDetailsAddClasspathWithExpansion(t *testing.T) { v := viper.New() v.Set("FOO", "foo-value") - r := NewRunDetails(v) + r := NewRunDetails(v, testLog) - r.addClasspath("${FOO}") + r.AddClasspath("${FOO}") g.Expect(r.Classpath).To(Equal("foo-value")) } func TestRunDetailsAddClasspathMultipleTimes(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") - r.addClasspath("bar") + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") + r.AddClasspath("bar") g.Expect(r.Classpath).To(Equal("foo:bar")) } func TestRunDetailsAddClasspathEmptyString(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") - r.addClasspath("") + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") + r.AddClasspath("") g.Expect(r.Classpath).To(Equal("foo")) } func TestRunDetailsAddToFrontClasspath(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.Classpath = "foo" - r.addToFrontOfClasspath("bar") + r.AddToFrontOfClasspath("bar") g.Expect(r.Classpath).To(Equal("bar:foo")) } func TestRunDetailsAddToFrontClasspathMultipleTimes(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.Classpath = "foo" - r.addToFrontOfClasspath("bar1") - r.addToFrontOfClasspath("bar2") + r.AddToFrontOfClasspath("bar1") + r.AddToFrontOfClasspath("bar2") g.Expect(r.Classpath).To(Equal("bar2:bar1:foo")) } func TestRunDetailsAddToFrontOfClasspathEmptyString(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.Classpath = "foo" - r.addToFrontOfClasspath("") + r.AddToFrontOfClasspath("") g.Expect(r.Classpath).To(Equal("foo")) } func TestRunDetailsGetClasspath(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - r.addClasspath("foo") - g.Expect(r.getClasspath()).To(Equal("foo")) + r := NewRunDetails(viper.New(), testLog) + r.AddClasspath("foo") + g.Expect(r.GetClasspath()).To(Equal("foo")) } func TestRunDetailsGetJavaEmpty(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) - g.Expect(r.getJavaExecutable()).To(Equal("java")) + r := NewRunDetails(viper.New(), testLog) + g.Expect(r.GetJavaExecutable()).To(Equal("java")) } func TestRunDetailsGetJavaWhenJavaHomeSet(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) r.JavaHome = "/local/bin/jdk11" - g.Expect(r.getJavaExecutable()).To(Equal("/local/bin/jdk11/bin/java")) + g.Expect(r.GetJavaExecutable()).To(Equal("/local/bin/jdk11/bin/java")) } func TestRunDetailsGetCommandWhenEmpty(t *testing.T) { g := NewGomegaWithT(t) - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) var expected []string - g.Expect(r.getCommand()).To(Equal(expected)) + g.Expect(r.GetCommand()).To(Equal(expected)) } func TestExpandEnv(t *testing.T) { @@ -152,7 +157,7 @@ func TestExpandEnv(t *testing.T) { env["B"] = "value-b" env["C"] = "value-c" - r := NewRunDetails(viper.New()) + r := NewRunDetails(viper.New(), testLog) result := r.Expand("$(A) ${B} $C", func(s string) string { return env[s] }) diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index fda98ed68..4ad08cf58 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -14,6 +14,7 @@ import ( "github.com/go-logr/logr" v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/pkg/operator" + "github.com/oracle/coherence-operator/pkg/runner/run_details" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -34,40 +35,6 @@ import ( // The code that actually starts the process in the Coherence container. const ( - // DefaultMain is an indicator to run the default main class. - DefaultMain = "$DEFAULT$" - // HelidonMain is the default Helidon main class name. - HelidonMain = "io.helidon.microprofile.cdi.Main" - // ServerMain is the default server main class name. - ServerMain = "com.oracle.coherence.k8s.Main" - // SpringBootMain2 is the default Spring Boot 2.x main class name. - SpringBootMain2 = "org.springframework.boot.loader.PropertiesLauncher" - // SpringBootMain3 is the default Spring Boot 3.x main class name. - SpringBootMain3 = "org.springframework.boot.loader.launch.PropertiesLauncher" - // ConsoleMain is the Coherence console main class - ConsoleMain = "com.tangosol.net.CacheFactory" - // QueryPlusMain is the main class to run Coherence Query Plus - QueryPlusMain = "com.tangosol.coherence.dslquery.QueryPlus" - // JShellMain is the main class to run a JShell console - JShellMain = "jdk.internal.jshell.tool.JShellToolProvider" - - // AppTypeNone is the argument to specify no application type. - AppTypeNone = "" - // AppTypeJava is the argument to specify a Java application. - AppTypeJava = "java" - // AppTypeCoherence is the argument to specify a Coherence application. - AppTypeCoherence = "coherence" - // AppTypeHelidon is the argument to specify a Helidon application. - AppTypeHelidon = "helidon" - // AppTypeSpring2 is the argument to specify an exploded Spring Boot 2.x application. - AppTypeSpring2 = "spring" - // AppTypeSpring3 is the argument to specify an exploded Spring Boot 3.x application. - AppTypeSpring3 = "spring3" - // AppTypeOperator is the argument to specify running an Operator command. - AppTypeOperator = "operator" - // AppTypeJShell is the argument to specify a JShell application. - AppTypeJShell = "jshell" - // defaultConfig is the root name of the default configuration file defaultConfig = ".coherence-runner" ) @@ -129,6 +96,7 @@ func NewRootCommand(env map[string]string, v *viper.Viper) *cobra.Command { rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") rootCmd.AddCommand(initCommand(env)) + rootCmd.AddCommand(configCommand(env)) rootCmd.AddCommand(serverCommand()) rootCmd.AddCommand(consoleCommand(v)) rootCmd.AddCommand(queryPlusCommand(v)) @@ -220,7 +188,11 @@ func Execute() (Execution, error) { // ExecuteWithArgsAndNewViper runs the runner with a given environment and argument overrides. func ExecuteWithArgsAndNewViper(env map[string]string, args []string) (Execution, error) { - return ExecuteWithArgsAndViper(env, args, viper.New()) + v := viper.New() + for key, value := range env { + v.SetDefault(key, value) + } + return ExecuteWithArgsAndViper(env, args, v) } // ExecuteWithArgsAndViper runs the runner with a given environment and argument overrides. @@ -242,10 +214,10 @@ func ExecuteWithArgsAndViper(env map[string]string, args []string, v *viper.Vipe } // RunFunction is a function to run a command -type RunFunction func(*RunDetails, *cobra.Command) +type RunFunction func(*run_details.RunDetails, *cobra.Command) // MaybeRunFunction is a function to maybe run a command depending on the return bool -type MaybeRunFunction func(*RunDetails, *cobra.Command) (bool, error) +type MaybeRunFunction func(*run_details.RunDetails, *cobra.Command) (bool, error) // always is a wrapper around a RunFunction to turn it into a MaybeFunction that always runs type always struct { @@ -253,7 +225,7 @@ type always struct { } // run will wrap a RunFunction and always return true -func (in always) run(details *RunDetails, cmd *cobra.Command) (bool, error) { +func (in always) run(details *run_details.RunDetails, cmd *cobra.Command) (bool, error) { in.Fn(details, cmd) return true, nil } @@ -269,7 +241,7 @@ func maybeRun(cmd *cobra.Command, fn MaybeRunFunction) error { var err error e := fromContext(cmd.Context()) - details := NewRunDetails(e.V) + details := run_details.NewRunDetails(e.V, log) runCommand, err := fn(details, cmd) if err != nil { return err @@ -311,82 +283,83 @@ func fromContext(ctx context.Context) *Execution { return &Execution{} } -// create the process to execute. -func createCommand(details *RunDetails) (string, *exec.Cmd, error) { +// configure the command details. +func configureCommand(details *run_details.RunDetails) error { var err error // Set standard system properties - details.addArgFromEnvVar(v1.EnvVarCohWka, "-Dcoherence.wka") - details.addArgFromEnvVar(v1.EnvVarCohMachineName, "-Dcoherence.machine") - details.addArgFromEnvVar(v1.EnvVarCohMemberName, "-Dcoherence.member") - details.addArgFromEnvVar(v1.EnvVarCohClusterName, "-Dcoherence.cluster") - details.addArgFromEnvVar(v1.EnvVarCohCacheConfig, "-Dcoherence.cacheconfig") - details.addArgFromEnvVar(v1.EnvVarCohIdentity, "-Dcoherence.k8s.operator.identity") - details.addArgFromEnvVar(v1.EnvVarCohForceExit, "-Dcoherence.k8s.operator.force.exit") - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.k8s.operator.health.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.management.http.port", fmt.Sprintf("%d", v1.DefaultManagementPort)) - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, "-Dcoherence.metrics.http.port", fmt.Sprintf("%d", v1.DefaultMetricsPort)) - - details.addArg("-XX:+UnlockDiagnosticVMOptions") + details.AddSystemPropertyArg(v1.SysPropCoherenceTTL, "0") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohWka, v1.SysPropCoherenceWKA) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohMachineName, v1.SysPropCoherenceMachine) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohMemberName, v1.SysPropCoherenceMember) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohClusterName, v1.SysPropCoherenceCluster) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohCacheConfig, v1.SysPropCoherenceCacheConfig) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohIdentity, v1.SysPropOperatorIdentity) + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohForceExit, v1.SysPropOperatorForceExit) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, v1.SysPropOperatorHealthPort, fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMgmtPrefix+v1.EnvVarCohPortSuffix, v1.SysPropCoherenceManagementHttpPort, fmt.Sprintf("%d", v1.DefaultManagementPort)) + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohMetricsPrefix+v1.EnvVarCohPortSuffix, v1.SysPropCoherenceMetricsHttpPort, fmt.Sprintf("%d", v1.DefaultMetricsPort)) + + details.AddVMOption(v1.JvmOptUnlockDiagnosticVMOptions) // Configure the classpath to support images created with the JIB Maven plugin // This is enabled by default unless the image is a buildpacks image, or we // are running a Spring Boot application. - if !details.isBuildPacks() && !details.IsSpringBoot() && details.isEnvTrueOrBlank(v1.EnvVarJvmClasspathJib) { - appDir := details.getenvOrDefault(v1.EnvVarCohAppDir, "/app") + if !details.IsBuildPacks() && !details.IsSpringBoot() && details.IsEnvTrueOrBlank(v1.EnvVarJvmClasspathJib) { + appDir := details.GetenvOrDefault(v1.EnvVarCohAppDir, "/app") cpFile := filepath.Join(appDir, "jib-classpath-file") fi, e := os.Stat(cpFile) + if e != nil && appDir != "/app" { + // try in /app + cpFile = "/app/jib-classpath-file" + fi, e = os.Stat(cpFile) + } + if e == nil && (fi.Size() != 0) { clsPath, _ := readFirstLineFromFile(cpFile) if len(clsPath) != 0 { - details.addClasspath(clsPath) + details.AddClasspath(clsPath) } } else { - details.addClasspathIfExists(appDir + "/resources") - details.addClasspathIfExists(appDir + "/classes") - details.addJarsToClasspath(appDir + "/classpath") - details.addJarsToClasspath(appDir + "/libs") + details.AddClasspathIfExists(appDir + "/resources") + details.AddClasspathIfExists(appDir + "/classes") + details.AddJarsToClasspath(appDir + "/classpath") + details.AddJarsToClasspath(appDir + "/libs") } } // Add the Operator Utils jar to the classpath - details.addClasspath(details.UtilsDir + "/lib/coherence-operator.jar") - details.addClasspathIfExists(details.UtilsDir + "/config") + details.AddClasspath(details.UtilsDir + v1.OperatorJarFileSuffix) + details.AddClasspathIfExists(details.UtilsDir + v1.OperatorConfigDirSuffix) // Configure Coherence persistence - mode := details.getenvOrDefault(v1.EnvVarCohPersistenceMode, "on-demand") - details.addArg("-Dcoherence.distributed.persistence-mode=" + mode) + mode := details.GetenvOrDefault(v1.EnvVarCohPersistenceMode, "on-demand") + details.AddSystemPropertyArg(v1.SysPropCoherencePersistenceMode, mode) persistence := details.Getenv(v1.EnvVarCohPersistenceDir) if persistence != "" { - details.addArg("-Dcoherence.distributed.persistence.base.dir=" + persistence) + details.AddSystemPropertyArg(v1.SysPropCoherencePersistenceBaseDir, persistence) } snapshots := details.Getenv(v1.EnvVarCohSnapshotDir) if snapshots != "" { - details.addArg("-Dcoherence.distributed.persistence.snapshot.dir=" + snapshots) + details.AddSystemPropertyArg(v1.SysPropCoherencePersistenceSnapshotDir, snapshots) } // Set the Coherence site and rack values configureSiteAndRack(details) // Set the Coherence log level - details.addArgFromEnvVar(v1.EnvVarCohLogLevel, "-Dcoherence.log.level") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohLogLevel, v1.SysPropCoherenceLogLevel) // Disable IPMonitor ipMon := details.Getenv(v1.EnvVarEnableIPMonitor) if ipMon != "TRUE" { - details.addArg("-Dcoherence.ipmonitor.pingtimeout=0") + details.AddSystemPropertyArg(v1.SysPropCoherenceIpMonitor, "0") } - // Do the Coherence version specific configuration - if ok := checkCoherenceVersion("12.2.1.4.0", details); ok { - // is at least 12.2.1.4 - cohPost12214(details) - } else { - // is at pre-12.2.1.4 - cohPre12214(details) - } + details.AddSystemPropertyArg(v1.SysPropCoherenceOverride, "k8s-coherence-override.xml") + details.AddSystemPropertyFromEnvVar(v1.EnvVarCohOverride, v1.SysPropOperatorOverride) post2206 := checkCoherenceVersion("14.1.1.2206.0", details) if post2206 { @@ -414,7 +387,7 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { allowEndangered := details.Getenv(v1.EnvVarCohAllowEndangered) if allowEndangered != "" { - details.addArg("-Dcoherence.k8s.operator.statusha.allowendangered=" + allowEndangered) + details.AddArg("-Dcoherence.operator.statusha.allowendangered=" + allowEndangered) } // Get the K8s Pod UID @@ -427,59 +400,59 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { jvmDir := v1.VolumeMountPathJVM + "/" + member + "/" + podUID if _, err = os.Stat(v1.VolumeMountPathJVM); err == nil { if err = os.MkdirAll(jvmDir, os.ModePerm); err != nil { - return "", nil, err + return err } if err = os.MkdirAll(jvmDir+"/jfr", os.ModePerm); err != nil { - return "", nil, err + return err } if err = os.MkdirAll(jvmDir+"/heap-dumps", os.ModePerm); err != nil { - return "", nil, err + return err } } - details.addArg(fmt.Sprintf("-Dcoherence.k8s.operator.diagnostics.dir=%s", jvmDir)) - details.addArg(fmt.Sprintf("-XX:HeapDumpPath=%s/heap-dumps/%s-%s.hprof", jvmDir, member, podUID)) + details.AddArg(fmt.Sprintf("-Dcoherence.operator.diagnostics.dir=%s", jvmDir)) + details.AddVMOption(fmt.Sprintf("-XX:HeapDumpPath=%s/heap-dumps/%s-%s.hprof", jvmDir, member, podUID)) // set the flag that allows the operator to resume suspended services on start-up - if !details.isEnvTrueOrBlank(v1.EnvVarOperatorAllowResume) { - details.addArg("-Dcoherence.k8s.operator.can.resume.services=false") + if !details.IsEnvTrueOrBlank(v1.EnvVarOperatorAllowResume) { + details.AddArg("-Dcoherence.operator.can.resume.services=false") } else { - details.addArg("-Dcoherence.k8s.operator.can.resume.services=true") + details.AddArg("-Dcoherence.operator.can.resume.services=true") } if svc := details.Getenv(v1.EnvVarOperatorResumeServices); svc != "" { - details.addArg("-Dcoherence.k8s.operator.resume.services=base64:" + svc) + details.AddArg("-Dcoherence.operator.resume.services=base64:" + svc) } gc := strings.ToLower(details.Getenv(v1.EnvVarJvmGcCollector)) switch { case gc == "" || gc == "g1": - details.addArg("-XX:+UseG1GC") + details.AddMemoryOption("-XX:+UseG1GC") case gc == "cms": - details.addArg("-XX:+UseConcMarkSweepGC") + details.AddMemoryOption("-XX:+UseConcMarkSweepGC") case gc == "parallel": - details.addArg("-XX:+UseParallelGC") + details.AddMemoryOption("-XX:+UseParallelGC") } maxRAM := details.Getenv(v1.EnvVarJvmMaxRAM) if maxRAM != "" { - details.addArg("-XX:MaxRAM=" + maxRAM) + details.AddMemoryOption("-XX:MaxRAM=" + maxRAM) } heap := details.Getenv(v1.EnvVarJvmMemoryHeap) if heap != "" { // if heap is set use it - details.addArg("-XX:InitialHeapSize=" + heap) - details.addArg("-XX:MaxHeapSize=" + heap) + details.AddMemoryOption("-XX:InitialHeapSize=" + heap) + details.AddMemoryOption("-XX:MaxHeapSize=" + heap) } else { // if heap is not set check whether the individual heap values are set initialHeap := details.Getenv(v1.EnvVarJvmMemoryInitialHeap) if initialHeap != "" { - details.addArg("-XX:InitialHeapSize=" + initialHeap) + details.AddMemoryOption("-XX:InitialHeapSize=" + initialHeap) } maxHeap := details.Getenv(v1.EnvVarJvmMemoryMaxHeap) if maxHeap != "" { - details.addArg("-XX:MaxHeapSize=" + maxHeap) + details.AddMemoryOption("-XX:MaxHeapSize=" + maxHeap) } } @@ -489,9 +462,9 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { q, err := resource.ParseQuantity(percentageHeap) if err == nil { d := q.AsDec() - details.addArg("-XX:InitialRAMPercentage=" + d.String()) - details.addArg("-XX:MinRAMPercentage=" + d.String()) - details.addArg("-XX:MaxRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:InitialRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MinRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MaxRAMPercentage=" + d.String()) } else { log.Info("ERROR: Heap Percentage is not a valid resource.Quantity", "Value", percentageHeap, "Error", err.Error()) os.Exit(1) @@ -503,7 +476,7 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { q, err := resource.ParseQuantity(initial) if err == nil { d := q.AsDec() - details.addArg("-XX:InitialRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:InitialRAMPercentage=" + d.String()) } else { log.Info("ERROR: InitialRAMPercentage is not a valid resource.Quantity", "Value", initial, "Error", err.Error()) os.Exit(1) @@ -515,7 +488,7 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { q, err := resource.ParseQuantity(maxRam) if err == nil { d := q.AsDec() - details.addArg("-XX:MaxRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MaxRAMPercentage=" + d.String()) } else { log.Info("ERROR: MaxRAMPercentage is not a valid resource.Quantity", "Value", maxRam, "Error", err.Error()) os.Exit(1) @@ -527,7 +500,7 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { q, err := resource.ParseQuantity(minRam) if err == nil { d := q.AsDec() - details.addArg("-XX:MinRAMPercentage=" + d.String()) + details.AddMemoryOption("-XX:MinRAMPercentage=" + d.String()) } else { log.Info("ERROR: MinRAMPercentage is not a valid resource.Quantity", "Value", minRam, "Error", err.Error()) os.Exit(1) @@ -537,28 +510,28 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { direct := details.Getenv(v1.EnvVarJvmMemoryDirect) if direct != "" { - details.addArg("-XX:MaxDirectMemorySize=" + direct) + details.AddMemoryOption("-XX:MaxDirectMemorySize=" + direct) } stack := details.Getenv(v1.EnvVarJvmMemoryStack) if stack != "" { - details.addArg("-Xss" + stack) + details.AddMemoryOption("-Xss" + stack) } meta := details.Getenv(v1.EnvVarJvmMemoryMeta) if meta != "" { - details.addArg("-XX:MetaspaceSize=" + meta) - details.addArg("-XX:MaxMetaspaceSize=" + meta) + details.AddMemoryOption("-XX:MetaspaceSize=" + meta) + details.AddMemoryOption("-XX:MaxMetaspaceSize=" + meta) } - track := details.getenvOrDefault(v1.EnvVarJvmMemoryNativeTracking, "summary") + track := details.GetenvOrDefault(v1.EnvVarJvmMemoryNativeTracking, "summary") if track != "" { - details.addArg("-XX:NativeMemoryTracking=" + track) - details.addArg("-XX:+PrintNMTStatistics") + details.AddDiagnosticOption("-XX:NativeMemoryTracking=" + track) + details.AddDiagnosticOption("-XX:+PrintNMTStatistics") } // Configure debugging debugArgs := "" - if details.isEnvTrue(v1.EnvVarJvmDebugEnabled) { + if details.IsEnvTrue(v1.EnvVarJvmDebugEnabled) { var suspend string - if details.isEnvTrue(v1.EnvVarJvmDebugSuspended) { + if details.IsEnvTrue(v1.EnvVarJvmDebugSuspended) { suspend = "y" } else { suspend = "n" @@ -577,59 +550,64 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { } } - details.addArg("-Dcoherence.ttl=0") - - details.addArg(fmt.Sprintf("-XX:ErrorFile=%s/hs-err-%s-%s.log", jvmDir, member, podUID)) + details.AddVMOption(fmt.Sprintf("-XX:ErrorFile=%s/hs-err-%s-%s.log", jvmDir, member, podUID)) - if details.isEnvTrueOrBlank(v1.EnvVarJvmOomHeapDump) { - details.addArg("-XX:+HeapDumpOnOutOfMemoryError") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmOomHeapDump) { + details.AddVMOption("-XX:+HeapDumpOnOutOfMemoryError") } - if details.isEnvTrueOrBlank(v1.EnvVarJvmOomExit) { - details.addArg("-XX:+ExitOnOutOfMemoryError") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmOomExit) { + details.AddVMOption("-XX:+ExitOnOutOfMemoryError") } // Use JVM container support - if details.isEnvTrueOrBlank(v1.EnvVarJvmUseContainerLimits) { - details.addArg("-XX:+UseContainerSupport") + if details.IsEnvTrueOrBlank(v1.EnvVarJvmUseContainerLimits) { + details.AddVMOption("-XX:+UseContainerSupport") } - details.addArgs(debugArgs) + details.AddArgs(debugArgs) gcArgs := details.Getenv(v1.EnvVarJvmGcArgs) if gcArgs != "" { - details.addArgs(strings.Split(gcArgs, " ")...) + details.AddArgs(strings.Split(gcArgs, " ")...) } jvmArgs := details.Getenv(v1.EnvVarJvmArgs) if jvmArgs != "" { - details.addArgs(strings.Split(jvmArgs, " ")...) + details.AddArgs(strings.Split(jvmArgs, " ")...) } extraJvmArgs := operator.GetExtraJvmArgs() if extraJvmArgs != nil { - details.addArgs(extraJvmArgs...) + details.AddArgs(extraJvmArgs...) } + return nil +} + +// create the process to execute. +func createCommand(details *run_details.RunDetails) (string, *exec.Cmd, error) { + var err error var cmd *exec.Cmd var app string + switch { - case details.AppType == AppTypeNone || details.AppType == AppTypeJava: + case details.AppType == v1.AppTypeNone || details.AppType == v1.AppTypeJava: app = "Java" - cmd, err = createJavaCommand(details.getJavaExecutable(), details) + cmd, err = createJavaCommand(details.GetJavaExecutable(), details) case details.IsSpringBoot(): app = "SpringBoot" - cmd, err = createSpringBootCommand(details.getJavaExecutable(), details) - case details.AppType == AppTypeHelidon: + cmd, err = createSpringBootCommand(details.GetJavaExecutable(), details) + case details.AppType == v1.AppTypeHelidon: app = "Java" - cmd, err = createJavaCommand(details.getJavaExecutable(), details) - case details.AppType == AppTypeCoherence: + cmd, err = createJavaCommand(details.GetJavaExecutable(), details) + case details.AppType == v1.AppTypeCoherence: app = "Java" - cmd, err = createJavaCommand(details.getJavaExecutable(), details) - case details.AppType == AppTypeJShell: + cmd, err = createJavaCommand(details.GetJavaExecutable(), details) + case details.AppType == v1.AppTypeJShell: app = "JShell" - cmd, err = createJShellCommand(details.getJShellExecutable(), details) - case details.AppType == AppTypeOperator: + cmd, err = createJShellCommand(details.GetJShellExecutable(), details) + case details.AppType == v1.AppTypeOperator: app = "Operator" cmd, err = createOperatorCommand(details) default: @@ -645,14 +623,14 @@ func createCommand(details *RunDetails) (string, *exec.Cmd, error) { return app, cmd, err } -func createJavaCommand(javaCmd string, details *RunDetails) (*exec.Cmd, error) { - args := details.getCommand() +func createJavaCommand(javaCmd string, details *run_details.RunDetails) (*exec.Cmd, error) { + args := details.GetCommand() args = append(args, details.MainClass) return _createJavaCommand(javaCmd, details, args) } -func createJShellCommand(jshellCmd string, details *RunDetails) (*exec.Cmd, error) { - args := details.getCommandWithPrefix("-R", "-J") +func createJShellCommand(jshellCmd string, details *run_details.RunDetails) (*exec.Cmd, error) { + args := details.GetCommandWithPrefix("-R", "-J") return _createJavaCommand(jshellCmd, details, args) } @@ -675,18 +653,18 @@ func readFirstLineFromFile(path string) (string, error) { return text[0], nil } -func createSpringBootCommand(javaCmd string, details *RunDetails) (*exec.Cmd, error) { - if details.isBuildPacks() { - if details.AppType == AppTypeSpring2 { - return _createBuildPackCommand(details, SpringBootMain2, details.getSpringBootArgs()) +func createSpringBootCommand(javaCmd string, details *run_details.RunDetails) (*exec.Cmd, error) { + if details.IsBuildPacks() { + if details.AppType == v1.AppTypeSpring2 { + return _createBuildPackCommand(details, v1.SpringBootMain2, details.GetSpringBootArgs()) } - return _createBuildPackCommand(details, SpringBootMain3, details.getSpringBootArgs()) + return _createBuildPackCommand(details, v1.SpringBootMain3, details.GetSpringBootArgs()) } - args := details.getSpringBootCommand() + args := details.GetSpringBootCommand() return _createJavaCommand(javaCmd, details, args) } -func _createJavaCommand(javaCmd string, details *RunDetails, args []string) (*exec.Cmd, error) { +func _createJavaCommand(javaCmd string, details *run_details.RunDetails, args []string) (*exec.Cmd, error) { args = append(args, details.MainArgs...) cmd := exec.Command(javaCmd, args...) cmd.Stdout = os.Stdout @@ -704,7 +682,7 @@ func _createJavaCommand(javaCmd string, details *RunDetails, args []string) (*ex return cmd, nil } -func createOperatorCommand(details *RunDetails) (*exec.Cmd, error) { +func createOperatorCommand(details *run_details.RunDetails) (*exec.Cmd, error) { executable := os.Args[0] args := details.MainArgs[1:] cmd := exec.Command(executable, args...) @@ -723,8 +701,8 @@ func createOperatorCommand(details *RunDetails) (*exec.Cmd, error) { return cmd, nil } -func _createBuildPackCommand(_ *RunDetails, className string, args []string) (*exec.Cmd, error) { - launcher := getBuildpackLauncher() +func _createBuildPackCommand(_ *run_details.RunDetails, className string, args []string) (*exec.Cmd, error) { + launcher := run_details.GetBuildpackLauncher() // Create the JVM arguments file argsFile, err := os.CreateTemp("", "jvm-args") @@ -748,17 +726,10 @@ func _createBuildPackCommand(_ *RunDetails, className string, args []string) (*e return cmd, nil } -func getBuildpackLauncher() string { - if launcher, ok := os.LookupEnv(v1.EnvVarCnbpLauncher); ok { - return launcher - } - return v1.DefaultCnbpLauncher -} - -func createGraalCommand(details *RunDetails) (*exec.Cmd, error) { +func createGraalCommand(details *run_details.RunDetails) (*exec.Cmd, error) { ex := details.AppType args := []string{"--polyglot", "--jvm"} - args = append(args, details.getCommand()...) + args = append(args, details.GetCommand()...) args = append(args, details.MainClass) args = append(args, details.MainArgs...) @@ -779,7 +750,7 @@ func createGraalCommand(details *RunDetails) (*exec.Cmd, error) { } // Set the Coherence site and rack values -func configureSiteAndRack(details *RunDetails) { +func configureSiteAndRack(details *run_details.RunDetails) { var err error if !details.GetSite { return @@ -810,7 +781,7 @@ func configureSiteAndRack(details *RunDetails) { } if site != "" { - details.addArg("-Dcoherence.site=" + site) + details.AddSystemPropertyArg(v1.SysPropCoherenceSite, site) } } else { expanded := details.ExpandEnv(site) @@ -818,10 +789,10 @@ func configureSiteAndRack(details *RunDetails) { log.Info("Coherence site property set from expanded "+v1.EnvVarCoherenceSite+" environment variable", v1.EnvVarCoherenceSite, site, "Site", expanded) site = expanded if strings.TrimSpace(site) != "" { - details.addArg("-Dcoherence.site=" + site) + details.AddSystemPropertyArg(v1.SysPropCoherenceSite, site) } } else { - log.Info("Coherence site property not set as "+v1.EnvVarCoherenceSite+" environment variable is set", "Site", site) + details.AddSystemPropertyArg(v1.SysPropCoherenceSite, site) } } @@ -848,9 +819,9 @@ func configureSiteAndRack(details *RunDetails) { } if rack != "" { - details.addArg("-Dcoherence.rack=" + rack) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, rack) } else if site != "" { - details.addArg("-Dcoherence.rack=" + site) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, site) } } else { expanded := details.ExpandEnv(rack) @@ -863,10 +834,10 @@ func configureSiteAndRack(details *RunDetails) { rack = site } if strings.TrimSpace(rack) != "" { - details.addArg("-Dcoherence.rack=" + rack) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, rack) } } else { - log.Info("Coherence rack property not set as "+v1.EnvVarCoherenceRack+" environment variable is set", "Rack", rack) + details.AddSystemPropertyArg(v1.SysPropCoherenceRack, rack) } } } @@ -879,7 +850,7 @@ func maybeStripFileScheme(uri string) string { } // httpGetWithBackoff does a http get for the specified url with retry back-off for errors. -func httpGetWithBackoff(url string, details *RunDetails) string { +func httpGetWithBackoff(url string, details *run_details.RunDetails) string { var backoff time.Duration timeout := 120 @@ -973,28 +944,28 @@ func httpGet(urlString string, client http.Client) (string, int, error) { return s, resp.StatusCode, nil } -func checkCoherenceVersion(v string, details *RunDetails) bool { +func checkCoherenceVersion(v string, details *run_details.RunDetails) bool { log.Info("Performing Coherence version check", "version", v) - if details.isEnvTrue(v1.EnvVarCohSkipVersionCheck) { + if details.IsEnvTrue(v1.EnvVarCohSkipVersionCheck) { log.Info("Skipping Coherence version check", "envVar", v1.EnvVarCohSkipVersionCheck, "value", details.Getenv(v1.EnvVarCohSkipVersionCheck)) return true } // Get the classpath to use (we need Coherence jar) - cp := details.getClasspath() + cp := details.GetClasspath() var exe string var cmd *exec.Cmd var args []string - if details.isBuildPacks() { + if details.IsBuildPacks() { // This is a build-packs image so use the Build-packs launcher to run Java - exe = getBuildpackLauncher() + exe = run_details.GetBuildpackLauncher() args = []string{exe} } else { // this should be a normal image with Java available - exe = details.getJavaExecutable() + exe = details.GetJavaExecutable() } if details.IsSpringBoot() { @@ -1004,21 +975,21 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { "-Dcoherence.operator.springboot.listener=false", "-Dloader.main=com.oracle.coherence.k8s.CoherenceVersion") - if jar, _ := details.lookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { + if jar, _ := details.LookupEnv(v1.EnvVarSpringBootFatJar); jar != "" { // This is a fat jar Spring boot app so put the fat jar on the classpath - args = append(args, "--class-path", jar) + args = append(args, v1.JvmOptClassPath, jar) } - if details.AppType == AppTypeSpring2 { + if details.AppType == v1.AppTypeSpring2 { // we are running SpringBoot 2.x - args = append(args, SpringBootMain2, v) + args = append(args, v1.SpringBootMain2, v) } else { // we are running SpringBoot 3.x - args = append(args, SpringBootMain3, v) + args = append(args, v1.SpringBootMain3, v) } } else { // We can use normal Java - args = append(args, "--class-path", cp, + args = append(args, v1.JvmOptClassPath, cp, "-Dcoherence.operator.springboot.listener=false", "com.oracle.coherence.k8s.CoherenceVersion", v) } @@ -1035,52 +1006,44 @@ func checkCoherenceVersion(v string, details *RunDetails) bool { log.Info("Executed Coherence version check, version is greater than or equal to expected", "version", v) return true } - if _, ok := err.(*exec.ExitError); ok { - // The program has exited with an exit code != 0 - log.Info("Executed Coherence version check, version is lower than expected", "version", v) - return false + if exitError, ok := err.(*exec.ExitError); ok { + // The program has exited with an exit code == 99 which means the version is lower than requested + if exitError.ExitCode() == 99 { + log.Info("Executed Coherence version check, version is lower than expected", "version", v) + return false + } } - // command exited with some other error - log.Error(err, "Coherence version check failed") - return false -} - -func cohPre12214(details *RunDetails) { - details.addArg("-Dcoherence.override=k8s-coherence-nossl-override.xml") - details.addArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") -} - -func cohPost12214(details *RunDetails) { - details.addArg("-Dcoherence.override=k8s-coherence-override.xml") - details.addArgFromEnvVar(v1.EnvVarCohOverride, "-Dcoherence.k8s.override") + // command exited with some other error, assume the version is good + log.Info("Coherence version check failed, assuming version is valid", "version", v, "error", err.Error()) + return true } -func cohPost2206(details *RunDetails) { +func cohPost2206(details *run_details.RunDetails) { if details.UseOperatorHealth { - details.addArg("-Dcoherence.k8s.operator.health.enabled=true") + details.AddArg("-Dcoherence.operator.health.enabled=true") } else { - useOperator := details.getenvOrDefault(v1.EnvVarUseOperatorHealthCheck, "false") + useOperator := details.GetenvOrDefault(v1.EnvVarUseOperatorHealthCheck, "false") if strings.EqualFold("true", useOperator) { - details.addArg("-Dcoherence.k8s.operator.health.enabled=true") + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "true") } else { - details.addArg("-Dcoherence.k8s.operator.health.enabled=false") - details.setSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, "-Dcoherence.health.http.port", fmt.Sprintf("%d", v1.DefaultHealthPort)) + details.AddSystemPropertyArg(v1.SysPropOperatorHealthEnabled, "false") + details.SetSystemPropertyFromEnvVarOrDefault(v1.EnvVarCohHealthPort, v1.SysPropCoherenceHealthHttpPort, fmt.Sprintf("%d", v1.DefaultHealthPort)) } } } -func addManagementSSL(details *RunDetails) { +func addManagementSSL(details *run_details.RunDetails) { addSSL(v1.EnvVarCohMgmtPrefix, v1.PortNameManagement, details) } -func addMetricsSSL(details *RunDetails) { +func addMetricsSSL(details *run_details.RunDetails) { addSSL(v1.EnvVarCohMetricsPrefix, v1.PortNameMetrics, details) } -func addSSL(prefix, prop string, details *RunDetails) { +func addSSL(prefix, prop string, details *run_details.RunDetails) { var urlPrefix string - sslCerts := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLCerts) + sslCerts := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLCerts) if sslCerts != "" { if !strings.HasSuffix(sslCerts, "/") { sslCerts += "/" @@ -1094,58 +1057,58 @@ func addSSL(prefix, prop string, details *RunDetails) { urlPrefix = "file:" } - if details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLEnabled) != "" { - details.addArg("-Dcoherence." + prop + ".http.provider=ManagementSSLProvider") + if details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLEnabled) != "" { + details.AddArg("-Dcoherence." + prop + ".http.provider=ManagementSSLProvider") } - ks := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStore) + ks := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStore) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore=" + urlPrefix + ks) + details.AddArg("-Dcoherence." + prop + ".security.keystore=" + urlPrefix + ks) } - kspw := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreCredFile) + kspw := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreCredFile) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.password=" + urlPrefix + kspw) + details.AddArg("-Dcoherence." + prop + ".security.keystore.password=" + urlPrefix + kspw) } - kpw := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyCredFile) + kpw := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyCredFile) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.key.password=" + urlPrefix + kpw) + details.AddArg("-Dcoherence." + prop + ".security.key.password=" + urlPrefix + kpw) } - kalg := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreAlgo) + kalg := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreAlgo) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.algorithm=" + urlPrefix + kalg) + details.AddArg("-Dcoherence." + prop + ".security.keystore.algorithm=" + urlPrefix + kalg) } - kprov := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreProvider) + kprov := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreProvider) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.provider=" + urlPrefix + kprov) + details.AddArg("-Dcoherence." + prop + ".security.keystore.provider=" + urlPrefix + kprov) } - ktyp := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreType) + ktyp := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLKeyStoreType) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.keystore.type=" + urlPrefix + ktyp) + details.AddArg("-Dcoherence." + prop + ".security.keystore.type=" + urlPrefix + ktyp) } - ts := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStore) + ts := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStore) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore=" + urlPrefix + ts) + details.AddArg("-Dcoherence." + prop + ".security.truststore=" + urlPrefix + ts) } - tspw := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreCredFile) + tspw := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreCredFile) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.password=" + urlPrefix + tspw) + details.AddArg("-Dcoherence." + prop + ".security.truststore.password=" + urlPrefix + tspw) } - talg := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreAlgo) + talg := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreAlgo) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.algorithm=" + urlPrefix + talg) + details.AddArg("-Dcoherence." + prop + ".security.truststore.algorithm=" + urlPrefix + talg) } - tprov := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreProvider) + tprov := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreProvider) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.provider=" + urlPrefix + tprov) + details.AddArg("-Dcoherence." + prop + ".security.truststore.provider=" + urlPrefix + tprov) } - ttyp := details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreType) + ttyp := details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLTrustStoreType) if ks != "" { - details.addArg("-Dcoherence." + prop + ".security.truststore.type=" + urlPrefix + ttyp) + details.AddArg("-Dcoherence." + prop + ".security.truststore.type=" + urlPrefix + ttyp) } - if details.getenvWithPrefix(prefix, v1.EnvVarSuffixSSLRequireClientCert) != "" { - details.addArg("-Dcoherence." + prop + ".http.auth=cert") + if details.GetenvWithPrefix(prefix, v1.EnvVarSuffixSSLRequireClientCert) != "" { + details.AddArg("-Dcoherence." + prop + ".http.auth=cert") } } diff --git a/pkg/runner/runner_application_test.go b/pkg/runner/runner_application_test.go index bb8a035f8..ed0374d5f 100644 --- a/pkg/runner/runner_application_test.go +++ b/pkg/runner/runner_application_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -30,11 +30,12 @@ func TestApplicationArgsEmpty(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,7 +44,7 @@ func TestApplicationArgsEmpty(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationArgs(t *testing.T) { @@ -60,11 +61,12 @@ func TestApplicationArgs(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "Foo", "Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -73,7 +75,7 @@ func TestApplicationArgs(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "Foo", "Bar"))) } func TestApplicationArgsWithEnvVarExpansion(t *testing.T) { @@ -94,11 +96,12 @@ func TestApplicationArgsWithEnvVarExpansion(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "foo-value", "bar-value") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -107,7 +110,7 @@ func TestApplicationArgsWithEnvVarExpansion(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "foo-value", "bar-value"))) } func TestApplicationMain(t *testing.T) { @@ -124,11 +127,12 @@ func TestApplicationMain(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), "$DEFAULT$", "com.oracle.test.Main") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -137,13 +141,15 @@ func TestApplicationMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.oracle.test.Main"))) } func TestApplicationWorkingDirectory(t *testing.T) { g := NewGomegaWithT(t) - wd, err := os.Getwd() + utils := ensureTestUtilsDir(t) + wd := utils + "/foo" + err := os.MkdirAll(wd, os.ModePerm) g.Expect(err).NotTo(HaveOccurred()) d := &coh.Coherence{ @@ -157,11 +163,12 @@ func TestApplicationWorkingDirectory(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedCP := GetOperatorClasspathWithUtilsDir(utils) + expectedArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutAppClasspath() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -169,6 +176,6 @@ func TestApplicationWorkingDirectory(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(wd)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithWorkingDir(t, wd))) } diff --git a/pkg/runner/runner_application_type_test.go b/pkg/runner/runner_application_type_test.go index 20f4831b0..ab42dd9f7 100644 --- a/pkg/runner/runner_application_type_test.go +++ b/pkg/runner/runner_application_type_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -22,17 +22,18 @@ func TestApplicationTypeNone(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeNone), + Type: ptr.To(coh.AppTypeNone), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -41,7 +42,7 @@ func TestApplicationTypeNone(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationTypeNoneWithMain(t *testing.T) { @@ -52,18 +53,19 @@ func TestApplicationTypeNoneWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeNone), + Type: ptr.To(coh.AppTypeNone), Main: ptr.To("com.foo.Bar"), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -72,7 +74,7 @@ func TestApplicationTypeNoneWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } func TestApplicationTypeCoherence(t *testing.T) { @@ -83,17 +85,18 @@ func TestApplicationTypeCoherence(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeCoherence), + Type: ptr.To(coh.AppTypeCoherence), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -102,7 +105,7 @@ func TestApplicationTypeCoherence(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationTypeCoherenceWithMain(t *testing.T) { @@ -113,18 +116,19 @@ func TestApplicationTypeCoherenceWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeCoherence), + Type: ptr.To(coh.AppTypeCoherence), Main: ptr.To("com.foo.Bar"), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -133,7 +137,7 @@ func TestApplicationTypeCoherenceWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } func TestApplicationTypeJava(t *testing.T) { @@ -144,17 +148,18 @@ func TestApplicationTypeJava(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeJava), + Type: ptr.To(coh.AppTypeJava), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -163,7 +168,7 @@ func TestApplicationTypeJava(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestApplicationTypeJavaWithMain(t *testing.T) { @@ -174,18 +179,19 @@ func TestApplicationTypeJavaWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeJava), + Type: ptr.To(coh.AppTypeJava), Main: ptr.To("com.foo.Bar"), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -194,7 +200,7 @@ func TestApplicationTypeJavaWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } func TestApplicationTypeHelidon(t *testing.T) { @@ -205,17 +211,18 @@ func TestApplicationTypeHelidon(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeHelidon), + Type: ptr.To(coh.AppTypeHelidon), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, HelidonMain) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -224,7 +231,7 @@ func TestApplicationTypeHelidon(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "io.helidon.microprofile.cdi.Main"))) } func TestApplicationTypeHelidonWithMain(t *testing.T) { @@ -235,18 +242,19 @@ func TestApplicationTypeHelidonWithMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeHelidon), + Type: ptr.To(coh.AppTypeHelidon), Main: ptr.To("com.foo.Bar"), }, }, }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := ReplaceArg(GetMinimalExpectedArgs(), DefaultMain, "com.foo.Bar") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(e).NotTo(BeNil()) @@ -255,5 +263,5 @@ func TestApplicationTypeHelidonWithMain(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.foo.Bar"))) } diff --git a/pkg/runner/runner_coherence_test.go b/pkg/runner/runner_coherence_test.go index d2af76187..9106f0c30 100644 --- a/pkg/runner/runner_coherence_test.go +++ b/pkg/runner/runner_coherence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -26,20 +26,23 @@ func TestCoherenceClusterName(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.cluster="), + expectedArgsFile := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.cluster="), "-Dcoherence.cluster=test-cluster") + verifyConfigFilesWithArgs(t, d, expectedArgsFile) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.cluster="), + "-Dcoherence.cluster=test-cluster") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -57,20 +60,23 @@ func TestCoherenceCacheConfig(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.cacheconfig="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.cacheconfig="), "-Dcoherence.cacheconfig=test-config.xml") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.cacheconfig="), + "-Dcoherence.cacheconfig=test-config.xml") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -88,20 +94,23 @@ func TestCoherenceOperationalConfig(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.k8s.override="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.k8s.override="), "-Dcoherence.k8s.override=test-override.xml") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.k8s.override="), + "-Dcoherence.k8s.override=test-override.xml") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -119,20 +128,23 @@ func TestCoherenceStorageEnabledTrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.distributed.localstorage="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.distributed.localstorage="), "-Dcoherence.distributed.localstorage=true") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.distributed.localstorage="), + "-Dcoherence.distributed.localstorage=true") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -150,20 +162,23 @@ func TestCoherenceStorageEnabledFalse(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.distributed.localstorage="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.distributed.localstorage="), "-Dcoherence.distributed.localstorage=false") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.distributed.localstorage="), + "-Dcoherence.distributed.localstorage=false") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -181,11 +196,10 @@ func TestCoherenceExcludeFromWKATrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -193,8 +207,8 @@ func TestCoherenceExcludeFromWKATrue(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceLogLevel(t *testing.T) { @@ -211,20 +225,23 @@ func TestCoherenceLogLevel(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.log.level="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.log.level="), "-Dcoherence.log.level=9") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.log.level="), + "-Dcoherence.log.level=9") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -243,11 +260,10 @@ func TestCoherenceTracingRatio(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.tracing.ratio=0.012340")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.tracing.ratio=0.012340") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -255,7 +271,8 @@ func TestCoherenceTracingRatio(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.tracing.ratio=0.012340") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -273,11 +290,10 @@ func TestCoherenceAllowEndangeredEmptyList(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -285,8 +301,8 @@ func TestCoherenceAllowEndangeredEmptyList(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceAllowEndangered(t *testing.T) { @@ -303,11 +319,10 @@ func TestCoherenceAllowEndangered(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.operator.statusha.allowendangered=foo,bar")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.k8s.operator.statusha.allowendangered=foo,bar") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -315,7 +330,8 @@ func TestCoherenceAllowEndangered(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.operator.statusha.allowendangered=foo,bar") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -336,12 +352,13 @@ func TestCoherenceExistingWKADeploymentSameNamespace(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedFileArgs := GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.wka") + expectedFileArgs = append(expectedFileArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".foo.svc") - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.wka") - expectedArgs = append(expectedArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".foo.svc") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -349,7 +366,9 @@ func TestCoherenceExistingWKADeploymentSameNamespace(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.wka"), + "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".foo.svc") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -370,12 +389,13 @@ func TestCoherenceExistingWKADeploymentDifferentNamespace(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedFileArgs := GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.wka") + expectedFileArgs = append(expectedFileArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".back-end.svc") - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.wka") - expectedArgs = append(expectedArgs, "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".back-end.svc") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -383,7 +403,9 @@ func TestCoherenceExistingWKADeploymentDifferentNamespace(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.wka"), + "-Dcoherence.wka=data"+coh.WKAServiceNameSuffix+".back-end.svc") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -401,11 +423,12 @@ func TestCoherenceEnableIpMonitor(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.ipmonitor.pingtimeout") - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.ipmonitor.pingtimeout") + verifyConfigFilesWithArgs(t, d, expectedArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -413,8 +436,8 @@ func TestCoherenceEnableIpMonitor(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetExpectedArgsWithoutPrefix(t, "-Dcoherence.ipmonitor.pingtimeout"))) } func TestCoherenceDisableIpMonitor(t *testing.T) { @@ -431,11 +454,10 @@ func TestCoherenceDisableIpMonitor(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -443,8 +465,8 @@ func TestCoherenceDisableIpMonitor(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceDefaultIpMonitor(t *testing.T) { @@ -461,11 +483,10 @@ func TestCoherenceDefaultIpMonitor(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -473,8 +494,8 @@ func TestCoherenceDefaultIpMonitor(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestCoherenceSiteEAndRackEnvVarSet(t *testing.T) { @@ -487,24 +508,22 @@ func TestCoherenceSiteEAndRackEnvVarSet(t *testing.T) { Env: []corev1.EnvVar{ { Name: coh.EnvVarCoherenceSite, - Value: "test-site", + Value: "site-foo", }, { Name: coh.EnvVarCoherenceRack, - Value: "test-rack", + Value: "rack-bar", }, }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) + verifyConfigFilesWithArgsWithSkipSite(t, d, GetExpectedArgsFileContentWith("-Dcoherence.site=site-foo", + "-Dcoherence.rack=rack-bar"), false) - expectedCommand := GetJavaCommand() - // site and rack system properties should not be set - expectedArgs := RemoveArg(GetMinimalExpectedArgs(), "-Dcoherence.site") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.rack") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -512,7 +531,8 @@ func TestCoherenceSiteEAndRackEnvVarSet(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=site-foo", "-Dcoherence.rack=rack-bar") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -530,7 +550,7 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVar(t *testing.T) { }, { Name: "TEST_SITE_VAR", - Value: "test-site", + Value: "x-site", }, { Name: coh.EnvVarCoherenceRack, @@ -538,19 +558,18 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVar(t *testing.T) { }, { Name: "TEST_RACK_VAR", - Value: "test-rack", + Value: "x-rack", }, }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) + verifyConfigFilesWithArgsWithSkipSite(t, d, GetExpectedArgsFileContentWith("-Dcoherence.site=x-site", + "-Dcoherence.rack=x-rack"), false) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.site=test-site") - expectedArgs = append(expectedArgs, "-Dcoherence.rack=test-rack") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -558,7 +577,8 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVar(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=x-site", "-Dcoherence.rack=x-rack") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -587,13 +607,13 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVarWhenRackIsMissing(t *testin }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.site=test-site") // rack should be set to site - expectedArgs = append(expectedArgs, "-Dcoherence.rack=test-site") + expectedFileArgs := append(GetExpectedArgsFileContent(), "-Dcoherence.site=test-site", "-Dcoherence.rack=test-site") + + verifyConfigFilesWithArgsWithSkipSite(t, d, expectedFileArgs, false) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -601,7 +621,9 @@ func TestCoherenceSiteAndRackEnvVarSetFromOtherEnvVarWhenRackIsMissing(t *testin g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=test-site", + "-Dcoherence.rack=test-site") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } @@ -626,12 +648,13 @@ func TestCoherenceSiteAndRackFromFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeploymentWithSkipSite(d, false) + expectedFileArgs := append(GetExpectedArgsFileContent(), "-Dcoherence.site=site-from-file", + "-Dcoherence.rack=rack-from-file") - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dcoherence.site=site-from-file") - expectedArgs = append(expectedArgs, "-Dcoherence.rack=rack-from-file") + verifyConfigFilesWithArgsWithSkipSite(t, d, expectedFileArgs, false) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeploymentWithSkipSite(t, d, false) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -639,6 +662,8 @@ func TestCoherenceSiteAndRackFromFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expectedArgs := append(GetMinimalExpectedArgs(t), "-Dcoherence.site=site-from-file", + "-Dcoherence.rack=rack-from-file") g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } diff --git a/pkg/runner/runner_initialise_test.go b/pkg/runner/runner_initialise_test.go index 0d44baaee..b472e00e9 100644 --- a/pkg/runner/runner_initialise_test.go +++ b/pkg/runner/runner_initialise_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -31,7 +31,7 @@ func TestInitialise(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test"}, } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) args, err := createArgs() g.Expect(err).NotTo(HaveOccurred()) @@ -49,7 +49,7 @@ func TestInitialiseWithCommand(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test"}, } - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) args, err := createArgs() g.Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/runner/runner_jvm_jibclasspath_test.go b/pkg/runner/runner_jvm_jibclasspath_test.go index 32e524298..b7684f024 100644 --- a/pkg/runner/runner_jvm_jibclasspath_test.go +++ b/pkg/runner/runner_jvm_jibclasspath_test.go @@ -17,7 +17,12 @@ import ( "testing" ) -func TestJibClasspath(t *testing.T) { +const ( + JibClassPath = "jib/classpath/*:jib/libs/*" + JibMainClass = "com.test.JibMainClass" +) + +func TestJibClasspathWhenNoJibFilePresent(t *testing.T) { g := NewGomegaWithT(t) d := &coh.Coherence{ @@ -31,11 +36,10 @@ func TestJibClasspath(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,11 +47,11 @@ func TestJibClasspath(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } -func TestJibClasspathFile(t *testing.T) { +func TestJibClasspathFileWhenJibFilePresent(t *testing.T) { g := NewGomegaWithT(t) d := &coh.Coherence{ @@ -61,13 +65,14 @@ func TestJibClasspathFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() f := createJibClasspathFile() defer os.Remove(f.Name()) - expectedArgs := GetMinimalExpectedArgsWithAppClasspathFile() + + expectedCp := JibClassPath + ":" + GetOperatorClasspathWithUtilsDir(ensureTestUtilsDir(t)) + verifyConfigFilesWithArgsAndClasspath(t, d, GetExpectedArgsFileContent(), expectedCp) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -75,8 +80,10 @@ func TestJibClasspathFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + + expected := append(GetMinimalExpectedArgsWithoutCP(), coh.JvmOptClassPath, expectedCp) + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJibMainClassFile(t *testing.T) { @@ -93,13 +100,13 @@ func TestJibMainClassFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() f := createJibMainClassFile() defer os.Remove(f.Name()) - expectedArgs := GetMinimalExpectedArgsWithAppMainClassFile() + + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -107,8 +114,8 @@ func TestJibMainClassFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, JibMainClass))) } func TestJibClasspathFileAndMainClassFile(t *testing.T) { @@ -125,15 +132,16 @@ func TestJibClasspathFileAndMainClassFile(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() f1 := createJibClasspathFile() defer os.Remove(f1.Name()) f2 := createJibMainClassFile() defer os.Remove(f2.Name()) - expectedArgs := GetMinimalExpectedArgsWithAppClasspathFileAndMainClassFile() + + expectedCp := JibClassPath + ":" + GetOperatorClasspathWithUtilsDir(ensureTestUtilsDir(t)) + verifyConfigFilesWithArgsAndClasspath(t, d, GetExpectedArgsFileContent(), expectedCp) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -141,8 +149,11 @@ func TestJibClasspathFileAndMainClassFile(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(GetMinimalExpectedArgsWithoutCP(), coh.JvmOptClassPath, expectedCp) + expected = ReplaceArg(expected, coh.DefaultMain, JibMainClass) + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) + // g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWithMainClass(t, "com.tangosol.net.DefaultCacheServer"))) } func createJibClasspathFile() *os.File { @@ -152,7 +163,7 @@ func createJibClasspathFile() *os.File { os.Exit(1) } - _, err = f.WriteString(fmt.Sprintf("%s/classpath/*:%s/libs/*", TestAppDir, TestAppDir)) + _, err = f.WriteString(JibClassPath) if err != nil { fmt.Print(err) os.Exit(1) @@ -173,7 +184,7 @@ func createJibMainClassFile() *os.File { os.Exit(1) } - _, err = f.WriteString("com.tangosol.net.DefaultCacheServer") + _, err = f.WriteString(JibMainClass) if err != nil { fmt.Print(err) os.Exit(1) @@ -190,9 +201,9 @@ func createJibMainClassFile() *os.File { func GetMinimalExpectedArgsWithAppClasspathFile() []string { fileName := fmt.Sprintf("%s/jib-classpath-file", TestAppDir) cp := readFirstLine(fileName) - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" + cp += ":/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} @@ -206,9 +217,9 @@ func GetMinimalExpectedArgsWithAppMainClassFile() []string { cp := fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar", TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" + cp += ":/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} @@ -223,9 +234,9 @@ func GetMinimalExpectedArgsWithAppMainClassFile() []string { func GetMinimalExpectedArgsWithAppClasspathFileAndMainClassFile() []string { fileName := fmt.Sprintf("%s/jib-classpath-file", TestAppDir) cp := readFirstLine(fileName) - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" + cp += ":/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} diff --git a/pkg/runner/runner_jvm_memory_test.go b/pkg/runner/runner_jvm_memory_test.go index 44974b559..485c14bd0 100644 --- a/pkg/runner/runner_jvm_memory_test.go +++ b/pkg/runner/runner_jvm_memory_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -31,11 +31,10 @@ func TestJvmHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialHeapSize=10g", "-XX:MaxHeapSize=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialHeapSize=10g", "-XX:MaxHeapSize=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,8 +42,8 @@ func TestJvmHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialHeapSize=10g", "-XX:MaxHeapSize=10g"))) } func TestJvmInitialHeapSize(t *testing.T) { @@ -63,11 +62,10 @@ func TestJvmInitialHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialHeapSize=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialHeapSize=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -75,8 +73,8 @@ func TestJvmInitialHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialHeapSize=10g"))) } func TestJvmMaxHeapSize(t *testing.T) { @@ -95,11 +93,10 @@ func TestJvmMaxHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxHeapSize=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxHeapSize=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -107,8 +104,8 @@ func TestJvmMaxHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxHeapSize=10g"))) } func TestJvmHeapSizeOverridesInitialAndMaxHeapSize(t *testing.T) { @@ -129,11 +126,10 @@ func TestJvmHeapSizeOverridesInitialAndMaxHeapSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialHeapSize=5g", "-XX:MaxHeapSize=5g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialHeapSize=5g", "-XX:MaxHeapSize=5g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -141,8 +137,8 @@ func TestJvmHeapSizeOverridesInitialAndMaxHeapSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialHeapSize=5g", "-XX:MaxHeapSize=5g"))) } func TestJvmMaxRam(t *testing.T) { @@ -161,11 +157,10 @@ func TestJvmMaxRam(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxRAM=10g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxRAM=10g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -173,8 +168,8 @@ func TestJvmMaxRam(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxRAM=10g"))) } func TestJvmRamPercent(t *testing.T) { @@ -194,12 +189,11 @@ func TestJvmRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialRAMPercentage=5.500", - "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -207,8 +201,9 @@ func TestJvmRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500"))) } func TestJvmInitialRamPercent(t *testing.T) { @@ -228,11 +223,10 @@ func TestJvmInitialRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -240,8 +234,8 @@ func TestJvmInitialRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialRAMPercentage=5.500"))) } func TestJvmMaxRamPercent(t *testing.T) { @@ -261,11 +255,10 @@ func TestJvmMaxRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -273,8 +266,8 @@ func TestJvmMaxRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxRAMPercentage=5.500"))) } func TestJvmMinRamPercent(t *testing.T) { @@ -294,11 +287,10 @@ func TestJvmMinRamPercent(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MinRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MinRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -306,8 +298,8 @@ func TestJvmMinRamPercent(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MinRAMPercentage=5.500"))) } func TestJvmRamPercentOverridesInitialMaxAndMin(t *testing.T) { @@ -333,12 +325,11 @@ func TestJvmRamPercentOverridesInitialMaxAndMin(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:InitialRAMPercentage=5.500", - "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -346,8 +337,9 @@ func TestJvmRamPercentOverridesInitialMaxAndMin(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:InitialRAMPercentage=5.500", + "-XX:MaxRAMPercentage=5.500", "-XX:MinRAMPercentage=5.500"))) } func TestJvmStackSize(t *testing.T) { @@ -366,11 +358,10 @@ func TestJvmStackSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Xss500k")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Xss500k") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -378,8 +369,8 @@ func TestJvmStackSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Xss500k"))) } func TestJvmMetaspaceSize(t *testing.T) { @@ -398,11 +389,10 @@ func TestJvmMetaspaceSize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MetaspaceSize=5g", "-XX:MaxMetaspaceSize=5g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MetaspaceSize=5g", "-XX:MaxMetaspaceSize=5g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -410,8 +400,9 @@ func TestJvmMetaspaceSize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, + "-XX:MetaspaceSize=5g", "-XX:MaxMetaspaceSize=5g"))) } func TestJvmDirectMemorySize(t *testing.T) { @@ -430,11 +421,10 @@ func TestJvmDirectMemorySize(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:MaxDirectMemorySize=5g")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:MaxDirectMemorySize=5g") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -442,8 +432,8 @@ func TestJvmDirectMemorySize(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:MaxDirectMemorySize=5g"))) } func TestJvmNativeMemoryTracking(t *testing.T) { @@ -462,11 +452,11 @@ func TestJvmNativeMemoryTracking(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:NativeMemoryTracking="), "-XX:NativeMemoryTracking=detail") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:NativeMemoryTracking="), "-XX:NativeMemoryTracking=detail") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -474,8 +464,9 @@ func TestJvmNativeMemoryTracking(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:NativeMemoryTracking="), "-XX:NativeMemoryTracking=detail") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmOOMHeapDumpOff(t *testing.T) { @@ -496,11 +487,11 @@ func TestJvmOOMHeapDumpOff(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-XX:+HeapDumpOnOutOfMemoryError") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-XX:+HeapDumpOnOutOfMemoryError") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -508,8 +499,9 @@ func TestJvmOOMHeapDumpOff(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+HeapDumpOnOutOfMemoryError") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmOOMExitOff(t *testing.T) { @@ -530,11 +522,11 @@ func TestJvmOOMExitOff(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-XX:+ExitOnOutOfMemoryError") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-XX:+ExitOnOutOfMemoryError") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -542,6 +534,7 @@ func TestJvmOOMExitOff(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+ExitOnOutOfMemoryError") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } diff --git a/pkg/runner/runner_jvm_test.go b/pkg/runner/runner_jvm_test.go index 5ff5a888b..8f94b16eb 100644 --- a/pkg/runner/runner_jvm_test.go +++ b/pkg/runner/runner_jvm_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -29,11 +29,10 @@ func TestJvmArgsEmpty(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -41,8 +40,8 @@ func TestJvmArgsEmpty(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestJvmArgs(t *testing.T) { @@ -59,11 +58,10 @@ func TestJvmArgs(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dfoo=foo-value", "-Dbar=bar-value")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dfoo=foo-value", "-Dbar=bar-value") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -71,8 +69,8 @@ func TestJvmArgs(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dfoo=foo-value", "-Dbar=bar-value"))) } func TestJvmArgsWithEnvExpansion(t *testing.T) { @@ -93,11 +91,10 @@ func TestJvmArgsWithEnvExpansion(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dfoo=foo-value", "-Dbar=bar-value")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-Dfoo=foo-value", "-Dbar=bar-value") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -105,8 +102,8 @@ func TestJvmArgsWithEnvExpansion(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dfoo=foo-value", "-Dbar=bar-value"))) } func TestJvmUseContainerLimitsFalse(t *testing.T) { @@ -123,11 +120,11 @@ func TestJvmUseContainerLimitsFalse(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := GetExpectedArgsFileContentWithoutPrefix("-XX:+UseContainerSupport") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgsWithoutPrefix("-XX:+UseContainerSupport") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -135,8 +132,9 @@ func TestJvmUseContainerLimitsFalse(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgsWith(t), "-XX:+UseContainerSupport") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmUseContainerLimitsTrue(t *testing.T) { @@ -153,11 +151,10 @@ func TestJvmUseContainerLimitsTrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -165,8 +162,8 @@ func TestJvmUseContainerLimitsTrue(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestJvmGarbageCollectorG1(t *testing.T) { @@ -185,11 +182,11 @@ func TestJvmGarbageCollectorG1(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseG1GC") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseG1GC") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -197,8 +194,9 @@ func TestJvmGarbageCollectorG1(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseG1GC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmGarbageCollectorCMS(t *testing.T) { @@ -217,11 +215,11 @@ func TestJvmGarbageCollectorCMS(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseConcMarkSweepGC") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseConcMarkSweepGC") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -229,8 +227,9 @@ func TestJvmGarbageCollectorCMS(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseConcMarkSweepGC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmGarbageCollectorParallel(t *testing.T) { @@ -249,11 +248,11 @@ func TestJvmGarbageCollectorParallel(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseParallelGC") + verifyConfigFilesWithArgs(t, d, expectedArgs) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseParallelGC") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -261,8 +260,9 @@ func TestJvmGarbageCollectorParallel(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseParallelGC") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { @@ -281,11 +281,7 @@ func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), + expectedArgs := append(GetExpectedArgsFileContent(), "-verbose:gc", "-XX:+PrintGCDetails", "-XX:+PrintGCTimeStamps", @@ -294,14 +290,26 @@ func TestJvmGarbageCollectorLoggingTrue(t *testing.T) { "-XX:+PrintGCApplicationStoppedTime", "-XX:+PrintGCApplicationConcurrentTime") + verifyConfigFilesWithArgs(t, d, expectedArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) + e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, + "-verbose:gc", + "-XX:+PrintGCDetails", + "-XX:+PrintGCTimeStamps", + "-XX:+PrintHeapAtGC", + "-XX:+PrintTenuringDistribution", + "-XX:+PrintGCApplicationStoppedTime", + "-XX:+PrintGCApplicationConcurrentTime"))) } func TestJvmGarbageCollectorArgsEmpty(t *testing.T) { @@ -320,11 +328,10 @@ func TestJvmGarbageCollectorArgsEmpty(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -332,8 +339,8 @@ func TestJvmGarbageCollectorArgsEmpty(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestJvmGarbageCollectorArgs(t *testing.T) { @@ -352,11 +359,10 @@ func TestJvmGarbageCollectorArgs(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-XX:Arg1", "-XX:Arg2")) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgs(), "-XX:Arg1", "-XX:Arg2") + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -364,6 +370,6 @@ func TestJvmGarbageCollectorArgs(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-XX:Arg1", "-XX:Arg2"))) } diff --git a/pkg/runner/runner_persistence_test.go b/pkg/runner/runner_persistence_test.go index cbbb30e0a..70880e05d 100644 --- a/pkg/runner/runner_persistence_test.go +++ b/pkg/runner/runner_persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -9,6 +9,7 @@ package runner import ( . "github.com/onsi/gomega" coh "github.com/oracle/coherence-operator/api/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" "testing" @@ -30,12 +31,12 @@ func TestServerWithPersistenceMode(t *testing.T) { }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.distributed.persistence-mode="), + expectedFileArgs := append(GetExpectedArgsFileContentWithoutPrefix("-Dcoherence.distributed.persistence-mode="), "-Dcoherence.distributed.persistence-mode=active") + verifyConfigFilesWithArgs(t, d, expectedFileArgs) + + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -43,46 +44,72 @@ func TestServerWithPersistenceMode(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-Dcoherence.distributed.persistence-mode=") + expected = append(expected, "-Dcoherence.distributed.persistence-mode=active") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestServerWithPersistenceDirectory(t *testing.T) { g := NewGomegaWithT(t) - args := []string{"server", "--dry-run"} - env := map[string]string{ - coh.EnvVarCohPersistenceDir: coh.VolumeMountPathPersistence, + d := &coh.Coherence{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: coh.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: coh.CoherenceResourceSpec{ + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarCohPersistenceDir, + Value: coh.VolumeMountPathPersistence, + }, + }, + }, + }, } - expectedCommand := GetJavaCommand() + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.distributed.persistence.base.dir="+coh.VolumeMountPathPersistence)) + env := EnvVarsFromDeployment(t, d) + + args := []string{"server", "--dry-run"} e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ContainElement("-Dcoherence.distributed.persistence.base.dir=" + coh.VolumeMountPathPersistence)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dcoherence.distributed.persistence.base.dir="+coh.VolumeMountPathPersistence))) } func TestServerWithSnapshotDirectory(t *testing.T) { g := NewGomegaWithT(t) - args := []string{"server", "--dry-run"} - env := map[string]string{ - coh.EnvVarCohSnapshotDir: coh.VolumeMountPathSnapshots, + d := &coh.Coherence{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: coh.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: coh.CoherenceResourceSpec{ + Env: []corev1.EnvVar{ + { + Name: coh.EnvVarCohSnapshotDir, + Value: coh.VolumeMountPathSnapshots, + }, + }, + }, + }, } - expectedCommand := GetJavaCommand() + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContentWith("-Dcoherence.distributed.persistence.snapshot.dir="+coh.VolumeMountPathSnapshots)) + + env := EnvVarsFromDeployment(t, d) + args := []string{"server", "--dry-run"} e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ContainElement("-Dcoherence.distributed.persistence.snapshot.dir=" + coh.VolumeMountPathSnapshots)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgsWith(t, "-Dcoherence.distributed.persistence.snapshot.dir="+coh.VolumeMountPathSnapshots))) } diff --git a/pkg/runner/runner_spring_test.go b/pkg/runner/runner_spring_test.go index fdb5358a6..6237f696d 100644 --- a/pkg/runner/runner_spring_test.go +++ b/pkg/runner/runner_spring_test.go @@ -12,7 +12,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" "os" - "strings" "testing" ) @@ -24,17 +23,20 @@ func TestSpringBootApplication(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd, err := os.Getwd() + g.Expect(err).To(BeNil()) + expectedCP := wd + "/*:" + wd + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootArgs(SpringBootMain2) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -42,8 +44,8 @@ func TestSpringBootApplication(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2))) } func TestSpringBoot3Application(t *testing.T) { @@ -54,17 +56,20 @@ func TestSpringBoot3Application(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring3), + Type: ptr.To(coh.AppTypeSpring3), }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + wd, err := os.Getwd() + g.Expect(err).To(BeNil()) + expectedCP := wd + "/*:" + wd + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootArgs(SpringBootMain3) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -72,8 +77,8 @@ func TestSpringBoot3Application(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain3))) } func TestSpringBootFatJarApplication(t *testing.T) { @@ -85,18 +90,19 @@ func TestSpringBootFatJarApplication(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedCP := jar + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgs(jar, SpringBootMain2) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -104,8 +110,9 @@ func TestSpringBootFatJarApplication(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), coh.JvmOptClassPath, "/apps/lib/foo.jar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestSpringBoot3FatJarApplication(t *testing.T) { @@ -117,18 +124,19 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring3), + Type: ptr.To(coh.AppTypeSpring3), SpringBootFatJar: &jar, }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedCP := jar + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgs(jar, SpringBootMain3) + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -136,8 +144,9 @@ func TestSpringBoot3FatJarApplication(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + expected := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain3), coh.JvmOptClassPath, "/apps/lib/foo.jar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expected)) } func TestSpringBootFatJarConsole(t *testing.T) { @@ -149,30 +158,19 @@ func TestSpringBootFatJarConsole(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, }, }, }, } + expectedCP := jar + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) + args := []string{"console", "--dry-run"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgsForRole(jar, ConsoleMain, "") - expectedArgs = ReplaceArg(expectedArgs, "-XX:NativeMemoryTracking=summary", "-XX:NativeMemoryTracking=off") - expectedArgs = ReplaceArg(expectedArgs, "-Dcoherence.health.http.port=6676", "-Dcoherence.health.http.port=0") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.k8s.operator.health.port=6676") - expectedArgs = append(expectedArgs, "-Dcoherence.localport.adjust=true", - "-Dcoherence.metrics.http.enabled=false", - "-Dcoherence.management.http=none", - "-Dcoherence.management.http.port=0", - "-Dcoherence.metrics.http.port=0", - "-Dcoherence.k8s.operator.health.enabled=false", - "-Dcoherence.health.http.port=0", - "-Dcoherence.grpc.enabled=false", - "-Dcoherence.k8s.operator.health.port=0") + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -180,56 +178,26 @@ func TestSpringBootFatJarConsole(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) -} - -func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { - g := NewGomegaWithT(t) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) - jar := "/apps/lib/foo.jar" - d := &coh.Coherence{ - ObjectMeta: metav1.ObjectMeta{Name: "test"}, - Spec: coh.CoherenceStatefulSetResourceSpec{ - CoherenceResourceSpec: coh.CoherenceResourceSpec{ - Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), - SpringBootFatJar: &jar, - }, - }, - }, - } - - args := []string{"console", "--dry-run", "--", "foo", "bar"} - env := EnvVarsFromDeployment(d) - - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedSpringBootFatJarArgsForRole(jar, ConsoleMain, "") - expectedArgs = ReplaceArg(expectedArgs, "-XX:NativeMemoryTracking=summary", "-XX:NativeMemoryTracking=off") - expectedArgs = ReplaceArg(expectedArgs, "-Dcoherence.health.http.port=6676", "-Dcoherence.health.http.port=0") - expectedArgs = RemoveArg(expectedArgs, "-Dcoherence.k8s.operator.health.port=6676") - expectedArgs = append(expectedArgs, "-Dcoherence.localport.adjust=true", - "-Dcoherence.metrics.http.enabled=false", + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), coh.JvmOptClassPath, jar) + expectedArgs = append(expectedArgs, "-Dcoherence.role=console", + "-Dloader.main=com.tangosol.net.CacheFactory", + "-Dcoherence.distributed.localstorage=false", + "-Dcoherence.localport.adjust=true", "-Dcoherence.management.http=none", "-Dcoherence.management.http.port=0", + "-Dcoherence.metrics.http.enabled=false", "-Dcoherence.metrics.http.port=0", - "-Dcoherence.k8s.operator.health.enabled=false", - "-Dcoherence.grpc.enabled=false", - "-Dcoherence.k8s.operator.health.port=0", + "-Dcoherence.operator.health.enabled=false", "-Dcoherence.health.http.port=0", - "foo", "bar") - - e, err := ExecuteWithArgsAndNewViper(env, args) - g.Expect(err).NotTo(HaveOccurred()) - g.Expect(e).NotTo(BeNil()) - g.Expect(e.OsCmd).NotTo(BeNil()) + "-Dcoherence.grpc.enabled=false", + "-XX:NativeMemoryTracking=off") - g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } -func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { +func TestSpringBootFatJarConsoleWithArgs(t *testing.T) { g := NewGomegaWithT(t) jar := "/apps/lib/foo.jar" @@ -238,19 +206,19 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), + Type: ptr.To(coh.AppTypeSpring2), SpringBootFatJar: &jar, - Main: ptr.To("foo.Bar"), }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedCP := jar + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedSpringBootFatJarArgs(jar, SpringBootMain2), "-Dloader.main=foo.Bar") + args := []string{"console", "--dry-run", "--", "foo", "bar"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -258,112 +226,75 @@ func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), coh.JvmOptClassPath, jar) + expectedArgs = append(expectedArgs, "-Dcoherence.role=console", + "-Dloader.main=com.tangosol.net.CacheFactory", + "-Dcoherence.distributed.localstorage=false", + "-Dcoherence.localport.adjust=true", + "-Dcoherence.management.http=none", + "-Dcoherence.management.http.port=0", + "-Dcoherence.metrics.http.enabled=false", + "-Dcoherence.metrics.http.port=0", + "-Dcoherence.operator.health.enabled=false", + "-Dcoherence.health.http.port=0", + "-Dcoherence.grpc.enabled=false", + "-XX:NativeMemoryTracking=off", + "foo", "bar") + g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } -func TestSpringBootBuildpacks(t *testing.T) { +func TestSpringBootFatJarApplicationWithCustomMain(t *testing.T) { g := NewGomegaWithT(t) + jar := "/apps/lib/foo.jar" d := &coh.Coherence{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: coh.CoherenceStatefulSetResourceSpec{ CoherenceResourceSpec: coh.CoherenceResourceSpec{ Application: &coh.ApplicationSpec{ - Type: ptr.To(AppTypeSpring2), - CloudNativeBuildPack: &coh.CloudNativeBuildPackSpec{ - Enabled: ptr.To(true), - }, + Type: ptr.To(coh.AppTypeSpring2), + SpringBootFatJar: &jar, + Main: ptr.To("foo.Bar"), }, }, }, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + expectedCP := jar + expectedFileArgs := GetExpectedArgsFileContent() + verifyConfigFilesWithArgsAndClasspath(t, d, expectedFileArgs, expectedCP) - expectedCommand := getBuildpackLauncher() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) g.Expect(e).NotTo(BeNil()) g.Expect(e.OsCmd).NotTo(BeNil()) - g.Expect(e.OsCmd.Dir).To(Equal("")) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - - g.Expect(len(e.OsCmd.Args)).To(Equal(4)) - g.Expect(e.OsCmd.Args[0]).To(Equal(coh.DefaultCnbpLauncher)) - g.Expect(e.OsCmd.Args[1]).To(Equal("java")) - g.Expect(e.OsCmd.Args[3]).To(Equal(SpringBootMain2)) - - g.Expect(e.OsCmd.Args[2]).To(HavePrefix("@")) - fileName := e.OsCmd.Args[2][1:] - data, err := os.ReadFile(fileName) - g.Expect(err).NotTo(HaveOccurred()) - - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" - } - - actualOpts := strings.Split(string(data), "\n") - expectedOpts := AppendCommonExpectedArgs([]string{"-Dloader.path=" + cp}) - g.Expect(actualOpts).To(ConsistOf(expectedOpts)) -} + g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) -func GetMinimalExpectedSpringBootArgs(main string) []string { - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ",/coherence-operator/utils/config" - } - args := []string{ - GetJavaArg(), - "-Dloader.path=" + cp, - } - args = append(AppendCommonExpectedArgs(args), main) - return args -} + expectedArgs := append(GetMinimalExpectedSpringBootArgs(t, coh.SpringBootMain2), + coh.JvmOptClassPath, jar, "-Dloader.main=foo.Bar") -func GetMinimalExpectedSpringBootFatJarArgs(jar, main string) []string { - return GetMinimalExpectedSpringBootFatJarArgsWithMain(jar, main, "") + g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) } -func GetMinimalExpectedSpringBootFatJarArgsWithMain(jar, springMain, main string) []string { - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ",/coherence-operator/utils/config" - } - args := []string{ - GetJavaArg(), - "--class-path", - jar, - "-Dloader.path=" + cp, - } - - if main != "" { - args = append(args, "-Dloader.main="+main) - } - - return append(AppendCommonExpectedArgs(args), springMain) -} +func GetMinimalExpectedSpringBootArgs(t *testing.T, main string) []string { + utils := ensureTestUtilsDir(t) -func GetMinimalExpectedSpringBootFatJarArgsForRole(jar, main, role string) []string { - cp := "/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ",/coherence-operator/utils/config" + cp := utils + "/lib/coherence-operator.jar" + cfg := utils + "config" + if _, err := os.Stat(cfg); err == nil { + cp += "," + cfg } args := []string{ GetJavaArg(), - "--class-path", - jar, "-Dloader.path=" + cp, - "-Dcoherence.distributed.localstorage=false", } - - if main != "" { - args = append(args, "-Dloader.main="+main) - } - - return append(AppendCommonExpectedNonServerArgs(args, role), SpringBootMain2) + return append(AppendCommonExpectedArgs(args), main) } diff --git a/pkg/runner/runner_test.go b/pkg/runner/runner_test.go index bb294748a..1a8604fdc 100644 --- a/pkg/runner/runner_test.go +++ b/pkg/runner/runner_test.go @@ -10,6 +10,7 @@ import ( "fmt" . "github.com/onsi/gomega" coh "github.com/oracle/coherence-operator/api/v1" + "github.com/oracle/coherence-operator/test/e2e/helper" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" @@ -26,11 +27,10 @@ func TestMinimalDeployment(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test"}, } - args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) - expectedCommand := GetJavaCommand() - expectedArgs := GetMinimalExpectedArgs() + args := []string{"server", "--dry-run"} + env := EnvVarsFromDeployment(t, d) e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -38,8 +38,8 @@ func TestMinimalDeployment(t *testing.T) { g.Expect(e.OsCmd).NotTo(BeNil()) g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) - g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) + g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand())) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { @@ -56,14 +56,12 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { }, } + verifyConfigFilesWithArgs(t, d, GetExpectedArgsFileContent()) + args := []string{"server", "--dry-run"} - env := EnvVarsFromDeployment(d) + env := EnvVarsFromDeployment(t, d) expectedCommand := GetJavaCommand() - expectedArgs := append(GetMinimalExpectedArgsWithoutPrefix("-Dcoherence.override="), - "-Dcoherence.override=k8s-coherence-override.xml", - "-Dcoherence.k8s.operator.health.enabled=false", - "-Dcoherence.health.http.port=6676") e, err := ExecuteWithArgsAndNewViper(env, args) g.Expect(err).NotTo(HaveOccurred()) @@ -72,11 +70,7 @@ func TestMinimalServerSkipCoherenceVersionCheck(t *testing.T) { g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir)) g.Expect(e.OsCmd.Path).To(Equal(expectedCommand)) - g.Expect(e.OsCmd.Args).To(ConsistOf(expectedArgs)) -} - -func GetMinimalExpectedArgsWithoutPrefix(prefix string) []string { - return RemoveArgWithPrefix(GetMinimalExpectedArgs(), prefix) + g.Expect(e.OsCmd.Args).To(ConsistOf(GetMinimalExpectedArgs(t))) } func ReplaceArg(args []string, toReplace, replaceWith string) []string { @@ -107,25 +101,49 @@ func GetJavaArg() string { return javaCmd } -func GetMinimalExpectedArgs() []string { - cp := fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar", - TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) +func GetMinimalExpectedArgs(t *testing.T) []string { + return GetMinimalExpectedArgsWithWorkingDir(t, TestAppDir) +} - cp = cp + ":/coherence-operator/utils/lib/coherence-operator.jar" - if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" +func GetMinimalExpectedArgsWithWorkingDir(t *testing.T, wd string) []string { + cp := "" + if wd == TestAppDir { + cp = fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar:", + TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) } - args := []string{GetJavaArg(), "--class-path", cp} + utils := ensureTestUtilsDir(t) + jar := fmt.Sprintf("%s/lib/coherence-operator.jar", utils) + cfg := fmt.Sprintf(":%s/config", utils) + cp += jar + if _, err := os.Stat(cfg); err == nil { + cp += ":" + cfg + } + args := []string{GetJavaArg(), "-cp", cp} return append(AppendCommonExpectedArgs(args), "com.oracle.coherence.k8s.Main", "$DEFAULT$") } +func GetExpectedArgsWithoutPrefix(t *testing.T, prefix ...string) []string { + args := GetMinimalExpectedArgs(t) + for _, p := range prefix { + args = RemoveArgWithPrefix(args, p) + } + return args +} + +func GetMinimalExpectedArgsWith(t *testing.T, args ...string) []string { + return append(GetMinimalExpectedArgs(t), args...) +} + +func GetMinimalExpectedArgsWithMainClass(t *testing.T, clz string) []string { + return append(RemoveArg(GetMinimalExpectedArgs(t), coh.DefaultMain), clz) +} + func GetMinimalExpectedArgsWithoutCP() []string { - args := make([]string, 0) - args = append(args, GetJavaArg()) + args := []string{GetJavaArg()} return append(AppendCommonExpectedArgs(args), "com.oracle.coherence.k8s.Main", "$DEFAULT$") @@ -134,7 +152,7 @@ func GetMinimalExpectedArgsWithoutCP() []string { func GetMinimalExpectedArgsWithoutAppClasspath() []string { cp := "/coherence-operator/utils/lib/coherence-operator.jar" if _, err := os.Stat("/coherence-operator/utils/config"); err == nil { - cp = cp + ":/coherence-operator/utils/config" + cp += ":/coherence-operator/utils/config" } args := []string{GetJavaArg(), "--class-path", cp} @@ -143,6 +161,36 @@ func GetMinimalExpectedArgsWithoutAppClasspath() []string { "$DEFAULT$") } +func GetExpectedClasspathWithUtilsDir(utils string) string { + cp := fmt.Sprintf("%s/resources:%s/classes:%s/classpath/bar2.JAR:%s/classpath/foo2.jar:%s/libs/bar1.JAR:%s/libs/foo1.jar", + TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir, TestAppDir) + return cp + ":" + GetOperatorClasspathWithUtilsDir(utils) +} + +func GetOperatorClasspathWithUtilsDir(utils string) string { + cp := utils + "/lib/coherence-operator.jar" + cfg := utils + "/config" + if _, err := os.Stat(cfg); err == nil { + cp += ":" + cfg + } + return cp +} + +func GetExpectedArgsFileContent() []string { + return GetExpectedArgsFileContentWith() +} + +func GetExpectedArgsFileContentWith(args ...string) []string { + var expected []string + expected = AppendCommonExpectedArgs(expected) + expected = append(expected, args...) + return expected +} + +func GetExpectedArgsFileContentWithoutPrefix(prefix string) []string { + return RemoveArgWithPrefix(GetExpectedArgsFileContent(), prefix) +} + func AppendCommonExpectedArgs(args []string) []string { return append(AppendCommonExpectedNonServerArgs(args, "test"), "-XshowSettings:all", @@ -158,15 +206,17 @@ func AppendCommonExpectedNonServerArgs(args []string, role string) []string { return append(args, "-Dcoherence.wka=test-wka..svc", "-Dcoherence.cluster=test", - "-Dcoherence.k8s.operator.health.port=6676", + "-Dcoherence.operator.health.port=6676", + "-Dcoherence.health.http.port=6676", + "-Dcoherence.operator.health.enabled=false", "-Dcoherence.management.http.port=30000", "-Dcoherence.metrics.http.port=9612", "-Dcoherence.distributed.persistence-mode=on-demand", - "-Dcoherence.override=k8s-coherence-nossl-override.xml", + "-Dcoherence.override=k8s-coherence-override.xml", "-Dcoherence.ipmonitor.pingtimeout=0", - "-Dcoherence.k8s.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown", + "-Dcoherence.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown", "-XX:HeapDumpPath=/coherence-operator/jvm/unknown/unknown/heap-dumps/unknown-unknown.hprof", - "-Dcoherence.k8s.operator.can.resume.services=true", + "-Dcoherence.operator.can.resume.services=true", "-XX:+UseG1GC", "-Dcoherence.ttl=0", "-XX:+UnlockDiagnosticVMOptions", @@ -210,14 +260,20 @@ func GetJavaCommand() string { return "java" } -func EnvVarsFromDeployment(d *coh.Coherence) map[string]string { - return EnvVarsFromDeploymentWithSkipSite(d, true) +func EnvVarsFromDeployment(t *testing.T, d *coh.Coherence) map[string]string { + return EnvVarsForContainerWithSkipSite(t, d, coh.ContainerNameCoherence, true) +} + +func EnvVarsFromDeploymentWithSkipSite(t *testing.T, d *coh.Coherence, skipSite bool) map[string]string { + return EnvVarsForContainerWithSkipSite(t, d, coh.ContainerNameCoherence, skipSite) +} + +func EnvVarsForConfigContainerWithSkipSite(t *testing.T, d *coh.Coherence, skipSite bool) map[string]string { + return EnvVarsForContainerWithSkipSite(t, d, coh.ContainerNameOperatorConfig, skipSite) } -func EnvVarsFromDeploymentWithSkipSite(d *coh.Coherence, skipSite bool) map[string]string { +func EnvVarsForContainerWithSkipSite(t *testing.T, d *coh.Coherence, containerName string, skipSite bool) map[string]string { envVars := make(map[string]string) - envVars[coh.EnvVarCohAppDir] = TestAppDir - envVars[coh.EnvVarCohSkipSite] = fmt.Sprintf("%t", skipSite) if d.Spec.JVM == nil { d.Spec.JVM = &coh.JVMSpec{} @@ -225,12 +281,102 @@ func EnvVarsFromDeploymentWithSkipSite(d *coh.Coherence, skipSite bool) map[stri res := d.Spec.CreateStatefulSetResource(d) sts := res.Spec.(*appsv1.StatefulSet) - c := coh.FindContainer(coh.ContainerNameCoherence, sts) + c := coh.FindContainer(containerName, sts) + if c == nil { + c = coh.FindInitContainer(containerName, sts) + } + if c == nil { + return nil + } + for _, ev := range c.Env { if ev.ValueFrom == nil { envVars[ev.Name] = ev.Value } } + if d.Spec.Application != nil && d.Spec.Application.WorkingDir != nil && *d.Spec.Application.WorkingDir != "" { + envVars[coh.EnvVarCohAppDir] = *d.Spec.Application.WorkingDir + } else { + envVars[coh.EnvVarCohAppDir] = TestAppDir + } + + dir := ensureTestUtilsDir(t) + envVars[coh.EnvVarCohUtilDir] = dir + envVars[coh.EnvVarCohCtlHome] = dir + envVars[coh.EnvVarCohSkipSite] = fmt.Sprintf("%t", skipSite) + return envVars } + +func ensureTestUtilsDir(t *testing.T) string { + g := NewGomegaWithT(t) + dir, err := helper.EnsureLogsDir(t.Name()) + g.Expect(err).NotTo(HaveOccurred()) + return dir +} + +func verifyConfigFilesWithArgs(t *testing.T, d *coh.Coherence, expectedArgs []string) { + verifyConfigFilesWithArgsWithSkipSite(t, d, expectedArgs, true) +} + +func verifyConfigFilesWithArgsWithSkipSite(t *testing.T, d *coh.Coherence, expectedArgs []string, skipSite bool) { + dir := ensureTestUtilsDir(t) + expectedCP := GetExpectedClasspathWithUtilsDir(dir) + verifyConfigFilesWithArgsAndClasspathWithSkipSite(t, d, expectedArgs, expectedCP, skipSite) +} + +func verifyConfigFilesWithArgsAndClasspath(t *testing.T, d *coh.Coherence, expectedArgs []string, expectedCP string) { + verifyConfigFilesWithArgsAndClasspathWithSkipSite(t, d, expectedArgs, expectedCP, true) +} + +func verifyConfigFilesWithArgsAndClasspathWithSkipSite(t *testing.T, d *coh.Coherence, expectedArgs []string, expectedCP string, skipSite bool) { + cfgEnv := EnvVarsForConfigContainerWithSkipSite(t, d, skipSite) + verifyConfigFilesWithArgsAndClasspathUsingEnv(t, cfgEnv, expectedArgs, expectedCP) +} + +func verifyConfigFilesWithArgsAndClasspathUsingEnv(t *testing.T, cfgEnv map[string]string, expectedArgs []string, expectedCP string) { + var err error + + g := NewGomegaWithT(t) + dir := ensureTestUtilsDir(t) + cfgEnv[coh.EnvVarCohUtilDir] = dir + cfgEnv[coh.EnvVarCohCtlHome] = dir + + _, err = ExecuteWithArgsAndNewViper(cfgEnv, []string{coh.RunnerConfig}) + g.Expect(err).NotTo(HaveOccurred()) + + cpName := fmt.Sprintf("%s/%s", dir, coh.OperatorClasspathFile) + _, err = os.Stat(cpName) + g.Expect(err).NotTo(HaveOccurred()) + dataCP, err := os.ReadFile(cpName) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(dataCP).NotTo(BeNil()) + cp := string(dataCP) + g.Expect(cp).To(Equal(expectedCP)) + + argsName := fmt.Sprintf("%s/%s", dir, coh.OperatorJvmArgsFile) + _, err = os.Stat(argsName) + g.Expect(err).NotTo(HaveOccurred()) + dataArgs, err := os.ReadFile(argsName) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(dataArgs).NotTo(BeNil()) + + args := filterNonEmptyStringArray(strings.Split(string(dataArgs), "\n")) + + g.Expect(args).To(ConsistOf(expectedArgs)) +} + +func filterNonEmptyStringArray(ss []string) (ret []string) { + test := func(s string) bool { return s != "" } + return filterStringArray(ss, test) +} + +func filterStringArray(ss []string, test func(string) bool) (ret []string) { + for _, s := range ss { + if test(s) { + ret = append(ret, s) + } + } + return +} diff --git a/pkg/runner/suite_test.go b/pkg/runner/suite_test.go index 61bd05100..7d5ae3087 100644 --- a/pkg/runner/suite_test.go +++ b/pkg/runner/suite_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -10,6 +10,7 @@ import ( "fmt" v1 "github.com/oracle/coherence-operator/api/v1" "os" + ctrl "sigs.k8s.io/controller-runtime" "testing" ) @@ -84,6 +85,8 @@ func TestMain(m *testing.M) { os.Exit(1) } + log = ctrl.Log.WithName("runner") + exitCode := m.Run() _ = os.RemoveAll(TestAppDir) diff --git a/test/certification/certify_management_test.go b/test/certification/certify_management_test.go index ef51b3c32..26618fdf3 100644 --- a/test/certification/certify_management_test.go +++ b/test/certification/certify_management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -81,6 +81,9 @@ func TestCertifyManagementDefaultPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) @@ -149,6 +152,9 @@ func TestCertifyManagementNonStandardPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) diff --git a/test/certification/certify_metrics_test.go b/test/certification/certify_metrics_test.go index d5c79c3d6..afb9b7b38 100644 --- a/test/certification/certify_metrics_test.go +++ b/test/certification/certify_metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -81,6 +81,9 @@ func TestCertifyMetricsDefaultPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) @@ -149,6 +152,9 @@ func TestCertifyMetricsNonStandardPort(t *testing.T) { } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) diff --git a/test/certification/certify_persistence_test.go b/test/certification/certify_persistence_test.go index 40dbf11a3..2db46c24b 100644 --- a/test/certification/certify_persistence_test.go +++ b/test/certification/certify_persistence_test.go @@ -1,8 +1,7 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. - * */ package certification @@ -272,10 +271,17 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType, snaps if err == nil { break } + if resp != nil { + _ = resp.Body.Close() + } } time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } + if err != nil { return err } @@ -294,6 +300,9 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType, snaps return false, err } resp, err = client.Do(req) + if resp != nil { + defer resp.Body.Close() + } if err != nil { fmt.Printf("Error in send idle check request: %v\n", url) return false, err diff --git a/test/coherence_compatibility/certifiy_deployment_test.go b/test/coherence_compatibility/certifiy_deployment_test.go index a72cd2301..7e658d412 100644 --- a/test/coherence_compatibility/certifiy_deployment_test.go +++ b/test/coherence_compatibility/certifiy_deployment_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -12,6 +12,7 @@ import ( v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/test/e2e/helper" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" "testing" "time" ) @@ -47,3 +48,85 @@ func TestCoherenceCompatibilityMinimalSpec(t *testing.T) { _, err = helper.WaitForStatefulSetForDeployment(testContext, ns, d, time.Second*10, time.Minute*5) g.Expect(err).NotTo(HaveOccurred()) } + +func TestCoherenceCompatibilityScaling(t *testing.T) { + // Ensure that everything is cleaned up after the test! + testContext.CleanupAfterTest(t) + g := NewGomegaWithT(t) + + ns := helper.GetTestClusterNamespace() + d := &v1.Coherence{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: "certify-scale", + }, + Spec: v1.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: v1.CoherenceResourceSpec{ + Replicas: ptr.To(int32(1)), + ReadinessProbe: &v1.ReadinessProbeSpec{ + InitialDelaySeconds: ptr.To(int32(10)), + PeriodSeconds: ptr.To(int32(10)), + }, + }, + }, + } + + if helper.GetTestCoherenceIsJava8() { + d.Spec.JVM = &v1.JVMSpec{ + Java8: ptr.To(true), + } + } + + // Start with one replica + err := testContext.Client.Create(context.TODO(), d) + g.Expect(err).NotTo(HaveOccurred()) + _, err = helper.WaitForStatefulSetForDeployment(testContext, ns, d, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) + + // Scale Up to three + err = scale(t, ns, d.Name, 3) + g.Expect(err).NotTo(HaveOccurred()) + _, err = helper.WaitForStatefulSet(testContext, ns, d.Name, 3, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) + + // Scale down to one + err = scale(t, ns, d.Name, 1) + g.Expect(err).NotTo(HaveOccurred()) + _, err = helper.WaitForStatefulSet(testContext, ns, d.Name, 1, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) +} + +// This test is not really using Java8 for images using Coherence 14.1.1-2206 +// and above. The test just sets the Java8 field to true to test running with +// the legacy container entry point. +func TestCoherenceCompatibilityJava8(t *testing.T) { + // Ensure that everything is cleaned up after the test! + testContext.CleanupAfterTest(t) + + g := NewGomegaWithT(t) + + ns := helper.GetTestNamespace() + d := &v1.Coherence{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: "certify-coherence", + }, + Spec: v1.CoherenceStatefulSetResourceSpec{ + CoherenceResourceSpec: v1.CoherenceResourceSpec{ + JVM: &v1.JVMSpec{ + Java8: ptr.To(true), + }, + }, + }, + } + + // ensure the imagePullSecrets are correctly injected + secrets := helper.GetImagePullSecrets() + d.Spec.ImagePullSecrets = append(d.Spec.ImagePullSecrets, secrets...) + + err := testContext.Client.Create(context.TODO(), d) + g.Expect(err).NotTo(HaveOccurred()) + + _, err = helper.WaitForStatefulSetForDeployment(testContext, ns, d, time.Second*10, time.Minute*5) + g.Expect(err).NotTo(HaveOccurred()) +} diff --git a/test/coherence_compatibility/certify_persistence_test.go b/test/coherence_compatibility/certify_persistence_test.go index 0bbe814f2..e51d53b89 100644 --- a/test/coherence_compatibility/certify_persistence_test.go +++ b/test/coherence_compatibility/certify_persistence_test.go @@ -1,8 +1,7 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. - * */ package compatibility @@ -15,6 +14,7 @@ import ( v1 "github.com/oracle/coherence-operator/api/v1" "github.com/oracle/coherence-operator/test/e2e/helper" corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" "testing" "time" ) @@ -140,6 +140,12 @@ func ensurePods(g *GomegaWithT, yamlFile, ns string) (v1.Coherence, []corev1.Pod deployment, err := helper.NewSingleCoherenceFromYaml(ns, yamlFile) g.Expect(err).NotTo(HaveOccurred()) + if helper.GetTestCoherenceIsJava8() { + deployment.Spec.JVM = &v1.JVMSpec{ + Java8: ptr.To(true), + } + } + d, _ := json.Marshal(deployment) fmt.Printf("Persistence Test installing deployment:\n%s\n", string(d)) diff --git a/test/coherence_compatibility/persistence-active-1.yaml b/test/coherence_compatibility/persistence-active-1.yaml index 2708cb52d..31d9e99a7 100644 --- a/test/coherence_compatibility/persistence-active-1.yaml +++ b/test/coherence_compatibility/persistence-active-1.yaml @@ -12,7 +12,7 @@ spec: periodSeconds: 10 jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" coherence: cacheConfig: test-cache-config.xml logLevel: 9 diff --git a/test/coherence_compatibility/persistence-active-3.yaml b/test/coherence_compatibility/persistence-active-3.yaml index 9fc09543b..4279449a5 100644 --- a/test/coherence_compatibility/persistence-active-3.yaml +++ b/test/coherence_compatibility/persistence-active-3.yaml @@ -12,7 +12,7 @@ spec: periodSeconds: 10 jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" coherence: cacheConfig: test-cache-config.xml logLevel: 9 diff --git a/test/e2e/helper/e2e-helpers.go b/test/e2e/helper/e2e-helpers.go index db1d7cdae..11da4fd47 100644 --- a/test/e2e/helper/e2e-helpers.go +++ b/test/e2e/helper/e2e-helpers.go @@ -174,7 +174,7 @@ func WaitForJob(ctx TestContext, namespace, stsName string, replicas int32, retr } else { ready = job.Status.Succeeded if job.Status.Ready != nil { - ready = ready + job.Status.Active + ready += job.Status.Active } } @@ -903,38 +903,47 @@ func DumpPodLog(ctx TestContext, pod *corev1.Pod, directory string) { } ctx.Logger.Info("Capturing Pod logs for " + pod.Name) + pathSep := string(os.PathSeparator) + name := logs + pathSep + directory + err = os.MkdirAll(name, os.ModePerm) + if err != nil { + ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " due to " + err.Error()) + } + for _, container := range pod.Spec.InitContainers { + DumpContainerLogs(ctx, container, pod, name) + } for _, container := range pod.Spec.Containers { - var err error - res := ctx.KubeClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Container: container.Name}) - s, err := res.Stream(ctx.Context) + DumpContainerLogs(ctx, container, pod, name) + } +} + +// DumpContainerLogs dumps the logs for a container +func DumpContainerLogs(ctx TestContext, container corev1.Container, pod *corev1.Pod, directory string) { + var err error + pathSep := string(os.PathSeparator) + res := ctx.KubeClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Container: container.Name}) + s, err := res.Stream(ctx.Context) + if err == nil { + suffix := 0 + logName := fmt.Sprintf("%s%s%s(%s).log", directory, pathSep, pod.Name, container.Name) + _, err = os.Stat(logName) + for err == nil { + suffix++ + logName = fmt.Sprintf("%s%s%s(%s)-%d.log", directory, pathSep, pod.Name, container.Name, suffix) + _, err = os.Stat(logName) + } + out, err := os.Create(logName) if err == nil { - name := logs + pathSep + directory - err = os.MkdirAll(name, os.ModePerm) - if err == nil { - suffix := 0 - logName := fmt.Sprintf("%s%s%s(%s).log", name, pathSep, pod.Name, container.Name) - _, err = os.Stat(logName) - for err == nil { - suffix++ - logName = fmt.Sprintf("%s%s%s(%s)-%d.log", name, pathSep, pod.Name, container.Name, suffix) - _, err = os.Stat(logName) - } - out, err := os.Create(logName) - if err == nil { - if _, err = io.Copy(out, s); err != nil { - ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) - } - } else { - ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) - } - } else { + if _, err = io.Copy(out, s); err != nil { ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } } else { ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } + } else { + ctx.Logger.Info("cannot capture logs for Pod " + pod.Name + " container " + container.Name + " due to " + err.Error()) } } @@ -1711,20 +1720,12 @@ func AssertDeploymentsInNamespace(ctx TestContext, t *testing.T, yamlFile, names // Assert that a StatefulSet or Job of the correct number or replicas is created for each roleSpec in the cluster for _, d := range deployments { - //if d.IsRunAsJob() { - // ctx.Logf("Waiting for Job for deployment %s", d.Name) - // // Wait for the Job for the roleSpec to be ready - wait five minutes max - // _, err := WaitForJob(ctx, namespace, d.Name, d.GetReplicas(), time.Second*10, time.Minute*5) - // g.Expect(err).NotTo(HaveOccurred()) - // ctx.Logf("Have Job for deployment %s", d.Name) - //} else { ctx.Logf("Waiting for StatefulSet for deployment %s", d.Name) // Wait for the StatefulSet for the roleSpec to be ready - wait five minutes max sts, err := WaitForStatefulSet(ctx, namespace, d.Name, d.GetReplicas(), time.Second*10, time.Minute*5) g.Expect(err).NotTo(HaveOccurred()) g.Expect(sts.Status.ReadyReplicas).To(Equal(d.GetReplicas())) ctx.Logf("Have StatefulSet for deployment %s", d.Name) - //} } // Assert that the finalizer has been added to all the deployments that do not have AllowUnsafeDelete=false diff --git a/test/e2e/helper/port_forward.go b/test/e2e/helper/port_forward.go index 6eae956df..914f8691a 100644 --- a/test/e2e/helper/port_forward.go +++ b/test/e2e/helper/port_forward.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -166,7 +166,6 @@ func (f *PortForwarder) Start() error { if err = f.forwarder.ForwardPorts(); err != nil { // Locks until stopChan is closed. pfError = err fmt.Println(err) - //close(readyChan) } }() diff --git a/test/e2e/helper/proj_helpers.go b/test/e2e/helper/proj_helpers.go index 564f4288b..dcc5c7151 100644 --- a/test/e2e/helper/proj_helpers.go +++ b/test/e2e/helper/proj_helpers.go @@ -34,6 +34,8 @@ const ( TestClusterNamespaceEnv = "CLUSTER_NAMESPACE" // TestClientNamespaceEnv is environment variable holding the name of the client test k8s namespace. TestClientNamespaceEnv = "OPERATOR_NAMESPACE_CLIENT" + // TestIsJava8Env is environment variable holding the flag to indicate the test Coherence image uses Java 8. + TestIsJava8Env = "OPERATOR_COHERENCE_JAVA_8" // PrometheusNamespaceEnv is environment variable holding the name of the Prometheus k8s namespace. PrometheusNamespaceEnv = "PROMETHEUS_NAMESPACE" // OperatorImageRegistryEnv is environment variable holding the registry of the Operator image. @@ -182,6 +184,12 @@ func GetTestClusterNamespace() string { return ns } +// GetTestCoherenceIsJava8 returns the name of the test cluster namespace. +func GetTestCoherenceIsJava8() bool { + s := os.Getenv(TestIsJava8Env) + return strings.ToLower(s) == "true" +} + // GetBuildOutputDirectory returns the build output directory func GetBuildOutputDirectory() (os.FileInfo, error) { name := os.Getenv(BuildOutputEnv) @@ -345,7 +353,7 @@ func NewCoherenceFromYamlWithSuffix(namespace, file, suffix string) ([]coh.Coher res, err := createCoherenceFromYaml(namespace, file) if err == nil && suffix != "" { for _, c := range res { - c.Name = c.Name + suffix + c.Name += suffix } } return res, err diff --git a/test/e2e/large-cluster/rolling_upgrade_test.go b/test/e2e/large-cluster/rolling_upgrade_test.go index f400a82d1..052294bf3 100644 --- a/test/e2e/large-cluster/rolling_upgrade_test.go +++ b/test/e2e/large-cluster/rolling_upgrade_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -226,7 +226,7 @@ func AssertPodRestartTimes(t *testing.T, before, after []corev1.Pod, idFunction // must not be equal g.Expect(i).NotTo(BeZero()) // ready must be the same comparison as scheduled, - //i.e. if scheduled is before then ready must be before + // i.e. if scheduled is before then ready must be before g.Expect(ready.Compare(readyOther)).To(Equal(i), fmt.Sprintf("node %s scheduled and ready overlap with node %s", name, otherName)) } } diff --git a/test/e2e/local/deployment-cli-home.yaml b/test/e2e/local/deployment-cli-home.yaml index a125fec84..b81f0cfe8 100644 --- a/test/e2e/local/deployment-cli-home.yaml +++ b/test/e2e/local/deployment-cli-home.yaml @@ -4,7 +4,7 @@ metadata: name: storage spec: env: - - name: COH_SKIP_SITE + - name: COHERENCE_OPERATOR_SKIP_SITE value: "true" - name: COHCTL_HOME value: /test/cli diff --git a/test/e2e/local/deployment-cli.yaml b/test/e2e/local/deployment-cli.yaml index e441c0feb..51bd3d846 100644 --- a/test/e2e/local/deployment-cli.yaml +++ b/test/e2e/local/deployment-cli.yaml @@ -4,7 +4,7 @@ metadata: name: storage spec: env: - - name: COH_SKIP_SITE + - name: COHERENCE_OPERATOR_SKIP_SITE value: "true" diff --git a/test/e2e/local/helidon_test.go b/test/e2e/local/helidon_test.go index dc9cf3276..eca244df3 100644 --- a/test/e2e/local/helidon_test.go +++ b/test/e2e/local/helidon_test.go @@ -46,6 +46,9 @@ func AssertHelidonEndpoint(t *testing.T, pods []corev1.Pod) { url := fmt.Sprintf("http://127.0.0.1:%d/ready", ports["web"]) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) } diff --git a/test/e2e/local/management_test.go b/test/e2e/local/management_test.go index c227decf0..cba4c5779 100644 --- a/test/e2e/local/management_test.go +++ b/test/e2e/local/management_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -218,6 +218,10 @@ func assertManagementRequest(pod corev1.Pod, client *http.Client, protocol strin time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } + if err != nil { return err } diff --git a/test/e2e/local/metrics_test.go b/test/e2e/local/metrics_test.go index f6395d673..86c47aa7b 100644 --- a/test/e2e/local/metrics_test.go +++ b/test/e2e/local/metrics_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -208,6 +208,10 @@ func assertMetricsRequest(pod corev1.Pod, client *http.Client, protocol string, time.Sleep(5 * time.Second) } + if resp != nil { + defer resp.Body.Close() + } + if err != nil { return err } diff --git a/test/e2e/local/rest_status_query_test.go b/test/e2e/local/rest_status_query_test.go index 6c9c7e8b9..ceb6ccf2e 100644 --- a/test/e2e/local/rest_status_query_test.go +++ b/test/e2e/local/rest_status_query_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -26,6 +26,9 @@ func TestRestStatusQueryWithInvalidPath(t *testing.T) { println("Connecting with: ", url) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusBadRequest)) } @@ -41,6 +44,9 @@ func TestRestStatusQueryForUnknownDeployment(t *testing.T) { println("Connecting with: ", url) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) } @@ -65,6 +71,9 @@ func TestRestStatusQueryForDeployment(t *testing.T) { t.Logf("Testing status query URL is %s", url) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } t.Logf("Received status response: %v err %v", resp, err) g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) diff --git a/test/e2e/local/spring-buildpack-cluster-2.yaml b/test/e2e/local/spring-buildpack-cluster-2.yaml index e549f8c61..94eb72e6a 100644 --- a/test/e2e/local/spring-buildpack-cluster-2.yaml +++ b/test/e2e/local/spring-buildpack-cluster-2.yaml @@ -7,6 +7,7 @@ spec: image: ${TEST_APPLICATION_IMAGE_SPRING_CNBP_2} application: type: spring + useImageEntryPoint: true jvm: args: - -Dcoherence.log=jdk diff --git a/test/e2e/local/spring-buildpack-cluster.yaml b/test/e2e/local/spring-buildpack-cluster.yaml index b7f04a9f3..fe91e7c07 100644 --- a/test/e2e/local/spring-buildpack-cluster.yaml +++ b/test/e2e/local/spring-buildpack-cluster.yaml @@ -7,6 +7,7 @@ spec: image: ${TEST_APPLICATION_IMAGE_SPRING_CNBP} application: type: spring3 + useImageEntryPoint: true jvm: args: - -Dcoherence.log=jdk diff --git a/test/e2e/local/spring_test.go b/test/e2e/local/spring_test.go index cca95fe64..3feb52a5a 100644 --- a/test/e2e/local/spring_test.go +++ b/test/e2e/local/spring_test.go @@ -27,11 +27,11 @@ func TestStartSpringFatJarCluster(t *testing.T) { AssertSpringEndpoint(t, pods) } -//func TestStartSpringBuildpacksCluster(t *testing.T) { -// testContext.CleanupAfterTest(t) -// _, pods := helper.AssertDeployments(testContext, t, "spring-buildpack-cluster.yaml") -// AssertSpringEndpoint(t, pods) -//} +func TestStartSpringBuildpacksCluster(t *testing.T) { + testContext.CleanupAfterTest(t) + _, pods := helper.AssertDeployments(testContext, t, "spring-buildpack-cluster.yaml") + AssertSpringEndpoint(t, pods) +} func TestStartSpringTwoCluster(t *testing.T) { testContext.CleanupAfterTest(t) @@ -63,6 +63,9 @@ func AssertSpringEndpoint(t *testing.T, pods []corev1.Pod) { url := fmt.Sprintf("http://127.0.0.1:%d/", ports["web"]) resp, err := client.Get(url) + if resp != nil { + defer resp.Body.Close() + } g.Expect(err).NotTo(HaveOccurred()) g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) } diff --git a/test/e2e/prometheus/prometheus_test.go b/test/e2e/prometheus/prometheus_test.go index 7f096a9d7..96039ff08 100644 --- a/test/e2e/prometheus/prometheus_test.go +++ b/test/e2e/prometheus/prometheus_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -219,6 +219,9 @@ func PrometheusAPIRequest(pod corev1.Pod, path string) (*PrometheusAPIResult, er url := fmt.Sprintf("http://127.0.0.1:%d%s%s", ports["web"], sep, path) resp, err := http.Get(url) + if resp != nil { + defer resp.Body.Close() + } if err != nil { return nil, err } diff --git a/test/e2e/remote/persistence-active-snapshot-security.yaml b/test/e2e/remote/persistence-active-snapshot-security.yaml index e811cf47d..4f25df21a 100644 --- a/test/e2e/remote/persistence-active-snapshot-security.yaml +++ b/test/e2e/remote/persistence-active-snapshot-security.yaml @@ -36,7 +36,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-active-snapshot.yaml b/test/e2e/remote/persistence-active-snapshot.yaml index 15a687843..7b15e8f60 100644 --- a/test/e2e/remote/persistence-active-snapshot.yaml +++ b/test/e2e/remote/persistence-active-snapshot.yaml @@ -31,7 +31,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-active.yaml b/test/e2e/remote/persistence-active.yaml index 0a7291347..6cfd9ee2c 100644 --- a/test/e2e/remote/persistence-active.yaml +++ b/test/e2e/remote/persistence-active.yaml @@ -25,7 +25,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-on-demand.yaml b/test/e2e/remote/persistence-on-demand.yaml index fbef9156a..9ae8d78bb 100644 --- a/test/e2e/remote/persistence-on-demand.yaml +++ b/test/e2e/remote/persistence-on-demand.yaml @@ -15,7 +15,7 @@ spec: port: 30000 jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence-snapshot.yaml b/test/e2e/remote/persistence-snapshot.yaml index b492b34d2..60cf407a2 100644 --- a/test/e2e/remote/persistence-snapshot.yaml +++ b/test/e2e/remote/persistence-snapshot.yaml @@ -25,7 +25,7 @@ spec: storage: 2Gi jvm: args: - - "-Dcoherence.k8s.operator.health.logs=true" + - "-Dcoherence.operator.health.logs=true" application: main: com.oracle.coherence.k8s.testing.RestServer ports: diff --git a/test/e2e/remote/persistence_test.go b/test/e2e/remote/persistence_test.go index 71f6b68cd..a2b40545c 100644 --- a/test/e2e/remote/persistence_test.go +++ b/test/e2e/remote/persistence_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -215,6 +215,9 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType) error req, err = http.NewRequest(httpMethod, url, nil) if err == nil { resp, err = client.Do(req) + if resp != nil { + _ = resp.Body.Close() + } if err == nil { break } @@ -240,6 +243,9 @@ func processSnapshotRequest(pod corev1.Pod, actionType snapshotActionType) error return false, err } resp, err = client.Do(req) + if resp != nil { + defer resp.Body.Close() + } if err != nil { fmt.Printf("Error in send idle check request: %v\n", url) return false, err diff --git a/test/e2e/remote/rolling-upgrade-with-persistence.yaml b/test/e2e/remote/rolling-upgrade-with-persistence.yaml index cf1d4dc13..39f1e2a7e 100644 --- a/test/e2e/remote/rolling-upgrade-with-persistence.yaml +++ b/test/e2e/remote/rolling-upgrade-with-persistence.yaml @@ -12,7 +12,7 @@ spec: periodSeconds: 10 jvm: args: - - -Dcoherence.k8s.operator.health.logs=true + - -Dcoherence.operator.health.logs=true coherence: cacheConfig: test-cache-config.xml management: diff --git a/test/e2e/remote/rolling-upgrade.yaml b/test/e2e/remote/rolling-upgrade.yaml index 563c2d3dd..e62c11c48 100644 --- a/test/e2e/remote/rolling-upgrade.yaml +++ b/test/e2e/remote/rolling-upgrade.yaml @@ -7,7 +7,7 @@ spec: version: one jvm: args: - - -Dcoherence.k8s.operator.health.logs=true + - -Dcoherence.operator.health.logs=true memory: heapSize: 256m