Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listing deployments from contracts instead of kvstore #2124

Merged
merged 49 commits into from
Mar 3, 2024
Merged
Changes from 1 commit
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a64d3ef
Change the listing the deployments from the kvstore to contracts data
AhmedHanafy725 Feb 4, 2024
ac40295
Update filtering the contracts while listing the deployments
AhmedHanafy725 Feb 4, 2024
8b5beb8
Update the contract field on the failed deployment to the new naming
AhmedHanafy725 Feb 5, 2024
b4377a5
Remove saving the deployment data after deploying the workload from k…
AhmedHanafy725 Feb 5, 2024
7631999
chore: Merge branch 'development' into development_listing
MohamedElmdary Feb 6, 2024
6be3dae
feat: Add markAsFromAnotherClient helper
MohamedElmdary Feb 6, 2024
ab63505
feat: use markAsFromAnotherClient and add switch to toggle between sh…
MohamedElmdary Feb 6, 2024
3c6b9eb
feat: use markAsFromAnotherClient and add switch to toggle between sh…
MohamedElmdary Feb 6, 2024
70df69f
- feat: Support disable in icon_action_btn
MohamedElmdary Feb 6, 2024
faee502
refactor: Remove console logs
MohamedElmdary Feb 6, 2024
1994bf2
fix: Elimiate a possible error due to null value of gridStore.client
MohamedElmdary Feb 7, 2024
671f5ce
fix: if projectName was empty it causes a leading / which causes issu…
MohamedElmdary Feb 7, 2024
fd0996e
fix: mark only item from different client
MohamedElmdary Feb 7, 2024
204f684
feat: Move filter to graphql level instead of client level
MohamedElmdary Feb 7, 2024
ef75fac
feat: Store parsed value instead of parsing deploymentData over and over
MohamedElmdary Feb 7, 2024
715fff0
chore: Merge branch 'development' into development_listing
MohamedElmdary Feb 8, 2024
35183e1
fix: Stop filtering out workers from k8s clusters
MohamedElmdary Feb 11, 2024
0ee9dfa
fix: interfaces might be empty
MohamedElmdary Feb 11, 2024
af5e598
chore: Merge branch 'development' into development_listing
MohamedElmdary Feb 11, 2024
810f5c7
feat: Disable k8s clusters from other clients
MohamedElmdary Feb 12, 2024
3f955bd
fix: Add reload deployment with no projectName if failed to load with…
MohamedElmdary Feb 13, 2024
02c6027
fix: Add reload deployment with no projectName if failed to load with…
MohamedElmdary Feb 13, 2024
612a439
feat: Add tooltip for 'show all deployments' switch to make it more c…
MohamedElmdary Feb 13, 2024
ed73037
Merge branch 'development' into development_listing
AhmedHanafy725 Feb 15, 2024
c0bf57f
Get the network names from contracts and merge them with old ones sto…
AhmedHanafy725 Feb 15, 2024
dec42be
Load the network from the contracts
AhmedHanafy725 Feb 17, 2024
dbe8523
Load reserved ips from vm deployments
AhmedHanafy725 Feb 17, 2024
df1e4cb
Update workload's metadata of the newly created deployments
AhmedHanafy725 Feb 18, 2024
1efd99d
Update metadata interface to have version and change it to match the …
AhmedHanafy725 Feb 19, 2024
587760b
Set user access in the node to be set on the metadata when deploying …
AhmedHanafy725 Feb 19, 2024
3844f15
Update getting the wireguard config with fallback to kvstore
AhmedHanafy725 Feb 20, 2024
a7320ad
Update getting wireguard access from the playground
AhmedHanafy725 Feb 21, 2024
8b2817a
Get the reserved ips from zos instead of loop on all vms on this node
AhmedHanafy725 Feb 22, 2024
1840e6a
Add version 3 to the metadata
AhmedHanafy725 Feb 25, 2024
126c222
Disallow change the contract metadata by the user
AhmedHanafy725 Feb 25, 2024
2745adb
Merge branch 'development' into development_listing
AhmedHanafy725 Feb 25, 2024
aba9b0e
Merge branch 'development_listing' into development_load_networks
AhmedHanafy725 Feb 25, 2024
60d9490
Save the newly deployed contracts on the module to cover the delay fr…
AhmedHanafy725 Feb 25, 2024
fd07e71
Add the missing the fields for the resulted contracts
AhmedHanafy725 Feb 25, 2024
78ede80
Remove saving the network in the kvstore/filesystem
AhmedHanafy725 Feb 25, 2024
82b8e58
Store the user access on the network object instead of the node object
AhmedHanafy725 Feb 27, 2024
20e4235
Update kubernetes metadata
AhmedHanafy725 Feb 27, 2024
550b90b
Update scripts with the project name
AhmedHanafy725 Feb 27, 2024
f1dd744
Handle the case of the mount was set with null while getting the mach…
AhmedHanafy725 Feb 28, 2024
df14ae7
Return empty list for wireguard access in case there is no wireguard …
AhmedHanafy725 Feb 28, 2024
f747cb9
Update kubernetes projectname in the dashboard
AhmedHanafy725 Feb 29, 2024
a77edbf
Remove the repeated instances
AhmedHanafy725 Feb 29, 2024
6d21fed
Merge pull request #2239 from threefoldtech/development_load_networks
AhmedHanafy725 Mar 3, 2024
60f9260
Fix importing k8s worker as type
AhmedHanafy725 Mar 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/grid_client/src/clients/tf-grid/contracts.ts
Original file line number Diff line number Diff line change
@@ -141,6 +141,34 @@ class TFContracts extends Contracts {
}
}

async listNodeContractsByTwinId(options: ListContractByTwinIdOptions): Promise<GqlNodeContract[]> {
options.stateList = options.stateList || [ContractStates.Created, ContractStates.GracePeriod];
const state = `[${options.stateList.join(", ")}]`;
const gqlClient = new Graphql(options.graphqlURL);
const opts = `(where: {twinID_eq: ${options.twinId}, state_in: ${state}}, orderBy: twinID_ASC)`;
try {
const nodeContractsCount = await gqlClient.getItemTotalCount("nodeContracts", opts);
const body = `query getContracts($nodeContractsCount: Int!){
nodeContracts(where: {twinID_eq: ${options.twinId}, state_in: ${state}}, limit: $nodeContractsCount) {
contractID
deploymentData
state
createdAt
nodeID
numberOfPublicIPs
}
}`;
const response = await gqlClient.query(body, {
nodeContractsCount,
});

return (response["data"] as GqlContracts).nodeContracts;
} catch (err) {
(err as Error).message = formatErrorMessage(`Error listing contracts by twin id ${options.twinId}.`, err);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we introduce a new error class and use it here ?

throw err;
}
}

/**
* Get contract consumption per hour in TFT.
*
@@ -221,6 +249,15 @@ class TFContracts extends Contracts {
});
}

async listMyNodeContracts(options: ListMyContractOptions): Promise<GqlNodeContract[]> {
const twinId = await this.client.twins.getMyTwinId();
return await this.listNodeContractsByTwinId({
graphqlURL: options.graphqlURL,
twinId: twinId,
stateList: options.stateList,
});
}

async contractLock(options: ContractLockOptions) {
const res = await super.contractLock(options);
const amountLocked = new Decimal(res.amountLocked);
83 changes: 58 additions & 25 deletions packages/grid_client/src/modules/base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { GridClientErrors, ValidationError } from "@threefold/types";
import * as PATH from "path";

import { RMB } from "../clients";
import { GqlNodeContract, RMB } from "../clients";
import { TFClient } from "../clients/tf-grid/client";
import { GridClientConfig } from "../config";
import { formatErrorMessage } from "../helpers";
@@ -22,6 +22,13 @@ import { Workload, WorkloadTypes } from "../zos/workload";
import { Zmachine, ZmachineResult } from "../zos/zmachine";
import { Zmount } from "../zos/zmount";

const modulesNames = {
machines: "vm",
kubernetes: "kubernetes",
gateways: "gateway",
qsfs_zdbs: "QSFS",
zdb: "zdb",
};
class BaseModule {
moduleName = "";
projectName = "";
@@ -31,6 +38,7 @@ class BaseModule {
twinDeploymentHandler: TwinDeploymentHandler;
backendStorage: BackendStorage;
tfClient: TFClient;
contracts: GqlNodeContract[];

constructor(public config: GridClientConfig) {
this.projectName = config.projectName;
@@ -57,7 +65,7 @@ class BaseModule {
return PATH.join(this.config.storePath, this.projectName, this.moduleName, name);
}

async getDeploymentContracts(name: string) {
async getOldDeploymentContracts(name: string) {
const path = this.getNewDeploymentPath(name, "contracts.json");
const contracts = await this.backendStorage.load(path);
if (!contracts) {
@@ -66,22 +74,25 @@ class BaseModule {
return contracts;
}

async getDeploymentContracts(name: string) {
const contracts = await this.getMyContracts();
const filteredContracts = contracts.filter(c => {
const deploymentData = JSON.parse(c.deploymentData) as { name: string };
return deploymentData.name === name;
});
if (!filteredContracts) {
return [];
}
return filteredContracts;
}

async save(name: string, contracts: Record<string, unknown[]>) {
const contractsPath = PATH.join(this.getNewDeploymentPath(name), "contracts.json");
const wireguardPath = PATH.join(this.getDeploymentPath(name), `${name}.conf`);
const oldContracts = await this.getDeploymentContracts(name);
const oldContracts = await this.getOldDeploymentContracts(name);
let StoreContracts = oldContracts;
let backendOperations = [];

for (const contract of contracts["created"]) {
StoreContracts.push({
contract_id: contract["contractId"],
node_id: contract["contractType"]["nodeContract"]["nodeId"],
});
const contractPath = PATH.join(this.config.storePath, "contracts", `${contract["contractId"]}.json`);
const contractInfo = { projectName: this.projectName, moduleName: this.moduleName, deploymentName: name };
backendOperations = backendOperations.concat(await this.backendStorage.dump(contractPath, contractInfo));
}
for (const contract of contracts["deleted"]) {
StoreContracts = StoreContracts.filter(c => c["contract_id"] !== contract["contractId"]);
const contractPath = PATH.join(this.config.storePath, "contracts", `${contract["contractId"]}.json`);
@@ -147,9 +158,30 @@ class BaseModule {
await Promise.all(keys.map(__updatePath).flat(1));
}

private async getMyContracts(fetch = false) {
if (fetch || !this.contracts) {
this.contracts = await this.tfClient.contracts.listMyNodeContracts({ graphqlURL: this.config.graphqlURL });
}
return this.contracts.filter(c => {
const deploymentData = JSON.parse(c.deploymentData) as { type: string; name: string; projectName: string };
if (
(this.projectName === "" && deploymentData.projectName === this.projectName) ||
(this.projectName !== "" && deploymentData.projectName.startsWith(this.projectName))
)
if (deploymentData.type === modulesNames[this.moduleName]) return true;
return false;
});
}

async _list(): Promise<string[]> {
await this._migrateListKeys();
return this.backendStorage.list(this.getNewDeploymentPath(""));
//TODO: optimize it by doing the filtering directly on graphql
const contracts = await this.getMyContracts(true);
return contracts.map(c => {
const deploymentData = JSON.parse(c.deploymentData) as { name: string };
console.log(this.projectName, deploymentData.name);
return deploymentData.name;
});
}

async exists(name: string): Promise<boolean> {
@@ -166,29 +198,31 @@ class BaseModule {
}

async _getDeploymentNodeIds(name: string): Promise<number[]> {
const nodeIds = [];
const nodeIds: number[] = [];
const contracts = await this.getDeploymentContracts(name);
for (const contract of contracts) {
nodeIds.push(contract["node_id"]);
nodeIds.push(contract.nodeID);
}
return nodeIds;
}

async _getContractIdFromNodeId(name: string, nodeId: number): Promise<number> {
const contracts = await this.getDeploymentContracts(name);
for (const contract of contracts) {
if (contract["node_id"] === nodeId) {
return contract["contract_id"];
if (contract.nodeID === nodeId) {
return +contract.contractID;
}
}
return 0;
}
async _getNodeIdFromContractId(name: string, contractId: number): Promise<number> {
const contracts = await this.getDeploymentContracts(name);
for (const contract of contracts) {
if (contract["contract_id"] === contractId) {
return contract["node_id"];
if (+contract.contractID === contractId) {
return contract.nodeID;
}
}
return 0;
}

async _getWorkloadsByTypes(deploymentName: string, deployments, types: WorkloadTypes[]): Promise<Workload[]> {
@@ -294,14 +328,14 @@ class BaseModule {
}
await this.tfClient.connect();
for (const contract of contracts) {
const c = await this.tfClient.contracts.get({ id: contract["contract_id"] });
const c = await this.tfClient.contracts.get({ id: +contract.contractID });
if (c === null) {
await this.save(name, { created: [], deleted: [{ contractId: contract["contract_id"] }] });
await this.save(name, { created: [], deleted: [{ contractId: +contract.contractID }] });
continue;
}
const nodes = new Nodes(this.config.graphqlURL, this.config.proxyURL, this.config.rmbClient);
const node_twin_id = await nodes.getNodeTwinId(contract["node_id"]);
const payload = JSON.stringify({ contract_id: contract["contract_id"] });
const node_twin_id = await nodes.getNodeTwinId(contract.nodeID);
const payload = JSON.stringify({ contract_id: +contract.contractID });
let deployment;
try {
deployment = await this.rmb.request([node_twin_id], "zos.deployment.get", payload);
@@ -318,7 +352,7 @@ class BaseModule {
if (found) {
deployments.push(deployment);
} else {
await this.save(name, { created: [], deleted: [{ contractId: contract["contract_id"] }] });
await this.save(name, { created: [], deleted: [{ contractId: +contract.contractID }] });
}
}
return deployments;
@@ -569,7 +603,6 @@ class BaseModule {
}
finalTwinDeployments.push(twinDeployment);
const contracts = await this.twinDeploymentHandler.handle(finalTwinDeployments);
await this.save(deployment_name, contracts);
return { contracts: contracts };
}

2 changes: 1 addition & 1 deletion packages/grid_client/src/modules/zdb.ts
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ import { AddZDBModel, DeleteZDBModel, ZDBDeleteModel, ZDBGetModel, ZDBSModel } f
import { checkBalance } from "./utils";

class ZdbsModule extends BaseModule {
fileName = "zdbs.json";
moduleName = "zdb";
workloadTypes = [WorkloadTypes.zdb];
zdb: ZdbHL;
constructor(public config: GridClientConfig) {
12 changes: 4 additions & 8 deletions packages/playground/src/components/vm_deployment_table.vue
Original file line number Diff line number Diff line change
@@ -160,19 +160,15 @@ async function loadDeployments() {
await migrateModule(grid!.gateway);
}

const filter =
props.projectName.toLowerCase() === ProjectName.VM.toLowerCase()
? undefined
: ([vm]: [{ flist: string }]) => vm.flist.replace(/-/g, "").includes(props.projectName.toLowerCase());

const chunk3 =
props.projectName.toLowerCase() === ProjectName.Fullvm.toLowerCase()
? { count: 0, items: [] }
: await loadVms(updateGrid(grid!, { projectName: "" }), { filter });
props.projectName.toLowerCase() === ProjectName.VM.toLowerCase()
? await loadVms(updateGrid(grid!, { projectName: "" }))
: { count: 0, items: [] };
if (chunk3.count > 0 && migrateGateways) {
await migrateModule(grid!.gateway);
}

console.log({ chunk1, chunk2, chunk3 });
const vms = mergeLoadedDeployments(chunk1, chunk2, chunk3 as any);
failedDeployments.value = [
...(Array.isArray((chunk1 as any).failedDeployments) ? (chunk1 as any).failedDeployments : []),