Skip to content

Commit

Permalink
Merge pull request #3346 from threefoldtech/development_jitsi
Browse files Browse the repository at this point in the history
create necessary files to run jitsi-meet on the grid
  • Loading branch information
eyad-hussein authored Sep 4, 2024
2 parents 935fc51 + d8bbd0c commit ae4d876
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 0 deletions.
Binary file added packages/playground/public/images/icons/jitsi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions packages/playground/public/info/jitsi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Jitsi
---

Jitsi Meet is a set of Open Source projects which empower users to use and deploy video conferencing platforms with state-of-the-art video quality and features. For more details, check [Jitsi documentation](https://www.manual.grid.tf/documentation/dashboard/solutions/jitsi.html).

```
```
2 changes: 2 additions & 0 deletions packages/playground/src/components/vm_deployment_table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ const filteredHeaders = computed(() => {
ProjectName.Subsquid,
ProjectName.Peertube,
ProjectName.Jenkins,
ProjectName.Jitsi,
] as string[];
const IPV4Solutions = [
Expand All @@ -367,6 +368,7 @@ const filteredHeaders = computed(() => {
ProjectName.Peertube,
ProjectName.Jenkins,
ProjectName.Caprover,
ProjectName.Jitsi,
] as string[];
const WireguardSolutions = [ProjectName.VM, ProjectName.Fullvm, ProjectName.Umbrel, ProjectName.TFRobot] as string[];
Expand Down
5 changes: 5 additions & 0 deletions packages/playground/src/constants/deployment_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export const deploymentListEnvironments = {
CASPERLABS_HOSTNAME: "Casperlabs Hostname",
},

jitsi: {
SSH_KEY: _ssh,
JITSI_HOSTNAME: "Jitsi Hostname",
},

discourse: {
SSH_KEY: _ssh,
DISCOURSE_HOSTNAME: "Discourse Hostname",
Expand Down
22 changes: 22 additions & 0 deletions packages/playground/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,28 @@ function createApplicationsRoutes(): RouteRecordRaw[] {
},
},
},
{
path: DashboardRoutes.Applications.Jitsi,
component: () => import("../views/jitsi_view.vue"),
meta: {
title: "Jitsi",
info: { page: "info/jitsi.md" },
navbarConfig: {
back: true,
path: [
{ title: "Deploy" },
{
title: "Applications",
disabled: false,
to: DashboardRoutes.Deploy.Applications,
},
{
title: "Jitsi",
},
],
},
},
},
{
path: DashboardRoutes.Applications.Algorand,
component: () => import("../views/algorand_view.vue"),
Expand Down
1 change: 1 addition & 0 deletions packages/playground/src/router/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ enum ApplicationRoutes {
Gitea = "/deploy/applications/gitea/",
Nostr = "/deploy/applications/nostr/",
Domains = "/deploy/applications/domains/",
Jitsi = "/deploy/applications/jitsi/",
}

const DashboardRoutes = {
Expand Down
3 changes: 3 additions & 0 deletions packages/playground/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export enum ProjectName {
Gitea = "Gitea",
Nostr = "Nostr",
Domains = "Domains",
Jitsi = "Jitsi",
}

export enum SolutionCode {
Expand Down Expand Up @@ -163,6 +164,7 @@ export enum SolutionCode {
gitea = "gt",
nostr = "nt",
Domains = "dm",
jitsi = "jt",
}

export const solutionType: { [key: string]: string } = {
Expand Down Expand Up @@ -191,6 +193,7 @@ export const solutionType: { [key: string]: string } = {
Gitea: "Gitea",
nostr: "Nostr",
domains: "Domains",
jitsi: "Jitsi",
};

export interface solutionFlavor {
Expand Down
1 change: 1 addition & 0 deletions packages/playground/src/utils/delete_deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export function solutionHasGateway(projectName: ProjectName) {
ProjectName.Taiga,
ProjectName.Wordpress,
ProjectName.Nextcloud,
ProjectName.Jitsi,
];

for (const solution of solutions) {
Expand Down
26 changes: 26 additions & 0 deletions packages/playground/src/views/jitsi_view.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<view-layout>
<tf-jitsi />

<template #list>
<TfDeploymentList title="Jitsi" :project-name="name" />
</template>
</view-layout>
</template>

<script lang="ts">
import { ProjectName } from "../types";
import TfDeploymentList from "../weblets/tf_deployment_list.vue";
import TfJitsi from "../weblets/tf_jitsi.vue";
export default {
name: "JitsiView",
components: {
TfDeploymentList,
TfJitsi,
},
setup() {
return { name: ProjectName.Jitsi };
},
};
</script>
7 changes: 7 additions & 0 deletions packages/playground/src/views/solutions_view.vue
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ export default {
icon: "domains.png",
route: DashboardRoutes.Applications.Domains,
},
{
title: "Jitsi",
excerpt:
"Jitsi Meet is a set of Open Source projects which empower users to use and deploy video conferencing platforms with state-of-the-art video quality and features.",
icon: "jitsi.png",
route: DashboardRoutes.Applications.Jitsi,
},
];
cards = cards.sort((a, b) => a.title.localeCompare(b.title));
Expand Down
10 changes: 10 additions & 0 deletions packages/playground/src/weblets/tf_deployment_list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,15 @@
:href="'https://' + item.env.WP_URL + '/wp-admin'"
/>
</template>

<template #Jitsi-actions="{ item }">
<IconActionBtn
tooltip="Show Details"
icon="mdi-eye-outline"
@click="openDialog(tabs[activeTab].value, item)"
/>
<IconActionBtn tooltip="Visit" icon="mdi-web" color="anchor" :href="'https://' + item.env.JITSI_HOSTNAME" />
</template>
</VmDeploymentTable>

<template #Kubernetes>
Expand Down Expand Up @@ -454,6 +463,7 @@ const tabs: Tab[] = [
{ title: "Nostr", value: "Nostr", imgPath: "images/icons/nostr.png" },
{ title: "Jenkins", value: "Jenkins", imgPath: "images/icons/jenkins.png" },
{ title: "Domains", value: "Domains", imgPath: "images/icons/domains.png" },
{ title: "Jitsi", value: "Jitsi", imgPath: "images/icons/jitsi.png" },
];
const layout = useLayout();
Expand Down
215 changes: 215 additions & 0 deletions packages/playground/src/weblets/tf_jitsi.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<template>
<weblet-layout
ref="layout"
:cpu="solution?.cpu"
:memory="solution?.memory"
:disk="solution?.disk"
:ipv4="ipv4"
:dedicated="dedicated"
:SelectedNode="selectionDetails?.node"
:valid-filters="selectionDetails?.validFilters"
title-image="images/icons/jitsi.png"
>
<template #title>Deploy a Jitsi Instance </template>

<d-tabs :tabs="[{ title: 'Config', value: 'config' }]">
<input-validator
:value="name"
:rules="[
validators.required('Name is required.'),
validators.IsAlphanumericExpectUnderscore('Name should consist of letters ,numbers and underscores only.'),
name => validators.isAlpha('Name must start with alphabet char.')(name[0]),
validators.minLength('Name must be at least 2 characters.', 2),
validators.maxLength('Name cannot exceed 50 characters.', 50),
]"
#="{ props }"
>
<input-tooltip tooltip="Instance name.">
<v-text-field label="Name" v-model="name" v-bind="props" />
</input-tooltip>
</input-validator>

<SelectSolutionFlavor
v-model="solution"
:small="{ cpu: 2, memory: 4, disk: 100 }"
:medium="{ cpu: 4, memory: 16, disk: 500 }"
:large="{ cpu: 8, memory: 32, disk: 1000 }"
/>

<Networks v-model:ipv4="ipv4" v-model:planetary="planetary" v-model:mycelium="mycelium" v-model:ipv6="ipv6" />

<input-tooltip inline tooltip="Click to know more about dedicated machines." :href="manual.dedicated_machines">
<v-switch color="primary" inset label="Dedicated" v-model="dedicated" hide-details />
</input-tooltip>

<input-tooltip inline tooltip="Renting capacity on certified nodes is charged 25% extra.">
<v-switch color="primary" inset label="Certified" v-model="certified" hide-details />
</input-tooltip>

<TfSelectionDetails
:filters="{
ipv4,
ipv6,
certified,
dedicated,
cpu: solution?.cpu,
solutionDisk: solution?.disk,
memory: solution?.memory,
rootFilesystemSize,
}"
require-domain
v-model="selectionDetails"
/>

<manage-ssh-deployemnt @selected-keys="updateSSHkeyEnv($event)" />
</d-tabs>

<template #footer-actions="{ validateBeforeDeploy }">
<v-btn color="secondary" @click="validateBeforeDeploy(deploy)" text="Deploy" />
</template>
</weblet-layout>
</template>

<script lang="ts" setup>
import { calculateRootFileSystem, type GridClient } from "@threefold/grid_client";
import { computed, type Ref, ref } from "vue";
import { manual } from "@/utils/manual";
import { useLayout } from "../components/weblet_layout.vue";
import { useGrid, useProfileManager } from "../stores";
import type { Flist, solutionFlavor as SolutionFlavor } from "../types";
import { ProjectName } from "../types";
import { deployVM } from "../utils/deploy_vm";
import { deployGatewayName, getSubdomain, rollbackDeployment } from "../utils/gateway";
import { normalizeError } from "../utils/helpers";
import { generateName } from "../utils/strings";
const layout = useLayout();
const profileManager = useProfileManager();
const name = ref(generateName({ prefix: "jt" }));
const solution = ref() as Ref<SolutionFlavor>;
const flist: Flist = {
value: "https://hub.grid.tf/tf-official-apps/jitsi-latest.flist",
entryPoint: "/sbin/zinit init",
};
const dedicated = ref(false);
const certified = ref(false);
const ipv4 = ref(false);
const ipv6 = ref(false);
const mycelium = ref(true);
const planetary = ref(false);
const rootFilesystemSize = computed(() =>
calculateRootFileSystem({ CPUCores: solution.value?.cpu ?? 0, RAMInMegaBytes: solution.value?.memory ?? 0 }),
);
const selectionDetails = ref<SelectionDetails>();
const selectedSSHKeys = ref("");
const gridStore = useGrid();
const grid = gridStore.client as GridClient;
function finalize(deployment: any) {
layout.value.reloadDeploymentsList();
layout.value.setStatus("success", "Successfully deployed a Jitsi instance.");
layout.value.openDialog(deployment, deploymentListEnvironments.jitsi);
}
async function deploy() {
layout.value.setStatus("deploy");
const projectName = ProjectName.Jitsi.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: any;
try {
layout.value?.validateSSH();
updateGrid(grid, { projectName });
await layout.value.validateBalance(grid!);
vm = await deployVM(grid!, {
name: name.value,
network: {
addAccess: selectionDetails.value!.domain!.enableSelectedDomain,
accessNodeId: selectionDetails.value?.domain?.selectedDomain?.nodeId,
},
machines: [
{
name: name.value,
cpu: solution.value.cpu,
memory: solution.value.memory,
disks: [{ size: solution?.value.disk, mountPoint: "/data" }],
flist: flist.value,
entryPoint: flist.entryPoint,
publicIpv4: ipv4.value,
publicIpv6: ipv6.value,
mycelium: mycelium.value,
planetary: planetary.value,
envs: [
{ key: "SSH_KEY", value: selectedSSHKeys.value },
{ key: "JITSI_HOSTNAME", value: domain },
],
nodeId: selectionDetails.value!.node!.nodeId,
rentedBy: dedicated.value ? grid!.twinId : undefined,
certified: certified.value,
rootFilesystemSize: rootFilesystemSize.value,
},
],
});
} catch (e) {
return layout.value.setStatus("failed", normalizeError(e, "Failed to deploy a Jitsi instance."));
}
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: 80,
network: vm[0].interfaces[0].network,
});
finalize(vm);
} catch (e) {
layout.value.setStatus("deploy", "Rolling back due to failure to deploy gateway...");
await rollbackDeployment(grid!, name.value);
layout.value.setStatus("failed", normalizeError(e, "Failed to deploy a Jitsi instance."));
}
}
function updateSSHkeyEnv(selectedKeys: string) {
selectedSSHKeys.value = selectedKeys;
}
</script>

<script lang="ts">
import Networks from "../components/networks.vue";
import SelectSolutionFlavor from "../components/select_solution_flavor.vue";
import ManageSshDeployemnt from "../components/ssh_keys/ManageSshDeployemnt.vue";
import { deploymentListEnvironments } from "../constants";
import type { SelectionDetails } from "../types/nodeSelector";
import { updateGrid } from "../utils/grid";
export default {
name: "TFJitsi",
components: { SelectSolutionFlavor, Networks, ManageSshDeployemnt },
};
</script>

0 comments on commit ae4d876

Please sign in to comment.