Skip to content

Commit

Permalink
feat(api): move deployment relations and ip lease validation from clo…
Browse files Browse the repository at this point in the history
  • Loading branch information
ygrishajev committed May 6, 2024
1 parent 1406990 commit 8a500e3
Showing 1 changed file with 61 additions and 2 deletions.
63 changes: 61 additions & 2 deletions src/sdl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { default as stableStringify } from "json-stable-stringify";
import crypto from "node:crypto";
import { MAINNET_ID, USDC_IBC_DENOMS } from "../config/network";
import { NetworkId } from "../types/network";
import { CustomValidationError } from "../error/CustomValidationError";
import { CustomValidationError } from "../error";

const Endpoint_SHARED_HTTP = 0;
const Endpoint_RANDOM_PORT = 1;
Expand Down Expand Up @@ -140,6 +140,10 @@ export class SDL {

private readonly ENDPOINT_KIND_IP = "ip";

private readonly endpointsUsed = new Set<string>();

private readonly portsUsed = new Map<string, string>();

constructor(
public readonly data: v2Sdl,
public readonly version: NetworkVersion = "beta2",
Expand All @@ -159,8 +163,14 @@ export class SDL {
SDL.validateStorage(name, resources.storage);
});

this.validateDenom();
this.validateEndpoints();

Object.keys(this.data.services).forEach(serviceName => {
this.validateDeploymentWithRelations(serviceName);
this.validateLeaseIP(serviceName);
});

this.validateDenom();
}

private validateDenom() {
Expand All @@ -186,6 +196,55 @@ export class SDL {
});
}

private validateDeploymentWithRelations(serviceName: string) {
const deployment = this.data.deployment[serviceName];
CustomValidationError.assert(deployment, `Service "${serviceName}" is not defined in the "deployment" section.`);

Object.keys(this.data.deployment[serviceName]).forEach(deploymentName => {
const serviceDeployment = this.data.deployment[serviceName][deploymentName];
const compute = this.data.profiles.compute[serviceDeployment.profile];
const infra = this.data.profiles.placement[deploymentName];

CustomValidationError.assert(infra, `The placement "${deploymentName}" is not defined in the "placement" section.`);
CustomValidationError.assert(
infra.pricing[serviceDeployment.profile],
`The pricing for the "${serviceDeployment.profile}" profile is not defined in the "${deploymentName}" "placement" definition.`
);
CustomValidationError.assert(
compute,
`The compute requirements for the "${serviceDeployment.profile}" profile are not defined in the "compute" section.`
);
});
}

private validateLeaseIP(serviceName: string) {
this.data.services[serviceName].expose?.forEach(expose => {
const proto = this.parseServiceProto(expose.proto);

expose.to?.forEach(to => {
if (to.ip?.length > 0) {
CustomValidationError.assert(to.global, `Error on "${serviceName}", if an IP is declared, the directive must be declared as global.`);

if (!this.data.endpoints?.[to.ip]) {
throw new CustomValidationError(
`Unknown endpoint "${to.ip}" in service "${serviceName}". Add to the list of endpoints in the "endpoints" section.`
);
}

this.endpointsUsed.add(to.ip);

const portKey = `${to.ip}-${expose.as}-${proto}`;
const otherServiceName = this.portsUsed.get(portKey);
CustomValidationError.assert(
!this.portsUsed.has(portKey),
`IP endpoint ${to.ip} port: ${expose.port} protocol: ${proto} specified by service ${serviceName} already in use by ${otherServiceName}`
);
this.portsUsed.set(portKey, serviceName);
}
});
});
}

services() {
if (this.data) {
return this.data.services;
Expand Down

0 comments on commit 8a500e3

Please sign in to comment.