Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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.9
1.25.11
277 changes: 192 additions & 85 deletions CHANGELOG/CHANGELOG-1.34.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.34.0-go1.25.9-bullseye.0
v1.34.0-go1.25.11-bullseye.0
4 changes: 2 additions & 2 deletions build/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ readonly KUBE_RSYNC_PORT="${KUBE_RSYNC_PORT:-}"
readonly KUBE_CONTAINER_RSYNC_PORT=8730

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

# These are the base images for the Docker-wrapped binaries.
Expand Down
6 changes: 3 additions & 3 deletions build/dependencies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,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.34.0-go1.25.9-bullseye.0
version: v1.34.0-go1.25.11-bullseye.0
refPaths:
- path: build/build-image/cross/VERSION

Expand Down Expand Up @@ -166,15 +166,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.9
version: v0.8.11
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.9-bookworm.0
version: v2.4.0-go1.25.11-bookworm.0
refPaths:
- path: build/common.sh
match: __default_go_runner_version=
Expand Down
14 changes: 10 additions & 4 deletions cmd/kubeadm/app/cmd/phases/init/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package phases

import (
"fmt"
"os"
"path/filepath"
"strings"

Expand Down Expand Up @@ -216,20 +217,25 @@ func runCAPhase(ca *certsphase.KubeadmCert) func(c workflow.RunData) error {

if cert, err := pkiutil.TryLoadCertFromDisk(data.CertificateDir(), ca.BaseName); err == nil {
certsphase.CheckCertificatePeriodValidity(ca.BaseName, cert)
srcCertPath, srcKeyPath := pkiutil.PathsForCertAndKey(data.CertificateDir(), ca.BaseName)
dryRunCertPath, dryRunKeyPath := pkiutil.PathsForCertAndKey(data.CertificateWriteDir(), ca.BaseName)

// If CA Cert existed while dryrun, copy CA Cert to dryrun dir for later use
if data.DryRun() {
err := kubeadmutil.CopyFile(filepath.Join(data.CertificateDir(), kubeadmconstants.CACertName), filepath.Join(data.CertificateWriteDir(), kubeadmconstants.CACertName))
if err := os.MkdirAll(filepath.Dir(dryRunCertPath), os.FileMode(0700)); err != nil {
return errors.Wrapf(err, "failed to create directory %s", filepath.Dir(dryRunCertPath))
}
err := kubeadmutil.CopyFile(srcCertPath, dryRunCertPath)
if err != nil {
return errors.Wrapf(err, "could not copy %s to dry run directory %s", kubeadmconstants.CACertName, data.CertificateWriteDir())
return errors.Wrapf(err, "could not copy %s to dry run directory %s", fmt.Sprintf("%s.crt", ca.BaseName), data.CertificateWriteDir())
}
}
if _, err := pkiutil.TryLoadKeyFromDisk(data.CertificateDir(), ca.BaseName); err == nil {
// If CA Key existed while dryrun, copy CA Key to dryrun dir for later use
if data.DryRun() {
err := kubeadmutil.CopyFile(filepath.Join(data.CertificateDir(), kubeadmconstants.CAKeyName), filepath.Join(data.CertificateWriteDir(), kubeadmconstants.CAKeyName))
err := kubeadmutil.CopyFile(srcKeyPath, dryRunKeyPath)
if err != nil {
return errors.Wrapf(err, "could not copy %s to dry run directory %s", kubeadmconstants.CAKeyName, data.CertificateWriteDir())
return errors.Wrapf(err, "could not copy %s to dry run directory %s", fmt.Sprintf("%s.key", ca.BaseName), data.CertificateWriteDir())
}
}
fmt.Printf("[certs] Using existing %s certificate authority\n", ca.BaseName)
Expand Down
55 changes: 55 additions & 0 deletions cmd/kubeadm/app/cmd/phases/init/certs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ limitations under the License.
package phases

import (
"os"
"path/filepath"
"testing"

"github.com/spf13/cobra"

kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
certstestutil "k8s.io/kubernetes/cmd/kubeadm/app/util/certs"
"k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil"
pkiutiltesting "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil/testing"
testutil "k8s.io/kubernetes/cmd/kubeadm/test"
)
Expand All @@ -33,10 +37,19 @@ type testCertsData struct {
cfg *kubeadmapi.InitConfiguration
}

type testDryRunCertsData struct {
testCertsData
certificateDir string
certificateWriteDir string
}

func (t *testCertsData) Cfg() *kubeadmapi.InitConfiguration { return t.cfg }
func (t *testCertsData) ExternalCA() bool { return false }
func (t *testCertsData) CertificateDir() string { return t.cfg.CertificatesDir }
func (t *testCertsData) CertificateWriteDir() string { return t.cfg.CertificatesDir }
func (t *testDryRunCertsData) DryRun() bool { return true }
func (t *testDryRunCertsData) CertificateDir() string { return t.certificateDir }
func (t *testDryRunCertsData) CertificateWriteDir() string { return t.certificateWriteDir }

func TestCreateSparseCerts(t *testing.T) {
for _, test := range certstestutil.GetSparseCertTestCases(t) {
Expand All @@ -63,3 +76,45 @@ func TestCreateSparseCerts(t *testing.T) {
})
}
}

func TestRunCAPhaseCopiesExistingCAFilesToDryRunDir(t *testing.T) {
for _, ca := range []*certsphase.KubeadmCert{
certsphase.KubeadmCertRootCA(),
certsphase.KubeadmCertFrontProxyCA(),
certsphase.KubeadmCertEtcdCA(),
} {
t.Run(ca.Name, func(t *testing.T) {
pkiutiltesting.Reset()

sourceDir := t.TempDir()
writeDir := t.TempDir()
caCert, caKey := certstestutil.SetupCertificateAuthority(t)
certPath, _ := pkiutil.PathsForCertAndKey(sourceDir, ca.BaseName)
if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0700)); err != nil {
t.Fatalf("failed to create source directory for %s: %v", ca.BaseName, err)
}
if err := pkiutil.WriteCertAndKey(sourceDir, ca.BaseName, caCert, caKey); err != nil {
t.Fatalf("failed to write source CA files for %s: %v", ca.BaseName, err)
}

cfg := testutil.GetDefaultInternalConfig(t)
cfg.CertificatesDir = sourceDir
data := &testDryRunCertsData{
testCertsData: testCertsData{cfg: cfg},
certificateDir: sourceDir,
certificateWriteDir: writeDir,
}

if err := runCAPhase(ca)(data); err != nil {
t.Fatalf("runCAPhase(%s) returned error: %v", ca.Name, err)
}

if _, err := pkiutil.TryLoadCertFromDisk(writeDir, ca.BaseName); err != nil {
t.Fatalf("expected copied cert for %s in dry-run dir: %v", ca.BaseName, err)
}
if _, err := pkiutil.TryLoadKeyFromDisk(writeDir, ca.BaseName); err != nil {
t.Fatalf("expected copied key for %s in dry-run dir: %v", ca.BaseName, err)
}
})
}
}
2 changes: 1 addition & 1 deletion openshift-hack/images/hyperkube/Dockerfile.rhel
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ COPY --from=builder /tmp/build/* /usr/bin/
LABEL io.k8s.display-name="OpenShift Kubernetes Server Commands" \
io.k8s.description="OpenShift is a platform for developing, building, and deploying containerized applications." \
io.openshift.tags="openshift,hyperkube" \
io.openshift.build.versions="kubernetes=1.34.8"
io.openshift.build.versions="kubernetes=1.34.9"
18 changes: 16 additions & 2 deletions pkg/controller/endpoint/endpoints_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,22 @@ func (e *Controller) addPod(obj interface{}) {

func podToEndpointAddressForService(svc *v1.Service, pod *v1.Pod) (*v1.EndpointAddress, error) {
var endpointIP string

wantIPv6 := svc.Spec.IPFamilies[0] == v1.IPv6Protocol
ipFamily := v1.IPv4Protocol

// IPFamilies is expected to be populated by apiserver defaulting, but
// some services may reach this controller with an empty IPFamilies via
// watch events. Infer the family from ClusterIP or
// pod IP so we never panic on IPFamilies[0].
if len(svc.Spec.IPFamilies) > 0 {
ipFamily = svc.Spec.IPFamilies[0]
} else if len(svc.Spec.ClusterIP) > 0 && svc.Spec.ClusterIP != v1.ClusterIPNone {
if utilnet.IsIPv6String(svc.Spec.ClusterIP) {
ipFamily = v1.IPv6Protocol
}
} else if utilnet.IsIPv6String(pod.Status.PodIP) {
ipFamily = v1.IPv6Protocol
}
wantIPv6 := ipFamily == v1.IPv6Protocol

// Find an IP that matches the family. We parse and restringify the IP in case the
// value on the Pod is in an irregular format.
Expand Down
80 changes: 80 additions & 0 deletions pkg/controller/endpoint/endpoints_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3167,3 +3167,83 @@ func TestSyncEndpointsAddDeletePorts(t *testing.T) {
t.Fatalf("incorrect endpoints after deleting first port:\n%s", diff)
}
}

func TestPodToEndpointAddressForServiceEmptyIPFamilies(t *testing.T) {
testCases := []struct {
name string
clusterIP string
podIPs []v1.PodIP
podIP string
wantErr bool
wantFamily v1.IPFamily
}{
{
name: "headful IPv4, IPv4 pod",
clusterIP: "10.0.0.1",
podIPs: []v1.PodIP{{IP: "10.244.0.1"}},
wantFamily: v1.IPv4Protocol,
},
{
name: "headful IPv6, IPv6 pod",
clusterIP: "fd00::1",
podIPs: []v1.PodIP{{IP: "fd00::10"}},
wantFamily: v1.IPv6Protocol,
},
{
name: "headful IPv4, no matching pod IP",
clusterIP: "10.0.0.1",
podIPs: []v1.PodIP{{IP: "fd00::10"}},
wantErr: true,
},
{
name: "headless, IPv4 pod",
clusterIP: v1.ClusterIPNone,
podIPs: []v1.PodIP{{IP: "10.244.0.1"}},
podIP: "10.244.0.1",
wantFamily: v1.IPv4Protocol,
},
{
name: "headless, IPv6 pod",
clusterIP: v1.ClusterIPNone,
podIPs: []v1.PodIP{{IP: "fd00::10"}},
podIP: "fd00::10",
wantFamily: v1.IPv6Protocol,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"},
Spec: v1.ServiceSpec{
// Intentionally leave IPFamilies empty.
ClusterIP: tc.clusterIP,
},
}
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "foo-pod", Namespace: "bar", UID: "uid-1"},
Spec: v1.PodSpec{NodeName: "node-1"},
Status: v1.PodStatus{PodIP: tc.podIP, PodIPs: tc.podIPs},
}

addr, err := podToEndpointAddressForService(svc, pod)
if tc.wantErr {
if err == nil {
t.Fatalf("expected error but got addr=%v", addr)
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if addr == nil {
t.Fatal("expected an address but got nil")
}
isV6 := utilnet.IsIPv6String(addr.IP)
wantV6 := tc.wantFamily == v1.IPv6Protocol
if isV6 != wantV6 {
t.Errorf("got IP %q (IPv6=%v), want family %v", addr.IP, isV6, tc.wantFamily)
}
})
}
}
2 changes: 1 addition & 1 deletion pkg/kubelet/container/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ type Image struct {
// EnvVar represents the environment variable.
type EnvVar struct {
Name string
Value string
Value string // TODO: switch to []byte
}

// Annotation represents an annotation.
Expand Down
5 changes: 4 additions & 1 deletion pkg/kubelet/kubelet_pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
var (
configMaps = make(map[string]*v1.ConfigMap)
secrets = make(map[string]*v1.Secret)
tmpEnv = make(map[string]string)
tmpEnv = make(map[string]string) // TODO: switch to map[string][]byte
)

// Env will override EnvFrom variables.
Expand Down Expand Up @@ -790,6 +790,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
k = envFrom.Prefix + k
}

// TODO: validate no NUL bytes
tmpEnv[k] = v
}
case envFrom.SecretRef != nil:
Expand Down Expand Up @@ -817,6 +818,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
k = envFrom.Prefix + k
}

// TODO: validate no NUL bytes
tmpEnv[k] = string(v)
}
}
Expand Down Expand Up @@ -910,6 +912,7 @@ func (kl *Kubelet) makeEnvironmentVariables(pod *v1.Pod, container *v1.Container
}
return result, fmt.Errorf("couldn't find key %v in Secret %v/%v", key, pod.Namespace, name)
}
// TODO: validate no NUL bytes
runtimeVal = string(runtimeValBytes)
case utilfeature.DefaultFeatureGate.Enabled(features.EnvFiles) && envVar.ValueFrom.FileKeyRef != nil:
f := envVar.ValueFrom.FileKeyRef
Expand Down
3 changes: 2 additions & 1 deletion pkg/kubelet/kuberuntime/kuberuntime_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"time"

codes "google.golang.org/grpc/codes"

crierror "k8s.io/cri-api/pkg/errors"

"github.com/opencontainers/selinux/go-selinux"
Expand Down Expand Up @@ -399,7 +400,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(ctx context.Context,
e := opts.Envs[idx]
envs[idx] = &runtimeapi.KeyValue{
Key: e.Name,
Value: e.Value,
Value: []byte(e.Value),
}
}
config.Envs = envs
Expand Down
6 changes: 5 additions & 1 deletion pkg/volume/csi/csi_mounter.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,11 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error

if csiRPCError != nil {
// If operation finished with error then we can remove the mount directory.
if volumetypes.IsOperationFinishedError(csiRPCError) {
// Skip on remount (e.g. CSIDriver.spec.requiresRepublish=true): the volume
// was already published and the pod is observing the existing bind mount,
// so removing the mount dir here would leave the pod with stale contents
// that a subsequent successful republish cannot repair (#121271).
if volumetypes.IsOperationFinishedError(csiRPCError) && !mounterArgs.IsRemount {
if removeMountDirErr := removeMountDir(c.plugin, dir); removeMountDirErr != nil {
klog.Error(log("mounter.SetupAt failed to remove mount dir after a NodePublish() error [%s]: %v", dir, removeMountDirErr))
}
Expand Down
Loading