Can create NAT networks

This commit is contained in:
2023-12-07 20:03:11 +01:00
parent 5f0f56a9f9
commit 54a3013c59
7 changed files with 210 additions and 12 deletions

View File

@ -30,6 +30,12 @@ export interface VMDisk {
deleteType?: "keepfile" | "deletefile";
}
export type VMNetInterface = VMNetUserspaceSLIRPStack;
export interface VMNetUserspaceSLIRPStack {
type: "UserspaceSLIRPStack";
}
interface VMInfoInterface {
name: string;
uuid?: string;
@ -43,6 +49,7 @@ interface VMInfoInterface {
vnc_access: boolean;
iso_file?: string;
disks: VMDisk[];
networks: VMNetInterface[];
}
export class VMInfo implements VMInfoInterface {
@ -58,6 +65,7 @@ export class VMInfo implements VMInfoInterface {
vnc_access: boolean;
iso_file?: string;
disks: VMDisk[];
networks: VMNetUserspaceSLIRPStack[];
constructor(int: VMInfoInterface) {
this.name = int.name;
@ -72,6 +80,7 @@ export class VMInfo implements VMInfoInterface {
this.vnc_access = int.vnc_access;
this.iso_file = int.iso_file;
this.disks = int.disks;
this.networks = int.networks;
}
static NewEmpty(): VMInfo {
@ -83,6 +92,7 @@ export class VMInfo implements VMInfoInterface {
number_vcpu: 1,
vnc_access: true,
disks: [],
networks: [],
});
}

View File

@ -1,9 +1,16 @@
import { FormControl, InputLabel, MenuItem, Select } from "@mui/material";
import {
FormControl,
InputLabel,
MenuItem,
Select,
Typography,
} from "@mui/material";
import { TextInput } from "./TextInput";
export interface SelectOption {
value?: string;
label: string;
description?: string;
}
export function SelectInput(p: {
@ -33,7 +40,18 @@ export function SelectInput(p: {
value={e.value}
style={{ fontStyle: e.value === undefined ? "italic" : undefined }}
>
{e.label}
<div>
{e.label}
{e.description && (
<Typography
component={"div"}
variant="caption"
style={{ whiteSpace: "normal" }}
>
{e.description}
</Typography>
)}
</div>
</MenuItem>
))}
</Select>

View File

@ -0,0 +1,116 @@
import { mdiNetworkOutline } from "@mdi/js";
import Icon from "@mdi/react";
import DeleteIcon from "@mui/icons-material/Delete";
import {
Avatar,
Button,
IconButton,
ListItem,
ListItemAvatar,
ListItemText,
Tooltip,
} from "@mui/material";
import { VMInfo, VMNetInterface } from "../../api/VMApi";
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
import { SelectInput } from "./SelectInput";
export function VMNetworksList(p: {
vm: VMInfo;
onChange?: () => void;
editable: boolean;
}): React.ReactElement {
const addNew = () => {
p.vm.networks.push({ type: "UserspaceSLIRPStack" });
p.onChange?.();
};
return (
<>
{/* networks list */}
{p.vm.networks.map((n, num) => (
<NetworkInfo
key={num}
editable={p.editable}
network={n}
onChange={p.onChange}
removeFromList={() => {
p.vm.networks.splice(num, 1);
p.onChange?.();
}}
/>
))}
{p.editable && (
<Button onClick={addNew}>Add a new network interface</Button>
)}
</>
);
}
function NetworkInfo(p: {
editable: boolean;
network: VMNetInterface;
onChange?: () => void;
removeFromList: () => void;
}): React.ReactElement {
const confirm = useConfirm();
const deleteNetwork = async () => {
if (
!(await confirm("Do you really want to remove this network interface?"))
)
return;
p.removeFromList();
p.onChange?.();
};
return (
<div>
<ListItem
secondaryAction={
p.editable && (
<IconButton
edge="end"
aria-label="remove network"
onClick={deleteNetwork}
>
<Tooltip title="Remove network">
<DeleteIcon />
</Tooltip>
</IconButton>
)
}
>
<ListItemAvatar>
<Avatar>
<Icon path={mdiNetworkOutline} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={
p.editable ? (
<SelectInput
label=""
editable
value={p.network.type}
onValueChange={(v) => {
p.network.type = v as any;
}}
options={[
{
label: "Userspace SLIRP stack",
value: "UserspaceSLIRPStack",
description:
"Provides a virtual LAN with NAT to the outside world. The virtual network has DHCP & DNS services",
},
]}
/>
) : (
p.network.type
)
}
/>
</ListItem>
</div>
);
}

View File

@ -13,6 +13,7 @@ import { VMDisksList } from "../forms/VMDisksList";
import { VMSelectIsoInput } from "../forms/VMSelectIsoInput";
import { VMScreenshot } from "./VMScreenshot";
import { ResAutostartInput } from "../forms/ResAutostartInput";
import { VMNetworksList } from "../forms/VMNetworksList";
interface DetailsProps {
vm: VMInfo;
@ -202,6 +203,11 @@ function VMDetailsInner(
/>
<VMDisksList vm={p.vm} editable={p.editable} onChange={p.onChange} />
</EditSection>
{/* Networks section */}
<EditSection title="Networks">
<VMNetworksList vm={p.vm} editable={p.editable} onChange={p.onChange} />
</EditSection>
</Grid>
);
}