diff --git a/.github/workflows/grid_client_tests.yml b/.github/workflows/grid_client_tests.yml index 36f1edcea0..1670aa7462 100644 --- a/.github/workflows/grid_client_tests.yml +++ b/.github/workflows/grid_client_tests.yml @@ -48,6 +48,13 @@ jobs: sudo sed -i -- 's/Peers\: \[\]/Peers: [\n'"$PEERS"']/g' /etc/yggdrasil/yggdrasil.conf sudo systemctl stop yggdrasil sudo systemctl start yggdrasil + - name: Install Mycelium + run: | + sudo apt-get update + wget https://github.com/threefoldtech/mycelium/releases/download/v0.5.6/mycelium-x86_64-unknown-linux-musl.tar.gz + tar -xvf mycelium-x86_64-unknown-linux-musl.tar.gz + mv mycelium /usr/local/bin + sudo mycelium --peers tcp://188.40.132.242:9651 quic://185.69.166.8:9651 --tun-name utun9 & - name: Generate SSH Key run: | ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_ed25519 diff --git a/packages/grid_client/tests/README.md b/packages/grid_client/tests/README.md index 71c752de18..d9fa640695 100644 --- a/packages/grid_client/tests/README.md +++ b/packages/grid_client/tests/README.md @@ -42,3 +42,5 @@ yarn test --runInBand > `--coverage`: Collect and report coverage. > `--colors`: Force colorful output. > `--forceExit`: Force the process to exit after tests complete. +> +> **Note:** Some tests are using Mycelium for the SSH connection, which is why it is important for Mycelium to be running. diff --git a/packages/grid_client/tests/modules/kubernetes.test.ts b/packages/grid_client/tests/modules/kubernetes.test.ts index 7873f8eaf8..c897b354b5 100644 --- a/packages/grid_client/tests/modules/kubernetes.test.ts +++ b/packages/grid_client/tests/modules/kubernetes.test.ts @@ -159,7 +159,7 @@ test("TC1231 - Kubernetes: Deploy a Kubernetes Cluster", async () => { public_ip: masterPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], workers: [ @@ -173,7 +173,7 @@ test("TC1231 - Kubernetes: Deploy a Kubernetes Cluster", async () => { public_ip: workerPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], metadata: metadata, @@ -196,6 +196,7 @@ test("TC1231 - Kubernetes: Deploy a Kubernetes Cluster", async () => { expect(result.masters[0].nodeId).toBe(masterNodeId); expect(result.masters[0].status).toBe("ok"); expect(result.masters[0].planetary).toBeDefined(); + expect(result.masters[0].myceliumIP).toBeDefined(); expect(result.masters[0].publicIP).toBeNull(); expect(result.masters[0].interfaces[0]["network"]).toBe(networkName); expect(result.masters[0].interfaces[0]["ip"]).toContain(splitIP(ipRange)); @@ -211,6 +212,7 @@ test("TC1231 - Kubernetes: Deploy a Kubernetes Cluster", async () => { expect(result.workers[0].nodeId).toBe(workerNodeId); expect(result.workers[0].status).toBe("ok"); expect(result.workers[0].planetary).toBeDefined(); + expect(result.workers[0].myceliumIP).toBeDefined(); expect(result.workers[0].publicIP).toBeNull(); expect(result.workers[0].interfaces[0]["network"]).toBe(networkName); expect(result.workers[0].interfaces[0]["ip"]).toContain(splitIP(ipRange)); @@ -285,7 +287,7 @@ test("TC1231 - Kubernetes: Deploy a Kubernetes Cluster", async () => { } }); -test("TC1232 - Kubernetes: Add Worker", async () => { +test.skip("TC1232 - Kubernetes: Add Worker", async () => { /********************************************** Test Suite: Grid3_Client_TS (Automated) Test Cases: TC1232 - Kubernetes: Add Worker @@ -425,7 +427,7 @@ test("TC1232 - Kubernetes: Add Worker", async () => { public_ip: masterPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], workers: [ @@ -439,7 +441,7 @@ test("TC1232 - Kubernetes: Add Worker", async () => { public_ip: workerPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], metadata: metadata, @@ -459,7 +461,7 @@ test("TC1232 - Kubernetes: Add Worker", async () => { public_ip: workerPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }; const res = await gridClient.k8s.deploy(k8s); @@ -491,6 +493,7 @@ test("TC1232 - Kubernetes: Add Worker", async () => { expect(newResult.workers[1].nodeId).toBe(workerNodeId); expect(newResult.workers[1].status).toBe("ok"); expect(newResult.workers[1].planetary).toBeDefined(); + expect(newResult.workers[1].myceliumIP).toBeDefined(); expect(newResult.workers[1].publicIP).toBeNull(); expect(newResult.workers[1].interfaces[0]["network"]).toBe(networkName); expect(newResult.workers[1].interfaces[0]["ip"]).toContain(splitIP(ipRange)); @@ -679,7 +682,7 @@ test("TC1233 - Kubernetes: Delete Worker", async () => { public_ip: masterPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], workers: [ @@ -693,7 +696,7 @@ test("TC1233 - Kubernetes: Delete Worker", async () => { public_ip: workerPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], metadata: metadata, diff --git a/packages/grid_client/tests/modules/qsfs.test.ts b/packages/grid_client/tests/modules/qsfs.test.ts index 4809ec2df3..517600391c 100644 --- a/packages/grid_client/tests/modules/qsfs.test.ts +++ b/packages/grid_client/tests/modules/qsfs.test.ts @@ -199,7 +199,7 @@ test("TC1234 - QSFS: Deploy QSFS underneath a VM", async () => { entrypoint: "/sbin/zinit init", public_ip: publicIP, planetary: true, - mycelium: false, + mycelium: true, qsfs_disks: [ { qsfs_zdbs_name: qsfsZdbName, @@ -250,6 +250,7 @@ test("TC1234 - QSFS: Deploy QSFS underneath a VM", async () => { expect(result[0].capacity["cpu"]).toBe(cpu); expect(result[0].capacity["memory"]).toBe(memory); expect(result[0].planetary).toBeDefined(); + expect(result[0].myceliumIP).toBeDefined(); expect(result[0].publicIP).toBeNull(); expect(result[0].description).toBe(description); @@ -537,7 +538,7 @@ test("TC1235 - QSFS: Deploy QSFS Underneath a Kubernetes Cluster", async () => { public_ip: masterPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, qsfs_disks: qsfsDisk, }, ], @@ -552,7 +553,7 @@ test("TC1235 - QSFS: Deploy QSFS Underneath a Kubernetes Cluster", async () => { public_ip: workerPublicIp, public_ip6: false, planetary: true, - mycelium: false, + mycelium: true, }, ], metadata: metadata, @@ -575,6 +576,7 @@ test("TC1235 - QSFS: Deploy QSFS Underneath a Kubernetes Cluster", async () => { expect(result.masters[0].nodeId).toBe(masterNodeId); expect(result.masters[0].status).toBe("ok"); expect(result.masters[0].planetary).toBeDefined(); + expect(result.masters[0].myceliumIP).toBeDefined(); expect(result.masters[0].publicIP).toBeNull(); expect(result.masters[0].interfaces[0]["network"]).toBe(networkName); expect(result.masters[0].interfaces[0]["ip"]).toContain(splitIP(ipRange)); @@ -599,6 +601,7 @@ test("TC1235 - QSFS: Deploy QSFS Underneath a Kubernetes Cluster", async () => { expect(result.workers[0].nodeId).toBe(workerNodeId); expect(result.workers[0].status).toBe("ok"); expect(result.workers[0].planetary).toBeDefined(); + expect(result.workers[0].myceliumIP).toBeDefined(); expect(result.workers[0].publicIP).toBeNull(); expect(result.workers[0].interfaces[0]["network"]).toBe(networkName); expect(result.workers[0].interfaces[0]["ip"]).toContain(splitIP(ipRange)); @@ -648,9 +651,9 @@ test("TC1235 - QSFS: Deploy QSFS Underneath a Kubernetes Cluster", async () => { await masterSSH.execCommand("df -h").then(async function (result) { const splittedRes = result.stdout.split("\n"); log(result.stdout); - log(splittedRes[6]); - expect(splittedRes[6]).toContain(qsfsName); - expect(splittedRes[6]).toContain(qsfsMountPoint); + log(splittedRes[5]); + expect(splittedRes[5]).toContain(qsfsName); + expect(splittedRes[5]).toContain(qsfsMountPoint); }); } finally { //Disconnect from the master diff --git a/packages/grid_client/tests/modules/vm.test.ts b/packages/grid_client/tests/modules/vm.test.ts index 8825b53ac2..73c982a31d 100644 --- a/packages/grid_client/tests/modules/vm.test.ts +++ b/packages/grid_client/tests/modules/vm.test.ts @@ -97,12 +97,12 @@ test("TC1228 - VM: Deploy a VM", async () => { cpu: cpu, memory: memory, rootfs_size: rootfsSize, - mycelium: false, disks: disks, flist: "https://hub.grid.tf/tf-official-apps/threefoldtech-ubuntu-22.04.flist", entrypoint: "/sbin/zinit init", public_ip: publicIP, planetary: true, + mycelium: true, env: { SSH_KEY: config.ssh_key, Test_KEY: envVarValue, @@ -144,6 +144,7 @@ test("TC1228 - VM: Deploy a VM", async () => { expect(result[0].capacity["cpu"]).toBe(cpu); expect(result[0].capacity["memory"]).toBe(memory); expect(result[0].planetary).toBeDefined(); + expect(result[0].myceliumIP).toBeDefined(); expect(result[0].publicIP).toBeNull(); expect(result[0].description).toBe(description); @@ -180,6 +181,169 @@ test("TC1228 - VM: Deploy a VM", async () => { } }); +test("TC2847 - VM: Deploy a VM With Mycelium", async () => { + /********************************************** + Test Suite: Grid3_Client_TS (Automated) + Test Cases: TC2847 - VM: Deploy a VM With Mycelium + Scenario: + - Generate Test Data/VM Config. + - Select a Node To Deploy the VM on. + - Deploy the VM. + - Assert that the generated data matches + the deployment details. + - SSH to the VM and Verify that you can + access it With Mycelium. + - Assert that the Environment Variables + Were passed successfully to the VM + - Verify the resources of the VM. + **********************************************/ + + //Test Data + let cpu = generateInt(1, 4); + let memory = generateInt(256, 4096); + let rootfsSize = generateInt(2, 5); + const networkName = generateString(15); + const vmName = generateString(15); + const disks = []; + const publicIP = false; + const ipRangeClassA = "10." + generateInt(1, 255) + ".0.0/16"; + const ipRangeClassB = "172." + generateInt(16, 31) + ".0.0/16"; + const ipRangeClassC = "192.168.0.0/16"; + const ipRange = randomChoice([ipRangeClassA, ipRangeClassB, ipRangeClassC]); + const metadata = "{'deploymentType': 'vm'}"; + const description = "test deploying VM with Mycelium via ts grid3 client"; + const envVarValue = generateString(30); + + //Node Selection + let nodes; + try { + nodes = await gridClient.capacity.filterNodes({ + cru: cpu, + mru: memory / 1024, + sru: rootfsSize, + farmId: 1, + availableFor: await gridClient.twins.get_my_twin_id(), + } as FilterOptions); + } catch (error) { + //Log the resources that were not found. + log("A Node was not found with the generated resources." + error); + log("Regenerating test data with lower resources...."); + + //Generate lower resources. + cpu = generateInt(1, cpu); + memory = generateInt(256, memory); + rootfsSize = generateInt(2, rootfsSize); + + //Search for another node with lower resources. + nodes = await gridClient.capacity.filterNodes({ + cru: cpu, + mru: memory / 1024, + sru: rootfsSize, + farmId: 1, + availableFor: await gridClient.twins.get_my_twin_id(), + } as FilterOptions); + } + const nodeId = await getOnlineNode(nodes); + if (nodeId == -1) throw new Error("no nodes available to complete this test"); + + //VM Model + const vms: MachinesModel = { + name: deploymentName, + network: { + name: networkName, + ip_range: ipRange, + }, + machines: [ + { + name: vmName, + node_id: nodeId, + cpu: cpu, + memory: memory, + rootfs_size: rootfsSize, + disks: disks, + flist: "https://hub.grid.tf/tf-official-apps/threefoldtech-ubuntu-22.04.flist", + entrypoint: "/sbin/zinit init", + public_ip: publicIP, + planetary: true, + mycelium: true, + env: { + SSH_KEY: config.ssh_key, + Test_KEY: envVarValue, + }, + solutionProviderId: null, + }, + ], + metadata: metadata, + description: description, + }; + + const res = await gridClient.machines.deploy(vms); + log(res); + + //Contracts Assertions + expect(res.contracts.created).toHaveLength(1); + expect(res.contracts.updated).toHaveLength(0); + expect(res.contracts.deleted).toHaveLength(0); + + const vmsList = await gridClient.machines.list(); + log(vmsList); + + //VM List Assertions + expect(vmsList.length).toBeGreaterThanOrEqual(1); + expect(vmsList).toContain(vms.name); + + const result = await gridClient.machines.getObj(vms.name); + log(result); + + //VM Assertions + expect(result[0].nodeId).toBe(nodeId); + expect(result[0].status).toBe("ok"); + expect(result[0].flist).toBe(vms.machines[0].flist); + expect(result[0].entrypoint).toBe(vms.machines[0].entrypoint); + expect(result[0].mounts).toHaveLength(0); + expect(result[0].interfaces[0]["network"]).toBe(vms.network.name); + expect(result[0].interfaces[0]["ip"]).toContain(splitIP(vms.network.ip_range)); + expect(result[0].interfaces[0]["ip"]).toMatch(ipRegex); + expect(result[0].capacity["cpu"]).toBe(cpu); + expect(result[0].capacity["memory"]).toBe(memory); + expect(result[0].planetary).toBeDefined(); + expect(result[0].myceliumIP).toBeDefined(); + expect(result[0].publicIP).toBeNull(); + expect(result[0].description).toBe(description); + + const host = result[0].myceliumIP; + const user = "root"; + + //SSH to the Created VM + const ssh = await RemoteRun(host, user); + + try { + //Verify that the added env var was successfully passed to the VM. + await ssh.execCommand("cat /proc/1/environ").then(async function (result) { + log(result.stdout); + expect(result.stdout).toContain(envVarValue); + }); + + //Verify VM Resources(CPU) + await ssh.execCommand("lscpu").then(async function (result) { + const splittedRes = result.stdout.split("\n"); + log(splittedRes[4]); + expect(splittedRes[4]).toContain(cpu.toString()); + }); + //Verify VM Resources(Memory) + await ssh.execCommand("free -m").then(async function (result) { + const splittedRes = result.stdout.split("\n"); + log(splittedRes[1]); + const memoryValue = splittedRes[1].match(/^\d+|\d+\b|\d+(?=\w)/g); + expect(+memoryValue[0]).toBeGreaterThanOrEqual(memory - memory * 0.2); + expect(+memoryValue[0]).toBeLessThan(memory); + }); + } finally { + //Disconnect from the machine + await ssh.dispose(); + } +}); + test("TC1229 - VM: Deploy a VM With a Disk", async () => { /********************************************** Test Suite: Grid3_Client_TS (Automated) @@ -264,7 +428,6 @@ test("TC1229 - VM: Deploy a VM With a Disk", async () => { cpu: cpu, memory: memory, rootfs_size: rootfsSize, - mycelium: false, disks: [ { name: diskName, @@ -276,6 +439,7 @@ test("TC1229 - VM: Deploy a VM With a Disk", async () => { entrypoint: "/sbin/zinit init", public_ip: publicIP, planetary: true, + mycelium: true, env: { SSH_KEY: config.ssh_key, Test_KEY: envVarValue, @@ -448,7 +612,7 @@ test("TC1230 - VM: Deploy Multiple VMs on Different Nodes", async () => { entrypoint: "/sbin/zinit init", public_ip: vmPublicIP, planetary: true, - mycelium: false, + mycelium: true, env: { SSH_KEY: config.ssh_key, TEST_KEY: vmEnvVarValue[0], @@ -466,7 +630,7 @@ test("TC1230 - VM: Deploy Multiple VMs on Different Nodes", async () => { entrypoint: "/sbin/zinit init", public_ip: vmPublicIP, planetary: true, - mycelium: false, + mycelium: true, env: { SSH_KEY: config.ssh_key, TEST_KEY: vmEnvVarValue[1], @@ -529,6 +693,7 @@ test("TC1230 - VM: Deploy Multiple VMs on Different Nodes", async () => { expect(result[currentIndex].capacity["cpu"]).toBe(vmCpu[maxIterations]); expect(result[currentIndex].capacity["memory"]).toBe(vmMemory[maxIterations]); expect(result[currentIndex].planetary).toBeDefined(); + expect(result[currentIndex].myceliumIP).toBeDefined(); expect(result[currentIndex].publicIP).toBeNull(); expect(result[currentIndex].description).toBe(description);