fix(hwlab): route d601 v03 postgres through gateway (#957)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -159,11 +159,8 @@ lanes:
|
||||
webProbe:
|
||||
browserProxyMode: direct
|
||||
defaultOrigin:
|
||||
mode: k8s-service-cluster-ip
|
||||
serviceName: hwlab-cloud-web
|
||||
namespace: hwlab-v03
|
||||
port: 8080
|
||||
scheme: http
|
||||
mode: public
|
||||
baseUrl: https://hwlab.pikapython.com
|
||||
alertThresholds:
|
||||
sameOriginApiSlowMs: 10000
|
||||
partialApiSlowMs: 10000
|
||||
@@ -438,9 +435,13 @@ lanes:
|
||||
externalPostgres:
|
||||
provider: PK01
|
||||
configRef: config/platform-db/postgres-pk01.yaml
|
||||
serviceName: pk01-platform-postgres
|
||||
serviceName: d601-pk01-platform-postgres
|
||||
endpointAddress: 82.156.23.220
|
||||
port: 5432
|
||||
runtimeAccess:
|
||||
routeName: d601-pk01-postgres
|
||||
endpointAddress: d601-tcp-egress-gateway.unidesk.svc.cluster.local
|
||||
port: 25432
|
||||
sslmode: require
|
||||
database: hwlab_d601_v03
|
||||
cloudApi:
|
||||
|
||||
@@ -230,6 +230,36 @@ postgres:
|
||||
user: agentrun_v02
|
||||
address: 74.48.78.17/32
|
||||
method: scram-sha-256
|
||||
- type: hostssl
|
||||
database: hwlab_d601_v03
|
||||
user: hwlab_d601_v03_app
|
||||
address: 10.0.8.0/22
|
||||
method: scram-sha-256
|
||||
- type: hostssl
|
||||
database: postgres
|
||||
user: hwlab_d601_v03_app
|
||||
address: 10.0.8.0/22
|
||||
method: scram-sha-256
|
||||
- type: hostssl
|
||||
database: hwlab_d601_v03
|
||||
user: hwlab_d601_v03_app
|
||||
address: 36.49.29.0/24
|
||||
method: scram-sha-256
|
||||
- type: hostssl
|
||||
database: postgres
|
||||
user: hwlab_d601_v03_app
|
||||
address: 36.49.29.0/24
|
||||
method: scram-sha-256
|
||||
- type: hostssl
|
||||
database: hwlab_d601_v03
|
||||
user: hwlab_d601_v03_app
|
||||
address: 74.48.78.17/32
|
||||
method: scram-sha-256
|
||||
- type: hostssl
|
||||
database: postgres
|
||||
user: hwlab_d601_v03_app
|
||||
address: 74.48.78.17/32
|
||||
method: scram-sha-256
|
||||
|
||||
secrets:
|
||||
source: master-local
|
||||
@@ -291,6 +321,20 @@ secrets:
|
||||
AGENTRUN_V02_DB_NAME: agentrun_v02
|
||||
randomHex:
|
||||
AGENTRUN_V02_DB_PASSWORD: 32
|
||||
- name: hwlab-d601-v03-db-credentials
|
||||
sourceRef: platform-db/hwlab-d601-v03-db.env
|
||||
type: env
|
||||
requiredKeys:
|
||||
- HWLAB_D601_V03_DB_USER
|
||||
- HWLAB_D601_V03_DB_PASSWORD
|
||||
- HWLAB_D601_V03_DB_NAME
|
||||
createIfMissing:
|
||||
enabled: true
|
||||
values:
|
||||
HWLAB_D601_V03_DB_USER: hwlab_d601_v03_app
|
||||
HWLAB_D601_V03_DB_NAME: hwlab_d601_v03
|
||||
randomHex:
|
||||
HWLAB_D601_V03_DB_PASSWORD: 32
|
||||
objects:
|
||||
roles:
|
||||
- name: sub2api
|
||||
@@ -329,6 +373,15 @@ objects:
|
||||
createdb: false
|
||||
createrole: false
|
||||
superuser: false
|
||||
- name: hwlab_d601_v03_app
|
||||
passwordRef:
|
||||
sourceRef: platform-db/hwlab-d601-v03-db.env
|
||||
key: HWLAB_D601_V03_DB_PASSWORD
|
||||
login: true
|
||||
attributes:
|
||||
createdb: false
|
||||
createrole: false
|
||||
superuser: false
|
||||
databases:
|
||||
- name: sub2api
|
||||
owner: sub2api
|
||||
@@ -350,6 +403,11 @@ objects:
|
||||
encoding: UTF8
|
||||
locale: C.UTF-8
|
||||
extensions: []
|
||||
- name: hwlab_d601_v03
|
||||
owner: hwlab_d601_v03_app
|
||||
encoding: UTF8
|
||||
locale: C.UTF-8
|
||||
extensions: []
|
||||
|
||||
exports:
|
||||
connectionStrings:
|
||||
@@ -413,6 +471,38 @@ exports:
|
||||
- scope: agentrun-v02
|
||||
secret: agentrun-v02-mgr-db
|
||||
key: DATABASE_URL
|
||||
- name: hwlab-d601-v03-cloud-api-database-url
|
||||
sourceSecretRef: platform-db/hwlab-d601-v03-db.env
|
||||
render:
|
||||
envKey: DATABASE_URL
|
||||
format: postgresql://$(HWLAB_D601_V03_DB_USER):$(HWLAB_D601_V03_DB_PASSWORD)@$(PGHOST):$(PGPORT)/$(HWLAB_D601_V03_DB_NAME)?sslmode=require
|
||||
variables:
|
||||
PGHOST: d601-tcp-egress-gateway.unidesk.svc.cluster.local
|
||||
PGPORT: "25432"
|
||||
writeToSecretSource:
|
||||
sourceRef: hwlab/d601-v03-cloud-api-db.env
|
||||
key: DATABASE_URL
|
||||
mode: update-or-insert
|
||||
consumers:
|
||||
- scope: hwlab-d601-v03
|
||||
secret: hwlab-cloud-api-v03-db
|
||||
key: DATABASE_URL
|
||||
- name: hwlab-d601-v03-openfga-datastore-uri
|
||||
sourceSecretRef: platform-db/hwlab-d601-v03-db.env
|
||||
render:
|
||||
envKey: DATASTORE_URI
|
||||
format: postgres://$(HWLAB_D601_V03_DB_USER):$(HWLAB_D601_V03_DB_PASSWORD)@$(PGHOST):$(PGPORT)/$(HWLAB_D601_V03_DB_NAME)?sslmode=require
|
||||
variables:
|
||||
PGHOST: d601-tcp-egress-gateway.unidesk.svc.cluster.local
|
||||
PGPORT: "25432"
|
||||
writeToSecretSource:
|
||||
sourceRef: hwlab/d601-v03-openfga-db.env
|
||||
key: DATASTORE_URI
|
||||
mode: update-or-insert
|
||||
consumers:
|
||||
- scope: hwlab-d601-v03
|
||||
secret: hwlab-v03-openfga
|
||||
key: DATASTORE_URI
|
||||
|
||||
backup:
|
||||
phase: minimum-restoreable
|
||||
@@ -452,6 +542,9 @@ observability:
|
||||
- kind: psql-app-role
|
||||
database: agentrun_v02
|
||||
user: agentrun_v02
|
||||
- kind: psql-app-role
|
||||
database: hwlab_d601_v03
|
||||
user: hwlab_d601_v03_app
|
||||
- kind: disk-free
|
||||
path: /var/lib/postgresql/16/main
|
||||
minFreeGiB: 10
|
||||
|
||||
@@ -69,12 +69,19 @@ export interface HwlabRuntimeExternalPostgresComponentSpec {
|
||||
readonly schema?: string;
|
||||
}
|
||||
|
||||
export interface HwlabRuntimeExternalPostgresRuntimeAccessSpec {
|
||||
readonly routeName?: string;
|
||||
readonly endpointAddress: string;
|
||||
readonly port: number;
|
||||
}
|
||||
|
||||
export interface HwlabRuntimeExternalPostgresSpec {
|
||||
readonly provider: string;
|
||||
readonly configRef: string;
|
||||
readonly serviceName: string;
|
||||
readonly endpointAddress: string;
|
||||
readonly port: number;
|
||||
readonly runtimeAccess?: HwlabRuntimeExternalPostgresRuntimeAccessSpec;
|
||||
readonly sslmode: "require";
|
||||
readonly database: string;
|
||||
readonly cloudApi: HwlabRuntimeExternalPostgresComponentSpec;
|
||||
@@ -657,6 +664,16 @@ function externalPostgresComponentConfig(value: unknown, path: string): HwlabRun
|
||||
};
|
||||
}
|
||||
|
||||
function externalPostgresRuntimeAccessConfig(value: unknown, path: string): HwlabRuntimeExternalPostgresRuntimeAccessSpec | undefined {
|
||||
if (value === undefined) return undefined;
|
||||
const raw = asRecord(value, path);
|
||||
return {
|
||||
routeName: optionalStringField(raw, "routeName", path),
|
||||
endpointAddress: stringField(raw, "endpointAddress", path),
|
||||
port: numberField(raw, "port", path),
|
||||
};
|
||||
}
|
||||
|
||||
function externalPostgresConfig(value: unknown, path: string): HwlabRuntimeExternalPostgresSpec | undefined {
|
||||
if (value === undefined) return undefined;
|
||||
const raw = asRecord(value, path);
|
||||
@@ -668,6 +685,7 @@ function externalPostgresConfig(value: unknown, path: string): HwlabRuntimeExter
|
||||
serviceName: stringField(raw, "serviceName", path),
|
||||
endpointAddress: stringField(raw, "endpointAddress", path),
|
||||
port: numberField(raw, "port", path),
|
||||
...(raw.runtimeAccess === undefined ? {} : { runtimeAccess: externalPostgresRuntimeAccessConfig(raw.runtimeAccess, `${path}.runtimeAccess`) }),
|
||||
sslmode,
|
||||
database: stringField(raw, "database", path),
|
||||
cloudApi: externalPostgresComponentConfig(raw.cloudApi, `${path}.cloudApi`),
|
||||
|
||||
@@ -156,6 +156,7 @@ export function nodeRuntimeExpected(spec: HwlabRuntimeLaneSpec): Record<string,
|
||||
serviceName: spec.externalPostgres.serviceName,
|
||||
endpointAddress: spec.externalPostgres.endpointAddress,
|
||||
port: spec.externalPostgres.port,
|
||||
runtimeAccess: spec.externalPostgres.runtimeAccess ?? null,
|
||||
sslmode: spec.externalPostgres.sslmode,
|
||||
database: spec.externalPostgres.database,
|
||||
cloudApi: {
|
||||
|
||||
@@ -197,6 +197,7 @@ export function runtimeSecretSpec(input: { node: string; lane: string }): Runtim
|
||||
const platformDb = externalPostgres !== undefined || postgresStore?.mode === "platform-service";
|
||||
const localPostgresService = postgresStore?.serviceName ?? `${namespace}-postgres`;
|
||||
const platformPostgresService = externalPostgres?.serviceName ?? postgresStore?.serviceName ?? "g14-platform-postgres";
|
||||
const platformPostgresRuntimeAccess = externalPostgres?.runtimeAccess;
|
||||
const legacyPostgresHost = `${localPostgresService}.${namespace}.svc.cluster.local`;
|
||||
const platformPostgresHost = `${platformPostgresService}.${namespace}.svc.cluster.local`;
|
||||
const platformPostgresEndpointSlice = `${platformPostgresService}-host`;
|
||||
@@ -212,7 +213,7 @@ export function runtimeSecretSpec(input: { node: string; lane: string }): Runtim
|
||||
...(runtimeLaneSpec === undefined ? {} : { runtimeLaneSpec }),
|
||||
...(externalPostgres === undefined ? {} : { externalPostgres }),
|
||||
platformPostgresService,
|
||||
platformPostgresEndpointAddress: externalPostgres?.endpointAddress,
|
||||
platformPostgresEndpointAddress: platformPostgresRuntimeAccess?.endpointAddress ?? externalPostgres?.endpointAddress,
|
||||
platformPostgresEndpointSlice,
|
||||
postgresSecret: postgresStore?.secretName ?? `${namespace}-postgres`,
|
||||
postgresStatefulSet: postgresStore?.statefulSet ?? postgresStore?.secretName ?? `${namespace}-postgres`,
|
||||
|
||||
@@ -1579,11 +1579,13 @@ export function nodeRuntimePipelinePostprocessScript(): string[] {
|
||||
"function patchExternalPostgres() {",
|
||||
" const pg = overlay.externalPostgres;",
|
||||
" if (!pg || !pg.serviceName) return false;",
|
||||
" const access = pg.runtimeAccess || { endpointAddress: pg.endpointAddress, port: pg.port };",
|
||||
" const file = path.join(runtimePath, 'external-postgres.yaml');",
|
||||
" if (!fs.existsSync(file)) return false;",
|
||||
" const doc = readYaml(file);",
|
||||
" const items = listItems(doc).filter(Boolean);",
|
||||
" let changed = false;",
|
||||
" const endpointIsIpv4 = /^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$/.test(String(access.endpointAddress));",
|
||||
" const endpointSliceName = String(pg.serviceName) + '-host';",
|
||||
" for (const item of items) {",
|
||||
" if (!item || typeof item !== 'object') continue;",
|
||||
@@ -1594,20 +1596,33 @@ export function nodeRuntimePipelinePostprocessScript(): string[] {
|
||||
" if (item.kind === 'Service') {",
|
||||
" item.metadata.name = pg.serviceName;",
|
||||
" item.spec = item.spec || {};",
|
||||
" item.spec.ports = [{ name: 'postgres', port: pg.port, targetPort: pg.port, protocol: 'TCP' }];",
|
||||
" if (endpointIsIpv4) {",
|
||||
" item.spec.type = 'ClusterIP';",
|
||||
" delete item.spec.externalName;",
|
||||
" } else {",
|
||||
" item.spec.type = 'ExternalName';",
|
||||
" item.spec.externalName = String(access.endpointAddress);",
|
||||
" delete item.spec.clusterIP;",
|
||||
" delete item.spec.clusterIPs;",
|
||||
" delete item.spec.ipFamilies;",
|
||||
" delete item.spec.ipFamilyPolicy;",
|
||||
" delete item.spec.internalTrafficPolicy;",
|
||||
" }",
|
||||
" item.spec.ports = [{ name: 'postgres', port: access.port, targetPort: access.port, protocol: 'TCP' }];",
|
||||
" delete item.spec.selector;",
|
||||
" changed = true;",
|
||||
" }",
|
||||
" if (item.kind === 'EndpointSlice') {",
|
||||
" if (!endpointIsIpv4) { item.__delete = true; changed = true; continue; }",
|
||||
" item.metadata.name = endpointSliceName;",
|
||||
" item.metadata.labels['kubernetes.io/service-name'] = pg.serviceName;",
|
||||
" item.addressType = 'IPv4';",
|
||||
" item.ports = [{ name: 'postgres', port: pg.port, protocol: 'TCP' }];",
|
||||
" item.endpoints = [{ addresses: [pg.endpointAddress], conditions: { ready: true } }];",
|
||||
" item.ports = [{ name: 'postgres', port: access.port, protocol: 'TCP' }];",
|
||||
" item.endpoints = [{ addresses: [access.endpointAddress], conditions: { ready: true } }];",
|
||||
" changed = true;",
|
||||
" }",
|
||||
" }",
|
||||
" if (changed) writeYaml(file, normalizeList(items));",
|
||||
" if (changed) writeYaml(file, normalizeList(items.filter((item) => !item.__delete)));",
|
||||
" return changed;",
|
||||
"}",
|
||||
"function patchHealthContract() {",
|
||||
@@ -1829,19 +1844,29 @@ export function nodeRuntimePipelinePostprocessScript(): string[] {
|
||||
"if (overlay.externalPostgres && overlay.externalPostgres.sslmode) checks.push('runtime-db-ssl-mode');",
|
||||
"const pg = overlay.externalPostgres;",
|
||||
"if (pg && pg.serviceName) {",
|
||||
" const access = pg.runtimeAccess || { endpointAddress: pg.endpointAddress, port: pg.port };",
|
||||
" const file = path.join(runtimePath, 'external-postgres.yaml');",
|
||||
" if (!fs.existsSync(file)) fail('external-postgres-missing');",
|
||||
" const items = listItems(readYaml(file)).filter(Boolean);",
|
||||
" const service = items.find((item) => item && item.kind === 'Service' && item.metadata && item.metadata.name === pg.serviceName);",
|
||||
" const endpointSlice = items.find((item) => item && item.kind === 'EndpointSlice' && item.metadata && item.metadata.name === String(pg.serviceName) + '-host');",
|
||||
" if (!service) fail('external-postgres-service-missing', { expected: pg.serviceName });",
|
||||
" if (!endpointSlice) fail('external-postgres-endpointslice-missing', { expected: String(pg.serviceName) + '-host' });",
|
||||
" const endpointIsIpv4 = /^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$/.test(String(access.endpointAddress));",
|
||||
" const servicePort = service.spec && Array.isArray(service.spec.ports) && service.spec.ports[0] ? service.spec.ports[0].port : null;",
|
||||
" if (!endpointIsIpv4) {",
|
||||
" if (service.spec && service.spec.type !== 'ExternalName') fail('external-postgres-service-type-mismatch', { value: service.spec.type, expected: 'ExternalName' });",
|
||||
" if (!service.spec || String(service.spec.externalName) !== String(access.endpointAddress)) fail('external-postgres-external-name-mismatch', { value: service.spec && service.spec.externalName, expected: access.endpointAddress });",
|
||||
" if (Number(servicePort) !== Number(access.port)) fail('external-postgres-port-mismatch', { servicePort, expectedPort: access.port });",
|
||||
" if (endpointSlice) fail('external-postgres-endpointslice-unexpected', { name: String(pg.serviceName) + '-host' });",
|
||||
" checks.push('external-postgres-bridge');",
|
||||
" } else {",
|
||||
" if (!endpointSlice) fail('external-postgres-endpointslice-missing', { expected: String(pg.serviceName) + '-host' });",
|
||||
" const endpointPort = Array.isArray(endpointSlice.ports) && endpointSlice.ports[0] ? endpointSlice.ports[0].port : null;",
|
||||
" const endpointAddress = Array.isArray(endpointSlice.endpoints) && endpointSlice.endpoints[0] && Array.isArray(endpointSlice.endpoints[0].addresses) ? endpointSlice.endpoints[0].addresses[0] : null;",
|
||||
" if (Number(servicePort) !== Number(pg.port) || Number(endpointPort) !== Number(pg.port)) fail('external-postgres-port-mismatch', { servicePort, endpointPort, expectedPort: pg.port });",
|
||||
" if (String(endpointAddress) !== String(pg.endpointAddress)) fail('external-postgres-address-mismatch', { endpointAddress, expectedEndpointAddress: pg.endpointAddress });",
|
||||
" if (Number(servicePort) !== Number(access.port) || Number(endpointPort) !== Number(access.port)) fail('external-postgres-port-mismatch', { servicePort, endpointPort, expectedPort: access.port });",
|
||||
" if (String(endpointAddress) !== String(access.endpointAddress)) fail('external-postgres-address-mismatch', { endpointAddress, expectedEndpointAddress: access.endpointAddress });",
|
||||
" checks.push('external-postgres-bridge');",
|
||||
" }",
|
||||
"}",
|
||||
"const exposure = overlay.publicExposure;",
|
||||
"if (exposure && exposure.enabled) {",
|
||||
|
||||
@@ -578,6 +578,7 @@ export function platformDbSecretStatusScript(options: NodeSecretOptions, spec: R
|
||||
"secret_exists_flag() { kubectl -n \"$namespace\" get secret \"$1\" >/dev/null 2>&1 && printf yes || printf no; }",
|
||||
"resource_exists_flag() { kubectl -n \"$namespace\" get \"$1\" \"$2\" >/dev/null 2>&1 && printf yes || printf no; }",
|
||||
"endpointslice_exists_flag() { kubectl -n \"$namespace\" get endpointslice \"$1\" >/dev/null 2>&1 && printf yes || printf no; }",
|
||||
"service_jsonpath() { kubectl -n \"$namespace\" get service \"$platform_service\" -o \"jsonpath=$1\" 2>/dev/null || true; }",
|
||||
"secret_b64_key() { kubectl -n \"$namespace\" get secret \"$1\" -o \"go-template={{ index .data \\\"$2\\\" }}\" 2>/dev/null || true; }",
|
||||
"decoded_value() { if [ -n \"$1\" ]; then printf '%s' \"$1\" | base64 -d 2>/dev/null || true; fi; }",
|
||||
"decoded_length() { if [ -n \"$1\" ]; then printf '%s' \"$1\" | base64 -d 2>/dev/null | wc -c | tr -d ' '; else printf '0'; fi; }",
|
||||
@@ -611,6 +612,11 @@ export function platformDbSecretStatusScript(options: NodeSecretOptions, spec: R
|
||||
"platform_service_exists=$(resource_exists_flag service \"$platform_service\")",
|
||||
"platform_endpoints_exists=$(resource_exists_flag endpoints \"$platform_service\")",
|
||||
"platform_endpointslice_exists=$(endpointslice_exists_flag \"$platform_endpointslice\")",
|
||||
"platform_service_type=$(service_jsonpath '{.spec.type}')",
|
||||
"platform_external_name=$(service_jsonpath '{.spec.externalName}')",
|
||||
"platform_service_port=$(service_jsonpath '{.spec.ports[0].port}')",
|
||||
"platform_external_name_matches=no",
|
||||
"if [ \"$platform_service_type\" = ExternalName ] && [ \"$platform_external_name\" = \"$db_host\" ]; then platform_external_name_matches=yes; fi",
|
||||
"uri_matches_expected \"$uri_value\"",
|
||||
"printf 'namespace\\t%s\\n' \"$namespace\"",
|
||||
"printf 'secret\\t%s\\n' \"$name\"",
|
||||
@@ -638,6 +644,10 @@ export function platformDbSecretStatusScript(options: NodeSecretOptions, spec: R
|
||||
"printf 'platformEndpointSlice\\t%s\\n' \"$platform_endpointslice\"",
|
||||
"printf 'platformEndpointSliceExists\\t%s\\n' \"$platform_endpointslice_exists\"",
|
||||
"printf 'platformEndpointAddress\\t%s\\n' \"$platform_endpoint_address\"",
|
||||
"printf 'platformServiceType\\t%s\\n' \"$platform_service_type\"",
|
||||
"printf 'platformExternalName\\t%s\\n' \"$platform_external_name\"",
|
||||
"printf 'platformServicePort\\t%s\\n' \"$platform_service_port\"",
|
||||
"printf 'platformExternalNameMatches\\t%s\\n' \"$platform_external_name_matches\"",
|
||||
"printf 'dbName\\t%s\\n' \"$db_name\"",
|
||||
"printf 'dbUser\\t%s\\n' \"$db_user\"",
|
||||
"printf 'dbHost\\t%s\\n' \"$db_host\"",
|
||||
@@ -1778,7 +1788,7 @@ export function secretStatusFromText(text: string, commandOk: boolean, exitCode:
|
||||
typeof afterUrlBytes === "number" && afterUrlBytes > 0;
|
||||
const platformBridgeHealthy = fields.platformServiceExists === "yes" &&
|
||||
fields.platformEndpointsExists !== "yes" &&
|
||||
fields.platformEndpointSliceExists === "yes";
|
||||
(fields.platformEndpointSliceExists === "yes" || fields.platformExternalNameMatches === "yes");
|
||||
const uriHealthy = fields.dbHostMatchesPlatform === "yes" &&
|
||||
fields.dbNameMatchesExpected === "yes" &&
|
||||
fields.dbUserMatchesExpected === "yes";
|
||||
@@ -1808,6 +1818,9 @@ export function secretStatusFromText(text: string, commandOk: boolean, exitCode:
|
||||
legacyEndpointsAbsent: fields.platformEndpointsExists !== "yes",
|
||||
endpointSlice: fields.platformEndpointSlice || `${spec.platformPostgresService}-host`,
|
||||
endpointSliceExists: fields.platformEndpointSliceExists === "yes",
|
||||
serviceType: fields.platformServiceType || null,
|
||||
externalName: fields.platformExternalName || null,
|
||||
externalNameMatches: fields.platformExternalNameMatches === "yes",
|
||||
},
|
||||
dbName: fields.dbName || spec.cloudApiDbName,
|
||||
dbUser: fields.dbUser || spec.cloudApiDbUser,
|
||||
@@ -1917,7 +1930,7 @@ export function secretStatusFromText(text: string, commandOk: boolean, exitCode:
|
||||
typeof afterUriBytes === "number" && afterUriBytes > 0;
|
||||
const platformBridgeHealthy = fields.platformServiceExists === "yes" &&
|
||||
fields.platformEndpointsExists !== "yes" &&
|
||||
fields.platformEndpointSliceExists === "yes";
|
||||
(fields.platformEndpointSliceExists === "yes" || fields.platformExternalNameMatches === "yes");
|
||||
const uriHealthy = fields.dbHostMatchesPlatform === "yes" &&
|
||||
fields.dbNameMatchesExpected === "yes" &&
|
||||
fields.dbUserMatchesExpected === "yes";
|
||||
@@ -1948,6 +1961,9 @@ export function secretStatusFromText(text: string, commandOk: boolean, exitCode:
|
||||
legacyEndpointsAbsent: fields.platformEndpointsExists !== "yes",
|
||||
endpointSlice: fields.platformEndpointSlice || `${spec.platformPostgresService}-host`,
|
||||
endpointSliceExists: fields.platformEndpointSliceExists === "yes",
|
||||
serviceType: fields.platformServiceType || null,
|
||||
externalName: fields.platformExternalName || null,
|
||||
externalNameMatches: fields.platformExternalNameMatches === "yes",
|
||||
},
|
||||
dbName: fields.dbName || spec.openFgaDbName,
|
||||
dbUser: fields.dbUser || spec.openFgaDbUser,
|
||||
|
||||
@@ -114,6 +114,7 @@ export function nodeRuntimeRenderOverlay(spec: HwlabRuntimeLaneSpec): Record<str
|
||||
serviceName: spec.externalPostgres.serviceName,
|
||||
endpointAddress: spec.externalPostgres.endpointAddress,
|
||||
port: spec.externalPostgres.port,
|
||||
runtimeAccess: spec.externalPostgres.runtimeAccess ?? null,
|
||||
sslmode: spec.externalPostgres.sslmode,
|
||||
},
|
||||
};
|
||||
@@ -1070,17 +1071,42 @@ export function externalPostgresBridgeStatus(spec: HwlabRuntimeLaneSpec, namespa
|
||||
const pg = spec.externalPostgres;
|
||||
if (pg === undefined) return { required: false, ready: true };
|
||||
if (!namespaceExists) return { required: true, ready: false, degradedReason: "runtime-namespace-missing" };
|
||||
const service = runNodeK3sArgs(spec, ["kubectl", "-n", spec.runtimeNamespace, "get", "service", pg.serviceName, "-o", "name"], 60);
|
||||
const endpointSlice = runNodeK3sArgs(spec, ["kubectl", "-n", spec.runtimeNamespace, "get", "endpointslice", `${pg.serviceName}-host`, "-o", "jsonpath={.endpoints[0].addresses[0]}{\"\\n\"}{.ports[0].port}{\"\\n\"}"], 60);
|
||||
const [address = "", port = ""] = endpointSlice.stdout.split(/\r?\n/u);
|
||||
const runtimeAccess = pg.runtimeAccess ?? { endpointAddress: pg.endpointAddress, port: pg.port };
|
||||
const endpointIsIpv4 = /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/u.test(runtimeAccess.endpointAddress);
|
||||
const service = runNodeK3sArgs(spec, ["kubectl", "-n", spec.runtimeNamespace, "get", "service", pg.serviceName, "-o", "jsonpath={.spec.type}{\"\\n\"}{.spec.externalName}{\"\\n\"}{.spec.ports[0].port}{\"\\n\"}"], 60);
|
||||
const [serviceType = "", externalName = "", servicePort = ""] = service.stdout.split(/\r?\n/u);
|
||||
if (!endpointIsIpv4) {
|
||||
const ready = service.exitCode === 0 && serviceType === "ExternalName" && externalName === runtimeAccess.endpointAddress && Number(servicePort) === runtimeAccess.port;
|
||||
return {
|
||||
required: true,
|
||||
ready,
|
||||
serviceName: pg.serviceName,
|
||||
serviceType: serviceType || null,
|
||||
externalName: externalName || null,
|
||||
expectedExternalName: runtimeAccess.endpointAddress,
|
||||
port: numericField(servicePort),
|
||||
expectedPort: runtimeAccess.port,
|
||||
providerEndpointAddress: pg.endpointAddress,
|
||||
providerPort: pg.port,
|
||||
runtimeAccess: pg.runtimeAccess ?? null,
|
||||
service: compactRuntimeCommand(service),
|
||||
};
|
||||
}
|
||||
const endpointSlice = runNodeK3sArgs(spec, ["kubectl", "-n", spec.runtimeNamespace, "get", "endpointslice", `${pg.serviceName}-host`, "-o", "jsonpath={.addressType}{\"\\n\"}{.endpoints[0].addresses[0]}{\"\\n\"}{.ports[0].port}{\"\\n\"}"], 60);
|
||||
const [addressType = "", address = "", port = ""] = endpointSlice.stdout.split(/\r?\n/u);
|
||||
return {
|
||||
required: true,
|
||||
ready: service.exitCode === 0 && endpointSlice.exitCode === 0 && address === pg.endpointAddress && Number(port) === pg.port,
|
||||
ready: service.exitCode === 0 && endpointSlice.exitCode === 0 && serviceType !== "ExternalName" && address === runtimeAccess.endpointAddress && Number(port) === runtimeAccess.port,
|
||||
serviceName: pg.serviceName,
|
||||
serviceType: serviceType || null,
|
||||
addressType: addressType || null,
|
||||
endpointAddress: address || null,
|
||||
expectedEndpointAddress: pg.endpointAddress,
|
||||
expectedEndpointAddress: runtimeAccess.endpointAddress,
|
||||
port: numericField(port),
|
||||
expectedPort: pg.port,
|
||||
expectedPort: runtimeAccess.port,
|
||||
providerEndpointAddress: pg.endpointAddress,
|
||||
providerPort: pg.port,
|
||||
runtimeAccess: pg.runtimeAccess ?? null,
|
||||
service: compactRuntimeCommand(service),
|
||||
endpointSlice: compactRuntimeCommand(endpointSlice),
|
||||
};
|
||||
|
||||
@@ -909,6 +909,8 @@ spec:
|
||||
ports:
|
||||
- name: pg
|
||||
containerPort: 15432
|
||||
- name: pk01-pg
|
||||
containerPort: 25432
|
||||
- name: oa
|
||||
containerPort: 4255
|
||||
- name: health
|
||||
@@ -917,7 +919,7 @@ spec:
|
||||
- name: TCP_EGRESS_HTTP_PROXY
|
||||
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
|
||||
- name: TCP_EGRESS_ROUTES
|
||||
value: "postgres=15432=74.48.78.17:15432,oa-event-flow=4255=74.48.78.17:4255"
|
||||
value: "postgres=15432=74.48.78.17:15432,pk01-postgres=25432=82.156.23.220:5432,oa-event-flow=4255=74.48.78.17:4255"
|
||||
- name: TCP_EGRESS_HEALTH_PORT
|
||||
value: "18080"
|
||||
- name: TCP_EGRESS_CONNECT_ATTEMPTS
|
||||
@@ -965,6 +967,9 @@ spec:
|
||||
- name: pg
|
||||
port: 15432
|
||||
targetPort: pg
|
||||
- name: pk01-pg
|
||||
port: 25432
|
||||
targetPort: pk01-pg
|
||||
- name: oa
|
||||
port: 4255
|
||||
targetPort: oa
|
||||
|
||||
Reference in New Issue
Block a user