diff --git a/.github/workflows/script/gcs_test.sh b/.github/workflows/script/gcs_test.sh index 90806a40f..f2eba6a06 100755 --- a/.github/workflows/script/gcs_test.sh +++ b/.github/workflows/script/gcs_test.sh @@ -31,11 +31,6 @@ else storageType=${STORAGE_TYPE} fi -if [ -z "${GCP_SERVICE_ACCOUNT_TOKEN}" ]; then - echo "GCP_SERVICE_ACCOUNT_TOKEN is not set. Exiting..." - exit 1 -fi - if [ -z "${PREFIX}" ]; then echo "PREFIX is not set" else @@ -47,6 +42,12 @@ else "--aws-write-secrets" "${GCS_SECRET_KEY}" "--aws-bucket" "${streamBucket}" "--aws-bucket-prefix" "${PREFIX}" + + "--backupWriteSecrets" "${GCS_SECRET_KEY}" + "--backupWriteAccessKey" "${GCS_ACCESS_KEY}" + "--backupEndpoint" "storage.googleapis.com" + "--backupRegion" "us-central1" + "--backup-bucket" "${streamBackupBucket}" ) elif [ "${storageType}" == "gcs_only" ]; then STORAGE_OPTIONS=( @@ -55,6 +56,12 @@ else "--gcs-write-secrets" "${GCS_SECRET_KEY}" "--gcs-bucket" "${streamBucket}" "--gcs-bucket-prefix" "${PREFIX}" + + "--backupWriteSecrets" "${GCS_SECRET_KEY}" + "--backupWriteAccessKey" "${GCS_ACCESS_KEY}" + "--backupEndpoint" "storage.googleapis.com" + "--backupRegion" "us-central1" + "--backup-bucket" "${streamBackupBucket}" ) fi @@ -72,8 +79,6 @@ fi echo "STORAGE_OPTIONS: " "${STORAGE_OPTIONS[@]}" echo "MIRROR_STORAGE_OPTIONS: " "${MIRROR_STORAGE_OPTIONS[@]}" -echo "${GCP_SERVICE_ACCOUNT_TOKEN}" > gcp_service_account.json - echo "Using bucket name: ${streamBucket}" echo "Test storage type: ${storageType}" @@ -97,9 +102,7 @@ npm run solo-test -- node keys --gossip-keys --tls-keys -i node1 --deployment "$ npm run solo-test -- network deploy --deployment "${SOLO_DEPLOYMENT}" -i node1 \ --storage-type "${storageType}" \ - "${STORAGE_OPTIONS[@]}" \ - --backup-bucket "${streamBackupBucket}" \ - --google-credential gcp_service_account.json + "${STORAGE_OPTIONS[@]}" npm run solo-test -- node setup -i node1 --deployment "${SOLO_DEPLOYMENT}" npm run solo-test -- node start -i node1 --deployment "${SOLO_DEPLOYMENT}" @@ -120,16 +123,18 @@ node examples/create-topic.js npm run solo-test -- node stop -i node1 --deployment "${SOLO_DEPLOYMENT}" -echo "Waiting for backup uploader to run" -# manually call script "backup.sh" from container backup-uploader since it only runs every 5 minutes -kubectl exec network-node1-0 -c backup-uploader -n solo-e2e -- /backup.sh - -echo "Retrieve logs and check if it include the error message" -# example : {"level":"error","msg":"Updated modification time ......} -kubectl logs network-node1-0 -c backup-uploader -n solo-e2e > backup-uploader.log -if grep -q \""error\"" backup-uploader.log; then - echo "Backup uploader logs contain error message" - exit 1 +if [ "${storageType}" == "aws_only" ] || [ "${storageType}" == "gcs_only" ]; then + echo "Waiting for backup uploader to run" + # manually call script "backup.sh" from container backup-uploader since it only runs every 5 minutes + kubectl exec network-node1-0 -c backup-uploader -n solo-e2e -- /app/backup.sh + + echo "Retrieve logs and check if it include the error message" + # example : {"level":"error","msg":"Updated modification time ......} + kubectl logs network-node1-0 -c backup-uploader -n solo-e2e > backup-uploader.log + if grep -q \""error\"" backup-uploader.log; then + echo "Backup uploader logs contain error message" + exit 1 + fi fi npm run solo-test -- network destroy --deployment "${SOLO_DEPLOYMENT}" --force -q diff --git a/Taskfile.helper.yml b/Taskfile.helper.yml index 5789743f2..6a3b19509 100644 --- a/Taskfile.helper.yml +++ b/Taskfile.helper.yml @@ -244,7 +244,7 @@ tasks: if [[ "${SOLO_CHART_VERSION}" != "" ]]; then export SOLO_CHART_FLAG="--solo-chart-version ${SOLO_CHART_VERSION}" fi - SOLO_HOME_DIR=${SOLO_HOME_DIR} npm run solo -- network deploy --deployment "${SOLO_DEPLOYMENT}" --node-aliases {{.node_identifiers}} ${CONSENSUS_NODE_FLAG} ${SOLO_CHART_FLAG} ${VALUES_FLAG} ${SETTINGS_FLAG} ${LOG4J2_FLAG} ${APPLICATION_PROPERTIES_FLAG} ${GENESIS_THROTTLES_FLAG} ${DEBUG_NODE_FLAG} ${SOLO_CHARTS_DIR_FLAG} ${LOAD_BALANCER_FLAG} ${NETWORK_DEPLOY_EXTRA_FLAGS} -q --dev + SOLO_HOME_DIR=${SOLO_HOME_DIR} npm run solo -- network deploy --deployment "${SOLO_DEPLOYMENT}" --node-aliases {{.node_identifiers}} ${CONSENSUS_NODE_FLAG} ${SOLO_CHART_FLAG} ${VALUES_FLAG} ${SETTINGS_FLAG} ${LOG4J2_FLAG} ${APPLICATION_PROPERTIES_FLAG} ${GENESIS_THROTTLES_FLAG} ${DEBUG_NODE_FLAG} ${LOAD_BALANCER_FLAG} ${NETWORK_DEPLOY_EXTRA_FLAGS} -q --dev - task: "solo:node:setup" solo:node:setup: @@ -405,7 +405,7 @@ tasks: cmds: - | export MINIO_FLAG=$(cat {{ .minio_flag_file }}) - SOLO_HOME_DIR=${SOLO_HOME_DIR} npm run solo -- cluster-ref setup --cluster-setup-namespace "${SOLO_CLUSTER_SETUP_NAMESPACE}" ${MINIO_FLAG} ${SOLO_CHARTS_DIR_FLAG} ${CLUSTER_TLS_FLAGS} -q --dev + SOLO_HOME_DIR=${SOLO_HOME_DIR} npm run solo -- cluster-ref setup --cluster-setup-namespace "${SOLO_CLUSTER_SETUP_NAMESPACE}" ${MINIO_FLAG} ${CLUSTER_TLS_FLAGS} -q --dev solo:node:addresses: internal: true @@ -507,7 +507,7 @@ tasks: npm run solo -- explorer deploy --deployment "${EXPLORER_DEPLOYMENT}" --cluster-ref ${EXPLORER_CLUSTER_CONTEXT} --mirrorNamespace ${SOLO_NAMESPACE} ${SOLO_CHARTS_DIR_FLAG} ${EXPLORER_DEPLOY_EXTRA_FLAGS} ${ENABLE_EXPLORER_TLS_FLAG} ${TLS_CLUSTER_ISSUER_TYPE_FLAG} ${ENABLE_EXPLORER_INGRESS} -q --dev export EXPLORER_DEPLOYED_NAME_SPACE=${EXPLORER_NAME_SPACE} else - SOLO_HOME_DIR=${SOLO_HOME_DIR} npm run solo -- explorer deploy --deployment "${SOLO_DEPLOYMENT}" --cluster-ref kind-${SOLO_CLUSTER_NAME} --mirrorNamespace ${SOLO_NAMESPACE} ${SOLO_CHARTS_DIR_FLAG} ${EXPLORER_DEPLOY_EXTRA_FLAGS} ${ENABLE_EXPLORER_TLS_FLAG} ${TLS_CLUSTER_ISSUER_TYPE_FLAG} ${ENABLE_EXPLORER_INGRESS} -q --dev + SOLO_HOME_DIR=${SOLO_HOME_DIR} npm run solo -- explorer deploy --deployment "${SOLO_DEPLOYMENT}" --cluster-ref kind-${SOLO_CLUSTER_NAME} --mirrorNamespace ${SOLO_NAMESPACE} ${EXPLORER_DEPLOY_EXTRA_FLAGS} ${ENABLE_EXPLORER_TLS_FLAG} ${TLS_CLUSTER_ISSUER_TYPE_FLAG} ${ENABLE_EXPLORER_INGRESS} -q --dev export EXPLORER_DEPLOYED_NAME_SPACE=${SOLO_NAMESPACE} fi if [[ "{{ .use_port_forwards }}" == "true" ]];then diff --git a/src/commands/flags.ts b/src/commands/flags.ts index e5ff97b22..a39e37403 100644 --- a/src/commands/flags.ts +++ b/src/commands/flags.ts @@ -2170,12 +2170,48 @@ export class Flags { prompt: undefined, }; - public static readonly googleCredential: CommandFlag = { - constName: 'googleCredential', - name: 'google-credential', + public static readonly backupWriteAccessKey: CommandFlag = { + constName: 'backupWriteAccessKey', + name: 'backup-write-access-key', definition: { defaultValue: '', - describe: 'path of google credential file in json format', + describe: 'backup storage access key for write access', + type: 'string', + dataMask: constants.STANDARD_DATAMASK, + }, + prompt: undefined, + }; + + public static readonly backupWriteSecrets: CommandFlag = { + constName: 'backupWriteSecrets', + name: 'backup-write-secrets', + definition: { + defaultValue: '', + describe: 'backup storage secret key for write access', + type: 'string', + dataMask: constants.STANDARD_DATAMASK, + }, + prompt: undefined, + }; + + public static readonly backupEndpoint: CommandFlag = { + constName: 'backupEndpoint', + name: 'backup-endpoint', + definition: { + defaultValue: '', + describe: 'backup storage endpoint URL', + type: 'string', + dataMask: constants.STANDARD_DATAMASK, + }, + prompt: undefined, + }; + + public static readonly backupRegion: CommandFlag = { + constName: 'backupRegion', + name: 'backup-region', + definition: { + defaultValue: 'us-central1', + describe: 'backup storage region', type: 'string', dataMask: constants.STANDARD_DATAMASK, }, @@ -2441,7 +2477,10 @@ export class Flags { Flags.storageBucket, Flags.storageBucketPrefix, Flags.backupBucket, - Flags.googleCredential, + Flags.backupWriteAccessKey, + Flags.backupWriteSecrets, + Flags.backupEndpoint, + Flags.backupRegion, Flags.tlsClusterIssuerType, Flags.tlsPrivateKey, Flags.tlsPublicKey, diff --git a/src/commands/network.ts b/src/commands/network.ts index 22a91ade1..e89028da2 100644 --- a/src/commands/network.ts +++ b/src/commands/network.ts @@ -88,7 +88,10 @@ export interface NetworkDeployConfigClass { awsBucket: string; awsBucketPrefix: string; backupBucket: string; - googleCredential: string; + backupWriteSecrets: string; + backupWriteAccessKey: string; + backupEndpoint: string; + backupRegion: string; consensusNodes: ConsensusNode[]; contexts: string[]; clusterRefs: ClusterReferences; @@ -192,7 +195,10 @@ export class NetworkCommand extends BaseCommand { flags.awsBucket, flags.awsBucketPrefix, flags.backupBucket, - flags.googleCredential, + flags.backupWriteAccessKey, + flags.backupWriteSecrets, + flags.backupEndpoint, + flags.backupRegion, flags.domainNames, ], }; @@ -306,27 +312,30 @@ export class NetworkCommand extends BaseCommand { } async prepareBackupUploaderSecrets(config: NetworkDeployConfigClass) { - if (config.googleCredential) { - const backupData = {}; - const namespace = config.namespace; - const googleCredential = fs.readFileSync(config.googleCredential, 'utf8'); - backupData['saJson'] = Base64.encode(googleCredential); - - // create secret in each cluster - for (const context of config.contexts) { - this.logger.debug(`creating secret for backup uploader using context: ${context}`); - - const k8client = this.k8Factory.getK8(context); - const isBackupSecretCreated = await k8client - .secrets() - .createOrReplace(namespace, constants.BACKUP_SECRET_NAME, SecretType.OPAQUE, backupData, undefined); - - if (!isBackupSecretCreated) { - throw new SoloError(`failed to create secret for backup uploader using context: ${context}`); - } + const {backupWriteAccessKey, backupWriteSecrets, backupEndpoint, backupRegion} = config; + const backupData = {}; + const namespace = config.namespace; + backupData['AWS_ACCESS_KEY_ID'] = Base64.encode(backupWriteAccessKey); + backupData['AWS_SECRET_ACCESS_KEY'] = Base64.encode(backupWriteSecrets); + backupData['RCLONE_CONFIG_BACKUPS_ENDPOINT'] = Base64.encode(backupEndpoint); + backupData['RCLONE_CONFIG_BACKUPS_REGION'] = Base64.encode(backupRegion); + backupData['RCLONE_CONFIG_BACKUPS_TYPE'] = Base64.encode('s3'); + backupData['RCLONE_CONFIG_BACKUPS_PROVIDER'] = Base64.encode('GCS'); + + // create secret in each cluster + for (const context of config.contexts) { + this.logger.debug(`creating secret for backup uploader using context: ${context}`); - this.logger.debug(`created secret for backup uploader using context: ${context}`); + const k8client = this.k8Factory.getK8(context); + const isBackupSecretCreated = await k8client + .secrets() + .createOrReplace(namespace, constants.BACKUP_SECRET_NAME, SecretType.OPAQUE, backupData, undefined); + + if (!isBackupSecretCreated) { + throw new SoloError(`failed to create secret for backup uploader using context: ${context}`); } + + this.logger.debug(`created secret for backup uploader using context: ${context}`); } } @@ -339,7 +348,9 @@ export class NetworkCommand extends BaseCommand { await this.prepareStreamUploaderSecrets(config); } - await this.prepareBackupUploaderSecrets(config); + if (config.backupBucket) { + await this.prepareBackupUploaderSecrets(config); + } } catch (error: Error | any) { throw new SoloError('Failed to create Kubernetes storage secret', error); } @@ -373,7 +384,6 @@ export class NetworkCommand extends BaseCommand { awsBucket: string; awsBucketPrefix: string; backupBucket: string; - googleCredential: string; loadBalancerEnabled: boolean; clusterRefs: ClusterReferences; consensusNodes: ConsensusNode[]; @@ -436,7 +446,6 @@ export class NetworkCommand extends BaseCommand { awsBucket: string; awsBucketPrefix: string; backupBucket: string; - googleCredential: string; loadBalancerEnabled: boolean; domainNamesMapping?: Record; }): Record { diff --git a/test/unit/core/helpers.test.ts b/test/unit/core/helpers.test.ts index bf20f71f9..accdc3c34 100644 --- a/test/unit/core/helpers.test.ts +++ b/test/unit/core/helpers.test.ts @@ -26,12 +26,6 @@ describe('Helpers', () => { expect(clonedArray).not.to.equal(input); // ensure cloning creates a new array }); - it('Should parse argv to args with datamask correctly', () => { - const argv = {[flags.googleCredential.name]: 'VALUE'}; - const result = flags.stringifyArgv(argv); - expect(result).to.equal(`--${flags.googleCredential.name} ${flags.googleCredential.definition.dataMask}`); - }); - it('Should parse argv to args with boolean flag correctly', () => { const argv = {[flags.quiet.name]: true}; const result = flags.stringifyArgv(argv); diff --git a/version.ts b/version.ts index 0e399cd9d..6d3bda7ed 100644 --- a/version.ts +++ b/version.ts @@ -11,7 +11,7 @@ import fs from 'node:fs'; */ export const HELM_VERSION = 'v3.14.2'; -export const SOLO_CHART_VERSION = '0.48.0'; +export const SOLO_CHART_VERSION = '0.49.0'; export const HEDERA_PLATFORM_VERSION = 'v0.59.5'; export const MIRROR_NODE_VERSION = 'v0.126.0'; export const HEDERA_EXPLORER_VERSION = '24.12.1';