Can define IP reservations for networks
This commit is contained in:
@ -1,9 +1,22 @@
|
||||
import { APIClient } from "./ApiClient";
|
||||
|
||||
export interface DHCPHost {
|
||||
// This field is unspecified in IPv6 configurations
|
||||
mac: string | undefined;
|
||||
name: string;
|
||||
ip: string;
|
||||
}
|
||||
|
||||
export interface DHCPConfig {
|
||||
start: string;
|
||||
end: string;
|
||||
hosts: DHCPHost[];
|
||||
}
|
||||
|
||||
export interface IpConfig {
|
||||
bridge_address: string;
|
||||
prefix: number;
|
||||
dhcp_range?: [string, string];
|
||||
dhcp?: DHCPConfig;
|
||||
}
|
||||
|
||||
export interface NetworkInfo {
|
||||
|
@ -19,6 +19,7 @@ export interface ServerConstraints {
|
||||
disk_size: LenConstraint;
|
||||
net_name_size: LenConstraint;
|
||||
net_title_size: LenConstraint;
|
||||
dhcp_reservation_host_name: LenConstraint;
|
||||
}
|
||||
|
||||
export interface LenConstraint {
|
||||
|
141
virtweb_frontend/src/widgets/net/DHCPHostReservations.tsx
Normal file
141
virtweb_frontend/src/widgets/net/DHCPHostReservations.tsx
Normal file
@ -0,0 +1,141 @@
|
||||
import { mdiIp } from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
IconButton,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { DHCPConfig, DHCPHost } from "../../api/NetworksApi";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||
import { IPInput } from "../forms/IPInput";
|
||||
import { MACInput } from "../forms/MACInput";
|
||||
import { TextInput } from "../forms/TextInput";
|
||||
|
||||
export function DHCPHostReservations(p: {
|
||||
editable: boolean;
|
||||
dhcp: DHCPConfig;
|
||||
version: 4 | 6;
|
||||
onChange?: (d: DHCPConfig) => void;
|
||||
}): React.ReactElement {
|
||||
const addHost = () => {
|
||||
p.dhcp.hosts.push({
|
||||
ip: p.version === 4 ? "192.168.1.30" : "fd00::b200",
|
||||
name: "host",
|
||||
mac: p.version === 4 ? "00:00:00:00:00:00" : undefined,
|
||||
});
|
||||
p.onChange?.(p.dhcp);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{p.dhcp.hosts.map((h, num) => (
|
||||
<HostReservationWidget
|
||||
key={num}
|
||||
{...p}
|
||||
onChange={() => {
|
||||
p.onChange?.(p.dhcp);
|
||||
}}
|
||||
host={h}
|
||||
onRemove={() => {
|
||||
p.dhcp.hosts.splice(num, 1);
|
||||
p.onChange?.(p.dhcp);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{p.editable && (
|
||||
<Button onClick={addHost}>Add new host reservation</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function HostReservationWidget(p: {
|
||||
editable: boolean;
|
||||
host: DHCPHost;
|
||||
version: 4 | 6;
|
||||
onChange: () => void;
|
||||
onRemove: () => void;
|
||||
}): React.ReactElement {
|
||||
const confirm = useConfirm();
|
||||
const deleteReservation = async () => {
|
||||
if (
|
||||
!(await confirm("Do you really want to remove this host IP reservation?"))
|
||||
)
|
||||
return;
|
||||
|
||||
p.onRemove();
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper elevation={3} style={{ padding: "10px", marginTop: "20px" }}>
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
p.editable && (
|
||||
<IconButton
|
||||
edge="end"
|
||||
aria-label="remove network"
|
||||
onClick={deleteReservation}
|
||||
>
|
||||
<Tooltip title="Remove host IP allocation">
|
||||
<DeleteIcon />
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<Icon path={mdiIp} />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<TextInput
|
||||
editable={p.editable}
|
||||
label="Host name"
|
||||
value={p.host.name}
|
||||
onValueChange={(v) => {
|
||||
p.host.name = v!;
|
||||
p.onChange();
|
||||
}}
|
||||
type="text"
|
||||
size={ServerApi.Config.constraints.dhcp_reservation_host_name}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<div style={{ marginLeft: "70px" }}>
|
||||
{p.version === 4 && (
|
||||
<MACInput
|
||||
editable={p.editable}
|
||||
label="MAC Address"
|
||||
value={p.host.mac}
|
||||
onValueChange={(v) => {
|
||||
p.host.mac = v!;
|
||||
p.onChange?.();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<IPInput
|
||||
editable={p.editable}
|
||||
label="IP address"
|
||||
version={p.version}
|
||||
value={p.host.ip}
|
||||
onValueChange={(v) => {
|
||||
p.host.ip = v!;
|
||||
p.onChange?.();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Paper>
|
||||
);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { Checkbox, Grid } from "@mui/material";
|
||||
import { Checkbox, Grid, Paper } from "@mui/material";
|
||||
import React from "react";
|
||||
import { IpConfig, NetworkApi, NetworkInfo } from "../../api/NetworksApi";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
@ -10,6 +10,7 @@ import { TextInput } from "../forms/TextInput";
|
||||
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||
import { CheckboxInput } from "../forms/CheckboxInput";
|
||||
import { ResAutostartInput } from "../forms/ResAutostartInput";
|
||||
import { DHCPHostReservations } from "./DHCPHostReservations";
|
||||
|
||||
interface DetailsProps {
|
||||
net: NetworkInfo;
|
||||
@ -239,44 +240,59 @@ function IPSection(p: {
|
||||
/>
|
||||
|
||||
<CheckboxInput
|
||||
checked={!!p.config.dhcp_range}
|
||||
checked={!!p.config.dhcp}
|
||||
editable={p.editable}
|
||||
label="Enable DHCP"
|
||||
onValueChange={(v) => {
|
||||
if (v)
|
||||
p.config!.dhcp_range =
|
||||
p.config!.dhcp =
|
||||
p.version === 4
|
||||
? ["192.168.1.100", "192.168.1.200"]
|
||||
: ["fd00::100", "fd00::f00"];
|
||||
else p.config!.dhcp_range = undefined;
|
||||
? {
|
||||
start: "192.168.1.100",
|
||||
end: "192.168.1.200",
|
||||
hosts: [],
|
||||
}
|
||||
: { start: "fd00::100", end: "fd00::f00", hosts: [] };
|
||||
else p.config!.dhcp = undefined;
|
||||
p.onChange?.(p.config);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{p.config?.dhcp_range && (
|
||||
{p.config?.dhcp && (
|
||||
<>
|
||||
<IPInput
|
||||
label="DHCP allocation start"
|
||||
editable={p.editable}
|
||||
version={p.version}
|
||||
value={p.config.dhcp_range[0]}
|
||||
onValueChange={(v) => {
|
||||
p.config!.dhcp_range![0] = v!;
|
||||
p.onChange(p.config);
|
||||
}}
|
||||
/>
|
||||
<IPInput
|
||||
label="DHCP allocation end"
|
||||
editable={p.editable}
|
||||
version={p.version}
|
||||
value={p.config.dhcp_range[1]}
|
||||
onValueChange={(v) => {
|
||||
p.config!.dhcp_range![1] = v!;
|
||||
p.onChange(p.config);
|
||||
}}
|
||||
/>
|
||||
<Paper elevation={3} style={{ padding: "10px" }}>
|
||||
<IPInput
|
||||
label="DHCP allocation start"
|
||||
editable={p.editable}
|
||||
version={p.version}
|
||||
value={p.config.dhcp.start}
|
||||
onValueChange={(v) => {
|
||||
p.config!.dhcp!.start = v!;
|
||||
p.onChange(p.config);
|
||||
}}
|
||||
/>
|
||||
<IPInput
|
||||
label="DHCP allocation end"
|
||||
editable={p.editable}
|
||||
version={p.version}
|
||||
value={p.config.dhcp.end}
|
||||
onValueChange={(v) => {
|
||||
p.config!.dhcp!.end = v!;
|
||||
p.onChange(p.config);
|
||||
}}
|
||||
/>
|
||||
|
||||
<DHCPHostReservations
|
||||
{...p}
|
||||
dhcp={p.config.dhcp}
|
||||
onChange={(d) => {
|
||||
p.config!.dhcp = d;
|
||||
p.onChange?.(p.config);
|
||||
}}
|
||||
/>
|
||||
</Paper>
|
||||
</>
|
||||
)}
|
||||
</EditSection>
|
||||
|
Reference in New Issue
Block a user