Skip to content

Commit a1b82a9

Browse files
TLS config with RDS tested with a healthy check (#1798)
This tests successful rhdh plugin initialization readding main deployment ignore the the TLS check in other tests consider rds values rename make all secrets base64 before applying add rhdh-dyanmic-plugins-root add path for postgres-crt Co-authored-by: Joseph Kim <[email protected]>
1 parent b37289a commit a1b82a9

File tree

10 files changed

+2823
-0
lines changed

10 files changed

+2823
-0
lines changed

.ibm/pipelines/env_variables.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ RELEASE_NAME_RBAC=rhdh-rbac
1919
NAME_SPACE="${NAME_SPACE:-showcase}"
2020
NAME_SPACE_RBAC="${NAME_SPACE_RBAC:-showcase-rbac}"
2121
NAME_SPACE_POSTGRES_DB="${NAME_SPACE_POSTGRES_DB:-postgress-external-db}"
22+
NAME_SPACE_RDS="showcase-rds-nightly"
2223
CHART_VERSION="2.15.2"
2324
GITHUB_APP_APP_ID=$(cat /tmp/secrets/GITHUB_APP_APP_ID)
2425
GITHUB_APP_CLIENT_ID=$(cat /tmp/secrets/GITHUB_APP_CLIENT_ID)
@@ -66,6 +67,11 @@ GOOGLE_ACC_COOKIE=$(cat /tmp/secrets/GOOGLE_ACC_COOKIE)
6667
GOOGLE_USER_ID=$(cat /tmp/secrets/GOOGLE_USER_ID)
6768
GOOGLE_USER_PASS=$(cat /tmp/secrets/GOOGLE_USER_PASS)
6869
GOOGLE_2FA_SECRET=$(cat /tmp/secrets/GOOGLE_2FA_SECRET)
70+
RDS_USER='cmhkaHFl'
71+
RDS_PASSWORD=$(cat /tmp/secrets/RDS_PASSWORD)
72+
RDS_1_HOST=$(cat /tmp/secrets/RDS_1_HOST)
73+
RDS_2_HOST=$(cat /tmp/secrets/RDS_2_HOST)
74+
RDS_3_HOST=$(cat /tmp/secrets/RDS_3_HOST)
6975

7076
JUNIT_RESULTS="junit-results.xml"
7177
DATA_ROUTER_URL=$(cat /tmp/secrets/DATA_ROUTER_URL)

.ibm/pipelines/openshift-ci-tests.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,20 @@ initiate_rbac_aks_deployment() {
359359
helm upgrade -i "${RELEASE_NAME_RBAC}" -n "${NAME_SPACE_RBAC_AKS}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "/tmp/${HELM_CHART_RBAC_AKS_MERGED_VALUE_FILE_NAME}" --set global.host="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}"
360360
}
361361

362+
initiate_rds_deployment() {
363+
local release_name=$1
364+
local namespace=$2
365+
configure_namespace "${namespace}"
366+
uninstall_helmchart "${namespace}" "${release_name}"
367+
sed -i "s|POSTGRES_USER:.*|POSTGRES_USER: $RDS_USER|g" "${DIR}/resources/postgres-db/postgres-cred.yaml"
368+
sed -i "s|POSTGRES_PASSWORD:.*|POSTGRES_PASSWORD: $(echo -n $RDS_PASSWORD | base64 -w 0)|g" "${DIR}/resources/postgres-db/postgres-cred.yaml"
369+
sed -i "s|POSTGRES_HOST:.*|POSTGRES_HOST: $(echo -n $RDS_1_HOST | base64 -w 0)|g" "${DIR}/resources/postgres-db/postgres-cred.yaml"
370+
oc apply -f "$DIR/resources/postgres-db/postgres-crt-rds.yaml" -n "${namespace}"
371+
oc apply -f "$DIR/resources/postgres-db/postgres-cred.yaml" -n "${namespace}"
372+
oc apply -f "$DIR/resources/postgres-db/dynamic-plugins-root-PVC.yaml" -n "${namespace}"
373+
helm upgrade -i "${release_name}" -n "${namespace}" "${HELM_REPO_NAME}/${HELM_IMAGE_NAME}" --version "${CHART_VERSION}" -f "$DIR/resources/postgres-db/values-showcase-postgres.yaml" --set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}" --set upstream.backstage.image.repository="${QUAY_REPO}" --set upstream.backstage.image.tag="${TAG_NAME}"
374+
}
375+
362376
check_and_test() {
363377
local release_name=$1
364378
local namespace=$2
@@ -437,6 +451,7 @@ main() {
437451
ENCODED_API_SERVER_URL=$(echo "${API_SERVER_URL}" | base64)
438452
ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64)
439453

454+
440455
if [[ "$JOB_NAME" == *aks* ]]; then
441456
initiate_aks_deployment
442457
check_and_test "${RELEASE_NAME}" "${NAME_SPACE_AKS}"
@@ -448,7 +463,13 @@ main() {
448463
initiate_deployments
449464
check_and_test "${RELEASE_NAME}" "${NAME_SPACE}"
450465
check_and_test "${RELEASE_NAME_RBAC}" "${NAME_SPACE_RBAC}"
466+
# Only test TLS config with RDS in nightly jobs
467+
if [[ "$JOB_NAME" == *periodic* ]]; then
468+
initiate_rds_deployment "${RELEASE_NAME}" "${NAME_SPACE_RDS}"
469+
check_and_test "${RELEASE_NAME}" "${NAME_SPACE_RDS}"
470+
fi
451471
fi
472+
452473
exit "${OVERALL_RESULT}"
453474
}
454475

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
kind: PersistentVolumeClaim
2+
apiVersion: v1
3+
metadata:
4+
name: rhdh-dynamic-plugins-root
5+
spec:
6+
accessModes:
7+
- ReadWriteOnce
8+
resources:
9+
requests:
10+
storage: 5Gi

.ibm/pipelines/resources/postgres-db/postgres-cred.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ data:
88
POSTGRES_USER: amFudXMtaWRw
99
POSTGRES_HOST: dG1w
1010
PGSSLMODE: cmVxdWlyZQ==
11+
NODE_EXTRA_CA_CERTS: L29wdC9hcHAtcm9vdC9zcmMvcG9zdGdyZXMtY3J0LnBlbQ==

.ibm/pipelines/resources/postgres-db/postgres-crt-rds.yaml

Lines changed: 2535 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
global:
2+
dynamic:
3+
includes:
4+
- dynamic-plugins.default.yaml
5+
plugins: []
6+
upstream:
7+
nameOverride: backstage
8+
commonLabels:
9+
backstage.io/kubernetes-id: developer-hub
10+
backstage:
11+
image:
12+
pullPolicy: Always
13+
registry: quay.io
14+
repository: janus-idp/backstage-showcase
15+
tag: next
16+
appConfig:
17+
app:
18+
baseUrl: 'https://{{- include "janus-idp.hostname" . }}'
19+
backend:
20+
auth:
21+
externalAccess:
22+
- options:
23+
secret: '${BACKEND_SECRET}'
24+
subject: legacy-default-config
25+
type: legacy
26+
baseUrl: 'https://{{- include "janus-idp.hostname" . }}'
27+
cors:
28+
origin: 'https://{{- include "janus-idp.hostname" . }}'
29+
database:
30+
connection: # configure Backstage DB connection parameters
31+
host: ${POSTGRES_HOST}
32+
port: ${POSTGRES_PORT}
33+
user: ${POSTGRES_USER}
34+
password: ${POSTGRES_PASSWORD}
35+
auth:
36+
environment: development
37+
providers:
38+
guest:
39+
dangerouslyAllowOutsideDevelopment: true
40+
extraEnvVars:
41+
- name: BACKEND_SECRET
42+
valueFrom:
43+
secretKeyRef:
44+
key: backend-secret
45+
name: '{{ include "janus-idp.backend-secret-name" $ }}'
46+
extraVolumeMounts:
47+
- mountPath: /opt/app-root/src/dynamic-plugins-root
48+
name: dynamic-plugins-root
49+
- mountPath: /opt/app-root/src/postgres-crt.pem
50+
name: postgres-crt # inject certificate secret to Backstage cont.
51+
subPath: postgres-crt.pem
52+
extraVolumes:
53+
- name: dynamic-plugins-root
54+
persistentVolumeClaim:
55+
claimName: '{{ printf "%s-dynamic-plugins-root" .Release.Name }}'
56+
- configMap:
57+
defaultMode: 420
58+
name: '{{ printf "%s-dynamic-plugins" .Release.Name }}'
59+
optional: true
60+
name: dynamic-plugins
61+
- name: dynamic-plugins-npmrc
62+
secret:
63+
defaultMode: 420
64+
optional: true
65+
secretName: '{{ printf "%s-dynamic-plugins-npmrc" .Release.Name }}'
66+
- name: dynamic-plugins-registry-auth
67+
secret:
68+
defaultMode: 416
69+
optional: true
70+
secretName: '{{ printf "%s-dynamic-plugins-registry-auth" .Release.Name }}'
71+
- name: postgres-crt
72+
secret:
73+
secretName: postgres-crt
74+
- emptyDir: {}
75+
name: npmcacache
76+
initContainers:
77+
- name: install-dynamic-plugins
78+
image: '{{ include "backstage.image" . }}'
79+
command:
80+
- ./install-dynamic-plugins.sh
81+
- /dynamic-plugins-root
82+
env:
83+
- name: NPM_CONFIG_USERCONFIG
84+
value: /opt/app-root/src/.npmrc.dynamic-plugins
85+
imagePullPolicy: Always
86+
volumeMounts:
87+
- mountPath: /dynamic-plugins-root
88+
name: dynamic-plugins-root
89+
- mountPath: /opt/app-root/src/dynamic-plugins.yaml
90+
name: dynamic-plugins
91+
readOnly: true
92+
subPath: dynamic-plugins.yaml
93+
- mountPath: /opt/app-root/src/.npmrc.dynamic-plugins
94+
name: dynamic-plugins-npmrc
95+
readOnly: true
96+
subPath: .npmrc
97+
- mountPath: /opt/app-root/src/.config/containers
98+
name: dynamic-plugins-registry-auth
99+
readOnly: true
100+
- mountPath: /opt/app-root/src/.npm/_cacache
101+
name: npmcacache
102+
workingDir: /opt/app-root/src
103+
installDir: /opt/app-root/src
104+
extraEnvVarsSecrets:
105+
- postgres-cred
106+
postgresql:
107+
enabled: false
108+
auth:
109+
existingSecret: postgres-cred

e2e-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"showcase-rbac-nightly": "playwright test --project=showcase-rbac",
1717
"showcase-aks-ci-nightly": "playwright test --project=showcase-aks",
1818
"showcase-rbac-aks-ci-nightly": "playwright test --project=showcase-rbac-aks",
19+
"showcase-rds-nightly": "playwright test --project=postgres-health-check",
1920
"lint:check": "eslint . --ext .js,.ts",
2021
"lint:fix": "eslint . --ext .js,.ts --fix",
2122
"postinstall": "playwright install",

e2e-tests/playwright.config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default defineConfig({
5555
"**/playwright/e2e/verify-tls-config-with-external-postgres-db.spec.ts",
5656
"**/playwright/e2e/authProviders/**/*.spec.ts",
5757
"**/playwright/e2e/plugins/bulk-import.spec.ts",
58+
"**/playwright/e2e/verify-tls-config-health-check.spec.ts",
5859
],
5960
},
6061
{
@@ -77,6 +78,7 @@ export default defineConfig({
7778
testIgnore: [
7879
"**/playwright/e2e/authProviders/setup-environment.spec.ts",
7980
"**/playwright/e2e/authProviders/clear-environment.spec.ts",
81+
"**/playwright/e2e/verify-tls-config-health-check.spec.ts",
8082
],
8183
dependencies: ["showcase-auth-providers-setup-environment"],
8284
teardown: "showcase-auth-providers-clear-environment",
@@ -105,6 +107,7 @@ export default defineConfig({
105107
"**/playwright/e2e/audit-log/**/*.spec.ts",
106108
"**/playwright/e2e/verify-redis-cache.spec.ts",
107109
"**/playwright/e2e/plugins/topology/topology.spec.ts",
110+
"**/playwright/e2e/verify-tls-config-health-check.spec.ts",
108111
],
109112
},
110113
{
@@ -116,6 +119,11 @@ export default defineConfig({
116119
"**/playwright/e2e/plugins/bulk-import.spec.ts",
117120
],
118121
},
122+
{
123+
name: "postgres-health-check",
124+
...useCommonDeviceAndViewportConfig,
125+
testMatch: ["**/playwright/e2e/verify-tls-config-health-check.spec.ts"],
126+
},
119127

120128
// {
121129
// name: 'firefox',
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { test } from "@playwright/test";
2+
import { Common } from "../utils/Common";
3+
import { kubeCLient } from "../utils/k8sHelper";
4+
5+
export const k8sClient = new kubeCLient();
6+
7+
test.describe
8+
.serial("Verify TLS configuration with Postgres DB health check", () => {
9+
const namespace = process.env.NAME_SPACE_RDS;
10+
const deploymentName = "rhdh-developer-hub";
11+
const secretName = "postgres-cred";
12+
const hostLatest2 = Buffer.from(process.env.RDS_2_HOST).toString("base64");
13+
const hostLatest3 = Buffer.from(process.env.RDS_3_HOST).toString("base64");
14+
15+
test("Verify successful DB connection and successful initialization of plugins with latest-1 postgres version", async ({
16+
page,
17+
}) => {
18+
const common = new Common(page);
19+
await common.loginAsGuest();
20+
});
21+
22+
test("Change the config to use the latest-2 postgres version", async () => {
23+
test.setTimeout(120000);
24+
const secretData = {
25+
POSTGRES_HOST: hostLatest2,
26+
};
27+
const patch = {
28+
data: secretData,
29+
};
30+
await k8sClient.updateSecret(secretName, namespace, patch);
31+
await k8sClient.restartDeployment(deploymentName, namespace);
32+
});
33+
34+
test("Verify successful DB connection and successful initialization of plugins with latest-2 postgres version", async ({
35+
page,
36+
}) => {
37+
const common = new Common(page);
38+
await common.loginAsGuest();
39+
});
40+
41+
test("Change the config to use the latest-3 postgres version", async () => {
42+
test.setTimeout(120000);
43+
const secretData = {
44+
POSTGRES_HOST: hostLatest3,
45+
};
46+
const patch = {
47+
data: secretData,
48+
};
49+
await k8sClient.updateSecret(secretName, namespace, patch);
50+
await k8sClient.restartDeployment(deploymentName, namespace);
51+
});
52+
53+
test("Verify successful DB connection and successful initialization of plugins with latest-3 postgres version", async ({
54+
page,
55+
}) => {
56+
const common = new Common(page);
57+
await common.loginAsGuest();
58+
});
59+
});

e2e-tests/playwright/utils/k8sHelper.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,32 @@ export class kubeCLient {
3434
}
3535
}
3636

37+
async scaleDeployment(
38+
deploymentName: string,
39+
namespace: string,
40+
replicas: number,
41+
) {
42+
const patch = { spec: { replicas: replicas } };
43+
try {
44+
await this.appsApi.patchNamespacedDeploymentScale(
45+
deploymentName,
46+
namespace,
47+
patch,
48+
undefined,
49+
undefined,
50+
undefined,
51+
undefined,
52+
undefined,
53+
{
54+
headers: { "Content-Type": "application/strategic-merge-patch+json" },
55+
},
56+
);
57+
console.log(`Deployment scaled to ${replicas} replicas.`);
58+
} catch (error) {
59+
console.error("Error scaling deployment:", error);
60+
}
61+
}
62+
3763
async getSecret(secretName: string, namespace: string) {
3864
try {
3965
logger.info(`Getting secret ${secretName} from namespace ${namespace}`);
@@ -181,4 +207,51 @@ export class kubeCLient {
181207
throw err;
182208
}
183209
}
210+
211+
async waitForDeploymentReady(
212+
deploymentName: string,
213+
namespace: string,
214+
expectedReplicas: number,
215+
timeout: number = 100000,
216+
checkInterval: number = 10000,
217+
) {
218+
const start = Date.now();
219+
220+
while (Date.now() - start < timeout) {
221+
try {
222+
const response = await this.appsApi.readNamespacedDeployment(
223+
deploymentName,
224+
namespace,
225+
);
226+
const availableReplicas = response.body.status?.availableReplicas || 0;
227+
228+
if (availableReplicas === expectedReplicas) {
229+
console.log(
230+
`Deployment ${deploymentName} is ready with ${availableReplicas} replicas.`,
231+
);
232+
return;
233+
}
234+
235+
console.log(
236+
`Waiting for ${deploymentName} to reach ${expectedReplicas} replicas, currently has ${availableReplicas}.`,
237+
);
238+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
239+
} catch (error) {
240+
console.error(`Error checking deployment status: ${error}`);
241+
throw error;
242+
}
243+
}
244+
245+
throw new Error(
246+
`Deployment ${deploymentName} did not become ready in time.`,
247+
);
248+
}
249+
250+
async restartDeployment(deploymentName: string, namespace: string) {
251+
await this.scaleDeployment(deploymentName, namespace, 0);
252+
await this.waitForDeploymentReady(deploymentName, namespace, 0);
253+
254+
await this.scaleDeployment(deploymentName, namespace, 1);
255+
await this.waitForDeploymentReady(deploymentName, namespace, 1);
256+
}
184257
}

0 commit comments

Comments
 (0)