From e5db64d689bfd02214b02627215ddbe2ae273acf Mon Sep 17 00:00:00 2001 From: MikelAlejoBR Date: Tue, 23 Dec 2025 09:21:00 -0500 Subject: [PATCH] feature: Make targets for debugging services and operators Adds a new Make target which triggers build in the underlying services and operators which end up building the images without any code optimizations and with Delve on them. Once pushed and deployed to the local OpenShift cluster, it patches the host operator, the member operator and the registration service to launch them with the Delve executable, which allows debugging them on port 50000 after port-forwarding to those pods. SANDBOX-1561 --- README.adoc | 10 +++++ deploy/host-operator/dev/toolchainconfig.yaml | 1 + make/dev.mk | 39 +++++++++++++++++++ make/test.mk | 14 ++++++- scripts/ci/manage-host-operator.sh | 9 ++++- scripts/ci/manage-member-operator.sh | 7 +++- scripts/ci/manage-operator.sh | 14 ++++++- testsupport/init.go | 2 +- 8 files changed, 88 insertions(+), 8 deletions(-) diff --git a/README.adoc b/README.adoc index ebde4184a..5641a7989 100644 --- a/README.adoc +++ b/README.adoc @@ -151,6 +151,16 @@ All e2e resources (host operator, member operator, registration-service, CRDs, e * `make dev-deploy-e2e-local` - deploys the same resources as `make test-e2e-local` in dev environment but doesn't run tests. +* `make dev-deploy-e2e-local-debug` - deploys the same resources as `make test-e2e-local` in the local OpenShift +instance, but builds the services and the operators without any code optimizations. It also ships Delve in the images, +and launches those services with it, which leaves the debugger listening on port `50000`. The default architecture for +which the binaries are built are `linux-amd64`, but you can override it with `export TARGET_ARCH=${YOUR_ARCH}`. Then, +you can simply `oc port-forward ${POD} 50000:50000` and connect to them with your favorite IDE. The services that are +built like that are: +** The registration service. +** The host operator controller manager. +** The member operator controller manager. + * `make dev-deploy-e2e` - deploys the same resources as `make test-e2e` in dev environment but doesn't run tests. * `make deploy-single-member-e2e-latest` - deploys the same resources (using the latest and greatest images of Toolchain operators) as `make test-e2e` but with only one member and doesn't run tests. diff --git a/deploy/host-operator/dev/toolchainconfig.yaml b/deploy/host-operator/dev/toolchainconfig.yaml index b221113ed..5979a94d6 100644 --- a/deploy/host-operator/dev/toolchainconfig.yaml +++ b/deploy/host-operator/dev/toolchainconfig.yaml @@ -10,6 +10,7 @@ spec: deactivationDomainsExcluded: '@redhat.com' registrationService: environment: 'dev' + replicas: 1 members: default: autoscaler: diff --git a/make/dev.mk b/make/dev.mk index a9b4f5673..7abc73cda 100644 --- a/make/dev.mk +++ b/make/dev.mk @@ -39,6 +39,45 @@ setup-dev-sso: .PHONY: dev-deploy-e2e-local dev-deploy-e2e-local: deploy-e2e-local-to-dev-namespaces print-reg-service-link +# Builds the services' and operators' images with the debugger in it, so that +# then an IDE can be connected to them. Since the targets down the line use +# the default namespaces, we can use them to patch the required CRs in order +# to launch the binaries with Delve. +.ONESHELL: +.PHONY: dev-deploy-e2e-local-debug +dev-deploy-e2e-local-debug: export DEBUG_MODE=true +dev-deploy-e2e-local-debug: + $(MAKE) dev-deploy-e2e-local + + # Get the CSVs for the host and member operators, in order to be able to + # patch them. + HOST_CSV_NAME=$$(oc get --namespace="${DEFAULT_HOST_NS}" --output name ClusterServiceVersion) + MEMBER_CSV_NAME=$$(oc get --namespace="${DEFAULT_MEMBER_NS}" --output name ClusterServiceVersion) + + # Patch the host operator indicating which command the registration + # service should be run with. The command simply adds an environment + # variable to the operator which then makes sure that the registration + # service is run with Delve, in case the user wants to connect to it. + if ! oc get "$${HOST_CSV_NAME}" --output jsonpath="{.spec.install.spec.deployments[0].spec.template.spec.containers[1].env}" | grep -q "REGISTRATION_SERVICE_COMMAND"; then \ + oc patch --namespace="${DEFAULT_HOST_NS}" "$${HOST_CSV_NAME}" --type='json' --patch='[{"op": "add", "path": "/spec/install/spec/deployments/0/spec/template/spec/containers/1/env/-", "value": {"name": "REGISTRATION_SERVICE_COMMAND", "value": "[\"dlv\", \"--listen=:50000\", \"--headless\", \"--continue\", \"--api-version=2\", \"--accept-multiclient\", \"exec\", \"/usr/local/bin/registration-service\"]"}}]' + + # Wait for the registration service's command to have the "dlv" bit, and the rollout for its deployment to be + # complete. + @echo "Waiting for the registration service's deployment to get updated..." + oc wait --namespace="${DEFAULT_HOST_NS}" --timeout=3m --for=jsonpath='{.spec.template.spec.containers[0].command[0]}'="dlv" "deployment/registration-service" + oc rollout status --namespace="${DEFAULT_HOST_NS}" --timeout=3m deployment/registration-service + fi + + # Patch the host-operator and member-operator CSVs to make them run with + # Delve. + oc patch --namespace="${DEFAULT_HOST_NS}" "$${HOST_CSV_NAME}" --type='json' --patch='[{"op": "replace", "path": "/spec/install/spec/deployments/0/spec/template/spec/containers/1/args", "value": []}, {"op": "replace", "path": "/spec/install/spec/deployments/0/spec/template/spec/containers/1/command", "value": ["dlv", "--listen=:50000", "--headless", "--continue", "--api-version=2", "--accept-multiclient", "exec", "/usr/local/bin/host-operator", "--", "--health-probe-bind-address=:8081", "--metrics-bind-address=127.0.0.1:8080", "--leader-elect"]}]' + @echo "Waiting for the host operator to be ready..." + oc wait --namespace "${DEFAULT_HOST_NS}" "$${HOST_CSV_NAME}" --for=jsonpath='{.status.phase}'=Succeeded --timeout=300s + + oc patch --namespace="${DEFAULT_MEMBER_NS}" "$${MEMBER_CSV_NAME}" --type='json' --patch='[{"op": "replace", "path": "/spec/install/spec/deployments/0/spec/template/spec/containers/0/args", "value": []}, {"op": "replace", "path": "/spec/install/spec/deployments/0/spec/template/spec/containers/0/command", "value": ["dlv", "--listen=:50000", "--headless", "--continue", "--api-version=2", "--accept-multiclient", "exec", "/usr/local/bin/member-operator", "--", "--health-probe-bind-address=:8081", "--metrics-bind-address=127.0.0.1:8080", "--leader-elect"]}]' + @echo "Waiting for the member operator to be ready..." + oc wait --namespace "${DEFAULT_MEMBER_NS}" "$${MEMBER_CSV_NAME}" --for=jsonpath='{.status.phase}'=Succeeded --timeout=300s + .PHONY: dev-deploy-e2e-local-two-members dev-deploy-e2e-local-two-members: deploy-e2e-local-to-dev-namespaces-two-members print-reg-service-link diff --git a/make/test.mk b/make/test.mk index c1653eb55..53abd7636 100644 --- a/make/test.mk +++ b/make/test.mk @@ -331,6 +331,11 @@ ifneq (${FORCED_TAG},"") $(eval FORCED_TAG_PARAM = -ft ${FORCED_TAG}) endif endif +ifneq (${DEBUG_MODE},"") + ifneq (${DEBUG_MODE},) + $(eval DEBUG_MODE_PARAM = --debug-mode) + endif +endif ifeq ($(DEPLOY_LATEST),true) @echo "Installing latest version of the member-operator in namespace ${MEMBER_NS}" ${KSCTL_BIN_DIR}ksctl adm install-operator member --kubeconfig "$(or ${KUBECONFIG}, ${HOME}/.kube/config)" --namespace ${MEMBER_NS} ${KSCTL_INSTALL_TIMEOUT_PARAM} -y @@ -340,7 +345,7 @@ ifeq ($(DEPLOY_LATEST),true) endif else @echo "Installing specific version of the member-operator" - scripts/ci/manage-member-operator.sh -po ${PUBLISH_OPERATOR} -io ${INSTALL_OPERATOR} -mn ${MEMBER_NS} ${MEMBER_REPO_PATH_PARAM} -qn ${QUAY_NAMESPACE} -ds ${DATE_SUFFIX} ${MEMBER_NS_2_PARAM} ${FORCED_TAG_PARAM} + scripts/ci/manage-member-operator.sh -po ${PUBLISH_OPERATOR} -io ${INSTALL_OPERATOR} -mn ${MEMBER_NS} ${MEMBER_REPO_PATH_PARAM} -qn ${QUAY_NAMESPACE} -ds ${DATE_SUFFIX} ${MEMBER_NS_2_PARAM} ${FORCED_TAG_PARAM} ${DEBUG_MODE_PARAM} endif .PHONY: get-and-publish-host-operator @@ -360,12 +365,17 @@ ifneq (${FORCED_TAG},"") $(eval FORCED_TAG_PARAM = -ft ${FORCED_TAG}) endif endif +ifneq (${DEBUG_MODE},"") + ifneq (${DEBUG_MODE},) + $(eval DEBUG_MODE_PARAM = --debug-mode) + endif +endif ifeq ($(DEPLOY_LATEST),true) @echo "Installing latest version of the host-operator" ${KSCTL_BIN_DIR}ksctl adm install-operator host --kubeconfig "$(or ${KUBECONFIG}, ${HOME}/.kube/config)" --namespace ${HOST_NS} ${KSCTL_INSTALL_TIMEOUT_PARAM} -y else @echo "Installing specific version of the host-operator" - scripts/ci/manage-host-operator.sh -po ${PUBLISH_OPERATOR} -io ${INSTALL_OPERATOR} -hn ${HOST_NS} ${HOST_REPO_PATH_PARAM} -ds ${DATE_SUFFIX} -qn ${QUAY_NAMESPACE} ${REG_REPO_PATH_PARAM} ${FORCED_TAG_PARAM} + scripts/ci/manage-host-operator.sh -po ${PUBLISH_OPERATOR} -io ${INSTALL_OPERATOR} -hn ${HOST_NS} ${HOST_REPO_PATH_PARAM} -ds ${DATE_SUFFIX} -qn ${QUAY_NAMESPACE} ${REG_REPO_PATH_PARAM} ${FORCED_TAG_PARAM} ${DEBUG_MODE_PARAM} endif ########################################################### diff --git a/scripts/ci/manage-host-operator.sh b/scripts/ci/manage-host-operator.sh index 8918356c5..17664eebb 100755 --- a/scripts/ci/manage-host-operator.sh +++ b/scripts/ci/manage-host-operator.sh @@ -11,6 +11,7 @@ user_help () { echo "-rr, --reg-repo-path Path to the registation service repo" echo "-ds, --date-suffix Date suffix to be added to some resources that are created" echo "-ft, --forced-tag Forces a tag to be set to all built images. In the case deployment the tag is used for index image in the created CatalogSource" + echo "-dm, --debug-mode Enables debug builds. The operator is built and pushed to quay with the Delve executable included in the image" echo "-h, --help To show this help text" echo "" exit 0 @@ -68,6 +69,10 @@ read_arguments() { FORCED_TAG=$1 shift ;; + -dm|--debug-mode) + DEBUG_MODE=true + shift + ;; *) echo "$1 is not a recognized flag!" >> /dev/stderr user_help @@ -96,7 +101,7 @@ if [[ -n "${CI}${REG_REPO_PATH}${HOST_REPO_PATH}" ]] && [[ $(echo ${REPO_NAME} | set_tags if [[ ${PUBLISH_OPERATOR} == "true" ]]; then - push_image + push_image "${DEBUG_MODE}" REG_SERV_IMAGE_LOC=${IMAGE_LOC} REG_REPO_PATH=${REPOSITORY_PATH} fi @@ -108,7 +113,7 @@ if [[ -n "${CI}${REG_REPO_PATH}${HOST_REPO_PATH}" ]] && [[ $(echo ${REPO_NAME} | set_tags if [[ ${PUBLISH_OPERATOR} == "true" ]]; then - push_image + push_image "${DEBUG_MODE}" OPERATOR_IMAGE_LOC=${IMAGE_LOC} make -C ${REPOSITORY_PATH} publish-current-bundle INDEX_IMAGE_TAG=${BUNDLE_AND_INDEX_TAG} BUNDLE_TAG=${BUNDLE_AND_INDEX_TAG} QUAY_NAMESPACE=${QUAY_NAMESPACE} OTHER_REPO_PATH=${REG_REPO_PATH} OTHER_REPO_IMAGE_LOC=${REG_SERV_IMAGE_LOC} IMAGE=${OPERATOR_IMAGE_LOC} fi diff --git a/scripts/ci/manage-member-operator.sh b/scripts/ci/manage-member-operator.sh index 51584903f..7ab472e14 100755 --- a/scripts/ci/manage-member-operator.sh +++ b/scripts/ci/manage-member-operator.sh @@ -11,6 +11,7 @@ user_help () { echo "-mr, --member-repo-path Path to the member operator repo" echo "-ds, --date-suffix Date suffix to be added to some resources that are created" echo "-ft, --forced-tag Forces a tag to be set to all built images. In the case deployment the tag is used for index image in the created CatalogSource" + echo "-dm, --debug-mode Enables debug builds. The operator is built and pushed to quay with the Delve executable included in the image" echo "-h, --help To show this help text" echo "" exit 0 @@ -67,6 +68,10 @@ read_arguments() { FORCED_TAG=$1 shift ;; + -dm|--debug-mode) + DEBUG_MODE=true + shift + ;; *) echo "$1 is not a recognized flag!" >> /dev/stderr user_help @@ -95,7 +100,7 @@ if [[ -n "${CI}${MEMBER_REPO_PATH}" ]] && [[ $(echo ${REPO_NAME} | sed 's/"//g') set_tags if [[ ${PUBLISH_OPERATOR} == "true" ]]; then - push_image + push_image "${DEBUG_MODE}" OPERATOR_IMAGE_LOC=${IMAGE_LOC} make -C ${REPOSITORY_PATH} publish-current-bundle INDEX_IMAGE_TAG=${BUNDLE_AND_INDEX_TAG} BUNDLE_TAG=${BUNDLE_AND_INDEX_TAG} QUAY_NAMESPACE=${QUAY_NAMESPACE} IMAGE=${OPERATOR_IMAGE_LOC} diff --git a/scripts/ci/manage-operator.sh b/scripts/ci/manage-operator.sh index cb64a69f4..926c4ce3f 100755 --- a/scripts/ci/manage-operator.sh +++ b/scripts/ci/manage-operator.sh @@ -45,11 +45,21 @@ set_tags() { } push_image() { + # When the "${DEBUG_MODE}" argument is passed, we instruct Make to push + # the "debug" images with Delve on them. + if [[ $1 == "true" ]]; then + DEBUG_MODE_SUFFIX="-debug" + else + DEBUG_MODE_SUFFIX="" + fi + + # Set a default image builder in case none has been specified. + IMAGE_BUILDER="${IMAGE_BUILDER:-podman}" + GIT_COMMIT_ID=$(git --git-dir=${REPOSITORY_PATH}/.git --work-tree=${REPOSITORY_PATH} rev-parse --short HEAD) IMAGE_LOC=quay.io/codeready-toolchain/${REPOSITORY_NAME}:${GIT_COMMIT_ID} if is_provided_or_paired; then - IMAGE_BUILDER=${IMAGE_BUILDER:-"podman"} - make -C ${REPOSITORY_PATH} ${IMAGE_BUILDER}-push QUAY_NAMESPACE=${QUAY_NAMESPACE} IMAGE_TAG=${TAGS} + make -C ${REPOSITORY_PATH} ${IMAGE_BUILDER}-push${DEBUG_MODE_SUFFIX} QUAY_NAMESPACE=${QUAY_NAMESPACE} IMAGE_TAG=${TAGS} IMAGE_LOC=quay.io/${QUAY_NAMESPACE}/${REPOSITORY_NAME}:${TAGS} fi } diff --git a/testsupport/init.go b/testsupport/init.go index 7fb8ce722..131b30619 100644 --- a/testsupport/init.go +++ b/testsupport/init.go @@ -91,7 +91,7 @@ func waitForOperators(t *testing.T) { initHostAwait.WaitForDeploymentToGetReady(t, "host-operator-controller-manager", 1) // wait for registration service to be ready - initHostAwait.WaitForDeploymentToGetReady(t, "registration-service", 3) + initHostAwait.WaitForDeploymentToGetReady(t, "registration-service", 1) // set registration service values registrationServiceRoute, err := initHostAwait.WaitForRouteToBeAvailable(t, registrationServiceNs, "registration-service", "/")