mirror of https://github.com/jetkvm/kvm.git
Compare commits
1 Commits
e72300e0a9
...
99faae710f
| Author | SHA1 | Date |
|---|---|---|
|
|
99faae710f |
20
cmd/main.go
20
cmd/main.go
|
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
envChildID = "JETKVM_CHILD_ID"
|
envChildID = "JETKVM_CHILD_ID"
|
||||||
errorDumpDir = "/userdata/jetkvm/crashdump"
|
errorDumpDir = "/userdata/jetkvm/"
|
||||||
errorDumpLastFile = "last-crash.log"
|
errorDumpLastFile = "last-crash.log"
|
||||||
errorDumpTemplate = "jetkvm-%s.log"
|
errorDumpTemplate = "jetkvm-%s.log"
|
||||||
)
|
)
|
||||||
|
|
@ -179,18 +179,6 @@ func renameFile(f *os.File, newName string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureErrorDumpDir() error {
|
|
||||||
// TODO: check if the directory is writable
|
|
||||||
f, err := os.Stat(errorDumpDir)
|
|
||||||
if err == nil && f.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := os.MkdirAll(errorDumpDir, 0755); err != nil {
|
|
||||||
return fmt.Errorf("failed to create error dump directory: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createErrorDump(logFile *os.File) {
|
func createErrorDump(logFile *os.File) {
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
|
|
@ -199,12 +187,6 @@ func createErrorDump(logFile *os.File) {
|
||||||
time.Now().Format("20060102-150405"),
|
time.Now().Format("20060102-150405"),
|
||||||
)
|
)
|
||||||
|
|
||||||
// check if the directory exists
|
|
||||||
if err := ensureErrorDumpDir(); err != nil {
|
|
||||||
fmt.Printf("failed to ensure error dump directory: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filePath := filepath.Join(errorDumpDir, fileName)
|
filePath := filepath.Join(errorDumpDir, fileName)
|
||||||
if err := renameFile(logFile, filePath); err != nil {
|
if err := renameFile(logFile, filePath); err != nil {
|
||||||
fmt.Printf("failed to rename file: %v\n", err)
|
fmt.Printf("failed to rename file: %v\n", err)
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,7 @@ func (m *MDNS) setLocalNames(localNames []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
m.localNames = localNames
|
m.localNames = localNames
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MDNS) setListenOptions(listenOptions *MDNSListenOptions) {
|
func (m *MDNS) setListenOptions(listenOptions *MDNSListenOptions) {
|
||||||
|
|
|
||||||
|
|
@ -2,49 +2,31 @@ import { LuPlus, LuX } from "react-icons/lu";
|
||||||
import { useFieldArray, useFormContext } from "react-hook-form";
|
import { useFieldArray, useFormContext } from "react-hook-form";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import validator from "validator";
|
import validator from "validator";
|
||||||
import { cx } from "cva";
|
|
||||||
|
|
||||||
import { GridCard } from "@/components/Card";
|
import { GridCard } from "@/components/Card";
|
||||||
import { Button } from "@/components/Button";
|
import { Button } from "@/components/Button";
|
||||||
import { InputFieldWithLabel } from "@/components/InputField";
|
import { InputFieldWithLabel } from "@/components/InputField";
|
||||||
import { NetworkSettings } from "@/hooks/stores";
|
import { NetworkSettings } from "@/hooks/stores";
|
||||||
import { netMaskFromCidr4 } from "@/utils/ip";
|
|
||||||
|
|
||||||
export default function StaticIpv4Card() {
|
export default function StaticIpv4Card() {
|
||||||
const formMethods = useFormContext<NetworkSettings>();
|
const formMethods = useFormContext<NetworkSettings>();
|
||||||
const { register, formState, watch, setValue } = formMethods;
|
const { register, formState, watch } = formMethods;
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({ name: "ipv4_static.dns" });
|
const { fields, append, remove } = useFieldArray({ name: "ipv4_static.dns" });
|
||||||
|
|
||||||
|
// TODO: set subnet mask if IP address is in CIDR notation
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (fields.length === 0) append("");
|
if (fields.length === 0) append("");
|
||||||
}, [append, fields.length]);
|
}, [append, fields.length]);
|
||||||
|
|
||||||
const dns = watch("ipv4_static.dns");
|
const dns = watch("ipv4_static.dns");
|
||||||
|
|
||||||
const ipv4StaticAddress = watch("ipv4_static.address");
|
|
||||||
const hideSubnetMask = ipv4StaticAddress?.includes("/");
|
|
||||||
useEffect(() => {
|
|
||||||
const parts = ipv4StaticAddress?.split("/", 2);
|
|
||||||
if (parts.length !== 2) return;
|
|
||||||
|
|
||||||
const cidrNotation = parseInt(parts[1]);
|
|
||||||
if (isNaN(cidrNotation) || cidrNotation < 0 || cidrNotation > 32) return;
|
|
||||||
|
|
||||||
const mask = netMaskFromCidr4(cidrNotation);
|
|
||||||
setValue("ipv4_static.netmask", mask);
|
|
||||||
}, [ipv4StaticAddress, setValue]);
|
|
||||||
|
|
||||||
const validate = (value: string) => {
|
const validate = (value: string) => {
|
||||||
if (!validator.isIP(value)) return "Invalid IP address";
|
if (!validator.isIP(value)) return "Invalid IP address";
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateIsIPOrCIDR4 = (value: string) => {
|
|
||||||
if (!validator.isIP(value, 4) && !validator.isIPRange(value, 4)) return "Invalid IP address or CIDR notation";
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridCard>
|
<GridCard>
|
||||||
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
<div className="animate-fadeIn p-4 text-black opacity-0 animation-duration-500 dark:text-white">
|
||||||
|
|
@ -53,25 +35,24 @@ export default function StaticIpv4Card() {
|
||||||
Static IPv4 Configuration
|
Static IPv4 Configuration
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div className={cx("grid grid-cols-1 gap-4", hideSubnetMask ? "md:grid-cols-1" : "md:grid-cols-2")}>
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<InputFieldWithLabel
|
<InputFieldWithLabel
|
||||||
label="IP Address"
|
label="IP Address"
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="192.168.1.100"
|
placeholder="192.168.1.100"
|
||||||
{
|
{...register("ipv4_static.address", { validate })}
|
||||||
...register("ipv4_static.address", { validate: validateIsIPOrCIDR4 })}
|
|
||||||
error={formState.errors.ipv4_static?.address?.message}
|
error={formState.errors.ipv4_static?.address?.message}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!hideSubnetMask && <InputFieldWithLabel
|
<InputFieldWithLabel
|
||||||
label="Subnet Mask"
|
label="Subnet Mask"
|
||||||
type="text"
|
type="text"
|
||||||
size="SM"
|
size="SM"
|
||||||
placeholder="255.255.255.0"
|
placeholder="255.255.255.0"
|
||||||
{...register("ipv4_static.netmask", { validate })}
|
{...register("ipv4_static.netmask", { validate })}
|
||||||
error={formState.errors.ipv4_static?.netmask?.message}
|
error={formState.errors.ipv4_static?.netmask?.message}
|
||||||
/>}
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<InputFieldWithLabel
|
<InputFieldWithLabel
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import { getNetworkSettings, getNetworkState } from "@/utils/jsonrpc";
|
||||||
import { Button } from "@components/Button";
|
import { Button } from "@components/Button";
|
||||||
import { GridCard } from "@components/Card";
|
import { GridCard } from "@components/Card";
|
||||||
import InputField, { InputFieldWithLabel } from "@components/InputField";
|
import InputField, { InputFieldWithLabel } from "@components/InputField";
|
||||||
import { netMaskFromCidr4 } from "@/utils/ip";
|
|
||||||
|
|
||||||
import AutoHeight from "../components/AutoHeight";
|
import AutoHeight from "../components/AutoHeight";
|
||||||
import DhcpLeaseCard from "../components/DhcpLeaseCard";
|
import DhcpLeaseCard from "../components/DhcpLeaseCard";
|
||||||
|
|
@ -156,16 +155,6 @@ export default function SettingsNetworkRoute() {
|
||||||
const { register, handleSubmit, watch, formState, reset } = formMethods;
|
const { register, handleSubmit, watch, formState, reset } = formMethods;
|
||||||
|
|
||||||
const onSubmit = async (settings: NetworkSettings) => {
|
const onSubmit = async (settings: NetworkSettings) => {
|
||||||
if (settings.ipv4_static?.address?.includes("/")) {
|
|
||||||
const parts = settings.ipv4_static.address.split("/");
|
|
||||||
const cidrNotation = parseInt(parts[1]);
|
|
||||||
if (isNaN(cidrNotation) || cidrNotation < 0 || cidrNotation > 32) {
|
|
||||||
return notifications.error("Invalid CIDR notation for IPv4 address");
|
|
||||||
}
|
|
||||||
settings.ipv4_static.netmask = netMaskFromCidr4(cidrNotation);
|
|
||||||
settings.ipv4_static.address = parts[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
send("setNetworkSettings", { settings }, async (resp) => {
|
send("setNetworkSettings", { settings }, async (resp) => {
|
||||||
if ("error" in resp) {
|
if ("error" in resp) {
|
||||||
return notifications.error(
|
return notifications.error(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue