diff --git a/cluster/pulumi/common/src/index.ts b/cluster/pulumi/common/src/index.ts index 5f9a04b202..2c66af56cb 100644 --- a/cluster/pulumi/common/src/index.ts +++ b/cluster/pulumi/common/src/index.ts @@ -24,6 +24,7 @@ export * from './dockerConfig'; export * from './serviceAccount'; export * from './participantKms'; export * from './config/migrationSchema'; +export * from './postgres'; export * from './pruning'; export * from './config/loadTesterConfig'; export * from './config/networkWideConfig'; diff --git a/cluster/pulumi/common/src/postgres.ts b/cluster/pulumi/common/src/postgres.ts index c20bb18ba8..26421f4176 100644 --- a/cluster/pulumi/common/src/postgres.ts +++ b/cluster/pulumi/common/src/postgres.ts @@ -65,7 +65,12 @@ export class CloudPostgres extends pulumi.ComponentResource implements Postgres secretName: string, cloudSqlConfig: CloudSqlConfig, active: boolean = true, - opts: { disableProtection?: boolean; migrationId?: string; logicalDecoding?: boolean } = {} + opts: { + disableProtection?: boolean; + migrationId?: string; + logicalDecoding?: boolean; + disableBackups?: boolean; + } = {} ) { const instanceLogicalName = xns.logicalName + '-' + instanceName; const instanceLogicalNameAlias = xns.logicalName + '-' + alias; // pulumi name before #12391 @@ -93,8 +98,8 @@ export class CloudPostgres extends pulumi.ComponentResource implements Postgres ...(opts.logicalDecoding ? [{ name: 'cloudsql.logical_decoding', value: 'on' }] : []), ], backupConfiguration: { - enabled: true, - pointInTimeRecoveryEnabled: true, + enabled: !opts.disableBackups, + pointInTimeRecoveryEnabled: !opts.disableBackups, ...(spliceConfig.pulumiProjectConfig.cloudSql.backupsToRetain ? { backupRetentionSettings: { diff --git a/cluster/pulumi/gha/src/performanceTests.ts b/cluster/pulumi/gha/src/performanceTests.ts new file mode 100644 index 0000000000..0677b50292 --- /dev/null +++ b/cluster/pulumi/gha/src/performanceTests.ts @@ -0,0 +1,27 @@ +// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +import { CloudPostgres, ExactNamespace } from '@lfdecentralizedtrust/splice-pulumi-common'; + +export function createCloudSQLInstanceForPerformanceTests( + ghaNamespace: ExactNamespace +): CloudPostgres { + return new CloudPostgres( + ghaNamespace, + 'performance-test-db', + 'performance-test-db', + 'performance-test-db-secret', + { + enabled: true, + maintenanceWindow: { day: 2, hour: 8 }, + protected: false, + tier: 'db-custom-2-7680', // same as devnet & testnet as of Jan 2026 + enterprisePlus: false, + }, + true, + { + disableProtection: true, + disableBackups: true, + logicalDecoding: false, + } + ); +} diff --git a/cluster/pulumi/gha/src/runners.test.ts b/cluster/pulumi/gha/src/runners.test.ts index 668889c260..516cf795be 100644 --- a/cluster/pulumi/gha/src/runners.test.ts +++ b/cluster/pulumi/gha/src/runners.test.ts @@ -15,6 +15,7 @@ jest.mock('./config', () => ({ runnerHookVersion: '1.1', }, })); +class FakeCloudPostgres extends pulumi.Resource {} jest.mock('@lfdecentralizedtrust/splice-pulumi-common', () => ({ __esModule: true, appsAffinityAndTolerations: {}, @@ -22,6 +23,9 @@ jest.mock('@lfdecentralizedtrust/splice-pulumi-common', () => ({ HELM_MAX_HISTORY_SIZE: 42, imagePullSecretByNamespaceNameForServiceAccount: () => [], infraAffinityAndTolerations: {}, + CloudPostgres: function CloudPostgres() { + return new FakeCloudPostgres('CloudPostgres', 'cloud-postgres', true); + }, })); jest.mock('@lfdecentralizedtrust/splice-pulumi-common/src/config/envConfig', () => ({ __esModule: true, diff --git a/cluster/pulumi/gha/src/runners.ts b/cluster/pulumi/gha/src/runners.ts index 71f1514c6d..b1e1907d62 100644 --- a/cluster/pulumi/gha/src/runners.ts +++ b/cluster/pulumi/gha/src/runners.ts @@ -3,7 +3,9 @@ import * as k8s from '@pulumi/kubernetes'; import { appsAffinityAndTolerations, + CloudPostgres, DOCKER_REPO, + ExactNamespace, HELM_MAX_HISTORY_SIZE, imagePullSecretByNamespaceNameForServiceAccount, infraAffinityAndTolerations, @@ -18,6 +20,7 @@ import yaml from 'js-yaml'; import { createCachePvc } from './cache'; import { ghaConfig } from './config'; +import { createCloudSQLInstanceForPerformanceTests } from './performanceTests'; type ResourcesSpec = { requests?: { @@ -403,7 +406,8 @@ function installK8sRunnerScaleSet( cachePvcName: string, resources: ResourcesSpec, serviceAccountName: string, - dependsOn: Resource[] + dependsOn: Resource[], + performanceTestsDb: CloudPostgres ): Release { const podConfigMapName = `${name}-pod-config`; // A configMap that will be mounted to runner pods and provide additional pod spec for the workflow pods @@ -534,6 +538,21 @@ function installK8sRunnerScaleSet( name: 'ACTIONS_RUNNER_CONTAINER_HOOK_TEMPLATE', value: '/pod.yaml', }, + { + name: 'PERFORMANCE_TESTS_DB_HOST', + value: performanceTestsDb.address, + }, + { + name: 'PERFORMANCE_TESTS_DB_USER', + value: 'cnadmin', + }, + { + name: 'PERFORMANCE_TESTS_DB_PASSWORD', + valueFrom: { + key: 'postgresPassword', + name: performanceTestsDb.secretName, + }, + }, ], volumeMounts: [ { @@ -701,9 +720,10 @@ function installK8sRunnerScaleSets( runnersNamespace: Namespace, tokenSecret: Secret, cachePvcName: string, - serviceAccountName: string + serviceAccountName: string, + performanceTestsDb: CloudPostgres ): void { - const dependsOn = [controller, runnersNamespace, tokenSecret]; + const dependsOn = [controller, runnersNamespace, tokenSecret, performanceTestsDb]; runnerSpecs .filter(spec => spec.k8s) @@ -715,7 +735,8 @@ function installK8sRunnerScaleSets( cachePvcName, spec.resources, serviceAccountName, - dependsOn + dependsOn, + performanceTestsDb ); }); } @@ -754,12 +775,17 @@ function installPodMonitor(runnersNamespace: Namespace) { ); } +const GHA_NAMESPACE_NAME = 'gha-runners'; export function installRunnerScaleSets(controller: k8s.helm.v3.Release): void { - const runnersNamespace = new Namespace('gha-runners', { + const runnersNamespace = new Namespace(GHA_NAMESPACE_NAME, { metadata: { - name: 'gha-runners', + name: GHA_NAMESPACE_NAME, }, }); + const exactNs: ExactNamespace = { + ns: runnersNamespace, + logicalName: GHA_NAMESPACE_NAME, + }; const tokenSecret = new k8s.core.v1.Secret( 'gh-access-token', @@ -791,7 +817,15 @@ export function installRunnerScaleSets(controller: k8s.helm.v3.Release): void { const saName = 'k8s-runners'; installRunnersServiceAccount(runnersNamespace, saName); + const performanceTestsDb = createCloudSQLInstanceForPerformanceTests(exactNs); installDockerRunnerScaleSets(controller, runnersNamespace, tokenSecret, cachePvc, saName); - installK8sRunnerScaleSets(controller, runnersNamespace, tokenSecret, cachePvcName, saName); + installK8sRunnerScaleSets( + controller, + runnersNamespace, + tokenSecret, + cachePvcName, + saName, + performanceTestsDb + ); installPodMonitor(runnersNamespace); }