Add support to bridge option on Web UI
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Pierre HUBERT 2025-05-26 21:02:02 +02:00
parent a8171375a8
commit 6a7af7e6c4
5 changed files with 83 additions and 24 deletions

View File

@ -217,4 +217,16 @@ export class ServerApi {
}) })
).data; ).data;
} }
/**
* Get host networks bridges list
*/
static async GetNetworksBridgesList(): Promise<string[]> {
return (
await APIClient.exec({
method: "GET",
uri: "/server/bridges",
})
).data;
}
} }

View File

@ -50,7 +50,11 @@ export interface VMNetInterfaceFilter {
parameters: VMNetInterfaceFilterParams[]; parameters: VMNetInterfaceFilterParams[];
} }
export type VMNetInterface = (VMNetUserspaceSLIRPStack | VMNetDefinedNetwork) & export type VMNetInterface = (
| VMNetUserspaceSLIRPStack
| VMNetDefinedNetwork
| VMNetBridge
) &
VMNetInterfaceBase; VMNetInterfaceBase;
export interface VMNetInterfaceBase { export interface VMNetInterfaceBase {
@ -67,6 +71,11 @@ export interface VMNetDefinedNetwork {
network: string; network: string;
} }
export interface VMNetBridge {
type: "Bridge";
bridge: string;
}
interface VMInfoInterface { interface VMInfoInterface {
name: string; name: string;
uuid?: string; uuid?: string;

View File

@ -29,6 +29,7 @@ export function VMNetworksList(p: {
onChange?: () => void; onChange?: () => void;
editable: boolean; editable: boolean;
networksList: NetworkInfo[]; networksList: NetworkInfo[];
bridgesList: string[];
networkFiltersList: NWFilter[]; networkFiltersList: NWFilter[];
}): React.ReactElement { }): React.ReactElement {
const addNew = () => { const addNew = () => {
@ -72,6 +73,7 @@ function NetworkInfoWidget(p: {
onChange?: () => void; onChange?: () => void;
removeFromList: () => void; removeFromList: () => void;
networksList: NetworkInfo[]; networksList: NetworkInfo[];
bridgesList: string[];
networkFiltersList: NWFilter[]; networkFiltersList: NWFilter[];
}): React.ReactElement { }): React.ReactElement {
const confirm = useConfirm(); const confirm = useConfirm();
@ -130,6 +132,11 @@ function NetworkInfoWidget(p: {
value: "DefinedNetwork", value: "DefinedNetwork",
description: "Attach to a defined network", description: "Attach to a defined network",
}, },
{
label: "Host bridge",
value: "Bridge",
description: "Attach to an host's bridge",
},
]} ]}
/> />
) : ( ) : (
@ -149,31 +156,53 @@ function NetworkInfoWidget(p: {
}} }}
/> />
{/* Defined network selection */}
{p.network.type === "DefinedNetwork" && ( {p.network.type === "DefinedNetwork" && (
<SelectInput
editable={p.editable}
label="Defined network"
options={p.networksList.map((n) => {
const chars = [n.forward_mode.toString()];
if (n.ip_v4) chars.push("IPv4");
if (n.ip_v6) chars.push("IPv6");
if (n.description) chars.push(n.description);
return {
label: n.name,
value: n.name,
description: chars.join(" - "),
};
})}
value={p.network.network}
onValueChange={(v) => {
if (p.network.type === "DefinedNetwork")
p.network.network = v as any;
p.onChange?.();
}}
/>
)}
{/* Bridge selection */}
{p.network.type === "Bridge" && (
<SelectInput
editable={p.editable}
label="Host bridge"
options={p.bridgesList.map((n) => {
return {
label: n,
value: n,
};
})}
value={p.network.bridge}
onValueChange={(v) => {
if (p.network.type === "Bridge") p.network.bridge = v as any;
p.onChange?.();
}}
/>
)}
{p.network.type !== "UserspaceSLIRPStack" && (
<> <>
<SelectInput
editable={p.editable}
label="Defined network"
options={p.networksList.map((n) => {
const chars = [n.forward_mode.toString()];
if (n.ip_v4) chars.push("IPv4");
if (n.ip_v6) chars.push("IPv6");
if (n.description) chars.push(n.description);
return {
label: n.name,
value: n.name,
description: chars.join(" - "),
};
})}
value={p.network.network}
onValueChange={(v) => {
if (p.network.type === "DefinedNetwork")
p.network.network = v as any;
p.onChange?.();
}}
/>
{/* Network Filter */} {/* Network Filter */}
<NWFilterSelectInput <NWFilterSelectInput
editable={p.editable} editable={p.editable}

View File

@ -725,6 +725,11 @@ export function TokenRightsEditor(p: {
right={{ verb: "GET", path: "/api/server/networks" }} right={{ verb: "GET", path: "/api/server/networks" }}
label="Get list of network cards" label="Get list of network cards"
/> />
<RouteRight
{...p}
right={{ verb: "GET", path: "/api/server/bridges" }}
label="Get list of network bridges"
/>
</RightsSection> </RightsSection>
</> </>
); );

View File

@ -38,6 +38,7 @@ interface DetailsProps {
export function VMDetails(p: DetailsProps): React.ReactElement { export function VMDetails(p: DetailsProps): React.ReactElement {
const [groupsList, setGroupsList] = React.useState<string[] | undefined>(); const [groupsList, setGroupsList] = React.useState<string[] | undefined>();
const [isoList, setIsoList] = React.useState<IsoFile[] | undefined>(); const [isoList, setIsoList] = React.useState<IsoFile[] | undefined>();
const [bridgesList, setBridgesList] = React.useState<string[] | undefined>();
const [vcpuCombinations, setVCPUCombinations] = React.useState< const [vcpuCombinations, setVCPUCombinations] = React.useState<
number[] | undefined number[] | undefined
>(); >();
@ -51,6 +52,7 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
const load = async () => { const load = async () => {
setGroupsList(await GroupApi.GetList()); setGroupsList(await GroupApi.GetList());
setIsoList(await IsoFilesApi.GetList()); setIsoList(await IsoFilesApi.GetList());
setBridgesList(await ServerApi.GetNetworksBridgesList());
setVCPUCombinations(await ServerApi.NumberVCPUs()); setVCPUCombinations(await ServerApi.NumberVCPUs());
setNetworksList(await NetworkApi.GetList()); setNetworksList(await NetworkApi.GetList());
setNetworkFiltersList(await NWFilterApi.GetList()); setNetworkFiltersList(await NWFilterApi.GetList());
@ -65,6 +67,7 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
<VMDetailsInner <VMDetailsInner
groupsList={groupsList!} groupsList={groupsList!}
isoList={isoList!} isoList={isoList!}
bridgesList={bridgesList!}
vcpuCombinations={vcpuCombinations!} vcpuCombinations={vcpuCombinations!}
networksList={networksList!} networksList={networksList!}
networkFiltersList={networkFiltersList!} networkFiltersList={networkFiltersList!}
@ -87,6 +90,7 @@ enum VMTab {
type DetailsInnerProps = DetailsProps & { type DetailsInnerProps = DetailsProps & {
groupsList: string[]; groupsList: string[];
isoList: IsoFile[]; isoList: IsoFile[];
bridgesList: string[];
vcpuCombinations: number[]; vcpuCombinations: number[];
networksList: NetworkInfo[]; networksList: NetworkInfo[];
networkFiltersList: NWFilter[]; networkFiltersList: NWFilter[];