Skip to content

Commit

Permalink
Updating networklight class in primitives
Browse files Browse the repository at this point in the history
  • Loading branch information
maayarosama committed Oct 23, 2024
1 parent de4bab1 commit a9cdb25
Showing 1 changed file with 153 additions and 114 deletions.
267 changes: 153 additions & 114 deletions packages/grid_client/src/primitives/networklight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,30 @@ import { TFClient } from "../clients/tf-grid/client";
import { GqlNodeContract } from "../clients/tf-grid/contracts";
import { GridClientConfig } from "../config";
import { events } from "../helpers/events";
import { generateRandomHexSeed } from "../helpers/utils";
import { formatErrorMessage, generateRandomHexSeed } from "../helpers/utils";
import { validateHexSeed } from "../helpers/validator";
import { ContractStates, MyceliumNetworkModel } from "../modules";
import { BackendStorage, BackendStorageType } from "../storage/backend";
import { MyceliumNetworkModel } from "../modules";
import { BackendStorage } from "../storage/backend";
import { NetworkLight } from "../zos";
import { Deployment } from "../zos/deployment";
import { Workload, WorkloadTypes } from "../zos/workload";
import { Nodes } from "./nodes";

class Node {
node_id: number;
contract_id: number;
reserved_ips: string[] = [];
}

interface NetworkMetadata {
version: number;
}
class ZNetworkLight {
node: Node;
capacity: Nodes;
deployments: Deployment[] = [];
network: NetworkLight;
contracts: Required<GqlNodeContract>[];
reservedSubnets: string[] = [];
backendStorage: BackendStorage;
static newContracts: GqlNodeContract[] = [];
static deletedContracts: number[] = [];
Expand All @@ -56,37 +61,32 @@ class ZNetworkLight {
config.seed,
);
this.rmb = new RMB(config.rmbClient);
// this.capacity = new Nodes(this.config.graphqlURL, this.config.proxyURL, this.config.rmbClient);
this.capacity = new Nodes(this.config.graphqlURL, this.config.proxyURL, this.config.rmbClient);
this.tfClient = config.tfclient;
}

private async saveIfKVStoreBackend(extrinsics) {
if (this.config.backendStorageType === BackendStorageType.tfkvstore && extrinsics && extrinsics.length > 0) {
extrinsics = extrinsics.filter(e => e !== undefined);
if (extrinsics.length > 0) {
await this.tfClient.connect();
await this.tfClient.applyAllExtrinsics(extrinsics);
}
private getUpdatedMetadata(nodeId: number, metadata: string): string {
if (this.node.node_id === nodeId) {
const parsedMetadata: NetworkMetadata = JSON.parse(metadata || "{}");
parsedMetadata.version = 4;
return JSON.stringify(parsedMetadata);
}

return metadata;
}

updateWorkload(nodeId: number, workload: Workload): Workload {
workload.data = this.getUpdatedNetwork(workload.data);
workload.metadata = this.getUpdatedMetadata(nodeId, workload.metadata);
return workload;
}
getUpdatedNetwork(znet_light): NetworkLight {
if (this.network.subnet === znet_light.subnet) {
return this.network;
}

return znet_light;
}
// Check this later
// private getUpdatedMetadata(nodeId: number, metadata: string): string {
// for (const node of this.nodes) {
// if (node.node_id === nodeId) {
// const parsedMetadata: NetworkMetadata = JSON.parse(metadata || "{}");
// parsedMetadata.version = 3;
// parsedMetadata.user_accesses = this.userAccesses;
// return JSON.stringify(parsedMetadata);
// }
// }
// return metadata;
// }

// updateWorkload(nodeId: number, workload: Workload): Workload {
// workload.data = this.getUpdatedNetwork(workload.data);
// workload.metadata = this.getUpdatedMetadata(nodeId, workload.metadata);
// return workload;
// }

async addNode(
nodeId: number,
Expand All @@ -96,20 +96,15 @@ class ZNetworkLight {
myceliumSeeds: MyceliumNetworkModel,
): Promise<Workload | undefined> {
events.emit("logs", `Adding node ${nodeId} to network ${this.name}`);
// const keypair = this.generateWireguardKeypair();
const znet_light = new NetworkLight();
let znet_light = new NetworkLight();
if (!subnet) {
znet_light.subnet = this.getFreeSubnet();
} else {
znet_light.subnet = subnet;
}
// Check this subnet=iprange?
// znet.ip_range = this.ipRange;

znet_light["node_id"] = nodeId;

if (mycelium) {
// const myceliumNetworkSeed = myceliumSeeds.find(item => item.nodeId === nodeId);
let seed = generateRandomHexSeed(32);
if (myceliumSeeds?.seed) {
seed = myceliumSeeds.seed;
Expand All @@ -123,11 +118,7 @@ class ZNetworkLight {
}

this.network = znet_light;

// Check this later
// await this.generatePeers();
// this.updateNetworkDeployments();
// znet = this.getUpdatedNetwork(znet);
znet_light = this.getUpdatedNetwork(znet_light);

const znet_light_workload = new Workload();
znet_light_workload.version = 0;
Expand All @@ -142,26 +133,11 @@ class ZNetworkLight {
return znet_light_workload;
}

getUpdatedNetwork(znet_light): NetworkLight {
if (this.network.subnet === znet_light.subnet) {
return this.network;
}

return znet_light;
}

_fromObj(net: NetworkLight): NetworkLight {
const znet_light = plainToInstance(NetworkLight, net);
return znet_light;
}

getPublicKey(privateKey: string): string {
const privKey = Buffer.from(privateKey, "base64");
const keypair = TweetNACL.box.keyPair.fromSecretKey(privKey);
return Buffer.from(keypair.publicKey).toString("base64");
}

// Check this what does it do
getFreeIP(node_id: number, subnet = ""): string | undefined {
let ip;

Expand All @@ -181,6 +157,7 @@ class ZNetworkLight {
throw new ValidationError(`node_id is not in the network. Please add it first.`);
}
}

validateUserIP(node_id: number, ip_address = "") {
const nodeSubnet = this.getNodeSubnet(node_id);
const ip = Addr(ip_address);
Expand All @@ -193,40 +170,41 @@ class ZNetworkLight {
return ip_address;
}
}

getNodeSubnet(node_id: number): string | undefined {
if (this.network["node_id"] === node_id) {
return this.network.subnet;
}
}

getFreeSubnet(): string {
const subnet = Addr(this.ipRange).mask(24).nextSibling().nextSibling();
const reservedSubnets = this.getReservedSubnets();
let subnet = Addr(this.ipRange).mask(24).nextSibling().nextSibling();
while (reservedSubnets.includes(subnet.toString())) {
subnet = subnet.nextSibling();
}
this.reservedSubnets.push(subnet.toString());
return subnet.toString();
}

// Check this later
getNetworksPath() {
// Check this Should we change to networklight
return PATH.join(this.config.storePath, "networks");
}
getReservedSubnets(): string[] {
const subnet = this.getNodeSubnet(this.node.node_id);
if (subnet && !this.reservedSubnets.includes(subnet)) {
this.reservedSubnets.push(subnet);
}

// Check this
async getNetwork() {
const path = this.getNetworksPath();
return await this.backendStorage.load(PATH.join(path, this.name, "info.json"));
return this.reservedSubnets;
}

private async getMyNetworkContracts(fetch = false) {
if (fetch || !this.contracts) {
// Check this Should we change to networklight
let contracts = await this.tfClient.contracts.listMyNodeContracts({
graphqlURL: this.config.graphqlURL,
type: "network",
type: "network-light",
});
const alreadyFetchedContracts: GqlNodeContract[] = [];
for (const contract of ZNetworkLight.newContracts) {
// Check this Should we change to networklight
if (contract.parsedDeploymentData!.type !== "network") continue;
if (contract.parsedDeploymentData!.type !== "network-light") continue;
const c = contracts.filter(c => +c.contractID === +contract.contractID);
if (c.length > 0) {
alreadyFetchedContracts.push(contract);
Expand Down Expand Up @@ -254,6 +232,108 @@ class ZNetworkLight {

return this.contracts;
}
async load(): Promise<void> {
if (!(await this.exists())) {
return;
}
events.emit("logs", `Loading network ${this.name}`);

await this.loadNetworkFromContracts();

// else {
// const network = await this.getNetwork();
// if (network["ip_range"] !== this.ipRange) {
// throw new ValidationError(`The same network name ${this.name} with a different ip range already exists.`);
// }

// await this.tfClient.connect();
// for (const node of network["nodes"]) {
// const contract = await this.tfClient.contracts.get({
// id: node.contract_id,
// });
// if (contract === null) continue;
// const node_twin_id = await this.capacity.getNodeTwinId(node.node_id);
// const payload = JSON.stringify({ contract_id: node.contract_id });
// let res;
// try {
// res = await this.rmb.request([node_twin_id], "zos.deployment.get", payload);
// } catch (e) {
// (e as Error).message = formatErrorMessage(`Failed to load network deployment ${node.contract_id}`, e);
// throw e;
// }
// res["node_id"] = node.node_id;
// for (const workload of res["workloads"]) {
// if (
// workload["type"] !== WorkloadTypes.network ||
// !Addr(this.ipRange).contains(Addr(workload["data"]["subnet"]))
// ) {
// continue;
// }
// if (workload.result.state === "deleted") {
// continue;
// }
// const znet = this._fromObj(workload["data"]);
// znet["node_id"] = node.node_id;
// const n: Node = node;
// this.nodes.push(n);
// this.networks.push(znet);
// this.deployments.push(res);
// }
// }
// }
}

private async getReservedIps(nodeId: number): Promise<string[]> {
const node_twin_id = await this.capacity.getNodeTwinId(nodeId);
const payload = JSON.stringify({ network_name: this.name });
let reservedIps: string[];
try {
reservedIps = await this.rmb.request([node_twin_id], "zos.network.list_private_ips", payload);
} catch (e) {
(e as Error).message = formatErrorMessage(`Failed to list reserved ips from node ${nodeId}`, e);
throw e;
}
return reservedIps;
}

private async loadNetworkFromContracts() {
const contracts = await this.getDeploymentContracts(this.name);
for (const contract of contracts) {
const node_twin_id = await this.capacity.getNodeTwinId(contract.nodeID);
const payload = JSON.stringify({ contract_id: +contract.contractID });
let res: Deployment;
try {
res = await this.rmb.request([node_twin_id], "zos.deployment.get", payload);
} catch (e) {
(e as Error).message = formatErrorMessage(`Failed to load network deployment ${contract.contractID}`, e);
throw e;
}
res["node_id"] = contract.nodeID;
for (const workload of res.workloads) {
const data = workload.data as NetworkLight;
if (workload.type !== WorkloadTypes.network || workload.name !== this.name) {
continue;
}
if (workload.result.state === "deleted") {
continue;
}
const znet_light = this._fromObj(data);
znet_light["node_id"] = contract.nodeID;
const reservedIps = await this.getReservedIps(contract.nodeID);

if (znet_light.subnet !== this.ipRange) {
throw new ValidationError(`The same network name ${this.name} with a different ip range already exists.`);
}
this.node = {
contract_id: +contract.contractID,
node_id: contract.nodeID,
reserved_ips: reservedIps,
};
this.network = znet_light;
this.deployments.push(res);
}
}
}

private async getDeploymentContracts(name: string) {
const contracts = await this.getMyNetworkContracts(true);
Expand All @@ -264,59 +344,18 @@ class ZNetworkLight {
return Array.from(new Set(contracts.map(c => c.parsedDeploymentData.name)));
}

private async listNewNetworks() {
private async listAllNetworks() {
const contracts = await this.getMyNetworkContracts(true);
return this.getContractsName(contracts);
}

private async existOnNewNetwork() {
return (await this.listNewNetworks()).includes(this.name);
}

async getNetworkNames(): Promise<string[]> {
const newNames = await this.listNewNetworks();

const path = this.getNetworksPath();
const oldNames = await this.backendStorage.list(path);
return Array.from(new Set([...newNames, ...oldNames]));
private async exists() {
return (await this.listAllNetworks()).includes(this.name);
}

isPrivateIP(ip: string): boolean {
return PrivateIp(ip.split("/")[0]);
}

async save(AddedContract?: Contract, deletedContract?: number) {
if (AddedContract?.contractType.nodeContract)
ZNetworkLight.newContracts.push({
contractID: String(AddedContract.contractId),
createdAt: Date.now().toString(),
updatedAt: Date.now().toString(),
deploymentData: AddedContract.contractType.nodeContract.deploymentData,
deploymentHash: AddedContract.contractType.nodeContract.deploymentHash,
gridVersion: "4",
id: "",
nodeID: AddedContract.contractType.nodeContract.nodeId,
numberOfPublicIPs: AddedContract.contractType.nodeContract.publicIps,
solutionProviderID: String(AddedContract.solutionProviderId),
state: ContractStates.Created,
twinID: String(AddedContract.twinId),
parsedDeploymentData: JSON.parse(AddedContract.contractType.nodeContract.deploymentData),
resourcesUsed: undefined,
});

if (deletedContract) ZNetworkLight.deletedContracts.push(deletedContract);

if (!this.node) {
await this.delete();
}
}

async delete(): Promise<void> {
events.emit("logs", `Deleting network ${this.name}`);
const path = PATH.join(this.getNetworksPath(), this.name, "info.json");
const updateOperations = await this.backendStorage.dump(path, "");
await this.saveIfKVStoreBackend(updateOperations);
}
}

export { ZNetworkLight, Node };

0 comments on commit a9cdb25

Please sign in to comment.