Skip to content

Migrate installer to Go#139

Draft
portainer-mike wants to merge 6 commits intodevelopfrom
KS-45
Draft

Migrate installer to Go#139
portainer-mike wants to merge 6 commits intodevelopfrom
KS-45

Conversation

@portainer-mike
Copy link
Copy Markdown
Contributor

KS-45: Go installer — replaces install.sh, kubesolo-service.sh, uninstall.sh

Rewrites the three bash installer scripts as a single compiled Go CLI binary (cmd/installer). Built with CGO_ENABLED=0 so one binary per architecture covers both glibc and musl systems, eliminating the libc split the bash scripts handle at runtime.

Supported targets

linux/amd64, linux/arm64, linux/arm (armhf), linux/riscv64

CLI

sudo installer [flags]               # install (default)
sudo installer install [flags]
sudo installer uninstall [--purge]
sudo installer service start|stop|restart|status|logs
sudo installer download [--version=] [--path=]
installer check
installer version

All flags have KUBESOLO_* environment variable equivalents.

What's new

cmd/installer/ — cobra CLI entry point. Six subcommands: install (default), uninstall, service, download, check, version. uninstall removes the service, binary, and optionally the data directory (--purge).

internal/installer/config/Config struct and constants. CmdArgs() builds the argument list passed to the kubesolo binary using bare boolean flags (--debug not --debug=true) to match kubesolo's flag parser.

internal/installer/detect/ — host detection with no subprocess calls. Detects arch, libc (musl vs glibc via /lib/ld-musl-*.so.1), init system (from filesystem landmarks — no which/command -v), and environment (container, SBC).

internal/installer/preflight/ — seven ordered checks: root, hostname RFC 1123, Docker conflict, iptables xt_comment module, nftables+iptables (Alpine only, installs via apk add if --install-prereqs), cgroups (enables Alpine OpenRC cgroups service proactively if needed), required ports. Stop runs before preflight so ports held by an existing KubeSolo installation don't cause false failures.

internal/installer/process/ — stops running KubeSolo before reinstalling. Reads /proc/*/exe symlinks, SIGTERMs with exponential backoff, SIGKILLs stragglers. Port holders found via /proc/net/tcp[6] inode mapping. No dependency on lsof, ss, or netstat.

internal/installer/download/ — online and offline install. Extracts by base name so nested tar paths (kubesolo-v1.1.2-linux-amd64/kubesolo) are handled correctly. Atomic install via os.Rename; cross-device fallback (tmpfs → ext4 on Alpine) explicitly chmod 0755es the staged binary before the final rename.

internal/installer/service/ — seven init system backends behind a common Manager interface: systemd, OpenRC, SysV, s6, runit, upstart, daemon (fallback). All templates support optional proxy environment injection. daemon_linux.go / daemon_other.go split via build tags keeps the package compilable on macOS for local development.

internal/installer/kubeconfig/ — waits up to 30s for the admin kubeconfig to appear, then merges it into the real user's ~/.kube/config via kubectl config view --flatten. Real user resolved in order: SUDO_USER (sudo), DOAS_USER (doas), /proc/self/loginuid (kernel login UID, preserved across any privilege escalation — reliable catch-all for doas on Alpine), fallback to current user. Source kubeconfig is chowned to the real user so KUBECONFIG=<path> in shell profiles keeps working.

scripts/get.sh — bootstrap script for get.kubesolo.io. Detects arch via uname -m, downloads the correct installer-linux-<arch> binary, and execs it. Supports KUBESOLO_VERSION, KUBESOLO_INSTALLER_BASE_URL, and KUBESOLO_FLAT_URLS for version pinning and internal mirrors.

Makefile — adds build-installer, build-installer-all, test-installer, clean-installer targets.

Building

make build-installer-all        # all four architectures → dist/
make test-installer              # unit tests (no root, no Linux required)

@linear
Copy link
Copy Markdown

linear Bot commented Apr 21, 2026

@portainer-mike portainer-mike requested a review from Copilot April 21, 2026 04:01
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the KubeSolo installer from multiple bash scripts to a single compiled Go-based CLI (cmd/installer) with subcommands for install/uninstall/service/download/check/version.

Changes:

  • Added a new Go installer CLI (cobra) that performs host detection, preflight checks, binary download/offline install, service setup, and kubeconfig merge.
  • Implemented init-system service backends (systemd/OpenRC/SysV/s6/runit/upstart) plus daemon/foreground run modes.
  • Added bootstrap script (scripts/get.sh) and Makefile targets to build/test the installer across supported architectures.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
scripts/get.sh Adds a curl/wget bootstrap script that downloads and execs the correct installer binary per arch.
cmd/installer/main.go Introduces the main cobra CLI and wires install/uninstall/service/download/check/version flows.
internal/installer/config/config.go Defines installer configuration defaults and builds kubesolo CLI args.
internal/installer/config/config_test.go Unit tests for Config.CmdArgs().
internal/installer/detect/detect.go Filesystem-/proc-based detection for arch/libc/init/environment and archive naming.
internal/installer/detect/detect_test.go Unit tests for archive naming, arch mapping, and constants.
internal/installer/download/download.go Downloads/extracts KubeSolo archives and supports offline installation.
internal/installer/download/download_test.go Unit tests for tar.gz extraction, copy, and progress reader.
internal/installer/kubeconfig/kubeconfig.go Waits for admin kubeconfig then merges it into the invoking user’s kubeconfig.
internal/installer/preflight/preflight.go Implements ordered preflight checks (root/hostname/docker/iptables/alpine/cgroups/ports).
internal/installer/preflight/preflight_test.go Tests for hostname regex, controllers, suite, and best-effort env checks.
internal/installer/process/process.go Stops existing KubeSolo processes via /proc scanning and port-owner detection.
internal/installer/process/exec.go Wraps command creation for potential test substitution.
internal/installer/process/process_test.go Unit tests for PID parsing, min duration, ports list, and non-panicking inode parsing.
internal/installer/service/manager.go Defines Manager interface, routing by init system/run mode, and template helpers.
internal/installer/service/systemd.go systemd unit generation/install/uninstall and systemctl invocations.
internal/installer/service/openrc.go OpenRC init script generation/install/uninstall.
internal/installer/service/sysvinit.go SysV init script generation/install/uninstall plus enable/start logic.
internal/installer/service/s6.go s6 service directory/scripts generation and optional supervisor activation.
internal/installer/service/runit.go runit service directory/script generation and enabling via symlink.
internal/installer/service/upstart.go Upstart job generation/install/uninstall via initctl.
internal/installer/service/daemon.go Fallback daemon-mode runner that starts kubesolo detached and writes a PID file.
internal/installer/service/daemon_linux.go Linux-specific SysProcAttr for daemon detachment.
internal/installer/service/daemon_other.go Non-Linux stub to keep builds/tests working on dev machines.
internal/installer/service/foreground.go Foreground run mode that executes kubesolo attached to the current TTY.
internal/installer/service/service_test.go Template rendering tests and init-system routing tests for New().
Makefile Adds build/test/clean targets for the new installer binary across architectures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/installer/service/daemon.go
Comment thread cmd/installer/main.go
Comment thread internal/installer/download/download.go Outdated
Comment thread internal/installer/kubeconfig/kubeconfig.go
Comment thread internal/installer/preflight/preflight_test.go
Comment thread internal/installer/service/daemon.go
Comment thread cmd/installer/main.go
Comment thread internal/installer/download/download.go Outdated
Comment thread internal/installer/service/manager.go
Comment thread internal/installer/process/process.go Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/installer/process/process.go
Comment on lines +1 to +5
package service

import "syscall"

// daemonSysProcAttr returns a SysProcAttr that puts the child process in its
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

daemon_linux.go is compiled on all platforms because it lacks a //go:build linux constraint. On non-Linux, both this file and daemon_other.go (//go:build !linux) will be included, causing a duplicate definition of daemonSysProcAttr and breaking macOS/Windows builds/tests. Add a Linux build tag to daemon_linux.go (and optionally the legacy // +build linux line) so only one implementation is compiled per platform.

Copilot uses AI. Check for mistakes.
Comment thread internal/installer/detect/detect.go
Comment thread internal/installer/kubeconfig/kubeconfig.go
Comment thread cmd/installer/main.go
Comment on lines +288 to +293
Long: `Control the KubeSolo system service.

Actions: start | stop | restart | status | logs | enable | disable`,
Args: cobra.ExactArgs(1),
ValidArgs: []string{"start", "stop", "restart", "status", "logs", "enable", "disable"},
SilenceUsage: true,
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service help text and ValidArgs include enable|disable, but the command only implements those for OpenRC. On SysV this will call service kubesolo enable/disable (typically invalid), and on Upstart initctl enable/disable is also not a thing. Either remove enable|disable from the advertised actions, or implement init-specific enable/disable behavior and validate actions explicitly (note: ValidArgs is used for completion; it doesn't enforce values at runtime without an Args validator).

Copilot uses AI. Check for mistakes.
Comment thread cmd/installer/main.go
Comment thread internal/installer/preflight/preflight.go
Comment thread cmd/installer/main.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants