From eb081813391cc12d7dde18f21577c0cc6056d6cf Mon Sep 17 00:00:00 2001 From: Nir Argaman Date: Thu, 13 Mar 2025 11:34:32 +1100 Subject: [PATCH] Use templates for deploy-on-kind and use envconfig for configuration * Rewrite deploy and delete operation to use the template files (both Openshift and Kind) * Change configuration file to be created using envconfig library Signed-off-by: Nir Argaman --- .github/workflows/kind.yml | 5 + .gitignore | 1 - Makefile | 123 +++++++++---- cmd/planner-api/migrate.go | 6 +- cmd/planner-api/run.go | 5 +- .../k8s/migration-planner-agent-service.yaml | 17 -- .../k8s/migration-planner-image-service.yaml | 17 -- deploy/k8s/migration-planner-service.yaml | 17 -- deploy/k8s/migration-planner-ui-service.yaml | 12 -- deploy/k8s/migration-planner-ui.yaml | 21 --- deploy/k8s/migration-planner-ui.yaml.template | 21 --- deploy/k8s/migration-planner.yaml.template | 75 -------- deploy/k8s/postgres-deployment.yaml | 63 ------- deploy/k8s/postgres-secret.yaml | 29 --- deploy/templates/postgres-template.yml | 1 - deploy/templates/service-template.yml | 106 +++++++++-- doc/deployment.md | 2 +- go.mod | 1 + go.sum | 2 + internal/auth/agent_authenticator_test.go | 2 +- internal/config/config.go | 166 ++++-------------- internal/service/agent/handler_test.go | 2 +- internal/service/source_test.go | 2 +- internal/store/agent_test.go | 2 +- internal/store/gorm.go | 2 +- internal/store/image_test.go | 2 +- internal/store/key_test.go | 2 +- internal/store/source_test.go | 2 +- internal/store/store_test.go | 2 +- test/e2e/e2e_test.go | 10 +- 30 files changed, 232 insertions(+), 486 deletions(-) delete mode 100644 deploy/k8s/migration-planner-agent-service.yaml delete mode 100644 deploy/k8s/migration-planner-image-service.yaml delete mode 100644 deploy/k8s/migration-planner-service.yaml delete mode 100644 deploy/k8s/migration-planner-ui-service.yaml delete mode 100644 deploy/k8s/migration-planner-ui.yaml delete mode 100644 deploy/k8s/migration-planner-ui.yaml.template delete mode 100644 deploy/k8s/migration-planner.yaml.template delete mode 100644 deploy/k8s/postgres-deployment.yaml delete mode 100644 deploy/k8s/postgres-secret.yaml diff --git a/.github/workflows/kind.yml b/.github/workflows/kind.yml index 32f2fdac..fd283147 100644 --- a/.github/workflows/kind.yml +++ b/.github/workflows/kind.yml @@ -19,6 +19,11 @@ jobs: - name: Checkout the code uses: actions/checkout@v2 + - name: Setup oc + uses: redhat-actions/openshift-tools-installer@v1 + with: + oc: "4" + - name: Set env variables run: | export "REGISTRY_IP=$(ip addr show eth0 | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+')" diff --git a/.gitignore b/.gitignore index aadb8165..00e3701a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,4 @@ examples/config.yaml /tmp/ cover.out /docker-config/ -deploy/k8s/migration-planner.yaml deploy/k8s/vcsim.yaml diff --git a/Makefile b/Makefile index 90632b91..88cc00ab 100644 --- a/Makefile +++ b/Makefile @@ -8,15 +8,19 @@ TIMEOUT ?= 30m VERBOSE ?= false MIGRATION_PLANNER_AGENT_IMAGE ?= quay.io/kubev2v/migration-planner-agent MIGRATION_PLANNER_API_IMAGE ?= quay.io/kubev2v/migration-planner-api +MIGRATION_PLANNER_API_IMAGE_TAG ?= latest MIGRATION_PLANNER_API_IMAGE_PULL_POLICY ?= Always MIGRATION_PLANNER_UI_IMAGE ?= quay.io/kubev2v/migration-planner-ui +MIGRATION_PLANNER_UI_IMAGE_TAG ?= latest MIGRATION_PLANNER_NAMESPACE ?= assisted-migration +MIGRATION_PLANNER_REPLICAS ?= 1 PERSISTENT_DISK_DEVICE ?= /dev/sda -INSECURE_REGISTRY ?= true +INSECURE_REGISTRY ?= "true" REGISTRY_TAG ?= latest DOWNLOAD_RHCOS ?= true KUBECTL ?= kubectl IFACE ?= eth0 +GREP ?= grep PODMAN ?= podman DOCKER_CONF ?= $(CURDIR)/docker-config DOCKER_AUTH_FILE ?= ${DOCKER_CONF}/auth.json @@ -55,7 +59,7 @@ help: @echo " clean: clean up all containers and volumes" GOBIN = $(shell pwd)/bin -GINKGO = $(GOBIN)/ginkgo +GINKGO ?= $(GOBIN)/ginkgo ginkgo: ## Download ginkgo locally if necessary. ifeq (, $(shell which ginkgo 2> /dev/null)) go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.15.0 @@ -136,37 +140,86 @@ push-agent-container: migration-planner-agent-container quay-login push-containers: push-api-container push-agent-container -deploy-on-kind: - sed "s|@MIGRATION_PLANNER_AGENT_IMAGE@|$(MIGRATION_PLANNER_AGENT_IMAGE)|g; \ - s|@INSECURE_REGISTRY@|$(INSECURE_REGISTRY)|g; \ - s|@MIGRATION_PLANNER_API_IMAGE_PULL_POLICY@|$(MIGRATION_PLANNER_API_IMAGE_PULL_POLICY)|g; \ - s|@MIGRATION_PLANNER_API_IMAGE@|$(MIGRATION_PLANNER_API_IMAGE)|g; \ - s|@PERSISTENT_DISK_DEVICE@|$(PERSISTENT_DISK_DEVICE)|g" \ - deploy/k8s/migration-planner.yaml.template > deploy/k8s/migration-planner.yaml - $(KUBECTL) apply -n "${MIGRATION_PLANNER_NAMESPACE}" -f 'deploy/k8s/*-service.yaml' - $(KUBECTL) apply -n "${MIGRATION_PLANNER_NAMESPACE}" -f 'deploy/k8s/*-secret.yaml' - config_server=$$(ip addr show ${IFACE}| grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+'); \ - migration_planner_image_url=$$(ip addr show ${IFACE}| grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+'); \ - $(KUBECTL) create secret generic migration-planner-secret -n "${MIGRATION_PLANNER_NAMESPACE}" --from-literal=migration_planner_image_url=http://$$migration_planner_image_url --from-literal=config_server=http://$$config_server:7443 --from-literal=config_server_ui=https://$$config_server_ui/migrate/wizard || true - $(KUBECTL) apply -n "${MIGRATION_PLANNER_NAMESPACE}" -f deploy/k8s/ - deploy-on-openshift: - sed "s|@MIGRATION_PLANNER_AGENT_IMAGE@|$(MIGRATION_PLANNER_AGENT_IMAGE)|g; \ - s|@INSECURE_REGISTRY@|$(INSECURE_REGISTRY)|g; \ - s|@MIGRATION_PLANNER_API_IMAGE_PULL_POLICY@|$(MIGRATION_PLANNER_API_IMAGE_PULL_POLICY)|g; \ - s|@MIGRATION_PLANNER_API_IMAGE@|$(MIGRATION_PLANNER_API_IMAGE)|g; \ - s|@PERSISTENT_DISK_DEVICE@|$(PERSISTENT_DISK_DEVICE)|g" \ - deploy/k8s/migration-planner.yaml.template > deploy/k8s/migration-planner.yaml - sed 's|@MIGRATION_PLANNER_UI_IMAGE@|$(MIGRATION_PLANNER_UI_IMAGE)|g' deploy/k8s/migration-planner-ui.yaml.template > deploy/k8s/migration-planner-ui.yaml - ls deploy/k8s | awk '/secret|service/' | xargs -I {} oc apply -n ${MIGRATION_PLANNER_NAMESPACE} -f deploy/k8s/{} - oc create route edge planner --service=migration-planner-ui -n ${MIGRATION_PLANNER_NAMESPACE} || true - oc expose service migration-planner-agent -n ${MIGRATION_PLANNER_NAMESPACE} --name planner-agent || true - oc expose service migration-planner-image -n ${MIGRATION_PLANNER_NAMESPACE} --name planner-image || true - config_server=$$(oc get route planner-agent -o jsonpath='{.spec.host}'); \ - migration_planner_image_url=$$(oc get route planner-image -o jsonpath='{.spec.host}'); \ - config_server_ui=$$(oc get route planner -o jsonpath='{.spec.host}'); \ - oc create secret generic migration-planner-secret -n ${MIGRATION_PLANNER_NAMESPACE} --from-literal=migration_planner_image_url=http://$$migration_planner_image_url --from-literal=config_server=http://$$config_server --from-literal=config_server_ui=https://$$config_server_ui/migrate/wizard || true - ls deploy/k8s | awk '! /secret|service|template/' | xargs -I {} oc apply -n ${MIGRATION_PLANNER_NAMESPACE} -f deploy/k8s/{} + @openshift_base_url=$$(oc whoami --show-server | sed -E 's~https?://api\.~~; s~:[0-9]+/?$$~~'); \ + openshift_project=$$(oc project -q); \ + echo "*** Deploy Migration Planner on Openshift. Project: $${openshift_project}, Base URL: $${openshift_base_url} ***";\ + oc process -f deploy/templates/postgres-template.yml | oc apply -f -; \ + oc process -f deploy/templates/service-template.yml \ + -p MIGRATION_PLANNER_IMAGE=$(MIGRATION_PLANNER_API_IMAGE) \ + -p MIGRATION_PLANNER_AGENT_IMAGE=$(MIGRATION_PLANNER_AGENT_IMAGE) \ + -p MIGRATION_PLANNER_REPLICAS=${MIGRATION_PLANNER_REPLICAS} \ + -p IMAGE_TAG=$(MIGRATION_PLANNER_API_IMAGE_TAG) \ + -p MIGRATION_PLANNER_URL=http://planner-agent-$${openshift_project}.apps.$${openshift_base_url} \ + -p MIGRATION_PLANNER_UI_URL=http://planner-ui-$${openshift_project}.apps.$${openshift_base_url} \ + -p MIGRATION_PLANNER_IMAGE_URL=http://planner-image-$${openshift_project}.apps.$${openshift_base_url} \ + | oc apply -f -; \ + oc process -f https://raw.githubusercontent.com/kubev2v/migration-planner-ui/refs/heads/main/deploy/templates/ui-template.yml \ + -p MIGRATION_PLANNER_UI_IMAGE=$(MIGRATION_PLANNER_UI_IMAGE) \ + -p MIGRATION_PLANNER_REPLICAS=$(MIGRATION_PLANNER_REPLICAS) \ + -p IMAGE_TAG=$(MIGRATION_PLANNER_UI_IMAGE_TAG) \ + | oc apply -f -; \ + oc expose service migration-planner-agent --name planner-agent; \ + oc expose service migration-planner-ui --name planner-ui; \ + oc expose service migration-planner-image --name planner-image; \ + echo "*** Migration Planner has been deployed successfully on Openshift ***"; \ + echo "*** Open UI: http://planner-ui-$${openshift_project}.apps.$${openshift_base_url}" + +delete-from-openshift: + @openshift_base_url=$$(oc whoami --show-server | sed -E 's~https?://api\.~~; s~:[0-9]+/?$$~~'); \ + openshift_project=$$(oc project -q); \ + echo "*** Delete Migration Planner from Openshift. Project: $${openshift_project}, Base URL: $${openshift_base_url} ***"; \ + oc process -f https://raw.githubusercontent.com/kubev2v/migration-planner-ui/refs/heads/main/deploy/templates/ui-template.yml \ + -p MIGRATION_PLANNER_UI_IMAGE=$(MIGRATION_PLANNER_UI_IMAGE) \ + -p MIGRATION_PLANNER_REPLICAS=$(MIGRATION_PLANNER_REPLICAS) \ + -p IMAGE_TAG=$(MIGRATION_PLANNER_UI_IMAGE_TAG) \ + | oc delete -f -; \ + openshift_base_url=$$(oc whoami --show-server | sed -E 's~https?://api\.~~; s~:[0-9]+/?$$~~'); \ + openshift_project=$$(oc project -q); \ + oc process -f deploy/templates/service-template.yml \ + -p MIGRATION_PLANNER_IMAGE=$(MIGRATION_PLANNER_API_IMAGE) \ + -p MIGRATION_PLANNER_AGENT_IMAGE=$(MIGRATION_PLANNER_AGENT_IMAGE) \ + -p MIGRATION_PLANNER_REPLICAS=$(MIGRATION_PLANNER_REPLICAS) \ + -p IMAGE_TAG=$(MIGRATION_PLANNER_API_IMAGE_TAG) \ + -p MIGRATION_PLANNER_URL=http://planner-agent-$${openshift_project}.apps.$${openshift_base_url} \ + -p MIGRATION_PLANNER_UI_URL=http://planner-ui-$${openshift_project}.apps.$${openshift_base_url} \ + -p MIGRATION_PLANNER_IMAGE_URL=http://planner-image-$${openshift_project}.apps.$${openshift_base_url} \ + | oc delete -f -; \ + oc process -f deploy/templates/postgres-template.yml | oc delete -f -; \ + oc delete route planner-agent planner-ui planner-image; \ + echo "*** Migration Planner has been deleted successfully from Openshift ***" + +deploy-on-kind: + @inet_ip=$$(ip addr show ${IFACE} | $(GREP) -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+'); \ + echo "*** Deploy Migration Planner on Kind. Namespace: $${MIGRATION_PLANNER_NAMESPACE}, inet_ip: $${inet_ip}, PERSISTENT_DISK_DEVICE: $${PERSISTENT_DISK_DEVICE} ***"; \ + oc process --local -f deploy/templates/postgres-template.yml | $(KUBECTL) apply -n "${MIGRATION_PLANNER_NAMESPACE}" -f -; \ + oc process --local -f deploy/templates/service-template.yml \ + -p MIGRATION_PLANNER_URL=http://$${inet_ip}:7443 \ + -p MIGRATION_PLANNER_UI_URL=http://$${inet_ip}:3333 \ + -p MIGRATION_PLANNER_IMAGE_URL=http://$${inet_ip}:11443 \ + -p MIGRATION_PLANNER_API_IMAGE_PULL_POLICY=Never \ + -p MIGRATION_PLANNER_IMAGE=$(MIGRATION_PLANNER_API_IMAGE) \ + -p MIGRATION_PLANNER_AGENT_IMAGE=$(MIGRATION_PLANNER_AGENT_IMAGE) \ + -p MIGRATION_PLANNER_REPLICAS=$(MIGRATION_PLANNER_REPLICAS) \ + -p PERSISTENT_DISK_DEVICE=$(PERSISTENT_DISK_DEVICE) \ + -p INSECURE_REGISTRY=$(INSECURE_REGISTRY) \ + | $(KUBECTL) apply -n "${MIGRATION_PLANNER_NAMESPACE}" -f -; \ + echo "*** Migration Planner has been deployed successfully on Kind ***" + +delete-from-kind: + inet_ip=$$(ip addr show ${IFACE} | $(GREP) -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+'); \ + oc process --local -f deploy/templates/service-template.yml \ + -p MIGRATION_PLANNER_URL=http://$${inet_ip}:7443 \ + -p MIGRATION_PLANNER_UI_URL=http://$${inet_ip}:3333 \ + -p MIGRATION_PLANNER_IMAGE_URL=http://$${inet_ip}:11443 \ + -p MIGRATION_PLANNER_API_IMAGE_PULL_POLICY=Never \ + -p MIGRATION_PLANNER_IMAGE=$(MIGRATION_PLANNER_API_IMAGE) \ + -p MIGRATION_PLANNER_AGENT_IMAGE=$(MIGRATION_PLANNER_AGENT_IMAGE) \ + -p MIGRATION_PLANNER_REPLICAS=$(MIGRATION_PLANNER_REPLICAS) \ + -p PERSISTENT_DISK_DEVICE=$(PERSISTENT_DISK_DEVICE) \ + -p INSECURE_REGISTRY=$(INSECURE_REGISTRY) \ + | $(KUBECTL) delete -n "${MIGRATION_PLANNER_NAMESPACE}" -f -; \ + oc process --local -f deploy/templates/postgres-template.yml | $(KUBECTL) delete -n "${MIGRATION_PLANNER_NAMESPACE}" -f - deploy-local-obs: @podman play kube --network host deploy/observability.yml @@ -174,12 +227,6 @@ deploy-local-obs: undeploy-local-obs: @podman kube down deploy/observability.yml -undeploy-on-openshift: - oc delete route planner || true - oc delete route planner-agent || true - oc delete secret migration-planner-secret || true - oc delete -f deploy/k8s || true - bin: mkdir -p bin diff --git a/cmd/planner-api/migrate.go b/cmd/planner-api/migrate.go index 6db79153..dfb15c02 100644 --- a/cmd/planner-api/migrate.go +++ b/cmd/planner-api/migrate.go @@ -18,11 +18,7 @@ var migrateCmd = &cobra.Command{ undo := zap.ReplaceGlobals(logger) defer undo() - if configFile == "" { - configFile = config.ConfigFile() - } - - cfg, err := config.Load(configFile) + cfg, err := config.New() if err != nil { zap.S().Fatalf("reading configuration: %v", err) } diff --git a/cmd/planner-api/run.go b/cmd/planner-api/run.go index 0c5c7c00..e0cd7b3f 100644 --- a/cmd/planner-api/run.go +++ b/cmd/planner-api/run.go @@ -29,10 +29,7 @@ var runCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { defer zap.S().Info("API service stopped") - if configFile == "" { - configFile = config.ConfigFile() - } - cfg, err := config.LoadOrGenerate(configFile) + cfg, err := config.New() if err != nil { zap.S().Fatalf("reading configuration: %v", err) } diff --git a/deploy/k8s/migration-planner-agent-service.yaml b/deploy/k8s/migration-planner-agent-service.yaml deleted file mode 100644 index 7f2572e5..00000000 --- a/deploy/k8s/migration-planner-agent-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: migration-planner - name: migration-planner-agent -spec: - ports: - - name: migration-planner-agent - port: 7443 - protocol: TCP - targetPort: 7443 - selector: - app: migration-planner - type: LoadBalancer -status: - loadBalancer: {} diff --git a/deploy/k8s/migration-planner-image-service.yaml b/deploy/k8s/migration-planner-image-service.yaml deleted file mode 100644 index 61450608..00000000 --- a/deploy/k8s/migration-planner-image-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: migration-planner - name: migration-planner-image -spec: - ports: - - name: migration-planner-image - port: 11443 - protocol: TCP - targetPort: 11443 - selector: - app: migration-planner - type: LoadBalancer -status: - loadBalancer: {} diff --git a/deploy/k8s/migration-planner-service.yaml b/deploy/k8s/migration-planner-service.yaml deleted file mode 100644 index b53a1ec6..00000000 --- a/deploy/k8s/migration-planner-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: migration-planner - name: migration-planner -spec: - ports: - - name: migration-planner - port: 3443 - protocol: TCP - targetPort: 3443 - selector: - app: migration-planner - type: LoadBalancer -status: - loadBalancer: {} diff --git a/deploy/k8s/migration-planner-ui-service.yaml b/deploy/k8s/migration-planner-ui-service.yaml deleted file mode 100644 index 48dea000..00000000 --- a/deploy/k8s/migration-planner-ui-service.yaml +++ /dev/null @@ -1,12 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: migration-planner-ui -spec: - type: LoadBalancer - ports: - - port: 8080 - targetPort: 8080 - protocol: TCP - selector: - app: migration-planner-ui diff --git a/deploy/k8s/migration-planner-ui.yaml b/deploy/k8s/migration-planner-ui.yaml deleted file mode 100644 index 7d344eff..00000000 --- a/deploy/k8s/migration-planner-ui.yaml +++ /dev/null @@ -1,21 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: migration-planner-ui -spec: - replicas: 1 - selector: - matchLabels: - app: migration-planner-ui - template: - metadata: - labels: - app: migration-planner-ui - spec: - containers: - - name: migration-planner-ui - image: quay.io/kubev2v/migration-planner-ui - imagePullPolicy: Always - ports: - - containerPort: 8080 - restartPolicy: Always diff --git a/deploy/k8s/migration-planner-ui.yaml.template b/deploy/k8s/migration-planner-ui.yaml.template deleted file mode 100644 index e940cd13..00000000 --- a/deploy/k8s/migration-planner-ui.yaml.template +++ /dev/null @@ -1,21 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - name: migration-planner-ui -spec: - replicas: 1 - selector: - matchLabels: - app: migration-planner-ui - template: - metadata: - labels: - app: migration-planner-ui - spec: - containers: - - name: migration-planner-ui - image: @MIGRATION_PLANNER_UI_IMAGE@ - imagePullPolicy: Always - ports: - - containerPort: 8080 - restartPolicy: Always diff --git a/deploy/k8s/migration-planner.yaml.template b/deploy/k8s/migration-planner.yaml.template deleted file mode 100644 index c10056da..00000000 --- a/deploy/k8s/migration-planner.yaml.template +++ /dev/null @@ -1,75 +0,0 @@ -apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 -kind: Deployment -metadata: - name: migration-planner -spec: - selector: - matchLabels: - app: migration-planner - replicas: 1 - template: - metadata: - labels: - app: migration-planner - spec: - containers: - - name: migration-planner - resources: - limits: - cpu: 500m - memory: 2000Mi - requests: - cpu: 300m - memory: 400Mi - image: @MIGRATION_PLANNER_API_IMAGE@ - imagePullPolicy: @MIGRATION_PLANNER_API_IMAGE_PULL_POLICY@ - ports: - - containerPort: 3443 - - containerPort: 7443 - - containerPort: 11443 - livenessProbe: - tcpSocket: - port: 3443 - initialDelaySeconds: 30 - env: - - name: MIGRATION_PLANNER_IMAGE_URL - valueFrom: - secretKeyRef: - name: migration-planner-secret - key: migration_planner_image_url - - name: CONFIG_SERVER - valueFrom: - secretKeyRef: - name: migration-planner-secret - key: config_server - - name: CONFIG_SERVER_UI - valueFrom: - secretKeyRef: - name: migration-planner-secret - key: config_server_ui - - name: MIGRATION_PLANNER_AGENT_IMAGE - value: @MIGRATION_PLANNER_AGENT_IMAGE@ - - name: INSECURE_REGISTRY - value: "@INSECURE_REGISTRY@" - - name: PERSISTENT_DISK_DEVICE - value: "@PERSISTENT_DISK_DEVICE@" - volumeMounts: - volumeMounts: - - name: migration-planner-config - mountPath: "/.migration-planner/config.yaml" - subPath: config.yaml - readOnly: true - serviceAccountName: migration-planner - volumes: - - name: migration-planner-config - secret: - secretName: migration-planner-rds - optional: true - items: - - key: config.yaml - path: config.yaml ---- -kind: ServiceAccount -apiVersion: v1 -metadata: - name: migration-planner diff --git a/deploy/k8s/postgres-deployment.yaml b/deploy/k8s/postgres-deployment.yaml deleted file mode 100644 index e2d50e4d..00000000 --- a/deploy/k8s/postgres-deployment.yaml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: migration-planner-postgres -spec: - selector: - matchLabels: - app: postgres - replicas: 1 - template: - metadata: - labels: - app: postgres - spec: - containers: - - name: postgres - image: quay.io/sclorg/postgresql-12-c8s - imagePullPolicy: "IfNotPresent" - ports: - - containerPort: 5432 - env: - - name: POSTGRESQL_DATABASE - valueFrom: - secretKeyRef: - name: migration-planner-rds - key: db.name - - name: POSTGRESQL_USER - valueFrom: - secretKeyRef: - name: migration-planner-rds - key: db.user - - name: POSTGRESQL_PASSWORD - valueFrom: - secretKeyRef: - name: migration-planner-rds - key: db.password - volumeMounts: - - mountPath: /var/lib/pgsql/data - name: postgredb - resources: - limits: - memory: 500Mi - requests: - cpu: 100m - memory: 400Mi - volumes: - - name: postgredb - emptyDir: - medium: Memory ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres - labels: - app: postgres -spec: - type: LoadBalancer - ports: - - port: 5432 - targetPort: 5432 - selector: - app: postgres diff --git a/deploy/k8s/postgres-secret.yaml b/deploy/k8s/postgres-secret.yaml deleted file mode 100644 index c1c041d0..00000000 --- a/deploy/k8s/postgres-secret.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: migration-planner-rds - labels: - app: postgres -type: Opaque -stringData: - config.yaml: | - database: - hostname: postgres - name: planner - password: adminpass - port: 5432 - type: pgsql - user: admin - service: - address: :3443 - agentEndpointAddress: :7443 - imageEndpointAddress: :11443 - baseAgentEndpointUrl: https://localhost:7443 - baseImageEndpointUrl: https://localhost:11443 - baseUrl: https://localhost:3443 - logLevel: debug - db.host: "postgres" - db.name: "planner" - db.password: "adminpass" - db.port: "5432" - db.user: "admin" diff --git a/deploy/templates/postgres-template.yml b/deploy/templates/postgres-template.yml index 3e38939d..39023c0b 100644 --- a/deploy/templates/postgres-template.yml +++ b/deploy/templates/postgres-template.yml @@ -110,7 +110,6 @@ objects: capabilities: {} privileged: false terminationMessagePath: /dev/termination-log - capabilities: {} dnsPolicy: ClusterFirst restartPolicy: Always volumes: diff --git a/deploy/templates/service-template.yml b/deploy/templates/service-template.yml index 41be9eef..43646a0f 100644 --- a/deploy/templates/service-template.yml +++ b/deploy/templates/service-template.yml @@ -6,8 +6,22 @@ metadata: parameters: - name: MIGRATION_PLANNER_IMAGE required: true + - name: MIGRATION_PLANNER_API_IMAGE_PULL_POLICY + value: Always - name: IMAGE_TAG value: latest + - name: MIGRATION_PLANNER_URL + description: The API URL of the migration assessment + required: true + - name: MIGRATION_PLANNER_UI_URL + description: The console URL of the migration assessment + required: true + - name: MIGRATION_PLANNER_IMAGE_URL + description: The URL for the Agent OVA file + required: true + - name: MIGRATION_PLANNER_AGENT_IMAGE + description: Migration Discovery Service image + required: true - name: MIGRATION_PLANNER_REPLICAS description: Number of replicas of the service to run. value: "3" @@ -23,23 +37,39 @@ parameters: - name: MIGRATION_PLANNER_CPU_LIMIT description: CPU limit for the API pods. value: "500m" - - name: MIGRATION_PLANNER_AGENT_IMAGE - description: Migration Discovery Service image - required: true - - name: MIGRATION_PLANNER_URL - description: The API URL of the migration assessment - required: true - - name: MIGRATION_PLANNER_UI_URL - description: The console URL of the migration assessment - required: true - - name: MIGRATION_PLANNER_JWK_URL - description: URL of the x.509 certificate chain that was used to verify the digital signature of the JWT - - name: MIGRATION_PLANNER_AUTH - description: Define the backend authentication mechanism - name: DB_SECRET_NAME description: The name of the OpenShift Secret used for the database. displayName: Database Secret Name value: migration-planner-db + - name: PERSISTENT_DISK_DEVICE + value: /dev/sda + - name: INSECURE_REGISTRY + value: "false" + # Svc Config values + - name: MIGRATION_PLANNER_ADDRESS + value: ":3443" + - name: MIGRATION_PLANNER_AGENT_ENDPOINT_ADDRESS + value: ":7443" + - name: MIGRATION_PLANNER_IMAGE_ENDPOINT_ADDRESS + value: ":11443" + - name: MIGRATION_PLANNER_BASE_URL + value: "https://localhost:3443" + - name: MIGRATION_PLANNER_BASE_AGENT_ENDPOINT_URL + value: "https://localhost:7443" + - name: MIGRATION_PLANNER_BASE_IMAGE_ENDPOINT_URL + value: "https://localhost:11443" + - name: MIGRATION_PLANNER_LOG_LEVEL + value: "info" + # Kafka Config values + - name: MIGRATION_PLANNER_KAFKA_BROKERS + - name: MIGRATION_PLANNER_KAFKA_TOPIC + - name: MIGRATION_PLANNER_KAFKA_VERSION + - name: MIGRATION_PLANNER_KAFKA_CLIENT_ID + # Auth Config values + - name: MIGRATION_PLANNER_AUTH + description: Define the backend authentication mechanism + - name: MIGRATION_PLANNER_JWK_URL + description: URL of the x.509 certificate chain that was used to verify the digital signature of the JWT objects: - kind: ServiceAccount @@ -105,6 +135,20 @@ objects: port: 8080 protocol: TCP targetPort: 8080 + - kind: Service + apiVersion: v1 + metadata: + labels: + app: migration-planner + name: migration-planner-image + spec: + ports: + - name: migration-planner-image + port: 11443 + protocol: TCP + targetPort: 11443 + selector: + app: migration-planner - kind: Deployment apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 metadata: @@ -129,7 +173,7 @@ objects: cpu: ${MIGRATION_PLANNER_CPU_LIMIT} memory: ${MIGRATION_PLANNER_MEMORY_LIMIT} image: ${MIGRATION_PLANNER_IMAGE}:${IMAGE_TAG} - imagePullPolicy: Always + imagePullPolicy: ${MIGRATION_PLANNER_API_IMAGE_PULL_POLICY} ports: - containerPort: 3443 name: api-port @@ -144,14 +188,46 @@ objects: value: ${MIGRATION_PLANNER_URL} - name: CONFIG_SERVER_UI value: ${MIGRATION_PLANNER_UI_URL}/migrate/wizard + - name: MIGRATION_PLANNER_IMAGE_URL + value: ${MIGRATION_PLANNER_IMAGE_URL} - name: MIGRATION_PLANNER_AGENT_IMAGE value: ${MIGRATION_PLANNER_AGENT_IMAGE}:${IMAGE_TAG} - - name: BASE_AGENT_ENDPOINT_URL + - name: BASE_AGENT_ENDPOINT_URL value: ${MIGRATION_PLANNER_URL} + - name: PERSISTENT_DISK_DEVICE + value: ${PERSISTENT_DISK_DEVICE} + - name: INSECURE_REGISTRY + value: ${INSECURE_REGISTRY} + # Svc Config values + - name: MIGRATION_PLANNER_ADDRESS + value: ${MIGRATION_PLANNER_ADDRESS} + - name: MIGRATION_PLANNER_AGENT_ENDPOINT_ADDRESS + value: ${MIGRATION_PLANNER_AGENT_ENDPOINT_ADDRESS} + - name: MIGRATION_PLANNER_IMAGE_ENDPOINT_ADDRESS + value: ${MIGRATION_PLANNER_IMAGE_ENDPOINT_ADDRESS} + - name: MIGRATION_PLANNER_BASE_URL + value: ${MIGRATION_PLANNER_BASE_URL} + - name: MIGRATION_PLANNER_BASE_AGENT_ENDPOINT_URL + value: ${MIGRATION_PLANNER_BASE_AGENT_ENDPOINT_URL} + - name: MIGRATION_PLANNER_BASE_IMAGE_ENDPOINT_URL + value: ${MIGRATION_PLANNER_BASE_IMAGE_ENDPOINT_URL} + - name: MIGRATION_PLANNER_LOG_LEVEL + value: ${MIGRATION_PLANNER_LOG_LEVEL} + # Kafka Config values + - name: MIGRATION_PLANNER_KAFKA_BROKERS + value: ${MIGRATION_PLANNER_KAFKA_BROKERS} + - name: MIGRATION_PLANNER_KAFKA_TOPIC + value: ${MIGRATION_PLANNER_KAFKA_TOPIC} + - name: MIGRATION_PLANNER_KAFKA_VERSION + value: ${MIGRATION_PLANNER_KAFKA_VERSION} + - name: MIGRATION_PLANNER_KAFKA_CLIENT_ID + value: ${MIGRATION_PLANNER_KAFKA_CLIENT_ID} + # Auth Config values - name: MIGRATION_PLANNER_AUTH value: ${MIGRATION_PLANNER_AUTH} - name: MIGRATION_PLANNER_JWK_URL value: ${MIGRATION_PLANNER_JWK_URL} + # DB Config values - name: DB_HOST valueFrom: secretKeyRef: diff --git a/doc/deployment.md b/doc/deployment.md index e5cc044d..d465cc74 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -15,7 +15,7 @@ The deployment process deploys all relevant parts of the project, including the To undeploy the project, which removes all the relevant parts, run: ``` -make undeploy-on-openshift +make delete-from-openshift ``` ## Using custom images for the Assisted Migration Service API, UI and agent diff --git a/go.mod b/go.mod index 068120fe..e14e7fff 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.1 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/google/uuid v1.6.0 + github.com/kelseyhightower/envconfig v1.4.0 github.com/konveyor/forklift-controller v0.0.0-20221102112227-e73b65a01cda github.com/kubev2v/migration-event-streamer v0.0.0-20241125102656-9cdf9e64a16b github.com/leosunmo/zapchi v0.2.0 diff --git a/go.sum b/go.sum index a8b68290..7e9215cd 100644 --- a/go.sum +++ b/go.sum @@ -267,6 +267,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 h1:VzM3TYHDgqPkettiP6I6q2jOeQFL4nrJM+UcAc4f6Fs= github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= diff --git a/internal/auth/agent_authenticator_test.go b/internal/auth/agent_authenticator_test.go index 17acdd66..efcf1605 100644 --- a/internal/auth/agent_authenticator_test.go +++ b/internal/auth/agent_authenticator_test.go @@ -30,7 +30,7 @@ var _ = Describe("agent authentication", Ordered, func() { ) BeforeEach(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/config/config.go b/internal/config/config.go index 9a659a65..2b84a59d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,163 +1,59 @@ package config import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "github.com/IBM/sarama" - "github.com/kubev2v/migration-planner/internal/util" - "sigs.k8s.io/yaml" + "github.com/kelseyhightower/envconfig" ) -const ( - appName = "migration-planner" -) +var singleConfig *Config = nil type Config struct { - Database *dbConfig `json:"database,omitempty"` - Service *svcConfig `json:"service,omitempty"` + Database *dbConfig + Service *svcConfig } type dbConfig struct { - Type string `json:"type,omitempty"` - Hostname string `json:"hostname,omitempty"` - Port uint `json:"port,omitempty"` - Name string `json:"name,omitempty"` - User string `json:"user,omitempty"` - Password string `json:"password,omitempty"` + Type string `envconfig:"DB_TYPE" default:"pgsql"` + Hostname string `envconfig:"DB_HOST" default:"localhost"` + Port string `envconfig:"DB_PORT" default:"5432"` + Name string `envconfig:"DB_NAME" default:"planner"` + User string `envconfig:"DB_USER" default:"admin"` + Password string `envconfig:"DB_PASS" default:"adminpass"` } type svcConfig struct { - Address string `json:"address,omitempty"` - AgentEndpointAddress string `json:"agentEndpointAddress,omitempty"` - ImageEndpointAddress string `json:"imageEndpointAddress,omitempty"` - BaseUrl string `json:"baseUrl,omitempty"` - BaseAgentEndpointUrl string `json:"baseAgentEndpointUrl,omitempty"` - BaseImageEndpointUrl string `json:"baseImageEndpointUrl,omitempty"` - LogLevel string `json:"logLevel,omitempty"` - Kafka kafkaConfig `json:"kafka,omitempty"` - Auth Auth `json:"auth"` + Address string `envconfig:"MIGRATION_PLANNER_ADDRESS" default:":3443"` + AgentEndpointAddress string `envconfig:"MIGRATION_PLANNER_AGENT_ENDPOINT_ADDRESS" default:":7443"` + ImageEndpointAddress string `envconfig:"MIGRATION_PLANNER_IMAGE_ENDPOINT_ADDRESS" default:":11443"` + BaseUrl string `envconfig:"MIGRATION_PLANNER_BASE_URL" default:"https://localhost:3443"` + BaseAgentEndpointUrl string `envconfig:"MIGRATION_PLANNER_BASE_AGENT_ENDPOINT_URL" default:"https://localhost:7443"` + BaseImageEndpointUrl string `envconfig:"MIGRATION_PLANNER_BASE_IMAGE_ENDPOINT_URL" default:"https://localhost:11443"` + LogLevel string `envconfig:"MIGRATION_PLANNER_LOG_LEVEL" default:"info"` + Kafka kafkaConfig + Auth Auth } type kafkaConfig struct { - Brokers []string `yaml:"brokers"` - Topic string `yaml:"topic"` - Version sarama.KafkaVersion `yaml:"-"` - ClientID string `yaml:"clientID"` + Brokers []string `envconfig:"MIGRATION_PLANNER_KAFKA_BROKERS" default:""` + Topic string `envconfig:"MIGRATION_PLANNER_KAFKA_TOPIC" default:""` + Version sarama.KafkaVersion `envconfig:"MIGRATION_PLANNER_KAFKA_VERSION" default:""` + ClientID string `envconfig:"MIGRATION_PLANNER_KAFKA_CLIENT_ID" default:""` SaramaConfig *sarama.Config } type Auth struct { - AuthenticationType string `json:"type"` - JwkCertURL string `json:"jwk_cert_url"` - LocalPrivateKey string `json:"localPrivateKey"` -} - -func ConfigDir() string { - return filepath.Join(util.MustString(os.UserHomeDir), "."+appName) -} - -func ConfigFile() string { - return filepath.Join(ConfigDir(), "config.yaml") -} - -func ClientConfigFile() string { - return filepath.Join(ConfigDir(), "client.yaml") -} - -func NewDefault() (*Config, error) { - port, err := util.GetIntEnv("DB_PORT", 5432) - if err != nil { - return nil, err - } - c := &Config{ - Database: &dbConfig{ - Type: "pgsql", - Hostname: util.GetEnv("DB_HOST", "localhost"), - Port: port, - Name: util.GetEnv("DB_NAME", "planner"), - User: util.GetEnv("DB_USER", "admin"), - Password: util.GetEnv("DB_PASS", "adminpass"), - }, - Service: &svcConfig{ - Address: ":3443", - AgentEndpointAddress: ":7443", - ImageEndpointAddress: ":11443", - BaseUrl: "https://localhost:3443", - BaseAgentEndpointUrl: "https://localhost:7443", - BaseImageEndpointUrl: "https://localhost:11443", - LogLevel: "info", - Auth: Auth{ - AuthenticationType: util.GetEnv("MIGRATION_PLANNER_AUTH", "none"), - JwkCertURL: util.GetEnv("MIGRATION_PLANNER_JWK_URL", ""), - LocalPrivateKey: util.GetEnv("MIGRATION_PLANNER_PRIVATE_KEY", ""), - }, - }, - } - return c, nil -} - -func NewFromFile(cfgFile string) (*Config, error) { - cfg, err := Load(cfgFile) - if err != nil { - return nil, err - } - if err := Validate(cfg); err != nil { - return nil, err - } - return cfg, nil + AuthenticationType string `envconfig:"MIGRATION_PLANNER_AUTH" default:""` + JwkCertURL string `envconfig:"MIGRATION_PLANNER_JWK_URL" default:""` + LocalPrivateKey string `envconfig:"MIGRATION_PLANNER_PRIVATE_KEY" default:""` } -func LoadOrGenerate(cfgFile string) (*Config, error) { - if _, err := os.Stat(cfgFile); os.IsNotExist(err) { - if err := os.MkdirAll(filepath.Dir(cfgFile), os.FileMode(0755)); err != nil { - return nil, fmt.Errorf("creating directory for config file: %v", err) - } - cfg, err := NewDefault() - if err != nil { - return nil, err - } - if err := Save(cfg, cfgFile); err != nil { +func New() (*Config, error) { + if singleConfig == nil { + singleConfig = new(Config) + if err := envconfig.Process("", singleConfig); err != nil { return nil, err } } - return NewFromFile(cfgFile) -} - -func Load(cfgFile string) (*Config, error) { - contents, err := os.ReadFile(cfgFile) - if err != nil { - return nil, fmt.Errorf("reading config file: %v", err) - } - c := &Config{} - if err := yaml.Unmarshal(contents, c); err != nil { - return nil, fmt.Errorf("decoding config: %v", err) - } - return c, nil -} - -func Save(cfg *Config, cfgFile string) error { - contents, err := yaml.Marshal(cfg) - if err != nil { - return fmt.Errorf("encoding config: %v", err) - } - if err := os.WriteFile(cfgFile, contents, 0600); err != nil { - return fmt.Errorf("writing config file: %v", err) - } - return nil -} - -func Validate(cfg *Config) error { - return nil -} - -func (cfg *Config) String() string { - contents, err := json.Marshal(cfg) // nolint: staticcheck - if err != nil { - return "" - } - return string(contents) + return singleConfig, nil } diff --git a/internal/service/agent/handler_test.go b/internal/service/agent/handler_test.go index 78b637c4..76e0972a 100644 --- a/internal/service/agent/handler_test.go +++ b/internal/service/agent/handler_test.go @@ -34,7 +34,7 @@ var _ = Describe("agent service", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/service/source_test.go b/internal/service/source_test.go index f22b5f96..e950bf7f 100644 --- a/internal/service/source_test.go +++ b/internal/service/source_test.go @@ -32,7 +32,7 @@ var _ = Describe("source handler", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/store/agent_test.go b/internal/store/agent_test.go index d90ed1c4..9bf2f378 100644 --- a/internal/store/agent_test.go +++ b/internal/store/agent_test.go @@ -26,7 +26,7 @@ var _ = Describe("agent store", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/store/gorm.go b/internal/store/gorm.go index 55a66222..93b1052b 100644 --- a/internal/store/gorm.go +++ b/internal/store/gorm.go @@ -19,7 +19,7 @@ func InitDB(cfg *config.Config) (*gorm.DB, error) { var dia gorm.Dialector if cfg.Database.Type == "pgsql" { - dsn := fmt.Sprintf("host=%s user=%s password=%s port=%d", + dsn := fmt.Sprintf("host=%s user=%s password=%s port=%s", cfg.Database.Hostname, cfg.Database.User, cfg.Database.Password, diff --git a/internal/store/image_test.go b/internal/store/image_test.go index 301f7f10..75d671df 100644 --- a/internal/store/image_test.go +++ b/internal/store/image_test.go @@ -24,7 +24,7 @@ var _ = Describe("image infra store", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/store/key_test.go b/internal/store/key_test.go index 811ba1bc..90e0a2d0 100644 --- a/internal/store/key_test.go +++ b/internal/store/key_test.go @@ -28,7 +28,7 @@ var _ = Describe("key store", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/store/source_test.go b/internal/store/source_test.go index 207f3a8c..1ab73a4c 100644 --- a/internal/store/source_test.go +++ b/internal/store/source_test.go @@ -25,7 +25,7 @@ var _ = Describe("source store", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := store.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/internal/store/store_test.go b/internal/store/store_test.go index dc2e54e0..fdc1d1dd 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -19,7 +19,7 @@ var _ = Describe("Store", Ordered, func() { ) BeforeAll(func() { - cfg, err := config.NewDefault() + cfg, err := config.New() Expect(err).To(BeNil()) db, err := st.InitDB(cfg) Expect(err).To(BeNil()) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 10f10c58..27aed0c6 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -30,12 +30,12 @@ var _ = Describe("e2e", func() { } createAgent := func(configPath string, idForTest string, uuid uuid.UUID, vmName string) PlannerAgent { - agent, err := NewPlannerAgent(configPath, uuid, vmName, idForTest) + newAgent, err := NewPlannerAgent(configPath, uuid, vmName, idForTest) Expect(err).To(BeNil(), "Failed to create PlannerAgent") - err = agent.Run() + err = newAgent.Run() Expect(err).To(BeNil(), "Failed to run PlannerAgent") Eventually(func() string { - agentIP, err = agent.GetIp() + agentIP, err = newAgent.GetIp() if err != nil { return "" } @@ -43,9 +43,9 @@ var _ = Describe("e2e", func() { }, "3m").ShouldNot(BeEmpty()) Expect(agentIP).ToNot(BeEmpty()) Eventually(func() bool { - return agent.IsServiceRunning(agentIP, "planner-agent") + return newAgent.IsServiceRunning(agentIP, "planner-agent") }, "3m").Should(BeTrue()) - return agent + return newAgent } loginToVsphere := func(username string, password string, expectedStatusCode int) {