@crossdelta/infrastructure 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/discover-services.d.ts +13 -10
- package/dist/index.cjs +264 -229
- package/dist/index.js +265 -230
- package/dist/runtimes/doks/types.d.ts +5 -2
- package/package.json +1 -1
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { K8sServiceConfig } from '../runtimes/doks/types';
|
|
2
2
|
/**
|
|
3
|
-
* Auto-discovers all service configurations from
|
|
4
|
-
* Each .ts file (except index.ts) should export a
|
|
3
|
+
* Auto-discovers all K8s service configurations from infra/services directory.
|
|
4
|
+
* Each .ts file (except index.ts) should export a K8sServiceConfig as default.
|
|
5
|
+
*
|
|
6
|
+
* If a config does not specify `image`, it will be auto-generated using
|
|
7
|
+
* the registry from root package.json's `pf.registry` config.
|
|
5
8
|
*
|
|
6
9
|
* @param servicesDir - Path to services directory (relative to cwd or absolute)
|
|
7
|
-
* @throws Error if duplicate ports are detected
|
|
10
|
+
* @throws Error if duplicate ports are detected or pf.registry is missing
|
|
8
11
|
*
|
|
9
12
|
* @example
|
|
10
13
|
* ```typescript
|
|
11
|
-
* //
|
|
12
|
-
* const
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* // Config without image - will use pf.registry automatically
|
|
15
|
+
* const config: K8sServiceConfig = {
|
|
16
|
+
* name: 'my-service',
|
|
17
|
+
* containerPort: 4001,
|
|
18
|
+
* }
|
|
16
19
|
* ```
|
|
17
20
|
*/
|
|
18
|
-
export declare function
|
|
21
|
+
export declare function discoverServiceConfigs(servicesDir?: string): K8sServiceConfig[];
|
package/dist/index.cjs
CHANGED
|
@@ -289067,7 +289067,7 @@ var require_lib38 = __commonJS((exports2, module2) => {
|
|
|
289067
289067
|
var require_lib39 = __commonJS((exports2, module2) => {
|
|
289068
289068
|
var fs = require("fs");
|
|
289069
289069
|
var { promisify } = require("util");
|
|
289070
|
-
var { readFileSync } = fs;
|
|
289070
|
+
var { readFileSync: readFileSync2 } = fs;
|
|
289071
289071
|
var readFile = promisify(fs.readFile);
|
|
289072
289072
|
var extractPath = (path, cmdshimContents) => {
|
|
289073
289073
|
if (/[.]cmd$/.test(path)) {
|
|
@@ -289119,7 +289119,7 @@ var require_lib39 = __commonJS((exports2, module2) => {
|
|
|
289119
289119
|
});
|
|
289120
289120
|
};
|
|
289121
289121
|
var readCmdShimSync = (path) => {
|
|
289122
|
-
const contents =
|
|
289122
|
+
const contents = readFileSync2(path);
|
|
289123
289123
|
const destination = extractPath(path, contents.toString());
|
|
289124
289124
|
if (!destination) {
|
|
289125
289125
|
throw notaShim(path);
|
|
@@ -308309,7 +308309,7 @@ var require_getImage = __commonJS((exports2) => {
|
|
|
308309
308309
|
exports2.getImageOutput = exports2.getImage = undefined;
|
|
308310
308310
|
var pulumi = require_pulumi();
|
|
308311
308311
|
var utilities = require_utilities();
|
|
308312
|
-
function
|
|
308312
|
+
function getImage2(args, opts) {
|
|
308313
308313
|
args = args || {};
|
|
308314
308314
|
opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {});
|
|
308315
308315
|
return pulumi.runtime.invoke("digitalocean:index/getImage:getImage", {
|
|
@@ -308319,7 +308319,7 @@ var require_getImage = __commonJS((exports2) => {
|
|
|
308319
308319
|
source: args.source
|
|
308320
308320
|
}, opts);
|
|
308321
308321
|
}
|
|
308322
|
-
exports2.getImage =
|
|
308322
|
+
exports2.getImage = getImage2;
|
|
308323
308323
|
function getImageOutput(args, opts) {
|
|
308324
308324
|
args = args || {};
|
|
308325
308325
|
opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {});
|
|
@@ -337015,12 +337015,12 @@ var exports_lib = {};
|
|
|
337015
337015
|
__export(exports_lib, {
|
|
337016
337016
|
ghcrImage: () => ghcrImage,
|
|
337017
337017
|
getServiceUrl: () => getServiceUrl,
|
|
337018
|
-
getServicePort: () =>
|
|
337018
|
+
getServicePort: () => getServicePort,
|
|
337019
337019
|
getImage: () => getImage,
|
|
337020
337020
|
filterByPlatform: () => filterByPlatform,
|
|
337021
337021
|
ensureDot: () => ensureDot,
|
|
337022
337022
|
dockerHubImage: () => dockerHubImage,
|
|
337023
|
-
|
|
337023
|
+
discoverServiceConfigs: () => discoverServiceConfigs,
|
|
337024
337024
|
deployNginxIngress: () => deployNginxIngress,
|
|
337025
337025
|
deployNats: () => deployNats,
|
|
337026
337026
|
deployK8sServices: () => deployK8sServices,
|
|
@@ -337081,21 +337081,67 @@ var defaultHealthCheck = {
|
|
|
337081
337081
|
// lib/helpers/discover-services.ts
|
|
337082
337082
|
var import_node_fs = require("node:fs");
|
|
337083
337083
|
var import_node_path = require("node:path");
|
|
337084
|
-
|
|
337085
|
-
|
|
337086
|
-
|
|
337087
|
-
|
|
337088
|
-
if (
|
|
337089
|
-
return
|
|
337090
|
-
|
|
337084
|
+
|
|
337085
|
+
// lib/helpers/image.ts
|
|
337086
|
+
var scopeImageTagsRaw = process.env.SCOPE_IMAGE_TAGS ?? "";
|
|
337087
|
+
var scopeImageTags = (() => {
|
|
337088
|
+
if (!scopeImageTagsRaw.trim()) {
|
|
337089
|
+
return {};
|
|
337090
|
+
}
|
|
337091
|
+
try {
|
|
337092
|
+
const parsed = JSON.parse(scopeImageTagsRaw);
|
|
337093
|
+
const tags = {};
|
|
337094
|
+
for (const [key, value] of Object.entries(parsed ?? {})) {
|
|
337095
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
337096
|
+
tags[key] = value.trim();
|
|
337097
|
+
}
|
|
337098
|
+
}
|
|
337099
|
+
return tags;
|
|
337100
|
+
} catch (error) {
|
|
337101
|
+
console.warn("Unable to parse scope image tags from environment:", error);
|
|
337102
|
+
return {};
|
|
337103
|
+
}
|
|
337104
|
+
})();
|
|
337105
|
+
var resolveImageTag = (scopeName) => {
|
|
337106
|
+
const tag = scopeImageTags[scopeName];
|
|
337107
|
+
if (!tag) {
|
|
337108
|
+
return "latest";
|
|
337109
|
+
}
|
|
337110
|
+
return tag;
|
|
337111
|
+
};
|
|
337112
|
+
var ghcrImage = (registry, serviceName) => {
|
|
337113
|
+
const tag = resolveImageTag(serviceName);
|
|
337114
|
+
return `ghcr.io/${registry}/${serviceName}:${tag}`;
|
|
337115
|
+
};
|
|
337116
|
+
var getImage = (registry, repository, registryCredentials) => {
|
|
337117
|
+
const scopeName = repository.split("/").pop();
|
|
337118
|
+
if (!scopeName) {
|
|
337119
|
+
throw new Error(`Invalid repository name: ${repository}`);
|
|
337120
|
+
}
|
|
337121
|
+
return {
|
|
337122
|
+
registryType: "GHCR",
|
|
337123
|
+
registry,
|
|
337124
|
+
repository,
|
|
337125
|
+
registryCredentials,
|
|
337126
|
+
tag: resolveImageTag(scopeName)
|
|
337127
|
+
};
|
|
337128
|
+
};
|
|
337129
|
+
|
|
337130
|
+
// lib/helpers/discover-services.ts
|
|
337131
|
+
function getRegistryFromPackageJson(workspaceRoot) {
|
|
337132
|
+
const pkgPath = import_node_path.join(workspaceRoot, "package.json");
|
|
337133
|
+
const pkg = JSON.parse(import_node_fs.readFileSync(pkgPath, "utf-8"));
|
|
337134
|
+
if (!pkg.pf?.registry) {
|
|
337135
|
+
throw new Error(`Missing "pf.registry" in ${pkgPath}. Add it to your root package.json, e.g.: "pf": { "registry": "orgname/reponame" }`);
|
|
337136
|
+
}
|
|
337137
|
+
return pkg.pf.registry;
|
|
337091
337138
|
}
|
|
337092
337139
|
function validateNoDuplicatePorts(configs) {
|
|
337093
337140
|
const portMap = new Map;
|
|
337094
337141
|
for (const config of configs) {
|
|
337095
|
-
const
|
|
337096
|
-
const existing = portMap.get(port) || [];
|
|
337142
|
+
const existing = portMap.get(config.containerPort) || [];
|
|
337097
337143
|
existing.push(config.name);
|
|
337098
|
-
portMap.set(
|
|
337144
|
+
portMap.set(config.containerPort, existing);
|
|
337099
337145
|
}
|
|
337100
337146
|
const conflicts = [...portMap.entries()].filter(([, services]) => services.length > 1).map(([port, services]) => `Port ${port}: ${services.join(", ")}`);
|
|
337101
337147
|
if (conflicts.length > 0) {
|
|
@@ -337104,13 +337150,22 @@ ${conflicts.join(`
|
|
|
337104
337150
|
`)}`);
|
|
337105
337151
|
}
|
|
337106
337152
|
}
|
|
337107
|
-
function
|
|
337153
|
+
function discoverServiceConfigs(servicesDir = "infra/services") {
|
|
337108
337154
|
const resolvedDir = import_node_path.isAbsolute(servicesDir) ? servicesDir : import_node_path.resolve(process.cwd(), servicesDir);
|
|
337155
|
+
const workspaceRoot = import_node_path.resolve(resolvedDir, "..", "..");
|
|
337156
|
+
const registry = getRegistryFromPackageJson(workspaceRoot);
|
|
337109
337157
|
const files = import_node_fs.readdirSync(resolvedDir).filter((file) => file.endsWith(".ts") && file !== "index.ts");
|
|
337110
337158
|
const configs = files.map((file) => {
|
|
337111
337159
|
const filePath = import_node_path.join(resolvedDir, file);
|
|
337112
337160
|
const module2 = require(filePath);
|
|
337113
|
-
|
|
337161
|
+
const config = module2.default ?? module2;
|
|
337162
|
+
if (!config.image) {
|
|
337163
|
+
return {
|
|
337164
|
+
...config,
|
|
337165
|
+
image: ghcrImage(registry, config.name)
|
|
337166
|
+
};
|
|
337167
|
+
}
|
|
337168
|
+
return config;
|
|
337114
337169
|
});
|
|
337115
337170
|
validateNoDuplicatePorts(configs);
|
|
337116
337171
|
return configs;
|
|
@@ -337338,50 +337393,6 @@ function buildDropletServices(options) {
|
|
|
337338
337393
|
function filterByPlatform(configs, platform) {
|
|
337339
337394
|
return configs.filter((c) => (c.platform || "app-platform") === platform);
|
|
337340
337395
|
}
|
|
337341
|
-
// lib/helpers/image.ts
|
|
337342
|
-
var scopeImageTagsRaw = process.env.SCOPE_IMAGE_TAGS ?? "";
|
|
337343
|
-
var scopeImageTags = (() => {
|
|
337344
|
-
if (!scopeImageTagsRaw.trim()) {
|
|
337345
|
-
return {};
|
|
337346
|
-
}
|
|
337347
|
-
try {
|
|
337348
|
-
const parsed = JSON.parse(scopeImageTagsRaw);
|
|
337349
|
-
const tags = {};
|
|
337350
|
-
for (const [key, value] of Object.entries(parsed ?? {})) {
|
|
337351
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
337352
|
-
tags[key] = value.trim();
|
|
337353
|
-
}
|
|
337354
|
-
}
|
|
337355
|
-
return tags;
|
|
337356
|
-
} catch (error) {
|
|
337357
|
-
console.warn("Unable to parse scope image tags from environment:", error);
|
|
337358
|
-
return {};
|
|
337359
|
-
}
|
|
337360
|
-
})();
|
|
337361
|
-
var resolveImageTag = (scopeName) => {
|
|
337362
|
-
const tag = scopeImageTags[scopeName];
|
|
337363
|
-
if (!tag) {
|
|
337364
|
-
return "latest";
|
|
337365
|
-
}
|
|
337366
|
-
return tag;
|
|
337367
|
-
};
|
|
337368
|
-
var ghcrImage = (registry, serviceName) => {
|
|
337369
|
-
const tag = resolveImageTag(serviceName);
|
|
337370
|
-
return `ghcr.io/${registry}/${serviceName}:${tag}`;
|
|
337371
|
-
};
|
|
337372
|
-
var getImage = (registry, repository, registryCredentials) => {
|
|
337373
|
-
const scopeName = repository.split("/").pop();
|
|
337374
|
-
if (!scopeName) {
|
|
337375
|
-
throw new Error(`Invalid repository name: ${repository}`);
|
|
337376
|
-
}
|
|
337377
|
-
return {
|
|
337378
|
-
registryType: "GHCR",
|
|
337379
|
-
registry,
|
|
337380
|
-
repository,
|
|
337381
|
-
registryCredentials,
|
|
337382
|
-
tag: resolveImageTag(scopeName)
|
|
337383
|
-
};
|
|
337384
|
-
};
|
|
337385
337396
|
// lib/helpers/service-builder.ts
|
|
337386
337397
|
function buildServices(options) {
|
|
337387
337398
|
const { serviceConfigs, registryCredentials, logtailToken, registry } = options;
|
|
@@ -337426,7 +337437,7 @@ function buildIngressRules(serviceConfigs) {
|
|
|
337426
337437
|
}
|
|
337427
337438
|
// lib/helpers/service-runtime.ts
|
|
337428
337439
|
var toEnvKey = (name) => name.toUpperCase().replace(/-/g, "_");
|
|
337429
|
-
function
|
|
337440
|
+
function getServicePort(serviceName, defaultPort = 8080) {
|
|
337430
337441
|
const envKey = `${toEnvKey(serviceName)}_PORT`;
|
|
337431
337442
|
const envValue = process.env[envKey];
|
|
337432
337443
|
if (envValue) {
|
|
@@ -337442,7 +337453,7 @@ function getServiceUrl(serviceName) {
|
|
|
337442
337453
|
return process.env[envKey];
|
|
337443
337454
|
}
|
|
337444
337455
|
// lib/helpers/service-urls.ts
|
|
337445
|
-
function
|
|
337456
|
+
function getServicePort2(config) {
|
|
337446
337457
|
if (config.httpPort)
|
|
337447
337458
|
return config.httpPort;
|
|
337448
337459
|
const internalPorts = config.internalPorts;
|
|
@@ -337452,7 +337463,7 @@ function getServicePort3(config) {
|
|
|
337452
337463
|
}
|
|
337453
337464
|
function buildInternalUrls(serviceConfigs) {
|
|
337454
337465
|
return Object.fromEntries(serviceConfigs.map((config) => {
|
|
337455
|
-
const url = config.internalUrl ?? `http://${config.name}:${
|
|
337466
|
+
const url = config.internalUrl ?? `http://${config.name}:${getServicePort2(config)}`;
|
|
337456
337467
|
return [config.name, url];
|
|
337457
337468
|
}));
|
|
337458
337469
|
}
|
|
@@ -337464,7 +337475,7 @@ function buildExternalUrls(serviceConfigs, baseUrl) {
|
|
|
337464
337475
|
}
|
|
337465
337476
|
function buildLocalUrls(serviceConfigs) {
|
|
337466
337477
|
return Object.fromEntries(serviceConfigs.map((config) => {
|
|
337467
|
-
const port =
|
|
337478
|
+
const port = getServicePort2(config);
|
|
337468
337479
|
return [config.name, `http://localhost:${port}`];
|
|
337469
337480
|
}));
|
|
337470
337481
|
}
|
|
@@ -337472,14 +337483,14 @@ function buildServiceUrlEnvs(serviceConfigs) {
|
|
|
337472
337483
|
return serviceConfigs.map((config) => ({
|
|
337473
337484
|
key: `${config.name.toUpperCase().replace(/-/g, "_")}_URL`,
|
|
337474
337485
|
scope: "RUN_TIME",
|
|
337475
|
-
value: config.internalUrl ?? `http://${config.name}:${
|
|
337486
|
+
value: config.internalUrl ?? `http://${config.name}:${getServicePort2(config)}`
|
|
337476
337487
|
}));
|
|
337477
337488
|
}
|
|
337478
337489
|
function buildServicePortEnvs(serviceConfigs) {
|
|
337479
337490
|
return serviceConfigs.map((config) => ({
|
|
337480
337491
|
key: `${config.name.toUpperCase().replace(/-/g, "_")}_PORT`,
|
|
337481
337492
|
scope: "RUN_TIME",
|
|
337482
|
-
value: String(
|
|
337493
|
+
value: String(getServicePort2(config))
|
|
337483
337494
|
}));
|
|
337484
337495
|
}
|
|
337485
337496
|
// lib/runtimes/doks/cert-manager.ts
|
|
@@ -337844,10 +337855,7 @@ function getImagePullPolicy(image2, explicit) {
|
|
|
337844
337855
|
return explicit;
|
|
337845
337856
|
return image2.endsWith(":latest") ? "Always" : "IfNotPresent";
|
|
337846
337857
|
}
|
|
337847
|
-
function
|
|
337848
|
-
const labels = buildLabels(config2.name, config2.labels);
|
|
337849
|
-
const replicas = config2.replicas ?? DEFAULTS.replicas;
|
|
337850
|
-
const imagePullPolicy = getImagePullPolicy(config2.image, config2.imagePullPolicy);
|
|
337858
|
+
function buildEnvVars(config2) {
|
|
337851
337859
|
const envVars = [];
|
|
337852
337860
|
envVars.push({ name: "PORT", value: String(config2.containerPort) });
|
|
337853
337861
|
if (config2.env) {
|
|
@@ -337855,17 +337863,7 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337855
337863
|
envVars.push({ name: key, value: pulumi6.output(value) });
|
|
337856
337864
|
}
|
|
337857
337865
|
}
|
|
337858
|
-
|
|
337859
|
-
if (config2.secrets && Object.keys(config2.secrets).length > 0) {
|
|
337860
|
-
secret = new k8s5.core.v1.Secret(`${config2.name}-secret`, {
|
|
337861
|
-
metadata: {
|
|
337862
|
-
name: `${config2.name}-secret`,
|
|
337863
|
-
namespace,
|
|
337864
|
-
labels
|
|
337865
|
-
},
|
|
337866
|
-
type: "Opaque",
|
|
337867
|
-
stringData: config2.secrets
|
|
337868
|
-
}, { provider });
|
|
337866
|
+
if (config2.secrets) {
|
|
337869
337867
|
for (const key of Object.keys(config2.secrets)) {
|
|
337870
337868
|
envVars.push({
|
|
337871
337869
|
name: key,
|
|
@@ -337878,80 +337876,205 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337878
337876
|
});
|
|
337879
337877
|
}
|
|
337880
337878
|
}
|
|
337879
|
+
return envVars;
|
|
337880
|
+
}
|
|
337881
|
+
function createServiceSecret(provider, namespace, config2, labels) {
|
|
337882
|
+
if (!config2.secrets || Object.keys(config2.secrets).length === 0) {
|
|
337883
|
+
return;
|
|
337884
|
+
}
|
|
337885
|
+
return new k8s5.core.v1.Secret(`${config2.name}-secret`, {
|
|
337886
|
+
metadata: {
|
|
337887
|
+
name: `${config2.name}-secret`,
|
|
337888
|
+
namespace,
|
|
337889
|
+
labels
|
|
337890
|
+
},
|
|
337891
|
+
type: "Opaque",
|
|
337892
|
+
stringData: config2.secrets
|
|
337893
|
+
}, { provider });
|
|
337894
|
+
}
|
|
337895
|
+
function createServiceVolumes(provider, namespace, config2, labels) {
|
|
337881
337896
|
const pvcs = [];
|
|
337882
337897
|
const volumeMounts = [];
|
|
337883
337898
|
const volumes = [];
|
|
337884
|
-
if (config2.volumes) {
|
|
337885
|
-
|
|
337886
|
-
|
|
337887
|
-
|
|
337888
|
-
|
|
337889
|
-
|
|
337890
|
-
|
|
337891
|
-
|
|
337892
|
-
|
|
337893
|
-
|
|
337894
|
-
|
|
337895
|
-
|
|
337896
|
-
|
|
337897
|
-
|
|
337898
|
-
|
|
337899
|
-
}
|
|
337900
|
-
}
|
|
337901
|
-
}, { provider });
|
|
337902
|
-
pvcs.push(pvc);
|
|
337903
|
-
volumeMounts.push({
|
|
337904
|
-
name: vol.name,
|
|
337905
|
-
mountPath: vol.mountPath,
|
|
337906
|
-
readOnly: vol.readOnly
|
|
337907
|
-
});
|
|
337908
|
-
volumes.push({
|
|
337909
|
-
name: vol.name,
|
|
337910
|
-
persistentVolumeClaim: {
|
|
337911
|
-
claimName: `${config2.name}-${vol.name}`
|
|
337899
|
+
if (!config2.volumes) {
|
|
337900
|
+
return { pvcs, volumeMounts, volumes };
|
|
337901
|
+
}
|
|
337902
|
+
for (const vol of config2.volumes) {
|
|
337903
|
+
const pvc = new k8s5.core.v1.PersistentVolumeClaim(`${config2.name}-${vol.name}`, {
|
|
337904
|
+
metadata: {
|
|
337905
|
+
name: `${config2.name}-${vol.name}`,
|
|
337906
|
+
namespace,
|
|
337907
|
+
labels
|
|
337908
|
+
},
|
|
337909
|
+
spec: {
|
|
337910
|
+
accessModes: [vol.accessMode ?? "ReadWriteOnce"],
|
|
337911
|
+
storageClassName: vol.storageClass ?? "do-block-storage",
|
|
337912
|
+
resources: {
|
|
337913
|
+
requests: { storage: vol.size ?? "10Gi" }
|
|
337912
337914
|
}
|
|
337913
|
-
}
|
|
337914
|
-
}
|
|
337915
|
+
}
|
|
337916
|
+
}, { provider });
|
|
337917
|
+
pvcs.push(pvc);
|
|
337918
|
+
volumeMounts.push({
|
|
337919
|
+
name: vol.name,
|
|
337920
|
+
mountPath: vol.mountPath,
|
|
337921
|
+
readOnly: vol.readOnly
|
|
337922
|
+
});
|
|
337923
|
+
volumes.push({
|
|
337924
|
+
name: vol.name,
|
|
337925
|
+
persistentVolumeClaim: {
|
|
337926
|
+
claimName: `${config2.name}-${vol.name}`
|
|
337927
|
+
}
|
|
337928
|
+
});
|
|
337915
337929
|
}
|
|
337930
|
+
return { pvcs, volumeMounts, volumes };
|
|
337931
|
+
}
|
|
337932
|
+
function buildHealthProbes(config2) {
|
|
337916
337933
|
const healthCheck = config2.healthCheck;
|
|
337917
|
-
|
|
337918
|
-
|
|
337919
|
-
if (healthCheck) {
|
|
337920
|
-
const probeConfig = {
|
|
337921
|
-
initialDelaySeconds: healthCheck.initialDelaySeconds ?? DEFAULTS.healthCheck.initialDelaySeconds,
|
|
337922
|
-
periodSeconds: healthCheck.periodSeconds ?? DEFAULTS.healthCheck.periodSeconds,
|
|
337923
|
-
failureThreshold: healthCheck.failureThreshold ?? DEFAULTS.healthCheck.failureThreshold,
|
|
337924
|
-
successThreshold: healthCheck.successThreshold ?? DEFAULTS.healthCheck.successThreshold,
|
|
337925
|
-
timeoutSeconds: healthCheck.timeoutSeconds ?? DEFAULTS.healthCheck.timeoutSeconds
|
|
337926
|
-
};
|
|
337927
|
-
if (healthCheck.httpPath) {
|
|
337928
|
-
const httpGet = {
|
|
337929
|
-
path: healthCheck.httpPath,
|
|
337930
|
-
port: healthCheck.port ?? config2.containerPort
|
|
337931
|
-
};
|
|
337932
|
-
livenessProbe = { ...probeConfig, httpGet };
|
|
337933
|
-
readinessProbe = { ...probeConfig, httpGet };
|
|
337934
|
-
} else {
|
|
337935
|
-
const tcpSocket = {
|
|
337936
|
-
port: healthCheck.port ?? config2.containerPort
|
|
337937
|
-
};
|
|
337938
|
-
livenessProbe = { ...probeConfig, tcpSocket };
|
|
337939
|
-
readinessProbe = { ...probeConfig, tcpSocket };
|
|
337940
|
-
}
|
|
337934
|
+
if (!healthCheck) {
|
|
337935
|
+
return {};
|
|
337941
337936
|
}
|
|
337942
|
-
const
|
|
337943
|
-
|
|
337937
|
+
const probeConfig = {
|
|
337938
|
+
initialDelaySeconds: healthCheck.initialDelaySeconds ?? DEFAULTS.healthCheck.initialDelaySeconds,
|
|
337939
|
+
periodSeconds: healthCheck.periodSeconds ?? DEFAULTS.healthCheck.periodSeconds,
|
|
337940
|
+
failureThreshold: healthCheck.failureThreshold ?? DEFAULTS.healthCheck.failureThreshold,
|
|
337941
|
+
successThreshold: healthCheck.successThreshold ?? DEFAULTS.healthCheck.successThreshold,
|
|
337942
|
+
timeoutSeconds: healthCheck.timeoutSeconds ?? DEFAULTS.healthCheck.timeoutSeconds
|
|
337943
|
+
};
|
|
337944
|
+
if (healthCheck.httpPath) {
|
|
337945
|
+
const httpGet = {
|
|
337946
|
+
path: healthCheck.httpPath,
|
|
337947
|
+
port: healthCheck.port ?? config2.containerPort
|
|
337948
|
+
};
|
|
337949
|
+
return {
|
|
337950
|
+
livenessProbe: { ...probeConfig, httpGet },
|
|
337951
|
+
readinessProbe: { ...probeConfig, httpGet }
|
|
337952
|
+
};
|
|
337953
|
+
}
|
|
337954
|
+
const tcpSocket = { port: healthCheck.port ?? config2.containerPort };
|
|
337955
|
+
return {
|
|
337956
|
+
livenessProbe: { ...probeConfig, tcpSocket },
|
|
337957
|
+
readinessProbe: { ...probeConfig, tcpSocket }
|
|
337958
|
+
};
|
|
337959
|
+
}
|
|
337960
|
+
function buildContainerPorts(config2) {
|
|
337961
|
+
const ports = [
|
|
337944
337962
|
{ containerPort: config2.containerPort, name: "http" }
|
|
337945
337963
|
];
|
|
337946
337964
|
if (config2.additionalPorts) {
|
|
337947
337965
|
for (const port of config2.additionalPorts) {
|
|
337948
|
-
|
|
337966
|
+
ports.push({
|
|
337949
337967
|
containerPort: port.targetPort ?? port.port,
|
|
337950
337968
|
name: port.name,
|
|
337951
337969
|
protocol: port.protocol ?? "TCP"
|
|
337952
337970
|
});
|
|
337953
337971
|
}
|
|
337954
337972
|
}
|
|
337973
|
+
return ports;
|
|
337974
|
+
}
|
|
337975
|
+
function buildServicePorts(config2) {
|
|
337976
|
+
const ports = [
|
|
337977
|
+
{
|
|
337978
|
+
name: "http",
|
|
337979
|
+
port: config2.containerPort,
|
|
337980
|
+
targetPort: config2.containerPort,
|
|
337981
|
+
protocol: "TCP"
|
|
337982
|
+
}
|
|
337983
|
+
];
|
|
337984
|
+
if (config2.additionalPorts) {
|
|
337985
|
+
for (const port of config2.additionalPorts) {
|
|
337986
|
+
ports.push({
|
|
337987
|
+
name: port.name,
|
|
337988
|
+
port: port.port,
|
|
337989
|
+
targetPort: port.targetPort ?? port.port,
|
|
337990
|
+
protocol: port.protocol ?? "TCP"
|
|
337991
|
+
});
|
|
337992
|
+
}
|
|
337993
|
+
}
|
|
337994
|
+
return ports;
|
|
337995
|
+
}
|
|
337996
|
+
function createServiceIngress(provider, namespace, config2, labels, service) {
|
|
337997
|
+
if (!config2.ingress) {
|
|
337998
|
+
return;
|
|
337999
|
+
}
|
|
338000
|
+
const ingressAnnotations = {
|
|
338001
|
+
"kubernetes.io/ingress.class": "nginx",
|
|
338002
|
+
...config2.ingress.annotations
|
|
338003
|
+
};
|
|
338004
|
+
if (config2.ingress.tls?.enabled) {
|
|
338005
|
+
ingressAnnotations["cert-manager.io/cluster-issuer"] = config2.ingress.tls.issuerName ?? "letsencrypt-production";
|
|
338006
|
+
}
|
|
338007
|
+
let ingressPath = config2.ingress.path;
|
|
338008
|
+
let ingressPathType = config2.ingress.pathType ?? "Prefix";
|
|
338009
|
+
const shouldStripPrefix = config2.ingress.path !== "/" && !config2.ingress.keepPrefix;
|
|
338010
|
+
if (shouldStripPrefix) {
|
|
338011
|
+
ingressPath = `${config2.ingress.path}(/|$)(.*)`;
|
|
338012
|
+
ingressPathType = "ImplementationSpecific";
|
|
338013
|
+
ingressAnnotations["nginx.ingress.kubernetes.io/use-regex"] = "true";
|
|
338014
|
+
ingressAnnotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$2";
|
|
338015
|
+
}
|
|
338016
|
+
const createRule = (host) => ({
|
|
338017
|
+
...host && { host },
|
|
338018
|
+
http: {
|
|
338019
|
+
paths: [
|
|
338020
|
+
{
|
|
338021
|
+
path: ingressPath,
|
|
338022
|
+
pathType: ingressPathType,
|
|
338023
|
+
backend: {
|
|
338024
|
+
service: {
|
|
338025
|
+
name: config2.name,
|
|
338026
|
+
port: { number: config2.containerPort }
|
|
338027
|
+
}
|
|
338028
|
+
}
|
|
338029
|
+
}
|
|
338030
|
+
]
|
|
338031
|
+
}
|
|
338032
|
+
});
|
|
338033
|
+
const ingressRules = [];
|
|
338034
|
+
if (config2.ingress.host) {
|
|
338035
|
+
ingressRules.push(createRule(config2.ingress.host));
|
|
338036
|
+
} else {
|
|
338037
|
+
ingressRules.push(createRule());
|
|
338038
|
+
}
|
|
338039
|
+
if (config2.ingress.additionalHosts) {
|
|
338040
|
+
for (const additionalHost of config2.ingress.additionalHosts) {
|
|
338041
|
+
ingressRules.push(createRule(additionalHost));
|
|
338042
|
+
}
|
|
338043
|
+
}
|
|
338044
|
+
const allHosts = [
|
|
338045
|
+
...config2.ingress.host ? [config2.ingress.host] : [],
|
|
338046
|
+
...config2.ingress.additionalHosts ?? []
|
|
338047
|
+
];
|
|
338048
|
+
const tlsSecretName = config2.ingress.tls?.secretName ?? `${config2.name}-tls`;
|
|
338049
|
+
return new k8s5.networking.v1.Ingress(`${config2.name}-ingress`, {
|
|
338050
|
+
metadata: {
|
|
338051
|
+
name: config2.name,
|
|
338052
|
+
namespace,
|
|
338053
|
+
labels,
|
|
338054
|
+
annotations: ingressAnnotations
|
|
338055
|
+
},
|
|
338056
|
+
spec: {
|
|
338057
|
+
...config2.ingress.tls?.enabled && allHosts.length > 0 && {
|
|
338058
|
+
tls: [{ hosts: allHosts, secretName: tlsSecretName }]
|
|
338059
|
+
},
|
|
338060
|
+
rules: ingressRules
|
|
338061
|
+
}
|
|
338062
|
+
}, { provider, dependsOn: [service] });
|
|
338063
|
+
}
|
|
338064
|
+
function deployK8sService(provider, namespace, config2) {
|
|
338065
|
+
if (!config2.image) {
|
|
338066
|
+
throw new Error(`Missing "image" for service "${config2.name}". Either specify image explicitly or use discoverServiceConfigs() which auto-generates it from pf.registry.`);
|
|
338067
|
+
}
|
|
338068
|
+
const labels = buildLabels(config2.name, config2.labels);
|
|
338069
|
+
const replicas = config2.replicas ?? DEFAULTS.replicas;
|
|
338070
|
+
const imagePullPolicy = getImagePullPolicy(config2.image, config2.imagePullPolicy);
|
|
338071
|
+
const resources = config2.resources ?? DEFAULTS.resources;
|
|
338072
|
+
const secret = createServiceSecret(provider, namespace, config2, labels);
|
|
338073
|
+
const envVars = buildEnvVars(config2);
|
|
338074
|
+
const { pvcs, volumeMounts, volumes } = createServiceVolumes(provider, namespace, config2, labels);
|
|
338075
|
+
const { livenessProbe, readinessProbe } = buildHealthProbes(config2);
|
|
338076
|
+
const containerPorts = buildContainerPorts(config2);
|
|
338077
|
+
const servicePorts = buildServicePorts(config2);
|
|
337955
338078
|
const deployment = new k8s5.apps.v1.Deployment(`${config2.name}-deployment`, {
|
|
337956
338079
|
metadata: {
|
|
337957
338080
|
name: config2.name,
|
|
@@ -337993,24 +338116,6 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337993
338116
|
}
|
|
337994
338117
|
}
|
|
337995
338118
|
}, { provider, dependsOn: pvcs.length > 0 ? pvcs : undefined });
|
|
337996
|
-
const servicePorts = [
|
|
337997
|
-
{
|
|
337998
|
-
name: "http",
|
|
337999
|
-
port: config2.containerPort,
|
|
338000
|
-
targetPort: config2.containerPort,
|
|
338001
|
-
protocol: "TCP"
|
|
338002
|
-
}
|
|
338003
|
-
];
|
|
338004
|
-
if (config2.additionalPorts) {
|
|
338005
|
-
for (const port of config2.additionalPorts) {
|
|
338006
|
-
servicePorts.push({
|
|
338007
|
-
name: port.name,
|
|
338008
|
-
port: port.port,
|
|
338009
|
-
targetPort: port.targetPort ?? port.port,
|
|
338010
|
-
protocol: port.protocol ?? "TCP"
|
|
338011
|
-
});
|
|
338012
|
-
}
|
|
338013
|
-
}
|
|
338014
338119
|
const service = new k8s5.core.v1.Service(`${config2.name}-service`, {
|
|
338015
338120
|
metadata: {
|
|
338016
338121
|
name: config2.name,
|
|
@@ -338023,77 +338128,7 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
338023
338128
|
ports: servicePorts
|
|
338024
338129
|
}
|
|
338025
338130
|
}, { provider, dependsOn: [deployment] });
|
|
338026
|
-
|
|
338027
|
-
if (config2.ingress) {
|
|
338028
|
-
const ingressAnnotations = {
|
|
338029
|
-
"kubernetes.io/ingress.class": "nginx",
|
|
338030
|
-
...config2.ingress.annotations
|
|
338031
|
-
};
|
|
338032
|
-
if (config2.ingress.tls?.enabled) {
|
|
338033
|
-
ingressAnnotations["cert-manager.io/cluster-issuer"] = config2.ingress.tls.issuerName ?? "letsencrypt-production";
|
|
338034
|
-
}
|
|
338035
|
-
let ingressPath = config2.ingress.path;
|
|
338036
|
-
let ingressPathType = config2.ingress.pathType ?? "Prefix";
|
|
338037
|
-
const shouldStripPrefix = config2.ingress.path !== "/" && !config2.ingress.keepPrefix;
|
|
338038
|
-
if (shouldStripPrefix) {
|
|
338039
|
-
ingressPath = `${config2.ingress.path}(/|$)(.*)`;
|
|
338040
|
-
ingressPathType = "ImplementationSpecific";
|
|
338041
|
-
ingressAnnotations["nginx.ingress.kubernetes.io/use-regex"] = "true";
|
|
338042
|
-
ingressAnnotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$2";
|
|
338043
|
-
}
|
|
338044
|
-
const tlsSecretName = config2.ingress.tls?.secretName ?? `${config2.name}-tls`;
|
|
338045
|
-
const ingressRules = [];
|
|
338046
|
-
const createRule = (host) => ({
|
|
338047
|
-
...host && { host },
|
|
338048
|
-
http: {
|
|
338049
|
-
paths: [
|
|
338050
|
-
{
|
|
338051
|
-
path: ingressPath,
|
|
338052
|
-
pathType: ingressPathType,
|
|
338053
|
-
backend: {
|
|
338054
|
-
service: {
|
|
338055
|
-
name: config2.name,
|
|
338056
|
-
port: { number: config2.containerPort }
|
|
338057
|
-
}
|
|
338058
|
-
}
|
|
338059
|
-
}
|
|
338060
|
-
]
|
|
338061
|
-
}
|
|
338062
|
-
});
|
|
338063
|
-
if (config2.ingress.host) {
|
|
338064
|
-
ingressRules.push(createRule(config2.ingress.host));
|
|
338065
|
-
} else {
|
|
338066
|
-
ingressRules.push(createRule());
|
|
338067
|
-
}
|
|
338068
|
-
if (config2.ingress.additionalHosts) {
|
|
338069
|
-
for (const additionalHost of config2.ingress.additionalHosts) {
|
|
338070
|
-
ingressRules.push(createRule(additionalHost));
|
|
338071
|
-
}
|
|
338072
|
-
}
|
|
338073
|
-
const allHosts = [
|
|
338074
|
-
...config2.ingress.host ? [config2.ingress.host] : [],
|
|
338075
|
-
...config2.ingress.additionalHosts ?? []
|
|
338076
|
-
];
|
|
338077
|
-
ingress = new k8s5.networking.v1.Ingress(`${config2.name}-ingress`, {
|
|
338078
|
-
metadata: {
|
|
338079
|
-
name: config2.name,
|
|
338080
|
-
namespace,
|
|
338081
|
-
labels,
|
|
338082
|
-
annotations: ingressAnnotations
|
|
338083
|
-
},
|
|
338084
|
-
spec: {
|
|
338085
|
-
...config2.ingress.tls?.enabled && allHosts.length > 0 && {
|
|
338086
|
-
tls: [
|
|
338087
|
-
{
|
|
338088
|
-
hosts: allHosts,
|
|
338089
|
-
secretName: tlsSecretName
|
|
338090
|
-
}
|
|
338091
|
-
]
|
|
338092
|
-
},
|
|
338093
|
-
rules: ingressRules
|
|
338094
|
-
}
|
|
338095
|
-
}, { provider, dependsOn: [service] });
|
|
338096
|
-
}
|
|
338131
|
+
const ingress = createServiceIngress(provider, namespace, config2, labels, service);
|
|
338097
338132
|
const serviceDns = `${config2.name}.${namespace}.svc.cluster.local`;
|
|
338098
338133
|
const internalUrl = pulumi6.output(`http://${serviceDns}:${config2.containerPort}`);
|
|
338099
338134
|
return {
|
package/dist/index.js
CHANGED
|
@@ -289030,7 +289030,7 @@ var require_lib38 = __commonJS((exports, module) => {
|
|
|
289030
289030
|
var require_lib39 = __commonJS((exports, module) => {
|
|
289031
289031
|
var fs = __require("fs");
|
|
289032
289032
|
var { promisify } = __require("util");
|
|
289033
|
-
var { readFileSync } = fs;
|
|
289033
|
+
var { readFileSync: readFileSync2 } = fs;
|
|
289034
289034
|
var readFile = promisify(fs.readFile);
|
|
289035
289035
|
var extractPath = (path, cmdshimContents) => {
|
|
289036
289036
|
if (/[.]cmd$/.test(path)) {
|
|
@@ -289082,7 +289082,7 @@ var require_lib39 = __commonJS((exports, module) => {
|
|
|
289082
289082
|
});
|
|
289083
289083
|
};
|
|
289084
289084
|
var readCmdShimSync = (path) => {
|
|
289085
|
-
const contents =
|
|
289085
|
+
const contents = readFileSync2(path);
|
|
289086
289086
|
const destination = extractPath(path, contents.toString());
|
|
289087
289087
|
if (!destination) {
|
|
289088
289088
|
throw notaShim(path);
|
|
@@ -308272,7 +308272,7 @@ var require_getImage = __commonJS((exports) => {
|
|
|
308272
308272
|
exports.getImageOutput = exports.getImage = undefined;
|
|
308273
308273
|
var pulumi = require_pulumi();
|
|
308274
308274
|
var utilities = require_utilities();
|
|
308275
|
-
function
|
|
308275
|
+
function getImage2(args, opts) {
|
|
308276
308276
|
args = args || {};
|
|
308277
308277
|
opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {});
|
|
308278
308278
|
return pulumi.runtime.invoke("digitalocean:index/getImage:getImage", {
|
|
@@ -308282,7 +308282,7 @@ var require_getImage = __commonJS((exports) => {
|
|
|
308282
308282
|
source: args.source
|
|
308283
308283
|
}, opts);
|
|
308284
308284
|
}
|
|
308285
|
-
exports.getImage =
|
|
308285
|
+
exports.getImage = getImage2;
|
|
308286
308286
|
function getImageOutput(args, opts) {
|
|
308287
308287
|
args = args || {};
|
|
308288
308288
|
opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {});
|
|
@@ -337003,23 +337003,69 @@ var defaultHealthCheck = {
|
|
|
337003
337003
|
httpPath: "/health"
|
|
337004
337004
|
};
|
|
337005
337005
|
// lib/helpers/discover-services.ts
|
|
337006
|
-
import { readdirSync } from "node:fs";
|
|
337006
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
337007
337007
|
import { isAbsolute, join, resolve } from "node:path";
|
|
337008
|
-
|
|
337009
|
-
|
|
337010
|
-
|
|
337011
|
-
|
|
337012
|
-
if (
|
|
337013
|
-
return
|
|
337014
|
-
|
|
337008
|
+
|
|
337009
|
+
// lib/helpers/image.ts
|
|
337010
|
+
var scopeImageTagsRaw = process.env.SCOPE_IMAGE_TAGS ?? "";
|
|
337011
|
+
var scopeImageTags = (() => {
|
|
337012
|
+
if (!scopeImageTagsRaw.trim()) {
|
|
337013
|
+
return {};
|
|
337014
|
+
}
|
|
337015
|
+
try {
|
|
337016
|
+
const parsed = JSON.parse(scopeImageTagsRaw);
|
|
337017
|
+
const tags = {};
|
|
337018
|
+
for (const [key, value] of Object.entries(parsed ?? {})) {
|
|
337019
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
337020
|
+
tags[key] = value.trim();
|
|
337021
|
+
}
|
|
337022
|
+
}
|
|
337023
|
+
return tags;
|
|
337024
|
+
} catch (error) {
|
|
337025
|
+
console.warn("Unable to parse scope image tags from environment:", error);
|
|
337026
|
+
return {};
|
|
337027
|
+
}
|
|
337028
|
+
})();
|
|
337029
|
+
var resolveImageTag = (scopeName) => {
|
|
337030
|
+
const tag = scopeImageTags[scopeName];
|
|
337031
|
+
if (!tag) {
|
|
337032
|
+
return "latest";
|
|
337033
|
+
}
|
|
337034
|
+
return tag;
|
|
337035
|
+
};
|
|
337036
|
+
var ghcrImage = (registry, serviceName) => {
|
|
337037
|
+
const tag = resolveImageTag(serviceName);
|
|
337038
|
+
return `ghcr.io/${registry}/${serviceName}:${tag}`;
|
|
337039
|
+
};
|
|
337040
|
+
var getImage = (registry, repository, registryCredentials) => {
|
|
337041
|
+
const scopeName = repository.split("/").pop();
|
|
337042
|
+
if (!scopeName) {
|
|
337043
|
+
throw new Error(`Invalid repository name: ${repository}`);
|
|
337044
|
+
}
|
|
337045
|
+
return {
|
|
337046
|
+
registryType: "GHCR",
|
|
337047
|
+
registry,
|
|
337048
|
+
repository,
|
|
337049
|
+
registryCredentials,
|
|
337050
|
+
tag: resolveImageTag(scopeName)
|
|
337051
|
+
};
|
|
337052
|
+
};
|
|
337053
|
+
|
|
337054
|
+
// lib/helpers/discover-services.ts
|
|
337055
|
+
function getRegistryFromPackageJson(workspaceRoot) {
|
|
337056
|
+
const pkgPath = join(workspaceRoot, "package.json");
|
|
337057
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
337058
|
+
if (!pkg.pf?.registry) {
|
|
337059
|
+
throw new Error(`Missing "pf.registry" in ${pkgPath}. Add it to your root package.json, e.g.: "pf": { "registry": "orgname/reponame" }`);
|
|
337060
|
+
}
|
|
337061
|
+
return pkg.pf.registry;
|
|
337015
337062
|
}
|
|
337016
337063
|
function validateNoDuplicatePorts(configs) {
|
|
337017
337064
|
const portMap = new Map;
|
|
337018
337065
|
for (const config of configs) {
|
|
337019
|
-
const
|
|
337020
|
-
const existing = portMap.get(port) || [];
|
|
337066
|
+
const existing = portMap.get(config.containerPort) || [];
|
|
337021
337067
|
existing.push(config.name);
|
|
337022
|
-
portMap.set(
|
|
337068
|
+
portMap.set(config.containerPort, existing);
|
|
337023
337069
|
}
|
|
337024
337070
|
const conflicts = [...portMap.entries()].filter(([, services]) => services.length > 1).map(([port, services]) => `Port ${port}: ${services.join(", ")}`);
|
|
337025
337071
|
if (conflicts.length > 0) {
|
|
@@ -337028,13 +337074,22 @@ ${conflicts.join(`
|
|
|
337028
337074
|
`)}`);
|
|
337029
337075
|
}
|
|
337030
337076
|
}
|
|
337031
|
-
function
|
|
337077
|
+
function discoverServiceConfigs(servicesDir = "infra/services") {
|
|
337032
337078
|
const resolvedDir = isAbsolute(servicesDir) ? servicesDir : resolve(process.cwd(), servicesDir);
|
|
337079
|
+
const workspaceRoot = resolve(resolvedDir, "..", "..");
|
|
337080
|
+
const registry = getRegistryFromPackageJson(workspaceRoot);
|
|
337033
337081
|
const files = readdirSync(resolvedDir).filter((file) => file.endsWith(".ts") && file !== "index.ts");
|
|
337034
337082
|
const configs = files.map((file) => {
|
|
337035
337083
|
const filePath = join(resolvedDir, file);
|
|
337036
337084
|
const module = __require(filePath);
|
|
337037
|
-
|
|
337085
|
+
const config = module.default ?? module;
|
|
337086
|
+
if (!config.image) {
|
|
337087
|
+
return {
|
|
337088
|
+
...config,
|
|
337089
|
+
image: ghcrImage(registry, config.name)
|
|
337090
|
+
};
|
|
337091
|
+
}
|
|
337092
|
+
return config;
|
|
337038
337093
|
});
|
|
337039
337094
|
validateNoDuplicatePorts(configs);
|
|
337040
337095
|
return configs;
|
|
@@ -337262,50 +337317,6 @@ function buildDropletServices(options) {
|
|
|
337262
337317
|
function filterByPlatform(configs, platform) {
|
|
337263
337318
|
return configs.filter((c) => (c.platform || "app-platform") === platform);
|
|
337264
337319
|
}
|
|
337265
|
-
// lib/helpers/image.ts
|
|
337266
|
-
var scopeImageTagsRaw = process.env.SCOPE_IMAGE_TAGS ?? "";
|
|
337267
|
-
var scopeImageTags = (() => {
|
|
337268
|
-
if (!scopeImageTagsRaw.trim()) {
|
|
337269
|
-
return {};
|
|
337270
|
-
}
|
|
337271
|
-
try {
|
|
337272
|
-
const parsed = JSON.parse(scopeImageTagsRaw);
|
|
337273
|
-
const tags = {};
|
|
337274
|
-
for (const [key, value] of Object.entries(parsed ?? {})) {
|
|
337275
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
337276
|
-
tags[key] = value.trim();
|
|
337277
|
-
}
|
|
337278
|
-
}
|
|
337279
|
-
return tags;
|
|
337280
|
-
} catch (error) {
|
|
337281
|
-
console.warn("Unable to parse scope image tags from environment:", error);
|
|
337282
|
-
return {};
|
|
337283
|
-
}
|
|
337284
|
-
})();
|
|
337285
|
-
var resolveImageTag = (scopeName) => {
|
|
337286
|
-
const tag = scopeImageTags[scopeName];
|
|
337287
|
-
if (!tag) {
|
|
337288
|
-
return "latest";
|
|
337289
|
-
}
|
|
337290
|
-
return tag;
|
|
337291
|
-
};
|
|
337292
|
-
var ghcrImage = (registry, serviceName) => {
|
|
337293
|
-
const tag = resolveImageTag(serviceName);
|
|
337294
|
-
return `ghcr.io/${registry}/${serviceName}:${tag}`;
|
|
337295
|
-
};
|
|
337296
|
-
var getImage = (registry, repository, registryCredentials) => {
|
|
337297
|
-
const scopeName = repository.split("/").pop();
|
|
337298
|
-
if (!scopeName) {
|
|
337299
|
-
throw new Error(`Invalid repository name: ${repository}`);
|
|
337300
|
-
}
|
|
337301
|
-
return {
|
|
337302
|
-
registryType: "GHCR",
|
|
337303
|
-
registry,
|
|
337304
|
-
repository,
|
|
337305
|
-
registryCredentials,
|
|
337306
|
-
tag: resolveImageTag(scopeName)
|
|
337307
|
-
};
|
|
337308
|
-
};
|
|
337309
337320
|
// lib/helpers/service-builder.ts
|
|
337310
337321
|
function buildServices(options) {
|
|
337311
337322
|
const { serviceConfigs, registryCredentials, logtailToken, registry } = options;
|
|
@@ -337350,7 +337361,7 @@ function buildIngressRules(serviceConfigs) {
|
|
|
337350
337361
|
}
|
|
337351
337362
|
// lib/helpers/service-runtime.ts
|
|
337352
337363
|
var toEnvKey = (name) => name.toUpperCase().replace(/-/g, "_");
|
|
337353
|
-
function
|
|
337364
|
+
function getServicePort(serviceName, defaultPort = 8080) {
|
|
337354
337365
|
const envKey = `${toEnvKey(serviceName)}_PORT`;
|
|
337355
337366
|
const envValue = process.env[envKey];
|
|
337356
337367
|
if (envValue) {
|
|
@@ -337366,7 +337377,7 @@ function getServiceUrl(serviceName) {
|
|
|
337366
337377
|
return process.env[envKey];
|
|
337367
337378
|
}
|
|
337368
337379
|
// lib/helpers/service-urls.ts
|
|
337369
|
-
function
|
|
337380
|
+
function getServicePort2(config) {
|
|
337370
337381
|
if (config.httpPort)
|
|
337371
337382
|
return config.httpPort;
|
|
337372
337383
|
const internalPorts = config.internalPorts;
|
|
@@ -337376,7 +337387,7 @@ function getServicePort3(config) {
|
|
|
337376
337387
|
}
|
|
337377
337388
|
function buildInternalUrls(serviceConfigs) {
|
|
337378
337389
|
return Object.fromEntries(serviceConfigs.map((config) => {
|
|
337379
|
-
const url = config.internalUrl ?? `http://${config.name}:${
|
|
337390
|
+
const url = config.internalUrl ?? `http://${config.name}:${getServicePort2(config)}`;
|
|
337380
337391
|
return [config.name, url];
|
|
337381
337392
|
}));
|
|
337382
337393
|
}
|
|
@@ -337388,7 +337399,7 @@ function buildExternalUrls(serviceConfigs, baseUrl) {
|
|
|
337388
337399
|
}
|
|
337389
337400
|
function buildLocalUrls(serviceConfigs) {
|
|
337390
337401
|
return Object.fromEntries(serviceConfigs.map((config) => {
|
|
337391
|
-
const port =
|
|
337402
|
+
const port = getServicePort2(config);
|
|
337392
337403
|
return [config.name, `http://localhost:${port}`];
|
|
337393
337404
|
}));
|
|
337394
337405
|
}
|
|
@@ -337396,14 +337407,14 @@ function buildServiceUrlEnvs(serviceConfigs) {
|
|
|
337396
337407
|
return serviceConfigs.map((config) => ({
|
|
337397
337408
|
key: `${config.name.toUpperCase().replace(/-/g, "_")}_URL`,
|
|
337398
337409
|
scope: "RUN_TIME",
|
|
337399
|
-
value: config.internalUrl ?? `http://${config.name}:${
|
|
337410
|
+
value: config.internalUrl ?? `http://${config.name}:${getServicePort2(config)}`
|
|
337400
337411
|
}));
|
|
337401
337412
|
}
|
|
337402
337413
|
function buildServicePortEnvs(serviceConfigs) {
|
|
337403
337414
|
return serviceConfigs.map((config) => ({
|
|
337404
337415
|
key: `${config.name.toUpperCase().replace(/-/g, "_")}_PORT`,
|
|
337405
337416
|
scope: "RUN_TIME",
|
|
337406
|
-
value: String(
|
|
337417
|
+
value: String(getServicePort2(config))
|
|
337407
337418
|
}));
|
|
337408
337419
|
}
|
|
337409
337420
|
// lib/runtimes/doks/cert-manager.ts
|
|
@@ -337768,10 +337779,7 @@ function getImagePullPolicy(image2, explicit) {
|
|
|
337768
337779
|
return explicit;
|
|
337769
337780
|
return image2.endsWith(":latest") ? "Always" : "IfNotPresent";
|
|
337770
337781
|
}
|
|
337771
|
-
function
|
|
337772
|
-
const labels = buildLabels(config2.name, config2.labels);
|
|
337773
|
-
const replicas = config2.replicas ?? DEFAULTS.replicas;
|
|
337774
|
-
const imagePullPolicy = getImagePullPolicy(config2.image, config2.imagePullPolicy);
|
|
337782
|
+
function buildEnvVars(config2) {
|
|
337775
337783
|
const envVars = [];
|
|
337776
337784
|
envVars.push({ name: "PORT", value: String(config2.containerPort) });
|
|
337777
337785
|
if (config2.env) {
|
|
@@ -337779,17 +337787,7 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337779
337787
|
envVars.push({ name: key, value: pulumi6.output(value) });
|
|
337780
337788
|
}
|
|
337781
337789
|
}
|
|
337782
|
-
|
|
337783
|
-
if (config2.secrets && Object.keys(config2.secrets).length > 0) {
|
|
337784
|
-
secret = new k8s5.core.v1.Secret(`${config2.name}-secret`, {
|
|
337785
|
-
metadata: {
|
|
337786
|
-
name: `${config2.name}-secret`,
|
|
337787
|
-
namespace,
|
|
337788
|
-
labels
|
|
337789
|
-
},
|
|
337790
|
-
type: "Opaque",
|
|
337791
|
-
stringData: config2.secrets
|
|
337792
|
-
}, { provider });
|
|
337790
|
+
if (config2.secrets) {
|
|
337793
337791
|
for (const key of Object.keys(config2.secrets)) {
|
|
337794
337792
|
envVars.push({
|
|
337795
337793
|
name: key,
|
|
@@ -337802,80 +337800,205 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337802
337800
|
});
|
|
337803
337801
|
}
|
|
337804
337802
|
}
|
|
337803
|
+
return envVars;
|
|
337804
|
+
}
|
|
337805
|
+
function createServiceSecret(provider, namespace, config2, labels) {
|
|
337806
|
+
if (!config2.secrets || Object.keys(config2.secrets).length === 0) {
|
|
337807
|
+
return;
|
|
337808
|
+
}
|
|
337809
|
+
return new k8s5.core.v1.Secret(`${config2.name}-secret`, {
|
|
337810
|
+
metadata: {
|
|
337811
|
+
name: `${config2.name}-secret`,
|
|
337812
|
+
namespace,
|
|
337813
|
+
labels
|
|
337814
|
+
},
|
|
337815
|
+
type: "Opaque",
|
|
337816
|
+
stringData: config2.secrets
|
|
337817
|
+
}, { provider });
|
|
337818
|
+
}
|
|
337819
|
+
function createServiceVolumes(provider, namespace, config2, labels) {
|
|
337805
337820
|
const pvcs = [];
|
|
337806
337821
|
const volumeMounts = [];
|
|
337807
337822
|
const volumes = [];
|
|
337808
|
-
if (config2.volumes) {
|
|
337809
|
-
|
|
337810
|
-
|
|
337811
|
-
|
|
337812
|
-
|
|
337813
|
-
|
|
337814
|
-
|
|
337815
|
-
|
|
337816
|
-
|
|
337817
|
-
|
|
337818
|
-
|
|
337819
|
-
|
|
337820
|
-
|
|
337821
|
-
|
|
337822
|
-
|
|
337823
|
-
}
|
|
337824
|
-
}
|
|
337825
|
-
}, { provider });
|
|
337826
|
-
pvcs.push(pvc);
|
|
337827
|
-
volumeMounts.push({
|
|
337828
|
-
name: vol.name,
|
|
337829
|
-
mountPath: vol.mountPath,
|
|
337830
|
-
readOnly: vol.readOnly
|
|
337831
|
-
});
|
|
337832
|
-
volumes.push({
|
|
337833
|
-
name: vol.name,
|
|
337834
|
-
persistentVolumeClaim: {
|
|
337835
|
-
claimName: `${config2.name}-${vol.name}`
|
|
337823
|
+
if (!config2.volumes) {
|
|
337824
|
+
return { pvcs, volumeMounts, volumes };
|
|
337825
|
+
}
|
|
337826
|
+
for (const vol of config2.volumes) {
|
|
337827
|
+
const pvc = new k8s5.core.v1.PersistentVolumeClaim(`${config2.name}-${vol.name}`, {
|
|
337828
|
+
metadata: {
|
|
337829
|
+
name: `${config2.name}-${vol.name}`,
|
|
337830
|
+
namespace,
|
|
337831
|
+
labels
|
|
337832
|
+
},
|
|
337833
|
+
spec: {
|
|
337834
|
+
accessModes: [vol.accessMode ?? "ReadWriteOnce"],
|
|
337835
|
+
storageClassName: vol.storageClass ?? "do-block-storage",
|
|
337836
|
+
resources: {
|
|
337837
|
+
requests: { storage: vol.size ?? "10Gi" }
|
|
337836
337838
|
}
|
|
337837
|
-
}
|
|
337838
|
-
}
|
|
337839
|
+
}
|
|
337840
|
+
}, { provider });
|
|
337841
|
+
pvcs.push(pvc);
|
|
337842
|
+
volumeMounts.push({
|
|
337843
|
+
name: vol.name,
|
|
337844
|
+
mountPath: vol.mountPath,
|
|
337845
|
+
readOnly: vol.readOnly
|
|
337846
|
+
});
|
|
337847
|
+
volumes.push({
|
|
337848
|
+
name: vol.name,
|
|
337849
|
+
persistentVolumeClaim: {
|
|
337850
|
+
claimName: `${config2.name}-${vol.name}`
|
|
337851
|
+
}
|
|
337852
|
+
});
|
|
337839
337853
|
}
|
|
337854
|
+
return { pvcs, volumeMounts, volumes };
|
|
337855
|
+
}
|
|
337856
|
+
function buildHealthProbes(config2) {
|
|
337840
337857
|
const healthCheck = config2.healthCheck;
|
|
337841
|
-
|
|
337842
|
-
|
|
337843
|
-
if (healthCheck) {
|
|
337844
|
-
const probeConfig = {
|
|
337845
|
-
initialDelaySeconds: healthCheck.initialDelaySeconds ?? DEFAULTS.healthCheck.initialDelaySeconds,
|
|
337846
|
-
periodSeconds: healthCheck.periodSeconds ?? DEFAULTS.healthCheck.periodSeconds,
|
|
337847
|
-
failureThreshold: healthCheck.failureThreshold ?? DEFAULTS.healthCheck.failureThreshold,
|
|
337848
|
-
successThreshold: healthCheck.successThreshold ?? DEFAULTS.healthCheck.successThreshold,
|
|
337849
|
-
timeoutSeconds: healthCheck.timeoutSeconds ?? DEFAULTS.healthCheck.timeoutSeconds
|
|
337850
|
-
};
|
|
337851
|
-
if (healthCheck.httpPath) {
|
|
337852
|
-
const httpGet = {
|
|
337853
|
-
path: healthCheck.httpPath,
|
|
337854
|
-
port: healthCheck.port ?? config2.containerPort
|
|
337855
|
-
};
|
|
337856
|
-
livenessProbe = { ...probeConfig, httpGet };
|
|
337857
|
-
readinessProbe = { ...probeConfig, httpGet };
|
|
337858
|
-
} else {
|
|
337859
|
-
const tcpSocket = {
|
|
337860
|
-
port: healthCheck.port ?? config2.containerPort
|
|
337861
|
-
};
|
|
337862
|
-
livenessProbe = { ...probeConfig, tcpSocket };
|
|
337863
|
-
readinessProbe = { ...probeConfig, tcpSocket };
|
|
337864
|
-
}
|
|
337858
|
+
if (!healthCheck) {
|
|
337859
|
+
return {};
|
|
337865
337860
|
}
|
|
337866
|
-
const
|
|
337867
|
-
|
|
337861
|
+
const probeConfig = {
|
|
337862
|
+
initialDelaySeconds: healthCheck.initialDelaySeconds ?? DEFAULTS.healthCheck.initialDelaySeconds,
|
|
337863
|
+
periodSeconds: healthCheck.periodSeconds ?? DEFAULTS.healthCheck.periodSeconds,
|
|
337864
|
+
failureThreshold: healthCheck.failureThreshold ?? DEFAULTS.healthCheck.failureThreshold,
|
|
337865
|
+
successThreshold: healthCheck.successThreshold ?? DEFAULTS.healthCheck.successThreshold,
|
|
337866
|
+
timeoutSeconds: healthCheck.timeoutSeconds ?? DEFAULTS.healthCheck.timeoutSeconds
|
|
337867
|
+
};
|
|
337868
|
+
if (healthCheck.httpPath) {
|
|
337869
|
+
const httpGet = {
|
|
337870
|
+
path: healthCheck.httpPath,
|
|
337871
|
+
port: healthCheck.port ?? config2.containerPort
|
|
337872
|
+
};
|
|
337873
|
+
return {
|
|
337874
|
+
livenessProbe: { ...probeConfig, httpGet },
|
|
337875
|
+
readinessProbe: { ...probeConfig, httpGet }
|
|
337876
|
+
};
|
|
337877
|
+
}
|
|
337878
|
+
const tcpSocket = { port: healthCheck.port ?? config2.containerPort };
|
|
337879
|
+
return {
|
|
337880
|
+
livenessProbe: { ...probeConfig, tcpSocket },
|
|
337881
|
+
readinessProbe: { ...probeConfig, tcpSocket }
|
|
337882
|
+
};
|
|
337883
|
+
}
|
|
337884
|
+
function buildContainerPorts(config2) {
|
|
337885
|
+
const ports = [
|
|
337868
337886
|
{ containerPort: config2.containerPort, name: "http" }
|
|
337869
337887
|
];
|
|
337870
337888
|
if (config2.additionalPorts) {
|
|
337871
337889
|
for (const port of config2.additionalPorts) {
|
|
337872
|
-
|
|
337890
|
+
ports.push({
|
|
337873
337891
|
containerPort: port.targetPort ?? port.port,
|
|
337874
337892
|
name: port.name,
|
|
337875
337893
|
protocol: port.protocol ?? "TCP"
|
|
337876
337894
|
});
|
|
337877
337895
|
}
|
|
337878
337896
|
}
|
|
337897
|
+
return ports;
|
|
337898
|
+
}
|
|
337899
|
+
function buildServicePorts(config2) {
|
|
337900
|
+
const ports = [
|
|
337901
|
+
{
|
|
337902
|
+
name: "http",
|
|
337903
|
+
port: config2.containerPort,
|
|
337904
|
+
targetPort: config2.containerPort,
|
|
337905
|
+
protocol: "TCP"
|
|
337906
|
+
}
|
|
337907
|
+
];
|
|
337908
|
+
if (config2.additionalPorts) {
|
|
337909
|
+
for (const port of config2.additionalPorts) {
|
|
337910
|
+
ports.push({
|
|
337911
|
+
name: port.name,
|
|
337912
|
+
port: port.port,
|
|
337913
|
+
targetPort: port.targetPort ?? port.port,
|
|
337914
|
+
protocol: port.protocol ?? "TCP"
|
|
337915
|
+
});
|
|
337916
|
+
}
|
|
337917
|
+
}
|
|
337918
|
+
return ports;
|
|
337919
|
+
}
|
|
337920
|
+
function createServiceIngress(provider, namespace, config2, labels, service) {
|
|
337921
|
+
if (!config2.ingress) {
|
|
337922
|
+
return;
|
|
337923
|
+
}
|
|
337924
|
+
const ingressAnnotations = {
|
|
337925
|
+
"kubernetes.io/ingress.class": "nginx",
|
|
337926
|
+
...config2.ingress.annotations
|
|
337927
|
+
};
|
|
337928
|
+
if (config2.ingress.tls?.enabled) {
|
|
337929
|
+
ingressAnnotations["cert-manager.io/cluster-issuer"] = config2.ingress.tls.issuerName ?? "letsencrypt-production";
|
|
337930
|
+
}
|
|
337931
|
+
let ingressPath = config2.ingress.path;
|
|
337932
|
+
let ingressPathType = config2.ingress.pathType ?? "Prefix";
|
|
337933
|
+
const shouldStripPrefix = config2.ingress.path !== "/" && !config2.ingress.keepPrefix;
|
|
337934
|
+
if (shouldStripPrefix) {
|
|
337935
|
+
ingressPath = `${config2.ingress.path}(/|$)(.*)`;
|
|
337936
|
+
ingressPathType = "ImplementationSpecific";
|
|
337937
|
+
ingressAnnotations["nginx.ingress.kubernetes.io/use-regex"] = "true";
|
|
337938
|
+
ingressAnnotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$2";
|
|
337939
|
+
}
|
|
337940
|
+
const createRule = (host) => ({
|
|
337941
|
+
...host && { host },
|
|
337942
|
+
http: {
|
|
337943
|
+
paths: [
|
|
337944
|
+
{
|
|
337945
|
+
path: ingressPath,
|
|
337946
|
+
pathType: ingressPathType,
|
|
337947
|
+
backend: {
|
|
337948
|
+
service: {
|
|
337949
|
+
name: config2.name,
|
|
337950
|
+
port: { number: config2.containerPort }
|
|
337951
|
+
}
|
|
337952
|
+
}
|
|
337953
|
+
}
|
|
337954
|
+
]
|
|
337955
|
+
}
|
|
337956
|
+
});
|
|
337957
|
+
const ingressRules = [];
|
|
337958
|
+
if (config2.ingress.host) {
|
|
337959
|
+
ingressRules.push(createRule(config2.ingress.host));
|
|
337960
|
+
} else {
|
|
337961
|
+
ingressRules.push(createRule());
|
|
337962
|
+
}
|
|
337963
|
+
if (config2.ingress.additionalHosts) {
|
|
337964
|
+
for (const additionalHost of config2.ingress.additionalHosts) {
|
|
337965
|
+
ingressRules.push(createRule(additionalHost));
|
|
337966
|
+
}
|
|
337967
|
+
}
|
|
337968
|
+
const allHosts = [
|
|
337969
|
+
...config2.ingress.host ? [config2.ingress.host] : [],
|
|
337970
|
+
...config2.ingress.additionalHosts ?? []
|
|
337971
|
+
];
|
|
337972
|
+
const tlsSecretName = config2.ingress.tls?.secretName ?? `${config2.name}-tls`;
|
|
337973
|
+
return new k8s5.networking.v1.Ingress(`${config2.name}-ingress`, {
|
|
337974
|
+
metadata: {
|
|
337975
|
+
name: config2.name,
|
|
337976
|
+
namespace,
|
|
337977
|
+
labels,
|
|
337978
|
+
annotations: ingressAnnotations
|
|
337979
|
+
},
|
|
337980
|
+
spec: {
|
|
337981
|
+
...config2.ingress.tls?.enabled && allHosts.length > 0 && {
|
|
337982
|
+
tls: [{ hosts: allHosts, secretName: tlsSecretName }]
|
|
337983
|
+
},
|
|
337984
|
+
rules: ingressRules
|
|
337985
|
+
}
|
|
337986
|
+
}, { provider, dependsOn: [service] });
|
|
337987
|
+
}
|
|
337988
|
+
function deployK8sService(provider, namespace, config2) {
|
|
337989
|
+
if (!config2.image) {
|
|
337990
|
+
throw new Error(`Missing "image" for service "${config2.name}". Either specify image explicitly or use discoverServiceConfigs() which auto-generates it from pf.registry.`);
|
|
337991
|
+
}
|
|
337992
|
+
const labels = buildLabels(config2.name, config2.labels);
|
|
337993
|
+
const replicas = config2.replicas ?? DEFAULTS.replicas;
|
|
337994
|
+
const imagePullPolicy = getImagePullPolicy(config2.image, config2.imagePullPolicy);
|
|
337995
|
+
const resources = config2.resources ?? DEFAULTS.resources;
|
|
337996
|
+
const secret = createServiceSecret(provider, namespace, config2, labels);
|
|
337997
|
+
const envVars = buildEnvVars(config2);
|
|
337998
|
+
const { pvcs, volumeMounts, volumes } = createServiceVolumes(provider, namespace, config2, labels);
|
|
337999
|
+
const { livenessProbe, readinessProbe } = buildHealthProbes(config2);
|
|
338000
|
+
const containerPorts = buildContainerPorts(config2);
|
|
338001
|
+
const servicePorts = buildServicePorts(config2);
|
|
337879
338002
|
const deployment = new k8s5.apps.v1.Deployment(`${config2.name}-deployment`, {
|
|
337880
338003
|
metadata: {
|
|
337881
338004
|
name: config2.name,
|
|
@@ -337917,24 +338040,6 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337917
338040
|
}
|
|
337918
338041
|
}
|
|
337919
338042
|
}, { provider, dependsOn: pvcs.length > 0 ? pvcs : undefined });
|
|
337920
|
-
const servicePorts = [
|
|
337921
|
-
{
|
|
337922
|
-
name: "http",
|
|
337923
|
-
port: config2.containerPort,
|
|
337924
|
-
targetPort: config2.containerPort,
|
|
337925
|
-
protocol: "TCP"
|
|
337926
|
-
}
|
|
337927
|
-
];
|
|
337928
|
-
if (config2.additionalPorts) {
|
|
337929
|
-
for (const port of config2.additionalPorts) {
|
|
337930
|
-
servicePorts.push({
|
|
337931
|
-
name: port.name,
|
|
337932
|
-
port: port.port,
|
|
337933
|
-
targetPort: port.targetPort ?? port.port,
|
|
337934
|
-
protocol: port.protocol ?? "TCP"
|
|
337935
|
-
});
|
|
337936
|
-
}
|
|
337937
|
-
}
|
|
337938
338043
|
const service = new k8s5.core.v1.Service(`${config2.name}-service`, {
|
|
337939
338044
|
metadata: {
|
|
337940
338045
|
name: config2.name,
|
|
@@ -337947,77 +338052,7 @@ function deployK8sService(provider, namespace, config2) {
|
|
|
337947
338052
|
ports: servicePorts
|
|
337948
338053
|
}
|
|
337949
338054
|
}, { provider, dependsOn: [deployment] });
|
|
337950
|
-
|
|
337951
|
-
if (config2.ingress) {
|
|
337952
|
-
const ingressAnnotations = {
|
|
337953
|
-
"kubernetes.io/ingress.class": "nginx",
|
|
337954
|
-
...config2.ingress.annotations
|
|
337955
|
-
};
|
|
337956
|
-
if (config2.ingress.tls?.enabled) {
|
|
337957
|
-
ingressAnnotations["cert-manager.io/cluster-issuer"] = config2.ingress.tls.issuerName ?? "letsencrypt-production";
|
|
337958
|
-
}
|
|
337959
|
-
let ingressPath = config2.ingress.path;
|
|
337960
|
-
let ingressPathType = config2.ingress.pathType ?? "Prefix";
|
|
337961
|
-
const shouldStripPrefix = config2.ingress.path !== "/" && !config2.ingress.keepPrefix;
|
|
337962
|
-
if (shouldStripPrefix) {
|
|
337963
|
-
ingressPath = `${config2.ingress.path}(/|$)(.*)`;
|
|
337964
|
-
ingressPathType = "ImplementationSpecific";
|
|
337965
|
-
ingressAnnotations["nginx.ingress.kubernetes.io/use-regex"] = "true";
|
|
337966
|
-
ingressAnnotations["nginx.ingress.kubernetes.io/rewrite-target"] = "/$2";
|
|
337967
|
-
}
|
|
337968
|
-
const tlsSecretName = config2.ingress.tls?.secretName ?? `${config2.name}-tls`;
|
|
337969
|
-
const ingressRules = [];
|
|
337970
|
-
const createRule = (host) => ({
|
|
337971
|
-
...host && { host },
|
|
337972
|
-
http: {
|
|
337973
|
-
paths: [
|
|
337974
|
-
{
|
|
337975
|
-
path: ingressPath,
|
|
337976
|
-
pathType: ingressPathType,
|
|
337977
|
-
backend: {
|
|
337978
|
-
service: {
|
|
337979
|
-
name: config2.name,
|
|
337980
|
-
port: { number: config2.containerPort }
|
|
337981
|
-
}
|
|
337982
|
-
}
|
|
337983
|
-
}
|
|
337984
|
-
]
|
|
337985
|
-
}
|
|
337986
|
-
});
|
|
337987
|
-
if (config2.ingress.host) {
|
|
337988
|
-
ingressRules.push(createRule(config2.ingress.host));
|
|
337989
|
-
} else {
|
|
337990
|
-
ingressRules.push(createRule());
|
|
337991
|
-
}
|
|
337992
|
-
if (config2.ingress.additionalHosts) {
|
|
337993
|
-
for (const additionalHost of config2.ingress.additionalHosts) {
|
|
337994
|
-
ingressRules.push(createRule(additionalHost));
|
|
337995
|
-
}
|
|
337996
|
-
}
|
|
337997
|
-
const allHosts = [
|
|
337998
|
-
...config2.ingress.host ? [config2.ingress.host] : [],
|
|
337999
|
-
...config2.ingress.additionalHosts ?? []
|
|
338000
|
-
];
|
|
338001
|
-
ingress = new k8s5.networking.v1.Ingress(`${config2.name}-ingress`, {
|
|
338002
|
-
metadata: {
|
|
338003
|
-
name: config2.name,
|
|
338004
|
-
namespace,
|
|
338005
|
-
labels,
|
|
338006
|
-
annotations: ingressAnnotations
|
|
338007
|
-
},
|
|
338008
|
-
spec: {
|
|
338009
|
-
...config2.ingress.tls?.enabled && allHosts.length > 0 && {
|
|
338010
|
-
tls: [
|
|
338011
|
-
{
|
|
338012
|
-
hosts: allHosts,
|
|
338013
|
-
secretName: tlsSecretName
|
|
338014
|
-
}
|
|
338015
|
-
]
|
|
338016
|
-
},
|
|
338017
|
-
rules: ingressRules
|
|
338018
|
-
}
|
|
338019
|
-
}, { provider, dependsOn: [service] });
|
|
338020
|
-
}
|
|
338055
|
+
const ingress = createServiceIngress(provider, namespace, config2, labels, service);
|
|
338021
338056
|
const serviceDns = `${config2.name}.${namespace}.svc.cluster.local`;
|
|
338022
338057
|
const internalUrl = pulumi6.output(`http://${serviceDns}:${config2.containerPort}`);
|
|
338023
338058
|
return {
|
|
@@ -338060,12 +338095,12 @@ function buildInternalUrl(serviceName, namespace, port) {
|
|
|
338060
338095
|
export {
|
|
338061
338096
|
ghcrImage,
|
|
338062
338097
|
getServiceUrl,
|
|
338063
|
-
|
|
338098
|
+
getServicePort,
|
|
338064
338099
|
getImage,
|
|
338065
338100
|
filterByPlatform,
|
|
338066
338101
|
ensureDot,
|
|
338067
338102
|
dockerHubImage,
|
|
338068
|
-
|
|
338103
|
+
discoverServiceConfigs,
|
|
338069
338104
|
deployNginxIngress,
|
|
338070
338105
|
deployNats,
|
|
338071
338106
|
deployK8sServices,
|
|
@@ -197,8 +197,11 @@ export interface K8sVolumeMount {
|
|
|
197
197
|
export interface K8sServiceConfig {
|
|
198
198
|
/** Unique name of the service (used for deployment, service, and labels) */
|
|
199
199
|
name: string;
|
|
200
|
-
/**
|
|
201
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Container image (e.g., 'ghcr.io/orderboss/platform/storefront:latest').
|
|
202
|
+
* If not specified, auto-generated from pf.registry config + service name.
|
|
203
|
+
*/
|
|
204
|
+
image?: string;
|
|
202
205
|
/** Port the container listens on */
|
|
203
206
|
containerPort: number;
|
|
204
207
|
/** Number of replicas (defaults to 1) */
|