diff --git a/packages/grid_client/src/high_level/twinDeploymentHandler.ts b/packages/grid_client/src/high_level/twinDeploymentHandler.ts index 27c72a39d7..0a00f9cd07 100644 --- a/packages/grid_client/src/high_level/twinDeploymentHandler.ts +++ b/packages/grid_client/src/high_level/twinDeploymentHandler.ts @@ -265,6 +265,43 @@ class TwinDeploymentHandler { return deployments; } + async checkFarmIps(twinDeployments: TwinDeployment[]) { + const farmIPs: Map = new Map(); + + for (const twinDeployment of twinDeployments) { + if (twinDeployment.operation !== Operations.deploy) { + continue; + } + + if (twinDeployment.publicIps === 0) { + continue; + } + + const node = await this.nodes.getNode(twinDeployment.nodeId); + if (!node) { + continue; + } + if (!farmIPs.has(node.farmId)) { + farmIPs.set(node.farmId, twinDeployment.publicIps); + } else { + farmIPs.set(node.farmId, farmIPs.get(node.farmId)! + twinDeployment.publicIps); + } + } + + for (const farmId of farmIPs.keys()) { + const _farm = await this.tfclient.farms.get({ id: farmId }); + const freeIps = _farm.publicIps.filter(res => res.contractId === 0).length; + + if (freeIps < farmIPs.get(farmId)!) { + throw Error( + `Farm ${farmId} doesn't have enough public IPs: requested IPs=${farmIPs.get( + farmId, + )}, available IPs=${freeIps}`, + ); + } + } + } + async checkNodesCapacity(twinDeployments: TwinDeployment[]) { for (const twinDeployment of twinDeployments) { let workloads: Workload[] = []; @@ -439,6 +476,8 @@ class TwinDeploymentHandler { twinDeployments = await this.merge(twinDeployments); await this.validate(twinDeployments); await this.checkNodesCapacity(twinDeployments); + await this.checkFarmIps(twinDeployments); + const contracts = { created: [], updated: [], deleted: [] }; const resultContracts = { created: [], updated: [], deleted: [] }; let nodeExtrinsics: ExtrinsicResult[] = []; diff --git a/packages/grid_client/src/modules/models.ts b/packages/grid_client/src/modules/models.ts index a8c02acdda..fccfb67867 100644 --- a/packages/grid_client/src/modules/models.ts +++ b/packages/grid_client/src/modules/models.ts @@ -596,6 +596,7 @@ class FarmFilterOptions { @Expose() @IsOptional() @IsInt() @Min(1) nodeRentedBy?: number; @Expose() @IsOptional() @IsInt() page?: number; @Expose() @IsOptional() @IsInt() size?: number; + @Expose() @IsOptional() @IsInt() farmId?: number; } class CalculatorModel { diff --git a/packages/grid_client/src/primitives/nodes.ts b/packages/grid_client/src/primitives/nodes.ts index d20eeac6e6..51356034c0 100644 --- a/packages/grid_client/src/primitives/nodes.ts +++ b/packages/grid_client/src/primitives/nodes.ts @@ -23,7 +23,7 @@ interface FarmInfo { interface PublicIps { id: string; ip: string; - contractId: number; + contract_id: number; // Added to match the one in the farm interface || TODO: Should we replace the whole http requests to be done with the gridProxy. gateway: string; } @@ -176,7 +176,7 @@ class Nodes { farms = await this.getAllFarms(url); } return farms - .filter(farm => farm.publicIps.filter(ip => ip.contractId === 0).length > 0) + .filter(farm => farm.publicIps.filter(ip => ip.contract_id === 0).length > 0) .map(farm => farm.farmId) .includes(farmId); } @@ -382,6 +382,7 @@ class Nodes { node_has_gpu: options.nodeHasGPU, node_rented_by: options.nodeRentedBy, node_certified: options.nodeCertified, + farm_id: options.farmId, }; return Object.entries(params) .map(param => param.join("="))