Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cluster/pulumi/common/src/config/migrationSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const MigrationInfoSchema = z
.lt(10, 'Migration id must be less than or equal to 10 as we use in the cometbft ports.')
.gte(0),
version: migrationVersion,
allowDowngrade: z.boolean().default(false),
releaseReference: GitReferenceSchema.optional(),
sequencer: z
.object({
Expand Down
1 change: 1 addition & 0 deletions cluster/pulumi/common/src/domainMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,4 @@ export const DecentralizedSynchronizerUpgradeConfig: DecentralizedSynchronizerMi
new DecentralizedSynchronizerMigrationConfig(spliceConfig.configuration);

export const activeVersion = DecentralizedSynchronizerUpgradeConfig.active.version;
export const allowDowngrade = DecentralizedSynchronizerUpgradeConfig.active.allowDowngrade;
2 changes: 1 addition & 1 deletion cluster/pulumi/local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ $(dir)/clean:
$(dir)/format: $(dir)/.build
cd $(@D) && npm run format:fix

pulumi_projects ::= operator deployment gcp infra canton-network sv-runbook validator-runbook multi-validator cluster sv-canton validator1 splitwell
pulumi_projects ::= operator deployment gcp infra canton-network sv-runbook validator-runbook multi-validator cluster sv-canton validator1 splitwell policies

.PHONY: $(dir)/test $(dir)/update-expected
$(dir)/test: $(foreach project,$(pulumi_projects),$(dir)/$(project)/test)
Expand Down
142 changes: 125 additions & 17 deletions cluster/pulumi/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cluster/pulumi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"validator1",
"splitwell",
"circleci",
"gha"
"gha",
"policies"
],
"dependencies": {
"@google-cloud/sql": "^0.20.1",
Expand Down
3 changes: 3 additions & 0 deletions cluster/pulumi/policies/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/bin/
/node_modules/
/test*.json
4 changes: 4 additions & 0 deletions cluster/pulumi/policies/PulumiPolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: policies
runtime: nodejs
description: Contain all pulumi policies
main: policies/
9 changes: 9 additions & 0 deletions cluster/pulumi/policies/local.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

dir := $(call current_dir)

# sort array by (name, type)
JQ_FILTER := 'sort_by("\(.name)|\(.type)")'

include $(PULUMI_TEST_DIR)/pulumi-test-clusters.mk
26 changes: 26 additions & 0 deletions cluster/pulumi/policies/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@lfdecentralizedtrust/splice-pulumi-policy",
"main": "src/index.ts",
"dependencies": {
"@pulumi/kubernetes-cert-manager": "0.2.0",
"@pulumiverse/grafana": "0.16.3",
"@lfdecentralizedtrust/splice-pulumi-common": "1.0.0",
"@pulumi/gcp": "8.32.1",
"@pulumi/policy": "^1.18.1"
},
"overrides": {
"@pulumi/kubernetes-cert-manager": {
"@pulumi/kubernetes": "4.21.1"
}
},
"scripts": {
"fix": "npm run format:fix && npm run lint:fix",
"check": "npm run format:check && npm run lint:check && npm run type:check",
"type:check": "tsc --noEmit",
"format:fix": "prettier --write -- src",
"format:check": "prettier --check -- src",
"lint:fix": "eslint --fix --max-warnings=0 -- src",
"lint:check": "eslint --max-warnings=0 -- src",
"dump-config": "env -u KUBECONFIG ts-node ./dump-config.ts"
}
}
69 changes: 69 additions & 0 deletions cluster/pulumi/policies/src/downgrade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
import * as k8s from '@pulumi/kubernetes';
import * as semver from 'semver';
import { allowDowngrade } from '@lfdecentralizedtrust/splice-pulumi-common';
import { PolicyPack, validateResourceOfType } from '@pulumi/policy';
import { execSync } from 'child_process';

interface HelmRelease {
name: string;
namespace: string;
revision: string;
updated: string;
status: string;
chart: string;
app_version: string;
}

function getHelmAppVersion(releaseName: string, namespace: string): string | undefined {
try {
const command = `helm list --namespace ${namespace} --output json`;
const stdout = execSync(command, { encoding: 'utf-8' });
const releases: HelmRelease[] = JSON.parse(stdout);
const targetRelease = releases.find(release => release.name === releaseName);
return targetRelease ? targetRelease.app_version : undefined;
} catch (error) {
console.warn(`Error fetching Helm releases in namespace "${namespace}":`, error);
return undefined;
}
}

export function applyDowngradePolicy(): PolicyPack {
return new PolicyPack('downgrade-policy', {
policies: [
{
name: 'prevent-app-version-downgrade',
description:
"Prohibits downgrading the 'appVersion' label on Kubernetes Deployments if `allowDowngrade` is not set.",
enforcementLevel: 'mandatory',
validateResource: validateResourceOfType(
k8s.helm.v3.Release,
(_, args, reportViolation) => {
const newVersion = args.props.version as string;
const currentVersion = getHelmAppVersion('ingress-sv', 'sv-1');

if (allowDowngrade) {
console.log('Allow downgrades');
return;
}

if (!currentVersion) {
console.log('Fresh cluster');
return;
}

if (newVersion && semver.valid(currentVersion) && semver.valid(newVersion)) {
if (semver.lt(newVersion, currentVersion)) {
reportViolation(
`Deployment '${args.name}' cannot be downgraded from appVersion '${currentVersion}' to '${newVersion}'.` +
` To override, configure this policy with 'allowDowngrades: true'.`
);
}
}
}
),
},
],
});
}
5 changes: 5 additions & 0 deletions cluster/pulumi/policies/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
import { applyDowngradePolicy } from './downgrade';

applyDowngradePolicy();
9 changes: 9 additions & 0 deletions cluster/pulumi/policies/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"include": [
"src/**/*.ts",
"*.ts"
,
"../common/src/operator/stack.ts"
]
}
3 changes: 3 additions & 0 deletions cluster/pulumi/pulumi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import fs from 'fs';
import os from 'os';
import path from 'path';
import {spliceEnvConfig} from "@lfdecentralizedtrust/splice-pulumi-common/src/config/envConfig";

const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pulumi-'));

Expand Down Expand Up @@ -44,6 +45,7 @@ export function pulumiOptsWithPrefix(
onOutput: (output: string) => void;
signal: AbortSignal;
color: 'always';
policyPacks: string[];
} {
return {
parallel: 128,
Expand All @@ -55,6 +57,7 @@ export function pulumiOptsWithPrefix(
},
signal: abortSignal,
color: 'always',
policyPacks: [`${spliceEnvConfig.context.splicePath}/cluster/pulumi/policies`],
};
}

Expand Down
Loading
Loading