-
Notifications
You must be signed in to change notification settings - Fork 8
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
Adding expose application #3215
Changes from 4 commits
bd2afab
9fd10ee
8c9f89e
46b4c53
b2af973
d52d90a
b8d037d
44e4b97
845e7ea
cf93d08
c7f2acd
54eec66
32a5530
699eac4
81e3152
fb920ad
21e47bc
2b402b7
ac90473
f7a6fe6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
title: Expose | ||
--- | ||
|
||
Expose allows users to securely expose servers hosted on local machines or VMs to the public internet. Users are required to specify the machine's IP, which can be a Mycelium IP, Yggdrasil IP, or a public IP (IPv4 or IPv6). For more details, check the [Expose documentation](https://www.manual.grid.tf/documentation/dashboard/solutions/expose.html). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<template> | ||
<view-layout> | ||
<TfExpose /> | ||
|
||
<template #list> | ||
<TfDeploymentList title="Expose" :project-name="name" /> | ||
</template> | ||
</view-layout> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { ProjectName } from "../types"; | ||
import TfDeploymentList from "../weblets/tf_deployment_list.vue"; | ||
import TfExpose from "../weblets/tf_expose.vue"; | ||
|
||
export default { | ||
name: "ExposeView", | ||
components: { | ||
TfExpose, | ||
TfDeploymentList, | ||
}, | ||
setup() { | ||
return { name: ProjectName.Expose }; | ||
}, | ||
}; | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
<template> | ||
<weblet-layout | ||
ref="layout" | ||
:cpu="solution?.cpu" | ||
:memory="solution?.memory" | ||
:disk="solution?.disk" | ||
:dedicated="dedicated" | ||
:SelectedNode="selectionDetails?.node" | ||
:valid-filters="selectionDetails?.validFilters" | ||
title-image="images/icons/expose.png" | ||
> | ||
<template #title>Deploy an Expose 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: 1, memory: 2, disk: 50 }" | ||
:medium="{ cpu: 2, memory: 4, disk: 100 }" | ||
/> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this solution shouldn't contain a vm, it should be only a gateway workload |
||
|
||
<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 | ||
require-domain | ||
:filters="{ | ||
certified, | ||
dedicated, | ||
cpu: solution?.cpu, | ||
solutionDisk: solution?.disk, | ||
memory: solution?.memory, | ||
rootFilesystemSize, | ||
}" | ||
v-model="selectionDetails" | ||
/> | ||
<input-tooltip tooltip="Selecting custom domain sets subdomain as gateway name."> | ||
<input-validator | ||
:value="subdomain" | ||
:rules="[ | ||
validators.required('Subdomain is required.'), | ||
validators.isLowercase('Subdomain should consist of lowercase letters only.'), | ||
validators.isAlphanumeric('Subdomain should consist of letters and numbers only.'), | ||
subdomain => validators.isAlpha('Subdomain must start with alphabet char.')(subdomain[0]), | ||
validators.minLength('Subdomain must be at least 4 characters.', 4), | ||
subdomain => validators.maxLength('Subdomain cannot exceed 50 characters.', 50)(subdomain), | ||
]" | ||
#="{ props }" | ||
> | ||
<v-text-field label="Subdomain" v-model.trim="subdomain" v-bind="props" /> | ||
</input-validator> | ||
</input-tooltip> | ||
|
||
<input-tooltip tooltip="Port used to access the machine."> | ||
<input-validator | ||
:value="port" | ||
:rules="[validators.required('Port is required.'), validators.isPort('Please provide a valid port.')]" | ||
#="{ props }" | ||
> | ||
<v-text-field label="Port" v-model.number="port" type="number" v-bind="props" /> | ||
</input-validator> | ||
</input-tooltip> | ||
|
||
<input-tooltip | ||
tooltip="User's machine's public IP , It could be Mycelium IP, Yggdrasil IP, or a public IP (IPv4 or IPv6)." | ||
> | ||
<input-validator | ||
:value="ip" | ||
:rules="[validators.required('Public IP is required.'), validators.isIP('Public IP is not valid.')]" | ||
#="{ props }" | ||
> | ||
<v-text-field label="Public IP" v-model="ip" v-bind="props" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it doesn't have to be a public ip. Mycelium and Yggdarsil are not public. let's rename it to |
||
</input-validator> | ||
</input-tooltip> | ||
|
||
<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 } from "../stores"; | ||
import type { Flist, solutionFlavor as SolutionFlavor } from "../types"; | ||
import { ProjectName } from "../types"; | ||
import { deployVM } from "../utils/deploy_vm"; | ||
import { deployGatewayName, rollbackDeployment } from "../utils/gateway"; | ||
import { normalizeError } from "../utils/helpers"; | ||
import { generateName } from "../utils/strings"; | ||
|
||
const layout = useLayout(); | ||
const name = ref(generateName({ prefix: "ex" })); | ||
const ip = ref(); | ||
const mycelium = ref(true); | ||
const solution = ref() as Ref<SolutionFlavor>; | ||
const subdomain = ref(""); | ||
const port = ref(80); | ||
const flist: Flist = { | ||
value: "https://hub.grid.tf/tf-official-vms/ubuntu-22.04.flist", | ||
entryPoint: "/init.sh", | ||
}; | ||
const dedicated = ref(false); | ||
const certified = 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 an Expose instance."); | ||
layout.value.openDialog(deployment, deploymentListEnvironments.expose); | ||
} | ||
|
||
async function deploy() { | ||
layout.value.setStatus("deploy"); | ||
|
||
const projectName = ProjectName.Expose.toLowerCase() + "/" + name.value; | ||
console.log(projectName); | ||
const domain = selectionDetails.value?.domain?.enabledCustomDomain | ||
? selectionDetails.value.domain.customDomain | ||
: subdomain.value + "." + selectionDetails.value?.domain?.selectedDomain?.publicConfig.domain; | ||
|
||
let vm: any; | ||
|
||
try { | ||
layout.value?.validateSSH(); | ||
updateGrid(grid, { projectName }); | ||
console.log(name.value); | ||
|
||
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: "/var/lib/docker", | ||
}, | ||
], | ||
flist: flist.value, | ||
entryPoint: flist.entryPoint, | ||
publicIpv4: false, | ||
publicIpv6: false, | ||
mycelium: mycelium.value, | ||
planetary: false, | ||
envs: [ | ||
{ key: "SSH_KEY", value: selectedSSHKeys.value }, | ||
{ key: "EXPOSE_WEBSERVER_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 Subsquid 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: subdomain.value, | ||
ip: ip.value, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the ipv4 here will work as it will be in the format |
||
port: port.value, | ||
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 Subsquid instance.")); | ||
} | ||
} | ||
|
||
function updateSSHkeyEnv(selectedKeys: string) { | ||
selectedSSHKeys.value = selectedKeys; | ||
} | ||
</script> | ||
|
||
<script lang="ts"> | ||
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: "TfExpose", | ||
components: { SelectSolutionFlavor, ManageSshDeployemnt }, | ||
}; | ||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need the changes in this file?