From ee7d15dd4adbad6d93e9b99f4287d860d0dd3721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 13:37:09 +0200 Subject: [PATCH 1/5] Add configure-dhcp microinit service after network. Wire /etc/init.d/configure-dhcp (binary from networking/configure-dhcp) to run after network so event Omada setups get dnsmasq when detected. Co-authored-by: Cursor --- apps/README.md | 1 + os/overlays/etc/init.d/configure-dhcp | 27 ++++++++++++++++++++++++ os/overlays/etc/microinit/microinit.json | 8 +++++++ 3 files changed, 36 insertions(+) create mode 100755 os/overlays/etc/init.d/configure-dhcp diff --git a/apps/README.md b/apps/README.md index 598e0a9..802c14d 100644 --- a/apps/README.md +++ b/apps/README.md @@ -35,6 +35,7 @@ make -C apps clean | `bigfred-os-ui` | Go | Hub admin web UI (logs, services) | | `rotate-hub-logs` | Go | Log rotation under `/data/logs` | | `configure-ethernet` | Go | One-shot Ethernet `up` + `check` for microinit liveness | +| `configure-dhcp` | Rust (source in `networking/configure-dhcp`) | Event DHCP via dnsmasq when Omada stack detected; microinit after `network` | | `prepare-nvme` | Rust | Migrate `/data` to NVMe (GPT via gptman) and remount | Init/PID 1 is **microinit** (OCI package), not under `apps/`. The SysV-style diff --git a/os/overlays/etc/init.d/configure-dhcp b/os/overlays/etc/init.d/configure-dhcp new file mode 100755 index 0000000..780b368 --- /dev/null +++ b/os/overlays/etc/init.d/configure-dhcp @@ -0,0 +1,27 @@ +#!/bin/sh +# Event WiFi DHCP: start dnsmasq when Omada (or other stack) is on the LAN. +# Runs after microinit service "network". + +CONFIGURE=/usr/sbin/configure-dhcp + +case "$1" in +start) + if [ ! -x "$CONFIGURE" ]; then + echo "configure-dhcp: $CONFIGURE missing" >&2 + exit 1 + fi + exec "$CONFIGURE" up + ;; +stop) + # Leave dnsmasq running if started; operator may still need leases. + exit 0 + ;; +restart) + $0 stop + $0 start + ;; +*) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac diff --git a/os/overlays/etc/microinit/microinit.json b/os/overlays/etc/microinit/microinit.json index fa86d8a..7f8eb5d 100644 --- a/os/overlays/etc/microinit/microinit.json +++ b/os/overlays/etc/microinit/microinit.json @@ -51,6 +51,14 @@ "interval": 30 } }, + { + "name": "configure-dhcp", + "enabled": true, + "daemon": false, + "cmd": "/etc/init.d/configure-dhcp", + "dependsOn": ["network"], + "startWaitSecs": 5 + }, { "name": "sysctl", "enabled": true, From 8d76f3813468b39367c5b1bec6113a5eaa903f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 14:26:17 +0200 Subject: [PATCH 2/5] Ship configure-ethernet/dhcp via micronet OCI; drop Go app. Add package/micronet (ORAS pull), enable in hub defconfig, and stop installing these binaries from apps/.bin. Co-authored-by: Cursor --- apps/README.md | 6 +- apps/configure-ethernet/Makefile | 25 -- apps/configure-ethernet/README.md | 65 ----- apps/configure-ethernet/main.go | 331 -------------------------- apps/configure-ethernet/main_test.go | 133 ----------- os/Makefile | 5 +- os/board/bigfred_hub/post-build.sh | 4 + os/configs/bigfred_hub_rpi5_defconfig | 2 + os/package/Config.in | 21 ++ os/package/micronet/README.md | 12 + os/package/micronet/fetch-oci.sh | 57 +++++ os/package/micronet/micronet.mk | 44 ++++ 12 files changed, 148 insertions(+), 557 deletions(-) delete mode 100644 apps/configure-ethernet/Makefile delete mode 100644 apps/configure-ethernet/README.md delete mode 100644 apps/configure-ethernet/main.go delete mode 100644 apps/configure-ethernet/main_test.go create mode 100644 os/package/micronet/README.md create mode 100755 os/package/micronet/fetch-oci.sh create mode 100644 os/package/micronet/micronet.mk diff --git a/apps/README.md b/apps/README.md index 802c14d..ec1b22e 100644 --- a/apps/README.md +++ b/apps/README.md @@ -34,10 +34,12 @@ make -C apps clean |-----|------|------| | `bigfred-os-ui` | Go | Hub admin web UI (logs, services) | | `rotate-hub-logs` | Go | Log rotation under `/data/logs` | -| `configure-ethernet` | Go | One-shot Ethernet `up` + `check` for microinit liveness | -| `configure-dhcp` | Rust (source in `networking/configure-dhcp`) | Event DHCP via dnsmasq when Omada stack detected; microinit after `network` | | `prepare-nvme` | Rust | Migrate `/data` to NVMe (GPT via gptman) and remount | +Network tools (`configure-ethernet`, `configure-dhcp`) ship via Buildroot package +`package/micronet` (OCI from [dcc-bigfred/micronet](https://github.com/dcc-bigfred/micronet)), +not under `apps/`. + Init/PID 1 is **microinit** (OCI package), not under `apps/`. The SysV-style `shutdown` CLI ships with that same OCI bundle (`/usr/sbin/shutdown`). diff --git a/apps/configure-ethernet/Makefile b/apps/configure-ethernet/Makefile deleted file mode 100644 index e8a0485..0000000 --- a/apps/configure-ethernet/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Go hub app → apps/.bin/configure-ethernet - -ROOT := $(abspath ../..) -BIN_DIR ?= $(ROOT)/apps/.bin -APP := $(notdir $(CURDIR)) - -GOOS ?= linux -GOARCH ?= arm64 -CGO_ENABLED ?= 0 - -.PHONY: all build test clean - -all: build - -build: - @mkdir -p "$(BIN_DIR)" - @echo "==> apps/$(APP)" - cd "$(ROOT)" && CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) \ - go build -ldflags="-s -w" -o "$(BIN_DIR)/$(APP)" ./apps/$(APP) - -test: - cd "$(ROOT)" && go test ./apps/$(APP)/... - -clean: - rm -f "$(BIN_DIR)/$(APP)" diff --git a/apps/configure-ethernet/README.md b/apps/configure-ethernet/README.md deleted file mode 100644 index a02df7b..0000000 --- a/apps/configure-ethernet/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# configure-ethernet - -One-shot Ethernet bring-up for the hub. Tries common club static subnets, then -falls back to DHCP. A separate `check` subcommand is a cheap liveness probe for -microinit. Linux only. - -Started at boot by `network` / microinit service `network` -(`/usr/sbin/configure-ethernet`). - -## Build (hub target) - -```bash -make -C apps build -# or: make -C apps configure-ethernet -``` - -Produces `apps/.bin/configure-ethernet` (`linux/arm64`, static). - -## Commands - -```bash -/usr/sbin/configure-ethernet # same as "up" -/usr/sbin/configure-ethernet up # configure once and exit -/usr/sbin/configure-ethernet check # exit 0 if UP+IPv4, else 1 -``` - -`check` only looks at link state and IPv4 on the first Ethernet interface (no ping). - -Configuration is read from `/data/etc/configure-ethernet.conf` (created on first run if missing). - -## Configuration - -```ini -# configure-ethernet static addresses (edit to match club subnet) -PRIMARY=192.168.0.120 -SECONDARY=192.168.1.120 -``` - -| Key | Default | Description | -|-----|---------|-------------| -| `PRIMARY` | `192.168.0.120` | First static address to try | -| `SECONDARY` | `192.168.1.120` | Fallback static address | - -Gateway is derived from the host address (last octet set to `.1`). Both static attempts use a `/24` prefix. - -## microinit liveness - -On the hub, `network` is a one-shot job with a liveness probe: - -```json -"livenessProbe": { - "cmd": "/usr/sbin/configure-ethernet check", - "successExitCodes": [0], - "interval": 30 -} -``` - -When `check` fails, microinit re-runs the network start (bring-up again). - -## Tests - -```bash -make -C apps test -# or: make -C apps/configure-ethernet test -``` diff --git a/apps/configure-ethernet/main.go b/apps/configure-ethernet/main.go deleted file mode 100644 index 44dec08..0000000 --- a/apps/configure-ethernet/main.go +++ /dev/null @@ -1,331 +0,0 @@ -//go:build linux - -// configure-ethernet brings up the first Ethernet interface with a static -// address on common club subnets, or falls back to DHCP. -// Subcommand "check" reports whether the link still looks connected (cheap). -package main - -import ( - "bufio" - "fmt" - "net" - "os" - "os/exec" - "path/filepath" - "sort" - "strings" - "time" -) - -const ( - defaultConfigPath = "/data/etc/configure-ethernet.conf" - defaultPrimaryAddr = "192.168.0.120" - defaultSecondaryAddr = "192.168.1.120" - defaultPrefixLen = 24 - pingCount = 1 - pingTimeoutSec = 2 - dhcpWait = 5 * time.Second - - // Absolute paths: PID 1 / microinit often start with no PATH, and Go's - // LookPath then searches only /usr/bin:/bin (not /sbin). - ipBin = "/sbin/ip" - dhclientBin = "/sbin/dhclient" - pingBin = "/bin/ping" -) - -type settings struct { - primaryAddr string - secondaryAddr string -} - -func main() { - cmd := "up" - if len(os.Args) > 1 { - cmd = os.Args[1] - } - - switch cmd { - case "up", "configure", "start": - if err := runConfigure(defaultConfigPath); err != nil { - fmt.Fprintf(os.Stderr, "configure-ethernet: %v\n", err) - os.Exit(1) - } - case "check": - if checkConnected() { - os.Exit(0) - } - os.Exit(1) - case "-h", "--help", "help": - usage() - default: - fmt.Fprintf(os.Stderr, "configure-ethernet: unknown command %q\n", cmd) - usage() - os.Exit(2) - } -} - -func usage() { - fmt.Fprintf(os.Stderr, "usage: %s [up|check]\n", os.Args[0]) - fmt.Fprintf(os.Stderr, " up bring up Ethernet (static / DHCP) and exit\n") - fmt.Fprintf(os.Stderr, " check exit 0 if link+IPv4 look OK, else 1 (cheap)\n") -} - -func runConfigure(configPath string) error { - cfg, err := loadOrCreateConfig(configPath, defaultPrimaryAddr, defaultSecondaryAddr) - if err != nil { - return err - } - - _ = runCmd(ipBin, "link", "set", "lo", "up") - - if connect(cfg) { - return nil - } - return fmt.Errorf("failed to configure ethernet (static and DHCP)") -} - -// checkConnected is a cheap liveness probe: ethernet iface is UP and has IPv4. -// No ping (that would be slower and flaky on quiet networks). -func checkConnected() bool { - iface, err := firstEthernetInterface() - if err != nil { - return false - } - return ifaceLinkUp(iface) && ifaceHasIPv4(iface) -} - -func connect(cfg settings) bool { - iface, err := firstEthernetInterface() - if err != nil { - fmt.Fprintf(os.Stderr, "configure-ethernet: %v\n", err) - return false - } - - fmt.Printf("configure-ethernet: using interface %s\n", iface) - _ = runCmd("/bin/killall", "dhclient") - - if tryStatic(iface, cfg.primaryAddr) { - fmt.Printf("configure-ethernet: static %s OK (gateway %s)\n", cfg.primaryAddr, gatewayFor(cfg.primaryAddr)) - return true - } - - if tryStatic(iface, cfg.secondaryAddr) { - fmt.Printf("configure-ethernet: static %s OK (gateway %s)\n", cfg.secondaryAddr, gatewayFor(cfg.secondaryAddr)) - return true - } - - if tryDHCP(iface) { - fmt.Println("configure-ethernet: DHCP OK") - return true - } - - fmt.Fprintf(os.Stderr, "configure-ethernet: failed to configure %s (static and DHCP)\n", iface) - return false -} - -func ifaceLinkUp(iface string) bool { - out, err := exec.Command(ipBin, "link", "show", "dev", iface).Output() - if err != nil { - return false - } - return strings.Contains(string(out), "state UP") || strings.Contains(string(out), ",UP") -} - -func loadOrCreateConfig(path, defaultPrimary, defaultSecondary string) (settings, error) { - defaults := settings{ - primaryAddr: defaultPrimary, - secondaryAddr: defaultSecondary, - } - - data, err := os.ReadFile(path) - if err != nil { - if !os.IsNotExist(err) { - return settings{}, fmt.Errorf("read %s: %w", path, err) - } - if writeErr := writeConfig(path, defaults); writeErr != nil { - fmt.Fprintf(os.Stderr, "warning: cannot write %s: %v\n", path, writeErr) - } - return defaults, nil - } - - return parseConfig(string(data), defaults), nil -} - -func parseConfig(text string, defaults settings) settings { - cfg := defaults - - scanner := bufio.NewScanner(strings.NewReader(text)) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - key, value, ok := strings.Cut(line, "=") - if !ok { - continue - } - key = strings.TrimSpace(key) - value = strings.TrimSpace(value) - if value == "" { - continue - } - switch strings.ToUpper(key) { - case "PRIMARY", "PRIMARY_ADDRESS", "ADDRESS": - if net.ParseIP(value) != nil { - cfg.primaryAddr = value - } - case "SECONDARY", "SECONDARY_ADDRESS", "FALLBACK", "FALLBACK_ADDRESS": - if net.ParseIP(value) != nil { - cfg.secondaryAddr = value - } - } - } - return cfg -} - -func writeConfig(path string, cfg settings) error { - dir := filepath.Dir(path) - if err := os.MkdirAll(dir, 0o755); err != nil { - return err - } - - content := fmt.Sprintf(`# configure-ethernet static addresses (edit to match club subnet) -PRIMARY=%s -SECONDARY=%s -`, cfg.primaryAddr, cfg.secondaryAddr) - - return os.WriteFile(path, []byte(content), 0o644) -} - -func firstEthernetInterface() (string, error) { - entries, err := os.ReadDir("/sys/class/net") - if err != nil { - return "", fmt.Errorf("list network interfaces: %w", err) - } - - names := make([]string, 0, len(entries)) - for _, ent := range entries { - name := ent.Name() - if name == "lo" { - continue - } - if isWireless(name) { - continue - } - names = append(names, name) - } - - if len(names) == 0 { - return "", fmt.Errorf("no Ethernet interface found") - } - - sort.Strings(names) - return names[0], nil -} - -func isWireless(iface string) bool { - _, err := os.Stat(filepath.Join("/sys/class/net", iface, "wireless")) - return err == nil -} - -func tryStatic(iface, addr string) bool { - gw := gatewayFor(addr) - if gw == "" { - return false - } - - if err := configureStatic(iface, addr); err != nil { - fmt.Fprintf(os.Stderr, "configure-ethernet: static %s on %s: %v\n", addr, iface, err) - return false - } - - if pingHost(gw) { - return true - } - - fmt.Fprintf(os.Stderr, "configure-ethernet: no reply from gateway %s\n", gw) - return false -} - -func configureStatic(iface, addr string) error { - if err := runCmd(ipBin, "link", "set", "dev", iface, "up"); err != nil { - return err - } - if err := runCmd(ipBin, "addr", "flush", "dev", iface); err != nil { - return err - } - cidr := fmt.Sprintf("%s/%d", addr, defaultPrefixLen) - return runCmd(ipBin, "addr", "add", cidr, "dev", iface) -} - -func pingHost(host string) bool { - err := runCmd(pingBin, "-c", fmt.Sprint(pingCount), "-W", fmt.Sprint(pingTimeoutSec), host) - return err == nil -} - -func tryDHCP(iface string) bool { - _ = runCmd(ipBin, "addr", "flush", "dev", iface) - _ = runCmd(ipBin, "link", "set", "dev", iface, "up") - - if err := runCmd(dhclientBin, iface); err != nil { - fmt.Fprintf(os.Stderr, "configure-ethernet: dhclient on %s: %v\n", iface, err) - return false - } - - time.Sleep(dhcpWait) - - if !ifaceHasIPv4(iface) { - fmt.Fprintf(os.Stderr, "configure-ethernet: no IPv4 address on %s after DHCP\n", iface) - return false - } - - if gw, ok := defaultGateway(); ok && pingHost(gw) { - return true - } - - return ifaceHasIPv4(iface) -} - -func ifaceHasIPv4(iface string) bool { - out, err := exec.Command(ipBin, "-4", "addr", "show", "dev", iface).Output() - if err != nil { - return false - } - return strings.Contains(string(out), "inet ") -} - -func defaultGateway() (string, bool) { - out, err := exec.Command(ipBin, "route", "show", "default").Output() - if err != nil { - return "", false - } - for _, line := range strings.Split(string(out), "\n") { - fields := strings.Fields(line) - for i, f := range fields { - if f == "via" && i+1 < len(fields) { - return fields[i+1], true - } - } - } - return "", false -} - -func gatewayFor(addr string) string { - ip := net.ParseIP(addr) - if ip == nil { - return "" - } - ip = ip.To4() - if ip == nil { - return "" - } - ip[3] = 1 - return ip.String() -} - -func runCmd(name string, args ...string) error { - cmd := exec.Command(name, args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} diff --git a/apps/configure-ethernet/main_test.go b/apps/configure-ethernet/main_test.go deleted file mode 100644 index 1109f51..0000000 --- a/apps/configure-ethernet/main_test.go +++ /dev/null @@ -1,133 +0,0 @@ -//go:build linux - -package main - -import ( - "os" - "path/filepath" - "strings" - "testing" -) - -func TestParseConfig_defaults(t *testing.T) { - defaults := settings{ - primaryAddr: "192.168.0.120", - secondaryAddr: "192.168.1.120", - } - cfg := parseConfig("", defaults) - if cfg.primaryAddr != "192.168.0.120" || cfg.secondaryAddr != "192.168.1.120" { - t.Fatalf("got primary=%q secondary=%q", cfg.primaryAddr, cfg.secondaryAddr) - } -} - -func TestParseConfig_overrides(t *testing.T) { - text := `# club subnet -PRIMARY=10.0.0.50 -SECONDARY=10.0.1.50 -` - defaults := settings{ - primaryAddr: "192.168.0.120", - secondaryAddr: "192.168.1.120", - } - cfg := parseConfig(text, defaults) - if cfg.primaryAddr != "10.0.0.50" || cfg.secondaryAddr != "10.0.1.50" { - t.Fatalf("got primary=%q secondary=%q", cfg.primaryAddr, cfg.secondaryAddr) - } -} - -func TestParseConfig_ignoresInvalidIP(t *testing.T) { - text := "PRIMARY=not-an-ip\nSECONDARY=192.168.1.99\n" - defaults := settings{ - primaryAddr: "192.168.0.120", - secondaryAddr: "192.168.1.120", - } - cfg := parseConfig(text, defaults) - if cfg.primaryAddr != "192.168.0.120" || cfg.secondaryAddr != "192.168.1.99" { - t.Fatalf("got primary=%q secondary=%q", cfg.primaryAddr, cfg.secondaryAddr) - } -} - -func TestGatewayFor(t *testing.T) { - tests := map[string]string{ - "192.168.0.120": "192.168.0.1", - "192.168.1.120": "192.168.1.1", - "10.20.30.40": "10.20.30.1", - } - for addr, want := range tests { - if got := gatewayFor(addr); got != want { - t.Fatalf("gatewayFor(%q) = %q, want %q", addr, got, want) - } - } - if gatewayFor("bad") != "" { - t.Fatal("expected empty gateway for invalid address") - } -} - -func TestLoadOrCreateConfig_createsFile(t *testing.T) { - dir := t.TempDir() - path := filepath.Join(dir, "configure-ethernet.conf") - - cfg, err := loadOrCreateConfig(path, "192.168.0.120", "192.168.1.120") - if err != nil { - t.Fatal(err) - } - if cfg.primaryAddr != "192.168.0.120" || cfg.secondaryAddr != "192.168.1.120" { - t.Fatalf("got primary=%q secondary=%q", cfg.primaryAddr, cfg.secondaryAddr) - } - - data, err := os.ReadFile(path) - if err != nil { - t.Fatal(err) - } - body := string(data) - for _, want := range []string{ - "PRIMARY=192.168.0.120", - "SECONDARY=192.168.1.120", - } { - if !strings.Contains(body, want) { - t.Fatalf("missing %q in:\n%s", want, data) - } - } -} - -func TestLoadOrCreateConfig_readsExisting(t *testing.T) { - dir := t.TempDir() - path := filepath.Join(dir, "configure-ethernet.conf") - content := "PRIMARY=172.16.0.8\nSECONDARY=172.16.1.8\n" - if err := os.WriteFile(path, []byte(content), 0o644); err != nil { - t.Fatal(err) - } - - cfg, err := loadOrCreateConfig(path, "192.168.0.120", "192.168.1.120") - if err != nil { - t.Fatal(err) - } - if cfg.primaryAddr != "172.16.0.8" || cfg.secondaryAddr != "172.16.1.8" { - t.Fatalf("got primary=%q secondary=%q", cfg.primaryAddr, cfg.secondaryAddr) - } -} - -func TestIsWireless(t *testing.T) { - root := t.TempDir() - eth := filepath.Join(root, "eth0") - wlan := filepath.Join(root, "wlan0") - - if err := os.MkdirAll(filepath.Join(eth, "device"), 0o755); err != nil { - t.Fatal(err) - } - if err := os.MkdirAll(filepath.Join(wlan, "wireless"), 0o755); err != nil { - t.Fatal(err) - } - - if isWirelessAt(root, "eth0") { - t.Fatal("eth0 should not be wireless") - } - if !isWirelessAt(root, "wlan0") { - t.Fatal("wlan0 should be wireless") - } -} - -func isWirelessAt(root, iface string) bool { - _, err := os.Stat(filepath.Join(root, iface, "wireless")) - return err == nil -} diff --git a/os/Makefile b/os/Makefile index 0b72a93..b74e615 100644 --- a/os/Makefile +++ b/os/Makefile @@ -15,6 +15,8 @@ APPS_BIN_DIR := $(REPO_ROOT)/apps/.bin BIGFRED_OCI_TAG ?= latest-release # microinit PID 1 OCI tag (also: BR2_PACKAGE_MICROINIT_OCI_TAG) MICROINIT_OCI_TAG ?= main +# micronet tools OCI tag (also: BR2_PACKAGE_MICRONET_OCI_TAG) +MICRONET_OCI_TAG ?= main BUILDROOT_TAR = $(CURDIR)/buildroot-$(BUILDROOT_VERSION).tar.gz BR2_MAKE = $(MAKE) -C $(BUILDROOT_DIR) O=$(OUTPUT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) @@ -43,6 +45,7 @@ help: @echo "Artifact: $(OUTPUT_DIR)/images/hub-nvme.img" @echo "BigFred OCI tag: BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) (master|latest-release|v*)" @echo "microinit OCI tag: MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) (main|sha-*)" + @echo "micronet OCI tag: MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) (main|sha-*|v*)" $(BUILDROOT_DIR)/Makefile: $(BUILDROOT_TAR) rm -rf $(BUILDROOT_DIR) @@ -76,7 +79,7 @@ image: defconfig fi; \ fi $(MAKE) -C $(REPO_ROOT)/apps build - $(BR2_MAKE) BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) + $(BR2_MAKE) BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) @echo "" @echo "Image ready: $(OUTPUT_DIR)/images/hub-nvme.img" @ls -lh "$(OUTPUT_DIR)/images/hub-nvme.img" 2>/dev/null || true diff --git a/os/board/bigfred_hub/post-build.sh b/os/board/bigfred_hub/post-build.sh index 5b7ebbf..d7a86cf 100755 --- a/os/board/bigfred_hub/post-build.sh +++ b/os/board/bigfred_hub/post-build.sh @@ -53,6 +53,10 @@ if [ -d "${APPS_BIN}" ]; then # Replaced by microinit (package/microinit) continue ;; + configure-ethernet|configure-dhcp) + # Replaced by micronet (package/micronet) + continue + ;; esac [ -x "$bin" ] || chmod 755 "$bin" name=$(basename "$bin") diff --git a/os/configs/bigfred_hub_rpi5_defconfig b/os/configs/bigfred_hub_rpi5_defconfig index 62cc341..0984e7a 100644 --- a/os/configs/bigfred_hub_rpi5_defconfig +++ b/os/configs/bigfred_hub_rpi5_defconfig @@ -93,6 +93,8 @@ BR2_PACKAGE_BIGFRED=y BR2_PACKAGE_BIGFRED_OCI_TAG="latest-release" BR2_PACKAGE_MICROINIT=y BR2_PACKAGE_MICROINIT_OCI_TAG="main" +BR2_PACKAGE_MICRONET=y +BR2_PACKAGE_MICRONET_OCI_TAG="main" BR2_PACKAGE_GRAFANA=y BR2_PACKAGE_VICTORIAMETRICS=y diff --git a/os/package/Config.in b/os/package/Config.in index e89f686..6badd72 100644 --- a/os/package/Config.in +++ b/os/package/Config.in @@ -54,6 +54,27 @@ config BR2_PACKAGE_MICROINIT_OCI_TAG endif +config BR2_PACKAGE_MICRONET + bool "micronet (configure-ethernet + configure-dhcp from GHCR OCI)" + default y + help + Pull ghcr.io/dcc-bigfred/micronet-linux-arm64 via oras and + install /usr/sbin/configure-ethernet and /usr/sbin/configure-dhcp. + + https://github.com/dcc-bigfred/micronet + +if BR2_PACKAGE_MICRONET + +config BR2_PACKAGE_MICRONET_OCI_TAG + string "OCI tag (main | sha-<7> | v*)" + default "main" + help + Tag of ghcr.io/dcc-bigfred/micronet-linux-arm64. + Override: make image MICRONET_OCI_TAG=main + Floating tags are re-pulled each download. + +endif + config BR2_PACKAGE_GRAFANA bool "Grafana OSS (prebuilt binary)" default y diff --git a/os/package/micronet/README.md b/os/package/micronet/README.md new file mode 100644 index 0000000..515030a --- /dev/null +++ b/os/package/micronet/README.md @@ -0,0 +1,12 @@ +# micronet (Buildroot package) + +Pulls [`ghcr.io/dcc-bigfred/micronet-linux-arm64`](https://github.com/dcc-bigfred/micronet) +via ORAS and installs: + +- `/usr/sbin/configure-ethernet` — club Ethernet bring-up (`network` / microinit) +- `/usr/sbin/configure-dhcp` — event WiFi DHCP when Omada (or other stack) detected + +Default OCI tag: `main` (override: `make image MICRONET_OCI_TAG=…` or +`BR2_PACKAGE_MICRONET_OCI_TAG`). + +Source: https://github.com/dcc-bigfred/micronet diff --git a/os/package/micronet/fetch-oci.sh b/os/package/micronet/fetch-oci.sh new file mode 100755 index 0000000..b82426b --- /dev/null +++ b/os/package/micronet/fetch-oci.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# Pull micronet linux/arm64 OCI bundle from GHCR and write a tar for Buildroot. +# Usage: fetch-oci.sh +# +# Env: +# MICRONET_OCI_IMAGE — default ghcr.io/dcc-bigfred/micronet-linux-arm64 +# GITHUB_TOKEN / GH_TOKEN / BIGFRED_NATIVE_TOKEN — optional GHCR auth +set -euo pipefail + +TAG="${1:?usage: $0 }" +OUT="${2:?usage: $0 }" +IMAGE="${MICRONET_OCI_IMAGE:-ghcr.io/dcc-bigfred/micronet-linux-arm64}" + +if ! command -v oras >/dev/null 2>&1; then + echo "error: oras not on PATH (install via docker/install-buildroot-deps.sh)" >&2 + exit 1 +fi + +TOKEN="${BIGFRED_NATIVE_TOKEN:-${GH_TOKEN:-${GITHUB_TOKEN:-}}}" +if [[ -n "${TOKEN}" ]]; then + USER="${GITHUB_ACTOR:-oauth2}" + echo "${TOKEN}" | oras login ghcr.io -u "${USER}" --password-stdin >/dev/null +fi + +tmpdir="$(mktemp -d)" +cleanup() { rm -rf "${tmpdir}"; } +trap cleanup EXIT + +pull_tag() { + local t="$1" + rm -rf "${tmpdir:?}"/* + mkdir -p "${tmpdir}" + echo "Pulling ${IMAGE}:${t}…" + oras pull "${IMAGE}:${t}" -o "${tmpdir}" +} + +if ! pull_tag "${TAG}"; then + echo "error: could not pull ${IMAGE}:${TAG}" >&2 + exit 1 +fi + +DHCP="${tmpdir}/configure-dhcp-linux-arm64" +ETH="${tmpdir}/configure-ethernet-linux-arm64" +if [[ ! -f "${DHCP}" ]] || [[ ! -f "${ETH}" ]]; then + echo "error: expected configure-dhcp-linux-arm64 and configure-ethernet-linux-arm64, found:" >&2 + find "${tmpdir}" -type f >&2 + exit 1 +fi + +chmod 755 "${DHCP}" "${ETH}" +mkdir -p "$(dirname "${OUT}")" +staged="${tmpdir}/stage" +mkdir -p "${staged}/bin" +cp -f "${DHCP}" "${staged}/bin/configure-dhcp" +cp -f "${ETH}" "${staged}/bin/configure-ethernet" +tar -C "${staged}" -cf "${OUT}" bin +echo "Wrote ${OUT} ($(wc -c < "${OUT}") bytes) from ${IMAGE}:${TAG}" diff --git a/os/package/micronet/micronet.mk b/os/package/micronet/micronet.mk new file mode 100644 index 0000000..2b8b04f --- /dev/null +++ b/os/package/micronet/micronet.mk @@ -0,0 +1,44 @@ +################################################################################ +# +# micronet — configure-ethernet + configure-dhcp from GHCR OCI bundle +# (ghcr.io/dcc-bigfred/micronet-linux-arm64) +# +################################################################################ + +MICRONET_VERSION = $(call qstrip,$(MICRONET_OCI_TAG)) +ifeq ($(MICRONET_VERSION),) +MICRONET_VERSION = $(call qstrip,$(BR2_PACKAGE_MICRONET_OCI_TAG)) +endif +ifeq ($(MICRONET_VERSION),) +MICRONET_VERSION = main +endif + +MICRONET_VERSION_SAFE = $(subst /,_,$(MICRONET_VERSION)) + +MICRONET_SOURCE = micronet-linux-arm64-$(MICRONET_VERSION_SAFE).tar +MICRONET_SITE = https://ghcr.io/dcc-bigfred/micronet-linux-arm64 +MICRONET_LICENSE = MIT + +define MICRONET_FETCH_OCI + mkdir -p $(MICRONET_DL_DIR) + rm -f "$(MICRONET_DL_DIR)/$(MICRONET_SOURCE)" + $(MICRONET_PKGDIR)/fetch-oci.sh "$(MICRONET_VERSION)" \ + "$(MICRONET_DL_DIR)/$(MICRONET_SOURCE)" +endef +MICRONET_PRE_DOWNLOAD_HOOKS += MICRONET_FETCH_OCI + +define MICRONET_EXTRACT_CMDS + $(TAR) -C $(@D) -xf $(MICRONET_DL_DIR)/$(MICRONET_SOURCE) +endef + +define MICRONET_INSTALL_TARGET_CMDS + $(INSTALL) -D -m 0755 $(@D)/bin/configure-ethernet \ + $(TARGET_DIR)/usr/sbin/configure-ethernet + $(INSTALL) -D -m 0755 $(@D)/bin/configure-dhcp \ + $(TARGET_DIR)/usr/sbin/configure-dhcp +endef + +$(eval $(generic-package)) + +.PHONY: MICRONET_FORCE_REDOWNLOAD +$(MICRONET_DIR)/.stamp_downloaded: MICRONET_FORCE_REDOWNLOAD From 2588b735b48fcc25d1a2c94cb8de3365ce775908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:39:00 +0200 Subject: [PATCH 3/5] Fetch hub binaries from GitHub Actions/Releases instead of ORAS. Bootstrap dcc-bigfred/.github @ v2 for fetch-github-binaries.sh; replace package fetch-oci wrappers; drop oras from build host deps. Co-authored-by: Cursor --- .github/workflows/build-hub-os.yml | 21 +++++++--- .gitignore | 1 + docker/install-buildroot-deps.sh | 20 +--------- os/Makefile | 37 ++++++++++++----- os/package/Config.in | 36 ++++++++--------- os/package/bigfred/README.md | 64 ++++-------------------------- os/package/bigfred/bigfred.mk | 25 ++++-------- os/package/bigfred/fetch-oci.sh | 63 ----------------------------- os/package/bigfred/fetch.sh | 33 +++++++++++++++ os/package/microinit/README.md | 33 +++------------ os/package/microinit/fetch-oci.sh | 62 ----------------------------- os/package/microinit/fetch.sh | 36 +++++++++++++++++ os/package/microinit/microinit.mk | 27 +++---------- os/package/micronet/README.md | 15 +++---- os/package/micronet/fetch-oci.sh | 57 -------------------------- os/package/micronet/fetch.sh | 29 ++++++++++++++ os/package/micronet/micronet.mk | 12 +++--- 17 files changed, 201 insertions(+), 370 deletions(-) delete mode 100755 os/package/bigfred/fetch-oci.sh create mode 100755 os/package/bigfred/fetch.sh delete mode 100755 os/package/microinit/fetch-oci.sh create mode 100755 os/package/microinit/fetch.sh delete mode 100755 os/package/micronet/fetch-oci.sh create mode 100755 os/package/micronet/fetch.sh diff --git a/.github/workflows/build-hub-os.yml b/.github/workflows/build-hub-os.yml index 1e308da..0b27a1a 100644 --- a/.github/workflows/build-hub-os.yml +++ b/.github/workflows/build-hub-os.yml @@ -15,17 +15,20 @@ on: type: boolean default: false bigfred_oci_tag: - description: BigFred hub OCI tag (master | latest-release | v*) + description: BigFred GitHub ref (master | latest-release | v*) type: string default: latest-release microinit_oci_tag: - description: microinit PID 1 OCI tag (main | sha-<7>) + description: microinit GitHub ref (main | sha-<7> | v*) + type: string + default: main + micronet_oci_tag: + description: micronet GitHub ref (main | sha-<7> | v*) type: string default: main permissions: contents: read - packages: read concurrency: group: build-hub-os-${{ github.ref }} @@ -41,6 +44,7 @@ jobs: MAKEFLAGS: -j$(( $(nproc) )) BIGFRED_OCI_TAG: ${{ inputs.bigfred_oci_tag }} MICROINIT_OCI_TAG: ${{ inputs.microinit_oci_tag }} + MICRONET_OCI_TAG: ${{ inputs.micronet_oci_tag }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -100,7 +104,11 @@ jobs: run: make -C apps test - name: Build hub OS image - run: make -C os image BIGFRED_OCI_TAG="${BIGFRED_OCI_TAG}" MICROINIT_OCI_TAG="${MICROINIT_OCI_TAG}" + run: | + make -C os image \ + BIGFRED_OCI_TAG="${BIGFRED_OCI_TAG}" \ + MICROINIT_OCI_TAG="${MICROINIT_OCI_TAG}" \ + MICRONET_OCI_TAG="${MICRONET_OCI_TAG}" - name: Save host toolchain to cache if: success() @@ -128,8 +136,9 @@ jobs: echo "" echo "- Run: \`${{ github.run_number }}\`" echo "- Commit: \`${{ github.sha }}\`" - echo "- BigFred OCI tag: \`${{ inputs.bigfred_oci_tag }}\`" - echo "- microinit OCI tag: \`${{ inputs.microinit_oci_tag }}\`" + echo "- BigFred ref: \`${{ inputs.bigfred_oci_tag }}\`" + echo "- microinit ref: \`${{ inputs.microinit_oci_tag }}\`" + echo "- micronet ref: \`${{ inputs.micronet_oci_tag }}\`" echo "- Artifact: \`bigfred-hub-nvme-${{ github.run_number }}\`" echo "" echo '```' diff --git a/.gitignore b/.gitignore index bae5d43..0b0594b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ apps/prepare-nvme/target/ go/ os/.cache/ .cache/ +.ci-github/ .npm/ .wget-hsts diff --git a/docker/install-buildroot-deps.sh b/docker/install-buildroot-deps.sh index 719c887..9b97051 100755 --- a/docker/install-buildroot-deps.sh +++ b/docker/install-buildroot-deps.sh @@ -43,21 +43,5 @@ apt-get install -y --no-install-recommends \ nodejs \ npm -# ORAS — pull BigFred hub OCI bundle (package/bigfred) -ORAS_VERSION="${ORAS_VERSION:-1.2.2}" -ORAS_ARCH="$(uname -m)" -case "${ORAS_ARCH}" in - x86_64|amd64) ORAS_ARCH=amd64 ;; - aarch64|arm64) ORAS_ARCH=arm64 ;; - *) - echo "error: unsupported arch for oras: ${ORAS_ARCH}" >&2 - exit 1 - ;; -esac -tmp_oras="$(mktemp -d)" -trap 'rm -rf "${tmp_oras}"' EXIT -curl -fsSL \ - "https://github.com/oras-project/oras/releases/download/v${ORAS_VERSION}/oras_${ORAS_VERSION}_linux_${ORAS_ARCH}.tar.gz" \ - | tar -xz -C "${tmp_oras}" -install -m 0755 "${tmp_oras}/oras" /usr/local/bin/oras -oras version +# curl / unzip / python3 already installed — used by package/*/fetch.sh +# (dcc-bigfred/.github fetch-github-binaries.sh). No oras / gh CLI. diff --git a/os/Makefile b/os/Makefile index b74e615..a9df41c 100644 --- a/os/Makefile +++ b/os/Makefile @@ -11,17 +11,21 @@ BUILDROOT_DIR ?= $(CURDIR)/buildroot OUTPUT_DIR ?= $(CURDIR)/output DEFCONFIG ?= bigfred_hub_rpi5_defconfig APPS_BIN_DIR := $(REPO_ROOT)/apps/.bin -# Hub OCI tag override (also: BR2_PACKAGE_BIGFRED_OCI_TAG in menuconfig) +# GitHub refs for package fetch (also BR2_PACKAGE_*_OCI_TAG in menuconfig) BIGFRED_OCI_TAG ?= latest-release -# microinit PID 1 OCI tag (also: BR2_PACKAGE_MICROINIT_OCI_TAG) MICROINIT_OCI_TAG ?= main -# micronet tools OCI tag (also: BR2_PACKAGE_MICRONET_OCI_TAG) MICRONET_OCI_TAG ?= main +CI_SCRIPTS_REPO ?= https://github.com/dcc-bigfred/.github.git +CI_SCRIPTS_REF ?= v2 +CI_SCRIPTS_DIR ?= $(REPO_ROOT)/.ci-github +export CI_SCRIPTS_DIR + BUILDROOT_TAR = $(CURDIR)/buildroot-$(BUILDROOT_VERSION).tar.gz BR2_MAKE = $(MAKE) -C $(BUILDROOT_DIR) O=$(OUTPUT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) -.PHONY: all help buildroot defconfig menuconfig image legal-info clean distclean flash apps-build apps-clean +.PHONY: all help buildroot defconfig menuconfig image legal-info clean distclean flash \ + apps-build apps-clean ci-scripts ci-scripts-update all: image @@ -31,6 +35,19 @@ apps-build: apps-clean: $(MAKE) -C $(REPO_ROOT)/apps clean +$(CI_SCRIPTS_DIR)/.ok: + @echo "Cloning $(CI_SCRIPTS_REPO) @ $(CI_SCRIPTS_REF) → $(CI_SCRIPTS_DIR)" + @rm -rf "$(CI_SCRIPTS_DIR)" + @git clone --depth 1 --branch "$(CI_SCRIPTS_REF)" "$(CI_SCRIPTS_REPO)" "$(CI_SCRIPTS_DIR)" \ + || { echo "error: failed to clone $(CI_SCRIPTS_REPO) @ $(CI_SCRIPTS_REF)"; exit 1; } + @touch "$@" + +ci-scripts: $(CI_SCRIPTS_DIR)/.ok + +ci-scripts-update: + rm -rf "$(CI_SCRIPTS_DIR)" + $(MAKE) "$(CI_SCRIPTS_DIR)/.ok" + help: @echo "BigFred hub OS (Raspberry Pi 5)" @echo "" @@ -38,14 +55,16 @@ help: @echo " make defconfig — load $(DEFCONFIG)" @echo " make menuconfig — customize Buildroot" @echo " make apps-build — build every apps/*/Makefile → apps/.bin/" + @echo " make ci-scripts — clone dcc-bigfred/.github @ $(CI_SCRIPTS_REF) for binary fetch" @echo " make image — apps-build + kernel, rootfs, hub-nvme.img" @echo " make clean — clean build output (keeps download cache)" @echo " make distclean — remove output/ and buildroot/" @echo "" @echo "Artifact: $(OUTPUT_DIR)/images/hub-nvme.img" - @echo "BigFred OCI tag: BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) (master|latest-release|v*)" - @echo "microinit OCI tag: MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) (main|sha-*)" - @echo "micronet OCI tag: MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) (main|sha-*|v*)" + @echo "BigFred ref: BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) (master|latest-release|v*)" + @echo "microinit ref: MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) (main|sha-*|v*)" + @echo "micronet ref: MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) (main|sha-*|v*)" + @echo "Tip refs need GITHUB_TOKEN / GH_TOKEN / BIGFRED_NATIVE_TOKEN" $(BUILDROOT_DIR)/Makefile: $(BUILDROOT_TAR) rm -rf $(BUILDROOT_DIR) @@ -64,7 +83,7 @@ defconfig: buildroot $(CURDIR)/configs/$(DEFCONFIG) menuconfig: buildroot $(BR2_MAKE) menuconfig -image: defconfig +image: defconfig ci-scripts $(BR2_MAKE) linux-pam # BIGFRED_PERMISSIONS uses |xattr; host-makedevs must be built with # -DEXTENDED_ATTRIBUTES. Rebuild when the binary still lacks that support @@ -79,7 +98,7 @@ image: defconfig fi; \ fi $(MAKE) -C $(REPO_ROOT)/apps build - $(BR2_MAKE) BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) + $(BR2_MAKE) BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) CI_SCRIPTS_DIR=$(CI_SCRIPTS_DIR) @echo "" @echo "Image ready: $(OUTPUT_DIR)/images/hub-nvme.img" @ls -lh "$(OUTPUT_DIR)/images/hub-nvme.img" 2>/dev/null || true diff --git a/os/package/Config.in b/os/package/Config.in index 6badd72..d25445e 100644 --- a/os/package/Config.in +++ b/os/package/Config.in @@ -12,9 +12,8 @@ config BR2_PACKAGE_BIGFRED bool "BigFred (loco-server)" default y help - Pull the hub OCI bundle from GHCR - (ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64) via oras and - install /opt/bigfred/bin/{bigfred,bigfred-remote-icmp} plus + Pull hub linux/arm64 binaries from GitHub (Actions tip or Releases) + and install /opt/bigfred/bin/{bigfred,bigfred-remote-icmp} plus /usr/bin wrappers that prefer /data/opt/bigfred over /opt. https://github.com/dcc-bigfred/bigfred @@ -22,21 +21,21 @@ config BR2_PACKAGE_BIGFRED if BR2_PACKAGE_BIGFRED config BR2_PACKAGE_BIGFRED_OCI_TAG - string "OCI tag (master | latest-release | v*)" + string "GitHub ref (master | latest-release | v* | sha-*)" default "latest-release" help - Tag of ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64. - Override at build time with: make image BIGFRED_OCI_TAG=master - Floating tags (master, latest-release) are re-pulled each download. + Ref for dcc-bigfred/bigfred binaries. + Override: make image BIGFRED_OCI_TAG=master + Tip refs need GITHUB_TOKEN; Releases usually do not. endif config BR2_PACKAGE_MICROINIT - bool "microinit (PID 1 from GHCR OCI)" + bool "microinit (PID 1 from GitHub)" default y help - Pull ghcr.io/dcc-bigfred/microinit-linux-arm64 via oras and - install /sbin/init, /usr/sbin/microinit, and /usr/sbin/shutdown. + Pull microinit linux/arm64 from GitHub (Actions tip or Releases) + and install /sbin/init, /usr/sbin/microinit, and /usr/sbin/shutdown. Use with BR2_INIT_NONE so BusyBox does not own /sbin/init. Hub early-boot: overlays/etc/microinit/early-boot.sh @@ -45,33 +44,32 @@ config BR2_PACKAGE_MICROINIT if BR2_PACKAGE_MICROINIT config BR2_PACKAGE_MICROINIT_OCI_TAG - string "OCI tag (main | sha-<7>)" + string "GitHub ref (main | sha-<7> | v*)" default "main" help - Tag of ghcr.io/dcc-bigfred/microinit-linux-arm64. + Ref for dcc-bigfred/microinit binaries. Override: make image MICROINIT_OCI_TAG=main - Floating tags (main, sha-*) are re-pulled each download. + Tip refs need GITHUB_TOKEN. endif config BR2_PACKAGE_MICRONET - bool "micronet (configure-ethernet + configure-dhcp from GHCR OCI)" + bool "micronet (configure-ethernet + configure-dhcp from GitHub)" default y help - Pull ghcr.io/dcc-bigfred/micronet-linux-arm64 via oras and - install /usr/sbin/configure-ethernet and /usr/sbin/configure-dhcp. + Pull configure-ethernet and configure-dhcp from GitHub + (Actions tip or Releases) into /usr/sbin/. https://github.com/dcc-bigfred/micronet if BR2_PACKAGE_MICRONET config BR2_PACKAGE_MICRONET_OCI_TAG - string "OCI tag (main | sha-<7> | v*)" + string "GitHub ref (main | sha-<7> | v*)" default "main" help - Tag of ghcr.io/dcc-bigfred/micronet-linux-arm64. + Ref for dcc-bigfred/micronet binaries. Override: make image MICRONET_OCI_TAG=main - Floating tags are re-pulled each download. endif diff --git a/os/package/bigfred/README.md b/os/package/bigfred/README.md index 119c21b..8b79952 100644 --- a/os/package/bigfred/README.md +++ b/os/package/bigfred/README.md @@ -1,60 +1,10 @@ -# BigFred (`loco-server`) +# bigfred (Buildroot package) -Fetches the hub OCI bundle from GHCR -([`ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64`](https://github.com/dcc-bigfred/bigfred)) -via `oras` and installs: +Pulls [dcc-bigfred/bigfred](https://github.com/dcc-bigfred/bigfred) hub linux/arm64 +binaries via shared GitHub fetch and installs loco-server + remote-icmp under +`/opt/bigfred/bin/` with `/usr/bin` wrappers. -| Path | Role | -|------|------| -| `/opt/bigfred/bin/bigfred` | `loco-server` (`dcc-bus` is a subcommand) | -| `/opt/bigfred/bin/bigfred-remote-icmp` | Wi-Fi RTT probe helper | -| `/usr/bin/bigfred` | Wrapper: prefers `/data/opt/bigfred`, then `/opt/bigfred` | +Default ref: `latest-release` (falls back to `master` if no release exists). +Tip/`master` needs a GitHub token; public Releases usually do not. -Bundle tags (from the `bigfred` CI): - -| Tag | Meaning | -|-----|---------| -| `latest-release` | Latest `v*` release (default) | -| `master` | Tip of `master` | -| `v1.2.3` | Pinned release | -| `sha-<7>` | Immutable commit from a `master` push | - -## Configuration - -Makefile (preferred): - -```bash -make image BIGFRED_OCI_TAG=latest-release -make image BIGFRED_OCI_TAG=master -make image-using-docker BIGFRED_OCI_TAG=v1.2.3 -``` - -Or in `make menuconfig` → *BigFred hub* → **OCI tag**. - -Host requirement: `oras` on `PATH` (installed by `docker/install-buildroot-deps.sh`). -For private GHCR packages, export `GITHUB_TOKEN` (or `GH_TOKEN`). - -Floating tags (`master`, `latest-release`, `sha-*`) are re-pulled on every package -download via a Buildroot `PRE_DOWNLOAD` hook (`oras`). After changing a pinned -`v*` tag, clear the cache if needed: - -```bash -rm -rf os/output/build/bigfred-* os/dl/bigfred -make -C os bigfred-dirclean # if already built -make image BIGFRED_OCI_TAG=v1.2.3 -``` - -## Runtime override - -Drop an updated binary on the RW data partition without reflashing: - -```text -/data/opt/bigfred/bin/bigfred -``` - -`/usr/bin/bigfred` (and `bigfred` / Update tab) prefer `/data/opt` over `/opt`. - -## Init - -`overlays/etc/init.d/bigfred` starts loco-server with CPU affinity on cores 2,3. -`remote-icmp` starts the ICMP helper separately. +Requires `make ci-scripts` (`dcc-bigfred/.github` @ v2). diff --git a/os/package/bigfred/bigfred.mk b/os/package/bigfred/bigfred.mk index 743865f..5ec5c46 100644 --- a/os/package/bigfred/bigfred.mk +++ b/os/package/bigfred/bigfred.mk @@ -1,11 +1,10 @@ ################################################################################ # -# bigfred — loco-server + bigfred-remote-icmp from GHCR OCI bundle -# (ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64) +# bigfred — loco-server + bigfred-remote-icmp from GitHub +# (Actions tip / Releases) # ################################################################################ -# Prefer Makefile override (make image BIGFRED_OCI_TAG=master), else Kconfig. BIGFRED_VERSION = $(call qstrip,$(BIGFRED_OCI_TAG)) ifeq ($(BIGFRED_VERSION),) BIGFRED_VERSION = $(call qstrip,$(BR2_PACKAGE_BIGFRED_OCI_TAG)) @@ -14,31 +13,23 @@ ifeq ($(BIGFRED_VERSION),) BIGFRED_VERSION = latest-release endif -# Sanitize for use as a download filename (no path separators). BIGFRED_VERSION_SAFE = $(subst /,_,$(BIGFRED_VERSION)) BIGFRED_SOURCE = bigfred-hub-linux-arm64-$(BIGFRED_VERSION_SAFE).tar -# SITE is unused for content (PRE_DOWNLOAD fills DL_DIR); keep non-empty so -# Buildroot still registers a MAIN_DOWNLOAD. After the hook creates the -# tarball, dl-wrapper finds it and skips network fetch. -BIGFRED_SITE = https://ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64 +BIGFRED_SITE = https://github.com/dcc-bigfred/bigfred BIGFRED_LICENSE = proprietary BIGFRED_DEPENDENCIES = host-libcap -# No bigfred.hash: floating OCI tags change under the same filename. -# dl-wrapper allows an existing DL file when no .hash is present. -# Buildroot 2025.x dropped *_DOWNLOAD_CMDS; use PRE_DOWNLOAD instead of -# wget/SITE. Floating tags are re-pulled every package download. -define BIGFRED_FETCH_OCI +define BIGFRED_FETCH_GITHUB mkdir -p $(BIGFRED_DL_DIR) case "$(BIGFRED_VERSION)" in \ - master|latest-release|sha-*) \ + master|main|latest-release|sha-*) \ rm -f "$(BIGFRED_DL_DIR)/$(BIGFRED_SOURCE)" ;; \ esac - $(BIGFRED_PKGDIR)/fetch-oci.sh "$(BIGFRED_VERSION)" \ + $(BIGFRED_PKGDIR)/fetch.sh "$(BIGFRED_VERSION)" \ "$(BIGFRED_DL_DIR)/$(BIGFRED_SOURCE)" endef -BIGFRED_PRE_DOWNLOAD_HOOKS += BIGFRED_FETCH_OCI +BIGFRED_PRE_DOWNLOAD_HOOKS += BIGFRED_FETCH_GITHUB define BIGFRED_EXTRACT_CMDS $(TAR) -C $(@D) -xf $(BIGFRED_DL_DIR)/$(BIGFRED_SOURCE) @@ -56,8 +47,6 @@ define BIGFRED_INSTALL_TARGET_CMDS $(TARGET_DIR)/usr/bin/bigfred-remote-icmp endef -# Applied under fakeroot when assembling the rootfs (works in Docker uid 1000 -# builds). Do not setcap in INSTALL_TARGET_CMDS — that runs outside fakeroot. define BIGFRED_PERMISSIONS /opt/bigfred/bin/bigfred-remote-icmp f 755 0 0 - - - - - |xattr cap_net_raw+ep diff --git a/os/package/bigfred/fetch-oci.sh b/os/package/bigfred/fetch-oci.sh deleted file mode 100755 index 5129669..0000000 --- a/os/package/bigfred/fetch-oci.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash -# Pull bigfred hub linux/arm64 OCI bundle from GHCR and write a tar for Buildroot. -# Usage: fetch-oci.sh -# -# Env: -# BIGFRED_HUB_OCI_IMAGE — default ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64 -# GITHUB_TOKEN / GH_TOKEN / BIGFRED_NATIVE_TOKEN — optional GHCR auth -set -euo pipefail - -TAG="${1:?usage: $0 }" -OUT="${2:?usage: $0 }" -IMAGE="${BIGFRED_HUB_OCI_IMAGE:-ghcr.io/dcc-bigfred/bigfred-hub-linux-arm64}" - -if ! command -v oras >/dev/null 2>&1; then - echo "error: oras not on PATH (install via docker/install-buildroot-deps.sh)" >&2 - exit 1 -fi - -TOKEN="${BIGFRED_NATIVE_TOKEN:-${GH_TOKEN:-${GITHUB_TOKEN:-}}}" -if [[ -n "${TOKEN}" ]]; then - USER="${GITHUB_ACTOR:-oauth2}" - echo "${TOKEN}" | oras login ghcr.io -u "${USER}" --password-stdin >/dev/null -fi - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -pull_tag() { - local t="$1" - rm -rf "${tmpdir:?}"/* - mkdir -p "${tmpdir}" - echo "Pulling ${IMAGE}:${t}…" - oras pull "${IMAGE}:${t}" -o "${tmpdir}" -} - -if ! pull_tag "${TAG}"; then - # Before the first v* release after hub OCI landed, :latest-release is absent. - if [[ "${TAG}" == "latest-release" ]] && pull_tag "master"; then - echo "warning: ${IMAGE}:latest-release missing; used :master" >&2 - else - echo "error: could not pull ${IMAGE}:${TAG}" >&2 - exit 1 - fi -fi - -SERVER="${tmpdir}/loco-server-linux-arm64" -ICMP="${tmpdir}/bigfred-remote-icmp-linux-arm64" -if [[ ! -f "${SERVER}" || ! -f "${ICMP}" ]]; then - echo "error: expected loco-server-linux-arm64 and bigfred-remote-icmp-linux-arm64, found:" >&2 - find "${tmpdir}" -type f >&2 - exit 1 -fi - -chmod 755 "${SERVER}" "${ICMP}" -mkdir -p "$(dirname "${OUT}")" -# Stable layout for EXTRACT/INSTALL: bin/bigfred + bin/bigfred-remote-icmp -staged="${tmpdir}/stage" -mkdir -p "${staged}/bin" -cp -f "${SERVER}" "${staged}/bin/bigfred" -cp -f "${ICMP}" "${staged}/bin/bigfred-remote-icmp" -tar -C "${staged}" -cf "${OUT}" bin -echo "Wrote ${OUT} ($(wc -c < "${OUT}") bytes) from ${IMAGE}:${TAG}" diff --git a/os/package/bigfred/fetch.sh b/os/package/bigfred/fetch.sh new file mode 100755 index 0000000..8f76ad5 --- /dev/null +++ b/os/package/bigfred/fetch.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Fetch bigfred hub linux/arm64 binaries (loco-server + remote-icmp). +# Usage: fetch.sh +set -euo pipefail + +REF="${1:?usage: $0 }" +OUT="${2:?usage: $0 }" + +PKGDIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "${PKGDIR}/../../.." && pwd)" +CI_SCRIPTS_DIR="${CI_SCRIPTS_DIR:-${REPO_ROOT}/.ci-github}" +FETCH="${CI_SCRIPTS_DIR}/scripts/fetch-github-binaries.sh" + +if [[ ! -x "${FETCH}" ]]; then + echo "error: missing ${FETCH}" >&2 + echo "hint: from bigfred-os/os run: make ci-scripts" >&2 + exit 1 +fi + +export GITHUB_REPO="${BIGFRED_GITHUB_REPO:-dcc-bigfred/bigfred}" +export ARTIFACT_NAME="${BIGFRED_ARTIFACT_NAME:-binaries}" +export CI_WORKFLOW="${BIGFRED_CI_WORKFLOW:-ci.yml}" +export FILES="${BIGFRED_FILES:-loco-server-linux-arm64:bin/bigfred,bigfred-remote-icmp-linux-arm64:bin/bigfred-remote-icmp}" + +if "${FETCH}" "${REF}" "${OUT}"; then + exit 0 +fi + +if [[ "${REF}" == "latest-release" ]]; then + echo "warning: latest-release missing; trying master" >&2 + exec "${FETCH}" master "${OUT}" +fi +exit 1 diff --git a/os/package/microinit/README.md b/os/package/microinit/README.md index c79b5c5..4bc5485 100644 --- a/os/package/microinit/README.md +++ b/os/package/microinit/README.md @@ -1,32 +1,11 @@ # microinit (Buildroot package) -Pulls [`ghcr.io/dcc-bigfred/microinit-linux-arm64`](https://github.com/dcc-bigfred/microinit) -via `oras` and installs: +Pulls [dcc-bigfred/microinit](https://github.com/dcc-bigfred/microinit) linux/arm64 +binaries via shared GitHub fetch (not the distroless container image) and installs: -- `/sbin/init` — PID 1 -- `/usr/sbin/microinit` — same binary for CLI (`microinit list`, `start`, …) -- `/usr/sbin/shutdown` (+ `/sbin/shutdown` symlink) — SysV-style ordered - poweroff/reboot/halt over the microinit control socket (when present in the - OCI bundle) +- `/usr/sbin/microinit` / `/sbin/init` +- `/usr/sbin/shutdown` when present in the artifact -Hub-specific early-boot and unmount stay in the rootfs overlay: -`overlays/etc/microinit/early-boot.sh` → `/etc/microinit/early-boot.sh`, -`overlays/etc/microinit/unmount.sh` → `/etc/microinit/unmount.sh`. -The portable `early-boot.sh` / `unmount.sh` layers from the OCI artifact are -**not** installed. +Requires `make ci-scripts`. Tip refs need a GitHub token. -## OCI tag - -Default: `main` (also published as `sha-<7>` from microinit CI). - -```bash -make image MICROINIT_OCI_TAG=main -# or pin: MICROINIT_OCI_TAG=sha-abcdef0 -``` - -Menuconfig: `BR2_PACKAGE_MICROINIT_OCI_TAG`. - -Host requirement: `oras` on `PATH` (`docker/install-buildroot-deps.sh`). -Optional auth: `GITHUB_TOKEN` / `GH_TOKEN` / `BIGFRED_NATIVE_TOKEN`. - -Floating tags (`main`, `sha-*`) are re-pulled on each package download. +Default ref: `main`. Overlay scripts stay under `overlays/etc/microinit/`. diff --git a/os/package/microinit/fetch-oci.sh b/os/package/microinit/fetch-oci.sh deleted file mode 100755 index 660aee1..0000000 --- a/os/package/microinit/fetch-oci.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash -# Pull microinit linux/arm64 OCI bundle from GHCR and write a tar for Buildroot. -# Usage: fetch-oci.sh -# -# Env: -# MICROINIT_OCI_IMAGE — default ghcr.io/dcc-bigfred/microinit-linux-arm64 -# GITHUB_TOKEN / GH_TOKEN / BIGFRED_NATIVE_TOKEN — optional GHCR auth -set -euo pipefail - -TAG="${1:?usage: $0 }" -OUT="${2:?usage: $0 }" -IMAGE="${MICROINIT_OCI_IMAGE:-ghcr.io/dcc-bigfred/microinit-linux-arm64}" - -if ! command -v oras >/dev/null 2>&1; then - echo "error: oras not on PATH (install via docker/install-buildroot-deps.sh)" >&2 - exit 1 -fi - -TOKEN="${BIGFRED_NATIVE_TOKEN:-${GH_TOKEN:-${GITHUB_TOKEN:-}}}" -if [[ -n "${TOKEN}" ]]; then - USER="${GITHUB_ACTOR:-oauth2}" - echo "${TOKEN}" | oras login ghcr.io -u "${USER}" --password-stdin >/dev/null -fi - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -pull_tag() { - local t="$1" - rm -rf "${tmpdir:?}"/* - mkdir -p "${tmpdir}" - echo "Pulling ${IMAGE}:${t}…" - oras pull "${IMAGE}:${t}" -o "${tmpdir}" -} - -if ! pull_tag "${TAG}"; then - echo "error: could not pull ${IMAGE}:${TAG}" >&2 - exit 1 -fi - -BIN="${tmpdir}/microinit-linux-arm64" -if [[ ! -f "${BIN}" ]]; then - echo "error: expected microinit-linux-arm64 in OCI layer, found:" >&2 - find "${tmpdir}" -type f >&2 - exit 1 -fi - -chmod 755 "${BIN}" -mkdir -p "$(dirname "${OUT}")" -# Stable layout for EXTRACT/INSTALL: bin/microinit (+ optional bin/shutdown) -# Do not install OCI early-boot.sh / unmount.sh — hub overlay ships both under -# /etc/microinit/. -staged="${tmpdir}/stage" -mkdir -p "${staged}/bin" -cp -f "${BIN}" "${staged}/bin/microinit" -if [[ -f "${tmpdir}/shutdown-linux-arm64" ]]; then - chmod 755 "${tmpdir}/shutdown-linux-arm64" - cp -f "${tmpdir}/shutdown-linux-arm64" "${staged}/bin/shutdown" -fi -tar -C "${staged}" -cf "${OUT}" bin -echo "Wrote ${OUT} ($(wc -c < "${OUT}") bytes) from ${IMAGE}:${TAG}" diff --git a/os/package/microinit/fetch.sh b/os/package/microinit/fetch.sh new file mode 100755 index 0000000..3945fe2 --- /dev/null +++ b/os/package/microinit/fetch.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Fetch microinit linux/arm64 binaries (microinit + optional shutdown). +# Usage: fetch.sh +set -euo pipefail + +REF="${1:?usage: $0 }" +OUT="${2:?usage: $0 }" + +PKGDIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "${PKGDIR}/../../.." && pwd)" +CI_SCRIPTS_DIR="${CI_SCRIPTS_DIR:-${REPO_ROOT}/.ci-github}" +FETCH="${CI_SCRIPTS_DIR}/scripts/fetch-github-binaries.sh" + +if [[ ! -x "${FETCH}" ]]; then + echo "error: missing ${FETCH}" >&2 + echo "hint: from bigfred-os/os run: make ci-scripts" >&2 + exit 1 +fi + +export GITHUB_REPO="${MICROINIT_GITHUB_REPO:-dcc-bigfred/microinit}" +export ARTIFACT_NAME="${MICROINIT_ARTIFACT_NAME:-binaries-arm64}" +export CI_WORKFLOW="${MICROINIT_CI_WORKFLOW:-ci.yml}" + +if [[ -n "${MICROINIT_FILES:-}" ]]; then + export FILES="${MICROINIT_FILES}" + exec "${FETCH}" "${REF}" "${OUT}" +fi + +# Prefer microinit + shutdown; fall back to microinit only. +export FILES="microinit-linux-arm64:bin/microinit,shutdown-linux-arm64:bin/shutdown" +if "${FETCH}" "${REF}" "${OUT}"; then + exit 0 +fi +echo "warning: shutdown layer missing; fetching microinit only" >&2 +export FILES="microinit-linux-arm64:bin/microinit" +exec "${FETCH}" "${REF}" "${OUT}" diff --git a/os/package/microinit/microinit.mk b/os/package/microinit/microinit.mk index e90c058..5005785 100644 --- a/os/package/microinit/microinit.mk +++ b/os/package/microinit/microinit.mk @@ -1,11 +1,10 @@ ################################################################################ # -# microinit — PID 1 / service supervisor from GHCR OCI bundle -# (ghcr.io/dcc-bigfred/microinit-linux-arm64) +# microinit — PID 1 / service supervisor from GitHub +# (Actions tip / Releases; not the distroless container image) # ################################################################################ -# Prefer Makefile override (make image MICROINIT_OCI_TAG=main), else Kconfig. MICROINIT_VERSION = $(call qstrip,$(MICROINIT_OCI_TAG)) ifeq ($(MICROINIT_VERSION),) MICROINIT_VERSION = $(call qstrip,$(BR2_PACKAGE_MICROINIT_OCI_TAG)) @@ -14,26 +13,19 @@ ifeq ($(MICROINIT_VERSION),) MICROINIT_VERSION = main endif -# Sanitize for use as a download filename (no path separators). MICROINIT_VERSION_SAFE = $(subst /,_,$(MICROINIT_VERSION)) MICROINIT_SOURCE = microinit-linux-arm64-$(MICROINIT_VERSION_SAFE).tar -# SITE is unused for content (PRE_DOWNLOAD fills DL_DIR); keep non-empty so -# Buildroot still registers a MAIN_DOWNLOAD. -MICROINIT_SITE = https://ghcr.io/dcc-bigfred/microinit-linux-arm64 +MICROINIT_SITE = https://github.com/dcc-bigfred/microinit MICROINIT_LICENSE = proprietary -# No microinit.hash: floating OCI tags change under the same filename. -# Always re-fetch the OCI artifact: even pinned tags can be re-pushed, and -# floating tags (main/latest-release) change under the same filename. There -# is no microinit.hash, so Buildroot cannot detect content drift on its own. -define MICROINIT_FETCH_OCI +define MICROINIT_FETCH_GITHUB mkdir -p $(MICROINIT_DL_DIR) rm -f "$(MICROINIT_DL_DIR)/$(MICROINIT_SOURCE)" - $(MICROINIT_PKGDIR)/fetch-oci.sh "$(MICROINIT_VERSION)" \ + $(MICROINIT_PKGDIR)/fetch.sh "$(MICROINIT_VERSION)" \ "$(MICROINIT_DL_DIR)/$(MICROINIT_SOURCE)" endef -MICROINIT_PRE_DOWNLOAD_HOOKS += MICROINIT_FETCH_OCI +MICROINIT_PRE_DOWNLOAD_HOOKS += MICROINIT_FETCH_GITHUB define MICROINIT_EXTRACT_CMDS $(TAR) -C $(@D) -xf $(MICROINIT_DL_DIR)/$(MICROINIT_SOURCE) @@ -42,12 +34,8 @@ endef define MICROINIT_INSTALL_TARGET_CMDS $(INSTALL) -D -m 0755 $(@D)/bin/microinit \ $(TARGET_DIR)/usr/sbin/microinit - # PID 1: kernel default /sbin/init $(INSTALL) -D -m 0755 $(@D)/bin/microinit \ $(TARGET_DIR)/sbin/init - # SysV-style shutdown CLI (ordered poweroff/reboot/halt via IPC). - # Present in OCI bundles published after the shutdown binary moved into - # the microinit repo; keep install optional for older tags. if [ -f $(@D)/bin/shutdown ]; then \ $(INSTALL) -D -m 0755 $(@D)/bin/shutdown \ $(TARGET_DIR)/usr/sbin/shutdown; \ @@ -58,8 +46,5 @@ endef $(eval $(generic-package)) -# Force the download step to re-run on every `make image`: without this, -# .stamp_downloaded stays present after the first build and Buildroot skips -# PRE_DOWNLOAD_HOOKS, so a re-pushed OCI tag would never be re-fetched. .PHONY: MICROINIT_FORCE_REDOWNLOAD $(MICROINIT_DIR)/.stamp_downloaded: MICROINIT_FORCE_REDOWNLOAD diff --git a/os/package/micronet/README.md b/os/package/micronet/README.md index 515030a..6a0bf18 100644 --- a/os/package/micronet/README.md +++ b/os/package/micronet/README.md @@ -1,12 +1,13 @@ # micronet (Buildroot package) -Pulls [`ghcr.io/dcc-bigfred/micronet-linux-arm64`](https://github.com/dcc-bigfred/micronet) -via ORAS and installs: +Pulls [dcc-bigfred/micronet](https://github.com/dcc-bigfred/micronet) binaries via +shared `fetch-github-binaries.sh` (tip = Actions artifact; `v*` / `latest-release` += GitHub Release) and installs: -- `/usr/sbin/configure-ethernet` — club Ethernet bring-up (`network` / microinit) -- `/usr/sbin/configure-dhcp` — event WiFi DHCP when Omada (or other stack) detected +- `/usr/sbin/configure-ethernet` +- `/usr/sbin/configure-dhcp` -Default OCI tag: `main` (override: `make image MICRONET_OCI_TAG=…` or -`BR2_PACKAGE_MICRONET_OCI_TAG`). +Requires `make ci-scripts` (clones `dcc-bigfred/.github` @ v2). Tip refs need a +GitHub token in the environment. -Source: https://github.com/dcc-bigfred/micronet +Default ref: `main` (`MICRONET_OCI_TAG` / `BR2_PACKAGE_MICRONET_OCI_TAG`). diff --git a/os/package/micronet/fetch-oci.sh b/os/package/micronet/fetch-oci.sh deleted file mode 100755 index b82426b..0000000 --- a/os/package/micronet/fetch-oci.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -# Pull micronet linux/arm64 OCI bundle from GHCR and write a tar for Buildroot. -# Usage: fetch-oci.sh -# -# Env: -# MICRONET_OCI_IMAGE — default ghcr.io/dcc-bigfred/micronet-linux-arm64 -# GITHUB_TOKEN / GH_TOKEN / BIGFRED_NATIVE_TOKEN — optional GHCR auth -set -euo pipefail - -TAG="${1:?usage: $0 }" -OUT="${2:?usage: $0 }" -IMAGE="${MICRONET_OCI_IMAGE:-ghcr.io/dcc-bigfred/micronet-linux-arm64}" - -if ! command -v oras >/dev/null 2>&1; then - echo "error: oras not on PATH (install via docker/install-buildroot-deps.sh)" >&2 - exit 1 -fi - -TOKEN="${BIGFRED_NATIVE_TOKEN:-${GH_TOKEN:-${GITHUB_TOKEN:-}}}" -if [[ -n "${TOKEN}" ]]; then - USER="${GITHUB_ACTOR:-oauth2}" - echo "${TOKEN}" | oras login ghcr.io -u "${USER}" --password-stdin >/dev/null -fi - -tmpdir="$(mktemp -d)" -cleanup() { rm -rf "${tmpdir}"; } -trap cleanup EXIT - -pull_tag() { - local t="$1" - rm -rf "${tmpdir:?}"/* - mkdir -p "${tmpdir}" - echo "Pulling ${IMAGE}:${t}…" - oras pull "${IMAGE}:${t}" -o "${tmpdir}" -} - -if ! pull_tag "${TAG}"; then - echo "error: could not pull ${IMAGE}:${TAG}" >&2 - exit 1 -fi - -DHCP="${tmpdir}/configure-dhcp-linux-arm64" -ETH="${tmpdir}/configure-ethernet-linux-arm64" -if [[ ! -f "${DHCP}" ]] || [[ ! -f "${ETH}" ]]; then - echo "error: expected configure-dhcp-linux-arm64 and configure-ethernet-linux-arm64, found:" >&2 - find "${tmpdir}" -type f >&2 - exit 1 -fi - -chmod 755 "${DHCP}" "${ETH}" -mkdir -p "$(dirname "${OUT}")" -staged="${tmpdir}/stage" -mkdir -p "${staged}/bin" -cp -f "${DHCP}" "${staged}/bin/configure-dhcp" -cp -f "${ETH}" "${staged}/bin/configure-ethernet" -tar -C "${staged}" -cf "${OUT}" bin -echo "Wrote ${OUT} ($(wc -c < "${OUT}") bytes) from ${IMAGE}:${TAG}" diff --git a/os/package/micronet/fetch.sh b/os/package/micronet/fetch.sh new file mode 100755 index 0000000..1332931 --- /dev/null +++ b/os/package/micronet/fetch.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Fetch micronet linux/arm64 binaries (configure-dhcp + configure-ethernet). +# Usage: fetch.sh +# +# Env: MICRONET_GITHUB_REPO (default dcc-bigfred/micronet) +# CI_SCRIPTS_DIR — path to cloned dcc-bigfred/.github (default /.ci-github) +# BIGFRED_NATIVE_TOKEN / GH_TOKEN / GITHUB_TOKEN — required for tip refs +set -euo pipefail + +REF="${1:?usage: $0 }" +OUT="${2:?usage: $0 }" + +PKGDIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "${PKGDIR}/../../.." && pwd)" +CI_SCRIPTS_DIR="${CI_SCRIPTS_DIR:-${REPO_ROOT}/.ci-github}" +FETCH="${CI_SCRIPTS_DIR}/scripts/fetch-github-binaries.sh" + +if [[ ! -x "${FETCH}" ]]; then + echo "error: missing ${FETCH}" >&2 + echo "hint: from bigfred-os/os run: make ci-scripts (clones dcc-bigfred/.github @ v2)" >&2 + exit 1 +fi + +export GITHUB_REPO="${MICRONET_GITHUB_REPO:-dcc-bigfred/micronet}" +export ARTIFACT_NAME="${MICRONET_ARTIFACT_NAME:-binaries-arm64}" +export CI_WORKFLOW="${MICRONET_CI_WORKFLOW:-ci.yml}" +export FILES="${MICRONET_FILES:-configure-dhcp-linux-arm64:bin/configure-dhcp,configure-ethernet-linux-arm64:bin/configure-ethernet}" + +exec "${FETCH}" "${REF}" "${OUT}" diff --git a/os/package/micronet/micronet.mk b/os/package/micronet/micronet.mk index 2b8b04f..1fdbc16 100644 --- a/os/package/micronet/micronet.mk +++ b/os/package/micronet/micronet.mk @@ -1,7 +1,7 @@ ################################################################################ # -# micronet — configure-ethernet + configure-dhcp from GHCR OCI bundle -# (ghcr.io/dcc-bigfred/micronet-linux-arm64) +# micronet — configure-ethernet + configure-dhcp from GitHub +# (Actions tip / Releases) # ################################################################################ @@ -16,16 +16,16 @@ endif MICRONET_VERSION_SAFE = $(subst /,_,$(MICRONET_VERSION)) MICRONET_SOURCE = micronet-linux-arm64-$(MICRONET_VERSION_SAFE).tar -MICRONET_SITE = https://ghcr.io/dcc-bigfred/micronet-linux-arm64 +MICRONET_SITE = https://github.com/dcc-bigfred/micronet MICRONET_LICENSE = MIT -define MICRONET_FETCH_OCI +define MICRONET_FETCH_GITHUB mkdir -p $(MICRONET_DL_DIR) rm -f "$(MICRONET_DL_DIR)/$(MICRONET_SOURCE)" - $(MICRONET_PKGDIR)/fetch-oci.sh "$(MICRONET_VERSION)" \ + $(MICRONET_PKGDIR)/fetch.sh "$(MICRONET_VERSION)" \ "$(MICRONET_DL_DIR)/$(MICRONET_SOURCE)" endef -MICRONET_PRE_DOWNLOAD_HOOKS += MICRONET_FETCH_OCI +MICRONET_PRE_DOWNLOAD_HOOKS += MICRONET_FETCH_GITHUB define MICRONET_EXTRACT_CMDS $(TAR) -C $(@D) -xf $(MICRONET_DL_DIR)/$(MICRONET_SOURCE) From 39fe57c7a3ad4957f48418e1fd8c81ada861422f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 19:52:13 +0200 Subject: [PATCH 4/5] Fetch binaries via go run dcc-bigfred/common/cmd/fetch. Replace .ci-github bootstrap and Python fetch with thin package/*/fetch.sh wrappers. Drop python3-requests host dep; Go is already installed. Co-authored-by: Cursor --- docker/install-buildroot-deps.sh | 4 +-- os/Makefile | 28 ++++--------------- os/package/bigfred/fetch.sh | 48 +++++++++++++++++++++----------- os/package/microinit/fetch.sh | 45 +++++++++++++----------------- os/package/micronet/README.md | 6 ++-- os/package/micronet/fetch.sh | 36 +++++++++++++----------- 6 files changed, 82 insertions(+), 85 deletions(-) diff --git a/docker/install-buildroot-deps.sh b/docker/install-buildroot-deps.sh index 9b97051..b78dade 100755 --- a/docker/install-buildroot-deps.sh +++ b/docker/install-buildroot-deps.sh @@ -43,5 +43,5 @@ apt-get install -y --no-install-recommends \ nodejs \ npm -# curl / unzip / python3 already installed — used by package/*/fetch.sh -# (dcc-bigfred/.github fetch-github-binaries.sh). No oras / gh CLI. +# python3 is a Buildroot host requirement. Binary fetch uses Go +# (go run github.com/dcc-bigfred/common/cmd/fetch@latest). No oras / gh CLI. diff --git a/os/Makefile b/os/Makefile index a9df41c..5ca875f 100644 --- a/os/Makefile +++ b/os/Makefile @@ -1,5 +1,6 @@ # BigFred hub OS — Buildroot wrapper # Requires: host packages per https://buildroot.org/downloads/manual/manual.html#requirement +# Binary fetch uses: go run github.com/dcc-bigfred/common/cmd/fetch@latest BUILDROOT_VERSION ?= 2025.02 BUILDROOT_URL = https://github.com/buildroot/buildroot/archive/$(BUILDROOT_VERSION).tar.gz @@ -16,16 +17,11 @@ BIGFRED_OCI_TAG ?= latest-release MICROINIT_OCI_TAG ?= main MICRONET_OCI_TAG ?= main -CI_SCRIPTS_REPO ?= https://github.com/dcc-bigfred/.github.git -CI_SCRIPTS_REF ?= v2 -CI_SCRIPTS_DIR ?= $(REPO_ROOT)/.ci-github -export CI_SCRIPTS_DIR - BUILDROOT_TAR = $(CURDIR)/buildroot-$(BUILDROOT_VERSION).tar.gz BR2_MAKE = $(MAKE) -C $(BUILDROOT_DIR) O=$(OUTPUT_DIR) BR2_EXTERNAL=$(BR2_EXTERNAL) .PHONY: all help buildroot defconfig menuconfig image legal-info clean distclean flash \ - apps-build apps-clean ci-scripts ci-scripts-update + apps-build apps-clean all: image @@ -35,19 +31,6 @@ apps-build: apps-clean: $(MAKE) -C $(REPO_ROOT)/apps clean -$(CI_SCRIPTS_DIR)/.ok: - @echo "Cloning $(CI_SCRIPTS_REPO) @ $(CI_SCRIPTS_REF) → $(CI_SCRIPTS_DIR)" - @rm -rf "$(CI_SCRIPTS_DIR)" - @git clone --depth 1 --branch "$(CI_SCRIPTS_REF)" "$(CI_SCRIPTS_REPO)" "$(CI_SCRIPTS_DIR)" \ - || { echo "error: failed to clone $(CI_SCRIPTS_REPO) @ $(CI_SCRIPTS_REF)"; exit 1; } - @touch "$@" - -ci-scripts: $(CI_SCRIPTS_DIR)/.ok - -ci-scripts-update: - rm -rf "$(CI_SCRIPTS_DIR)" - $(MAKE) "$(CI_SCRIPTS_DIR)/.ok" - help: @echo "BigFred hub OS (Raspberry Pi 5)" @echo "" @@ -55,7 +38,6 @@ help: @echo " make defconfig — load $(DEFCONFIG)" @echo " make menuconfig — customize Buildroot" @echo " make apps-build — build every apps/*/Makefile → apps/.bin/" - @echo " make ci-scripts — clone dcc-bigfred/.github @ $(CI_SCRIPTS_REF) for binary fetch" @echo " make image — apps-build + kernel, rootfs, hub-nvme.img" @echo " make clean — clean build output (keeps download cache)" @echo " make distclean — remove output/ and buildroot/" @@ -65,6 +47,7 @@ help: @echo "microinit ref: MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) (main|sha-*|v*)" @echo "micronet ref: MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) (main|sha-*|v*)" @echo "Tip refs need GITHUB_TOKEN / GH_TOKEN / BIGFRED_NATIVE_TOKEN" + @echo "Binary fetch: go run github.com/dcc-bigfred/common/cmd/fetch@latest" $(BUILDROOT_DIR)/Makefile: $(BUILDROOT_TAR) rm -rf $(BUILDROOT_DIR) @@ -83,7 +66,8 @@ defconfig: buildroot $(CURDIR)/configs/$(DEFCONFIG) menuconfig: buildroot $(BR2_MAKE) menuconfig -image: defconfig ci-scripts +image: defconfig + @command -v go >/dev/null 2>&1 || { echo "error: go required for package/*/fetch.sh"; exit 1; } $(BR2_MAKE) linux-pam # BIGFRED_PERMISSIONS uses |xattr; host-makedevs must be built with # -DEXTENDED_ATTRIBUTES. Rebuild when the binary still lacks that support @@ -98,7 +82,7 @@ image: defconfig ci-scripts fi; \ fi $(MAKE) -C $(REPO_ROOT)/apps build - $(BR2_MAKE) BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) CI_SCRIPTS_DIR=$(CI_SCRIPTS_DIR) + $(BR2_MAKE) BIGFRED_OCI_TAG=$(BIGFRED_OCI_TAG) MICROINIT_OCI_TAG=$(MICROINIT_OCI_TAG) MICRONET_OCI_TAG=$(MICRONET_OCI_TAG) @echo "" @echo "Image ready: $(OUTPUT_DIR)/images/hub-nvme.img" @ls -lh "$(OUTPUT_DIR)/images/hub-nvme.img" 2>/dev/null || true diff --git a/os/package/bigfred/fetch.sh b/os/package/bigfred/fetch.sh index 8f76ad5..8dccb9a 100755 --- a/os/package/bigfred/fetch.sh +++ b/os/package/bigfred/fetch.sh @@ -1,33 +1,49 @@ #!/usr/bin/env bash # Fetch bigfred hub linux/arm64 binaries (loco-server + remote-icmp). # Usage: fetch.sh +# +# Env overrides: BIGFRED_GITHUB_REPO, BIGFRED_ARTIFACT_NAME, +# BIGFRED_CI_WORKFLOW, BIGFRED_FILES +# Token: BIGFRED_NATIVE_TOKEN / GH_TOKEN / GITHUB_TOKEN (required for tip refs) set -euo pipefail REF="${1:?usage: $0 }" OUT="${2:?usage: $0 }" -PKGDIR="$(cd "$(dirname "$0")" && pwd)" -REPO_ROOT="$(cd "${PKGDIR}/../../.." && pwd)" -CI_SCRIPTS_DIR="${CI_SCRIPTS_DIR:-${REPO_ROOT}/.ci-github}" -FETCH="${CI_SCRIPTS_DIR}/scripts/fetch-github-binaries.sh" - -if [[ ! -x "${FETCH}" ]]; then - echo "error: missing ${FETCH}" >&2 - echo "hint: from bigfred-os/os run: make ci-scripts" >&2 +command -v go >/dev/null 2>&1 || { + echo "error: go is required (install Go toolchain)" >&2 exit 1 -fi +} + +export GOPROXY="${GOPROXY:-direct}" +FETCH_PKG="${FETCH_PKG:-github.com/dcc-bigfred/common/cmd/fetch@latest}" + +REPO="${BIGFRED_GITHUB_REPO:-dcc-bigfred/bigfred}" +ARTIFACT="${BIGFRED_ARTIFACT_NAME:-binaries}" +WORKFLOW="${BIGFRED_CI_WORKFLOW:-ci.yml}" +FILES="${BIGFRED_FILES:-loco-server-linux-arm64:bin/bigfred,bigfred-remote-icmp-linux-arm64:bin/bigfred-remote-icmp}" -export GITHUB_REPO="${BIGFRED_GITHUB_REPO:-dcc-bigfred/bigfred}" -export ARTIFACT_NAME="${BIGFRED_ARTIFACT_NAME:-binaries}" -export CI_WORKFLOW="${BIGFRED_CI_WORKFLOW:-ci.yml}" -export FILES="${BIGFRED_FILES:-loco-server-linux-arm64:bin/bigfred,bigfred-remote-icmp-linux-arm64:bin/bigfred-remote-icmp}" +set +e +go run "${FETCH_PKG}" \ + --repo="${REPO}" \ + --files="${FILES}" \ + --artifact="${ARTIFACT}" \ + --workflow="${WORKFLOW}" \ + "${REF}" "${OUT}" +rc=$? +set -e -if "${FETCH}" "${REF}" "${OUT}"; then +if [[ "${rc}" -eq 0 ]]; then exit 0 fi if [[ "${REF}" == "latest-release" ]]; then echo "warning: latest-release missing; trying master" >&2 - exec "${FETCH}" master "${OUT}" + exec go run "${FETCH_PKG}" \ + --repo="${REPO}" \ + --files="${FILES}" \ + --artifact="${ARTIFACT}" \ + --workflow="${WORKFLOW}" \ + master "${OUT}" fi -exit 1 +exit "${rc}" diff --git a/os/package/microinit/fetch.sh b/os/package/microinit/fetch.sh index 3945fe2..0185bcf 100755 --- a/os/package/microinit/fetch.sh +++ b/os/package/microinit/fetch.sh @@ -1,36 +1,31 @@ #!/usr/bin/env bash -# Fetch microinit linux/arm64 binaries (microinit + optional shutdown). +# Fetch microinit linux/arm64 binaries (microinit + shutdown). # Usage: fetch.sh +# +# Env overrides: MICROINIT_GITHUB_REPO, MICROINIT_ARTIFACT_NAME, +# MICROINIT_CI_WORKFLOW, MICROINIT_FILES +# Token: BIGFRED_NATIVE_TOKEN / GH_TOKEN / GITHUB_TOKEN (required for tip refs) set -euo pipefail REF="${1:?usage: $0 }" OUT="${2:?usage: $0 }" -PKGDIR="$(cd "$(dirname "$0")" && pwd)" -REPO_ROOT="$(cd "${PKGDIR}/../../.." && pwd)" -CI_SCRIPTS_DIR="${CI_SCRIPTS_DIR:-${REPO_ROOT}/.ci-github}" -FETCH="${CI_SCRIPTS_DIR}/scripts/fetch-github-binaries.sh" - -if [[ ! -x "${FETCH}" ]]; then - echo "error: missing ${FETCH}" >&2 - echo "hint: from bigfred-os/os run: make ci-scripts" >&2 +command -v go >/dev/null 2>&1 || { + echo "error: go is required (install Go toolchain)" >&2 exit 1 -fi +} -export GITHUB_REPO="${MICROINIT_GITHUB_REPO:-dcc-bigfred/microinit}" -export ARTIFACT_NAME="${MICROINIT_ARTIFACT_NAME:-binaries-arm64}" -export CI_WORKFLOW="${MICROINIT_CI_WORKFLOW:-ci.yml}" +export GOPROXY="${GOPROXY:-direct}" +FETCH_PKG="${FETCH_PKG:-github.com/dcc-bigfred/common/cmd/fetch@latest}" -if [[ -n "${MICROINIT_FILES:-}" ]]; then - export FILES="${MICROINIT_FILES}" - exec "${FETCH}" "${REF}" "${OUT}" -fi +REPO="${MICROINIT_GITHUB_REPO:-dcc-bigfred/microinit}" +ARTIFACT="${MICROINIT_ARTIFACT_NAME:-binaries-arm64}" +WORKFLOW="${MICROINIT_CI_WORKFLOW:-ci.yml}" +FILES="${MICROINIT_FILES:-microinit-linux-arm64:bin/microinit,shutdown-linux-arm64:bin/shutdown}" -# Prefer microinit + shutdown; fall back to microinit only. -export FILES="microinit-linux-arm64:bin/microinit,shutdown-linux-arm64:bin/shutdown" -if "${FETCH}" "${REF}" "${OUT}"; then - exit 0 -fi -echo "warning: shutdown layer missing; fetching microinit only" >&2 -export FILES="microinit-linux-arm64:bin/microinit" -exec "${FETCH}" "${REF}" "${OUT}" +exec go run "${FETCH_PKG}" \ + --repo="${REPO}" \ + --files="${FILES}" \ + --artifact="${ARTIFACT}" \ + --workflow="${WORKFLOW}" \ + "${REF}" "${OUT}" diff --git a/os/package/micronet/README.md b/os/package/micronet/README.md index 6a0bf18..ff24c87 100644 --- a/os/package/micronet/README.md +++ b/os/package/micronet/README.md @@ -1,13 +1,13 @@ # micronet (Buildroot package) Pulls [dcc-bigfred/micronet](https://github.com/dcc-bigfred/micronet) binaries via -shared `fetch-github-binaries.sh` (tip = Actions artifact; `v*` / `latest-release` -= GitHub Release) and installs: +`go run github.com/dcc-bigfred/common/cmd/fetch@latest` (tip = Actions artifact; +`v*` / `latest-release` = GitHub Release) and installs: - `/usr/sbin/configure-ethernet` - `/usr/sbin/configure-dhcp` -Requires `make ci-scripts` (clones `dcc-bigfred/.github` @ v2). Tip refs need a +Requires Go on the host (`install-go.sh` / Docker image). Tip refs need a GitHub token in the environment. Default ref: `main` (`MICRONET_OCI_TAG` / `BR2_PACKAGE_MICRONET_OCI_TAG`). diff --git a/os/package/micronet/fetch.sh b/os/package/micronet/fetch.sh index 1332931..5eda8e5 100755 --- a/os/package/micronet/fetch.sh +++ b/os/package/micronet/fetch.sh @@ -2,28 +2,30 @@ # Fetch micronet linux/arm64 binaries (configure-dhcp + configure-ethernet). # Usage: fetch.sh # -# Env: MICRONET_GITHUB_REPO (default dcc-bigfred/micronet) -# CI_SCRIPTS_DIR — path to cloned dcc-bigfred/.github (default /.ci-github) -# BIGFRED_NATIVE_TOKEN / GH_TOKEN / GITHUB_TOKEN — required for tip refs +# Env overrides: MICRONET_GITHUB_REPO, MICRONET_ARTIFACT_NAME, +# MICRONET_CI_WORKFLOW, MICRONET_FILES +# Token: BIGFRED_NATIVE_TOKEN / GH_TOKEN / GITHUB_TOKEN (required for tip refs) set -euo pipefail REF="${1:?usage: $0 }" OUT="${2:?usage: $0 }" -PKGDIR="$(cd "$(dirname "$0")" && pwd)" -REPO_ROOT="$(cd "${PKGDIR}/../../.." && pwd)" -CI_SCRIPTS_DIR="${CI_SCRIPTS_DIR:-${REPO_ROOT}/.ci-github}" -FETCH="${CI_SCRIPTS_DIR}/scripts/fetch-github-binaries.sh" - -if [[ ! -x "${FETCH}" ]]; then - echo "error: missing ${FETCH}" >&2 - echo "hint: from bigfred-os/os run: make ci-scripts (clones dcc-bigfred/.github @ v2)" >&2 +command -v go >/dev/null 2>&1 || { + echo "error: go is required (install Go toolchain)" >&2 exit 1 -fi +} + +export GOPROXY="${GOPROXY:-direct}" +FETCH_PKG="${FETCH_PKG:-github.com/dcc-bigfred/common/cmd/fetch@latest}" -export GITHUB_REPO="${MICRONET_GITHUB_REPO:-dcc-bigfred/micronet}" -export ARTIFACT_NAME="${MICRONET_ARTIFACT_NAME:-binaries-arm64}" -export CI_WORKFLOW="${MICRONET_CI_WORKFLOW:-ci.yml}" -export FILES="${MICRONET_FILES:-configure-dhcp-linux-arm64:bin/configure-dhcp,configure-ethernet-linux-arm64:bin/configure-ethernet}" +REPO="${MICRONET_GITHUB_REPO:-dcc-bigfred/micronet}" +ARTIFACT="${MICRONET_ARTIFACT_NAME:-binaries-arm64}" +WORKFLOW="${MICRONET_CI_WORKFLOW:-ci.yml}" +FILES="${MICRONET_FILES:-configure-dhcp-linux-arm64:bin/configure-dhcp,configure-ethernet-linux-arm64:bin/configure-ethernet}" -exec "${FETCH}" "${REF}" "${OUT}" +exec go run "${FETCH_PKG}" \ + --repo="${REPO}" \ + --files="${FILES}" \ + --artifact="${ARTIFACT}" \ + --workflow="${WORKFLOW}" \ + "${REF}" "${OUT}" From e903a28e5f5e8cb1be5722dab5984835c24b8e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20K=C4=99ska?= <372403+keskad@users.noreply.github.com> Date: Thu, 6 Aug 2026 19:52:35 +0200 Subject: [PATCH 5/5] docs: point bigfred package at common Go fetch Co-authored-by: Cursor --- os/package/bigfred/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/package/bigfred/README.md b/os/package/bigfred/README.md index 8b79952..3e46288 100644 --- a/os/package/bigfred/README.md +++ b/os/package/bigfred/README.md @@ -7,4 +7,4 @@ binaries via shared GitHub fetch and installs loco-server + remote-icmp under Default ref: `latest-release` (falls back to `master` if no release exists). Tip/`master` needs a GitHub token; public Releases usually do not. -Requires `make ci-scripts` (`dcc-bigfred/.github` @ v2). +Requires Go on the host (`go run github.com/dcc-bigfred/common/cmd/fetch@latest`).