don't try building x86_64 image
This commit is contained in:
@@ -17,9 +17,6 @@ jobs:
|
|||||||
- name: Install Skopeo
|
- name: Install Skopeo
|
||||||
run: nix shell nixpkgs#skopeo -c echo "skopeo installed"
|
run: nix shell nixpkgs#skopeo -c echo "skopeo installed"
|
||||||
|
|
||||||
- name: Build x86_64 Image
|
|
||||||
run: nix build .#dockerImages.x86_64-linux.node --out-link ./image-x86_64.tar.gz
|
|
||||||
|
|
||||||
- name: Build aarch64 Image
|
- name: Build aarch64 Image
|
||||||
run: nix build .#dockerImages.aarch64-linux.node --out-link ./image-aarch64.tar.gz
|
run: nix build .#dockerImages.aarch64-linux.node --out-link ./image-aarch64.tar.gz
|
||||||
|
|
||||||
@@ -28,24 +25,16 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
# Push x86_64 image
|
# Push aarch64 image
|
||||||
skopeo copy \
|
|
||||||
--insecure-policy \
|
|
||||||
--dest-creds "${{ github.actor }}:${GITEA_TOKEN}" \
|
|
||||||
"docker-archive:./image-x86_64.tar.gz" \
|
|
||||||
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest-amd64"
|
|
||||||
|
|
||||||
# Push aarch64 image
|
|
||||||
skopeo copy \
|
skopeo copy \
|
||||||
--insecure-policy \
|
--insecure-policy \
|
||||||
--dest-creds "${{ github.actor }}:${GITEA_TOKEN}" \
|
--dest-creds "${{ github.actor }}:${GITEA_TOKEN}" \
|
||||||
"docker-archive:./image-aarch64.tar.gz" \
|
"docker-archive:./image-aarch64.tar.gz" \
|
||||||
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest-arm64"
|
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest-arm64"
|
||||||
|
|
||||||
# Create and push manifest for multi-arch
|
# Create and push manifest for arm64
|
||||||
skopeo manifest create \
|
skopeo manifest create \
|
||||||
--insecure-policy \
|
--insecure-policy \
|
||||||
--dest-creds "${{ github.actor }}:${GITEA_TOKEN}" \
|
--dest-creds "${{ github.actor }}:${GITEA_TOKEN}" \
|
||||||
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest" \
|
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest" \
|
||||||
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest-amd64" \
|
|
||||||
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest-arm64"
|
"docker://${{ github.server_url }}/${{ github.repository }}/node:latest-arm64"
|
||||||
|
|||||||
@@ -41,12 +41,6 @@ in
|
|||||||
description = "Path to write Unbound include file";
|
description = "Path to write Unbound include file";
|
||||||
};
|
};
|
||||||
|
|
||||||
leasesJsonPath = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "/var/lib/router/leases.json";
|
|
||||||
description = "Path to write leases JSON file";
|
|
||||||
};
|
|
||||||
|
|
||||||
interval = lib.mkOption {
|
interval = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "30s";
|
default = "30s";
|
||||||
@@ -67,7 +61,6 @@ in
|
|||||||
# Ensure directories and files exist with proper permissions
|
# Ensure directories and files exist with proper permissions
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d /var/lib/unbound 0755 unbound unbound -"
|
"d /var/lib/unbound 0755 unbound unbound -"
|
||||||
"d /var/lib/router 0755 dhcp-dns-sync dhcp-dns-sync -"
|
|
||||||
"f ${cfg.unboundConfigPath} 0644 dhcp-dns-sync dhcp-dns-sync -"
|
"f ${cfg.unboundConfigPath} 0644 dhcp-dns-sync dhcp-dns-sync -"
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -99,22 +92,16 @@ in
|
|||||||
# Allow access to networkctl via D-Bus
|
# Allow access to networkctl via D-Bus
|
||||||
SupplementaryGroups = [ "systemd-network" ];
|
SupplementaryGroups = [ "systemd-network" ];
|
||||||
# Read/write paths
|
# Read/write paths
|
||||||
ReadWritePaths = [
|
ReadWritePaths = [ "/var/lib/unbound" ];
|
||||||
"/var/lib/unbound"
|
ExecStart = lib.concatStringsSep " " [
|
||||||
"/var/lib/router"
|
(lib.getExe dhcp-leases-to-unbound)
|
||||||
|
"-i ${cfg.interface}"
|
||||||
|
"-d ${cfg.domain}"
|
||||||
|
"-o ${cfg.unboundConfigPath}"
|
||||||
|
"--networkctl ${lib.getExe' pkgs.systemd "networkctl"}"
|
||||||
|
"--unbound-control ${lib.getExe' pkgs.unbound "unbound-control"}"
|
||||||
];
|
];
|
||||||
# Execute paths
|
|
||||||
ExecPaths = [ "/run/current-system/sw/bin" ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
script = ''
|
|
||||||
${lib.getExe dhcp-leases-to-unbound} \
|
|
||||||
-i ${cfg.interface} \
|
|
||||||
-d ${cfg.domain} \
|
|
||||||
-o ${cfg.unboundConfigPath} \
|
|
||||||
--leases-json ${cfg.leasesJsonPath} \
|
|
||||||
--networkctl ${lib.getExe' pkgs.systemd "networkctl"}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Systemd timer
|
# Systemd timer
|
||||||
|
|||||||
@@ -8,23 +8,34 @@ struct Lease
|
|||||||
include JSON::Serializable
|
include JSON::Serializable
|
||||||
|
|
||||||
@[JSON::Field(key: "Address")]
|
@[JSON::Field(key: "Address")]
|
||||||
property address : String
|
property address_bytes : Array(Int32)
|
||||||
|
|
||||||
@[JSON::Field(key: "MACAddress")]
|
@[JSON::Field(key: "HardwareAddress")]
|
||||||
property mac_address : String?
|
property hardware_address : Array(Int32)?
|
||||||
|
|
||||||
@[JSON::Field(key: "Hostname")]
|
@[JSON::Field(key: "Hostname")]
|
||||||
property hostname : String?
|
property hostname : String?
|
||||||
|
|
||||||
@[JSON::Field(key: "Lifetime")]
|
@[JSON::Field(key: "ExpirationUSec")]
|
||||||
property lifetime : Int64?
|
property expiration_usec : Int64?
|
||||||
|
|
||||||
|
def address : String
|
||||||
|
address_bytes.join('.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
struct DHCPServer
|
||||||
|
include JSON::Serializable
|
||||||
|
|
||||||
|
@[JSON::Field(key: "Leases")]
|
||||||
|
property leases : Array(Lease)?
|
||||||
end
|
end
|
||||||
|
|
||||||
struct NetworkStatus
|
struct NetworkStatus
|
||||||
include JSON::Serializable
|
include JSON::Serializable
|
||||||
|
|
||||||
@[JSON::Field(key: "OfferedDHCPLeases")]
|
@[JSON::Field(key: "DHCPServer")]
|
||||||
property offered_dhcp_leases : Array(Lease)?
|
property dhcp_server : DHCPServer?
|
||||||
end
|
end
|
||||||
|
|
||||||
def sanitize_hostname(hostname : String) : String?
|
def sanitize_hostname(hostname : String) : String?
|
||||||
@@ -86,7 +97,7 @@ def get_leases(interface : String, networkctl_path : String? = nil) : Array(Leas
|
|||||||
raise "networkctl failed (exit code #{$?.exit_status}): #{output}" unless $?.success?
|
raise "networkctl failed (exit code #{$?.exit_status}): #{output}" unless $?.success?
|
||||||
|
|
||||||
status = NetworkStatus.from_json(output)
|
status = NetworkStatus.from_json(output)
|
||||||
status.offered_dhcp_leases || [] of Lease
|
status.dhcp_server.try(&.leases) || [] of Lease
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_if_changed(content : String, path : String) : Bool
|
def write_if_changed(content : String, path : String) : Bool
|
||||||
@@ -107,8 +118,8 @@ end
|
|||||||
interface = "koti"
|
interface = "koti"
|
||||||
domain = "home.arpa"
|
domain = "home.arpa"
|
||||||
output_path = "/var/lib/unbound/dhcp-hosts.conf"
|
output_path = "/var/lib/unbound/dhcp-hosts.conf"
|
||||||
leases_json_path = "/var/lib/router/leases.json"
|
|
||||||
networkctl_path : String? = nil
|
networkctl_path : String? = nil
|
||||||
|
unbound_control_path : String? = nil
|
||||||
|
|
||||||
OptionParser.parse do |parser|
|
OptionParser.parse do |parser|
|
||||||
parser.banner = "Usage: dhcp-leases-to-unbound [options]"
|
parser.banner = "Usage: dhcp-leases-to-unbound [options]"
|
||||||
@@ -125,20 +136,30 @@ OptionParser.parse do |parser|
|
|||||||
output_path = o
|
output_path = o
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on("--leases-json PATH", "Output path for leases JSON (default: /var/lib/router/leases.json)") do |path|
|
|
||||||
leases_json_path = path
|
|
||||||
end
|
|
||||||
|
|
||||||
parser.on("--networkctl PATH", "Path to networkctl binary (default: networkctl from PATH)") do |path|
|
parser.on("--networkctl PATH", "Path to networkctl binary (default: networkctl from PATH)") do |path|
|
||||||
networkctl_path = path
|
networkctl_path = path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parser.on("--unbound-control PATH", "Path to unbound-control binary (default: unbound-control from PATH)") do |path|
|
||||||
|
unbound_control_path = path
|
||||||
|
end
|
||||||
|
|
||||||
parser.on("-h", "--help", "Show this help") do
|
parser.on("-h", "--help", "Show this help") do
|
||||||
puts parser
|
puts parser
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reload_unbound(unbound_control_path : String?)
|
||||||
|
cmd = unbound_control_path ? "#{unbound_control_path} reload" : "unbound-control reload"
|
||||||
|
puts "Reloading Unbound..."
|
||||||
|
result = system(cmd)
|
||||||
|
unless result
|
||||||
|
# Fallback to systemctl
|
||||||
|
system("systemctl reload unbound")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
# Get leases from networkd
|
# Get leases from networkd
|
||||||
leases = get_leases(interface, networkctl_path)
|
leases = get_leases(interface, networkctl_path)
|
||||||
@@ -149,18 +170,9 @@ begin
|
|||||||
# Write Unbound config if changed
|
# Write Unbound config if changed
|
||||||
changed = write_if_changed(config, output_path)
|
changed = write_if_changed(config, output_path)
|
||||||
|
|
||||||
# Also write leases JSON for dashboard
|
|
||||||
FileUtils.mkdir_p(File.dirname(leases_json_path))
|
|
||||||
File.write(leases_json_path, leases.to_json)
|
|
||||||
|
|
||||||
# Reload Unbound if config changed
|
# Reload Unbound if config changed
|
||||||
if changed
|
if changed
|
||||||
puts "DHCP leases updated, reloading Unbound..."
|
reload_unbound(unbound_control_path)
|
||||||
result = system("unbound-control reload")
|
|
||||||
unless result
|
|
||||||
# Fallback to systemctl if unbound-control fails
|
|
||||||
system("systemctl reload unbound")
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
puts "No DHCP lease changes detected."
|
puts "No DHCP lease changes detected."
|
||||||
end
|
end
|
||||||
|
|||||||
64
modules/services/network-status.nix
Normal file
64
modules/services/network-status.nix
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.modules.services.network-status;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.modules.services.network-status = {
|
||||||
|
enable = lib.mkEnableOption "Enable network status socket service";
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 8473;
|
||||||
|
description = "TCP port to listen on for network status requests";
|
||||||
|
};
|
||||||
|
|
||||||
|
interface = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "koti";
|
||||||
|
description = "Network interface to allow access from";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
users.users.network-status = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "network-status";
|
||||||
|
description = "Network status socket service user";
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.network-status = { };
|
||||||
|
|
||||||
|
systemd.sockets.network-status = {
|
||||||
|
description = "Network Status Socket";
|
||||||
|
wantedBy = [ "sockets.target" ];
|
||||||
|
socketConfig = {
|
||||||
|
ListenStream = cfg.port;
|
||||||
|
Accept = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services."network-status@" = {
|
||||||
|
description = "Network Status Service";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "network-status";
|
||||||
|
Group = "systemd-network";
|
||||||
|
SupplementaryGroups = [ "systemd-network" ];
|
||||||
|
StandardOutput = "socket";
|
||||||
|
StandardInput = "socket";
|
||||||
|
ExecStart = lib.concatStringsSep " " [
|
||||||
|
(lib.getExe' pkgs.systemd "networkctl")
|
||||||
|
"status"
|
||||||
|
"--json=short"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
modules.firewall.interfaces.${cfg.interface} = lib.mkDefault [ "network-status" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user