Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
799beb9
kubeadm: skip promote call when etcd member is already a voting member
wgkingk Apr 15, 2026
bf604dc
test/compatibility_lifecycle: resolve feature names from variables
siyuanfoundation Apr 24, 2026
dd84374
Fix job controller reporting active=0 during pod creation backoff
akhilsingh-git Jun 3, 2026
923d2d9
Update CHANGELOG/CHANGELOG-1.35.md for v1.35.6
k8s-release-robot Jun 11, 2026
4c89481
Update google.golang.org/protobuf to v1.36.12-0.20260120151049-f2248a…
dims Mar 5, 2026
463e908
kubeadm: use KubernetesAPICallTimeout for mandatory kubeadm-config fetch
damdo Jun 17, 2026
4b3619c
Merge pull request #139809 from damdo/automated-cherry-pick-of-139667…
k8s-ci-robot Jun 17, 2026
cfad4b5
kubeadm: treat already promoted learner as successful
jihyun-huh Jun 18, 2026
64f72b7
Restore string JSON encoding of cri-api KeyValue
liggitt Jun 23, 2026
8b1184f
Make utf8 replacement char test pass on Go 1.27
liggitt Jun 24, 2026
c371666
Merge pull request #139666 from kmala/automated-cherry-pick-of-#13745…
kubernetes-prow[bot] Jun 25, 2026
2165452
Fix vet error
liggitt Feb 17, 2026
7a90faf
Merge pull request #139966 from liggitt/automated-cherry-pick-of-#139…
kubernetes-prow[bot] Jul 1, 2026
860b2bb
Merge pull request #140030 from kmala/release-1.35
kubernetes-prow[bot] Jul 2, 2026
6a68e67
Merge pull request #139751 from akhilsingh-git/automated-cherry-pick-…
kubernetes-prow[bot] Jul 3, 2026
44b56f8
Merge pull request #139909 from jihyun-huh/automated-cherry-pick-of-#…
kubernetes-prow[bot] Jul 3, 2026
13fcb37
Merge pull request #138492 from wgkingk/automated-cherry-pick-of-#138…
kubernetes-prow[bot] Jul 3, 2026
14e26b5
Merge pull request #138976 from stmcginnis/automated-cherry-pick-of-#…
kubernetes-prow[bot] Jul 3, 2026
ff899e0
stop logging missing optional container annotations
HirazawaUi Jul 1, 2026
d1bb523
Fix ObjectVal ConvertToNative for structpb and refine mutation tests
lalitc375 Jul 10, 2026
36793df
Fix linter warnings
lalitc375 Jul 13, 2026
68bd319
Bump images and versions to golang 1.25.12 and update distroless-ipta…
palnabarun Jul 15, 2026
a4bbdac
Fix case where preemptor may be stuck in unschedulable queue
brejman May 19, 2026
c4d272d
Merge pull request #140321 from HirazawaUi/automated-cherry-pick-of-#…
kubernetes-prow[bot] Jul 18, 2026
d5eba19
Merge pull request #140585 from palnabarun/bump-go-1.35
kubernetes-prow[bot] Jul 18, 2026
96cb9ab
Release commit for Kubernetes v1.35.7
k8s-release-robot Jul 22, 2026
28e0796
Update CHANGELOG/CHANGELOG-1.35.md for v1.35.7
k8s-release-robot Jul 22, 2026
e5d59a4
Bump to go 1.26.5
kmala Jul 24, 2026
b5d9d08
Update golang.org/x deps
liggitt Aug 6, 2026
7f729ec
Merge pull request #140920 from kmala/release-1.35
kubernetes-prow[bot] Aug 7, 2026
1cf1491
Merge pull request #140637 from iomarsayed/automated-cherry-pick-of-#…
kubernetes-prow[bot] Aug 8, 2026
9d6e640
Merge pull request #141225 from liggitt/golang-deps-1-35
kubernetes-prow[bot] Aug 8, 2026
7fad80f
Merge pull request #140558 from lalitc375/automated-cherry-pick-of-#1…
kubernetes-prow[bot] Aug 10, 2026
1c2e10a
Release commit for Kubernetes v1.35.8
k8s-release-robot Aug 20, 2026
1d87214
Merge tag 'v1.35.8' into release-4.22
redhat-chai-bot Aug 21, 2026
69102a5
UPSTREAM: <drop>: hack/update-vendor.sh, make update and update image
redhat-chai-bot Aug 21, 2026
29af28a
UPSTREAM: <drop>: update builder image to golang 1.26
redhat-chai-bot Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.25.11
1.26.5
350 changes: 288 additions & 62 deletions CHANGELOG/CHANGELOG-1.35.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/build-image/cross/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.35.0-go1.25.11-bullseye.0
v1.35.0-go1.26.5-bullseye.0
4 changes: 2 additions & 2 deletions build/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ readonly REMOTE_OUTPUT_BINPATH="${REMOTE_OUTPUT_SUBPATH}/bin"
readonly REMOTE_OUTPUT_GOPATH="${REMOTE_OUTPUT_SUBPATH}/go"

# These are the default versions (image tags) for their respective base images.
readonly __default_distroless_iptables_version=v0.8.11
readonly __default_go_runner_version=v2.4.0-go1.25.11-bookworm.0
readonly __default_distroless_iptables_version=v0.9.6
readonly __default_go_runner_version=v2.4.0-go1.26.5-bookworm.0
readonly __default_setcap_version=bookworm-v1.0.6

# The default image for all binaries which are dynamically linked.
Expand Down
12 changes: 6 additions & 6 deletions build/dependencies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ dependencies:
# should also be updated, but go-runner is much harder to exploit and has
# far less relevancy to go updates for Kubernetes more generally.
- name: "registry.k8s.io/kube-cross: dependents"
version: v1.35.0-go1.25.11-bullseye.0
version: v1.35.0-go1.26.5-bullseye.0
refPaths:
- path: build/build-image/cross/VERSION

Expand All @@ -132,11 +132,11 @@ dependencies:
# This entry is a stub of the major version to allow dependency checks to
# pass when building Kubernetes using a pre-release of Golang.
- name: "golang: 1.<major>"
version: 1.25
version: 1.26
refPaths:
- path: build/build-image/cross/VERSION
- path: hack/lib/golang.sh
match: minimum_go_version=go([0-9]+\.[0-9]+)
#- path: hack/lib/golang.sh
# match: minimum_go_version=go([0-9]+\.[0-9]+)

# Base images
- name: "registry.k8s.io/debian-base: dependents"
Expand Down Expand Up @@ -170,15 +170,15 @@ dependencies:
match: registry\.k8s\.io\/build-image\/debian-base:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)

- name: "registry.k8s.io/distroless-iptables: dependents"
version: v0.8.11
version: v0.9.6
refPaths:
- path: build/common.sh
match: __default_distroless_iptables_version=
- path: test/utils/image/manifest.go
match: configs\[DistrolessIptables\] = Config{list\.BuildImageRegistry, "distroless-iptables", "v([0-9]+)\.([0-9]+)\.([0-9]+)"}

- name: "registry.k8s.io/go-runner: dependents"
version: v2.4.0-go1.25.11-bookworm.0
version: v2.4.0-go1.26.5-bookworm.0
refPaths:
- path: build/common.sh
match: __default_go_runner_version=
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ func getInternalCfg(cfgPath string, client kubernetes.Interface, cfg kubeadmapiv
getNodeRegistration := true
getAPIEndpoint := staticpodutil.IsControlPlaneNode()
getComponentConfigs := true
internalcfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, getNodeRegistration, getAPIEndpoint, getComponentConfigs)
internalcfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, logPrefix, getNodeRegistration, getAPIEndpoint, getComponentConfigs, true)
if err == nil {
printer.Println() // add empty line to separate the FetchInitConfigurationFromCluster output from the command output
// certificate renewal or expiration checking doesn't depend on a running cluster, which means the CertificatesDir
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ func fetchInitConfiguration(client clientset.Interface) (*kubeadmapi.InitConfigu
getNodeRegistration := false
getAPIEndpoint := false
getComponentConfigs := true
initConfiguration, err := configutil.FetchInitConfigurationFromCluster(client, nil, "preflight", getNodeRegistration, getAPIEndpoint, getComponentConfigs)
initConfiguration, err := configutil.FetchInitConfigurationFromCluster(client, nil, "preflight", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false)
if err != nil {
return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func newResetData(cmd *cobra.Command, opts *resetOptions, in io.Reader, out io.W
getNodeRegistration := true
getAPIEndpoint := staticpodutil.IsControlPlaneNode()
getComponentConfigs := true
initCfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "reset", getNodeRegistration, getAPIEndpoint, getComponentConfigs)
initCfg, err = configutil.FetchInitConfigurationFromCluster(client, nil, "reset", getNodeRegistration, getAPIEndpoint, getComponentConfigs, true)
if err != nil {
klog.Warningf("[reset] Unable to fetch the kubeadm-config ConfigMap from cluster: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/upgrade/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func newApplyData(cmd *cobra.Command, args []string, applyFlags *applyFlags) (*a
getNodeRegistration := true
isControlPlaneNode := true
getComponentConfigs := true
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, isControlPlaneNode, getComponentConfigs)
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, isControlPlaneNode, getComponentConfigs, false)
if err != nil {
if apierrors.IsNotFound(err) {
_, _ = printer.Printf("[upgrade] In order to upgrade, a ConfigMap called %q in the %q namespace must exist.\n", constants.KubeadmConfigConfigMap, metav1.NamespaceSystem)
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/upgrade/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func enforceRequirements(flagSet *pflag.FlagSet, flags *applyPlanFlags, args []s
getNodeRegistration := true
getAPIEndpoint := staticpodutil.IsControlPlaneNode()
getComponentConfigs := true
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", getNodeRegistration, getAPIEndpoint, getComponentConfigs)
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, printer, "upgrade/config", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false)
if err != nil {
return nil, nil, nil, nil, errors.Wrap(err, "[upgrade/init config] FATAL")
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/kubeadm/app/cmd/upgrade/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func validateManifestsPath(manifests ...string) (err error) {
}

// FetchInitConfigurationFunc defines the signature of the function which will fetch InitConfiguration from cluster.
type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error)
type FetchInitConfigurationFunc func(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error)

func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfigurationFromCluster FetchInitConfigurationFunc) error {
externalCfg := &v1beta4.UpgradeConfiguration{}
Expand All @@ -123,7 +123,7 @@ func runDiff(fs *pflag.FlagSet, flags *diffFlags, args []string, fetchInitConfig
getNodeRegistration := true
getAPIEndpoint := staticpodutil.IsControlPlaneNode()
getComponentConfigs := false
initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", getNodeRegistration, getAPIEndpoint, getComponentConfigs)
initCfg, err := fetchInitConfigurationFromCluster(client, &output.TextPrinter{}, "upgrade/diff", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/upgrade/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func createTestRunDiffFile(contents []byte) (string, error) {
return file.Name(), nil
}

func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) {
func fakeFetchInitConfig(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) {
return &kubeadmapi.InitConfiguration{
ClusterConfiguration: kubeadmapi.ClusterConfiguration{
KubernetesVersion: "v1.0.1",
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/cmd/upgrade/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func newNodeData(cmd *cobra.Command, nodeOptions *nodeOptions, out io.Writer) (*
getNodeRegistration := true
getAPIEndpoint := isControlPlaneNode
getComponentConfigs := true
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, getAPIEndpoint, getComponentConfigs)
initCfg, err := configutil.FetchInitConfigurationFromCluster(client, nil, "upgrade", getNodeRegistration, getAPIEndpoint, getComponentConfigs, false)
if err != nil {
return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
}
Expand Down
35 changes: 30 additions & 5 deletions cmd/kubeadm/app/util/config/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"time"

authv1 "k8s.io/api/authentication/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/wait"
Expand All @@ -51,8 +52,10 @@ import (
kubeadmruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime"
)

// FetchInitConfigurationFromCluster fetches configuration from a ConfigMap in the cluster
func FetchInitConfigurationFromCluster(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) {
// FetchInitConfigurationFromCluster fetches configuration from a ConfigMap in the cluster.
// If shortConfigMapGet is true, a short retry is used when fetching the kubeadm-config ConfigMap,
// which is suitable for callers like "kubeadm reset" that don't need a long retry.
func FetchInitConfigurationFromCluster(client clientset.Interface, printer output.Printer, logPrefix string, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) {
if printer == nil {
printer = &output.TextPrinter{}
}
Expand All @@ -61,7 +64,7 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu
_, _ = printer.Printf("[%s] Use 'kubeadm init phase upload-config kubeadm --config your-config-file' to re-upload it.\n", logPrefix)

// Fetch the actual config from cluster
cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, getNodeRegistration, getAPIEndpoint, getComponentConfigs)
cfg, err := getInitConfigurationFromCluster(constants.KubernetesDir, client, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet)
if err != nil {
return nil, err
}
Expand All @@ -78,9 +81,31 @@ func FetchInitConfigurationFromCluster(client clientset.Interface, printer outpu
}

// getInitConfigurationFromCluster is separate only for testing purposes, don't call it directly, use FetchInitConfigurationFromCluster instead
func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, getNodeRegistration, getAPIEndpoint, getComponentConfigs bool) (*kubeadmapi.InitConfiguration, error) {
func getInitConfigurationFromCluster(kubeconfigDir string, client clientset.Interface, getNodeRegistration, getAPIEndpoint, getComponentConfigs, shortConfigMapGet bool) (*kubeadmapi.InitConfiguration, error) {
// Also, the config map really should be KubeadmConfigConfigMap...
configMap, err := apiclient.GetConfigMapWithShortRetry(client, metav1.NamespaceSystem, constants.KubeadmConfigConfigMap)
var configMap *v1.ConfigMap
var err error
if shortConfigMapGet {
configMap, err = apiclient.GetConfigMapWithShortRetry(client, metav1.NamespaceSystem, constants.KubeadmConfigConfigMap)
} else {
var lastErr error
err = wait.PollUntilContextTimeout(context.Background(),
constants.KubernetesAPICallRetryInterval,
kubeadmapi.GetActiveTimeouts().KubernetesAPICall.Duration,
true, func(_ context.Context) (bool, error) {
var err error
configMap, err = client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(
context.Background(), constants.KubeadmConfigConfigMap, metav1.GetOptions{})
if err == nil {
return true, nil
}
lastErr = err
return false, nil
})
if err != nil {
err = lastErr
}
}
if err != nil {
return nil, errors.Wrap(err, "failed to get config map")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kubeadm/app/util/config/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ func TestGetInitConfigurationFromCluster(t *testing.T) {
}

getComponentConfigs := true
cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.getNodeRegistration, rt.getAPIEndpoint, getComponentConfigs)
cfg, err := getInitConfigurationFromCluster(tmpdir, client, rt.getNodeRegistration, rt.getAPIEndpoint, getComponentConfigs, true)
if rt.expectedError != (err != nil) {
t.Errorf("unexpected return err from getInitConfigurationFromCluster: %v", err)
return
Expand Down
42 changes: 37 additions & 5 deletions cmd/kubeadm/app/util/etcd/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,14 +584,17 @@ func (c *Client) getMemberStatus(memberID uint64) (isLearner bool, started bool,
func (c *Client) MemberPromote(learnerID uint64) error {
var (
lastError error
isLearner bool
isStarted bool
learnerIDUint = strconv.FormatUint(learnerID, 16)
)

klog.V(1).Infof("[etcd] Waiting for a learner to start: %s", learnerIDUint)

err := wait.PollUntilContextTimeout(context.Background(), constants.EtcdAPICallRetryInterval, kubeadmapi.GetActiveTimeouts().EtcdAPICall.Duration,
true, func(_ context.Context) (bool, error) {
isLearner, started, err := c.getMemberStatus(learnerID)
var err error
isLearner, isStarted, err = c.getMemberStatus(learnerID)
if err != nil {
lastError = errors.WithMessagef(err, "failed to get member %s status", learnerIDUint)
return false, nil
Expand All @@ -600,7 +603,7 @@ func (c *Client) MemberPromote(learnerID uint64) error {
klog.V(1).Infof("[etcd] Member %s was already promoted.", learnerIDUint)
return true, nil
}
if !started {
if !isStarted {
klog.V(1).Infof("[etcd] Member %s is not started yet. Waiting for it to be started.", learnerIDUint)
lastError = errors.Errorf("the etcd member %s is not started", learnerIDUint)
return false, nil
Expand All @@ -611,6 +614,10 @@ func (c *Client) MemberPromote(learnerID uint64) error {
return lastError
}

if !isLearner {
return nil
}

klog.V(1).Infof("[etcd] Promoting a learner as a voting member: %s", learnerIDUint)

cli, err := c.newEtcdClient(c.Endpoints)
Expand All @@ -626,14 +633,39 @@ func (c *Client) MemberPromote(learnerID uint64) error {
// 2. context deadline exceeded
// 3. peer URLs already exists
// Once the client provides a way to check if the etcd learner is ready to promote, the retry logic can be revisited.
var promoteResp *clientv3.MemberPromoteResponse
var memberList []*etcdserverpb.Member
err = wait.PollUntilContextTimeout(context.Background(), constants.EtcdAPICallRetryInterval, kubeadmapi.GetActiveTimeouts().EtcdAPICall.Duration,
true, func(_ context.Context) (bool, error) {
// MemberPromote can return a transient client-side error even if the
// promotion already succeeded on the etcd side. Check the current
// member state before attempting another promotion so that retries
// remain idempotent.
resp, statusErr := c.listMembersOnce()
if statusErr != nil {
klog.V(5).Infof("[etcd] Failed to list members before promoting learner %s: %v", learnerIDUint, statusErr)
lastError = statusErr
return false, nil
}

for _, m := range resp.Members {
if m.ID != learnerID {
continue
}

if !m.IsLearner {
klog.V(1).Infof("[etcd] Member %s is already a voting member, treating promotion as successful", learnerIDUint)
memberList = resp.Members
return true, nil
}
break
}

ctx, cancel := context.WithTimeout(context.Background(), etcdTimeout)
defer cancel()
promoteResp, err = cli.MemberPromote(ctx, learnerID)
promoteResp, err := cli.MemberPromote(ctx, learnerID)
if err == nil {
klog.V(1).Infof("[etcd] The learner was promoted as a voting member: %s", learnerIDUint)
memberList = promoteResp.Members
return true, nil
}
klog.V(5).Infof("[etcd] Promoting the learner %s failed: %v", learnerIDUint, err)
Expand All @@ -644,7 +676,7 @@ func (c *Client) MemberPromote(learnerID uint64) error {
return lastError
}

for _, m := range promoteResp.Members {
for _, m := range memberList {
if m.ID == learnerID {
parsedPeerAddrs, err := url.Parse(m.PeerURLs[0])
if err != nil {
Expand Down
Loading