Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions web/src/IpSettingsForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
*/

import React, { useState } from "react";
import { HelperText, HelperTextItem, Form, FormGroup, FormSelect, FormSelectOption, Text, TextInput } from "@patternfly/react-core";
import { HelperText, HelperTextItem, Form, FormGroup, FormSelect, FormSelectOption, TextInput } from "@patternfly/react-core";
import { useInstallerClient } from "./context/installer";
import AddressesDataList from "./AddressesDataList";
import DnsDataList from "./DnsDataList";
import Popup from "./Popup";
import { addressesFromIpConfig, dnsFromIpConfig, ip4_from_text } from "./utils";

const METHODS = {
MANUAL: "manual",
Expand All @@ -36,9 +37,9 @@ const usingDHCP = (method) => method === METHODS.AUTO;
export default function IpSettingsForm({ connection, onClose }) {
const client = useInstallerClient();
const { ipv4 = {} } = connection;
const [addresses, setAddresses] = useState(connection.addresses || []);
const [addresses, setAddresses] = useState(addressesFromIpConfig(ipv4));
// TODO: fill initial DNS Servers value from connection object
const [dnsServers, setDnsServers] = useState([]);
const [nameServers, setNameServers] = useState(dnsFromIpConfig(ipv4));
const [method, setMethod] = useState(ipv4.method?.v || "auto");
const [gateway, setGateway] = useState(ipv4.gateway?.v || "");
const [errors, setErrors] = useState({});
Expand Down Expand Up @@ -92,6 +93,7 @@ export default function IpSettingsForm({ connection, onClose }) {
e.preventDefault();

const sanitizedAddresses = cleanAddresses(addresses);
const sanitizedNameServers = cleanAddresses(nameServers);

if (!validate(sanitizedAddresses)) return;

Expand All @@ -101,7 +103,8 @@ export default function IpSettingsForm({ connection, onClose }) {
ipv4: {
addresses: sanitizedAddresses,
method,
gateway
gateway,
dns: sanitizedNameServers.map((s) => ip4_from_text(s.address))
}
};

Expand All @@ -119,10 +122,6 @@ export default function IpSettingsForm({ connection, onClose }) {
);
};

const gatewayLabel = usingDHCP(method)
? <>Gateway <Text component="small">(only for manual mode)</Text></>
: <>Gateway</>;

return (
<Popup isOpen height="medium" title={`Edit "${connection.id}" connection`}>
{/* FIXME: use a real onSubmit callback */}
Expand All @@ -149,19 +148,19 @@ export default function IpSettingsForm({ connection, onClose }) {
allowEmpty={usingDHCP(method)}
/>

<FormGroup fieldId="gateway" label={gatewayLabel}>
<FormGroup fieldId="gateway" label="Gateway">
<TextInput
id="gateway"
name="gateway"
aria-label="Gateway"
value={gateway}
label="Gateway"
isDisabled={usingDHCP(method)}
isDisabled={addresses.length === 0}
onChange={setGateway}
/>
</FormGroup>

<DnsDataList servers={dnsServers} updateDnsServers={setDnsServers} />
<DnsDataList servers={nameServers} updateDnsServers={setNameServers} />
</Form>

<Popup.Actions>
Expand Down
9 changes: 6 additions & 3 deletions web/src/client/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class NetworkManagerAdapter {
delete settings.ipv4.addresses;
delete settings.ipv4["address-data"];
delete settings.ipv4.gateway;
delete settings.ipv4.dns;

const newSettings = {
...settings,
Expand All @@ -205,17 +206,19 @@ class NetworkManagerAdapter {
}
))
),
dns: cockpit.variant("au", connection.ipv4.dns),
method: cockpit.variant("s", connection.ipv4.method)
}
};

// FIXME: find a better way to add gateway only if there are addresses. If not, a DBusError will
// be raises "gateway cannot be set if there are no addresses configured".
if (newSettings.ipv4["address-data"].v.length !== 0) {
const gateway = newSettings.ipv4.method === "manual" ? newSettings.ipv4.gateway : "";
newSettings.ipv4.gateway = cockpit.variant("s", gateway);
if ((connection.ipv4.gateway) && (newSettings.ipv4["address-data"].v.length !== 0)) {
newSettings.ipv4.gateway = cockpit.variant("s", connection.ipv4.gateway);
}

console.log(newSettings);

await settingsObject.Update(newSettings);
await this.activateConnection(connection);
}
Expand Down
8 changes: 6 additions & 2 deletions web/src/client/network.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ const ipv4SettingsMock = {
]
]
},
dns: {
t: "au",
v: [67305985, 16843009]
},
"dns-search": {
t: "as",
v: []
Expand Down Expand Up @@ -321,12 +325,12 @@ describe("NetworkClient", () => {
};
});

it("sends an empty gateway", async () => {
it("sends the configured gateway", async () => {
await client.updateConnection(updatedConnection);
expect(connectionSettingsMock.Update).toHaveBeenCalledWith(
expect.objectContaining({
ipv4: expect.objectContaining({
gateway: expect.objectContaining({ v: "" })
gateway: expect.objectContaining({ v: "192.168.1.1" })
})
})
);
Expand Down
69 changes: 68 additions & 1 deletion web/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,76 @@ const isValidIpPrefix = (value) => {
}
};

/**
* Converts an IP given in decimal format to text format
*
* @param {integer} address - An IP Address in Decimal format
* @return {string} the address given as a string
*/
const int_to_text = (address) => {
const ip = ipaddr.parse(address.toString());

return ip.octets.reverse().join(".");
};

/**
*
* Returns a list of nameservers from the given Connection Ip settings
*
* @param {object} config
* @return { { address: string }[] } list of nameservers in IP format
*
*/
const dnsFromIpConfig = (config) => {
const dns = config.dns.v || [];

return dns.map((address) => ({ address: int_to_text(address) }));
};

/**
*
* Returns a list of nameservers from the given Connection Ip settings
*
* @param {object} config
* @return { { address: string, prefix: string }[] } list of nameservers in IP format
*
*/
const addressesFromIpConfig = (config) => {
const addresses = config["address-data"]?.v || [];

return addresses.map((address) => ({ address: address.address.v, prefix: address.prefix.v }));
};

/** Convert a IP address from text to network-byte-order integer
*
* FIXME: Currently it is assumed 'le' ordering which should be read from NetworkManager State
*
* @param {string} IPv4 address
* @return {integer} IP address as network byte order integer
*
*/
const ip4_from_text = (text) => {
if (text === "")
return 0;

console.log(text);

const parts = text.split(".");
const bytes = parts.map((s) => parseInt(s.trim()));

let num = 0;
const shift = (b) => 0x100 * num + b;
for (const n of bytes.reverse()) { num = shift(n) }

return num;
};

export {
partition,
useCancellablePromise,
isValidIp,
isValidIpPrefix
isValidIpPrefix,
dnsFromIpConfig,
addressesFromIpConfig,
ip4_from_text
};