Skip to content

Commit

Permalink
feat(deployment): implement plain linux deployment page
Browse files Browse the repository at this point in the history
refs #227
  • Loading branch information
ygrishajev committed Jun 25, 2024
1 parent f5fe74e commit dae1822
Show file tree
Hide file tree
Showing 14 changed files with 459 additions and 217 deletions.
42 changes: 40 additions & 2 deletions apps/deploy-web/src/components/deployments/LeaseRow.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"use client";
import React, { SetStateAction, useCallback } from "react";
import React, { SetStateAction, useCallback, useMemo } from "react";
import { useEffect, useState } from "react";
import { Alert, Badge, Button, Card, CardContent, CardHeader, CustomTooltip, Spinner } from "@akashnetwork/ui/components";
import { Check, Copy, InfoCircle, OpenInWindow } from "iconoir-react";
import yaml from "js-yaml";
import get from "lodash/get";
import Link from "next/link";
import { useSnackbar } from "notistack";

import { AuditorButton } from "@src/components/providers/AuditorButton";
import { CodeSnippet } from "@src/components/shared/CodeSnippet";
import { FavoriteButton } from "@src/components/shared/FavoriteButton";
import { LabelValueOld } from "@src/components/shared/LabelValueOld";
import { LinkTo } from "@src/components/shared/LinkTo";
Expand All @@ -28,6 +30,7 @@ import { copyTextToClipboard } from "@src/utils/copyClipboard";
import { deploymentData } from "@src/utils/deploymentData";
import { getGpusFromAttributes, sendManifestToProvider } from "@src/utils/deploymentUtils";
import { udenomToDenom } from "@src/utils/mathHelpers";
import { sshVmImages } from "@src/utils/sdl/data";
import { cn } from "@src/utils/styleUtils";
import { UrlService } from "@src/utils/urlUtils";
import { ManifestErrorSnackbar } from "../shared/ManifestErrorSnackbar";
Expand Down Expand Up @@ -92,6 +95,8 @@ export const LeaseRow = React.forwardRef<AcceptRefType, Props>(({ lease, setActi
}
}, [isLeaseActive, provider, localCert, getLeaseStatus, getProviderStatus]);

const parsedManifest = useMemo(() => yaml.load(deploymentManifest), [deploymentManifest]);

const checkIfServicesAreAvailable = leaseStatus => {
const servicesNames = leaseStatus ? Object.keys(leaseStatus.services) : [];
const isServicesAvailable =
Expand All @@ -117,7 +122,7 @@ export const LeaseRow = React.forwardRef<AcceptRefType, Props>(({ lease, setActi
async function sendManifest() {
setIsSendingManifest(true);
try {
const doc = yaml.load(deploymentManifest);
const doc = parsedManifest;
const manifest = deploymentData.getManifest(doc, true);

await sendManifestToProvider(provider as ApiProviderList, manifest, dseq, localCert as LocalCert);
Expand All @@ -142,6 +147,28 @@ export const LeaseRow = React.forwardRef<AcceptRefType, Props>(({ lease, setActi

const gpuModels = bid && bid.bid.resources_offer.flatMap(x => getGpusFromAttributes(x.resources.gpu.attributes));

const sshInstructions = useMemo(() => {
return servicesNames.reduce((acc, serviceName) => {
if (!sshVmImages.has(get(parsedManifest, ["services", serviceName, "image"]))) {
return acc;
}

const exposes = leaseStatus.forwarded_ports[serviceName];

return exposes.reduce((exposesAcc, expose) => {
if (expose.port !== 22) {
return exposesAcc;
}

if (exposesAcc) {
exposesAcc += "\n";
}

return exposesAcc.concat(`ssh root@${expose.host} -p ${expose.externalPort} -i ~/.ssh/id_rsa`);
}, acc);
}, "");
}, [parsedManifest, servicesNames, leaseStatus]);

return (
<Card className="mb-4">
<CardHeader className="bg-secondary py-2">
Expand Down Expand Up @@ -421,6 +448,17 @@ export const LeaseRow = React.forwardRef<AcceptRefType, Props>(({ lease, setActi
</ul>
</div>
)}

{sshInstructions && (
<div className="mt-4">
<h5 className="font-bold dark:text-neutral-500">SSH Instructions:</h5>
<p>
Use this command in your terminal to access your VM via SSH. Make sure to pass the correct path to the private key corresponding to the public one
provided during this deployment creation.
</p>
<CodeSnippet code={sshInstructions} />
</div>
)}
</CardContent>
</Card>
);
Expand Down
97 changes: 54 additions & 43 deletions apps/deploy-web/src/components/new-deployment/ManifestEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { event } from "nextjs-google-analytics";
import { useCertificate } from "@src/context/CertificateProvider";
import { useChainParam } from "@src/context/ChainParamProvider";
import { useWallet } from "@src/context/WalletProvider";
import { useWhen } from "@src/hooks/useWhen";
import sdlStore from "@src/store/sdlStore";
import { TemplateCreation } from "@src/types";
import { AnalyticsEvents } from "@src/utils/analytics";
Expand All @@ -39,9 +40,11 @@ type Props = {
selectedTemplate: TemplateCreation | null;
editedManifest: string | null;
setEditedManifest: Dispatch<string>;
imageList?: string[];
ssh?: boolean;
};

export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, setEditedManifest, onTemplateSelected, selectedTemplate }) => {
export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, setEditedManifest, onTemplateSelected, selectedTemplate, imageList, ssh }) => {
const [parsingError, setParsingError] = useState<string | null>(null);
const [deploymentName, setDeploymentName] = useState("");
const [isCreatingDeployment, setIsCreatingDeployment] = useState(false);
Expand All @@ -60,10 +63,14 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
const { minDeposit } = useChainParam();

const searchParams = useSearchParams();
const templateId = searchParams.get('templateId');
const templateId = searchParams.get("templateId");

const fileUploadRef = useRef<HTMLInputElement>(null);

useWhen(ssh, () => {
setSelectedSdlEditMode("builder");
});

const propagateUploadedSdl = (event: React.ChangeEvent<HTMLInputElement>) => {
const selectedFiles = event.target.files ?? [];
const hasFileSelected = selectedFiles.length > 0;
Expand All @@ -81,15 +88,15 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
content: event.target?.result as string
});
setEditedManifest(event.target?.result as string);
setSelectedSdlEditMode('yaml');
setSelectedSdlEditMode("yaml");
};

reader.readAsText(fileUploaded);
};

const triggerFileInput = () => {
if (fileUploadRef.current) {
fileUploadRef.current.value = '';
fileUploadRef.current.value = "";
fileUploadRef.current.click();
}
};
Expand All @@ -106,8 +113,7 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
const timer = Timer(500);

timer.start().then(() => {
if (editedManifest)
createAndValidateDeploymentData(editedManifest, "TEST_DSEQ_VALIDATION");
if (editedManifest) createAndValidateDeploymentData(editedManifest, "TEST_DSEQ_VALIDATION");
});

return () => {
Expand Down Expand Up @@ -173,7 +179,7 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
async function handleCreateClick(deposit: number, depositorAddress: string) {
setIsCreatingDeployment(true);

const sdl = selectedSdlEditMode === "yaml" ? editedManifest : (sdlBuilderRef.current?.getSdl());
const sdl = selectedSdlEditMode === "yaml" ? editedManifest : sdlBuilderRef.current?.getSdl();

if (!sdl) {
setIsCreatingDeployment(false);
Expand Down Expand Up @@ -241,7 +247,7 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
}
}

const onModeChange = (mode: "yaml" | "builder") => {
const changeMode = (mode: "yaml" | "builder") => {
if (mode === selectedSdlEditMode) return;

if (mode === "yaml") {
Expand All @@ -250,6 +256,7 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
}
} else {
const sdl = sdlBuilderRef.current?.getSdl();

if (sdl) {
setEditedManifest(sdl);
}
Expand Down Expand Up @@ -306,51 +313,55 @@ export const ManifestEdit: React.FunctionComponent<Props> = ({ editedManifest, s
</div>
</div>

<div className="mb-2 flex gap-2">
<div className="flex items-center">
<Button
variant={selectedSdlEditMode === "builder" ? "default" : "outline"}
onClick={() => onModeChange("builder")}
size="sm"
className="flex-grow rounded-e-none sm:flex-grow-0"
disabled={!!parsingError && selectedSdlEditMode === "yaml"}
>
Builder
</Button>
<Button
variant={selectedSdlEditMode === "yaml" ? "default" : "outline"}
color={selectedSdlEditMode === "yaml" ? "secondary" : "primary"}
onClick={() => onModeChange("yaml")}
size="sm"
className="flex-grow rounded-s-none sm:flex-grow-0"
>
YAML
</Button>
</div>
{!templateId && (
<>
<input type="file" ref={fileUploadRef} onChange={propagateUploadedSdl} style={{ display: "none" }} accept=".yml,.yaml,.txt" />
{!ssh && (
<div className="mb-2 flex gap-2">
<div className="flex items-center">
<Button
variant="outline"
color="secondary"
onClick={() => triggerFileInput()}
variant={selectedSdlEditMode === "builder" ? "default" : "outline"}
onClick={() => changeMode("builder")}
size="sm"
className="flex-grow hover:bg-primary hover:text-white sm:flex-grow-0"
className="flex-grow rounded-e-none sm:flex-grow-0"
disabled={!!parsingError && selectedSdlEditMode === "yaml"}
>
Upload SDL
Builder
</Button>
</>
)}
</div>
<Button
variant={selectedSdlEditMode === "yaml" ? "default" : "outline"}
color={selectedSdlEditMode === "yaml" ? "secondary" : "primary"}
onClick={() => changeMode("yaml")}
size="sm"
className="flex-grow rounded-s-none sm:flex-grow-0"
>
YAML
</Button>
</div>
{!templateId && (
<>
<input type="file" ref={fileUploadRef} onChange={propagateUploadedSdl} style={{ display: "none" }} accept=".yml,.yaml,.txt" />
<Button
variant="outline"
color="secondary"
onClick={() => triggerFileInput()}
size="sm"
className="flex-grow hover:bg-primary hover:text-white sm:flex-grow-0"
>
Upload SDL
</Button>
</>
)}
</div>
)}

{parsingError && <Alert variant="warning">{parsingError}</Alert>}

{selectedSdlEditMode === "yaml" && (
{!ssh && selectedSdlEditMode === "yaml" && (
<ViewPanel stickToBottom className={cn("overflow-hidden", { ["-mx-4"]: smallScreen })}>
<DynamicMonacoEditor value={editedManifest || ''} onChange={handleTextChange} />
<DynamicMonacoEditor value={editedManifest || ""} onChange={handleTextChange} />
</ViewPanel>
)}
{selectedSdlEditMode === "builder" && <SdlBuilder sdlString={editedManifest} ref={sdlBuilderRef} setEditedManifest={setEditedManifest} />}
{(ssh || selectedSdlEditMode === "builder") && (
<SdlBuilder sdlString={editedManifest} ref={sdlBuilderRef} setEditedManifest={setEditedManifest} imageList={imageList} ssh={ssh} />
)}

{isDepositingDeployment && (
<DeploymentDepositModal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import { useEffect, useState } from "react";
import { FC, useEffect, useState } from "react";
import { useAtomValue } from "jotai";
import { useRouter, useSearchParams } from "next/navigation";

Expand All @@ -8,6 +8,7 @@ import { useTemplates } from "@src/context/TemplatesProvider";
import sdlStore from "@src/store/sdlStore";
import { TemplateCreation } from "@src/types";
import { RouteStepKeys } from "@src/utils/constants";
import { sshVmDistros } from "@src/utils/sdl/data";
import { hardcodedTemplates } from "@src/utils/templates";
import { UrlService } from "@src/utils/urlUtils";
import Layout from "../layout/Layout";
Expand All @@ -16,7 +17,12 @@ import { ManifestEdit } from "./ManifestEdit";
import { CustomizedSteppers } from "./Stepper";
import { TemplateList } from "./TemplateList";

export function NewDeploymentContainer() {
interface NewDeploymentContainerProps {
imageSource?: "ssh-vms" | "user-provided";
ssh?: boolean;
}

export const NewDeploymentContainer: FC<NewDeploymentContainerProps> = ({ imageSource = "user-provided", ssh }) => {
const { isLoading: isLoadingTemplates, templates } = useTemplates();
const [activeStep, setActiveStep] = useState<number | null>(null);
const [selectedTemplate, setSelectedTemplate] = useState<TemplateCreation | null>(null);
Expand Down Expand Up @@ -118,6 +124,8 @@ export function NewDeploymentContainer() {
{activeStep === 0 && <TemplateList />}
{activeStep === 1 && (
<ManifestEdit
imageList={imageSource === "ssh-vms" ? sshVmDistros : undefined}
ssh={ssh}
selectedTemplate={selectedTemplate}
onTemplateSelected={setSelectedTemplate}
editedManifest={editedManifest}
Expand All @@ -127,4 +135,4 @@ export function NewDeploymentContainer() {
{activeStep === 2 && <CreateLease dseq={dseq as string} />}
</Layout>
);
}
};
Loading

0 comments on commit dae1822

Please sign in to comment.