Skip to content

Commit 080efcb

Browse files
committed
feat: add k8s-version parameter to k8s-bundle
Allow overriding K8s version in the command. Signed-off-by: Mateusz Urbanek <mateusz.urbanek@siderolabs.com>
1 parent b764f5f commit 080efcb

File tree

6 files changed

+235
-77
lines changed

6 files changed

+235
-77
lines changed

cmd/talosctl/cmd/talos/image.go

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -138,36 +138,56 @@ var imagePullCmd = &cobra.Command{
138138
},
139139
}
140140

141-
// imageDefaultCmd represents the image k8s-bundle command.
142-
var imageDefaultCmd = &cobra.Command{
141+
var imageK8sBundleCmdFlags = struct {
142+
k8sVersion pflag.Value
143+
flannelVersion pflag.Value
144+
corednsVersion pflag.Value
145+
etcdVersion pflag.Value
146+
}{
147+
k8sVersion: helpers.Semver(constants.DefaultKubernetesVersion),
148+
flannelVersion: helpers.Semver(constants.FlannelVersion),
149+
corednsVersion: helpers.Semver(constants.DefaultCoreDNSVersion),
150+
etcdVersion: helpers.Semver(constants.DefaultEtcdVersion),
151+
}
152+
153+
// imageK8sBundleCmd represents the image k8s-bundle command.
154+
var imageK8sBundleCmd = &cobra.Command{
143155
Use: "k8s-bundle",
144156
Aliases: []string{"default"},
145157
Short: "List the default Kubernetes images used by Talos",
146158
Long: ``,
147159
RunE: func(cmd *cobra.Command, args []string) error {
148-
images := images.List(container.NewV1Alpha1(&v1alpha1.Config{
149-
MachineConfig: &v1alpha1.MachineConfig{
150-
MachineKubelet: &v1alpha1.KubeletConfig{},
160+
images := images.ListWithOptions(container.NewV1Alpha1(
161+
&v1alpha1.Config{
162+
MachineConfig: &v1alpha1.MachineConfig{
163+
MachineKubelet: &v1alpha1.KubeletConfig{},
164+
},
165+
ClusterConfig: &v1alpha1.ClusterConfig{
166+
EtcdConfig: &v1alpha1.EtcdConfig{},
167+
APIServerConfig: &v1alpha1.APIServerConfig{},
168+
ControllerManagerConfig: &v1alpha1.ControllerManagerConfig{},
169+
SchedulerConfig: &v1alpha1.SchedulerConfig{},
170+
CoreDNSConfig: &v1alpha1.CoreDNS{},
171+
ProxyConfig: &v1alpha1.ProxyConfig{},
172+
},
173+
}),
174+
images.VersionsListOptions{
175+
KubernetesVersion: imageK8sBundleCmdFlags.k8sVersion.String(),
176+
EtcdVersion: imageK8sBundleCmdFlags.etcdVersion.String(),
177+
FlannelVersion: imageK8sBundleCmdFlags.flannelVersion.String(),
178+
CoreDNSVersion: imageK8sBundleCmdFlags.corednsVersion.String(),
151179
},
152-
ClusterConfig: &v1alpha1.ClusterConfig{
153-
EtcdConfig: &v1alpha1.EtcdConfig{},
154-
APIServerConfig: &v1alpha1.APIServerConfig{},
155-
ControllerManagerConfig: &v1alpha1.ControllerManagerConfig{},
156-
SchedulerConfig: &v1alpha1.SchedulerConfig{},
157-
CoreDNSConfig: &v1alpha1.CoreDNS{},
158-
ProxyConfig: &v1alpha1.ProxyConfig{},
159-
},
160-
}))
180+
)
161181

162182
fmt.Printf("%s\n", images.Flannel)
163183
fmt.Printf("%s\n", images.CoreDNS)
164184
fmt.Printf("%s\n", images.Etcd)
185+
fmt.Printf("%s\n", images.Pause)
165186
fmt.Printf("%s\n", images.KubeAPIServer)
166187
fmt.Printf("%s\n", images.KubeControllerManager)
167188
fmt.Printf("%s\n", images.KubeScheduler)
168189
fmt.Printf("%s\n", images.KubeProxy)
169190
fmt.Printf("%s\n", images.Kubelet)
170-
fmt.Printf("%s\n", images.Pause)
171191

172192
return nil
173193
},
@@ -317,15 +337,15 @@ var imageIntegrationCmd = &cobra.Command{
317337
}))
318338

319339
imageNames := []string{
320-
imgs.Flannel,
321-
imgs.CoreDNS,
322-
imgs.Etcd,
323-
imgs.KubeAPIServer,
324-
imgs.KubeControllerManager,
325-
imgs.KubeScheduler,
326-
imgs.KubeProxy,
327-
imgs.Kubelet,
328-
imgs.Pause,
340+
imgs.Flannel.String(),
341+
imgs.CoreDNS.String(),
342+
imgs.Etcd.String(),
343+
imgs.KubeAPIServer.String(),
344+
imgs.KubeControllerManager.String(),
345+
imgs.KubeScheduler.String(),
346+
imgs.KubeProxy.String(),
347+
imgs.Kubelet.String(),
348+
imgs.Pause.String(),
329349
"registry.k8s.io/conformance:v" + constants.DefaultKubernetesVersion,
330350
"docker.io/library/alpine:latest",
331351
"ghcr.io/siderolabs/talosctl:latest",
@@ -651,7 +671,11 @@ func init() {
651671
imageTalosBundleCmd.PersistentFlags().BoolVar(&imageTalosBundleCmdFlags.overlays, "overlays", true, "Include images that belong to Talos overlays")
652672
imageTalosBundleCmd.PersistentFlags().BoolVar(&imageTalosBundleCmdFlags.extensions, "extensions", true, "Include images that belong to Talos extensions")
653673

654-
imageCmd.AddCommand(imageDefaultCmd)
674+
imageCmd.AddCommand(imageK8sBundleCmd)
675+
imageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.k8sVersion, "k8s-version", "Kubernetes semantic version")
676+
imageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.etcdVersion, "etcd-version", "ETCD semantic version")
677+
imageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.flannelVersion, "flannel-version", "Flannel CNI semantic version")
678+
imageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.corednsVersion, "coredns-version", "CoreDNS semantic version")
655679

656680
imageCmd.AddCommand(imageCacheCreateCmd)
657681
imageCacheCreateCmd.PersistentFlags().StringVar(&imageCacheCreateCmdFlags.imageCachePath, "image-cache-path", "", "directory to save the image cache in OCI format")

cmd/talosctl/pkg/talos/helpers/flags.go

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,32 @@ import (
88
"fmt"
99
"slices"
1010

11+
"github.com/blang/semver/v4"
1112
"github.com/spf13/pflag"
1213
)
1314

14-
// choiceValue implements the [pflag.Value] interface.
1515
type choiceValue struct {
1616
value string
1717
validate func(string) error
1818
}
1919

20-
// Set sets the value of the choice.
21-
func (f *choiceValue) Set(s string) error {
22-
err := f.validate(s)
20+
// Set implements pflag.Value interface.
21+
func (v *choiceValue) Set(s string) error {
22+
err := v.validate(s)
2323
if err != nil {
2424
return err
2525
}
2626

27-
f.value = s
27+
v.value = s
2828

2929
return nil
3030
}
3131

32-
// Type returns the type of the choice, which must be "string" for [pflag.FlagSet.GetString].
33-
func (f *choiceValue) Type() string { return "string" }
32+
// Type implements pflag.Value interface.
33+
func (v *choiceValue) Type() string { return "string" }
3434

35-
// String returns the current value of the choice.
36-
func (f *choiceValue) String() string { return f.value }
35+
// String implements pflag.Value interface.
36+
func (v *choiceValue) String() string { return v.value }
3737

3838
// StringChoice returns a [choiceValue] that validates the value against a set
3939
// of choices. Only the last value will be used if multiple values are set.
@@ -51,3 +51,54 @@ func StringChoice(defaultValue string, otherChoices ...string) pflag.Value {
5151
},
5252
}
5353
}
54+
55+
type semverValue struct {
56+
value semver.Version
57+
validators []SemverValidateFunc
58+
}
59+
60+
// SemverValidateFunc allows setting restrictions on the version.
61+
type SemverValidateFunc func(v semver.Version) error
62+
63+
// Set implements pflag.Value interface.
64+
func (v *semverValue) Set(s string) error {
65+
vers, err := semver.ParseTolerant(s)
66+
if err != nil {
67+
return err
68+
}
69+
70+
for _, validator := range v.validators {
71+
if err := validator(vers); err != nil {
72+
return err
73+
}
74+
}
75+
76+
v.value = vers
77+
78+
return nil
79+
}
80+
81+
// Type implements pflag.Value interface.
82+
func (v *semverValue) Type() string { return "semver" }
83+
84+
// String implements pflag.Value interface.
85+
func (v *semverValue) String() string { return "v" + v.value.String() }
86+
87+
// Semver returns a pflag.Value that parses and stores a semantic version.
88+
//
89+
// Parsing is performed using semver.ParseTolerant. After parsing, any provided
90+
// SemverValidateFunc validators are applied in order and may reject the version.
91+
//
92+
// The returned value is initialized with defaultValue, which is used until Set
93+
// is called successfully.
94+
func Semver(defaultValue string, validators ...SemverValidateFunc) pflag.Value {
95+
v, err := semver.ParseTolerant(defaultValue)
96+
if err != nil {
97+
panic(err)
98+
}
99+
100+
return &semverValue{
101+
value: v,
102+
validators: validators,
103+
}
104+
}

hack/release.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ The switch and inventory backfill is automatic and no action is needed from the
101101
description = """\
102102
The `talosctl images talos-bundle` command now accepts optional `--ovelays` and `--extensions` flags.
103103
If those are set to `false`, the command will not attempt to reach out to the container registry to fetch the latest versions and digests of the overlays and extensions.
104+
"""
105+
106+
[notes.images_k8s_bundle]
107+
title = "Talosctl images k8s-bundle subcommand accepts version parameter"
108+
description = """\
109+
The `talosctl images k8s-bundle` command now accepts an optional version overrides arguments.
104110
"""
105111

106112
[make_deps]

internal/app/machined/pkg/controllers/k8s/control_plane.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ func NewControlPlaneBootstrapManifestsController() *ControlPlaneBootstrapManifes
339339
DNSServiceIPv6: dnsServiceIPv6,
340340

341341
FlannelEnabled: cfgProvider.Cluster().Network().CNI().Name() == constants.FlannelCNI,
342-
FlannelImage: images.Flannel,
342+
FlannelImage: images.Flannel.String(),
343343
FlannelExtraArgs: cfgProvider.Cluster().Network().CNI().Flannel().ExtraArgs(),
344344
FlannelKubeServiceHost: flannelKubeServiceHost,
345345
FlannelKubeServicePort: flannelKubeServicePort,

0 commit comments

Comments
 (0)