Skip to content

Commit

Permalink
feat(network) allow creation and editing of physical managed networks…
Browse files Browse the repository at this point in the history
… WD-11519

Signed-off-by: David Edler <[email protected]>
  • Loading branch information
edlerd committed Jun 10, 2024
1 parent 129c7a1 commit a42ff46
Show file tree
Hide file tree
Showing 18 changed files with 495 additions and 140 deletions.
7 changes: 6 additions & 1 deletion src/api/networks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const fetchNetworkState = (
});
};

export const createClusterBridge = (
export const createClusterNetwork = (
network: Partial<LxdNetwork>,
project: string,
clusterMembers: LxdClusterMember[],
Expand All @@ -47,6 +47,9 @@ export const createClusterBridge = (
name: network.name,
description: network.description,
type: network.type,
config: {
parent: network.config?.parent,
},
};

void Promise.allSettled(
Expand All @@ -65,6 +68,8 @@ export const createClusterBridge = (
reject(error);
return;
}
// The network parent is cluster member specific, so we omit it on the cluster wide network configuration.
delete network.config?.parent;
createNetwork(network, project).then(resolve).catch(reject);
})
.catch(reject);
Expand Down
4 changes: 2 additions & 2 deletions src/pages/networks/CreateNetwork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "util/queryKeys";
import { useNavigate, useParams } from "react-router-dom";
import { checkDuplicateName } from "util/helpers";
import { createClusterBridge, createNetwork } from "api/networks";
import { createClusterNetwork, createNetwork } from "api/networks";
import NetworkForm, {
NetworkFormValues,
toNetwork,
Expand Down Expand Up @@ -81,7 +81,7 @@ const CreateNetwork: FC = () => {

const mutation =
isClustered && values.networkType !== "ovn"
? () => createClusterBridge(network, project, clusterMembers)
? () => createClusterNetwork(network, project, clusterMembers)
: () => createNetwork(network, project);

mutation()
Expand Down
72 changes: 39 additions & 33 deletions src/pages/networks/NetworkDetailOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const NetworkDetailOverview: FC<Props> = ({ network }) => {
return <>Missing project</>;
}

const isPhysicalManagedNetwork =
network.type === "physical" && network.managed;

const { data: networkState, isLoading } = useQuery({
queryKey: [
queryKeys.projects,
Expand All @@ -34,6 +37,7 @@ const NetworkDetailOverview: FC<Props> = ({ network }) => {
queryKeys.state,
],
queryFn: () => fetchNetworkState(network.name, project),
enabled: !isPhysicalManagedNetwork,
});

const updateContentHeight = () => {
Expand Down Expand Up @@ -92,39 +96,41 @@ const NetworkDetailOverview: FC<Props> = ({ network }) => {
</table>
</Col>
</Row>
<Row className="section">
<Col size={3}>
<h2 className="p-heading--5">Status</h2>
</Col>
<Col size={7}>
<table>
<tbody>
<tr className="list-wrapper">
<th className="p-muted-heading">RX</th>
<td>
{humanFileSize(networkState?.counters.bytes_received ?? 0)} (
{networkState?.counters.packets_received ?? 0} packets)
</td>
</tr>
<tr className="list-wrapper">
<th className="p-muted-heading">TX</th>
<td>
{humanFileSize(networkState?.counters.bytes_sent ?? 0)} (
{networkState?.counters.packets_sent ?? 0} packets)
</td>
</tr>
<tr className="list-wrapper">
<th className="p-muted-heading">MAC address</th>
<td>{networkState?.hwaddr ?? "-"}</td>
</tr>
<tr className="list-wrapper">
<th className="p-muted-heading">MTU</th>
<td>{networkState?.mtu ?? "-"}</td>
</tr>
</tbody>
</table>
</Col>
</Row>
{!isPhysicalManagedNetwork && (
<Row className="section">
<Col size={3}>
<h2 className="p-heading--5">Status</h2>
</Col>
<Col size={7}>
<table>
<tbody>
<tr className="list-wrapper">
<th className="p-muted-heading">RX</th>
<td>
{humanFileSize(networkState?.counters.bytes_received ?? 0)}{" "}
({networkState?.counters.packets_received ?? 0} packets)
</td>
</tr>
<tr className="list-wrapper">
<th className="p-muted-heading">TX</th>
<td>
{humanFileSize(networkState?.counters.bytes_sent ?? 0)} (
{networkState?.counters.packets_sent ?? 0} packets)
</td>
</tr>
<tr className="list-wrapper">
<th className="p-muted-heading">MAC address</th>
<td>{networkState?.hwaddr ?? "-"}</td>
</tr>
<tr className="list-wrapper">
<th className="p-muted-heading">MTU</th>
<td>{networkState?.mtu ?? "-"}</td>
</tr>
</tbody>
</table>
</Col>
</Row>
)}
<Row className="usage list-wrapper">
<Col size={3}>
<h2 className="p-heading--5">Usage ({usageCount})</h2>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/networks/forms/IpAddressSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const IpAddressSelector: FC<Props> = ({ id, address, setAddress }) => {
onChange={() => setAddress("auto")}
/>
<RadioInput
label="off"
label="none"
checked={address === "none"}
onChange={() => setAddress("none")}
/>
Expand Down
21 changes: 21 additions & 0 deletions src/pages/networks/forms/NetworkForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import NetworkFormMenu, {
IPV4,
IPV6,
MAIN_CONFIGURATION,
OVN,
YAML_CONFIGURATION,
} from "pages/networks/forms/NetworkFormMenu";
import { FormikProps } from "formik/dist/types";
Expand All @@ -35,6 +36,7 @@ import { slugify } from "util/slugify";
import { useDocs } from "context/useDocs";
import YamlConfirmation from "components/forms/YamlConfirmation";
import { getHandledNetworkConfigKeys, getNetworkKey } from "util/networks";
import NetworkFormOvn from "pages/networks/forms/NetworkFormOvn";

export interface NetworkFormValues {
readOnly: boolean;
Expand All @@ -47,6 +49,7 @@ export interface NetworkFormValues {
bridge_mtu?: string;
dns_domain?: string;
dns_mode?: LxdNetworkDnsMode;
dns_nameservers?: string;
dns_search?: string;
ipv4_address?: string;
ipv4_dhcp?: string;
Expand All @@ -56,6 +59,9 @@ export interface NetworkFormValues {
ipv4_nat?: string;
ipv4_nat_address?: string;
ipv4_ovn_ranges?: string;
ipv4_gateway?: string;
ipv4_routes?: string;
ipv4_routes_anycast?: string;
ipv6_address?: string;
ipv6_dhcp?: string;
ipv6_dhcp_expiry?: string;
Expand All @@ -65,7 +71,12 @@ export interface NetworkFormValues {
ipv6_nat?: string;
ipv6_nat_address?: string;
ipv6_ovn_ranges?: string;
ipv6_gateway?: string;
ipv6_routes?: string;
ipv6_routes_anycast?: string;
network?: string;
ovn_ingress_mode?: string;
parent?: string;
yaml?: string;
entityType: "network";
bareNetwork?: LxdNetwork;
Expand Down Expand Up @@ -110,6 +121,7 @@ export const toNetwork = (values: NetworkFormValues): Partial<LxdNetwork> => {
[getNetworkKey("bridge_mtu")]: values.bridge_mtu,
[getNetworkKey("dns_domain")]: values.dns_domain,
[getNetworkKey("dns_mode")]: values.dns_mode,
[getNetworkKey("dns_nameservers")]: values.dns_nameservers,
[getNetworkKey("dns_search")]: values.dns_search,
[getNetworkKey("ipv4_address")]: values.ipv4_address,
[getNetworkKey("ipv4_dhcp")]: values.ipv4_dhcp,
Expand All @@ -119,6 +131,9 @@ export const toNetwork = (values: NetworkFormValues): Partial<LxdNetwork> => {
[getNetworkKey("ipv4_nat")]: values.ipv4_nat,
[getNetworkKey("ipv4_nat_address")]: values.ipv4_nat_address,
[getNetworkKey("ipv4_ovn_ranges")]: values.ipv4_ovn_ranges,
[getNetworkKey("ipv4_gateway")]: values.ipv4_gateway,
[getNetworkKey("ipv4_routes")]: values.ipv4_routes,
[getNetworkKey("ipv4_routes_anycast")]: values.ipv4_routes_anycast,
[getNetworkKey("ipv6_address")]: values.ipv6_address,
[getNetworkKey("ipv6_dhcp")]: values.ipv6_dhcp,
[getNetworkKey("ipv6_dhcp_expiry")]: values.ipv6_dhcp_expiry,
Expand All @@ -128,7 +143,12 @@ export const toNetwork = (values: NetworkFormValues): Partial<LxdNetwork> => {
[getNetworkKey("ipv6_nat")]: values.ipv6_nat,
[getNetworkKey("ipv6_nat_address")]: values.ipv6_nat_address,
[getNetworkKey("ipv6_ovn_ranges")]: values.ipv6_ovn_ranges,
[getNetworkKey("ipv6_gateway")]: values.ipv6_gateway,
[getNetworkKey("ipv6_routes")]: values.ipv6_routes,
[getNetworkKey("ipv6_routes_anycast")]: values.ipv6_routes_anycast,
[getNetworkKey("network")]: values.network,
[getNetworkKey("ovn_ingress_mode")]: values.ovn_ingress_mode,
[getNetworkKey("parent")]: values.parent,
},
};
};
Expand Down Expand Up @@ -196,6 +216,7 @@ const NetworkForm: FC<Props> = ({
{section === slugify(DNS) && <NetworkFormDns formik={formik} />}
{section === slugify(IPV4) && <NetworkFormIpv4 formik={formik} />}
{section === slugify(IPV6) && <NetworkFormIpv6 formik={formik} />}
{section === slugify(OVN) && <NetworkFormOvn formik={formik} />}
{section === slugify(YAML_CONFIGURATION) && (
<YamlForm
key={`yaml-form-${formik.values.readOnly}`}
Expand Down
44 changes: 30 additions & 14 deletions src/pages/networks/forms/NetworkFormDns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ const NetworkFormDns: FC<Props> = ({ formik }) => {
return (
<ScrollableConfigurationTable
rows={[
getConfigurationRow({
formik,
name: "dns_domain",
label: "DNS domain",
defaultValue: "",
children: <Input type="text" />,
}),
...(formik.values.networkType !== "physical"
? [
getConfigurationRow({
formik,
name: "dns_domain",
label: "DNS domain",
defaultValue: "",
children: <Input type="text" />,
}),
]
: []),

...(formik.values.networkType === "bridge"
? [
Expand Down Expand Up @@ -55,13 +59,25 @@ const NetworkFormDns: FC<Props> = ({ formik }) => {
]
: []),

getConfigurationRow({
formik,
name: "dns_search",
label: "DNS search",
defaultValue: "",
children: <Textarea />,
}),
...(formik.values.networkType === "physical"
? [
getConfigurationRow({
formik,
name: "dns_nameservers",
label: "DNS nameservers",
defaultValue: "",
children: <Input type="text" />,
}),
]
: [
getConfigurationRow({
formik,
name: "dns_search",
label: "DNS search",
defaultValue: "",
children: <Textarea />,
}),
]),
]}
/>
);
Expand Down
48 changes: 40 additions & 8 deletions src/pages/networks/forms/NetworkFormIpv4.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ const NetworkFormIpv4: FC<Props> = ({ formik }) => {
return (
<ScrollableConfigurationTable
rows={[
getConfigurationRow({
formik,
name: "ipv4_dhcp",
label: "IPv4 DHCP",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
...(formik.values.networkType !== "physical"
? [
getConfigurationRow({
formik,
name: "ipv4_dhcp",
label: "IPv4 DHCP",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
]
: []),

...(formik.values.networkType !== "ovn" && hasDhcp
...(formik.values.networkType !== "ovn" &&
formik.values.networkType !== "physical" &&
hasDhcp
? [
getConfigurationRow({
formik,
Expand Down Expand Up @@ -67,6 +73,32 @@ const NetworkFormIpv4: FC<Props> = ({ formik }) => {
}),
]
: []),

...(formik.values.networkType === "physical"
? [
getConfigurationRow({
formik,
name: "ipv4_gateway",
label: "IPv4 gateway",
defaultValue: "",
children: <Textarea />,
}),
getConfigurationRow({
formik,
name: "ipv4_routes",
label: "IPv4 routes",
defaultValue: "",
children: <Textarea />,
}),
getConfigurationRow({
formik,
name: "ipv4_routes_anycast",
label: "IPv4 routes anycast",
defaultValue: "",
children: <Select options={optionTrueFalse} />,
}),
]
: []),
]}
/>
);
Expand Down
Loading

0 comments on commit a42ff46

Please sign in to comment.