commit ecceff225f2a66da684f93815bf756736abf040898a35820a9d738ce74cc14b4
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-03-28T12:28:22Z |
| subject | Matches ctl version to upstream |
commit ecceff225f2a66da684f93815bf756736abf040898a35820a9d738ce74cc14b4
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-03-28T12:28:22Z
Matches ctl version to upstream
---
.gitignore | 1 +
alpine/configure-system.sh | 2 -
clitools/README | 28 ++++++
clitools/makefile | 15 ++-
clitools/pkg/apis/monok8s/v1alpha1/types.go | 12 +--
clitools/pkg/bootstrap/registry.go | 7 +-
clitools/pkg/bootstrap/runner.go | 12 ++-
clitools/pkg/buildinfo/README | 1 +
clitools/pkg/cmd/create/create.go | 16 +++-
clitools/pkg/cmd/root/root.go | 8 +-
clitools/pkg/cmd/version/version.go | 22 +++++
clitools/pkg/config/config.go | 29 +++---
clitools/pkg/node/context.go | 2 +-
clitools/pkg/node/crio.go | 58 +++++++++--
clitools/pkg/node/kubeadm.go | 85 +++++++++++++----
clitools/pkg/node/network.go | 50 ++++++++--
clitools/pkg/node/prereqs.go | 117 +++++++++++++++++++----
clitools/pkg/render/monoks.go | 55 +++++++++++
clitools/pkg/scheme/v1alpha1.go | 27 ++++++
clitools/pkg/system/helpers.go | 4 +
clitools/pkg/system/hostname_linux.go | 12 +++
clitools/pkg/system/hostname_stub.go | 8 ++
clitools/pkg/templates/templates.go | 143 ++++++++++++++++++----------
docker/alpine.Dockerfile | 7 +-
makefile | 29 +++---
25 files changed, 591 insertions(+), 159 deletions(-)
diff --git a/.gitignore b/.gitignore
index dca5a56..22b1c22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
clitools/bin
packages/
out/
+*_gen.go
*.swp
diff --git a/alpine/configure-system.sh b/alpine/configure-system.sh
index a4d49a5..9d931d1 100755
--- a/alpine/configure-system.sh
+++ b/alpine/configure-system.sh
@@ -11,5 +11,3 @@ rc-update add fancontrol boot
rc-update add loopback boot
rc-update add hostname boot
rc-update add localmount boot
-rc-update add apply-node-config default
-rc-update add bootstrap-cluster default
diff --git a/clitools/README b/clitools/README
new file mode 100644
index 0000000..5e1e863
--- /dev/null
+++ b/clitools/README
@@ -0,0 +1,28 @@
+## For development workflow
+
+Run this on device
+```bash
+while true; do nc -l -p 1234 -e sh; done
+```
+
+Run this script on the dev machine
+```bash
+#!/bin/bash
+make build
+
+SIZE=$(wc -c < ./bin/ctl-linux-aarch64-dev)
+
+(
+ echo 'base64 -d > /var/ctl <<'"'"'EOF'"'"''
+ pv -s "$SIZE" < ./bin/ctl-linux-aarch64-dev | base64
+ echo 'EOF'
+ echo 'chmod +x /var/ctl'
+ echo '/var/ctl create config > /var/abc.yaml'
+ echo "/var/ctl internal run-step $1 -c /var/abc.yaml 2>&1"
+) | nc 10.0.0.10 1234
+```
+
+And use it like this
+```bash
+./send.sh start_crio
+```
diff --git a/clitools/makefile b/clitools/makefile
index 7ab571c..f4ce3f3 100644
--- a/clitools/makefile
+++ b/clitools/makefile
@@ -1,11 +1,22 @@
VERSION ?= dev
+KUBE_VERSION=v1.35.1
+
BIN_DIR := bin
-build:
+BUILDINFO_FILE := pkg/buildinfo/buildinfo_gen.go
+
+$(BUILDINFO_FILE):
+ echo 'package buildinfo' > $@
+ echo '' >> $@
+ echo 'const DefaultKubernetesVersion = "$(KUBE_VERSION)"' >> $@
+
+build: $(BUILDINFO_FILE)
mkdir -p $(BIN_DIR)
GOOS=linux GOARCH=arm64 go build -o $(BIN_DIR)/ctl-linux-aarch64-$(VERSION) ./cmd/ctl/
-# go build -o $(BIN_DIR)/ctl-$(VERSION) ./cmd/ctl
+
+build-local:
+ go build -o $(BIN_DIR)/ctl-$(VERSION) ./cmd/ctl
run:
go run ./cmd/ctl
diff --git a/clitools/pkg/apis/monok8s/v1alpha1/types.go b/clitools/pkg/apis/monok8s/v1alpha1/types.go
index 51ddb30..24e389f 100644
--- a/clitools/pkg/apis/monok8s/v1alpha1/types.go
+++ b/clitools/pkg/apis/monok8s/v1alpha1/types.go
@@ -20,8 +20,8 @@ var (
type MonoKSConfig struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
- Spec MonoKSConfigSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
- Status MonoKSConfigStatus `json:"status,omitempty" yaml:"status,omitempty"`
+ Spec MonoKSConfigSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
+ Status *MonoKSConfigStatus `json:"status,omitempty" yaml:"status,omitempty"`
}
type MonoKSConfigList struct {
@@ -35,13 +35,13 @@ type MonoKSConfigSpec struct {
NodeName string `json:"nodeName,omitempty" yaml:"nodeName,omitempty"`
ClusterName string `json:"clusterName,omitempty" yaml:"clusterName,omitempty"`
ClusterDomain string `json:"clusterDomain,omitempty" yaml:"clusterDomain,omitempty"`
+ ClusterRole string `json:"clusterRole,omitempty" yaml:"clusterRole,omitempty"`
+ InitControlPlane bool `json:"initControlPlane,omitempty" yaml:"initControlPlane,omitempty"`
PodSubnet string `json:"podSubnet,omitempty" yaml:"podSubnet,omitempty"`
ServiceSubnet string `json:"serviceSubnet,omitempty" yaml:"serviceSubnet,omitempty"`
APIServerAdvertiseAddress string `json:"apiServerAdvertiseAddress,omitempty" yaml:"apiServerAdvertiseAddress,omitempty"`
APIServerEndpoint string `json:"apiServerEndpoint,omitempty" yaml:"apiServerEndpoint,omitempty"`
ContainerRuntimeEndpoint string `json:"containerRuntimeEndpoint,omitempty" yaml:"containerRuntimeEndpoint,omitempty"`
- BootstrapMode string `json:"bootstrapMode,omitempty" yaml:"bootstrapMode,omitempty"`
- JoinKind string `json:"joinKind,omitempty" yaml:"joinKind,omitempty"`
BootstrapToken string `json:"bootstrapToken,omitempty" yaml:"bootstrapToken,omitempty"`
DiscoveryTokenCACertHash string `json:"discoveryTokenCACertHash,omitempty" yaml:"discoveryTokenCACertHash,omitempty"`
ControlPlaneCertKey string `json:"controlPlaneCertKey,omitempty" yaml:"controlPlaneCertKey,omitempty"`
@@ -74,8 +74,8 @@ type MonoKSConfigStatus struct {
type OSUpgrade struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
- Spec OSUpgradeSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
- Status OSUpgradeStatus `json:"status,omitempty" yaml:"status,omitempty"`
+ Spec OSUpgradeSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
+ Status *OSUpgradeStatus `json:"status,omitempty" yaml:"status,omitempty"`
}
type OSUpgradeList struct {
diff --git a/clitools/pkg/bootstrap/registry.go b/clitools/pkg/bootstrap/registry.go
index 20ffccd..964ec2d 100644
--- a/clitools/pkg/bootstrap/registry.go
+++ b/clitools/pkg/bootstrap/registry.go
@@ -12,6 +12,7 @@ type Registry struct {
func NewRegistry(ctx *node.NodeContext) *Registry {
netCfg := node.NetworkConfig{
+ Hostname: ctx.Config.Spec.Network.Hostname,
MgmtIface: ctx.Config.Spec.Network.ManagementIface,
MgmtAddress: ctx.Config.Spec.Network.ManagementCIDR,
MgmtGateway: ctx.Config.Spec.Network.ManagementGW,
@@ -21,13 +22,10 @@ func NewRegistry(ctx *node.NodeContext) *Registry {
return &Registry{
steps: map[string]node.Step{
- "check_prereqs": node.CheckPrereqs,
"validate_network_requirements": node.ValidateNetworkRequirements,
- "install_cni_if_requested": node.InstallCNIIfRequested,
+ "configure_default_cni": node.ConfigureDefaultCNI,
"start_crio": node.StartCRIO,
- "check_crio_running": node.CheckCRIORunning,
"wait_for_existing_cluster_if_needed": node.WaitForExistingClusterIfNeeded,
- "decide_bootstrap_action": node.DecideBootstrapAction,
"check_required_images": node.CheckRequiredImages,
"generate_kubeadm_config": node.GenerateKubeadmConfig,
"run_kubeadm_init": node.RunKubeadmInit,
@@ -35,6 +33,7 @@ func NewRegistry(ctx *node.NodeContext) *Registry {
"apply_local_node_metadata_if_possible": node.ApplyLocalNodeMetadataIfPossible,
"allow_single_node_scheduling": node.AllowSingleNodeScheduling,
"ensure_ip_forward": node.EnsureIPForward,
+ "configure_hostname": node.ConfigureHostname(netCfg),
"configure_mgmt_interface": node.ConfigureMgmtInterface(netCfg),
"configure_dns": node.ConfigureDNS(netCfg),
"set_hostname_if_needed": node.SetHostnameIfNeeded,
diff --git a/clitools/pkg/bootstrap/runner.go b/clitools/pkg/bootstrap/runner.go
index f2a3c59..677c8d3 100644
--- a/clitools/pkg/bootstrap/runner.go
+++ b/clitools/pkg/bootstrap/runner.go
@@ -16,8 +16,8 @@ type Runner struct {
func NewRunner(cfg *monov1alpha1.MonoKSConfig) *Runner {
runnerCfg := system.RunnerConfig{}
nctx := &node.NodeContext{
- Config: cfg,
- System: system.NewRunner(runnerCfg),
+ Config: cfg,
+ SystemRunner: system.NewRunner(runnerCfg),
}
return &Runner{
NodeCtx: nctx,
@@ -27,11 +27,13 @@ func NewRunner(cfg *monov1alpha1.MonoKSConfig) *Runner {
func (r *Runner) Init(ctx context.Context) error {
for _, name := range []string{
- "check_prereqs",
+ "configure_hostname",
+ "configure_dns",
+ "configure_mgmt_interface",
"validate_network_requirements",
- "install_cni_if_requested",
+ "configure_default_cni",
"start_crio",
- "check_crio_running",
+ "check_container_images",
"wait_for_existing_cluster_if_needed",
"decide_bootstrap_action",
"check_required_images",
diff --git a/clitools/pkg/buildinfo/README b/clitools/pkg/buildinfo/README
new file mode 100644
index 0000000..06a3d45
--- /dev/null
+++ b/clitools/pkg/buildinfo/README
@@ -0,0 +1 @@
+Use `make build` to generate the files. Do not modify.
diff --git a/clitools/pkg/cmd/create/create.go b/clitools/pkg/cmd/create/create.go
index bc78ef9..22a4441 100644
--- a/clitools/pkg/cmd/create/create.go
+++ b/clitools/pkg/cmd/create/create.go
@@ -2,9 +2,9 @@ package create
import (
"fmt"
-
- "undecided.project/monok8s/pkg/templates"
"github.com/spf13/cobra"
+
+ render "undecided.project/monok8s/pkg/render"
)
func NewCmdCreate() *cobra.Command {
@@ -14,7 +14,11 @@ func NewCmdCreate() *cobra.Command {
Use: "config",
Short: "Print a MonoKSConfig template",
RunE: func(cmd *cobra.Command, _ []string) error {
- _, err := fmt.Fprint(cmd.OutOrStdout(), templates.MonoKSConfigYAML)
+ out, err := render.RenderMonoKSConfig()
+ if err != nil {
+ return err
+ }
+ _, err = fmt.Fprint(cmd.OutOrStdout(), out)
return err
},
},
@@ -22,7 +26,11 @@ func NewCmdCreate() *cobra.Command {
Use: "osupgrade",
Short: "Print an OSUpgrade template",
RunE: func(cmd *cobra.Command, _ []string) error {
- _, err := fmt.Fprint(cmd.OutOrStdout(), templates.OSUpgradeYAML)
+ out, err := render.RenderOSUpgrade()
+ if err != nil {
+ return err
+ }
+ _, err = fmt.Fprint(cmd.OutOrStdout(), out)
return err
},
},
diff --git a/clitools/pkg/cmd/root/root.go b/clitools/pkg/cmd/root/root.go
index c1e1541..0055d9d 100644
--- a/clitools/pkg/cmd/root/root.go
+++ b/clitools/pkg/cmd/root/root.go
@@ -3,15 +3,16 @@ package root
import (
"flag"
+ "github.com/spf13/cobra"
+ "k8s.io/cli-runtime/pkg/genericclioptions"
+ "k8s.io/klog/v2"
agentcmd "undecided.project/monok8s/pkg/cmd/agent"
applycmd "undecided.project/monok8s/pkg/cmd/apply"
checkconfigcmd "undecided.project/monok8s/pkg/cmd/checkconfig"
createcmd "undecided.project/monok8s/pkg/cmd/create"
initcmd "undecided.project/monok8s/pkg/cmd/initcmd"
internalcmd "undecided.project/monok8s/pkg/cmd/internal"
- "github.com/spf13/cobra"
- "k8s.io/cli-runtime/pkg/genericclioptions"
- "k8s.io/klog/v2"
+ versioncmd "undecided.project/monok8s/pkg/cmd/version"
)
func NewRootCmd() *cobra.Command {
@@ -30,6 +31,7 @@ func NewRootCmd() *cobra.Command {
flags.AddFlags(cmd.PersistentFlags())
cmd.AddCommand(
+ versioncmd.NewCmdVersion(),
initcmd.NewCmdInit(flags),
checkconfigcmd.NewCmdCheckConfig(),
createcmd.NewCmdCreate(),
diff --git a/clitools/pkg/cmd/version/version.go b/clitools/pkg/cmd/version/version.go
new file mode 100644
index 0000000..a351a64
--- /dev/null
+++ b/clitools/pkg/cmd/version/version.go
@@ -0,0 +1,22 @@
+package apply
+
+import (
+ "fmt"
+
+ "github.com/spf13/cobra"
+
+ buildInfo "undecided.project/monok8s/pkg/buildinfo"
+)
+
+func NewCmdVersion() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "version",
+ Short: "Print the version information",
+ RunE: func(cmd *cobra.Command, _ []string) error {
+
+ _, err := fmt.Fprintln(cmd.OutOrStdout(), buildInfo.Version)
+ return err
+ },
+ }
+ return cmd
+}
diff --git a/clitools/pkg/config/config.go b/clitools/pkg/config/config.go
index f944e60..cd7503a 100644
--- a/clitools/pkg/config/config.go
+++ b/clitools/pkg/config/config.go
@@ -6,8 +6,8 @@ import (
"os"
"strings"
- monov1alpha1 "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1"
"gopkg.in/yaml.v3"
+ monov1alpha1 "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1"
)
const EnvVar = "MONOKSCONFIG"
@@ -62,11 +62,8 @@ func ApplyDefaults(cfg *monov1alpha1.MonoKSConfig) {
if cfg.Spec.ContainerRuntimeEndpoint == "" {
cfg.Spec.ContainerRuntimeEndpoint = "unix:///var/run/crio/crio.sock"
}
- if cfg.Spec.BootstrapMode == "" {
- cfg.Spec.BootstrapMode = "init"
- }
- if cfg.Spec.JoinKind == "" {
- cfg.Spec.JoinKind = "worker"
+ if cfg.Spec.ClusterRole == "" {
+ cfg.Spec.ClusterRole = "control-plane"
}
if cfg.Spec.CNIPlugin == "" {
cfg.Spec.CNIPlugin = "none"
@@ -102,30 +99,26 @@ func Validate(cfg *monov1alpha1.MonoKSConfig) error {
if !strings.Contains(cfg.Spec.Network.ManagementCIDR, "/") {
problems = append(problems, "spec.network.managementCIDR must include a CIDR prefix")
}
- if cfg.Spec.BootstrapMode != "init" && cfg.Spec.BootstrapMode != "join" {
- problems = append(problems, "spec.bootstrapMode must be init or join")
- }
- if cfg.Spec.JoinKind != "worker" && cfg.Spec.JoinKind != "control-plane" {
- problems = append(problems, "spec.joinKind must be worker or control-plane")
+ if cfg.Spec.ClusterRole != "control-plane" && cfg.Spec.ClusterRole != "worker" {
+ problems = append(problems, "spec.clusterRole can either be control-plane or worker")
}
for _, ns := range cfg.Spec.Network.DNSNameservers {
if ns == "10.96.0.10" {
problems = append(problems, "spec.network.dnsNameservers must not include cluster DNS service IP 10.96.0.10")
}
}
- if cfg.Spec.BootstrapMode == "join" {
+ if cfg.Spec.ClusterRole == "worker" {
if cfg.Spec.APIServerEndpoint == "" {
- problems = append(problems, "spec.apiServerEndpoint is required for join mode")
+ problems = append(problems, "spec.apiServerEndpoint is required to join a cluster")
}
if cfg.Spec.BootstrapToken == "" {
- problems = append(problems, "spec.bootstrapToken is required for join mode")
+ problems = append(problems, "spec.bootstrapToken is required to join a cluster")
}
if cfg.Spec.DiscoveryTokenCACertHash == "" {
- problems = append(problems, "spec.discoveryTokenCACertHash is required for join mode")
- }
- if cfg.Spec.JoinKind == "control-plane" && cfg.Spec.ControlPlaneCertKey == "" {
- problems = append(problems, "spec.controlPlaneCertKey is required for control-plane join")
+ problems = append(problems, "spec.discoveryTokenCACertHash is required to join a cluster")
}
+ } else if !cfg.Spec.InitControlPlane && cfg.Spec.ControlPlaneCertKey == "" {
+ problems = append(problems, "spec.controlPlaneCertKey is required for control-plane join")
}
if len(problems) > 0 {
return errors.New(strings.Join(problems, "; "))
diff --git a/clitools/pkg/node/context.go b/clitools/pkg/node/context.go
index d308b4f..4a19a4d 100644
--- a/clitools/pkg/node/context.go
+++ b/clitools/pkg/node/context.go
@@ -9,7 +9,7 @@ import (
type NodeContext struct {
Config *monov1alpha1.MonoKSConfig
- System *system.Runner
+ SystemRunner *system.Runner
}
type Step func(context.Context, *NodeContext) error
diff --git a/clitools/pkg/node/crio.go b/clitools/pkg/node/crio.go
index a99f261..9a451c8 100644
--- a/clitools/pkg/node/crio.go
+++ b/clitools/pkg/node/crio.go
@@ -2,21 +2,61 @@ package node
import (
"context"
+ "fmt"
+ "os"
+ "strings"
"k8s.io/klog/v2"
+ system "undecided.project/monok8s/pkg/system"
)
-func InstallCNIIfRequested(context.Context, *NodeContext) error {
- klog.Info("install_cni_if_requested: TODO implement bridge/none CNI toggling")
- return nil
-}
+func ConfigureDefaultCNI(ctx context.Context, n *NodeContext) error {
+ _ = ctx
+
+ const (
+ cniDir = "/etc/cni/net.d"
+ enabledPath = cniDir + "/10-crio-bridge.conflist"
+ disabledPath = cniDir + "/10-crio-bridge.conflist.disabled"
+ )
+
+ plugin := strings.TrimSpace(n.Config.Spec.CNIPlugin)
+
+ switch plugin {
+ case "none":
+ // Fail hard if we cannot ensure the default bridge CNI is disabled.
+ if _, err := os.Stat(enabledPath); err == nil {
+ if err := os.Rename(enabledPath, disabledPath); err != nil {
+ return fmt.Errorf("disable default CRI-O bridge CNI: %w", err)
+ }
+ } else if !os.IsNotExist(err) {
+ return fmt.Errorf("stat %s: %w", enabledPath, err)
+ }
-func StartCRIO(context.Context, *NodeContext) error {
- klog.Info("start_crio: TODO implement rc-service crio start")
+ klog.Infof("Default CRI-O bridge CNI disabled")
+ return nil
+
+ case "bridge":
+ fallthrough
+ case "default":
+ // Fail soft. User can still install or provide their own CNI.
+ if _, err := os.Stat(disabledPath); err == nil {
+ if err := os.Rename(disabledPath, enabledPath); err != nil {
+ klog.Warningf("failed enabling default CRI-O bridge CNI: %v", err)
+ return nil
+ }
+ } else if !os.IsNotExist(err) {
+ klog.Warningf("failed stating %s while enabling default CRI-O bridge CNI: %v", disabledPath, err)
+ return nil
+ }
+
+ klog.Infof("Default CRI-O bridge CNI enabled")
+ return nil
+
+ }
+ klog.Infof("unsupported CNIPlugin: %q", plugin)
return nil
}
-func CheckCRIORunning(context.Context, *NodeContext) error {
- klog.Info("check_crio_running: TODO implement crictl readiness checks")
- return nil
+func StartCRIO(ctx context.Context, n *NodeContext) error {
+ return system.EnsureServiceRunning(ctx, n.SystemRunner, "crio")
}
diff --git a/clitools/pkg/node/kubeadm.go b/clitools/pkg/node/kubeadm.go
index 1a3b757..b8a8805 100644
--- a/clitools/pkg/node/kubeadm.go
+++ b/clitools/pkg/node/kubeadm.go
@@ -1,36 +1,87 @@
package node
import (
- "context"
+ "context"
+ "fmt"
+ "strings"
- "k8s.io/klog/v2"
+ "k8s.io/klog/v2"
)
func WaitForExistingClusterIfNeeded(context.Context, *NodeContext) error {
- klog.Info("wait_for_existing_cluster_if_needed: TODO implement kubelet/admin.conf waits")
- return nil
+ klog.Info("wait_for_existing_cluster_if_needed: TODO implement kubelet/admin.conf waits")
+ return nil
}
-func CheckRequiredImages(context.Context, *NodeContext) error {
- klog.Info("check_required_images: TODO implement kubeadm image list + crictl image presence")
- return nil
+
+func CheckRequiredImages(ctx context.Context, n *NodeContext) error {
+ if n.Config.Spec.SkipImageCheck {
+ klog.Infof("skipping image check (skipImageCheck=true)")
+ return nil
+ }
+
+ k8sVersion := strings.TrimSpace(n.Config.Spec.KubernetesVersion)
+ if k8sVersion == "" {
+ return fmt.Errorf("kubernetesVersion is required")
+ }
+
+ klog.Infof("checking required Kubernetes images for %s...", k8sVersion)
+
+ result, err := n.SystemRunner.Run(ctx,
+ "kubeadm", "config", "images", "list",
+ "--kubernetes-version", k8sVersion,
+ )
+ if err != nil {
+ return fmt.Errorf("list required Kubernetes images for %s: %w", k8sVersion, err)
+ }
+
+ var missing []string
+ for _, img := range strings.Fields(result.Stdout) {
+ if err := checkImagePresent(ctx, n, img); err != nil {
+ klog.Errorf("MISSING image: %s", img)
+ missing = append(missing, img)
+ continue
+ }
+ klog.Infof("found image: %s", img)
+ }
+
+ if len(missing) > 0 {
+ return fmt.Errorf("preload the Kubernetes images before bootstrapping; missing: %s", strings.Join(missing, ", "))
+ }
+
+ klog.Infof("all required images are present")
+ return nil
+}
+
+func checkImagePresent(ctx context.Context, n *NodeContext, image string) error {
+ image = strings.TrimSpace(image)
+ if image == "" {
+ return fmt.Errorf("image is required")
+ }
+
+ // crictl inspecti exits non-zero when the image is absent.
+ _, err := n.SystemRunner.Run(ctx, "crictl", "inspecti", image)
+ if err != nil {
+ return fmt.Errorf("image %q not present: %w", image, err)
+ }
+ return nil
}
func GenerateKubeadmConfig(context.Context, *NodeContext) error {
- klog.Info("generate_kubeadm_config: TODO render kubeadm v1beta4 config from MonoKSConfig")
- return nil
+ klog.Info("generate_kubeadm_config: TODO render kubeadm v1beta4 config from MonoKSConfig")
+ return nil
}
func RunKubeadmInit(context.Context, *NodeContext) error {
- klog.Info("run_kubeadm_init: TODO implement kubeadm init --config <file>")
- return nil
+ klog.Info("run_kubeadm_init: TODO implement kubeadm init --config <file>")
+ return nil
}
func RunKubeadmUpgradeApply(context.Context, *NodeContext) error {
- klog.Info("run_kubeadm_upgrade_apply: TODO implement kubeadm upgrade apply")
- return nil
+ klog.Info("run_kubeadm_upgrade_apply: TODO implement kubeadm upgrade apply")
+ return nil
}
func RunKubeadmJoin(context.Context, *NodeContext) error {
- klog.Info("run_kubeadm_join: TODO implement kubeadm join")
- return nil
+ klog.Info("run_kubeadm_join: TODO implement kubeadm join")
+ return nil
}
func RunKubeadmUpgradeNode(context.Context, *NodeContext) error {
- klog.Info("run_kubeadm_upgrade_node: TODO implement kubeadm upgrade node")
- return nil
+ klog.Info("run_kubeadm_upgrade_node: TODO implement kubeadm upgrade node")
+ return nil
}
diff --git a/clitools/pkg/node/network.go b/clitools/pkg/node/network.go
index 4f40943..b2a538d 100644
--- a/clitools/pkg/node/network.go
+++ b/clitools/pkg/node/network.go
@@ -12,6 +12,7 @@ import (
)
type NetworkConfig struct {
+ Hostname string
MgmtIface string
MgmtAddress string
MgmtGateway string
@@ -48,11 +49,11 @@ func ConfigureMgmtInterface(cfg NetworkConfig) Step {
}
}
- if _, err := nctx.System.Run(ctx, "ip", "link", "show", "dev", cfg.MgmtIface); err != nil {
+ if _, err := nctx.SystemRunner.Run(ctx, "ip", "link", "show", "dev", cfg.MgmtIface); err != nil {
return fmt.Errorf("interface not found: %s: %w", cfg.MgmtIface, err)
}
- if _, err := nctx.System.Run(ctx, "ip", "link", "set", "dev", cfg.MgmtIface, "up"); err != nil {
+ if _, err := nctx.SystemRunner.Run(ctx, "ip", "link", "set", "dev", cfg.MgmtIface, "up"); err != nil {
return fmt.Errorf("failed to bring up interface %s: %w", cfg.MgmtIface, err)
}
@@ -64,13 +65,13 @@ func ConfigureMgmtInterface(cfg NetworkConfig) Step {
if hasAddr {
klog.Infof("address already present on %s: %s", cfg.MgmtIface, wantCIDR)
} else {
- if _, err := nctx.System.Run(ctx, "ip", "addr", "add", wantCIDR, "dev", cfg.MgmtIface); err != nil {
+ if _, err := nctx.SystemRunner.Run(ctx, "ip", "addr", "add", wantCIDR, "dev", cfg.MgmtIface); err != nil {
return fmt.Errorf("failed assigning %s to %s: %w", wantCIDR, cfg.MgmtIface, err)
}
}
if gw := strings.TrimSpace(cfg.MgmtGateway); gw != "" {
- if _, err := nctx.System.Run(ctx, "ip", "route", "replace", "default", "via", gw, "dev", cfg.MgmtIface); err != nil {
+ if _, err := nctx.SystemRunner.Run(ctx, "ip", "route", "replace", "default", "via", gw, "dev", cfg.MgmtIface); err != nil {
return fmt.Errorf("failed setting default route via %s dev %s: %w", gw, cfg.MgmtIface, err)
}
}
@@ -85,7 +86,44 @@ func maskSize(m net.IPMask) int {
}
func EnsureIPForward(ctx context.Context, n *NodeContext) error {
- return system.EnsureSysctl(ctx, n.System, "net.ipv4.ip_forward", "1")
+ return system.EnsureSysctl(ctx, n.SystemRunner, "net.ipv4.ip_forward", "1")
+}
+
+func ConfigureHostname(cfg NetworkConfig) Step {
+ return func(context.Context, *NodeContext) error {
+ want := strings.TrimSpace(cfg.Hostname)
+ if want == "" {
+ return fmt.Errorf("hostname is required")
+ }
+
+ current, err := os.Hostname()
+ if err != nil {
+ current = ""
+ }
+
+ if current == want {
+ return nil
+ }
+
+ if err := system.SetHostname(want); err != nil {
+ return fmt.Errorf("set hostname to %q: %w", want, err)
+ }
+
+ if err := os.WriteFile("/etc/hostname", []byte(want+"\n"), 0o644); err != nil {
+ return fmt.Errorf("write /etc/hostname: %w", err)
+ }
+
+ current, err = os.Hostname()
+ if err != nil {
+ current = ""
+ }
+
+ if current != want {
+ return fmt.Errorf("Unable to set hostname: %q", want)
+ }
+
+ return nil
+ }
}
func ConfigureDNS(cfg NetworkConfig) Step {
@@ -159,7 +197,7 @@ func ConfigureDNS(cfg NetworkConfig) Step {
}
func interfaceHasIPv4(ctx context.Context, nctx *NodeContext, iface, wantIP string) (bool, error) {
- res, err := nctx.System.Run(ctx, "ip", "-o", "-4", "addr", "show", "dev", iface)
+ res, err := nctx.SystemRunner.Run(ctx, "ip", "-o", "-4", "addr", "show", "dev", iface)
if err != nil {
return false, err
}
diff --git a/clitools/pkg/node/prereqs.go b/clitools/pkg/node/prereqs.go
index b6599c4..bd9b0ea 100644
--- a/clitools/pkg/node/prereqs.go
+++ b/clitools/pkg/node/prereqs.go
@@ -1,27 +1,112 @@
package node
import (
- "context"
+ "context"
+ "fmt"
+ "net"
+ "strings"
+ "time"
- "k8s.io/klog/v2"
+ "k8s.io/klog/v2"
)
-func CheckPrereqs(context.Context, *NodeContext) error {
- klog.Info("check_prereqs: TODO implement command discovery and runtime validation")
- return nil
-}
+func ValidateNetworkRequirements(ctx context.Context, nct *NodeContext) error {
+ requireLocalIP := func(wantedIP string) error {
+ wantedIP = strings.TrimSpace(wantedIP)
+ if wantedIP == "" {
+ return fmt.Errorf("API server advertise address is required")
+ }
-func ValidateNetworkRequirements(context.Context, *NodeContext) error {
- klog.Info("validate_network_requirements: TODO implement local IP and API reachability checks")
- return nil
-}
+ ip := net.ParseIP(wantedIP)
+ if ip == nil {
+ return fmt.Errorf("invalid API server advertise address %q", wantedIP)
+ }
-func CheckUpgradePrereqs(context.Context, *NodeContext) error {
- klog.Info("check_upgrade_prereqs: TODO implement kubeadm version / skew checks")
- return nil
+ ifaces, err := net.Interfaces()
+ if err != nil {
+ return fmt.Errorf("list interfaces: %w", err)
+ }
+
+ for _, iface := range ifaces {
+ addrs, err := iface.Addrs()
+ if err != nil {
+ continue
+ }
+ for _, addr := range addrs {
+ var got net.IP
+ switch v := addr.(type) {
+ case *net.IPNet:
+ got = v.IP
+ case *net.IPAddr:
+ got = v.IP
+ }
+ if got != nil && got.Equal(ip) {
+ return nil
+ }
+ }
+ }
+
+ return fmt.Errorf("required local IP is not present on any interface: %s", wantedIP)
+ }
+
+ checkAPIServerReachable := func(endpoint string) error {
+ endpoint = strings.TrimSpace(endpoint)
+ if endpoint == "" {
+ return fmt.Errorf("API server endpoint is required")
+ }
+
+ host, port, err := net.SplitHostPort(endpoint)
+ if err != nil {
+ return fmt.Errorf("invalid API server endpoint %q: %w", endpoint, err)
+ }
+ if strings.TrimSpace(host) == "" || strings.TrimSpace(port) == "" {
+ return fmt.Errorf("invalid API server endpoint %q", endpoint)
+ }
+
+ klog.Infof("checking API server reachability: %s:%s", host, port)
+
+ var lastErr error
+ for i := 0; i < 20; i++ {
+ d := net.Dialer{Timeout: 1 * time.Second}
+ conn, err := d.DialContext(ctx, "tcp", endpoint)
+ if err == nil {
+ _ = conn.Close()
+ klog.Infof("API server is reachable")
+ return nil
+ }
+ lastErr = err
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-time.After(1 * time.Second):
+ }
+ }
+
+ return fmt.Errorf("cannot reach API server at %s: %w", endpoint, lastErr)
+ }
+
+ cfg := nct.Config.Spec
+ switch strings.TrimSpace(cfg.ClusterRole) {
+ case "control-plane":
+ if err := requireLocalIP(cfg.APIServerAdvertiseAddress); err != nil {
+ return err
+ }
+ case "worker":
+ if err := requireLocalIP(cfg.APIServerAdvertiseAddress); err != nil {
+ return err
+ }
+ if err := checkAPIServerReachable(cfg.APIServerEndpoint); err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("Incorrect ClusterRole: %s", cfg.ClusterRole)
+ }
+
+ return nil
}
-func DecideBootstrapAction(_ context.Context, nctx *NodeContext) error {
- klog.InfoS("decide_bootstrap_action", "bootstrapMode", nctx.Config.Spec.BootstrapMode, "joinKind", nctx.Config.Spec.JoinKind)
- return nil
+func CheckUpgradePrereqs(context.Context, *NodeContext) error {
+ klog.Info("check_upgrade_prereqs: TODO implement kubeadm version / skew checks")
+ return nil
}
diff --git a/clitools/pkg/render/monoks.go b/clitools/pkg/render/monoks.go
new file mode 100644
index 0000000..c4f7645
--- /dev/null
+++ b/clitools/pkg/render/monoks.go
@@ -0,0 +1,55 @@
+package templates
+
+import (
+ "bytes"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/serializer/json"
+
+ "undecided.project/monok8s/pkg/scheme"
+ tmpl "undecided.project/monok8s/pkg/templates"
+)
+
+func RenderMonoKSConfig() (string, error) {
+ cfg := tmpl.DefaultMonoKSConfig()
+
+ s := runtime.NewScheme()
+ if err := scheme.AddToScheme(s); err != nil {
+ return "", err
+ }
+
+ serializer := json.NewYAMLSerializer(
+ json.DefaultMetaFactory,
+ s,
+ s,
+ )
+
+ var buf bytes.Buffer
+ if err := serializer.Encode(&cfg, &buf); err != nil {
+ return "", err
+ }
+
+ return buf.String(), nil
+}
+
+func RenderOSUpgrade() (string, error) {
+ cfg := tmpl.DefaultOSUpgrade()
+
+ s := runtime.NewScheme()
+ if err := scheme.AddToScheme(s); err != nil {
+ return "", err
+ }
+
+ serializer := json.NewYAMLSerializer(
+ json.DefaultMetaFactory,
+ s,
+ s,
+ )
+
+ var buf bytes.Buffer
+ if err := serializer.Encode(&cfg, &buf); err != nil {
+ return "", err
+ }
+
+ return buf.String(), nil
+}
diff --git a/clitools/pkg/scheme/v1alpha1.go b/clitools/pkg/scheme/v1alpha1.go
new file mode 100644
index 0000000..8054680
--- /dev/null
+++ b/clitools/pkg/scheme/v1alpha1.go
@@ -0,0 +1,27 @@
+package scheme
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1"
+)
+
+var (
+ GroupVersion = schema.GroupVersion{
+ Group: "monok8s.io",
+ Version: "v1alpha1",
+ }
+)
+
+func AddToScheme(s *runtime.Scheme) error {
+ s.AddKnownTypes(GroupVersion,
+ &types.MonoKSConfig{},
+ )
+
+ // Required for meta stuff
+ metav1.AddToGroupVersion(s, GroupVersion)
+
+ return nil
+}
diff --git a/clitools/pkg/system/helpers.go b/clitools/pkg/system/helpers.go
index 6b13973..b350fca 100644
--- a/clitools/pkg/system/helpers.go
+++ b/clitools/pkg/system/helpers.go
@@ -5,15 +5,19 @@ import (
"fmt"
"os"
"strings"
+
+ "k8s.io/klog/v2"
)
const DefaultSecond = 1_000_000_000
func EnsureServiceRunning(ctx context.Context, r *Runner, svc string) error {
+
if _, err := r.Run(ctx, " rc-service", svc, "status"); err == nil {
return nil
}
+ klog.Infof("Starting service: %q", svc)
_, err := r.RunRetry(ctx, RetryOptions{
Attempts: 3,
Delay: 2 * DefaultSecond,
diff --git a/clitools/pkg/system/hostname_linux.go b/clitools/pkg/system/hostname_linux.go
new file mode 100644
index 0000000..d95c248
--- /dev/null
+++ b/clitools/pkg/system/hostname_linux.go
@@ -0,0 +1,12 @@
+//go:build linux
+
+package system
+
+import "golang.org/x/sys/unix"
+
+func SetHostname(hostname string) error {
+ if hostname == "" {
+ return nil
+ }
+ return unix.Sethostname([]byte(hostname))
+}
diff --git a/clitools/pkg/system/hostname_stub.go b/clitools/pkg/system/hostname_stub.go
new file mode 100644
index 0000000..3188277
--- /dev/null
+++ b/clitools/pkg/system/hostname_stub.go
@@ -0,0 +1,8 @@
+//go:build !linux
+
+package system
+
+func SetHostname(hostname string) error {
+ // intentionally a no-op
+ return nil
+}
diff --git a/clitools/pkg/templates/templates.go b/clitools/pkg/templates/templates.go
index a1708f2..ac9cae0 100644
--- a/clitools/pkg/templates/templates.go
+++ b/clitools/pkg/templates/templates.go
@@ -1,54 +1,93 @@
package templates
-const MonoKSConfigYAML = `apiVersion: monok8s.io/v1alpha1
-kind: MonoKSConfig
-metadata:
- name: example
- namespace: kube-system
-spec:
- kubernetesVersion: v1.35.3
- nodeName: monok8s-master-1
- clusterName: monok8s
- clusterDomain: cluster.local
- podSubnet: 10.244.0.0/16
- serviceSubnet: 10.96.0.0/12
- apiServerAdvertiseAddress: 10.0.0.10
- apiServerEndpoint: 10.0.0.10:6443
- containerRuntimeEndpoint: unix:///var/run/crio/crio.sock
- bootstrapMode: init
- joinKind: worker
- cniPlugin: none
- allowSchedulingOnControlPlane: true
- skipImageCheck: false
- kubeProxyNodePortAddresses:
- - primary
- subjectAltNames:
- - 10.0.0.10
- nodeLabels:
- node-role.kubernetes.io/control-plane: ""
- nodeAnnotations: {}
- network:
- hostname: monok8s-master-1
- managementIface: eth0
- managementCIDR: 10.0.0.10/24
- managementGateway: 10.0.0.1
- dnsNameservers:
- - 1.1.1.1
- - 8.8.8.8
- dnsSearchDomains:
- - lan
-`
-
-const OSUpgradeYAML = `apiVersion: monok8s.io/v1alpha1
-kind: OSUpgrade
-metadata:
- name: example
- namespace: kube-system
-spec:
- version: v0.0.1
- imageURL: https://example.invalid/images/monok8s-v0.0.1.img.zst
- targetPartition: B
- nodeSelector:
- - monok8s-master-1
- force: false
-`
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1"
+ buildinfo "undecided.project/monok8s/pkg/buildinfo"
+)
+
+func DefaultMonoKSConfig() types.MonoKSConfig {
+ return types.MonoKSConfig{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "monok8s.io/v1alpha1",
+ Kind: "MonoKSConfig",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example",
+ Namespace: "kube-system",
+ },
+ Spec: types.MonoKSConfigSpec{
+ KubernetesVersion: buildinfo.Version,
+ NodeName: "monok8s-master-1",
+
+ ClusterRole: "control-plane",
+ InitControlPlane: true,
+
+ ClusterName: "monok8s",
+ ClusterDomain: "cluster.local",
+
+ PodSubnet: "10.244.0.0/16",
+ ServiceSubnet: "10.96.0.0/12",
+
+ APIServerAdvertiseAddress: "10.0.0.10",
+ APIServerEndpoint: "10.0.0.10:6443",
+
+ ContainerRuntimeEndpoint: "unix:///var/run/crio/crio.sock",
+
+ CNIPlugin: "default",
+
+ AllowSchedulingOnControlPlane: true,
+ SkipImageCheck: false,
+
+ KubeProxyNodePortAddresses: []string{
+ "primary",
+ },
+
+ SubjectAltNames: []string{
+ "10.0.0.10",
+ },
+
+ NodeLabels: map[string]string{
+ "node-role.kubernetes.io/control-plane": "",
+ },
+
+ NodeAnnotations: map[string]string{},
+
+ Network: types.NetworkSpec{
+ Hostname: "monok8s-master-1",
+ ManagementIface: "eth0",
+ ManagementCIDR: "10.0.0.10/24",
+ ManagementGW: "10.0.0.1",
+ DNSNameservers: []string{
+ "1.1.1.1",
+ "8.8.8.8",
+ },
+ DNSSearchDomains: []string{
+ "lan",
+ },
+ },
+ },
+ }
+}
+
+func DefaultOSUpgrade() types.OSUpgrade {
+ return types.OSUpgrade{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "monok8s.io/v1alpha1",
+ Kind: "OSUpgrade",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example",
+ Namespace: "kube-system",
+ },
+ Spec: types.OSUpgradeSpec{
+ Version: "v0.0.1",
+ ImageURL: "https://example.invalid/images/monok8s-v0.0.1.img.zst",
+ TargetPartition: "B",
+ NodeSelector: []string{
+ "monok8s-master-1",
+ },
+ Force: false,
+ },
+ }
+}
diff --git a/docker/alpine.Dockerfile b/docker/alpine.Dockerfile
index e0c0f36..2cdb6a5 100644
--- a/docker/alpine.Dockerfile
+++ b/docker/alpine.Dockerfile
@@ -3,9 +3,11 @@ ARG DOCKER_IMAGE_ROOT=monok8s
FROM --platform=$BUILDPLATFORM ${DOCKER_IMAGE_ROOT}/build-base:${TAG} AS build-base
+ARG TAG
ARG ALPINE_ARCH
ARG ALPINE_VER
ARG CRIO_VERSION
+ARG KUBE_VERSION
ARG DEVICE_TREE_TARGET
RUN mkdir -p "/out/rootfs"
@@ -20,7 +22,10 @@ COPY out/Image.gz ./
RUN tar -xf alpine.tar.gz -C "/out/rootfs"
RUN mkdir -p /out/rootfs/usr/local/bin/
-COPY packages/kubernetes/* /out/rootfs/usr/local/bin/
+COPY packages/kubernetes/kubelet-${KUBE_VERSION} /out/rootfs/usr/local/bin/kubelet
+COPY packages/kubernetes/kubeadm-${KUBE_VERSION} /out/rootfs/usr/local/bin/kubeadm
+COPY packages/kubernetes/kubectl-${KUBE_VERSION} /out/rootfs/usr/local/bin/kubectl
+COPY clitools/bin/ctl-linux-${ALPINE_ARCH}-${TAG} /out/rootfs/usr/local/bin/ctl
RUN chmod +x /out/rootfs/usr/local/bin/*
COPY alpine/rootfs-extra ./rootfs-extra
diff --git a/makefile b/makefile
index ed0568c..f7d26e2 100644
--- a/makefile
+++ b/makefile
@@ -13,9 +13,9 @@ NXP_TAR := $(PACKAGES_DIR)/$(NXP_VERSION).tar.gz
CRIO_TAR := $(PACKAGES_DIR)/$(CRIO_VERSION).tar.gz
# Kubernetes components
-KUBELET_BIN := $(PACKAGES_DIR)/kubernetes/kubelet
-KUBEADM_BIN := $(PACKAGES_DIR)/kubernetes/kubeadm
-KUBECTL_BIN := $(PACKAGES_DIR)/kubernetes/kubectl
+KUBELET_BIN := $(PACKAGES_DIR)/kubernetes/kubelet-$(KUBE_VERSION)
+KUBEADM_BIN := $(PACKAGES_DIR)/kubernetes/kubeadm-$(KUBE_VERSION)
+KUBECTL_BIN := $(PACKAGES_DIR)/kubernetes/kubectl-$(KUBE_VERSION)
CONFIGS_DIR := configs
SCRIPTS_DIR := scripts
@@ -31,6 +31,7 @@ RELEASE_IMAGE := $(OUT_DIR)/monok8s-$(TAG).img.gz
KERNEL_IMAGE := $(OUT_DIR)/Image.gz
BUILD_BASE_STAMP := $(OUT_DIR)/.build-base-$(TAG).stamp
+CLITOOLS_BIN := bin/ctl-linux-$(ARCH)-$(TAG)
ALPINE_SERIES := $(word 1,$(subst ., ,$(ALPINE_VER))).$(word 2,$(subst ., ,$(ALPINE_VER)))
@@ -46,6 +47,8 @@ ALPINE_SRCS := $(shell find alpine -type f 2>/dev/null)
INITRAMFS_SRCS := $(shell find initramfs -type f 2>/dev/null)
KERNEL_SRCS := $(shell find kernel-build -type f 2>/dev/null)
+CLITOOLS_SRCS := $(shell find clitools -type f 2>/dev/null)
+
BUILD_BASE_DEPS := \
docker/build-base.Dockerfile \
build.env \
@@ -77,11 +80,15 @@ ITB_DEPS := \
build.env \
makefile
+CLITOOLS := \
+ $(CLITOOLS_SRCS)
+
RELEASE_DEPS := \
$(BUILD_BASE_STAMP) \
$(BUILD_INFO_FILE) \
$(BOARD_ITB) \
$(ALPINE_TAR) \
+ $(CLITOOLS_BIN) \
$(CRIO_TAR) \
$(KUBELET_BIN) \
$(KUBEADM_BIN) \
@@ -91,12 +98,6 @@ RELEASE_DEPS := \
build.env \
makefile
-CLITOOLS := \
- clitools/pkg \
- clitools/cmd \
- clitools/go.mod \
- clitools/go.sum
-
# ---- Directory creation ------------------------------------------------------
$(PACKAGES_DIR):
@@ -174,6 +175,9 @@ $(INITRAMFS): $(INITRAMFS_DEPS) | $(OUT_DIR)
--output type=local,dest=./$(OUT_DIR) .
test -f $@
+$(CLITOOLS_BIN): $(CLITOOLS_SRCS)
+ $(MAKE) -C clitools
+
$(BOARD_ITB): $(ITB_DEPS) | $(OUT_DIR)
docker build \
-f docker/itb.Dockerfile \
@@ -191,6 +195,7 @@ $(RELEASE_IMAGE): $(RELEASE_DEPS) | $(OUT_DIR)
--build-arg TAG=$(TAG) \
--build-arg ALPINE_ARCH=$(ALPINE_ARCH) \
--build-arg ALPINE_VER=$(ALPINE_VER) \
+ --build-arg KUBE_VERSION=$(KUBE_VERSION) \
--build-arg CRIO_VERSION=$(CRIO_VERSION) \
--build-arg DEVICE_TREE_TARGET=$(DEVICE_TREE_TARGET) \
-t $(DOCKER_IMAGE_ROOT)/buildenv-alpine:$(TAG) .
@@ -263,9 +268,7 @@ kernel: $(KERNEL_IMAGE)
initramfs: $(INITRAMFS)
itb: $(BOARD_ITB)
build-base: $(BUILD_BASE_STAMP)
-
-clitools: $(CLITOOLS)
- $(MAKE) -C clitools
+clitools: $(CLITOOLS_BIN)
clean:
rm -f \
@@ -274,7 +277,7 @@ clean:
$(INITRAMFS) \
$(BOARD_ITB) \
$(RELEASE_IMAGE) \
- $(CLITOOLS)
+ $(CLITOOLS_BIN)
distclean: clean
rm -rf $(OUT_DIR)