diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7ac4eccc6e..959be1b111 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,7 @@ "features": { "ghcr.io/devcontainers/features/docker-in-docker": {}, "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers/features/node:1": { "version": "22" }, + "ghcr.io/devcontainers/features/node:1": { "version": "24" }, "ghcr.io/devcontainers/features/python:1": {}, "ghcr.io/devcontainers/features/sshd:1": {}, "ghcr.io/devcontainers-extra/features/kind:1": {}, diff --git a/.github/scripts/end2end/configure-e2e-endpoints.sh b/.github/scripts/end2end/configure-e2e-endpoints.sh index 9013418c5e..5fd2eb9aef 100755 --- a/.github/scripts/end2end/configure-e2e-endpoints.sh +++ b/.github/scripts/end2end/configure-e2e-endpoints.sh @@ -131,21 +131,4 @@ if ! grep -q "backbeat-api.zenko.local" /etc/hosts 2>/dev/null; then echo "127.0.0.1 ${ZENKO_HOSTS}" | sudo tee -a /etc/hosts fi -# --- Export endpoint variables --- -# These use the ingress hostnames, reachable from outside the cluster. - -export CLOUDSERVER_HOST="s3.zenko.local" -export CLOUDSERVER_ENDPOINT="http://s3.zenko.local" -export BACKBEAT_API_ENDPOINT="http://backbeat-api.zenko.local" -export VAULT_ENDPOINT="http://iam.zenko.local" -export VAULT_STS_ENDPOINT="http://sts.zenko.local" -export VAULT_AUTH_HOST="vault-auth.zenko.local" -export KAFKA_CONNECT_URL="http://kafka-connect.zenko.local/connectors" - echo "=== Endpoints configured for out-of-cluster access ===" -echo " S3: ${CLOUDSERVER_ENDPOINT}" -echo " Backbeat API: ${BACKBEAT_API_ENDPOINT}" -echo " Vault IAM: ${VAULT_ENDPOINT}" -echo " Vault STS: ${VAULT_STS_ENDPOINT}" -echo " Vault Auth: http://${VAULT_AUTH_HOST}" -echo " Kafka Connect: ${KAFKA_CONNECT_URL}" diff --git a/.github/scripts/end2end/setup-e2e-env.sh b/.github/scripts/end2end/setup-e2e-env.sh index 6867959d71..4a357f33d0 100755 --- a/.github/scripts/end2end/setup-e2e-env.sh +++ b/.github/scripts/end2end/setup-e2e-env.sh @@ -48,9 +48,6 @@ export MONGO_REPLICA_SET_HOSTS="localhost:${MONGO_PORT}" # --- 5. Credentials from K8s secrets --- export ADMIN_ACCESS_KEY_ID=$(kubectl get secret ${ZENKO_NAME}-management-vault-admin-creds.v1 -o jsonpath='{.data.accessKey}' | base64 -d) export ADMIN_SECRET_ACCESS_KEY=$(kubectl get secret ${ZENKO_NAME}-management-vault-admin-creds.v1 -o jsonpath='{.data.secretKey}' | base64 -d) -export ZENKO_ACCESS_KEY=$(kubectl get secret ${ZENKO_NAME}-account-zenko -o jsonpath='{.data.AccessKeyId}' | base64 -d) -export ZENKO_SECRET_KEY=$(kubectl get secret ${ZENKO_NAME}-account-zenko -o jsonpath='{.data.SecretAccessKey}' | base64 -d) -export ZENKO_SESSION_TOKEN=$(kubectl get secret ${ZENKO_NAME}-account-zenko -o jsonpath='{.data.SessionToken}' | base64 -d) # CRR account credentials _src_secret="${ZENKO_NAME}-account-${CRR_SOURCE_ACCOUNT_NAME:-crr-source-account}" @@ -72,11 +69,8 @@ export CRR_DESTINATION_INFO="{\"AccessKeyId\":\"${DESTINATION_ACCESS_KEY}\",\"Se export KEYCLOAK_TEST_USER="${OIDC_USERNAME}-norights" export KEYCLOAK_TEST_PASSWORD=${OIDC_PASSWORD} export KEYCLOAK_TEST_HOST=${OIDC_ENDPOINT} -export KEYCLOAK_TEST_PORT="80" export KEYCLOAK_TEST_REALM_NAME=${OIDC_REALM} export KEYCLOAK_REALM=${OIDC_REALM} # cli-testing KeycloakSetup hook reads KEYCLOAK_REALM from env -export KEYCLOAK_TEST_CLIENT_ID=${OIDC_CLIENT_ID} -export KEYCLOAK_TEST_GRANT_TYPE="password" # --- 7. Test backend env vars --- export AWS_BACKEND_SOURCE_LOCATION AWS_BACKEND_DESTINATION_LOCATION @@ -131,40 +125,8 @@ export TARGET_VERSION=$(sed -n 's/^VERSION="\([^"]*\)"/\1/p' "${ZENKO_ROOT}/VERS if [ "${SKIP_CTST:-}" = "1" ]; then echo "SKIP_CTST=1 set, skipping CTST-specific setup" else - # CTST account & user names - export ZENKO_ACCOUNT_NAME="zenko-ctst" - export STORAGE_MANAGER_USER_NAME="storage_manager" - export STORAGE_ACCOUNT_OWNER_USER_NAME="storage_account_owner" - export DATA_CONSUMER_USER_NAME="data_consumer" - export DATA_ACCESSOR_USER_NAME="data_accessor" - # env vars used by cli-testing's Keycloak.ts seeder - export ACCOUNT="${ZENKO_ACCOUNT_NAME}" - export STORAGE_MANAGER="${STORAGE_MANAGER_USER_NAME}" - export STORAGE_ACCOUNT_OWNER="${STORAGE_ACCOUNT_OWNER_USER_NAME}" - export DATA_CONSUMER="${DATA_CONSUMER_USER_NAME}" - export DATA_ACCESSOR="${DATA_ACCESSOR_USER_NAME}" + export ACCOUNT="zenko-ctst" export SEED_KEYCLOAK_DEFAULT_ROLES=true - export ZENKO_PORT="80" - - # PRA admin credentials (may not exist for non-PRA runs; ignore errors) - export ADMIN_PRA_ACCESS_KEY_ID=$(kubectl get secret ${ZENKO_NAME}-pra-management-vault-admin-creds.v1 -o jsonpath='{.data.accessKey}' 2>/dev/null | base64 -d 2>/dev/null || echo "") - export ADMIN_PRA_SECRET_ACCESS_KEY=$(kubectl get secret ${ZENKO_NAME}-pra-management-vault-admin-creds.v1 -o jsonpath='{.data.secretKey}' 2>/dev/null | base64 -d 2>/dev/null || echo "") - - # --- 11. Service user credentials --- - BACKBEAT_LCBP_1_CREDS=$(kubectl get secret -l app.kubernetes.io/name=backbeat-lcbp-user-creds,app.kubernetes.io/instance=${ZENKO_NAME} -o jsonpath='{.items[0].data.backbeat-lifecycle-bp-1\.json}' | base64 -d) - BACKBEAT_LCC_1_CREDS=$(kubectl get secret -l app.kubernetes.io/name=backbeat-lcc-user-creds,app.kubernetes.io/instance=${ZENKO_NAME} -o jsonpath='{.items[0].data.backbeat-lifecycle-conductor-1\.json}' | base64 -d) - BACKBEAT_LCOP_1_CREDS=$(kubectl get secret -l app.kubernetes.io/name=backbeat-lcop-user-creds,app.kubernetes.io/instance=${ZENKO_NAME} -o jsonpath='{.items[0].data.backbeat-lifecycle-op-1\.json}' | base64 -d) - BACKBEAT_QP_1_CREDS=$(kubectl get secret -l app.kubernetes.io/name=backbeat-qp-user-creds,app.kubernetes.io/instance=${ZENKO_NAME} -o jsonpath='{.items[0].data.backbeat-qp-1\.json}' | base64 -d) - SORBET_FWD_2_ACCESSKEY=$(kubectl get secret -l app.kubernetes.io/name=sorbet-fwd-creds,app.kubernetes.io/instance=${ZENKO_NAME} -o jsonpath='{.items[0].data.accessKey}' | base64 -d) - SORBET_FWD_2_SECRETKEY=$(kubectl get secret -l app.kubernetes.io/name=sorbet-fwd-creds,app.kubernetes.io/instance=${ZENKO_NAME} -o jsonpath='{.items[0].data.secretKey}' | base64 -d) - export SERVICE_USERS_CREDENTIALS=$(echo '{"backbeat-lifecycle-bp-1":'"${BACKBEAT_LCBP_1_CREDS}"',"backbeat-lifecycle-conductor-1":'"${BACKBEAT_LCC_1_CREDS}"',"backbeat-lifecycle-op-1":'"${BACKBEAT_LCOP_1_CREDS}"',"backbeat-qp-1":'"${BACKBEAT_QP_1_CREDS}"',"sorbet-fwd-2":{"accessKey":"'"${SORBET_FWD_2_ACCESSKEY}"'","secretKey":"'"${SORBET_FWD_2_SECRETKEY}"'"}}' | jq -R) - - # --- 12. Kafka topics for sorbet --- - SORBET_CONFIG=$(kubectl get secret -l app.kubernetes.io/name=cold-sorbet-config-e2e-azure-archive,app.kubernetes.io/instance=${ZENKO_NAME} \ - -o jsonpath='{.items[0].data.config\.json}' | base64 -di) - export KAFKA_DEAD_LETTER_TOPIC=$(echo "${SORBET_CONFIG}" | jq -r '."kafka-dead-letter-topic"') - export KAFKA_OBJECT_TASK_TOPIC=$(echo "${SORBET_CONFIG}" | jq -r '."kafka-object-task-topic"') - export KAFKA_GC_REQUEST_TOPIC=$(echo "${SORBET_CONFIG}" | jq -r '."kafka-gc-request-topic"') # --- 13. Kafka host from backbeat config + port-forward --- KAFKA_HOST_PORT_ORIG=$(kubectl get secret -l app.kubernetes.io/name=backbeat-config,app.kubernetes.io/instance=${ZENKO_NAME} \ @@ -235,23 +197,7 @@ else fi export PROMETHEUS_SERVICE="${PROMETHEUS_SVC}.${NAMESPACE}.svc.cluster.local" - # --- 14. Zenko CR metadata --- - export TIME_PROGRESSION_FACTOR=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath="{.metadata.annotations.zenko\.io/time-progression-factor}") - export INSTANCE_ID=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath='{.status.instanceID}') - export KAFKA_CLEANER_INTERVAL=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath='{.spec.kafkaCleaner.interval}') - export SORBETD_RESTORE_TIMEOUT=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath='{.spec.sorbet.server.azure.restoreTimeout}') - - # Backbeat API (use ingress — already exported as BACKBEAT_API_ENDPOINT) - export BACKBEAT_API_HOST="backbeat-api.zenko.local" - export BACKBEAT_API_PORT="80" - - # Utilization service - export UTILIZATION_SERVICE_HOST=$(kubectl get zenko ${ZENKO_NAME} -o jsonpath='{.spec.scuba.api.ingress.hostname}') - export UTILIZATION_SERVICE_PORT="80" - # Azure archive settings - export AZURE_ARCHIVE_ACCESS_TIER="Hot" - export AZURE_ARCHIVE_MANIFEST_ACCESS_TIER="Hot" export AZURE_BLOB_URL="${AZURE_BACKEND_ENDPOINT}" export AZURE_QUEUE_URL="${AZURE_BACKEND_QUEUE_ENDPOINT}" @@ -286,11 +232,7 @@ else "subdomain":"${SUBDOMAIN}", "DRSubdomain":"${DR_SUBDOMAIN:-}", "ssl":false, - "port":"${ZENKO_PORT}", - "AccountName":"${ZENKO_ACCOUNT_NAME}", - "AdminAccessKey":"${ADMIN_ACCESS_KEY_ID}", - "AdminSecretKey":"${ADMIN_SECRET_ACCESS_KEY}", - "VaultAuthHost":"${VAULT_AUTH_HOST}", + "port":"80", "NotificationDestination":"${NOTIF_DEST_NAME}", "NotificationDestinationTopic":"${NOTIF_DEST_TOPIC}", "NotificationDestinationAlt":"${NOTIF_ALT_DEST_NAME}", @@ -304,40 +246,16 @@ else "PrometheusEndpoint":"http://localhost:${PROMETHEUS_PORT}", "KafkaHosts":"${KAFKA_HOST_PORT}", "KafkaAuthHosts":"${KAFKA_AUTH_HOST_PORT}", - "KafkaConnectUrl":"${KAFKA_CONNECT_URL}", "KeycloakUsername":"${OIDC_USERNAME}", "KeycloakPassword":"${OIDC_PASSWORD}", "KeycloakTestPassword":"${KEYCLOAK_TEST_PASSWORD}", "KeycloakHost":"${OIDC_HOST}", - "KeycloakPort":"${KEYCLOAK_TEST_PORT}", "KeycloakRealm":"${KEYCLOAK_TEST_REALM_NAME}", - "KeycloakClientId":"${KEYCLOAK_TEST_CLIENT_ID}", - "KeycloakGrantType":"${KEYCLOAK_TEST_GRANT_TYPE}", - "StorageManagerUsername":"${STORAGE_MANAGER_USER_NAME}", - "StorageAccountOwnerUsername":"${STORAGE_ACCOUNT_OWNER_USER_NAME}", - "DataConsumerUsername":"${DATA_CONSUMER_USER_NAME}", - "DataAccessorUsername":"${DATA_ACCESSOR_USER_NAME}", - "ServiceUsersCredentials":${SERVICE_USERS_CREDENTIALS}, "AzureAccountName":"${AZURE_ACCOUNT_NAME}", "AzureAccountKey":"${AZURE_SECRET_KEY}", "AzureArchiveContainer":"${AZURE_ARCHIVE_BUCKET_NAME}", "AzureArchiveContainer2":"${AZURE_ARCHIVE_BUCKET_NAME_2:-}", - "AzureArchiveAccessTier":"${AZURE_ARCHIVE_ACCESS_TIER}", - "AzureArchiveManifestTier":"${AZURE_ARCHIVE_MANIFEST_ACCESS_TIER}", "AzureArchiveQueue":"${AZURE_ARCHIVE_QUEUE_NAME:-}", - "TimeProgressionFactor":"${TIME_PROGRESSION_FACTOR}", - "KafkaObjectTaskTopic":"${KAFKA_OBJECT_TASK_TOPIC}", - "KafkaGCRequestTopic":"${KAFKA_GC_REQUEST_TOPIC}", - "KafkaDeadLetterQueueTopic":"${KAFKA_DEAD_LETTER_TOPIC}", - "InstanceID":"${INSTANCE_ID}", - "BackbeatApiHost":"${BACKBEAT_API_HOST}", - "BackbeatApiPort":"${BACKBEAT_API_PORT}", - "KafkaCleanerInterval":"${KAFKA_CLEANER_INTERVAL}", - "SorbetdRestoreTimeout":"${SORBETD_RESTORE_TIMEOUT}", - "DRAdminAccessKey":"${ADMIN_PRA_ACCESS_KEY_ID}", - "DRAdminSecretKey":"${ADMIN_PRA_SECRET_ACCESS_KEY}", - "UtilizationServiceHost":"${UTILIZATION_SERVICE_HOST}", - "UtilizationServicePort":"${UTILIZATION_SERVICE_PORT}", "KubeconfigPath":"${KUBECONFIG:-${HOME}/.kube/config}" } EOF @@ -358,24 +276,11 @@ if [ -n "${GITHUB_ENV:-}" ]; then # Don't do it for Codespace echo "MONGO_AUTH_PASSWORD=$MONGO_AUTH_PASSWORD" >> "$GITHUB_ENV" echo "ADMIN_ACCESS_KEY_ID=$ADMIN_ACCESS_KEY_ID" >> "$GITHUB_ENV" echo "ADMIN_SECRET_ACCESS_KEY=$ADMIN_SECRET_ACCESS_KEY" >> "$GITHUB_ENV" - echo "ZENKO_ACCESS_KEY=$ZENKO_ACCESS_KEY" >> "$GITHUB_ENV" - echo "ZENKO_SECRET_KEY=$ZENKO_SECRET_KEY" >> "$GITHUB_ENV" - echo "ZENKO_SESSION_TOKEN=$ZENKO_SESSION_TOKEN" >> "$GITHUB_ENV" echo "KEYCLOAK_TEST_USER=$KEYCLOAK_TEST_USER" >> "$GITHUB_ENV" echo "KEYCLOAK_TEST_PASSWORD=$KEYCLOAK_TEST_PASSWORD" >> "$GITHUB_ENV" echo "KEYCLOAK_TEST_HOST=$KEYCLOAK_TEST_HOST" >> "$GITHUB_ENV" - echo "KEYCLOAK_TEST_PORT=$KEYCLOAK_TEST_PORT" >> "$GITHUB_ENV" echo "KEYCLOAK_TEST_REALM_NAME=$KEYCLOAK_TEST_REALM_NAME" >> "$GITHUB_ENV" echo "KEYCLOAK_REALM=$KEYCLOAK_REALM" >> "$GITHUB_ENV" - echo "KEYCLOAK_TEST_CLIENT_ID=$KEYCLOAK_TEST_CLIENT_ID" >> "$GITHUB_ENV" - echo "KEYCLOAK_TEST_GRANT_TYPE=$KEYCLOAK_TEST_GRANT_TYPE" >> "$GITHUB_ENV" - echo "CLOUDSERVER_HOST=$CLOUDSERVER_HOST" >> "$GITHUB_ENV" - echo "CLOUDSERVER_ENDPOINT=$CLOUDSERVER_ENDPOINT" >> "$GITHUB_ENV" - echo "BACKBEAT_API_ENDPOINT=$BACKBEAT_API_ENDPOINT" >> "$GITHUB_ENV" - echo "VAULT_ENDPOINT=$VAULT_ENDPOINT" >> "$GITHUB_ENV" - echo "VAULT_STS_ENDPOINT=$VAULT_STS_ENDPOINT" >> "$GITHUB_ENV" - echo "VAULT_AUTH_HOST=$VAULT_AUTH_HOST" >> "$GITHUB_ENV" - echo "KAFKA_CONNECT_URL=$KAFKA_CONNECT_URL" >> "$GITHUB_ENV" echo "NODE_EXTRA_CA_CERTS=$NODE_EXTRA_CA_CERTS" >> "$GITHUB_ENV" echo "MOCHA_FILE=$MOCHA_FILE" >> "$GITHUB_ENV" echo "VERIFY_CERTIFICATES=$VERIFY_CERTIFICATES" >> "$GITHUB_ENV" diff --git a/tests/functional/ctst/common/common.ts b/tests/functional/ctst/common/common.ts index 3a5f29c193..1edec6ffe7 100644 --- a/tests/functional/ctst/common/common.ts +++ b/tests/functional/ctst/common/common.ts @@ -1,6 +1,7 @@ import { ListObjectVersionsOutput } from '@aws-sdk/client-s3'; import { Given, setDefaultTimeout, Then, When } from '@cucumber/cucumber'; import { CacheHelper, Constants, Identity, IdentityEnum, S3, Utils } from 'cli-testing'; +import { config, ZENKO_ACCOUNT_NAME } from 'tests_common/configuration'; import Zenko from 'world/Zenko'; import { parseGoDuration, safeJsonParse } from './utils'; import assert from 'assert'; @@ -39,8 +40,7 @@ export async function cleanS3Bucket( // Do not try to clean a bucket with compliance retention return; } - Identity.useIdentity(IdentityEnum.ACCOUNT, world.getSaved('accountName') || - world.parameters.AccountName); + Identity.useIdentity(IdentityEnum.ACCOUNT, world.getSaved('accountName') || ZENKO_ACCOUNT_NAME); world.resetCommand(); world.addCommandParameter({ bucket: bucketName }); const createdObjects = world.getCreatedObjects(); @@ -143,14 +143,14 @@ async function createBucket(world: Zenko, versioning: string, bucketName: string Given('a {string} bucket with dot', async function (this: Zenko, versioning: string) { const preName = this.getSaved('accountName') || - this.parameters.AccountName || Constants.ACCOUNT_NAME; + ZENKO_ACCOUNT_NAME; await createBucket(this, versioning, `${preName}.${Constants.BUCKET_NAME_TEST}${Utils.randomString()}`.toLocaleLowerCase()); }); Given('a {string} bucket', async function (this: Zenko, versioning: string) { const preName = this.getSaved('accountName') || - this.parameters.AccountName || Constants.ACCOUNT_NAME; + ZENKO_ACCOUNT_NAME; await createBucket(this, versioning, `${preName}${Constants.BUCKET_NAME_TEST}${Utils.randomString()}`.toLocaleLowerCase()); }); @@ -310,7 +310,7 @@ Then('i {string} be able to add user metadata to object {string}', Then('kafka consumed messages should not take too much place on disk', { timeout: -1 }, async function (this: Zenko) { - const kfkcIntervalSeconds = parseGoDuration(this.parameters.KafkaCleanerInterval); + const kfkcIntervalSeconds = parseGoDuration(config.ZenkoCR.KafkaCleanerInterval); const checkInterval = kfkcIntervalSeconds * 1000; const deadline = Date.now() + checkInterval * 3; @@ -321,7 +321,7 @@ Then('kafka consumed messages should not take too much place on disk', { timeout try { const excludedTopics = ['dead-letter', 'backbeat-metrics']; - const prefix = `${this.parameters.InstanceID}.`; + const prefix = `${config.ZenkoCR.InstanceID}.`; const allTopics = await kafkaAdmin.listTopics(); const topics: string[] = allTopics .filter(t => t.startsWith(prefix) && diff --git a/tests/functional/ctst/common/hooks.ts b/tests/functional/ctst/common/hooks.ts index ca266e2ca1..6343708a78 100644 --- a/tests/functional/ctst/common/hooks.ts +++ b/tests/functional/ctst/common/hooks.ts @@ -9,6 +9,7 @@ import { } from '@cucumber/cucumber'; import Zenko from '../world/Zenko'; import { CacheHelper, Identity, WorkCoordination } from 'cli-testing'; +import { config, initConfig } from 'tests_common/configuration'; import { prepareQuotaScenarios, teardownQuotaScenarios } from 'steps/quotas/quotas'; import { prepareUtilizationScenarios } from 'steps/utilization/utilizationAPI'; import { prepareMetricsScenarios } from './utils'; @@ -21,6 +22,12 @@ import { import { createKubeCustomObjectClient, waitForZenkoToStabilize } from 'steps/utils/kubernetes'; import { startDLQConsumer, stopDLQConsumer } from 'steps/utils/kafka'; +BeforeAll(async function () { + // Some hooks are defined in cli-testing and use the configuration, + // we need to have this run before anything else + await initConfig(); +}); + import 'cli-testing/hooks/KeycloakSetup'; import 'cli-testing/hooks/Logger'; import 'cli-testing/hooks/versionTags'; @@ -45,7 +52,7 @@ setParallelCanAssign(noParallelRun); BeforeAll(async function () { const kafkaHosts = process.env['KAFKA_HOST_PORT']; - const dlqTopic = process.env['KAFKA_DEAD_LETTER_TOPIC']; + const dlqTopic = config.KafkaTopics.DeadLetterQueue; if (kafkaHosts && dlqTopic) { await startDLQConsumer(kafkaHosts, dlqTopic, Zenko.addToDLQBuffer); } diff --git a/tests/functional/ctst/steps/azureArchive.ts b/tests/functional/ctst/steps/azureArchive.ts index 398eb595fe..e65f3b30e4 100644 --- a/tests/functional/ctst/steps/azureArchive.ts +++ b/tests/functional/ctst/steps/azureArchive.ts @@ -3,6 +3,10 @@ import path from 'path'; import assert from 'assert'; import { safeJsonParse, request } from '../common/utils'; import { Given, Then, When } from '@cucumber/cucumber'; +import { + config, BACKBEAT_API_HOST, BACKBEAT_API_PORT, + AZURE_ARCHIVE_ACCESS_TIER, AZURE_ARCHIVE_MANIFEST_TIER, +} from 'tests_common/configuration'; import { AzureHelper, S3, Constants, Utils } from 'cli-testing'; import util from 'util'; import { exec } from 'child_process'; @@ -205,7 +209,7 @@ Then('manifest access tier should be valid for object {string}', async function manifestName, getAzureCreds(this), ); - assert.strictEqual(manifestProperties.accessTier, this.parameters.AzureArchiveManifestTier); + assert.strictEqual(manifestProperties.accessTier, AZURE_ARCHIVE_MANIFEST_TIER); }); Then('tar access tier should be valid for object {string}', async function (this: Zenko, objectName: string) { @@ -223,7 +227,7 @@ Then('tar access tier should be valid for object {string}', async function (this tarName, getAzureCreds(this), ); - assert.strictEqual(packProperties.accessTier, this.parameters.AzureArchiveAccessTier); + assert.strictEqual(packProperties.accessTier, AZURE_ARCHIVE_ACCESS_TIER); }); Then('manifest and tar containing object {string} should exist', async function (this: Zenko, objectName: string) { @@ -316,7 +320,7 @@ Then('restoration of object {string} failed and ends up in DLQ', const bucketName = this.getSaved('bucketName'); // wait for restore to fail and end up in dead letter queue - const restoreTimeoutMs = parseInt(this.parameters.SorbetdRestoreTimeout) * 1000; + const restoreTimeoutMs = parseInt(config.ZenkoCR.SorbetdRestoreTimeout) * 1000; if (isNaN(restoreTimeoutMs)) { throw new Error('SorbetdRestoreTimeout world parameter is missing or not a valid integer'); } @@ -364,9 +368,9 @@ When('i run sorbetctl to retry failed restore for {string} location', { timeout: 10 * 60 * 1000 }, async function (this: Zenko, location: string) { const command = `./ctst/sorbetctl forward list failed --trigger-retry --skip-invalid \ --limit 300 \ - --kafka-dead-letter-topic=${this.parameters.KafkaDeadLetterQueueTopic} \ - --kafka-object-task-topic=${this.parameters.KafkaObjectTaskTopic} \ - --kafka-gc-request-topic=${this.parameters.KafkaGCRequestTopic} \ + --kafka-dead-letter-topic=${config.KafkaTopics.DeadLetterQueue} \ + --kafka-object-task-topic=${config.KafkaTopics.ObjectTasks} \ + --kafka-gc-request-topic=${config.KafkaTopics.GcRequest} \ --kafka-brokers ${this.parameters.KafkaHosts}`; try { this.logger.debug('Running command', { command, location }); @@ -380,11 +384,13 @@ When('i run sorbetctl to retry failed restore for {string} location', } }); -When('i wait for {int} days', { timeout: 10 * 60 * 1000 }, async function (this: Zenko, days: number) { - const realTimeDay = days * 24 * 60 * 60 * 1000 / - (this.parameters.TimeProgressionFactor > 1 ? this.parameters.TimeProgressionFactor : 1); - await Utils.sleep(realTimeDay); -}); +When('i wait for {int} days', { timeout: 10 * 60 * 1000 }, + async function (this: Zenko, days: number) { + const tpf = config.ZenkoCR.TimeProgressionFactor; + const realTimeDay = days * 24 * 60 * 60 * 1000 / + (tpf > 1 ? tpf : 1); + await Utils.sleep(realTimeDay); + }); Then('object {string} should expire in {int} days', async function (this: Zenko, objectName: string, days: number) { const objName = objectName || this.getSaved('objectName'); @@ -405,9 +411,10 @@ Then('object {string} should expire in {int} days', async function (this: Zenko, const expiryDate = new Date(expireResDate[1]).getTime(); const lastModified = new Date(head.LastModified).getTime(); const diff = (expiryDate - lastModified) / 1000 / 86400; - const realTimeDays = days / (this.parameters.TimeProgressionFactor > 1 ? this.parameters.TimeProgressionFactor : 1); + const tpf = config.ZenkoCR.TimeProgressionFactor; + const realTimeDays = days / (tpf > 1 ? tpf : 1); assert.ok(diff >= realTimeDays && diff < realTimeDays + 0.005, - `Expected ${realTimeDays} but got ${diff} ; ${this.parameters.TimeProgressionFactor}`); + `Expected ${realTimeDays} but got ${diff} ; ${tpf}`); }); Given('that lifecycle is {string} for the {string} location', @@ -419,8 +426,8 @@ Given('that lifecycle is {string} for the {string} location', path = `/_/lifecycle/resume/${location}`; } const options = { - hostname: this.parameters.BackbeatApiHost, - port: this.parameters.BackbeatApiPort, + hostname: BACKBEAT_API_HOST, + port: BACKBEAT_API_PORT, method: 'POST', path, }; @@ -447,7 +454,8 @@ Given('an azure archive location {string}', { timeout: 15 * 60 * 1000 }, }, }, }; - const result = await this.managementAPIRequest('POST', `/config/${this.parameters.InstanceID}/location`, {}, + const result = await this.managementAPIRequest( + 'POST', `/config/${config.ZenkoCR.InstanceID}/location`, {}, locationConfig); assert.strictEqual(result.statusCode, 201); this.addToSaved('locationName', locationName); @@ -457,7 +465,11 @@ Given('an azure archive location {string}', { timeout: 15 * 60 * 1000 }, When('i change azure archive location {string} container target', { timeout: 15 * 60 * 1000 }, async function (this: Zenko, locationName: string) { - const result = await this.managementAPIRequest('GET', `/config/overlay/view/${this.parameters.InstanceID}`); + const instanceID = config.ZenkoCR.InstanceID; + const result = await this.managementAPIRequest( + 'GET', + `/config/overlay/view/${instanceID}`, + ); if ('err' in result) { assert.ifError(result.err); } else { @@ -469,7 +481,7 @@ When('i change azure archive location {string} container target', { timeout: 15 details.bucketName = this.parameters.AzureArchiveContainer2; auth.accountKey = this.parameters.AzureAccountKey; const putResult = await this.managementAPIRequest('PUT', - `/config/${this.parameters.InstanceID}/location/${locationName}`, + `/config/${config.ZenkoCR.InstanceID}/location/${locationName}`, {}, locationConfig); if ('err' in putResult) { diff --git a/tests/functional/ctst/steps/cloudserverAuth.ts b/tests/functional/ctst/steps/cloudserverAuth.ts index a75a104be4..a069960413 100644 --- a/tests/functional/ctst/steps/cloudserverAuth.ts +++ b/tests/functional/ctst/steps/cloudserverAuth.ts @@ -1,6 +1,7 @@ import { When, Then } from '@cucumber/cucumber'; import Zenko from '../world/Zenko'; import { Utils, S3, Constants } from 'cli-testing'; +import { ZENKO_ACCOUNT_NAME } from 'tests_common/configuration'; import { strict as assert } from 'assert'; interface DeleteObjectsResult { @@ -36,7 +37,7 @@ When('the user tries to perform CreateBucket', async function (this: Zenko) { this.resetCommand(); this.useSavedIdentity(); const preName = this.getSaved('accountName') || - this.parameters.AccountName || Constants.ACCOUNT_NAME; + ZENKO_ACCOUNT_NAME; const usedBucketName = `${preName}${Constants.BUCKET_NAME_TEST}${Utils.randomString()}`.toLocaleLowerCase(); this.addToSaved('bucketName', usedBucketName); this.addCommandParameter({ bucket: usedBucketName }); diff --git a/tests/functional/ctst/steps/iam-policies/common.ts b/tests/functional/ctst/steps/iam-policies/common.ts index 19e3f5e1f6..99d40b2bee 100644 --- a/tests/functional/ctst/steps/iam-policies/common.ts +++ b/tests/functional/ctst/steps/iam-policies/common.ts @@ -3,6 +3,7 @@ import { strict as assert } from 'assert'; import Zenko from '../../world/Zenko'; import { CacheHelper, ClientOptions, Command, Identity, VaultAuth } from 'cli-testing'; import { runActionAgainstBucket } from 'steps/utils/utils'; +import { VAULT_AUTH_HOST, ZENKO_ACCOUNT_NAME } from 'tests_common/configuration'; When('the user tries to perform {string} on the bucket', async function (this: Zenko, action: string) { await runActionAgainstBucket(this, action); @@ -21,22 +22,18 @@ When('the user tries to perform vault auth {string}', async function (this: Zenk + 'Make sure the `IAMSession` and `AssumedSession` world parameter are defined.'); } - if (!this.parameters.VaultAuthHost) { - throw new Error('Vault auth endpoint is not set. Make sure the `VaultAuthHost` world parameter is defined.'); - } - const vaultAuthClientOptions: ClientOptions = { AccessKey: userCredentials.accessKeyId, SecretKey: userCredentials.secretAccessKey, SessionToken: userCredentials.sessionToken, - ip: this.parameters.VaultAuthHost, + ip: VAULT_AUTH_HOST, ssl: CacheHelper.parameters ? CacheHelper.parameters.ssl as boolean : undefined, }; switch (action) { case 'GetAccountInfo': this.setResult(await VaultAuth.getAccounts([ - lastIdentity.accountName || this.parameters.AccountName, + lastIdentity.accountName || ZENKO_ACCOUNT_NAME, ], null, null, { // @ts-expect-error accountNames is not generated by CTST yet accountNames: true, diff --git a/tests/functional/ctst/steps/notifications.ts b/tests/functional/ctst/steps/notifications.ts index 5d4eead837..93b873b42e 100644 --- a/tests/functional/ctst/steps/notifications.ts +++ b/tests/functional/ctst/steps/notifications.ts @@ -186,7 +186,7 @@ When('i subscribe to {string} notifications for destination {int}', this.addCommandParameter({ notificationConfiguration: `'${JSON.stringify(destinationConfig)}'` }); } await S3.putBucketNotificationConfiguration(this.getCommandParameters()); - await waitForBucketInConnectorPipeline(this.parameters.KafkaConnectUrl, this.getSaved('bucketName')); + await waitForBucketInConnectorPipeline(this.getSaved('bucketName')); }); When('i subscribe to {string} notifications for destination {int} with {string} filter', @@ -235,7 +235,7 @@ When('i subscribe to {string} notifications for destination {int} with {string} this.addCommandParameter({ notificationConfiguration: `'${JSON.stringify(destinationConfig)}'` }); } await S3.putBucketNotificationConfiguration(this.getCommandParameters()); - await waitForBucketInConnectorPipeline(this.parameters.KafkaConnectUrl, this.getSaved('bucketName')); + await waitForBucketInConnectorPipeline(this.getSaved('bucketName')); }); When('i unsubscribe from {string} notifications for destination {int}', diff --git a/tests/functional/ctst/steps/replication.ts b/tests/functional/ctst/steps/replication.ts index 7e0311355a..2067236a0b 100644 --- a/tests/functional/ctst/steps/replication.ts +++ b/tests/functional/ctst/steps/replication.ts @@ -3,6 +3,7 @@ import Zenko from '../world/Zenko'; import { createAndRunPod, getZenkoVersion } from 'steps/utils/kubernetes'; import assert from 'assert'; import { IdentityEnum, Identity, Utils } from 'cli-testing'; +import { ZENKO_ACCOUNT_NAME } from 'tests_common/configuration'; import { GetObjectCommand, DeleteBucketCommand, @@ -26,7 +27,7 @@ When('the job to replicate existing objects with status {string} is executed', const s3utilsVersion = zenkoVersion.spec.versions.s3utils; const credentials = Identity.getCredentialsForIdentity( IdentityEnum.ACCOUNT, - this.parameters.AccountName + ZENKO_ACCOUNT_NAME ); const podManifest = { apiVersion: 'v1', diff --git a/tests/functional/ctst/steps/reporting/storageUsageReporting.ts b/tests/functional/ctst/steps/reporting/storageUsageReporting.ts index fd769b3aa9..3da60cc6c5 100644 --- a/tests/functional/ctst/steps/reporting/storageUsageReporting.ts +++ b/tests/functional/ctst/steps/reporting/storageUsageReporting.ts @@ -1,6 +1,7 @@ import { Given, When, Then } from '@cucumber/cucumber'; import { strict as assert } from 'assert'; import Zenko from '../../world/Zenko'; +import { config } from 'tests_common/configuration'; import { IdentityEnum } from 'cli-testing'; interface LocationUsage { @@ -15,15 +16,14 @@ interface ReportingUsageResponse { } Given('an identity with the {string} keycloak persona', function (this: Zenko, persona: string) { - const username = (this.parameters as Record)[persona] || persona; - this.addToSaved('keycloakPersona', username); + this.addToSaved('keycloakPersona', persona); }); async function fetchStorageUsageReport(world: Zenko) { const persona = world.getSaved('keycloakPersona'); const result = await world.managementAPIRequest( 'GET', - `/instance/${world.parameters.InstanceID}/reporting/usage`, + `/instance/${config.ZenkoCR.InstanceID}/reporting/usage`, {}, {}, persona, diff --git a/tests/functional/ctst/steps/utilization/utilizationAPI.ts b/tests/functional/ctst/steps/utilization/utilizationAPI.ts index f76cef9a72..6bdcf22578 100644 --- a/tests/functional/ctst/steps/utilization/utilizationAPI.ts +++ b/tests/functional/ctst/steps/utilization/utilizationAPI.ts @@ -1,6 +1,7 @@ import { When, Then, ITestCaseHookParameter } from '@cucumber/cucumber'; import { strict as assert } from 'assert'; import Zenko from '../../world/Zenko'; +import { config } from 'tests_common/configuration'; import { Command } from 'cli-testing'; import { Identity } from 'cli-testing'; import ScubaClient, { ScubaMetrics } from 'scubaclient'; @@ -27,8 +28,8 @@ When('the user retrieves utilization metrics using scubaclient for metric type { this.addToSaved('metricType', metricType); const client = new ScubaClient({ - port: parseInt(this.parameters.UtilizationServicePort), - host: this.parameters.UtilizationServiceHost, + port: 80, + host: config.ZenkoCR.UtilizationServiceHost, useHttps: false, auth: { awsV4: { diff --git a/tests/functional/ctst/steps/utils/kafka.ts b/tests/functional/ctst/steps/utils/kafka.ts index fb46fc7de6..63e038c6ae 100644 --- a/tests/functional/ctst/steps/utils/kafka.ts +++ b/tests/functional/ctst/steps/utils/kafka.ts @@ -1,5 +1,6 @@ import { Utils } from 'cli-testing'; import { Consumer, stringDeserializers } from '@platformatic/kafka'; +import { KAFKA_CONNECT_URL } from 'tests_common/configuration'; export interface DLQMessage { op: string; @@ -116,7 +117,6 @@ interface ConnectorInfo { * test proceeds to trigger events. */ export async function waitForBucketInConnectorPipeline( - kafkaConnectUrl: string, bucketName: string, timeoutMs = 120000, intervalMs = 1000, @@ -125,7 +125,7 @@ export async function waitForBucketInConnectorPipeline( let lastConnectorCount = 0; while (Date.now() < deadline) { try { - const response = await fetch(`${kafkaConnectUrl}?expand=info`, { + const response = await fetch(`${KAFKA_CONNECT_URL}?expand=info`, { signal: AbortSignal.timeout(5000), }); const connectors = await response.json() as Record; diff --git a/tests/functional/ctst/steps/utils/utils.ts b/tests/functional/ctst/steps/utils/utils.ts index d19a73013a..5de6ee3dc9 100644 --- a/tests/functional/ctst/steps/utils/utils.ts +++ b/tests/functional/ctst/steps/utils/utils.ts @@ -12,6 +12,7 @@ import { } from 'cli-testing'; import { extractPropertyFromResults, s3FunctionExtraParams, safeJsonParse } from 'common/utils'; import Zenko from 'world/Zenko'; +import { ZENKO_ACCOUNT_NAME } from 'tests_common/configuration'; import assert from 'assert'; import constants from 'common/constants'; import { getLocationConfigs } from './kubernetes'; @@ -181,7 +182,7 @@ async function createBucketWithConfiguration( retentionMode?: string) { world.resetCommand(); const preName = world.getSaved('accountName') || - world.parameters.AccountName || Constants.ACCOUNT_NAME; + ZENKO_ACCOUNT_NAME; const usedBucketName = bucketName || `${preName}${Constants.BUCKET_NAME_TEST}${Utils.randomString()}`.toLocaleLowerCase(); world.addToSaved('bucketName', usedBucketName); diff --git a/tests/functional/ctst/world/Zenko.ts b/tests/functional/ctst/world/Zenko.ts index 6b56a1ab38..30f5bd1761 100644 --- a/tests/functional/ctst/world/Zenko.ts +++ b/tests/functional/ctst/world/Zenko.ts @@ -26,11 +26,12 @@ import { import { extractPropertyFromResults } from '../common/utils'; import ZenkoDrctl from 'steps/dr/drctl'; import assert from 'assert'; - -interface ServiceUsersCredentials { - accessKey: string; - secretKey: string; -} +import { + config, + ZENKO_ACCOUNT_NAME, + KEYCLOAK_TEST_PORT, + KEYCLOAK_GRANT_TYPE, +} from 'tests_common/configuration'; // Zenko entities export interface SavedIdentity { @@ -51,13 +52,7 @@ export enum EntityType { } export interface ZenkoWorldParameters extends ClientOptions { - AccountName: string; - AccountAccessKey: string; - AccountSecretKey: string; - DRAdminAccessKey?: string; - DRAdminSecretKey?: string; DRSubdomain?: string; - VaultAuthHost: string; NotificationDestination: string; NotificationDestinationTopic: string; NotificationDestinationAlt: string; @@ -69,41 +64,19 @@ export interface ZenkoWorldParameters extends ClientOptions { KafkaExternalIps: string; KafkaHosts: string; KafkaAuthHosts: string; - KafkaConnectUrl: string; PrometheusService: string; PrometheusEndpoint: string; KeycloakUsername: string; KeycloakPassword: string; KeycloakHost: string; - KeycloakPort: string; KeycloakRealm: string; - KeycloakClientId: string; - KeycloakGrantType: string; - StorageManagerUsername: string; - StorageAccountOwnerUsername: string; - DataConsumerUsername: string; - DataAccessorUsername: string; - ServiceUsersCredentials: string; KeycloakTestPassword: string; AzureAccountName: string; AzureAccountKey: string; AzureArchiveContainer: string; AzureArchiveContainer2: string; - AzureArchiveAccessTier: string; - AzureArchiveManifestTier: string; AzureArchiveQueue: string; - TimeProgressionFactor: number; - KafkaDeadLetterQueueTopic: string; - KafkaObjectTaskTopic: string; - KafkaGCRequestTopic: string; - InstanceID: string; - BackbeatApiHost: string; - BackbeatApiPort: string; - KafkaCleanerInterval: string; - SorbetdRestoreTimeout: string; - UtilizationServiceHost: string; - UtilizationServicePort: string; - [key: string]: unknown; + KubeconfigPath?: string; } /** @@ -153,17 +126,15 @@ export default class Zenko extends World { */ constructor(options: IWorldOptions) { super(options); + Logger.createLogger(this); - // store service users credentials from world parameters - if (this.parameters.ServiceUsersCredentials) { - const serviceUserCredentials = - JSON.parse(this.parameters.ServiceUsersCredentials) as Record; - for (const serviceUserName in serviceUserCredentials) { - if (!Identity.hasIdentity(IdentityEnum.SERVICE_USER, serviceUserName, this.parameters.AccountName)) { - Identity.addIdentity(IdentityEnum.SERVICE_USER, serviceUserName, { - accessKeyId: serviceUserCredentials[serviceUserName].accessKey, - secretAccessKey: serviceUserCredentials[serviceUserName].secretKey, - }, this.parameters.AccountName); + if (config?.ServiceUsers) { + for (const creds of Object.values(config.ServiceUsers)) { + if (creds?.name && !Identity.hasIdentity(IdentityEnum.SERVICE_USER, creds.name, ZENKO_ACCOUNT_NAME)) { + Identity.addIdentity(IdentityEnum.SERVICE_USER, creds.name, { + accessKeyId: creds.accessKey, + secretAccessKey: creds.secretKey, + }, ZENKO_ACCOUNT_NAME); } } } @@ -175,44 +146,37 @@ export default class Zenko extends World { CacheHelper.savedAcrossTests[Zenko.PRA_INSTALL_COUNT_KEY] = 0; - - if (this.parameters.AccountName && !Identity.hasIdentity(IdentityEnum.ACCOUNT, this.parameters.AccountName)) { - Identity.addIdentity(IdentityEnum.ACCOUNT, this.parameters.AccountName, { - accessKeyId: this.parameters.AccountAccessKey, - secretAccessKey: this.parameters.AccountSecretKey, - }); + Identity.defaultAccountName = ZENKO_ACCOUNT_NAME; + if (Identity.hasIdentity(IdentityEnum.ACCOUNT, ZENKO_ACCOUNT_NAME)) { + Identity.useIdentity(IdentityEnum.ACCOUNT, ZENKO_ACCOUNT_NAME); } - if (this.parameters.AccountName) { - Identity.useIdentity(IdentityEnum.ACCOUNT, this.parameters.AccountName); - Identity.defaultAccountName = this.parameters.AccountName; - } + if (config.AdminCredentials) { + if (!Identity.hasIdentity(IdentityEnum.ADMIN, Zenko.PRIMARY_SITE_NAME)) { + Identity.addIdentity(IdentityEnum.ADMIN, Zenko.PRIMARY_SITE_NAME, { + accessKeyId: config.AdminCredentials.accessKey, + secretAccessKey: config.AdminCredentials.secretKey, + }, undefined, undefined, undefined, this.parameters.subdomain); - if (this.parameters.AdminAccessKey && this.parameters.AdminSecretKey && - !Identity.hasIdentity(IdentityEnum.ADMIN, Zenko.PRIMARY_SITE_NAME)) { - Identity.addIdentity(IdentityEnum.ADMIN, Zenko.PRIMARY_SITE_NAME, { - accessKeyId: this.parameters.AdminAccessKey, - secretAccessKey: this.parameters.AdminSecretKey, - }, undefined, undefined, undefined, this.parameters.subdomain); + Zenko.sites['source'] = { + accountName: Identity.defaultAccountName, + adminIdentityName: Zenko.PRIMARY_SITE_NAME, + }; + } - Zenko.sites['source'] = { - accountName: Identity.defaultAccountName, - adminIdentityName: Zenko.PRIMARY_SITE_NAME, - }; - } + if (this.needsSecondarySite()) { + if (!Identity.hasIdentity(IdentityEnum.ADMIN, Zenko.SECONDARY_SITE_NAME)) { + Identity.addIdentity(IdentityEnum.ADMIN, Zenko.SECONDARY_SITE_NAME, { + accessKeyId: config.DRAdmin!.accessKey, + secretAccessKey: config.DRAdmin!.secretKey, + }, undefined, undefined, undefined, this.parameters.DRSubdomain); + } - if (this.needsSecondarySite()) { - if (!Identity.hasIdentity(IdentityEnum.ADMIN, Zenko.SECONDARY_SITE_NAME)) { - Identity.addIdentity(IdentityEnum.ADMIN, Zenko.SECONDARY_SITE_NAME, { - accessKeyId: this.parameters.DRAdminAccessKey!, - secretAccessKey: this.parameters.DRAdminSecretKey!, - }, undefined, undefined, undefined, this.parameters.DRSubdomain); + Zenko.sites['sink'] = { + accountName: `dr${ZENKO_ACCOUNT_NAME}`, + adminIdentityName: Zenko.SECONDARY_SITE_NAME, + }; } - - Zenko.sites['sink'] = { - accountName: `dr${this.parameters.AccountName}`, - adminIdentityName: Zenko.SECONDARY_SITE_NAME, - }; } this.logger.debug('Zenko sites', { @@ -221,7 +185,7 @@ export default class Zenko extends World { } private needsSecondarySite() { - return this.parameters.DRAdminAccessKey && this.parameters.DRAdminSecretKey && this.parameters.DRSubdomain; + return config.DRAdmin && this.parameters.DRSubdomain; } /** @@ -276,19 +240,19 @@ export default class Zenko extends World { await this.prepareIamUser(); break; case EntityType.STORAGE_MANAGER: - await this.prepareARWWI(this.parameters.StorageManagerUsername || 'storage_manager', + await this.prepareARWWI('storage_manager', 'storage-manager-role', this.parameters.KeycloakTestPassword); break; case EntityType.STORAGE_ACCOUNT_OWNER: - await this.prepareARWWI(this.parameters.StorageAccountOwnerUsername || 'storage_account_owner', + await this.prepareARWWI('storage_account_owner', 'storage-account-owner-role', this.parameters.KeycloakTestPassword); break; case EntityType.DATA_CONSUMER: - await this.prepareARWWI(this.parameters.DataConsumerUsername || 'data_consumer', + await this.prepareARWWI('data_consumer', 'data-consumer-role', this.parameters.KeycloakTestPassword); break; case EntityType.DATA_ACCESSOR: - await this.prepareARWWI(this.parameters.DataAccessorUsername || 'data_accessor', + await this.prepareARWWI('data_accessor', 'data-accessor-role', this.parameters.KeycloakTestPassword); break; case EntityType.ASSUME_ROLE_USER: @@ -327,10 +291,10 @@ export default class Zenko extends World { ARWWIName, ARWWIPassword || '123', this.parameters.KeycloakHost || 'keycloak.zenko.local', - this.parameters.KeycloakPort || '80', - `/auth/realms/${this.parameters.KeycloakRealm || 'zenko'}/protocol/openid-connect/token`, - this.parameters.KeycloakClientId || Constants.K_CLIENT, - this.parameters.KeycloakGrantType || 'password', + KEYCLOAK_TEST_PORT, + `/auth/realms/${this.parameters.KeycloakRealm}/protocol/openid-connect/token`, + Constants.K_CLIENT, + KEYCLOAK_GRANT_TYPE, ); if (!webIdentityToken) { throw new Error('Error when trying to get a WebIdentity token.'); @@ -732,10 +696,10 @@ export default class Zenko extends World { } } - const accountName = this.sites['source']?.accountName || CacheHelper.parameters.AccountName!; + const accountName = this.sites['source']?.accountName || ZENKO_ACCOUNT_NAME; const accountAccessKeys = Identity.getCredentialsForIdentity( IdentityEnum.ACCOUNT, this.sites['source']?.accountName - || CacheHelper.parameters.AccountName!) || { + || ZENKO_ACCOUNT_NAME) || { accessKeyId: '', secretAccessKey: '', }; @@ -1000,13 +964,13 @@ export default class Zenko extends World { username?: string, ): Promise<{ statusCode: number; data: object } | { statusCode: number; err: unknown }> { const token = await this.getWebIdentityToken( - username || this.parameters.KeycloakUsername || 'storage_manager', - this.parameters.KeycloakPassword || '123', - this.parameters.KeycloakHost || 'keycloak.zenko.local', - this.parameters.KeycloakPort || '80', - `/auth/realms/${this.parameters.KeycloakRealm || 'zenko'}/protocol/openid-connect/token`, - this.parameters.KeycloakClientId || Constants.K_CLIENT, - this.parameters.KeycloakGrantType || 'password', + username || this.parameters.KeycloakUsername, + this.parameters.KeycloakPassword, + this.parameters.KeycloakHost, + KEYCLOAK_TEST_PORT, + `/auth/realms/${this.parameters.KeycloakRealm}/protocol/openid-connect/token`, + Constants.K_CLIENT, + KEYCLOAK_GRANT_TYPE, ); const axiosInstance = axios.create(); const protocol = this.parameters.ssl === false ? 'http://' : 'https://'; @@ -1053,7 +1017,7 @@ export default class Zenko extends World { async addWebsiteEndpoint(this: Zenko, endpoint: string): Promise<{ statusCode: number; data: object } | { statusCode: number; err: unknown }> { return await this.managementAPIRequest('POST', - `/config/${this.parameters.InstanceID}/website/endpoint`, + `/config/${config.ZenkoCR.InstanceID}/website/endpoint`, { 'Content-Type': 'application/json', }, @@ -1063,7 +1027,7 @@ export default class Zenko extends World { async deleteLocation(this: Zenko, locationName: string): Promise<{ statusCode: number; data: object } | { statusCode: number; err: unknown }> { return await this.managementAPIRequest('DELETE', - `/config/${this.parameters.InstanceID}/location/${locationName}`); + `/config/${config.ZenkoCR.InstanceID}/location/${locationName}`); } saveCreatedObject(objectName: string, versionId: string) { diff --git a/tests/functional/mocha/.mocharc.js b/tests/functional/mocha/.mocharc.js index c0efbe6b89..665f82df74 100644 --- a/tests/functional/mocha/.mocharc.js +++ b/tests/functional/mocha/.mocharc.js @@ -5,4 +5,5 @@ module.exports = { 'exit': true, 'reporter': 'mocha-multi-reporters', 'reporter-options': 'configFile=mocha/mocha-reporter.json', + 'require': ['ts-node/register', 'tsconfig-paths/register', './mocha/setup.ts'], }; diff --git a/tests/functional/mocha/VaultClient.js b/tests/functional/mocha/VaultClient.js index dc34e779dc..10ed3b19f6 100644 --- a/tests/functional/mocha/VaultClient.js +++ b/tests/functional/mocha/VaultClient.js @@ -1,4 +1,5 @@ const fs = require('fs'); +const { config, VAULT_ENDPOINT } = require('tests_common/configuration'); const { IAMClient, DetachUserPolicyCommand, @@ -91,8 +92,7 @@ class VaultClient { * @returns {object} - returns an IAM client */ static getIamClient(accessKey, secretKey, sessionToken) { - const endpoint = process.env.VAULT_ENDPOINT - || 'http://localhost:8600'; + const endpoint = VAULT_ENDPOINT; const info = { endpoint, region: 'us-east-1', @@ -129,32 +129,16 @@ class VaultClient { * @returns {object} Vault endpoint information */ static getEndpointInformation() { - let host = '127.0.0.1'; - let port = 8600; + const res = /^https?:\/\/([^:]*)(:[0-9]+)?\/?$/.exec(VAULT_ENDPOINT); + let [host, port] = res.slice(1); + port = port ? parseInt(port.substring(1), 10) : 80; let ca; let cert; let key; - if (process.env.VAULT_ENDPOINT) { - const res = /^https?:\/\/([^:]*)(:[0-9]+)?\/?$/.exec( - process.env.VAULT_ENDPOINT, - ); - [host, port] = res.slice(1); - port = port ? parseInt(port.substring(1), 10) : 80; - const https = process.env.VAULT_ENDPOINT.startsWith('https://'); - if (https) { - ca = fs.readFileSync( - process.env.VAULT_SSL_CA || '/conf/ca.crt', - 'ascii', - ); - cert = fs.readFileSync( - process.env.VAULT_SSL_CERT || '/conf/test.crt', - 'ascii', - ); - key = fs.readFileSync( - process.env.VAULT_SSL_KEY || '/conf/test.key', - 'ascii', - ); - } + if (VAULT_ENDPOINT.startsWith('https://')) { + ca = fs.readFileSync(process.env.VAULT_SSL_CA || '/conf/ca.crt', 'ascii'); + cert = fs.readFileSync(process.env.VAULT_SSL_CERT || '/conf/test.crt', 'ascii'); + key = fs.readFileSync(process.env.VAULT_SSL_KEY || '/conf/test.key', 'ascii'); } return { host, @@ -172,8 +156,8 @@ class VaultClient { */ static getAdminClient() { const adminCredentials = { - accessKey: process.env.ADMIN_ACCESS_KEY_ID, - secretKeyValue: process.env.ADMIN_SECRET_ACCESS_KEY, + accessKey: config.AdminCredentials.accessKey, + secretKeyValue: config.AdminCredentials.secretKey, }; const info = this.getEndpointInformation(); return new vaultclient.Client( diff --git a/tests/functional/mocha/backbeat/IngestionUtility.js b/tests/functional/mocha/backbeat/IngestionUtility.js index 64dc598948..9204857cac 100644 --- a/tests/functional/mocha/backbeat/IngestionUtility.js +++ b/tests/functional/mocha/backbeat/IngestionUtility.js @@ -8,7 +8,8 @@ const { ListObjectVersionsCommand, PutObjectCommand, } = require('@aws-sdk/client-s3'); -const { scalityS3Client, ringS3Client } = require('../s3SDK'); +const { ringS3Client } = require('../s3SDK'); +const { config } = require('tests_common/configuration'); const ReplicationUtility = require('./ReplicationUtility'); const BackbeatAPIUtility = require('./BackbeatAPIUtility'); @@ -213,7 +214,7 @@ class IngestionUtility extends ReplicationUtility { versionId, next, ), - next => this._setS3Client(scalityS3Client).getObjectTagging( + next => this._setS3Client(config.ZenkoAccount.s3Client).getObjectTagging( destBucket, key, versionId, diff --git a/tests/functional/mocha/backbeat/ReplicationUtility.js b/tests/functional/mocha/backbeat/ReplicationUtility.js index 1c79d449da..cdd125fdf1 100644 --- a/tests/functional/mocha/backbeat/ReplicationUtility.js +++ b/tests/functional/mocha/backbeat/ReplicationUtility.js @@ -26,7 +26,8 @@ const { GetObjectTaggingCommand, DeleteObjectCommand, } = require('@aws-sdk/client-s3'); -const { scalityS3Client, awsS3Client } = require('../s3SDK'); +const { awsS3Client } = require('../s3SDK'); +const { config } = require('tests_common/configuration'); const srcLocation = process.env.AWS_BACKEND_SOURCE_LOCATION; const destAWSLocation = process.env.AWS_BACKEND_DESTINATION_LOCATION; @@ -829,7 +830,7 @@ class ReplicationUtility { next => this._setS3Client(awsS3Client) .getObject(destBucket, `${srcBucket}/${key}`, next), ], (err, data) => { - this._setS3Client(scalityS3Client); + this._setS3Client(config.ZenkoAccount.s3Client); if (err) { return cb(err); } @@ -1112,7 +1113,7 @@ class ReplicationUtility { next => this._setS3Client(awsS3Client) .getObjectACL(destBucket, `${srcBucket}/${key}`, next), ], (err, data) => { - this._setS3Client(scalityS3Client); + this._setS3Client(config.ZenkoAccount.s3Client); if (err) { return cb(err); } @@ -1165,7 +1166,7 @@ class ReplicationUtility { next => this._setS3Client(awsS3Client) .getObjectTagging(destBucket, `${srcBucket}/${key}`, AWSVersionId, next), ], (err, data) => { - this._setS3Client(scalityS3Client); + this._setS3Client(config.ZenkoAccount.s3Client); if (err) { return cb(err); } diff --git a/tests/functional/mocha/backbeat/tests/api/metrics.js b/tests/functional/mocha/backbeat/tests/api/metrics.js index 6b1745c23b..e6dcb0cf38 100644 --- a/tests/functional/mocha/backbeat/tests/api/metrics.js +++ b/tests/functional/mocha/backbeat/tests/api/metrics.js @@ -2,12 +2,12 @@ const assert = require('assert'); const crypto = require('crypto'); const { doWhilst, series } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const sharedBlobSvc = require('../../azureSDK'); const ReplicationUtility = require('../../ReplicationUtility'); const { makeGETRequest, getResponseBody } = require('../../../utils/request'); -const scalityUtils = new ReplicationUtility(scalityS3Client, sharedBlobSvc); const awsUtils = new ReplicationUtility(awsS3Client); const srcBucket = `source-bucket-${Date.now()}`; @@ -116,11 +116,14 @@ describe('Backbeat replication metrics route validation', function dF() { }); describe('Backbeat replication metrics data', function dF() { + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; const storageClass = `${destAWSLocation},${destAzureLocation}`; const pathPrefix = '/_/backbeat/api/metrics/crr'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client, sharedBlobSvc); }); + beforeEach(done => series([ next => scalityUtils.createVersionedBucket(srcBucket, next), next => scalityUtils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/api/objectMonitor.js b/tests/functional/mocha/backbeat/tests/api/objectMonitor.js index 7b5db563da..e2d14bceae 100644 --- a/tests/functional/mocha/backbeat/tests/api/objectMonitor.js +++ b/tests/functional/mocha/backbeat/tests/api/objectMonitor.js @@ -2,11 +2,11 @@ const assert = require('assert'); const crypto = require('crypto'); const { series, waterfall, doWhilst } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const ReplicationUtility = require('../../ReplicationUtility'); const { makeGETRequest, getResponseBody } = require('../../../utils/request'); -const scalityUtils = new ReplicationUtility(scalityS3Client); const awsUtils = new ReplicationUtility(awsS3Client); const srcBucket = `source-bucket-${Date.now()}`; const destBucket = process.env.AWS_CRR_BUCKET_NAME; @@ -54,9 +54,12 @@ function getAndCheckResponse(path, expectedBody, cb) { } describe('Backbeat object monitor CRR metrics', function () { + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client); }); + beforeEach(done => series([ next => scalityUtils.createVersionedBucket(srcBucket, next), next => scalityUtils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/crr-pause-resume/awsBackend.js b/tests/functional/mocha/backbeat/tests/crr-pause-resume/awsBackend.js index eb771b5640..342e0ab0b1 100644 --- a/tests/functional/mocha/backbeat/tests/crr-pause-resume/awsBackend.js +++ b/tests/functional/mocha/backbeat/tests/crr-pause-resume/awsBackend.js @@ -2,11 +2,11 @@ const assert = require('assert'); const crypto = require('crypto'); const { series } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const ReplicationUtility = require('../../ReplicationUtility'); const BackbeatAPIUtility = require('../../BackbeatAPIUtility'); -const scalityUtils = new ReplicationUtility(scalityS3Client); const awsUtils = new ReplicationUtility(awsS3Client); const backbeatAPIUtils = new BackbeatAPIUtility(); const srcBucket = `source-bucket-${Date.now()}`; @@ -30,9 +30,12 @@ const REPLICATION_TIMEOUT = 300000; // the tests checked before replication was complete. describe('Replication Pause-Resume with AWS backend', function () { + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client); }); + beforeEach(done => series([ next => scalityUtils.createVersionedBucket(srcBucket, next), next => scalityUtils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/crr/awsBackend.js b/tests/functional/mocha/backbeat/tests/crr/awsBackend.js index 0a9017ce33..fc1e66d33a 100644 --- a/tests/functional/mocha/backbeat/tests/crr/awsBackend.js +++ b/tests/functional/mocha/backbeat/tests/crr/awsBackend.js @@ -1,10 +1,10 @@ const crypto = require('crypto'); const { series } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const ReplicationUtility = require('../../ReplicationUtility'); -const scalityUtils = new ReplicationUtility(scalityS3Client); const awsUtils = new ReplicationUtility(awsS3Client); const srcBucket = `source-bucket-${Date.now()}`; const destBucket = process.env.AWS_CRR_BUCKET_NAME; @@ -21,11 +21,13 @@ const keyutf8 = `${keyPrefix}/%EA%9D%8崰㈌㒈保轖䳷䀰⺩ቆ楪僷ꈅꓜ퇬 const REPLICATION_TIMEOUT = 300000; describe('Replication with AWS backend', function () { - // eslint-disable-next-line + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); this.retries(3); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client); }); + beforeEach(done => series([ next => scalityUtils.createVersionedBucket(srcBucket, next), next => scalityUtils.putBucketReplication( @@ -979,9 +981,12 @@ describe('Replication with AWS backend', function () { }); describe.skip('Replication with AWS backend: source AWS location', function () { + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client); }); + beforeEach(done => series([ next => scalityUtils.createVersionedBucketAWS(srcBucket, next), next => scalityUtils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/crr/azureBackend.js b/tests/functional/mocha/backbeat/tests/crr/azureBackend.js index ae8be2b572..91ed998d88 100644 --- a/tests/functional/mocha/backbeat/tests/crr/azureBackend.js +++ b/tests/functional/mocha/backbeat/tests/crr/azureBackend.js @@ -2,11 +2,10 @@ const assert = require('assert'); const crypto = require('crypto'); const { series } = require('async'); -const { scalityS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const sharedBlobSvc = require('../../azureSDK'); const ReplicationUtility = require('../../ReplicationUtility'); -const utils = new ReplicationUtility(scalityS3Client, sharedBlobSvc); const destContainer = process.env.AZURE_CRR_BUCKET_NAME; const destLocation = process.env.AZURE_BACKEND_DESTINATION_LOCATION; const srcBucket = `source-bucket-${Date.now()}`; @@ -23,10 +22,13 @@ const keyutf8 = `${keyPrefix}/%EA%9D%8B崰㈌㒈保轖䳷䀰⺩ቆ楪秲ⴝ㿅 const REPLICATION_TIMEOUT = 300000; describe('Replication with Azure backend', function () { + let utils; this.timeout(REPLICATION_TIMEOUT); this.retries(3); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { utils = new ReplicationUtility(config.ZenkoAccount.s3Client, sharedBlobSvc); }); + beforeEach(done => series([ next => utils.createVersionedBucket(srcBucket, next), next => utils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/crr/gcpBackend.js b/tests/functional/mocha/backbeat/tests/crr/gcpBackend.js index 5b7d4afae9..66f4f4334f 100644 --- a/tests/functional/mocha/backbeat/tests/crr/gcpBackend.js +++ b/tests/functional/mocha/backbeat/tests/crr/gcpBackend.js @@ -2,11 +2,10 @@ const assert = require('assert'); const crypto = require('crypto'); const { series } = require('async'); -const { scalityS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const gcpStorage = require('../../gcpStorage'); const ReplicationUtility = require('../../ReplicationUtility'); -const utils = new ReplicationUtility(scalityS3Client, undefined, gcpStorage); const destBucket = process.env.GCP_CRR_BUCKET_NAME; const destGCPLocation = process.env.GCP_BACKEND_DESTINATION_LOCATION; const srcBucket = `source-bucket-${Date.now()}`; @@ -22,6 +21,7 @@ const fileutf8 = `${filePrefix}/%EA%9D%8B崰㈌㒈保轖䳷䀰⺩ቆ楪僷ꈅꓜ const REPLICATION_TIMEOUT = 300000; describe('Replication with GCP backend', function () { + let utils; if (!process.env.GCP_BACKEND_DESTINATION_LOCATION) { this.skip(); } @@ -30,6 +30,8 @@ describe('Replication with GCP backend', function () { this.retries(3); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { utils = new ReplicationUtility(config.ZenkoAccount.s3Client, undefined, gcpStorage); }); + beforeEach(done => series([ next => utils.createVersionedBucket(srcBucket, next), next => utils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/crr/oneToMany.js b/tests/functional/mocha/backbeat/tests/crr/oneToMany.js index c89a7d4716..b08f4cb38b 100644 --- a/tests/functional/mocha/backbeat/tests/crr/oneToMany.js +++ b/tests/functional/mocha/backbeat/tests/crr/oneToMany.js @@ -1,12 +1,12 @@ const crypto = require('crypto'); const { series } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const sharedBlobSvc = require('../../azureSDK'); const gcpStorage = require('../../gcpStorage'); const ReplicationUtility = require('../../ReplicationUtility'); -const utils = new ReplicationUtility(scalityS3Client, sharedBlobSvc, gcpStorage); const awsUtils = new ReplicationUtility(awsS3Client); const srcBucket = `source-bucket-${Date.now()}`; const awsDestBucket = process.env.AWS_CRR_BUCKET_NAME; @@ -28,11 +28,14 @@ const REPLICATION_TIMEOUT = 300000; describe( 'Replication with AWS, Azure, and GCP backends (one-to-many)', function () { + let utils; this.timeout(REPLICATION_TIMEOUT); this.retries(3); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; const storageClass = `${destAWSLocation},${destAzureLocation},${destGCPLocation}`; + before(() => { utils = new ReplicationUtility(config.ZenkoAccount.s3Client, sharedBlobSvc, gcpStorage); }); + beforeEach(done => series([ next => utils.createVersionedBucket(srcBucket, next), next => utils.putBucketReplication( diff --git a/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3C.js b/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3C.js index ffaa446a5f..27d738a31a 100644 --- a/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3C.js +++ b/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3C.js @@ -3,10 +3,10 @@ const async = require('async'); const { v4: uuid } = require('uuid'); const { ListObjectVersionsCommand } = require('@aws-sdk/client-s3'); -const { scalityS3Client, ringS3Client } = require('../../../s3SDK'); +const { ringS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const IngestionUtility = require('../../IngestionUtility'); -const scalityUtils = new IngestionUtility(scalityS3Client, ringS3Client); const ringS3CUtils = new IngestionUtility(ringS3Client); const ingestionSrcBucket = process.env.RING_S3C_INGESTION_SRC_BUCKET_NAME; const srcLocation = process.env.RING_S3C_BACKEND_SOURCE_LOCATION; @@ -20,6 +20,9 @@ let KEY_PREFIX; let OBJ_KEY; describe('Ingesting existing data from RING S3C bucket', () => { + let scalityUtils; + before(() => { scalityUtils = new IngestionUtility(config.ZenkoAccount.s3Client, ringS3Client); }); + beforeEach(function () { INGESTION_DEST_BUCKET = `ingestion-${uuid()}`; KEY_PREFIX = `${ingestionSrcBucket}-${uuid()}`; diff --git a/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3CPauseResume.js b/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3CPauseResume.js index 944874e22e..cc11cf0d79 100644 --- a/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3CPauseResume.js +++ b/tests/functional/mocha/backbeat/tests/ingestion/ingestionS3CPauseResume.js @@ -2,11 +2,11 @@ const assert = require('assert'); const { series } = require('async'); const { v4: uuid } = require('uuid'); -const { scalityS3Client, ringS3Client } = require('../../../s3SDK'); +const { ringS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const IngestionUtility = require('../../IngestionUtility'); const BackbeatAPIUtility = require('../../BackbeatAPIUtility'); -const scalityUtils = new IngestionUtility(scalityS3Client, ringS3Client); const ringS3CUtils = new IngestionUtility(ringS3Client); const backbeatAPIUtils = new BackbeatAPIUtility(); const ingestionSrcBucket = process.env.RING_S3C_INGESTION_SRC_BUCKET_NAME; @@ -20,8 +20,11 @@ let OBJ_DATA; const INGESTION_TIMEOUT = 300000; describe('Ingestion pause resume', function () { + let scalityUtils; this.timeout(INGESTION_TIMEOUT); + before(() => { scalityUtils = new IngestionUtility(config.ZenkoAccount.s3Client, ringS3Client); }); + beforeEach(done => { INGESTION_DEST_BUCKET = `ingestion-${uuid()}`; KEY_PREFIX = `${ingestionSrcBucket}-${uuid()}`; diff --git a/tests/functional/mocha/backbeat/tests/ingestion/oobS3C.js b/tests/functional/mocha/backbeat/tests/ingestion/oobS3C.js index 49dc09aae6..a12245a8f1 100644 --- a/tests/functional/mocha/backbeat/tests/ingestion/oobS3C.js +++ b/tests/functional/mocha/backbeat/tests/ingestion/oobS3C.js @@ -2,10 +2,10 @@ const async = require('async'); const { v4: uuid } = require('uuid'); const { ListObjectVersionsCommand } = require('@aws-sdk/client-s3'); -const { scalityS3Client, ringS3Client } = require('../../../s3SDK'); +const { ringS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const IngestionUtility = require('../../IngestionUtility'); -const scalityUtils = new IngestionUtility(scalityS3Client, ringS3Client); const ringS3CUtils = new IngestionUtility(ringS3Client); const ingestionSrcBucket = process.env.RING_S3C_INGESTION_SRC_BUCKET_NAME; const srcLocation = process.env.RING_S3C_BACKEND_SOURCE_LOCATION; @@ -15,6 +15,9 @@ let INGESTION_DEST_BUCKET; let OBJ_KEY; describe('OOB updates for RING S3C bucket', () => { + let scalityUtils; + before(() => { scalityUtils = new IngestionUtility(config.ZenkoAccount.s3Client, ringS3Client); }); + beforeEach(done => { INGESTION_DEST_BUCKET = `ingestion-${uuid()}`; OBJ_KEY = `${KEY_PREFIX}/object-to-ingest-${uuid()}`; diff --git a/tests/functional/mocha/backbeat/tests/lifecycle/expiration.js b/tests/functional/mocha/backbeat/tests/lifecycle/expiration.js index fad0bef0da..2314e162a7 100644 --- a/tests/functional/mocha/backbeat/tests/lifecycle/expiration.js +++ b/tests/functional/mocha/backbeat/tests/lifecycle/expiration.js @@ -1,10 +1,9 @@ const uuid = require('uuid'); const async = require('async'); -const { scalityS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const LifecycleUtlity = require('../../LifecycleUtility'); -const utils = new LifecycleUtlity(scalityS3Client); const getBucketName = prefix => `${prefix}${uuid.v4()}`; const getObjectKey = prefix => `${prefix}${uuid.v4()}`; const getObjectKeys = (prefix, count) => Array.from(Array(count)).map((_, n) => getObjectKey(`${prefix}${n}-`)); @@ -108,16 +107,20 @@ const longExpireMPURule = (prefix, tag, enabled) => ({ }); describe('Lifecycle Expiration', function () { + let utils; const notTargetObjectPrefix = 'not-exp-target/'; const targetObjectPrefix = 'exp-target/'; - utils.setSourceLocation('us-east-1'); - // GC consumer might take a long time to consume its entries. // If it is the case, timeout after 5 minutes and retry. this.retries(3); this.timeout(360000); + before(() => { + utils = new LifecycleUtlity(config.ZenkoAccount.s3Client); + utils.setSourceLocation('us-east-1'); + }); + describe('behavior: should not delete objects', () => { const bucketName = getBucketName('exp-dis-'); const objectKey = getObjectKey('exp-disabled-'); diff --git a/tests/functional/mocha/backbeat/tests/lifecycle/transition.js b/tests/functional/mocha/backbeat/tests/lifecycle/transition.js index 8466bf7faa..7904f30420 100644 --- a/tests/functional/mocha/backbeat/tests/lifecycle/transition.js +++ b/tests/functional/mocha/backbeat/tests/lifecycle/transition.js @@ -2,7 +2,8 @@ const assert = require('assert'); const { v4: uuid } = require('uuid'); const { series } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const LifecycleUtility = require('../../LifecycleUtility'); function compareTransitionedData(sourceClient, destinationClient, versionId, cb) { @@ -92,9 +93,7 @@ testsToRun.forEach(test => { describe(`Lifecycle transition from ${test.from} to ${test.to}`, function () { const srcBucket = `transition-${uuid()}`; const keyPrefix = uuid(); - const cloudServer = new LifecycleUtility(scalityS3Client) - .setBucket(srcBucket) - .setKeyPrefix(keyPrefix); + let cloudServer; const cloud = new LifecycleUtility(awsS3Client).setKeyPrefix(keyPrefix); const fromLoc = locationParams[test.from]; const toLoc = locationParams[test.to]; @@ -108,6 +107,9 @@ testsToRun.forEach(test => { } before(() => { + cloudServer = new LifecycleUtility(config.ZenkoAccount.s3Client) + .setBucket(srcBucket) + .setKeyPrefix(keyPrefix); cloudServer.setSourceLocation(fromLoc.name); cloudServer.setDestinationLocation(toLoc.name); if (!toLoc.isCold) { diff --git a/tests/functional/mocha/backbeat/tests/retry/pendingMetrics.js b/tests/functional/mocha/backbeat/tests/retry/pendingMetrics.js index 14295d9738..6b71aa8d76 100644 --- a/tests/functional/mocha/backbeat/tests/retry/pendingMetrics.js +++ b/tests/functional/mocha/backbeat/tests/retry/pendingMetrics.js @@ -4,12 +4,12 @@ const { doWhilst, parallel, waterfall, series, } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const sharedBlobSvc = require('../../azureSDK'); const ReplicationUtility = require('../../ReplicationUtility'); const { makeGETRequest, getResponseBody, makeUpdateRequest } = require('../../../utils/request'); -const scalityUtils = new ReplicationUtility(scalityS3Client, sharedBlobSvc); const awsUtils = new ReplicationUtility(awsS3Client); const srcBucket = `source-bucket-${Date.now()}`; @@ -59,9 +59,12 @@ function getPendingPath(location) { } describe('Backbeat API pending metrics', function () { + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client, sharedBlobSvc); }); + describe('Completed CRR', () => { const pendingPath = getPendingPath(destAWSLocation); diff --git a/tests/functional/mocha/backbeat/tests/retry/retry.js b/tests/functional/mocha/backbeat/tests/retry/retry.js index d27c434847..f4ead161d0 100644 --- a/tests/functional/mocha/backbeat/tests/retry/retry.js +++ b/tests/functional/mocha/backbeat/tests/retry/retry.js @@ -4,11 +4,11 @@ const { series, parallel, times, timesSeries, doWhilst, } = require('async'); -const { scalityS3Client, awsS3Client } = require('../../../s3SDK'); +const { awsS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const ReplicationUtility = require('../../ReplicationUtility'); const { makeGETRequest, makeUpdateRequest, getResponseBody } = require('../../../utils/request'); -const scalityUtils = new ReplicationUtility(scalityS3Client); const awsUtils = new ReplicationUtility(awsS3Client); const srcBucket = `source-bucket-${Date.now()}`; const destFailBucket = process.env.AWS_S3_FAIL_BACKBEAT_BUCKET_NAME; @@ -41,7 +41,7 @@ function checkMetrics( assert.strictEqual((pending.results.size - prevPending.size), 0); } -function performRetries(keys, done) { +function performRetries(scalityUtils, keys, done) { let postBody; return series([ next => awsUtils.deleteVersionedBucket(destFailBucket, next), @@ -126,9 +126,12 @@ function performRetries(keys, done) { } describe('Backbeat replication retry', function () { + let scalityUtils; this.timeout(REPLICATION_TIMEOUT); const roleArn = 'arn:aws:iam::root:role/s3-replication-role'; + before(() => { scalityUtils = new ReplicationUtility(config.ZenkoAccount.s3Client); }); + beforeEach(done => series([ next => scalityUtils.createVersionedBucket(srcBucket, next), next => scalityUtils.putBucketReplication( @@ -159,7 +162,7 @@ describe('Backbeat replication retry', function () { for (let i = 0; i < N; i++) { keys.push(`${key}-${i}`); } - return performRetries(keys, done); + return performRetries(scalityUtils, keys, done); }); }); @@ -183,7 +186,7 @@ describe('Backbeat replication retry', function () { return next(); }); }), - next => performRetries([key], next), + next => performRetries(scalityUtils, [key], next), next => { let shouldContinue = false; return doWhilst( diff --git a/tests/functional/mocha/cloudserver/bucketGetV2/tests/bucketGetV2.js b/tests/functional/mocha/cloudserver/bucketGetV2/tests/bucketGetV2.js index 449d41dcac..437f11d0e8 100644 --- a/tests/functional/mocha/cloudserver/bucketGetV2/tests/bucketGetV2.js +++ b/tests/functional/mocha/cloudserver/bucketGetV2/tests/bucketGetV2.js @@ -9,7 +9,8 @@ const { ListObjectsV2Command, } = require('@aws-sdk/client-s3'); -const s3 = require('../../../s3SDK').scalityS3Client; +const { config } = require('tests_common/configuration'); +let s3; const bucket = `list-v2-${uuidV4()}`; @@ -44,6 +45,7 @@ function expectedKeyList(startKey, endKey) { describe('Bucket GET V2 api', () => { before(done => { + s3 = config.ZenkoAccount.s3Client; async.series([ next => { s3.send(new CreateBucketCommand({ Bucket: bucket })) diff --git a/tests/functional/mocha/cloudserver/bucketPolicy/tests/bucketPolicy.js b/tests/functional/mocha/cloudserver/bucketPolicy/tests/bucketPolicy.js index 5b6d345072..2efa1e667a 100644 --- a/tests/functional/mocha/cloudserver/bucketPolicy/tests/bucketPolicy.js +++ b/tests/functional/mocha/cloudserver/bucketPolicy/tests/bucketPolicy.js @@ -13,7 +13,9 @@ const { GetBucketLocationCommand, } = require('@aws-sdk/client-s3'); -const { scalityS3Client, altScalityS3Client } = require('../../../s3SDK'); +const { altScalityS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); +let scalityS3Client; const testUtils = require('../../../utils/testUtils'); const bucket = `bpolicy-${uuidV4()}`; @@ -99,6 +101,7 @@ function getPolicyParams(paramsToChange) { describe('Bucket policies', () => { beforeEach(async () => { + scalityS3Client = config.ZenkoAccount.s3Client; await scalityS3Client.send(new CreateBucketCommand({ Bucket: bucket, CreateBucketConfiguration: { LocationConstraint: 'us-east-1' }, @@ -585,6 +588,7 @@ describe('Bucket policies', () => { describe('Bucket policies with basic policies', () => { before(done => { + scalityS3Client = config.ZenkoAccount.s3Client; scalityS3Client.createBucket( { Bucket: bucket, diff --git a/tests/functional/mocha/cloudserver/keyFormatVersion/tests/nonVersionedBucket.js b/tests/functional/mocha/cloudserver/keyFormatVersion/tests/nonVersionedBucket.js index 12b582ef04..415ac08710 100644 --- a/tests/functional/mocha/cloudserver/keyFormatVersion/tests/nonVersionedBucket.js +++ b/tests/functional/mocha/cloudserver/keyFormatVersion/tests/nonVersionedBucket.js @@ -11,7 +11,8 @@ const { GetObjectCommand, ListObjectsV2Command, } = require('@aws-sdk/client-s3'); -const s3 = require('../../../s3SDK').scalityS3Client; +const { config } = require('tests_common/configuration'); +let s3; const logger = new werelogs.Logger('keyFormatVersion', 'debug', 'debug'); const { BucketVersioningKeyFormat } = versioning.VersioningConstants; @@ -98,6 +99,7 @@ describe('Cloudserver : keyFormatVersion : non versioned bucket', () => { } before(async () => { + s3 = config.ZenkoAccount.s3Client; const opts = { mongodb: { replicaSetHosts: process.env.MONGO_REPLICA_SET_HOSTS, diff --git a/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versionedBucket.js b/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versionedBucket.js index fd1ef9f3f0..3a89b6d1b5 100644 --- a/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versionedBucket.js +++ b/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versionedBucket.js @@ -13,7 +13,8 @@ const { ListObjectVersionsCommand, PutBucketVersioningCommand, } = require('@aws-sdk/client-s3'); -const s3 = require('../../../s3SDK').scalityS3Client; +const { config } = require('tests_common/configuration'); +let s3; const logger = new werelogs.Logger('keyFormatVersion', 'debug', 'debug'); const { BucketVersioningKeyFormat } = versioning.VersioningConstants; @@ -126,6 +127,7 @@ describe('Cloudserver : keyFormatVersion : versioned bucket', () => { } before(async () => { + s3 = config.ZenkoAccount.s3Client; const opts = { mongodb: { replicaSetHosts: process.env.MONGO_REPLICA_SET_HOSTS, diff --git a/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versioningSuspended.js b/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versioningSuspended.js index 649d16a722..29800e3934 100644 --- a/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versioningSuspended.js +++ b/tests/functional/mocha/cloudserver/keyFormatVersion/tests/versioningSuspended.js @@ -13,7 +13,8 @@ const { ListObjectVersionsCommand, PutBucketVersioningCommand, } = require('@aws-sdk/client-s3'); -const s3 = require('../../../s3SDK').scalityS3Client; +const { config } = require('tests_common/configuration'); +let s3; const logger = new werelogs.Logger('keyFormatVersion', 'debug', 'debug'); const { BucketVersioningKeyFormat } = versioning.VersioningConstants; @@ -138,6 +139,7 @@ describe('Cloudserver : keyFormatVersion : versioning suspended bucket', () => { } before(async () => { + s3 = config.ZenkoAccount.s3Client; const opts = { mongodb: { replicaSetHosts: process.env.MONGO_REPLICA_SET_HOSTS, diff --git a/tests/functional/mocha/cloudserver/locationQuota/tests/locationQuota.js b/tests/functional/mocha/cloudserver/locationQuota/tests/locationQuota.js index c284edea8c..4424a912b6 100644 --- a/tests/functional/mocha/cloudserver/locationQuota/tests/locationQuota.js +++ b/tests/functional/mocha/cloudserver/locationQuota/tests/locationQuota.js @@ -3,15 +3,16 @@ const crypto = require('crypto'); const async = require('async'); const { v4: uuidV4 } = require('uuid'); -const { scalityS3Client } = require('../../../s3SDK'); +const { config } = require('tests_common/configuration'); const QuotaUtility = require('../QuotaUtility'); const TEN_MB_BYTES = 10485760; const bucket = `quota-${uuidV4()}`; -const scalityS3 = new QuotaUtility(scalityS3Client); +let scalityS3; describe('Location storage quota', () => { + before(() => { scalityS3 = new QuotaUtility(config.ZenkoAccount.s3Client); }); beforeEach(function beFn(done) { this.timeout(50000); async.series([ diff --git a/tests/functional/mocha/iam_policies/cloudserver/AssumeRole.js b/tests/functional/mocha/iam_policies/cloudserver/AssumeRole.js index 22a108bf92..7b009331f4 100644 --- a/tests/functional/mocha/iam_policies/cloudserver/AssumeRole.js +++ b/tests/functional/mocha/iam_policies/cloudserver/AssumeRole.js @@ -23,8 +23,6 @@ const { getS3Client } = require('../../s3SDK'); const { getSTSClient } = require('../../stsSDK'); const { metadataSearchResponseCode, restoreObjectResponseCode, putObjectVersionResponseCode } = require('./utils'); -const clientAdmin = VaultClient.getAdminClient(); - const trustPolicy = JSON.stringify({ Version: '2012-10-17', Statement: { @@ -64,6 +62,7 @@ const testAPIs = [ ]; testAPIs.forEach(testAPI => { + let clientAdmin; const account1Name = `iam-policies-assume-role-test-account1-${testAPI.API.toLowerCase()}`; const account1Info = { @@ -95,6 +94,7 @@ testAPIs.forEach(testAPI => { describe(`iam policies - cloudserver - AssumeRole - ${testAPI.API}`, () => { before(async () => { + clientAdmin = VaultClient.getAdminClient(); const res = await new Promise((resolve, reject) => { clientAdmin.createAccount(account1Name, account1Info, (err, res) => (err ? reject(err) : resolve(res))); }); diff --git a/tests/functional/mocha/iam_policies/cloudserver/AssumeRoleWithWebIdentity.js b/tests/functional/mocha/iam_policies/cloudserver/AssumeRoleWithWebIdentity.js index 4c7572e0a0..595c1814e6 100644 --- a/tests/functional/mocha/iam_policies/cloudserver/AssumeRoleWithWebIdentity.js +++ b/tests/functional/mocha/iam_policies/cloudserver/AssumeRoleWithWebIdentity.js @@ -61,7 +61,6 @@ let iamClient = null; let stsClient = null; let s3Client = null; -const clientAdmin = VaultClient.getAdminClient(); const accountName = 'AccountTest'; const accountInfo = { email: `${accountName}@test.com`, @@ -247,10 +246,12 @@ const testAPIs = [ ]; testAPIs.forEach(testAPI => { + let clientAdmin; const bucket1 = `bucket1-${testAPI.API.toLowerCase()}`; describe(`iam policies - cloudserver - AssumeRoleWithWebIdentity - ${testAPI.API}`, () => { before(done => { + clientAdmin = VaultClient.getAdminClient(); async.series([ // create an account, generateAccountAccessKey for it // get iam client, sts client and s3 client of this account diff --git a/tests/functional/mocha/iam_policies/cloudserver/IAMUser.js b/tests/functional/mocha/iam_policies/cloudserver/IAMUser.js index 72f239121d..7ceee3ca6f 100644 --- a/tests/functional/mocha/iam_policies/cloudserver/IAMUser.js +++ b/tests/functional/mocha/iam_policies/cloudserver/IAMUser.js @@ -17,8 +17,8 @@ const { } = require('@aws-sdk/client-iam'); const { metadataSearchResponseCode, createPolicy, restoreObjectResponseCode } = require('./utils'); -const iam = require('../../s3SDK').scalityIAMClient; -const s3 = require('../../s3SDK').scalityS3Client; +const { config } = require('tests_common/configuration'); +let iam, s3; const testAPIs = [ { @@ -58,6 +58,8 @@ testAPIs.forEach(testAPI => { }; before(async () => { + iam = config.ZenkoAccount.iamClient; + s3 = config.ZenkoAccount.s3Client; await s3.send(new CreateBucketCommand({ Bucket: bucketName })); await s3.send(new PutObjectCommand({ Bucket: bucketName, diff --git a/tests/functional/mocha/iam_policies/cloudserver/utils.js b/tests/functional/mocha/iam_policies/cloudserver/utils.js index aba4c3ca76..5815ddfd98 100644 --- a/tests/functional/mocha/iam_policies/cloudserver/utils.js +++ b/tests/functional/mocha/iam_policies/cloudserver/utils.js @@ -1,9 +1,7 @@ const aws4 = require('aws4'); const http = require('http'); const { makeGETRequest, getResponseBody, makeUpdateRequest } = require('../../utils/request'); - -const DEFAULT_HOST = process.env.CLOUDSERVER_HOST; -const DEFAULT_PORT = process.env.CLOUDSERVER_PORT || '80'; +const { CLOUDSERVER_HOST } = require('tests_common/configuration'); // eslint-disable-next-line default-param-last function makeApiCallGeneric(mode = 'GET', body, userCredentials, query, cb) { @@ -59,8 +57,8 @@ function putObjectResponseCode(userCredentials, bucketName, cb, fileName) { function putObjectVersionResponseCode(userCredentials, bucketName, cb, fileName) { const signOptions = { - host: DEFAULT_HOST, - port: DEFAULT_PORT, + host: CLOUDSERVER_HOST, + port: 80, service: 's3', method: 'PUT', path: `/${bucketName}/${fileName}`, diff --git a/tests/functional/mocha/init_test.js b/tests/functional/mocha/init_test.js index 3a46988e93..f89e6bb15c 100644 --- a/tests/functional/mocha/init_test.js +++ b/tests/functional/mocha/init_test.js @@ -10,13 +10,16 @@ const { PutObjectCommand, } = require('@aws-sdk/client-s3'); -const s3 = require('./s3SDK').scalityS3Client; +const { config } = require('tests_common/configuration'); +let s3; const bucket = `get-bucket-${uuidV4()}`; const key = `object-key-${uuidV4()}`; const body = 'testbody'; describe('Test Configuration', () => { + before(() => { s3 = config.ZenkoAccount.s3Client; }); + it('should create a bucket and upload an object', async () => { await s3.send(new CreateBucketCommand({ Bucket: bucket, diff --git a/tests/functional/mocha/s3SDK.js b/tests/functional/mocha/s3SDK.js index 5fd30a32da..1433fe7385 100644 --- a/tests/functional/mocha/s3SDK.js +++ b/tests/functional/mocha/s3SDK.js @@ -1,6 +1,6 @@ const { S3Client } = require('@aws-sdk/client-s3'); -const { IAMClient } = require('@aws-sdk/client-iam'); const { NodeHttpHandler } = require('@smithy/node-http-handler'); +const { CLOUDSERVER_ENDPOINT } = require('tests_common/configuration'); const sharedHttpHandler = new NodeHttpHandler({ requestTimeout: 0, @@ -11,43 +11,6 @@ function createS3Client(config) { return new S3Client(config); } -const scalityS3Client = createS3Client({ - credentials: { - accessKeyId: process.env.ZENKO_ACCESS_KEY, - secretAccessKey: process.env.ZENKO_SECRET_KEY, - sessionToken: process.env.ZENKO_SESSION_TOKEN, - }, - tls: false, - endpoint: process.env.CLOUDSERVER_ENDPOINT, - region: 'us-east-1', - forcePathStyle: true, - // disable node sdk retries and timeout to prevent InvalidPart - // and SocketHangUp errors. If retries are allowed, sdk will send - // another request after first request has already deleted parts, - // causing InvalidPart. Meanwhile, if request takes too long to finish, - // sdk will create SocketHangUp error before response. - maxAttempts: 1, - requestHandler: sharedHttpHandler, -}); - -const scalityIAMClient = new IAMClient({ - credentials: { - accessKeyId: process.env.ZENKO_ACCESS_KEY, - secretAccessKey: process.env.ZENKO_SECRET_KEY, - sessionToken: process.env.ZENKO_SESSION_TOKEN, - }, - tls: false, - endpoint: process.env.VAULT_ENDPOINT, - region: 'us-east-1', - // disable node sdk retries and timeout to prevent InvalidPart - // and SocketHangUp errors. If retries are allowed, sdk will send - // another request after first request has already deleted parts, - // causing InvalidPart. Meanwhile, if request takes too long to finish, - // sdk will create SocketHangUp error before response. - maxAttempts: 1, - requestHandler: sharedHttpHandler, -}); - const verifyCerts = process.env.VERIFY_CERTIFICATES ? process.env.VERIFY_CERTIFICATES : true; @@ -83,7 +46,7 @@ const altScalityS3Client = createS3Client({ secretAccessKey: process.env.AWS_SECRET_KEY, }, tls: false, - endpoint: process.env.CLOUDSERVER_ENDPOINT, + endpoint: CLOUDSERVER_ENDPOINT, region: 'us-east-1', forcePathStyle: true, maxAttempts: 1, @@ -93,7 +56,7 @@ const altScalityS3Client = createS3Client({ function getS3Client(accessKey, secretKey, sessionToken) { const config = { tls: false, - endpoint: process.env.CLOUDSERVER_ENDPOINT, + endpoint: CLOUDSERVER_ENDPOINT, region: 'us-east-1', forcePathStyle: true, credentials: { @@ -108,10 +71,8 @@ function getS3Client(accessKey, secretKey, sessionToken) { } module.exports = { - scalityS3Client, awsS3Client, ringS3Client, altScalityS3Client, - scalityIAMClient, getS3Client, }; diff --git a/tests/functional/mocha/setup.ts b/tests/functional/mocha/setup.ts new file mode 100644 index 0000000000..44a2a7ec0b --- /dev/null +++ b/tests/functional/mocha/setup.ts @@ -0,0 +1,5 @@ +import { initConfig } from '../tests_common/configuration'; + +export const mochaHooks = { + beforeAll: () => initConfig(), +}; diff --git a/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/adminApi.js b/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/adminApi.js index 85ddd37939..e0e9dc2321 100644 --- a/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/adminApi.js +++ b/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/adminApi.js @@ -1,7 +1,6 @@ const async = require('async'); const VaultClient = require('../../VaultClient'); -const clientAdmin = VaultClient.getAdminClient(); const accountName = 'admin-api-test-account'; const accountInfo = { email: `${accountName}@test.com`, @@ -11,6 +10,9 @@ const accountInfo = { let iamClient = null; describe('Accounts: ', () => { + let clientAdmin; + before(() => { clientAdmin = VaultClient.getAdminClient(); }); + it('should be able create, generate credentials and delete an account', done => { async.series([ next => clientAdmin.createAccount(accountName, accountInfo, next), diff --git a/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/iamApi.js b/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/iamApi.js index 876e515e34..e67c9f88ec 100644 --- a/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/iamApi.js +++ b/tests/functional/mocha/smoke_tests/vault_admin_and_IAM_API_tests/iamApi.js @@ -11,7 +11,6 @@ const { } = require('@aws-sdk/client-iam'); const VaultClient = require('../../VaultClient'); -const clientAdmin = VaultClient.getAdminClient(); const accountName = 'iam-api-test-account'; const accountInfo = { email: `${accountName}@test.com`, @@ -23,8 +22,11 @@ const userName = 'iam-api-test-user'; const randomPath = '/random/path/'; describe('IAM users: ', () => { + let clientAdmin; let iamAccountClient = null; + before(() => { clientAdmin = VaultClient.getAdminClient(); }); + beforeEach(done => async.series([ next => clientAdmin.createAccount(accountName, accountInfo, next), next => clientAdmin.generateAccountAccessKey(accountName, next, { externalAccessKey, externalSecretKey }), @@ -50,9 +52,12 @@ describe('IAM users: ', () => { }); describe('IAM user - Access Keys: ', () => { + let clientAdmin; let iamAccountClient = null; let keyPair = null; + before(() => { clientAdmin = VaultClient.getAdminClient(); }); + beforeEach(done => async.series([ next => clientAdmin.createAccount(accountName, accountInfo, next), next => clientAdmin.generateAccountAccessKey(accountName, next, { externalAccessKey, externalSecretKey }), diff --git a/tests/functional/mocha/stsSDK.js b/tests/functional/mocha/stsSDK.js index e664d48bfe..c3829f26d5 100644 --- a/tests/functional/mocha/stsSDK.js +++ b/tests/functional/mocha/stsSDK.js @@ -1,8 +1,9 @@ const { STSClient } = require('@aws-sdk/client-sts'); +const { VAULT_STS_ENDPOINT } = require('tests_common/configuration'); function getSTSClient(accessKey, secretKey, sessionToken) { const config = { - endpoint: process.env.VAULT_STS_ENDPOINT, + endpoint: VAULT_STS_ENDPOINT, region: 'us-east-1', maxAttempts: 1, tls: false, diff --git a/tests/functional/mocha/utils/getWebIdentityToken.js b/tests/functional/mocha/utils/getWebIdentityToken.js index 8a02914c44..71df2b40aa 100644 --- a/tests/functional/mocha/utils/getWebIdentityToken.js +++ b/tests/functional/mocha/utils/getWebIdentityToken.js @@ -1,14 +1,13 @@ const querystring = require('querystring'); const http = require('http'); const assert = require('assert'); +const { KEYCLOAK_TEST_PORT, KEYCLOAK_GRANT_TYPE } = require('tests_common/configuration'); const USER_1_PASSWORD = process.env.KEYCLOAK_TEST_PASSWORD || '123'; const HOST_1_URL = process.env.KEYCLOAK_TEST_HOST || 'http://keycloak.zenko.local'; -const HOST_1_PORT = parseInt(process.env.KEYCLOAK_TEST_PORT, 10) || 80; const REALM_NAME = process.env.KEYCLOAK_TEST_REALM_NAME || 'zenko'; const KEYCLOAK_PATH = `/auth/realms/${REALM_NAME}/protocol/openid-connect/token`; -const CLIENT_ID = process.env.KEYCLOAK_TEST_CLIENT_ID || 'zenko-ui'; -const GRANT_TYPE = process.env.KEYCLOAK_TEST_GRANT_TYPE || 'password'; +const CLIENT_ID = 'zenko-ui'; /** @@ -84,10 +83,10 @@ function getTokenForIdentity(identity, callback) { identity, USER_1_PASSWORD, HOST_1_URL, - HOST_1_PORT, + KEYCLOAK_TEST_PORT, KEYCLOAK_PATH, CLIENT_ID, - GRANT_TYPE, + KEYCLOAK_GRANT_TYPE, (err, token) => { assert(err === null); callback(err, token); diff --git a/tests/functional/mocha/utils/request.js b/tests/functional/mocha/utils/request.js index 2987a35738..5aa72531c4 100644 --- a/tests/functional/mocha/utils/request.js +++ b/tests/functional/mocha/utils/request.js @@ -1,19 +1,21 @@ const http = require('http'); const aws4 = require('aws4'); - -const DEFAULT_HOST = process.env.CLOUDSERVER_HOST; -const DEFAULT_PORT = process.env.CLOUDSERVER_PORT || '80'; - -const accessKeyId = process.env.ZENKO_ACCESS_KEY; -const secretAccessKey = process.env.ZENKO_SECRET_KEY; -const sessionToken = process.env.ZENKO_SESSION_TOKEN; +const { config, CLOUDSERVER_HOST } = require('tests_common/configuration'); const defaultOptions = { - host: DEFAULT_HOST, - port: DEFAULT_PORT, + host: CLOUDSERVER_HOST, + port: 80, service: 's3', }; -const credentials = { accessKeyId, secretAccessKey, sessionToken }; + +const getCredentials = () => { + const { ZenkoAccount } = config; + return { + accessKeyId: ZenkoAccount.credentials.accessKeyId, + secretAccessKey: ZenkoAccount.credentials.secretAccessKey, + sessionToken: ZenkoAccount.credentials.sessionToken, + }; +}; function getResponseBody(res, cb, isXml = false) { res.setEncoding('utf8'); @@ -43,7 +45,7 @@ function makeGETRequest(path, cb, userCredentials) { method: 'GET', path, }; - options = aws4.sign(options, userCredentials || credentials); + options = aws4.sign(options, userCredentials || getCredentials()); const req = http.request(options, res => cb(null, res)); req.on('error', err => cb(err)); @@ -65,7 +67,7 @@ function makeUpdateRequest(path, cb, userCredentials, body, mode = 'POST') { method: mode || 'POST', path, }; - options = aws4.sign(options, userCredentials || credentials); + options = aws4.sign(options, userCredentials || getCredentials()); const req = http.request(options, res => cb(null, res)); req.on('error', err => cb(err)); diff --git a/tests/functional/mocha/utils/testUtils.js b/tests/functional/mocha/utils/testUtils.js index 96b2fe58c2..8ed74184c1 100644 --- a/tests/functional/mocha/utils/testUtils.js +++ b/tests/functional/mocha/utils/testUtils.js @@ -5,7 +5,7 @@ const { ListMultipartUploadsCommand, ListObjectsCommand, } = require('@aws-sdk/client-s3'); -const { scalityS3Client } = require('../s3SDK'); +const { config } = require('tests_common/configuration'); const testUtils = {}; @@ -13,7 +13,7 @@ testUtils.deleteAllObjects = async (objList, bucketName) => { if (!objList.Contents || objList.Contents.length === 0) { return; } - await Promise.all(objList.Contents.map(obj => scalityS3Client.send( + await Promise.all(objList.Contents.map(obj => config.ZenkoAccount.s3Client.send( new DeleteObjectCommand({ Bucket: bucketName, Key: obj.Key }), ))); }; @@ -22,7 +22,7 @@ testUtils.abortAllMpus = async (mpuList, bucketName) => { if (!mpuList.Uploads || mpuList.Uploads.length === 0) { return; } - await Promise.all(mpuList.Uploads.map(mpu => scalityS3Client.send(new AbortMultipartUploadCommand({ + await Promise.all(mpuList.Uploads.map(mpu => config.ZenkoAccount.s3Client.send(new AbortMultipartUploadCommand({ Bucket: bucketName, Key: mpu.Key, UploadId: mpu.UploadId, @@ -31,12 +31,12 @@ testUtils.abortAllMpus = async (mpuList, bucketName) => { testUtils.emptyDeleteBucket = async bucketName => { const [objList, mpuList] = await Promise.all([ - scalityS3Client.send(new ListObjectsCommand({ Bucket: bucketName })), - scalityS3Client.send(new ListMultipartUploadsCommand({ Bucket: bucketName })), + config.ZenkoAccount.s3Client.send(new ListObjectsCommand({ Bucket: bucketName })), + config.ZenkoAccount.s3Client.send(new ListMultipartUploadsCommand({ Bucket: bucketName })), ]); await testUtils.deleteAllObjects(objList, bucketName); await testUtils.abortAllMpus(mpuList, bucketName); - await scalityS3Client.send(new DeleteBucketCommand({ Bucket: bucketName })); + await config.ZenkoAccount.s3Client.send(new DeleteBucketCommand({ Bucket: bucketName })); }; module.exports = testUtils; diff --git a/tests/functional/tests_common/configuration.ts b/tests/functional/tests_common/configuration.ts new file mode 100644 index 0000000000..99f8e5580b --- /dev/null +++ b/tests/functional/tests_common/configuration.ts @@ -0,0 +1,227 @@ +import { S3Client } from '@aws-sdk/client-s3'; +import { IAMClient } from '@aws-sdk/client-iam'; +import { NodeHttpHandler } from '@smithy/node-http-handler'; +import { getSecretByLabel, getSecretByName, getSecretAllFieldsByLabel, getCustomObject } from "./kubernetes"; + +const ZENKO_NAME = process.env.ZENKO_NAME || 'end2end'; +const INSTANCE_SELECTOR = `app.kubernetes.io/instance=${ZENKO_NAME}`; + +export const ZENKO_ACCOUNT_NAME = 'zenko-ctst'; +export const CLOUDSERVER_HOST = 's3.zenko.local'; +export const CLOUDSERVER_ENDPOINT = 'http://s3.zenko.local'; +export const VAULT_ENDPOINT = 'http://iam.zenko.local'; +export const VAULT_AUTH_HOST = 'vault-auth.zenko.local'; +export const VAULT_STS_ENDPOINT = 'http://sts.zenko.local'; +export const BACKBEAT_API_HOST = 'backbeat-api.zenko.local'; +export const BACKBEAT_API_ENDPOINT = 'http://backbeat-api.zenko.local'; +export const BACKBEAT_API_PORT = '80'; +export const KEYCLOAK_TEST_PORT = '80' +export const KEYCLOAK_GRANT_TYPE = 'password' +export const KAFKA_CONNECT_URL = 'http://kafka-connect.zenko.local/connectors'; +export const AZURE_ARCHIVE_ACCESS_TIER = 'Hot'; +export const AZURE_ARCHIVE_MANIFEST_TIER = 'Hot'; + +export interface VaultCredentials { + accessKey: string; + secretKey: string; +} + +export interface NamedVaultCredentials extends VaultCredentials { + name: string; +} + +export interface AccountCredentials { + accessKeyId: string; + secretAccessKey: string; + sessionToken?: string; +} + +// Minimal Zenko CR (only fields needed for the tests) +interface ZenkoCR { + metadata: { + annotations?: Record; + }; + spec: { + kafkaCleaner: { + interval?: string; + }; + sorbet: { + server: { + azure: { + restoreTimeout?: string; + }; + }; + }; + scuba: { + api: { + ingress: { + hostname?: string; + }; + }; + }; + }; + status: { + instanceID: string; + }; +} + +export interface TestsConfiguration { + KafkaTopics: { + DeadLetterQueue: string; + ObjectTasks: string; + GcRequest: string; + } + ServiceUsers: { + BackbeatLifecycleBp1: NamedVaultCredentials; + BackbeatLifecycleConductor1: NamedVaultCredentials; + BackbeatLifecycleOp1: NamedVaultCredentials; + BackbeatQp1: NamedVaultCredentials; + SorbetFwd2: NamedVaultCredentials; + }; + DRAdmin?: VaultCredentials; + AdminCredentials: VaultCredentials; + ZenkoAccount: { + credentials: AccountCredentials; + s3Client: S3Client; + iamClient: IAMClient; + }; + ZenkoCR: { + TimeProgressionFactor: number; + InstanceID: string; + KafkaCleanerInterval: string; + SorbetdRestoreTimeout: string; + UtilizationServiceHost: string; + }; +} + +export const config = {} as TestsConfiguration; + +export const initConfig = async (): Promise => { + if (Object.keys(config).length > 0) { + return; + } + const zenkoAccountCredentials = await loadZenkoAccount(); + const clients = createClients(zenkoAccountCredentials); + Object.assign(config, { + KafkaTopics: await loadKafkaTopics(), + ServiceUsers: await loadServiceUsers(), + DRAdmin: await loadDRAdminCredentials(), + AdminCredentials: await loadAdminCredentials(), + ZenkoCR: await loadZenkoCR(), + ZenkoAccount: { + credentials: zenkoAccountCredentials, + iamClient: clients.iamClient, + s3Client: clients.s3Client, + }, + }); +}; + +const createClients = (zenkoAccount: AccountCredentials): { s3Client: S3Client; iamClient: IAMClient } => { + const sharedHttpHandler = new NodeHttpHandler({ requestTimeout: 0, connectionTimeout: 0 }); + const credentials = { + accessKeyId: zenkoAccount.accessKeyId, + secretAccessKey: zenkoAccount.secretAccessKey, + sessionToken: zenkoAccount.sessionToken, + }; + return { + s3Client: new S3Client({ + credentials, + tls: false, + endpoint: CLOUDSERVER_ENDPOINT, + region: 'us-east-1', + forcePathStyle: true, + maxAttempts: 1, + requestHandler: sharedHttpHandler, + }), + iamClient: new IAMClient({ + credentials, + tls: false, + endpoint: VAULT_ENDPOINT, + region: 'us-east-1', + maxAttempts: 1, + requestHandler: sharedHttpHandler, + }), + }; +}; + +const loadKafkaTopics = async (): Promise => { + const labelSelector = + 'app.kubernetes.io/name=cold-sorbet-config-e2e-azure-archive' + + `,${INSTANCE_SELECTOR}`; + const raw = await getSecretByLabel(labelSelector, 'config.json'); + const sorbetKafkaConfig = JSON.parse(raw) as Record; + return { + DeadLetterQueue: sorbetKafkaConfig['kafka-dead-letter-topic'], + ObjectTasks: sorbetKafkaConfig['kafka-object-task-topic'], + GcRequest: sorbetKafkaConfig['kafka-gc-request-topic'], + }; +}; + +const loadServiceUsers = async (): Promise => { + const load = async (secretName: string): Promise => { + const label = `app.kubernetes.io/name=${secretName},${INSTANCE_SELECTOR}`; + const data = await getSecretAllFieldsByLabel(label); + const jsonKey = Object.keys(data).find(k => k.endsWith('.json')); + if (!jsonKey) { + throw new Error(`No .json key found in secret "${secretName}"`); + } + return { ...JSON.parse(data[jsonKey]) as VaultCredentials, name: jsonKey.replace('.json', '') }; + }; + const sorbetSelector = `app.kubernetes.io/name=sorbet-fwd-creds,${INSTANCE_SELECTOR}`; + return { + BackbeatLifecycleBp1: await load('backbeat-lcbp-user-creds'), + BackbeatLifecycleConductor1: await load('backbeat-lcc-user-creds'), + BackbeatLifecycleOp1: await load('backbeat-lcop-user-creds'), + BackbeatQp1: await load('backbeat-qp-user-creds'), + SorbetFwd2: { + name: 'sorbet-fwd-2', + accessKey: await getSecretByLabel(sorbetSelector, 'accessKey'), + secretKey: await getSecretByLabel(sorbetSelector, 'secretKey'), + }, + }; +}; + +const loadDRAdminCredentials = async (): Promise => { + const praSecretName = `${ZENKO_NAME}-pra-management-vault-admin-creds.v1`; + try { + const accessKey = await getSecretByName(praSecretName, 'accessKey'); + const secretKey = await getSecretByName(praSecretName, 'secretKey'); + return { accessKey, secretKey }; + } catch { + // PRA admin credentials are optional : may not exist for non-PRA runs + return undefined; + } +}; + +const loadAdminCredentials = async (): Promise => { + const secretName = `${ZENKO_NAME}-management-vault-admin-creds.v1`; + const accessKey = await getSecretByName(secretName, 'accessKey'); + const secretKey = await getSecretByName(secretName, 'secretKey'); + return { accessKey, secretKey }; +}; + +const loadZenkoAccount = async (): Promise => { + const secretName = `${ZENKO_NAME}-account-zenko`; + const accessKeyId = await getSecretByName(secretName, 'AccessKeyId'); + const secretAccessKey = await getSecretByName(secretName, 'SecretAccessKey'); + let sessionToken: string | undefined; + try { + sessionToken = await getSecretByName(secretName, 'SessionToken'); + } catch { + sessionToken = undefined; + } + return { accessKeyId, secretAccessKey, sessionToken }; +}; + +const loadZenkoCR = async (): Promise => { + const cr = await getCustomObject( + 'zenko.io', 'v1alpha2', 'zenkos', ZENKO_NAME, + ) as unknown as ZenkoCR; + return { + TimeProgressionFactor: Number(cr.metadata.annotations?.['zenko.io/time-progression-factor'] || '1'), + InstanceID: cr.status.instanceID, + KafkaCleanerInterval: cr.spec.kafkaCleaner.interval || '', + SorbetdRestoreTimeout: cr.spec.sorbet.server.azure.restoreTimeout || '', + UtilizationServiceHost: cr.spec.scuba.api.ingress.hostname || '', + }; +}; diff --git a/tests/functional/tests_common/kubernetes.ts b/tests/functional/tests_common/kubernetes.ts new file mode 100644 index 0000000000..6fe2c1619b --- /dev/null +++ b/tests/functional/tests_common/kubernetes.ts @@ -0,0 +1,65 @@ +import { KubeConfig, CoreV1Api, CustomObjectsApi } from '@kubernetes/client-node'; + +const kc = new KubeConfig(); +kc.loadFromDefault(); + +const coreClient = kc.makeApiClient(CoreV1Api); +const customClient = kc.makeApiClient(CustomObjectsApi); + +export const getSecretByLabel = async ( + labelSelector: string, + dataField: string, + namespace = 'default', +): Promise => { + const secretList = await coreClient.listNamespacedSecret({ + namespace, + labelSelector, + }); + const secret = secretList.items[0]; + if (!secret?.data?.[dataField]) { + throw new Error( + `Secret field "${dataField}" not found for label "${labelSelector}"`, + ); + } + return Buffer.from(secret.data[dataField], 'base64').toString('utf-8'); +}; + +export const getSecretByName = async ( + secretName: string, + dataField: string, + namespace = 'default', +): Promise => { + const secret = await coreClient.readNamespacedSecret({ name: secretName, namespace }); + if (!secret?.data?.[dataField]) { + throw new Error( + `Secret field "${dataField}" not found in secret "${secretName}"`, + ); + } + return Buffer.from(secret.data[dataField], 'base64').toString('utf-8'); +}; + +export const getSecretAllFieldsByLabel = async ( + labelSelector: string, + namespace = 'default', +): Promise> => { + const secretList = await coreClient.listNamespacedSecret({ namespace, labelSelector }); + const secret = secretList.items[0]; + if (!secret?.data) { + throw new Error(`Secret not found for label "${labelSelector}"`); + } + return Object.fromEntries( + Object.entries(secret.data).map(([k, v]) => [k, Buffer.from(v, 'base64').toString('utf-8')]), + ); +}; + +export const getCustomObject = async ( + group: string, + version: string, + plural: string, + name: string, + namespace = 'default', +): Promise> => { + return await customClient.getNamespacedCustomObject({ + group, version, namespace, plural, name, + }) as Record; +}; diff --git a/tests/functional/tsconfig.json b/tests/functional/tsconfig.json index 90436de81d..8d86c14019 100644 --- a/tests/functional/tsconfig.json +++ b/tests/functional/tsconfig.json @@ -17,7 +17,8 @@ "cli-testing": ["./node_modules/cli-testing"], "common/*": ["./ctst/common/*"], "steps/*": ["./ctst/steps/*"], - "world/*": ["./ctst/world/*"] + "world/*": ["./ctst/world/*"], + "tests_common/*": ["./tests_common/*"] }, "esModuleInterop": true }, @@ -29,7 +30,9 @@ "ignore": ["(?:^|/)node_modules/(?!cli-testing)"] }, "include": [ - "ctst/**/*" + "ctst/**/*", + "tests_common/**/*", + "mocha/**/*.ts" ], "exclude": [ "node_modules"