Can attach defined networks to domains
This commit is contained in:
		@@ -63,11 +63,20 @@ pub struct FeaturesXML {
 | 
				
			|||||||
#[serde(rename = "acpi")]
 | 
					#[serde(rename = "acpi")]
 | 
				
			||||||
pub struct ACPIXML {}
 | 
					pub struct ACPIXML {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
 | 
					#[serde(rename = "source")]
 | 
				
			||||||
 | 
					pub struct NetIntSourceXML {
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@network"))]
 | 
				
			||||||
 | 
					    pub network: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
#[serde(rename = "interface")]
 | 
					#[serde(rename = "interface")]
 | 
				
			||||||
pub struct DomainNetInterfaceXML {
 | 
					pub struct DomainNetInterfaceXML {
 | 
				
			||||||
    #[serde(rename(serialize = "@type"))]
 | 
					    #[serde(rename(serialize = "@type"))]
 | 
				
			||||||
    pub r#type: String,
 | 
					    pub r#type: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub source: Option<NetIntSourceXML>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Devices information
 | 
					/// Devices information
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ use crate::constants;
 | 
				
			|||||||
use crate::libvirt_lib_structures::{
 | 
					use crate::libvirt_lib_structures::{
 | 
				
			||||||
    DevicesXML, DiskBootXML, DiskDriverXML, DiskReadOnlyXML, DiskSourceXML, DiskTargetXML, DiskXML,
 | 
					    DevicesXML, DiskBootXML, DiskDriverXML, DiskReadOnlyXML, DiskSourceXML, DiskTargetXML, DiskXML,
 | 
				
			||||||
    DomainCPUTopology, DomainCPUXML, DomainMemoryXML, DomainNetInterfaceXML, DomainVCPUXML,
 | 
					    DomainCPUTopology, DomainCPUXML, DomainMemoryXML, DomainNetInterfaceXML, DomainVCPUXML,
 | 
				
			||||||
    DomainXML, FeaturesXML, GraphicsXML, NetworkDHCPRangeXML, NetworkDHCPXML,
 | 
					    DomainXML, FeaturesXML, GraphicsXML, NetIntSourceXML, NetworkDHCPRangeXML, NetworkDHCPXML,
 | 
				
			||||||
    NetworkDNSForwarderXML, NetworkDNSXML, NetworkDomainXML, NetworkForwardXML, NetworkIPXML,
 | 
					    NetworkDNSForwarderXML, NetworkDNSXML, NetworkDomainXML, NetworkForwardXML, NetworkIPXML,
 | 
				
			||||||
    NetworkXML, OSLoaderXML, OSTypeXML, XMLUuid, ACPIXML, OSXML,
 | 
					    NetworkXML, OSLoaderXML, OSTypeXML, XMLUuid, ACPIXML, OSXML,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -68,7 +68,7 @@ pub enum VMArchitecture {
 | 
				
			|||||||
#[serde(tag = "type")]
 | 
					#[serde(tag = "type")]
 | 
				
			||||||
pub enum Network {
 | 
					pub enum Network {
 | 
				
			||||||
    UserspaceSLIRPStack,
 | 
					    UserspaceSLIRPStack,
 | 
				
			||||||
    // TODO : complete network types
 | 
					    DefinedNetwork { network: String }, // TODO : complete network types
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
					#[derive(serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
@@ -226,6 +226,11 @@ impl VMInfo {
 | 
				
			|||||||
            networks.push(match n {
 | 
					            networks.push(match n {
 | 
				
			||||||
                Network::UserspaceSLIRPStack => DomainNetInterfaceXML {
 | 
					                Network::UserspaceSLIRPStack => DomainNetInterfaceXML {
 | 
				
			||||||
                    r#type: "user".to_string(),
 | 
					                    r#type: "user".to_string(),
 | 
				
			||||||
 | 
					                    source: None,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                Network::DefinedNetwork { network } => DomainNetInterfaceXML {
 | 
				
			||||||
 | 
					                    r#type: "network".to_string(),
 | 
				
			||||||
 | 
					                    source: Some(NetIntSourceXML { network }),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -344,6 +349,9 @@ impl VMInfo {
 | 
				
			|||||||
                .iter()
 | 
					                .iter()
 | 
				
			||||||
                .map(|d| match d.r#type.as_str() {
 | 
					                .map(|d| match d.r#type.as_str() {
 | 
				
			||||||
                    "user" => Ok(Network::UserspaceSLIRPStack),
 | 
					                    "user" => Ok(Network::UserspaceSLIRPStack),
 | 
				
			||||||
 | 
					                    "network" => Ok(Network::DefinedNetwork {
 | 
				
			||||||
 | 
					                        network: d.source.as_ref().unwrap().network.to_string(),
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
                    a => Err(LibVirtStructError::DomainExtraction(format!(
 | 
					                    a => Err(LibVirtStructError::DomainExtraction(format!(
 | 
				
			||||||
                        "Unknown network interface type: {a}! "
 | 
					                        "Unknown network interface type: {a}! "
 | 
				
			||||||
                    ))),
 | 
					                    ))),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,12 +30,17 @@ export interface VMDisk {
 | 
				
			|||||||
  deleteType?: "keepfile" | "deletefile";
 | 
					  deleteType?: "keepfile" | "deletefile";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type VMNetInterface = VMNetUserspaceSLIRPStack;
 | 
					export type VMNetInterface = VMNetUserspaceSLIRPStack | VMNetDefinedNetwork;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface VMNetUserspaceSLIRPStack {
 | 
					export interface VMNetUserspaceSLIRPStack {
 | 
				
			||||||
  type: "UserspaceSLIRPStack";
 | 
					  type: "UserspaceSLIRPStack";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface VMNetDefinedNetwork {
 | 
				
			||||||
 | 
					  type: "DefinedNetwork";
 | 
				
			||||||
 | 
					  network: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface VMInfoInterface {
 | 
					interface VMInfoInterface {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
  uuid?: string;
 | 
					  uuid?: string;
 | 
				
			||||||
@@ -65,7 +70,7 @@ export class VMInfo implements VMInfoInterface {
 | 
				
			|||||||
  vnc_access: boolean;
 | 
					  vnc_access: boolean;
 | 
				
			||||||
  iso_file?: string;
 | 
					  iso_file?: string;
 | 
				
			||||||
  disks: VMDisk[];
 | 
					  disks: VMDisk[];
 | 
				
			||||||
  networks: VMNetUserspaceSLIRPStack[];
 | 
					  networks: VMNetInterface[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(int: VMInfoInterface) {
 | 
					  constructor(int: VMInfoInterface) {
 | 
				
			||||||
    this.name = int.name;
 | 
					    this.name = int.name;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,11 +13,13 @@ import {
 | 
				
			|||||||
import { VMInfo, VMNetInterface } from "../../api/VMApi";
 | 
					import { VMInfo, VMNetInterface } from "../../api/VMApi";
 | 
				
			||||||
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
 | 
					import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
 | 
				
			||||||
import { SelectInput } from "./SelectInput";
 | 
					import { SelectInput } from "./SelectInput";
 | 
				
			||||||
 | 
					import { NetworkInfo } from "../../api/NetworksApi";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function VMNetworksList(p: {
 | 
					export function VMNetworksList(p: {
 | 
				
			||||||
  vm: VMInfo;
 | 
					  vm: VMInfo;
 | 
				
			||||||
  onChange?: () => void;
 | 
					  onChange?: () => void;
 | 
				
			||||||
  editable: boolean;
 | 
					  editable: boolean;
 | 
				
			||||||
 | 
					  networksList: NetworkInfo[];
 | 
				
			||||||
}): React.ReactElement {
 | 
					}): React.ReactElement {
 | 
				
			||||||
  const addNew = () => {
 | 
					  const addNew = () => {
 | 
				
			||||||
    p.vm.networks.push({ type: "UserspaceSLIRPStack" });
 | 
					    p.vm.networks.push({ type: "UserspaceSLIRPStack" });
 | 
				
			||||||
@@ -28,15 +30,14 @@ export function VMNetworksList(p: {
 | 
				
			|||||||
    <>
 | 
					    <>
 | 
				
			||||||
      {/* networks list */}
 | 
					      {/* networks list */}
 | 
				
			||||||
      {p.vm.networks.map((n, num) => (
 | 
					      {p.vm.networks.map((n, num) => (
 | 
				
			||||||
        <NetworkInfo
 | 
					        <NetworkInfoWidget
 | 
				
			||||||
          key={num}
 | 
					          key={num}
 | 
				
			||||||
          editable={p.editable}
 | 
					 | 
				
			||||||
          network={n}
 | 
					          network={n}
 | 
				
			||||||
          onChange={p.onChange}
 | 
					 | 
				
			||||||
          removeFromList={() => {
 | 
					          removeFromList={() => {
 | 
				
			||||||
            p.vm.networks.splice(num, 1);
 | 
					            p.vm.networks.splice(num, 1);
 | 
				
			||||||
            p.onChange?.();
 | 
					            p.onChange?.();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
 | 
					          {...p}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      ))}
 | 
					      ))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,11 +48,12 @@ export function VMNetworksList(p: {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function NetworkInfo(p: {
 | 
					function NetworkInfoWidget(p: {
 | 
				
			||||||
  editable: boolean;
 | 
					  editable: boolean;
 | 
				
			||||||
  network: VMNetInterface;
 | 
					  network: VMNetInterface;
 | 
				
			||||||
  onChange?: () => void;
 | 
					  onChange?: () => void;
 | 
				
			||||||
  removeFromList: () => void;
 | 
					  removeFromList: () => void;
 | 
				
			||||||
 | 
					  networksList: NetworkInfo[];
 | 
				
			||||||
}): React.ReactElement {
 | 
					}): React.ReactElement {
 | 
				
			||||||
  const confirm = useConfirm();
 | 
					  const confirm = useConfirm();
 | 
				
			||||||
  const deleteNetwork = async () => {
 | 
					  const deleteNetwork = async () => {
 | 
				
			||||||
@@ -65,7 +67,7 @@ function NetworkInfo(p: {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <>
 | 
				
			||||||
      <ListItem
 | 
					      <ListItem
 | 
				
			||||||
        secondaryAction={
 | 
					        secondaryAction={
 | 
				
			||||||
          p.editable && (
 | 
					          p.editable && (
 | 
				
			||||||
@@ -95,6 +97,7 @@ function NetworkInfo(p: {
 | 
				
			|||||||
                value={p.network.type}
 | 
					                value={p.network.type}
 | 
				
			||||||
                onValueChange={(v) => {
 | 
					                onValueChange={(v) => {
 | 
				
			||||||
                  p.network.type = v as any;
 | 
					                  p.network.type = v as any;
 | 
				
			||||||
 | 
					                  p.onChange?.();
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
                options={[
 | 
					                options={[
 | 
				
			||||||
                  {
 | 
					                  {
 | 
				
			||||||
@@ -103,6 +106,11 @@ function NetworkInfo(p: {
 | 
				
			|||||||
                    description:
 | 
					                    description:
 | 
				
			||||||
                      "Provides a virtual LAN with NAT to the outside world. The virtual network has DHCP & DNS services",
 | 
					                      "Provides a virtual LAN with NAT to the outside world. The virtual network has DHCP & DNS services",
 | 
				
			||||||
                  },
 | 
					                  },
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    label: "Defined network",
 | 
				
			||||||
 | 
					                    value: "DefinedNetwork",
 | 
				
			||||||
 | 
					                    description: "Attach to a defined network",
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
                ]}
 | 
					                ]}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            ) : (
 | 
					            ) : (
 | 
				
			||||||
@@ -111,6 +119,32 @@ function NetworkInfo(p: {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </ListItem>
 | 
					      </ListItem>
 | 
				
			||||||
 | 
					      <div style={{ marginLeft: "70px" }}>
 | 
				
			||||||
 | 
					        {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?.();
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import { VMSelectIsoInput } from "../forms/VMSelectIsoInput";
 | 
				
			|||||||
import { VMScreenshot } from "./VMScreenshot";
 | 
					import { VMScreenshot } from "./VMScreenshot";
 | 
				
			||||||
import { ResAutostartInput } from "../forms/ResAutostartInput";
 | 
					import { ResAutostartInput } from "../forms/ResAutostartInput";
 | 
				
			||||||
import { VMNetworksList } from "../forms/VMNetworksList";
 | 
					import { VMNetworksList } from "../forms/VMNetworksList";
 | 
				
			||||||
 | 
					import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface DetailsProps {
 | 
					interface DetailsProps {
 | 
				
			||||||
  vm: VMInfo;
 | 
					  vm: VMInfo;
 | 
				
			||||||
@@ -27,10 +28,12 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
 | 
				
			|||||||
  const [vcpuCombinations, setVCPUCombinations] = React.useState<
 | 
					  const [vcpuCombinations, setVCPUCombinations] = React.useState<
 | 
				
			||||||
    number[] | any
 | 
					    number[] | any
 | 
				
			||||||
  >();
 | 
					  >();
 | 
				
			||||||
 | 
					  const [networksList, setNetworksList] = React.useState<NetworkInfo[] | any>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const load = async () => {
 | 
					  const load = async () => {
 | 
				
			||||||
    setIsoList(await IsoFilesApi.GetList());
 | 
					    setIsoList(await IsoFilesApi.GetList());
 | 
				
			||||||
    setVCPUCombinations(await ServerApi.NumberVCPUs());
 | 
					    setVCPUCombinations(await ServerApi.NumberVCPUs());
 | 
				
			||||||
 | 
					    setNetworksList(await NetworkApi.GetList());
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
@@ -42,6 +45,7 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
 | 
				
			|||||||
        <VMDetailsInner
 | 
					        <VMDetailsInner
 | 
				
			||||||
          isoList={isoList}
 | 
					          isoList={isoList}
 | 
				
			||||||
          vcpuCombinations={vcpuCombinations}
 | 
					          vcpuCombinations={vcpuCombinations}
 | 
				
			||||||
 | 
					          networksList={networksList}
 | 
				
			||||||
          {...p}
 | 
					          {...p}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
@@ -50,7 +54,11 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function VMDetailsInner(
 | 
					function VMDetailsInner(
 | 
				
			||||||
  p: DetailsProps & { isoList: IsoFile[]; vcpuCombinations: number[] }
 | 
					  p: DetailsProps & {
 | 
				
			||||||
 | 
					    isoList: IsoFile[];
 | 
				
			||||||
 | 
					    vcpuCombinations: number[];
 | 
				
			||||||
 | 
					    networksList: NetworkInfo[];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
): React.ReactElement {
 | 
					): React.ReactElement {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Grid container spacing={2}>
 | 
					    <Grid container spacing={2}>
 | 
				
			||||||
@@ -201,12 +209,12 @@ function VMDetailsInner(
 | 
				
			|||||||
            p.onChange?.();
 | 
					            p.onChange?.();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <VMDisksList vm={p.vm} editable={p.editable} onChange={p.onChange} />
 | 
					        <VMDisksList {...p} />
 | 
				
			||||||
      </EditSection>
 | 
					      </EditSection>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {/* Networks section */}
 | 
					      {/* Networks section */}
 | 
				
			||||||
      <EditSection title="Networks">
 | 
					      <EditSection title="Networks">
 | 
				
			||||||
        <VMNetworksList vm={p.vm} editable={p.editable} onChange={p.onChange} />
 | 
					        <VMNetworksList {...p} />
 | 
				
			||||||
      </EditSection>
 | 
					      </EditSection>
 | 
				
			||||||
    </Grid>
 | 
					    </Grid>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user