Skip to content

Commit fdfdc86

Browse files
authored
Merge pull request #50 from alicefr/target-imgref
Add option target imgref
2 parents 7a1fef0 + db77fa9 commit fdfdc86

6 files changed

Lines changed: 36 additions & 6 deletions

File tree

internal/cli/cluster/start.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func newStartCmd() *cobra.Command {
2929
var maxMemory int
3030
var exposePath string
3131
var hostNetworkPopulator bool
32+
var targetImgRef string
3233

3334
cmd := &cobra.Command{
3435
Use: "start",
@@ -44,7 +45,7 @@ func newStartCmd() *cobra.Command {
4445
bink cluster start --memory 4096 --expose ./kubeconfig`,
4546
RunE: func(cmd *cobra.Command, args []string) error {
4647
logger := logrus.New()
47-
return runStart(cmd.Context(), logger, nodeName, nodeImage, apiPort, memory, maxMemory, exposePath, hostNetworkPopulator)
48+
return runStart(cmd.Context(), logger, nodeName, nodeImage, apiPort, memory, maxMemory, exposePath, hostNetworkPopulator, targetImgRef)
4849
},
4950
}
5051

@@ -55,11 +56,12 @@ func newStartCmd() *cobra.Command {
5556
cmd.Flags().IntVar(&maxMemory, "max-memory", 0, "VM max memory in MB for balloon (0 = use role default: 4096 for control-plane, 2048 for worker)")
5657
cmd.Flags().StringVar(&exposePath, "expose", "", "Expose API and save kubeconfig to PATH after cluster is up")
5758
cmd.Flags().BoolVar(&hostNetworkPopulator, "host-network-populator", false, "Use host networking for the image populator container (fixes DNS in nested podman)")
59+
cmd.Flags().StringVar(&targetImgRef, "target-imgref", "", "Override the bootc image reference tracked by the VM (e.g., registry.cluster.local:5000/node:latest)")
5860

5961
return cmd
6062
}
6163

62-
func runStart(ctx context.Context, logger *logrus.Logger, nodeName string, nodeImage string, apiPort int, memory int, maxMemory int, exposePath string, hostNetworkPopulator bool) error {
64+
func runStart(ctx context.Context, logger *logrus.Logger, nodeName string, nodeImage string, apiPort int, memory int, maxMemory int, exposePath string, hostNetworkPopulator bool, targetImgRef string) error {
6365
logger.Info("=== Creating Kubernetes cluster ===")
6466
logger.Info("")
6567

@@ -140,6 +142,7 @@ func runStart(ctx context.Context, logger *logrus.Logger, nodeName string, nodeI
140142
node.WithMaxMemory(maxMemory),
141143
node.WithDNSIP(dnsIP),
142144
node.WithClusterImagesVolume(clusterImagesVolume),
145+
node.WithTargetImgRef(targetImgRef),
143146
)
144147
if err != nil {
145148
return fmt.Errorf("creating node: %w", err)

internal/cli/node/add.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func newAddCmd() *cobra.Command {
2727
var maxMemory int
2828
var hostNetworkPopulator bool
2929
var labelFlags []string
30+
var targetImgRef string
3031

3132
cmd := &cobra.Command{
3233
Use: "add <node-name>",
@@ -47,7 +48,7 @@ func newAddCmd() *cobra.Command {
4748
return err
4849
}
4950
logger := logrus.New()
50-
return runAdd(cmd.Context(), args[0], nodeImage, role, memory, maxMemory, hostNetworkPopulator, labels, logger)
51+
return runAdd(cmd.Context(), args[0], nodeImage, role, memory, maxMemory, hostNetworkPopulator, labels, targetImgRef, logger)
5152
},
5253
}
5354

@@ -57,6 +58,7 @@ func newAddCmd() *cobra.Command {
5758
cmd.Flags().IntVar(&maxMemory, "max-memory", 0, "VM max memory in MB for balloon (0 = use role default: 4096 for control-plane, 2048 for worker)")
5859
cmd.Flags().BoolVar(&hostNetworkPopulator, "host-network-populator", false, "Use host networking for the image populator container (fixes DNS in nested podman)")
5960
cmd.Flags().StringArrayVarP(&labelFlags, "label", "l", nil, "Node label in key=value format (can be specified multiple times)")
61+
cmd.Flags().StringVar(&targetImgRef, "target-imgref", "", "Override the bootc image reference tracked by the VM (e.g., registry.cluster.local:5000/node:latest)")
6062

6163
cmd.RegisterFlagCompletionFunc("role", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
6264
return []string{"worker", "control-plane"}, cobra.ShellCompDirectiveNoFileComp
@@ -84,7 +86,7 @@ func parseLabels(labelFlags []string) (map[string]string, error) {
8486
return labels, nil
8587
}
8688

87-
func runAdd(ctx context.Context, nodeName, nodeImage, role string, memory int, maxMemory int, hostNetworkPopulator bool, labels map[string]string, logger *logrus.Logger) error {
89+
func runAdd(ctx context.Context, nodeName, nodeImage, role string, memory int, maxMemory int, hostNetworkPopulator bool, labels map[string]string, targetImgRef string, logger *logrus.Logger) error {
8890
// Validate and convert role to boolean
8991
var isControlPlane bool
9092
switch role {
@@ -165,6 +167,7 @@ func runAdd(ctx context.Context, nodeName, nodeImage, role string, memory int, m
165167
node.WithUsedIPs(usedIPs),
166168
node.WithDNSIP(dnsIP),
167169
node.WithClusterImagesVolume(clusterImagesVolume),
170+
node.WithTargetImgRef(targetImgRef),
168171
}
169172
if isControlPlane {
170173
nodeOpts = append(nodeOpts, node.WithAPIPort(-1))

internal/node/cloudinit.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type CloudInitData struct {
3838
RegistryPort int
3939
RegistryHostname string
4040
ServiceCIDR string
41+
TargetImgRef string
4142
}
4243

4344
func (n *Node) newCloudInitData(sshPubKey string) CloudInitData {
@@ -54,6 +55,7 @@ func (n *Node) newCloudInitData(sshPubKey string) CloudInitData {
5455
RegistryPort: config.RegistryPort,
5556
RegistryHostname: config.RegistryHostname,
5657
ServiceCIDR: config.ServiceCIDR,
58+
TargetImgRef: n.TargetImgRef,
5759
}
5860
}
5961

internal/node/node.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type Node struct {
2929
ClusterImagesVolume string
3030
APIPort int // Configured API port (0 = auto-assign)
3131
AssignedAPIPort int // Actual assigned port after container creation
32+
TargetImgRef string
3233

3334
usedIPs []string
3435
podman *podman.Client
@@ -93,6 +94,13 @@ func WithDNSIP(ip string) NodeOption {
9394
}
9495
}
9596

97+
func WithTargetImgRef(ref string) NodeOption {
98+
return func(n *Node) error {
99+
n.TargetImgRef = ref
100+
return nil
101+
}
102+
}
103+
96104
func WithClusterImagesVolume(volumeName string) NodeOption {
97105
return func(n *Node) error {
98106
n.ClusterImagesVolume = volumeName

internal/node/templates/user-data.yaml.tmpl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,11 @@ runcmd:
8585
- nmcli connection up "cloud-init enp2s0"
8686
- systemctl enable --now crio
8787
- systemctl enable kubelet
88+
{{- if .TargetImgRef}}
89+
- |
90+
mount -o remount,rw /sysroot
91+
DEPLOY_PATH=$(bootc status --json | jq -r '.status.booted.ostree.deploySerial // empty')
92+
CHECKSUM=$(bootc status --json | jq -r '.status.booted.ostree.checksum')
93+
ORIGIN="/ostree/deploy/default/deploy/${CHECKSUM}.${DEPLOY_PATH}.origin"
94+
sed -i 's|^container-image-reference=.*|container-image-reference=ostree-unverified-registry:{{.TargetImgRef}}|' "$ORIGIN"
95+
{{- end}}

test/integration/cluster_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ var _ = Describe("Cluster Lifecycle", func() {
3838
kubeconfigPath := fmt.Sprintf("../../kubeconfig-%s", clusterName)
3939
defer helpers.CleanupKubeconfig(kubeconfigPath)
4040

41-
By("Creating cluster with --expose, custom node name, and memory ballooning")
42-
cmd := helpers.BinkCmd("cluster", "start", "--cluster-name", clusterName, "--api-port", "0", "--memory", "1900", "--max-memory", "4096", "--node-name", customNodeName, "--expose", kubeconfigPath)
41+
targetImgRef := "registry.cluster.local:5000/node:latest"
42+
43+
By("Creating cluster with --expose, custom node name, memory ballooning, and target-imgref")
44+
cmd := helpers.BinkCmd("cluster", "start", "--cluster-name", clusterName, "--api-port", "0", "--memory", "1900", "--max-memory", "4096", "--node-name", customNodeName, "--expose", kubeconfigPath, "--target-imgref", targetImgRef)
4345
session := helpers.RunCommand(cmd)
4446

4547
By("Verifying cluster creation command succeeded")
@@ -93,6 +95,10 @@ var _ = Describe("Cluster Lifecycle", func() {
9395
sshOutput := string(sshSession.Out.Contents())
9496
Expect(sshOutput).To(ContainSubstring(customNodeName), "SSH command output should contain the node hostname")
9597

98+
By("Verifying bootc status shows the overridden image reference")
99+
bootcOutput := helpers.SSHExec(clusterName, customNodeName, "sudo bootc status")
100+
Expect(bootcOutput).To(ContainSubstring(targetImgRef), "bootc status should show the target image reference")
101+
96102
By("Verifying bink node ssh propagates non-zero exit codes")
97103
failCmd := helpers.BinkCmd("node", "ssh", customNodeName, "--cluster-name", clusterName, "--", "exit", "42")
98104
failSession := helpers.RunCommand(failCmd)

0 commit comments

Comments
 (0)