diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b936944d15..8a81393441 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,9 +5,9 @@ name: Full Clients Build on: push: - branches: [development, development_314] + branches: [development, development_2.6] pull_request: - branches: [development, development_314] + branches: [development, development_2.6] jobs: build: diff --git a/.github/workflows/link_checker.yml b/.github/workflows/link_checker.yml new file mode 100644 index 0000000000..2714335414 --- /dev/null +++ b/.github/workflows/link_checker.yml @@ -0,0 +1,17 @@ +name: Link Checker + +on: + schedule: + - cron: '0 8 * * *' + +jobs: + check-links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Link Checker + id: checker + uses: docker://ghcr.io/threefoldfoundation/website-link-checker:latest + with: + args: 'https://staging.dashboard.dev.grid.tf -e 404 501 503 504 -w all' \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e7f17fccab..ba40884c5a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,9 +5,9 @@ name: Full Clients Lint on: push: - branches: [development, development_314] + branches: [development, development_2.6] pull_request: - branches: [development, development_314] + branches: [development, development_2.6] jobs: lint: diff --git a/.github/workflows/playground_build.yml b/.github/workflows/playground_build.yml index abbd78c1da..6301773009 100644 --- a/.github/workflows/playground_build.yml +++ b/.github/workflows/playground_build.yml @@ -6,13 +6,13 @@ on: push: branches: - development - - development_314 + - development_2.6 paths: - "packages/playground/**" pull_request: branches: - development - - development_314 + - development_2.6 paths: - "packages/playground/**" diff --git a/.github/workflows/stats_build.yaml b/.github/workflows/stats_build.yaml index 613f22293a..b17162672b 100644 --- a/.github/workflows/stats_build.yaml +++ b/.github/workflows/stats_build.yaml @@ -4,11 +4,11 @@ name: Stats Build on: push: - branches: [development, development_314] + branches: [development, development_2.6] paths: - "packages/stats/**" pull_request: - branches: [development, development_314] + branches: [development, development_2.6] paths: - "packages/stats/**" diff --git a/.github/workflows/yarn_audit.yml b/.github/workflows/yarn_audit.yml new file mode 100644 index 0000000000..4996ba7bae --- /dev/null +++ b/.github/workflows/yarn_audit.yml @@ -0,0 +1,24 @@ +# When the action is executed, it runs yarn audit command in all the paths that is mentioned in the input. The exit codes of the commands are compared and if it is greater than 7 (only high severity as of now), the action will try to fetch the open issues in the repo with the label provided in the input. The label is mandatory to prevent from creating duplicate issues. If there are no open issues with the given label in open state, the action will try to create a Github Issue with the details provided in the input. + +name: Full Clients Audit + +on: + push: + branches: [development, development_2.6] + pull_request: + branches: [development, development_2.6] + +jobs: + audit-and-open-issue: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Yarn Audit + uses: pragatheeswarans/yarn-audit-action@v1.0.0 + with: + token: ${{ github.token }} + label: 'audit' + title: "${{ github.workflow }}: Critical Security Vulnerability Identified" + description: 'High severity issues are identified in the repo.' + paths: | + . diff --git a/packages/grid_client/scripts/single_vm.ts b/packages/grid_client/scripts/single_vm.ts index a64ac5a9e4..cb0e66f0d2 100644 --- a/packages/grid_client/scripts/single_vm.ts +++ b/packages/grid_client/scripts/single_vm.ts @@ -1,23 +1,25 @@ -import { MachinesModel } from "../src"; +import { GridClient, MachinesModel } from "../src"; +import { type ZmachineData } from "../src/helpers/types"; import { config, getClient } from "./client_loader"; import { log } from "./utils"; -async function deploy(client, vms) { +async function deploy(client: GridClient, vms: MachinesModel) { const res = await client.machines.deploy(vms); log("================= Deploying VM ================="); log(res); log("================= Deploying VM ================="); } -async function getDeployment(client, vms) { - const res = await client.machines.getObj(vms); +async function getDeployment(client: GridClient, name: string): Promise { + const res = await client.machines.getObj(name); log("================= Getting deployment information ================="); log(res); log("================= Getting deployment information ================="); + return res; } -async function cancel(client, vms) { - const res = await client.machines.delete(vms); +async function cancel(client: GridClient, name: string) { + const res = await client.machines.delete({ name: name }); log("================= Canceling the deployment ================="); log(res); log("================= Canceling the deployment ================="); @@ -69,7 +71,7 @@ async function main() { await getDeployment(grid3, name); //Uncomment the line below to cancel the deployment - // await cancel(grid3, { name }); + // await cancel(grid3, name); await grid3.disconnect(); } diff --git a/packages/grid_client/src/helpers/index.ts b/packages/grid_client/src/helpers/index.ts index ef382c8e77..9426b9396b 100644 --- a/packages/grid_client/src/helpers/index.ts +++ b/packages/grid_client/src/helpers/index.ts @@ -4,3 +4,5 @@ export * from "./events"; export * from "./validator"; export * from "./expose"; export * from "./migration"; +export * from "./root_fs"; +export * from "./types"; diff --git a/packages/grid_client/src/helpers/root_fs.ts b/packages/grid_client/src/helpers/root_fs.ts new file mode 100644 index 0000000000..6988b959be --- /dev/null +++ b/packages/grid_client/src/helpers/root_fs.ts @@ -0,0 +1,39 @@ +import { Decimal } from "decimal.js"; + +const GB = 1024; + +interface RootFSOptions { + /** The machine CPU, should be in cores e.g. 5 cores*/ + CPUCores: number; + /** The machine memory, should be in megabytes e.g. 1024 or 2048 MG*/ + RAMInMegaBytes: number; +} + +/** + * Calculate the root filesystem size (CU - Compute Units) based on provided options. + * + * This function calculates the compute units (CU) required based on the CPU cores and RAM in megabytes. + * If both CPU cores and RAM are provided in the `options` parameter, it calculates CU by multiplying + * the CPU cores with RAM and dividing by 8 * GB, then converting the result to an integer. If the + * calculated CU is zero, it returns 500 / GB; otherwise, it returns 2. + * + * @param {RootFSOptions} [options] - Optional configuration object. + * @param {number} [options.CPUCores] - The number of CPU cores. + * @param {number} [options.RAMInMegaBytes] - The RAM size in megabytes. + * + * @returns {number} - The calculated compute units (CU) based on the provided options. + */ +function calculateRootFileSystem(options?: RootFSOptions): number { + let cu = 0; + + if (options && options.CPUCores && options.RAMInMegaBytes) { + cu = new Decimal(options.CPUCores) + .mul(options.RAMInMegaBytes) + .divToInt(8 * GB) + .toNumber(); + } + + return cu === 0 ? 500 / GB : 2; +} + +export { calculateRootFileSystem, RootFSOptions }; diff --git a/packages/grid_client/src/helpers/types.ts b/packages/grid_client/src/helpers/types.ts new file mode 100644 index 0000000000..3d1c9e7f8a --- /dev/null +++ b/packages/grid_client/src/helpers/types.ts @@ -0,0 +1,100 @@ +import { PublicIPResult, ResultStates } from "../zos"; + +interface NetworkInterface { + /** The network identifier */ + network: string; + /** The IP address of the interface */ + ip: string; +} + +interface ComputeCapacity { + /** Number of CPU cores allocated */ + cpu: number; + /** Amount of memory allocated in MB */ + memory: number; +} + +interface BaseMountData { + /** The name of the mount */ + name: string; + /** The mount point in the filesystem */ + mountPoint: string; +} + +interface ExtendedMountData extends BaseMountData { + /** The size of the mount (optional) */ + size?: number; + /** The state of the mount result (optional) */ + state?: ResultStates; + /** Message providing additional information about the mount result (optional) */ + message?: string; + /** Cache information (optional) */ + cache?: any; + /** Prefix information (optional) */ + prefix?: any; + /** Minimal shards (optional) */ + minimal_shards?: number; + /** Expected shards (optional) */ + expected_shards?: number; + /** QSFS ZDBs name (optional) */ + qsfs_zdbs_name?: string; + /** Metrics endpoint (optional) */ + metricsEndpoint?: string; +} + +// Union type for the mount data +type MountData = BaseMountData | ExtendedMountData; + +interface ZmachineData { + /** The version of the workload */ + version: number; + /** The contract ID associated with the workload */ + contractId: number; + /** The node ID where the workload is deployed */ + nodeId: string; + /** The name of the workload */ + name: string; + /** The creation timestamp of the workload result */ + created: number; + /** The current state of the workload */ + status: string; + /** Message providing additional information about the workload state */ + message: string; + /** The flist (file list) used by the workload */ + flist: string; + /** The public IP address obtained by the machine */ + publicIP: PublicIPResult; + /** The planetary IP address of the machine */ + planetary: string; + /** The Mycelium IP address of the machine, if applicable */ + myceliumIP: string; + /** List of network interfaces */ + interfaces: NetworkInterface[]; + /** The compute capacity (CPU and memory) allocated to the machine */ + capacity: ComputeCapacity; + /** List of mounts associated with the machine */ + mounts: MountData[]; + /** Environment variables set for the workload */ + env: Record; + /** The entrypoint command for the workload */ + entrypoint: string; + /** Metadata associated with the workload */ + metadata: string; + /** Description of the workload */ + description: string; + /** Size of the root filesystem */ + rootfs_size: number; + /** Indicates if corex is enabled */ + corex: boolean; + /** The list of the GPUs */ + gpu: string[] | undefined; +} + +interface VM extends ZmachineData { + customDomain?: string; + deploymentName: string; + projectName: string; + wireguard: string; +} + +export { ZmachineData, VM }; diff --git a/packages/grid_client/src/high_level/machine.ts b/packages/grid_client/src/high_level/machine.ts index d01821d906..0de7b154c1 100644 --- a/packages/grid_client/src/high_level/machine.ts +++ b/packages/grid_client/src/high_level/machine.ts @@ -2,6 +2,7 @@ import { GridClientErrors, ValidationError } from "@threefold/types"; import { Addr } from "netaddr"; import { events } from "../helpers/events"; +import { calculateRootFileSystem } from "../helpers/root_fs"; import { randomChoice, zeroPadding } from "../helpers/utils"; import { validateHexSeed } from "../helpers/validator"; import { DiskModel, MyceliumNetworkModel, QSFSDiskModel } from "../modules/models"; @@ -53,6 +54,12 @@ class VMHL extends HighLevelBase { zlogsOutput?: string, gpus: string[] = [], ): Promise<[TwinDeployment[], string]> { + if (!rootfs_size) { + rootfs_size = calculateRootFileSystem({ + CPUCores: cpu, + RAMInMegaBytes: memory, + }); + } const deployments: TwinDeployment[] = []; const workloads: Workload[] = []; let totalDisksSize = rootfs_size; diff --git a/packages/grid_client/src/modules/base.ts b/packages/grid_client/src/modules/base.ts index 3c474a1952..b7bf30f6c1 100644 --- a/packages/grid_client/src/modules/base.ts +++ b/packages/grid_client/src/modules/base.ts @@ -6,6 +6,7 @@ import { GqlNodeContract, RMB } from "../clients"; import { TFClient } from "../clients/tf-grid/client"; import { GridClientConfig } from "../config"; import { formatErrorMessage } from "../helpers"; +import { type ZmachineData } from "../helpers/types"; import { HighLevelBase } from "../high_level/base"; import { KubernetesHL } from "../high_level/kubernetes"; import { VMHL } from "../high_level/machine"; @@ -306,7 +307,7 @@ class BaseModule { return null; } - async _getZmachineData(deploymentName: string, deployments, workload: Workload): Promise> { + async _getZmachineData(deploymentName: string, deployments, workload: Workload): Promise { const data = workload.data as Zmachine; const resultData = workload.result.data as ZmachineResult; return { diff --git a/packages/grid_client/tests/modules/zmachine.test.ts b/packages/grid_client/tests/modules/zmachine.test.ts new file mode 100644 index 0000000000..1090f8d2c8 --- /dev/null +++ b/packages/grid_client/tests/modules/zmachine.test.ts @@ -0,0 +1,64 @@ +import { ComputeCapacity, Mount, Zmachine, ZmachineNetwork } from "../../src"; + +const zmachine = new Zmachine(); + +beforeAll(() => { + const computeCapacity = new ComputeCapacity(); + computeCapacity.cpu = 1; + computeCapacity.memory = 5; + + const network = new ZmachineNetwork(); + network.planetary = true; + network.public_ip = "10.249.0.0/16"; + network.interfaces = [ + { + network: "znetwork", + ip: "10.20.2.2", + }, + ]; + + const rootfs_size = 2; + + const disks = new Mount(); + disks.name = "zdisk"; + disks.mountpoint = "/mnt/data"; + + zmachine.flist = "https://hub.grid.tf/tf-official-vms/ubuntu-22.04.flist"; + zmachine.network = network; + zmachine.size = rootfs_size * 1024 ** 3; + zmachine.mounts = [disks]; + zmachine.entrypoint = "/sbin/zinit init"; + zmachine.compute_capacity = computeCapacity; + zmachine.env = {}; + zmachine.corex = false; + zmachine.gpu = []; +}); + +describe("Zmachine Class Tests", () => { + it("should create a valid Zmachine instance", () => { + expect(zmachine).toBeInstanceOf(Zmachine); + }); + + it("should correctly compute the challenge string", () => { + const expectedChallenge = + "https://hub.grid.tf/tf-official-vms/ubuntu-22.04.flist" + + "10.249.0.0/16" + + "true" + + "znetwork" + + "10.20.2.22" + + "14748364815" + + "zdisk" + + "/mnt/data" + + "/sbin/zinit init"; + + expect(zmachine.challenge()).toBe(expectedChallenge); + }); + + it("should fail validation for missing required fields", () => { + const result = () => { + zmachine.flist = ""; + zmachine.entrypoint = ""; + }; + expect(result).toThrow(); + }); +}); diff --git a/packages/grid_client/tests/modules/zmount.test.ts b/packages/grid_client/tests/modules/zmount.test.ts new file mode 100644 index 0000000000..81ee902ba9 --- /dev/null +++ b/packages/grid_client/tests/modules/zmount.test.ts @@ -0,0 +1,58 @@ +import { Zmount } from "../../src"; + +let zmount: Zmount; + +beforeEach(() => { + zmount = new Zmount(); +}); +describe("Zmount module", () => { + test("Zmount instance is of type Zmount.", () => { + expect(zmount).toBeInstanceOf(Zmount); + }); + + test("Min value for size.", () => { + const size = 100 * 1025 ** 2; + + zmount.size = size; + + const result = () => zmount.challenge(); + + expect(result).toThrow(); + }); + + test("Max value for size.", () => { + const size = 100 * 1025 ** 4; + + zmount.size = size; + + const result = () => zmount.challenge(); + + expect(result).toThrow(); + }); + + test("Size doesn't accept decimal value.", () => { + const size = 1.5; + + zmount.size = size; + + const result = () => zmount.challenge(); + + expect(result).toThrow(); + }); + + test("Size empty value.", () => { + const result = () => zmount.challenge(); + + expect(result).toThrow(); + }); + + test("Size negative value.", () => { + const negative_size = -1; + + zmount.size = negative_size; + + const result = () => zmount.challenge(); + + expect(result).toThrow(); + }); +}); diff --git a/packages/grid_client/tests/unittests/root_fs.test.ts b/packages/grid_client/tests/unittests/root_fs.test.ts new file mode 100644 index 0000000000..f4e07a1e79 --- /dev/null +++ b/packages/grid_client/tests/unittests/root_fs.test.ts @@ -0,0 +1,15 @@ +import { calculateRootFileSystem } from "../../src/helpers/root_fs"; + +describe("Calculate the rootFS size based on the machine specs", () => { + it("should return 2GB when the options are provided", () => { + const options = { CPUCores: 5, RAMInMegaBytes: 2048 }; + const result = calculateRootFileSystem(options); + expect(result).toEqual(2); + }); + + it("should return 0.48828125 when CPU cores and RAM are zero", () => { + const options = { CPUCores: 0, RAMInMegaBytes: 0 }; + const result = calculateRootFileSystem(options); + expect(result).toEqual(0.48828125); + }); +}); diff --git a/packages/playground/index.html b/packages/playground/index.html index e07e59fd7e..72f6262517 100644 --- a/packages/playground/index.html +++ b/packages/playground/index.html @@ -46,6 +46,7 @@
+
diff --git a/packages/playground/public/images/icons/gitea.png b/packages/playground/public/images/icons/gitea.png new file mode 100644 index 0000000000..f7d93493b2 Binary files /dev/null and b/packages/playground/public/images/icons/gitea.png differ diff --git a/packages/playground/public/images/icons/nostr.png b/packages/playground/public/images/icons/nostr.png new file mode 100644 index 0000000000..590dbb1a2e Binary files /dev/null and b/packages/playground/public/images/icons/nostr.png differ diff --git a/packages/playground/public/info/gitea.md b/packages/playground/public/info/gitea.md new file mode 100644 index 0000000000..99956b4dda --- /dev/null +++ b/packages/playground/public/info/gitea.md @@ -0,0 +1,5 @@ +--- +title: Gitea +--- + +Gitea is a forge software package for hosting software development version control using Git as well as other collaborative features like bug tracking, code review, continuous integration, kanban boards, tickets, and wikis. It supports self-hosting but also provides a free public first-party instance. diff --git a/packages/playground/public/info/nostr.md b/packages/playground/public/info/nostr.md new file mode 100644 index 0000000000..52b7cefaf6 --- /dev/null +++ b/packages/playground/public/info/nostr.md @@ -0,0 +1,5 @@ +--- +title: Nostr +--- + +Nostr is a simple, open protocol that enables global, decentralized, and censorship-resistant social media. diff --git a/packages/playground/src/App.vue b/packages/playground/src/App.vue index a7202dd780..3bb673370a 100644 --- a/packages/playground/src/App.vue +++ b/packages/playground/src/App.vue @@ -494,4 +494,12 @@ export default { .v-theme--dark .v-btn--disabled { color: #7b7b7b !important; } +body { + overflow: auto; + height: 100vh; +} + +html { + overflow: hidden; +} diff --git a/packages/playground/src/calculator/pricing_calculator.vue b/packages/playground/src/calculator/pricing_calculator.vue index 85556fefb0..3fbd8aabc0 100644 --- a/packages/playground/src/calculator/pricing_calculator.vue +++ b/packages/playground/src/calculator/pricing_calculator.vue @@ -171,7 +171,11 @@

-
+ +

Too expensive? can upgrade to Gold package to get discount up to 60% when you fund your wallet with {{ dedicatedUpgradePrice }} TFT @@ -198,7 +202,10 @@

-
+

Too expensive? can upgrade to Gold package to get discount up to 60% when you fund your wallet with {{ sharedUpgradePrice }} TFT @@ -222,7 +229,7 @@ + + diff --git a/packages/playground/src/components/caprover_worker.vue b/packages/playground/src/components/caprover_worker.vue index f6b24beac9..6b3a05ea8a 100644 --- a/packages/playground/src/components/caprover_worker.vue +++ b/packages/playground/src/components/caprover_worker.vue @@ -22,7 +22,7 @@ :small="{ cpu: 1, memory: 2, disk: 50 }" :medium="{ cpu: 2, memory: 4, disk: 100 }" /> - + @@ -36,6 +36,7 @@ :nodes-lock="nodesLock" :filters="{ ipv4: true, + ipv6: $props.modelValue.ipv6, certified: $props.modelValue.certified, dedicated: $props.modelValue.dedicated, cpu: $props.modelValue.solution?.cpu, @@ -49,6 +50,7 @@ diff --git a/packages/playground/src/components/list_table.vue b/packages/playground/src/components/list_table.vue index aa57732f04..edc36cb898 100644 --- a/packages/playground/src/components/list_table.vue +++ b/packages/playground/src/components/list_table.vue @@ -5,12 +5,13 @@ item-title="title" item-value="key" hover - :items-per-page="-1" hide-default-footer show-select v-model="selectedItems" hide-no-data :return-object="returnObject" + @update:options="selectedItems = []" + v-bind="$attrs" > - - - diff --git a/packages/playground/src/views/solutions_view.vue b/packages/playground/src/views/solutions_view.vue index fa6b72ddcd..00e297f78b 100644 --- a/packages/playground/src/views/solutions_view.vue +++ b/packages/playground/src/views/solutions_view.vue @@ -5,56 +5,39 @@ Applications - - - - - - - -

No solution was found with the provided search query.

- + +

No solution was found with the provided search query.

- - diff --git a/packages/playground/src/views/stats.vue b/packages/playground/src/views/stats.vue index 53fd755054..16b1bbed06 100644 --- a/packages/playground/src/views/stats.vue +++ b/packages/playground/src/views/stats.vue @@ -14,8 +14,8 @@ - - + + Failed to get stats data after 3 attempts, Feel free to contact the support team or try again later. @@ -24,14 +24,21 @@ - + - - - - - + + + + + + diff --git a/packages/playground/src/views/vms_view.vue b/packages/playground/src/views/vms_view.vue index 916a448ce0..bbb348944d 100644 --- a/packages/playground/src/views/vms_view.vue +++ b/packages/playground/src/views/vms_view.vue @@ -4,50 +4,22 @@ mdi-television Virtual Machines - - - - - - - - + - - diff --git a/packages/playground/src/weblets/freeflow.vue b/packages/playground/src/weblets/freeflow.vue index 7a88321bdd..4a53e60d29 100644 --- a/packages/playground/src/weblets/freeflow.vue +++ b/packages/playground/src/weblets/freeflow.vue @@ -46,7 +46,7 @@ :large="{ cpu: 4, memory: 32, disk: 1000 }" /> - + @@ -59,6 +59,7 @@ -import type { GridClient } from "@threefold/grid_client"; +import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client"; import { computed, onMounted, type Ref, ref } from "vue"; import { manual } from "@/utils/manual"; @@ -103,7 +104,10 @@ const disks = ref([]); const dedicated = ref(false); const certified = ref(false); const ipv4 = ref(false); -const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0)); +const ipv6 = ref(false); +const rootFilesystemSize = computed(() => + calculateRootFileSystem({ CPUCores: solution.value?.cpu ?? 0, RAMInMegaBytes: solution.value?.memory ?? 0 }), +); const selectionDetails = ref(); const selectedSSHKeys = ref(""); const gridStore = useGrid(); @@ -160,6 +164,7 @@ async function deploy() { flist: flist?.value!.value, entryPoint: flist.value!.entryPoint, publicIpv4: ipv4.value, + publicIpv6: ipv6.value, envs: [ { key: "SSH_KEY", value: selectedSSHKeys.value }, { key: "USER_ID", value: threebotName.value }, @@ -214,7 +219,6 @@ import ManageSshDeployemnt from "../components/ssh_keys/ManageSshDeployemnt.vue" import { deploymentListEnvironments } from "../constants"; import type { SelectionDetails } from "../types/nodeSelector"; import { updateGrid } from "../utils/grid"; -import rootFs from "../utils/root_fs"; export default { name: "TFFreeflow", diff --git a/packages/playground/src/weblets/profile_manager.vue b/packages/playground/src/weblets/profile_manager.vue index 5acece2b69..4eada15053 100644 --- a/packages/playground/src/weblets/profile_manager.vue +++ b/packages/playground/src/weblets/profile_manager.vue @@ -4,6 +4,7 @@ class="mx-auto" :model-value="$props.modelValue" @update:model-value="handleProfileDialog($event)" + attach="#modals" > @@ -305,6 +309,7 @@ ...validationProps, }" :disabled="creatingAccount || activatingAccount || activating" + autocomplete="off" /> diff --git a/packages/playground/src/weblets/tf_algorand.vue b/packages/playground/src/weblets/tf_algorand.vue index 3f0cf97b2f..beaeff3a44 100644 --- a/packages/playground/src/weblets/tf_algorand.vue +++ b/packages/playground/src/weblets/tf_algorand.vue @@ -28,9 +28,7 @@ - - - + ; const memory = ref() as Ref; @@ -172,8 +173,9 @@ async function deploy() { : [], rootFilesystemSize: rootFilesystemSize.value, publicIpv4: ipv4.value, + publicIpv6: ipv6.value, mycelium: mycelium.value, - planetary: true, + planetary: planetary.value, nodeId: selectionDetails.value!.node!.nodeId, rentedBy: dedicated.value ? grid!.twinId : undefined, certified: certified.value, diff --git a/packages/playground/src/weblets/tf_caprover.vue b/packages/playground/src/weblets/tf_caprover.vue index 8c8875de88..1bc534d27d 100644 --- a/packages/playground/src/weblets/tf_caprover.vue +++ b/packages/playground/src/weblets/tf_caprover.vue @@ -6,8 +6,18 @@ :disk=" workers.reduce( (disk, worker) => - disk + (worker.solution?.disk ?? 0) + rootFs(worker.solution?.cpu ?? 0, worker.solution?.memory ?? 0), - leader.solution?.disk ?? 0 + rootFs(leader.solution?.cpu ?? 0, leader.solution?.memory ?? 0), + disk + + (worker.solution?.disk ?? 0) + + calculateRootFileSystem({ + CPUCores: worker.solution?.cpu ?? 0, + RAMInMegaBytes: worker.solution?.memory ?? 0, + }), + leader.solution?.disk ?? + 0 + + calculateRootFileSystem({ + CPUCores: leader.solution?.cpu ?? 0, + RAMInMegaBytes: leader.solution?.memory ?? 0, + }), ) " :ipv4="true" @@ -174,7 +184,12 @@ function normalizeCaproverWorker(worker: CW, envs: Env[]): Machine { publicIpv4: true, planetary: true, mycelium: worker.mycelium || false, - rootFilesystemSize: rootFs(worker.solution!.cpu, worker.solution!.memory), + publicIpv6: worker.ipv6 || false, + + rootFilesystemSize: calculateRootFileSystem({ + CPUCores: worker.solution!.cpu, + RAMInMegaBytes: worker.solution!.memory, + }), disks: [ { name: "data0", @@ -195,7 +210,7 @@ function updateSSHkeyEnv(selectedKeys: string) { + + diff --git a/packages/playground/src/weblets/tf_mattermost.vue b/packages/playground/src/weblets/tf_mattermost.vue index 0a8a805d7d..69fc8b97b7 100644 --- a/packages/playground/src/weblets/tf_mattermost.vue +++ b/packages/playground/src/weblets/tf_mattermost.vue @@ -42,7 +42,7 @@ :medium="{ cpu: 2, memory: 4, disk: 50 }" :large="{ cpu: 4, memory: 16, disk: 100 }" /> - + @@ -55,6 +55,7 @@ -import type { GridClient } from "@threefold/grid_client"; +import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client"; import { computed, type Ref, ref, watch } from "vue"; import { manual } from "@/utils/manual"; @@ -106,8 +107,12 @@ const flist: Flist = { const dedicated = ref(false); const certified = ref(false); const ipv4 = ref(false); +const ipv6 = ref(false); +const planetary = ref(true); const smtp = ref(createSMTPServer()); -const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0)); +const rootFilesystemSize = computed(() => + calculateRootFileSystem({ CPUCores: solution.value?.cpu ?? 0, RAMInMegaBytes: solution.value?.memory ?? 0 }), +); const selectionDetails = ref(); const mycelium = ref(true); const selectedSSHKeys = ref(""); @@ -164,7 +169,8 @@ async function deploy() { entryPoint: flist.entryPoint, rootFilesystemSize: rootFilesystemSize.value, publicIpv4: ipv4.value, - planetary: true, + publicIpv6: ipv6.value, + planetary: planetary.value, mycelium: mycelium.value, envs: [ { key: "SSH_KEY", value: selectedSSHKeys.value }, @@ -246,7 +252,6 @@ import ManageSshDeployemnt from "../components/ssh_keys/ManageSshDeployemnt.vue" import { deploymentListEnvironments } from "../constants"; import type { SelectionDetails } from "../types/nodeSelector"; import { normalizeError } from "../utils/helpers"; -import rootFs from "../utils/root_fs"; export default { name: "TfMattermost", diff --git a/packages/playground/src/weblets/tf_nextcloud.vue b/packages/playground/src/weblets/tf_nextcloud.vue index ac56cd57c1..f7de9e86c8 100644 --- a/packages/playground/src/weblets/tf_nextcloud.vue +++ b/packages/playground/src/weblets/tf_nextcloud.vue @@ -36,7 +36,7 @@ :large="{ cpu: 4, memory: 16, disk: 1000 }" v-model="solution" /> - + @@ -49,6 +49,7 @@ -import type { GridClient } from "@threefold/grid_client"; +import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client"; import { computed, type Ref, ref } from "vue"; import { manual } from "@/utils/manual"; @@ -96,8 +97,12 @@ const flist: Flist = { const dedicated = ref(false); const certified = ref(false); const ipv4 = ref(false); +const ipv6 = ref(false); const mycelium = ref(true); -const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0)); +const planetary = ref(false); +const rootFilesystemSize = computed(() => + calculateRootFileSystem({ CPUCores: solution.value?.cpu ?? 0, RAMInMegaBytes: solution.value?.memory ?? 0 }), +); const selectionDetails = ref(); const selectedSSHKeys = ref(""); const gridStore = useGrid(); @@ -158,6 +163,8 @@ async function deploy() { flist: flist.value, entryPoint: flist.entryPoint, publicIpv4: ipv4.value, + publicIpv6: ipv6.value, + planetary: planetary.value, mycelium: mycelium.value, envs: [ { key: "SSH_KEY", value: selectedSSHKeys.value }, @@ -214,7 +221,6 @@ import ManageSshDeployemnt from "../components/ssh_keys/ManageSshDeployemnt.vue" import { deploymentListEnvironments } from "../constants"; import type { SelectionDetails } from "../types/nodeSelector"; import { updateGrid } from "../utils/grid"; -import rootFs from "../utils/root_fs"; export default { name: "TFNextcloud", diff --git a/packages/playground/src/weblets/tf_node_pilot.vue b/packages/playground/src/weblets/tf_node_pilot.vue index bdc26b639a..6e1c08fed1 100644 --- a/packages/playground/src/weblets/tf_node_pilot.vue +++ b/packages/playground/src/weblets/tf_node_pilot.vue @@ -35,6 +35,13 @@ :large="{ cpu: 8, memory: 32, disk: 2000 }" v-model="solution" /> + @@ -55,6 +62,7 @@ rootFilesystemSize, }" v-model="selectionDetails" + require-domain /> @@ -71,8 +79,9 @@ import { type Ref, ref } from "vue"; import { manual } from "@/utils/manual"; +import Network from "../components/networks.vue"; import { useLayout } from "../components/weblet_layout.vue"; -import { useGrid } from "../stores"; +import { useGrid, useProfileManager } from "../stores"; import { type Flist, ProjectName } from "../types"; import { deployVM } from "../utils/deploy_vm"; import { generateName } from "../utils/strings"; @@ -83,6 +92,10 @@ const flist: Flist = { value: "https://hub.grid.tf/tf-official-vms/node-pilot-zdbfs.flist", entryPoint: "/", }; +const ipv4 = ref(false); +const ipv6 = ref(false); +const planetary = ref(true); +const mycelium = ref(true); const dedicated = ref(false); const certified = ref(false); const rootFilesystemSize = 2; @@ -90,20 +103,41 @@ const selectionDetails = ref(); const selectedSSHKeys = ref(""); const gridStore = useGrid(); const grid = gridStore.client as GridClient; +const profileManager = useProfileManager(); +function finalize(deployment: any) { + layout.value.reloadDeploymentsList(); + layout.value.setStatus("success", "Successfully deployed a Node Pilot instance."); + layout.value.openDialog(deployment, deploymentListEnvironments.nodepilot); +} async function deploy() { layout.value.setStatus("deploy"); const projectName = ProjectName.NodePilot.toLowerCase() + "/" + name.value; + const subdomain = getSubdomain({ + deploymentName: name.value, + projectName, + twinId: profileManager.profile!.twinId, + }); + + const domain = selectionDetails.value?.domain?.enabledCustomDomain + ? selectionDetails.value.domain.customDomain + : subdomain + "." + selectionDetails.value?.domain?.selectedDomain?.publicConfig.domain; + + let vm: VM[]; + try { layout.value?.validateSSH(); updateGrid(grid, { projectName }); await layout.value.validateBalance(grid!); - - const vm = await deployVM(grid!, { + vm = await deployVM(grid!, { name: name.value, + network: { + addAccess: selectionDetails.value!.domain!.enableSelectedDomain, + accessNodeId: selectionDetails.value!.domain?.selectedDomain?.nodeId, + }, machines: [ { name: name.value, @@ -111,10 +145,14 @@ async function deploy() { memory: solution.value.memory, flist: flist.value, entryPoint: flist.entryPoint, - publicIpv4: true, - publicIpv6: true, - planetary: false, - envs: [{ key: "SSH_KEY", value: selectedSSHKeys.value }], + publicIpv4: ipv4.value, + publicIpv6: ipv6.value, + planetary: planetary.value, + mycelium: mycelium.value, + envs: [ + { key: "SSH_KEY", value: selectedSSHKeys.value }, + { key: "NODE_PILOT_HOSTNAME", value: domain }, + ], rootFilesystemSize, disks: [ { @@ -128,10 +166,28 @@ async function deploy() { }, ], }); - - layout.value.reloadDeploymentsList(); - layout.value.setStatus("success", "Successfully deployed a node pilot instance."); - layout.value.openDialog(vm, deploymentListEnvironments.vm); + if (!selectionDetails.value?.domain?.enableSelectedDomain) { + vm[0].customDomain = selectionDetails.value?.domain?.customDomain; + finalize(vm); + return; + } + + try { + layout.value.setStatus("deploy", "Preparing to deploy gateway..."); + await deployGatewayName(grid, selectionDetails.value.domain, { + subdomain, + ip: vm[0].interfaces[0].ip, + port: 34416, + network: vm[0].interfaces[0].network, + }); + + finalize(vm); + } catch (e) { + layout.value.setStatus("deploy", "Rollbacking back due to fail to deploy gateway..."); + + await rollbackDeployment(grid!, name.value); + layout.value.setStatus("failed", normalizeError(e, "Failed to deploy a Node Pilot instance.")); + } } catch (e) { layout.value.setStatus("failed", normalizeError(e, "Failed to deploy a Node Pilot instance.")); } @@ -143,13 +199,14 @@ function updateSSHkeyEnv(selectedKeys: string) { + + diff --git a/packages/playground/src/weblets/tf_owncloud.vue b/packages/playground/src/weblets/tf_owncloud.vue index 664094bbda..23ef8540be 100644 --- a/packages/playground/src/weblets/tf_owncloud.vue +++ b/packages/playground/src/weblets/tf_owncloud.vue @@ -80,7 +80,7 @@ :medium="{ cpu: 4, memory: 16, disk: 500 }" :large="{ cpu: 8, memory: 32, disk: 1000 }" /> - + @@ -92,6 +92,7 @@ -import type { GridClient } from "@threefold/grid_client"; +import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client"; import { computed, type Ref, ref, watch } from "vue"; import { manual } from "@/utils/manual"; @@ -150,9 +151,12 @@ const flist: Flist = { const dedicated = ref(false); const certified = ref(false); const ipv4 = ref(false); +const ipv6 = ref(false); const mycelium = ref(true); const smtp = ref(createSMTPServer()); -const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0)); +const rootFilesystemSize = computed(() => + calculateRootFileSystem({ CPUCores: solution.value?.cpu ?? 0, RAMInMegaBytes: solution.value?.memory ?? 0 }), +); const selectedSSHKeys = ref(""); const gridStore = useGrid(); const grid = gridStore.client as GridClient; @@ -205,6 +209,7 @@ async function deploy() { entryPoint: flist.entryPoint, rootFilesystemSize: rootFilesystemSize.value, publicIpv4: ipv4.value, + publicIpv6: ipv6.value, planetary: true, mycelium: mycelium.value, envs: [ @@ -291,7 +296,6 @@ import { deploymentListEnvironments } from "../constants"; import type { SelectionDetails } from "../types/nodeSelector"; import { updateGrid } from "../utils/grid"; import { normalizeError } from "../utils/helpers"; -import rootFs from "../utils/root_fs"; export default { name: "TfOwncloud", diff --git a/packages/playground/src/weblets/tf_peertube.vue b/packages/playground/src/weblets/tf_peertube.vue index d891978123..a95363861d 100644 --- a/packages/playground/src/weblets/tf_peertube.vue +++ b/packages/playground/src/weblets/tf_peertube.vue @@ -63,7 +63,7 @@ - + @@ -76,6 +76,7 @@ -import type { GridClient } from "@threefold/grid_client"; +import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client"; import { computed, type Ref, ref } from "vue"; import { manual } from "@/utils/manual"; @@ -123,9 +124,13 @@ const flist: Flist = { const dedicated = ref(false); const certified = ref(false); const ipv4 = ref(false); -const rootFilesystemSize = computed(() => rootFs(solution.value?.cpu ?? 0, solution.value?.memory ?? 0)); +const ipv6 = ref(false); +const rootFilesystemSize = computed(() => + calculateRootFileSystem({ CPUCores: solution.value?.cpu ?? 0, RAMInMegaBytes: solution.value?.memory ?? 0 }), +); const selectionDetails = ref(); const mycelium = ref(true); +const planetary = ref(true); const selectedSSHKeys = ref(""); const gridStore = useGrid(); const grid = gridStore.client as GridClient; @@ -177,7 +182,8 @@ async function deploy() { flist: flist.value, entryPoint: flist.entryPoint, publicIpv4: ipv4.value, - planetary: true, + publicIpv6: ipv6.value, + planetary: planetary.value, mycelium: mycelium.value, envs: [ { key: "SSH_KEY", value: selectedSSHKeys.value }, @@ -234,7 +240,6 @@ import { deploymentListEnvironments } from "../constants"; import type { SelectionDetails } from "../types/nodeSelector"; import { updateGrid } from "../utils/grid"; import { normalizeError } from "../utils/helpers"; -import rootFs from "../utils/root_fs"; export default { name: "TfPeertube", diff --git a/packages/playground/src/weblets/tf_presearch.vue b/packages/playground/src/weblets/tf_presearch.vue index 0904085636..a70bfe156b 100644 --- a/packages/playground/src/weblets/tf_presearch.vue +++ b/packages/playground/src/weblets/tf_presearch.vue @@ -57,7 +57,14 @@ - + @@ -69,6 +76,7 @@