diff --git a/go.mod b/go.mod index 78c6f405b719..5f0485f5d8c0 100644 --- a/go.mod +++ b/go.mod @@ -60,20 +60,20 @@ require ( gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.31.12 - k8s.io/apiextensions-apiserver v0.31.12 - k8s.io/apimachinery v0.31.12 - k8s.io/apiserver v0.31.12 - k8s.io/cli-runtime v0.31.12 - k8s.io/client-go v0.31.12 - k8s.io/component-base v0.31.12 - k8s.io/component-helpers v0.31.12 + k8s.io/api v0.31.14 + k8s.io/apiextensions-apiserver v0.31.14 + k8s.io/apimachinery v0.31.14 + k8s.io/apiserver v0.31.14 + k8s.io/cli-runtime v0.31.14 + k8s.io/client-go v0.31.14 + k8s.io/component-base v0.31.14 + k8s.io/component-helpers v0.31.14 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-aggregator v0.31.12 + k8s.io/kube-aggregator v0.31.14 k8s.io/kube-openapi v0.0.0-20240322212309-b815d8309940 - k8s.io/kubectl v0.31.12 - k8s.io/kubernetes v1.31.12 - k8s.io/pod-security-admission v0.31.12 + k8s.io/kubectl v0.31.14 + k8s.io/kubernetes v1.31.14 + k8s.io/pod-security-admission v0.31.14 k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d sigs.k8s.io/cloud-provider-azure v1.30.4 sigs.k8s.io/kustomize/kyaml v0.17.1 @@ -313,34 +313,34 @@ require ( replace ( github.com/onsi/ginkgo/v2 => github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241008152707-25bf9f14db44 - k8s.io/api => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20250907190718-a4cad449903e - k8s.io/apiextensions-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20250907190718-a4cad449903e - k8s.io/apimachinery => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20250907190718-a4cad449903e - k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20250907190718-a4cad449903e - k8s.io/cli-runtime => github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20250907190718-a4cad449903e - k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20250907190718-a4cad449903e - k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20250907190718-a4cad449903e - k8s.io/cluster-bootstrap => github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20250907190718-a4cad449903e - k8s.io/code-generator => github.com/openshift/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20250907190718-a4cad449903e - k8s.io/component-base => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20250907190718-a4cad449903e - k8s.io/component-helpers => github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20250907190718-a4cad449903e - k8s.io/controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20250907190718-a4cad449903e - k8s.io/cri-api => github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20250907190718-a4cad449903e - k8s.io/cri-client => github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20250907190718-a4cad449903e - k8s.io/csi-translation-lib => github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20250907190718-a4cad449903e - k8s.io/dynamic-resource-allocation => github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20250907190718-a4cad449903e - k8s.io/endpointslice => github.com/openshift/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20250907190718-a4cad449903e - k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20250907190718-a4cad449903e - k8s.io/kube-controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20250907190718-a4cad449903e - k8s.io/kube-proxy => github.com/openshift/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20250907190718-a4cad449903e - k8s.io/kube-scheduler => github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20250907190718-a4cad449903e - k8s.io/kubectl => github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20250907190718-a4cad449903e - k8s.io/kubelet => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20250907190718-a4cad449903e - k8s.io/kubernetes => github.com/openshift/kubernetes v1.30.1-0.20250907190718-a4cad449903e - k8s.io/metrics => github.com/openshift/kubernetes/staging/src/k8s.io/metrics v0.0.0-20250907190718-a4cad449903e - k8s.io/mount-utils => github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20250907190718-a4cad449903e - k8s.io/pod-security-admission => github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20250907190718-a4cad449903e - k8s.io/sample-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20250907190718-a4cad449903e - k8s.io/sample-cli-plugin => github.com/openshift/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20250907190718-a4cad449903e - k8s.io/sample-controller => github.com/openshift/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20250907190718-a4cad449903e + k8s.io/api => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20251128114408-436b373e7dec + k8s.io/apiextensions-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251128114408-436b373e7dec + k8s.io/apimachinery => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20251128114408-436b373e7dec + k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20251128114408-436b373e7dec + k8s.io/cli-runtime => github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20251128114408-436b373e7dec + k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20251128114408-436b373e7dec + k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20251128114408-436b373e7dec + k8s.io/cluster-bootstrap => github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20251128114408-436b373e7dec + k8s.io/code-generator => github.com/openshift/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20251128114408-436b373e7dec + k8s.io/component-base => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20251128114408-436b373e7dec + k8s.io/component-helpers => github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20251128114408-436b373e7dec + k8s.io/controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20251128114408-436b373e7dec + k8s.io/cri-api => github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20251128114408-436b373e7dec + k8s.io/cri-client => github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20251128114408-436b373e7dec + k8s.io/csi-translation-lib => github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20251128114408-436b373e7dec + k8s.io/dynamic-resource-allocation => github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20251128114408-436b373e7dec + k8s.io/endpointslice => github.com/openshift/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20251128114408-436b373e7dec + k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20251128114408-436b373e7dec + k8s.io/kube-controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20251128114408-436b373e7dec + k8s.io/kube-proxy => github.com/openshift/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20251128114408-436b373e7dec + k8s.io/kube-scheduler => github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20251128114408-436b373e7dec + k8s.io/kubectl => github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20251128114408-436b373e7dec + k8s.io/kubelet => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20251128114408-436b373e7dec + k8s.io/kubernetes => github.com/openshift/kubernetes v0.0.0-20251128114408-436b373e7dec + k8s.io/metrics => github.com/openshift/kubernetes/staging/src/k8s.io/metrics v0.0.0-20251128114408-436b373e7dec + k8s.io/mount-utils => github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20251128114408-436b373e7dec + k8s.io/pod-security-admission => github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20251128114408-436b373e7dec + k8s.io/sample-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20251128114408-436b373e7dec + k8s.io/sample-cli-plugin => github.com/openshift/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20251128114408-436b373e7dec + k8s.io/sample-controller => github.com/openshift/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20251128114408-436b373e7dec ) diff --git a/go.sum b/go.sum index 899243785446..6f4a6c1935d7 100644 --- a/go.sum +++ b/go.sum @@ -680,52 +680,52 @@ github.com/openshift/client-go v0.0.0-20241107164952-923091dd2b1a h1:h3F55x+zOXw github.com/openshift/client-go v0.0.0-20241107164952-923091dd2b1a/go.mod h1:JBIcn1JfD/JCpGYnRRT0+HLxrleF/Y7T3Y/t0p8o5jk= github.com/openshift/cluster-network-operator v0.0.0-20240708200319-1cd8678b38fb h1:Dr0dbSQTAU9UaoAvimGjR+fsvwx2twJ5KR0s/jyAz88= github.com/openshift/cluster-network-operator v0.0.0-20240708200319-1cd8678b38fb/go.mod h1:LnhqxbWhAnhPwilJ4yX1/ly7wCMCYJKkaiSJQSh+Wjg= -github.com/openshift/kubernetes v1.30.1-0.20250907190718-a4cad449903e h1:TjJ1HijZMj8ZWx5MwBRNjomeMjmqVexkkx+tRGzdR4M= -github.com/openshift/kubernetes v1.30.1-0.20250907190718-a4cad449903e/go.mod h1:tAQ3HfJZYZz6uAmTND0QOYSG7E4Sfz3yHiR/9v2adV0= -github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20250907190718-a4cad449903e h1:aAJ9rfreJxDPm7Uas0PGeYVkAotxd3lCb6Bdgqt5GSc= -github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20250907190718-a4cad449903e/go.mod h1:c4/1bhM5qyJS3C315ioNbye2Cyb/iw73tZy68S9dr7I= -github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20250907190718-a4cad449903e h1:DLjYq2d8TNqPasfF5ou7g17xW+fzQmiq9OgigytNgZ4= -github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20250907190718-a4cad449903e/go.mod h1:dGQ4R3teaL3D6GVYl9uGqOK7OrQNL8wnAAk3U56Zt/w= -github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20250907190718-a4cad449903e h1:cqMmpn4ENdDXtWiTNQXCIcgfqNTsMvgssezD/M6TmuI= -github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20250907190718-a4cad449903e/go.mod h1:DESUJPjrTWS0YmETcifsHEKOo08a7J20LkYD8kSuPaI= -github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20250907190718-a4cad449903e h1:18oCasYNyoB+OAoQaEnxtffzNyyNyKKQ2xgZRtgsOsA= -github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20250907190718-a4cad449903e/go.mod h1:m0X3VdIQUG0+5cMqzB/34Ur+LDQKVYelCwEc3FfI+IY= -github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20250907190718-a4cad449903e h1:y0c8FIVQjGTkOBeIVt4u0mRhZfAOtGmAISjUeN2H0mc= -github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20250907190718-a4cad449903e/go.mod h1:7mIF0av5qJ4DSYGbNLBdzbf93wTdmRigWWMm3oroVPY= -github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20250907190718-a4cad449903e h1:hwlz7rqHxTLdeW/m+Cph28KS6aqCgofoE7c3IZcBcoA= -github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20250907190718-a4cad449903e/go.mod h1:KEnQp4pgQ2zdMSYfbCYTs0YasvrxAVx2iekiuoJYjQM= -github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20250907190718-a4cad449903e h1:OR5UGvCflg5Ld1lqvKyfp84OUqL+pcxF9YNmsb3F1Wo= -github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20250907190718-a4cad449903e/go.mod h1:quuMw5yefUpYWy/wwj3gVzv1d278qZ955vgdf0KoMaQ= -github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20250907190718-a4cad449903e h1:sB8NJbHQJT8dLOD4DNmPfXC+Wf9/EwNpSPJP8UCpp1M= -github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20250907190718-a4cad449903e/go.mod h1:2FS5mTet6db56CX8fh1L3nSiRxhve6Bd6PzfWrKS2wY= -github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20250907190718-a4cad449903e h1:HuyC7o3BbzHGZz086mrRGEg99QaHjPlO53QQJ44hmsg= -github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20250907190718-a4cad449903e/go.mod h1:yktypWGrmGVlLfcbsoJmw/4YDNP55y+Yi6y1Rn7s120= -github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20250907190718-a4cad449903e h1:Esw1myXnxhr/+cgGM9SG525LEI3G/vuam3lHJM8xZmY= -github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20250907190718-a4cad449903e/go.mod h1:rg4Cs8Cz8ca6ieLkAytQ3FXHyEcm9yDCFgchxzNfJ6k= -github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20250907190718-a4cad449903e h1:22FRw1FPqEBDbV+o4u68crEI2dJ5sAqYlk55+RjKgSk= -github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20250907190718-a4cad449903e/go.mod h1:iFvmLS5dWasxkIgw+BNG/VbuFSUxyQGcGF521EN9B/I= -github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20250907190718-a4cad449903e h1:ZZyTROwdO1GXu+QYROKYXIAaETtEf0tGvBMUlgtTC9Q= -github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20250907190718-a4cad449903e/go.mod h1:YpEDCYwaFGuuH5G6cKM2zbgDSvm702C+9Md5rMWNnZU= -github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20250907190718-a4cad449903e h1:xwen0DcqpGrCC3j5nytT0nDKop8SQLhZyL7b+oBd4Kg= -github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20250907190718-a4cad449903e/go.mod h1:j3wMbaWkfpRosgrcMI2zpGLdkvkvHBl2hw80Khk8jGc= -github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20250907190718-a4cad449903e h1:V79ttFw+3QvLI7Jj7FXNLLO+HhhqXvrDkMJNbO/wo1I= -github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20250907190718-a4cad449903e/go.mod h1:CE0eNw5xUf4V+w5ZEuXgGNwwWlzcrV3oeh1oN8A7byM= -github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20250907190718-a4cad449903e h1:v0IP3i297sH+1GWnmAedLEVcO3Bm6X7zL+uLJhy0vU4= -github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20250907190718-a4cad449903e/go.mod h1:9EG+cylLe3BInQjd8n7/hBaNIG5joc2kmKoNjiVNUoI= -github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20250907190718-a4cad449903e h1:qrB2jFNsOTy8RtyPN8Go4IaEDNfF3IjPo9VZIz9uvng= -github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20250907190718-a4cad449903e/go.mod h1:fiugR55RMmpATQFDUm5nb3RzSit2I14v9//fG0gbUJY= -github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20250907190718-a4cad449903e h1:Qcw1ynGXRBrorAywbXrHGjEqunfwNB5x+FN+OE99SKE= -github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20250907190718-a4cad449903e/go.mod h1:8RBMsB1Vyp8wJe4Hu02I7I6assk7uqz6F1j9ejG5pBw= -github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20250907190718-a4cad449903e h1:A/SCf6dxgrTE4eFDvGMnEeyFDdunUH1u/LTg7vqSp7k= -github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20250907190718-a4cad449903e/go.mod h1:ZZoyj+ofRlbElHajU0pqTd6fEinQQW/B+8RQpMJ7PlM= -github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20250907190718-a4cad449903e h1:Or51Q+eIeDTgX4jZjny8WoGvk6uEGF8QRg5DeBHF9BE= -github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20250907190718-a4cad449903e/go.mod h1:aba+hw0aVr0RPzXhBLxs7UIkV9VyxfpiN7U4zpSUWzM= -github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20250907190718-a4cad449903e h1:k95iOPO5FtrmyvfZE/f74ReO5BHQgG+l0TCfX04z5zE= -github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20250907190718-a4cad449903e/go.mod h1:+OJMa3w16QOf8hZQu6Cq+pAt5nRnLWjcc1/ZGi+LTCk= -github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20250907190718-a4cad449903e h1:EOOde8EK9YzKPmnbHW85MntodmenmCtuCXKkWiX+ndk= -github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20250907190718-a4cad449903e/go.mod h1:lYnh13syOSXUO+zZ78dh+6nRbwmNbg8fzzkFxQvdYr4= -github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20250907190718-a4cad449903e h1:TFcWZY3kk0UrImMgS7EChZ3319lo2ZGMX6qinZ3eKNs= -github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20250907190718-a4cad449903e/go.mod h1:ezZxd9niYysb9GpW8rw5teKvz+PEX779jTR3Z3dEmPg= +github.com/openshift/kubernetes v0.0.0-20251128114408-436b373e7dec h1:00sauomETyEwiaaq/WzpN1uf642c2mP4KV0VWCeOJy4= +github.com/openshift/kubernetes v0.0.0-20251128114408-436b373e7dec/go.mod h1:tAQ3HfJZYZz6uAmTND0QOYSG7E4Sfz3yHiR/9v2adV0= +github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20251128114408-436b373e7dec h1:LuglaBM4+DUpfPwmdpiVXAzqz2PkA5Av01sGxxmCB5Y= +github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20251128114408-436b373e7dec/go.mod h1:c4/1bhM5qyJS3C315ioNbye2Cyb/iw73tZy68S9dr7I= +github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251128114408-436b373e7dec h1:kOu61T4pCzhz8We2XpLUb4hMOfkBZGPfT7P5HtvN4GQ= +github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251128114408-436b373e7dec/go.mod h1:dGQ4R3teaL3D6GVYl9uGqOK7OrQNL8wnAAk3U56Zt/w= +github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20251128114408-436b373e7dec h1:vA2stGF2Q0p2SH16pectP++jCju2EVPZhFrYsF6reGU= +github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20251128114408-436b373e7dec/go.mod h1:DESUJPjrTWS0YmETcifsHEKOo08a7J20LkYD8kSuPaI= +github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20251128114408-436b373e7dec h1:zYYxXvpb0ABugEqExySH4KOG8jIOCGPT5zoaqKccMJI= +github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20251128114408-436b373e7dec/go.mod h1:m0X3VdIQUG0+5cMqzB/34Ur+LDQKVYelCwEc3FfI+IY= +github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20251128114408-436b373e7dec h1:XQC6OifaaFu+p/6gxfFizMuMcXUCrMDtENUgeWug2vI= +github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20251128114408-436b373e7dec/go.mod h1:7mIF0av5qJ4DSYGbNLBdzbf93wTdmRigWWMm3oroVPY= +github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20251128114408-436b373e7dec h1:oz+PdSSOiyQeidi4R/Me/YtkJZQ2zTiaX/SYMkszxzk= +github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20251128114408-436b373e7dec/go.mod h1:KEnQp4pgQ2zdMSYfbCYTs0YasvrxAVx2iekiuoJYjQM= +github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20251128114408-436b373e7dec h1:R2qgPUucNJypcqF24bWa0JeEPdQtH/HBXXROnY5kPkE= +github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20251128114408-436b373e7dec/go.mod h1:quuMw5yefUpYWy/wwj3gVzv1d278qZ955vgdf0KoMaQ= +github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20251128114408-436b373e7dec h1:B8yx5b9pTcP04xLL2O8wtmZP2Y8UR8xwVr/+9lwB3A8= +github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20251128114408-436b373e7dec/go.mod h1:2FS5mTet6db56CX8fh1L3nSiRxhve6Bd6PzfWrKS2wY= +github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20251128114408-436b373e7dec h1:jCtIxFRuRhLbnt89/73yIAT0viufjS/E7bPUcTv9mH4= +github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20251128114408-436b373e7dec/go.mod h1:yktypWGrmGVlLfcbsoJmw/4YDNP55y+Yi6y1Rn7s120= +github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20251128114408-436b373e7dec h1:wxwHqWXPM4V+a8rXFLmtO8zGOrwkbu9+A98MPs34ZzU= +github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20251128114408-436b373e7dec/go.mod h1:rg4Cs8Cz8ca6ieLkAytQ3FXHyEcm9yDCFgchxzNfJ6k= +github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20251128114408-436b373e7dec h1:faZsrCnwvE3dVEuOItg55LJ0lcZxlr9W0/eW0kf441U= +github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20251128114408-436b373e7dec/go.mod h1:iFvmLS5dWasxkIgw+BNG/VbuFSUxyQGcGF521EN9B/I= +github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20251128114408-436b373e7dec h1:tiN+35h8/tp7j5V24/xrG6wIvos800adp35OZKT7GdA= +github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20251128114408-436b373e7dec/go.mod h1:YpEDCYwaFGuuH5G6cKM2zbgDSvm702C+9Md5rMWNnZU= +github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20251128114408-436b373e7dec h1:CFX8aOgppMXG9NSkjSa0TzfSrzjynGoVDpM2lmNhwW4= +github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20251128114408-436b373e7dec/go.mod h1:j3wMbaWkfpRosgrcMI2zpGLdkvkvHBl2hw80Khk8jGc= +github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20251128114408-436b373e7dec h1:pBDUZPN6/Y3tmwfz7Mt52UOs+pdWpK/x7L9I37uXXYE= +github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20251128114408-436b373e7dec/go.mod h1:CE0eNw5xUf4V+w5ZEuXgGNwwWlzcrV3oeh1oN8A7byM= +github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20251128114408-436b373e7dec h1:hURmT4h42/C907CKjqmaIQLzLAXUUW8IRVedlE0hbK0= +github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20251128114408-436b373e7dec/go.mod h1:9EG+cylLe3BInQjd8n7/hBaNIG5joc2kmKoNjiVNUoI= +github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20251128114408-436b373e7dec h1:N09acgTEdcgryU9bOqCBxlU2VuF2C5dWxCQcIErEEFY= +github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20251128114408-436b373e7dec/go.mod h1:fiugR55RMmpATQFDUm5nb3RzSit2I14v9//fG0gbUJY= +github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20251128114408-436b373e7dec h1:URsKK3qR9HHLxr/10w2eUsqwRhDrW/+zjkEyo5/Agjk= +github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20251128114408-436b373e7dec/go.mod h1:8RBMsB1Vyp8wJe4Hu02I7I6assk7uqz6F1j9ejG5pBw= +github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20251128114408-436b373e7dec h1:d95JFS+MjQIxEDP6Q8+vLE7r90w2EzbmLr5mXgQNLNE= +github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20251128114408-436b373e7dec/go.mod h1:ZZoyj+ofRlbElHajU0pqTd6fEinQQW/B+8RQpMJ7PlM= +github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20251128114408-436b373e7dec h1:UE95L65Fc2DE8AmZXoklw5WBS16yPCA4mWjA3dDwAo8= +github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20251128114408-436b373e7dec/go.mod h1:aba+hw0aVr0RPzXhBLxs7UIkV9VyxfpiN7U4zpSUWzM= +github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20251128114408-436b373e7dec h1:0ogXhGwoHYqZfcim8kAReOJpVVLL57qEok9HZwTGB1k= +github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20251128114408-436b373e7dec/go.mod h1:+OJMa3w16QOf8hZQu6Cq+pAt5nRnLWjcc1/ZGi+LTCk= +github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20251128114408-436b373e7dec h1:ZFGwPxva4Eb6GkAeOnZkCfKV4Fi2xy232lDevD6NtfI= +github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20251128114408-436b373e7dec/go.mod h1:lYnh13syOSXUO+zZ78dh+6nRbwmNbg8fzzkFxQvdYr4= +github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20251128114408-436b373e7dec h1:Dh04drzDiMmTxVp+4AhXRRSBsFVwkIPlb+T2dsYfOWQ= +github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20251128114408-436b373e7dec/go.mod h1:ezZxd9niYysb9GpW8rw5teKvz+PEX779jTR3Z3dEmPg= github.com/openshift/library-go v0.0.0-20250403134058-7c43fdf96c62 h1:SSb9MKF7czLU0O3HZtMoOXuk/FYfau8ILDnzdciGjEo= github.com/openshift/library-go v0.0.0-20250403134058-7c43fdf96c62/go.mod h1:l/3SegTa9x+ry2J213bh7+DBofXOOvdrqU4JC9ktJa0= github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241008152707-25bf9f14db44 h1:dKUAGq29JBk2oRn955gnnz3sG/UhlkUKh1ISleLiews= diff --git a/images/tests/Dockerfile.rhel b/images/tests/Dockerfile.rhel index 4b738800614f..51432532ff5b 100644 --- a/images/tests/Dockerfile.rhel +++ b/images/tests/Dockerfile.rhel @@ -22,5 +22,5 @@ RUN PACKAGES="git gzip util-linux" && \ LABEL io.k8s.display-name="OpenShift End-to-End Tests" \ io.openshift.release.operator=true \ io.k8s.description="OpenShift is a platform for developing, building, and deploying containerized applications." \ - io.openshift.build.versions="kubernetes-tests=1.31.12" \ + io.openshift.build.versions="kubernetes-tests=1.31.14" \ io.openshift.tags="openshift,tests,e2e" diff --git a/test/extended/util/image/zz_generated.txt b/test/extended/util/image/zz_generated.txt index 60bbf949459b..e49e465c0807 100644 --- a/test/extended/util/image/zz_generated.txt +++ b/test/extended/util/image/zz_generated.txt @@ -6,7 +6,7 @@ quay.io/openshifttest/multicast:1.1 quay.io/openshift/community-e2e-images:e2e-q quay.io/redhat-developer/nfs-server:1.1 quay.io/openshift/community-e2e-images:e2e-quay-io-redhat-developer-nfs-server-1-1-dlXGfzrk5aNo8EjC quay.io/redhat-developer/test-build-roots2i:1.2 quay.io/openshift/community-e2e-images:e2e-quay-io-redhat-developer-test-build-roots2i-1-2-gLJ7WcnS2TSllJ32 quay.io/redhat-developer/test-build-simples2i:1.2 quay.io/openshift/community-e2e-images:e2e-quay-io-redhat-developer-test-build-simples2i-1-2-thirLMR-JKplfkmE -registry.k8s.io/build-image/distroless-iptables:v0.6.12 quay.io/openshift/community-e2e-images:e2e-10-registry-k8s-io-build-image-distroless-iptables-v0-6-12-y1U6BasHO2iyXXl9 +registry.k8s.io/build-image/distroless-iptables:v0.7.11 quay.io/openshift/community-e2e-images:e2e-10-registry-k8s-io-build-image-distroless-iptables-v0-7-11-71lH0kZrOPDMzxPB registry.k8s.io/cloud-provider-gcp/gcp-compute-persistent-disk-csi-driver:v1.2.2 quay.io/openshift/community-e2e-images:e2e-50-registry-k8s-io-cloud-provider-gcp-gcp-compute-persistent-disk-csi-driver-v1-2-2-fk3Ddr8np00iPF9c registry.k8s.io/cloud-provider-gcp/gcp-compute-persistent-disk-csi-driver:v1.4.0 quay.io/openshift/community-e2e-images:e2e-48-registry-k8s-io-cloud-provider-gcp-gcp-compute-persistent-disk-csi-driver-v1-4-0-mUHHjVVuv0UQiTyf registry.k8s.io/e2e-test-images/agnhost:2.52 quay.io/openshift/community-e2e-images:e2e-1-registry-k8s-io-e2e-test-images-agnhost-2-52-vo_U710PrYLetnfE diff --git a/vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go b/vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go index 1b549610aa70..e698c0c08d8c 100644 --- a/vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go +++ b/vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/customresource_handler.go @@ -69,8 +69,10 @@ import ( "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/apiserver/pkg/endpoints/metrics" apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/generic" genericfilters "k8s.io/apiserver/pkg/server/filters" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/pkg/util/webhook" "k8s.io/apiserver/pkg/warning" "k8s.io/client-go/scale" @@ -848,6 +850,7 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd clusterScoped := crd.Spec.Scope == apiextensionsv1.ClusterScoped // CRDs explicitly do not support protobuf, but some objects returned by the API server do + streamingCollections := utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) negotiatedSerializer := unstructuredNegotiatedSerializer{ typer: typer, creator: creator, @@ -861,10 +864,11 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd MediaTypeType: "application", MediaTypeSubType: "json", EncodesAsText: true, - Serializer: json.NewSerializer(json.DefaultMetaFactory, creator, typer, false), - PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, creator, typer, true), + Serializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{StreamingCollectionsEncoding: streamingCollections}), + PrettySerializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{Pretty: true}), StrictSerializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{ - Strict: true, + Strict: true, + StreamingCollectionsEncoding: streamingCollections, }), StreamSerializer: &runtime.StreamSerializerInfo{ EncodesAsText: true, @@ -887,7 +891,9 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd MediaType: "application/vnd.kubernetes.protobuf", MediaTypeType: "application", MediaTypeSubType: "vnd.kubernetes.protobuf", - Serializer: protobuf.NewSerializer(creator, typer), + Serializer: protobuf.NewSerializerWithOptions(creator, typer, protobuf.SerializerOptions{ + StreamingCollectionsEncoding: utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf), + }), StreamSerializer: &runtime.StreamSerializerInfo{ Serializer: protobuf.NewRawSerializer(creator, typer), Framer: protobuf.LengthDelimitedFramer, @@ -958,7 +964,14 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd scaleScope := *requestScopes[v.Name] scaleConverter := scale.NewScaleConverter() scaleScope.Subresource = "scale" - scaleScope.Serializer = serializer.NewCodecFactory(scaleConverter.Scheme()) + var opts []serializer.CodecFactoryOptionsMutator + if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) { + opts = append(opts, serializer.WithStreamingCollectionEncodingToJSON()) + } + if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf) { + opts = append(opts, serializer.WithStreamingCollectionEncodingToProtobuf()) + } + scaleScope.Serializer = serializer.NewCodecFactory(scaleConverter.Scheme(), opts...) scaleScope.Kind = autoscalingv1.SchemeGroupVersion.WithKind("Scale") scaleScope.Namer = handlers.ContextBasedNaming{ Namer: meta.NewAccessor(), diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/help.go b/vendor/k8s.io/apimachinery/pkg/api/meta/help.go index 1fdd32c4ba3e..468afd0e9ee0 100644 --- a/vendor/k8s.io/apimachinery/pkg/api/meta/help.go +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/help.go @@ -221,6 +221,9 @@ func extractList(obj runtime.Object, allocNew bool) ([]runtime.Object, error) { if err != nil { return nil, err } + if items.IsNil() { + return nil, nil + } list := make([]runtime.Object, items.Len()) if len(list) == 0 { return list, nil diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go index ff9820842046..805e9b68bf3d 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go @@ -52,7 +52,7 @@ type serializerType struct { func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []serializerType { jsonSerializer := json.NewSerializerWithOptions( mf, scheme, scheme, - json.SerializerOptions{Yaml: false, Pretty: false, Strict: options.Strict}, + json.SerializerOptions{Yaml: false, Pretty: false, Strict: options.Strict, StreamingCollectionsEncoding: options.StreamingCollectionsEncodingToJSON}, ) jsonSerializerType := serializerType{ AcceptContentTypes: []string{runtime.ContentTypeJSON}, @@ -73,7 +73,7 @@ func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, option strictJSONSerializer := json.NewSerializerWithOptions( mf, scheme, scheme, - json.SerializerOptions{Yaml: false, Pretty: false, Strict: true}, + json.SerializerOptions{Yaml: false, Pretty: false, Strict: true, StreamingCollectionsEncoding: options.StreamingCollectionsEncodingToJSON}, ) jsonSerializerType.StrictSerializer = strictJSONSerializer @@ -85,7 +85,9 @@ func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, option mf, scheme, scheme, json.SerializerOptions{Yaml: true, Pretty: false, Strict: true}, ) - protoSerializer := protobuf.NewSerializer(scheme, scheme) + protoSerializer := protobuf.NewSerializerWithOptions(scheme, scheme, protobuf.SerializerOptions{ + StreamingCollectionsEncoding: options.StreamingCollectionsEncodingToProtobuf, + }) protoRawSerializer := protobuf.NewRawSerializer(scheme, scheme) serializers := []serializerType{ @@ -136,6 +138,9 @@ type CodecFactoryOptions struct { Strict bool // Pretty includes a pretty serializer along with the non-pretty one Pretty bool + + StreamingCollectionsEncodingToJSON bool + StreamingCollectionsEncodingToProtobuf bool } // CodecFactoryOptionsMutator takes a pointer to an options struct and then modifies it. @@ -162,6 +167,18 @@ func DisableStrict(options *CodecFactoryOptions) { options.Strict = false } +func WithStreamingCollectionEncodingToJSON() CodecFactoryOptionsMutator { + return func(options *CodecFactoryOptions) { + options.StreamingCollectionsEncodingToJSON = true + } +} + +func WithStreamingCollectionEncodingToProtobuf() CodecFactoryOptionsMutator { + return func(options *CodecFactoryOptions) { + options.StreamingCollectionsEncodingToProtobuf = true + } +} + // NewCodecFactory provides methods for retrieving serializers for the supported wire formats // and conversion wrappers to define preferred internal and external versions. In the future, // as the internal version is used less, callers may instead use a defaulting serializer and diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/collections.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/collections.go new file mode 100644 index 000000000000..63b4e5ccb5f5 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/collections.go @@ -0,0 +1,231 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package json + +import ( + "encoding/json" + "fmt" + "io" + "sort" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/conversion" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" +) + +func streamEncodeCollections(obj runtime.Object, w io.Writer) (bool, error) { + list, ok := obj.(*unstructured.UnstructuredList) + if ok { + return true, streamingEncodeUnstructuredList(w, list) + } + if _, ok := obj.(json.Marshaler); ok { + return false, nil + } + typeMeta, listMeta, items, err := getListMeta(obj) + if err == nil { + return true, streamingEncodeList(w, typeMeta, listMeta, items) + } + return false, nil +} + +// getListMeta implements list extraction logic for json stream serialization. +// +// Reason for a custom logic instead of reusing accessors from meta package: +// * Validate json tags to prevent incompatibility with json standard package. +// * ListMetaAccessor doesn't distinguish empty from nil value. +// * TypeAccessort reparsing "apiVersion" and serializing it with "{group}/{version}" +func getListMeta(list runtime.Object) (metav1.TypeMeta, metav1.ListMeta, []runtime.Object, error) { + listValue, err := conversion.EnforcePtr(list) + if err != nil { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, err + } + listType := listValue.Type() + if listType.NumField() != 3 { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, fmt.Errorf("expected ListType to have 3 fields") + } + // TypeMeta + typeMeta, ok := listValue.Field(0).Interface().(metav1.TypeMeta) + if !ok { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, fmt.Errorf("expected TypeMeta field to have TypeMeta type") + } + if listType.Field(0).Tag.Get("json") != ",inline" { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, fmt.Errorf(`expected TypeMeta json field tag to be ",inline"`) + } + // ListMeta + listMeta, ok := listValue.Field(1).Interface().(metav1.ListMeta) + if !ok { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, fmt.Errorf("expected ListMeta field to have ListMeta type") + } + if listType.Field(1).Tag.Get("json") != "metadata,omitempty" { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, fmt.Errorf(`expected ListMeta json field tag to be "metadata,omitempty"`) + } + // Items + items, err := meta.ExtractList(list) + if err != nil { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, err + } + if listType.Field(2).Tag.Get("json") != "items" { + return metav1.TypeMeta{}, metav1.ListMeta{}, nil, fmt.Errorf(`expected Items json field tag to be "items"`) + } + return typeMeta, listMeta, items, nil +} + +func streamingEncodeList(w io.Writer, typeMeta metav1.TypeMeta, listMeta metav1.ListMeta, items []runtime.Object) error { + // Start + if _, err := w.Write([]byte(`{`)); err != nil { + return err + } + + // TypeMeta + if typeMeta.Kind != "" { + if err := encodeKeyValuePair(w, "kind", typeMeta.Kind, []byte(",")); err != nil { + return err + } + } + if typeMeta.APIVersion != "" { + if err := encodeKeyValuePair(w, "apiVersion", typeMeta.APIVersion, []byte(",")); err != nil { + return err + } + } + + // ListMeta + if err := encodeKeyValuePair(w, "metadata", listMeta, []byte(",")); err != nil { + return err + } + + // Items + if err := encodeItemsObjectSlice(w, items); err != nil { + return err + } + + // End + _, err := w.Write([]byte("}\n")) + return err +} + +func encodeItemsObjectSlice(w io.Writer, items []runtime.Object) (err error) { + if items == nil { + err := encodeKeyValuePair(w, "items", nil, nil) + return err + } + _, err = w.Write([]byte(`"items":[`)) + if err != nil { + return err + } + suffix := []byte(",") + for i, item := range items { + if i == len(items)-1 { + suffix = nil + } + err := encodeValue(w, item, suffix) + if err != nil { + return err + } + } + _, err = w.Write([]byte("]")) + if err != nil { + return err + } + return err +} + +func streamingEncodeUnstructuredList(w io.Writer, list *unstructured.UnstructuredList) error { + _, err := w.Write([]byte(`{`)) + if err != nil { + return err + } + keys := make([]string, 0, len(list.Object)) + for k := range list.Object { + keys = append(keys, k) + } + if _, exists := list.Object["items"]; !exists { + keys = append(keys, "items") + } + sort.Strings(keys) + + suffix := []byte(",") + for i, key := range keys { + if i == len(keys)-1 { + suffix = nil + } + if key == "items" { + err = encodeItemsUnstructuredSlice(w, list.Items, suffix) + } else { + err = encodeKeyValuePair(w, key, list.Object[key], suffix) + } + if err != nil { + return err + } + } + _, err = w.Write([]byte("}\n")) + return err +} + +func encodeItemsUnstructuredSlice(w io.Writer, items []unstructured.Unstructured, suffix []byte) (err error) { + _, err = w.Write([]byte(`"items":[`)) + if err != nil { + return err + } + comma := []byte(",") + for i, item := range items { + if i == len(items)-1 { + comma = nil + } + err := encodeValue(w, item.Object, comma) + if err != nil { + return err + } + } + _, err = w.Write([]byte("]")) + if err != nil { + return err + } + if len(suffix) > 0 { + _, err = w.Write(suffix) + } + return err +} + +func encodeKeyValuePair(w io.Writer, key string, value any, suffix []byte) (err error) { + err = encodeValue(w, key, []byte(":")) + if err != nil { + return err + } + err = encodeValue(w, value, suffix) + if err != nil { + return err + } + return err +} + +func encodeValue(w io.Writer, value any, suffix []byte) error { + data, err := json.Marshal(value) + if err != nil { + return err + } + _, err = w.Write(data) + if err != nil { + return err + } + if len(suffix) > 0 { + _, err = w.Write(suffix) + } + return err +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go index 1ae4a32eb720..24f66a10174b 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go @@ -36,7 +36,7 @@ import ( // is not nil, the object has the group, version, and kind fields set. // Deprecated: use NewSerializerWithOptions instead. func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, pretty bool) *Serializer { - return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{false, pretty, false}) + return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{false, pretty, false, false}) } // NewYAMLSerializer creates a YAML serializer that handles encoding versioned objects into the proper YAML form. If typer @@ -44,7 +44,7 @@ func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtim // matches JSON, and will error if constructs are used that do not serialize to JSON. // Deprecated: use NewSerializerWithOptions instead. func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer { - return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{true, false, false}) + return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{true, false, false, false}) } // NewSerializerWithOptions creates a JSON/YAML serializer that handles encoding versioned objects into the proper JSON/YAML @@ -93,6 +93,9 @@ type SerializerOptions struct { // Strict: configures the Serializer to return strictDecodingError's when duplicate fields are present decoding JSON or YAML. // Note that enabling this option is not as performant as the non-strict variant, and should not be used in fast paths. Strict bool + + // StreamingCollectionsEncoding enables encoding collection, one item at the time, drastically reducing memory needed. + StreamingCollectionsEncoding bool } // Serializer handles encoding versioned objects into the proper JSON form @@ -242,6 +245,15 @@ func (s *Serializer) doEncode(obj runtime.Object, w io.Writer) error { _, err = w.Write(data) return err } + if s.options.StreamingCollectionsEncoding { + ok, err := streamEncodeCollections(obj, w) + if err != nil { + return err + } + if ok { + return nil + } + } encoder := json.NewEncoder(w) return encoder.Encode(obj) } diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/collections.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/collections.go new file mode 100644 index 000000000000..754a80820b06 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/collections.go @@ -0,0 +1,174 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package protobuf + +import ( + "errors" + "io" + "math/bits" + + "github.com/gogo/protobuf/proto" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" +) + +var ( + errFieldCount = errors.New("expected ListType to have 3 fields") + errTypeMetaField = errors.New("expected TypeMeta field to have TypeMeta type") + errTypeMetaProtobufTag = errors.New(`expected TypeMeta protobuf field tag to be ""`) + errListMetaField = errors.New("expected ListMeta field to have ListMeta type") + errListMetaProtobufTag = errors.New(`expected ListMeta protobuf field tag to be "bytes,1,opt,name=metadata"`) + errItemsProtobufTag = errors.New(`expected Items protobuf field tag to be "bytes,2,rep,name=items"`) + errItemsSizer = errors.New(`expected Items elements to implement proto.Sizer`) +) + +// getStreamingListData implements list extraction logic for protobuf stream serialization. +// +// Reason for a custom logic instead of reusing accessors from meta package: +// * Validate proto tags to prevent incompatibility with proto standard package. +// * ListMetaAccessor doesn't distinguish empty from nil value. +// * TypeAccessor reparsing "apiVersion" and serializing it with "{group}/{version}" +func getStreamingListData(list runtime.Object) (data streamingListData, err error) { + listValue, err := conversion.EnforcePtr(list) + if err != nil { + return data, err + } + listType := listValue.Type() + if listType.NumField() != 3 { + return data, errFieldCount + } + // TypeMeta: validated, but not returned as is not serialized. + _, ok := listValue.Field(0).Interface().(metav1.TypeMeta) + if !ok { + return data, errTypeMetaField + } + if listType.Field(0).Tag.Get("protobuf") != "" { + return data, errTypeMetaProtobufTag + } + // ListMeta + listMeta, ok := listValue.Field(1).Interface().(metav1.ListMeta) + if !ok { + return data, errListMetaField + } + // if we were ever to relax the protobuf tag check we should update the hardcoded `0xa` below when writing ListMeta. + if listType.Field(1).Tag.Get("protobuf") != "bytes,1,opt,name=metadata" { + return data, errListMetaProtobufTag + } + data.listMeta = listMeta + // Items; if we were ever to relax the protobuf tag check we should update the hardcoded `0x12` below when writing Items. + if listType.Field(2).Tag.Get("protobuf") != "bytes,2,rep,name=items" { + return data, errItemsProtobufTag + } + items, err := meta.ExtractList(list) + if err != nil { + return data, err + } + data.items = items + data.totalSize, data.listMetaSize, data.itemsSizes, err = listSize(listMeta, items) + return data, err +} + +type streamingListData struct { + // totalSize is the total size of the serialized List object, including their proto headers/size bytes + totalSize int + + // listMetaSize caches results from .Size() call to listMeta, doesn't include header bytes (field identifier, size) + listMetaSize int + listMeta metav1.ListMeta + + // itemsSizes caches results from .Size() call to items, doesn't include header bytes (field identifier, size) + itemsSizes []int + items []runtime.Object +} + +// listSize return size of ListMeta and items to be later used for preallocations. +// listMetaSize and itemSizes do not include header bytes (field identifier, size). +func listSize(listMeta metav1.ListMeta, items []runtime.Object) (totalSize, listMetaSize int, itemSizes []int, err error) { + // ListMeta + listMetaSize = listMeta.Size() + totalSize += 1 + sovGenerated(uint64(listMetaSize)) + listMetaSize + // Items + itemSizes = make([]int, len(items)) + for i, item := range items { + sizer, ok := item.(proto.Sizer) + if !ok { + return totalSize, listMetaSize, nil, errItemsSizer + } + n := sizer.Size() + itemSizes[i] = n + totalSize += 1 + sovGenerated(uint64(n)) + n + } + return totalSize, listMetaSize, itemSizes, nil +} + +func streamingEncodeUnknownList(w io.Writer, unk runtime.Unknown, listData streamingListData, memAlloc runtime.MemoryAllocator) error { + _, err := w.Write(protoEncodingPrefix) + if err != nil { + return err + } + // encodeList is responsible for encoding the List into the unknown Raw. + encodeList := func(writer io.Writer) (int, error) { + return streamingEncodeList(writer, listData, memAlloc) + } + _, err = unk.MarshalToWriter(w, listData.totalSize, encodeList) + return err +} + +func streamingEncodeList(w io.Writer, listData streamingListData, memAlloc runtime.MemoryAllocator) (size int, err error) { + // ListMeta; 0xa = (1 << 3) | 2; field number: 1, type: 2 (LEN). https://protobuf.dev/programming-guides/encoding/#structure + n, err := doEncodeWithHeader(&listData.listMeta, w, 0xa, listData.listMetaSize, memAlloc) + size += n + if err != nil { + return size, err + } + // Items; 0x12 = (2 << 3) | 2; field number: 2, type: 2 (LEN). https://protobuf.dev/programming-guides/encoding/#structure + for i, item := range listData.items { + n, err := doEncodeWithHeader(item, w, 0x12, listData.itemsSizes[i], memAlloc) + size += n + if err != nil { + return size, err + } + } + return size, nil +} + +func writeVarintGenerated(w io.Writer, v int) (int, error) { + buf := make([]byte, sovGenerated(uint64(v))) + encodeVarintGenerated(buf, len(buf), uint64(v)) + return w.Write(buf) +} + +// sovGenerated is copied from `generated.pb.go` returns size of varint. +func sovGenerated(v uint64) int { + return (bits.Len64(v|1) + 6) / 7 +} + +// encodeVarintGenerated is copied from `generated.pb.go` encodes varint. +func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { + offset -= sovGenerated(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go index c63e6dc63f6b..c66c49ac4c2d 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go @@ -72,10 +72,18 @@ func IsNotMarshalable(err error) bool { // is passed, the encoded object will have group, version, and kind fields set. If typer is nil, the objects will be written // as-is (any type info passed with the object will be used). func NewSerializer(creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer { + return NewSerializerWithOptions(creater, typer, SerializerOptions{}) +} + +// NewSerializerWithOptions creates a Protobuf serializer that handles encoding versioned objects into the proper wire form. If a typer +// is passed, the encoded object will have group, version, and kind fields set. If typer is nil, the objects will be written +// as-is (any type info passed with the object will be used). +func NewSerializerWithOptions(creater runtime.ObjectCreater, typer runtime.ObjectTyper, opts SerializerOptions) *Serializer { return &Serializer{ prefix: protoEncodingPrefix, creater: creater, typer: typer, + options: opts, } } @@ -84,6 +92,14 @@ type Serializer struct { prefix []byte creater runtime.ObjectCreater typer runtime.ObjectTyper + + options SerializerOptions +} + +// SerializerOptions holds the options which are used to configure a Proto serializer. +type SerializerOptions struct { + // StreamingCollectionsEncoding enables encoding collection, one item at the time, drastically reducing memory needed. + StreamingCollectionsEncoding bool } var _ runtime.Serializer = &Serializer{} @@ -209,6 +225,13 @@ func (s *Serializer) doEncode(obj runtime.Object, w io.Writer, memAlloc runtime. }, } } + if s.options.StreamingCollectionsEncoding { + listData, err := getStreamingListData(obj) + if err == nil { + // Doesn't honor custom proto marshaling methods (like json streaming), because all proto objects implement proto methods. + return streamingEncodeUnknownList(w, unk, listData, memAlloc) + } + } switch t := obj.(type) { case bufferedMarshaller: @@ -428,6 +451,39 @@ func (s *RawSerializer) encode(obj runtime.Object, w io.Writer, memAlloc runtime } func (s *RawSerializer) doEncode(obj runtime.Object, w io.Writer, memAlloc runtime.MemoryAllocator) error { + _, err := doEncode(obj, w, nil, memAlloc) + return err +} + +func doEncodeWithHeader(obj any, w io.Writer, field byte, precomputedSize int, memAlloc runtime.MemoryAllocator) (size int, err error) { + // Field identifier + n, err := w.Write([]byte{field}) + size += n + if err != nil { + return size, err + } + // Size + n, err = writeVarintGenerated(w, precomputedSize) + size += n + if err != nil { + return size, err + } + // Obj + n, err = doEncode(obj, w, &precomputedSize, memAlloc) + size += n + if err != nil { + return size, err + } + if n != precomputedSize { + return size, fmt.Errorf("the size value was %d, but doEncode wrote %d bytes to data", precomputedSize, n) + } + return size, nil +} + +// doEncode encodes provided object into writer using a allocator if possible. +// Avoids call by object Size if precomputedObjSize is provided. +// precomputedObjSize should not include header bytes (field identifier, size). +func doEncode(obj any, w io.Writer, precomputedObjSize *int, memAlloc runtime.MemoryAllocator) (int, error) { if memAlloc == nil { klog.Error("a mandatory memory allocator wasn't provided, this might have a negative impact on performance, check invocations of EncodeWithAllocator method, falling back on runtime.SimpleAllocator") memAlloc = &runtime.SimpleAllocator{} @@ -436,40 +492,43 @@ func (s *RawSerializer) doEncode(obj runtime.Object, w io.Writer, memAlloc runti case bufferedReverseMarshaller: // this path performs a single allocation during write only when the Allocator wasn't provided // it also requires the caller to implement the more efficient Size and MarshalToSizedBuffer methods - encodedSize := uint64(t.Size()) - data := memAlloc.Allocate(encodedSize) + if precomputedObjSize == nil { + s := t.Size() + precomputedObjSize = &s + } + data := memAlloc.Allocate(uint64(*precomputedObjSize)) n, err := t.MarshalToSizedBuffer(data) if err != nil { - return err + return 0, err } - _, err = w.Write(data[:n]) - return err + return w.Write(data[:n]) case bufferedMarshaller: // this path performs a single allocation during write only when the Allocator wasn't provided // it also requires the caller to implement the more efficient Size and MarshalTo methods - encodedSize := uint64(t.Size()) - data := memAlloc.Allocate(encodedSize) + if precomputedObjSize == nil { + s := t.Size() + precomputedObjSize = &s + } + data := memAlloc.Allocate(uint64(*precomputedObjSize)) n, err := t.MarshalTo(data) if err != nil { - return err + return 0, err } - _, err = w.Write(data[:n]) - return err + return w.Write(data[:n]) case proto.Marshaler: // this path performs extra allocations data, err := t.Marshal() if err != nil { - return err + return 0, err } - _, err = w.Write(data) - return err + return w.Write(data) default: - return errNotMarshalable{reflect.TypeOf(obj)} + return 0, errNotMarshalable{reflect.TypeOf(obj)} } } diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go b/vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go index a82227b239af..27a2064c4163 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/types_proto.go @@ -18,6 +18,7 @@ package runtime import ( "fmt" + "io" ) type ProtobufMarshaller interface { @@ -28,6 +29,124 @@ type ProtobufReverseMarshaller interface { MarshalToSizedBuffer(data []byte) (int, error) } +const ( + typeMetaTag = 0xa + rawTag = 0x12 + contentEncodingTag = 0x1a + contentTypeTag = 0x22 + + // max length of a varint for a uint64 + maxUint64VarIntLength = 10 +) + +// MarshalToWriter allows a caller to provide a streaming writer for raw bytes, +// instead of populating them inside the Unknown struct. +// rawSize is the number of bytes rawWriter will write in a success case. +// writeRaw is called when it is time to write the raw bytes. It must return `rawSize, nil` or an error. +func (m *Unknown) MarshalToWriter(w io.Writer, rawSize int, writeRaw func(io.Writer) (int, error)) (int, error) { + size := 0 + + // reuse the buffer for varint marshaling + varintBuffer := make([]byte, maxUint64VarIntLength) + writeVarint := func(i int) (int, error) { + offset := encodeVarintGenerated(varintBuffer, len(varintBuffer), uint64(i)) + return w.Write(varintBuffer[offset:]) + } + + // TypeMeta + { + n, err := w.Write([]byte{typeMetaTag}) + size += n + if err != nil { + return size, err + } + + typeMetaBytes, err := m.TypeMeta.Marshal() + if err != nil { + return size, err + } + + n, err = writeVarint(len(typeMetaBytes)) + size += n + if err != nil { + return size, err + } + + n, err = w.Write(typeMetaBytes) + size += n + if err != nil { + return size, err + } + } + + // Raw, delegating write to writeRaw() + { + n, err := w.Write([]byte{rawTag}) + size += n + if err != nil { + return size, err + } + + n, err = writeVarint(rawSize) + size += n + if err != nil { + return size, err + } + + n, err = writeRaw(w) + size += n + if err != nil { + return size, err + } + if n != int(rawSize) { + return size, fmt.Errorf("the size value was %d, but encoding wrote %d bytes to data", rawSize, n) + } + } + + // ContentEncoding + { + n, err := w.Write([]byte{contentEncodingTag}) + size += n + if err != nil { + return size, err + } + + n, err = writeVarint(len(m.ContentEncoding)) + size += n + if err != nil { + return size, err + } + + n, err = w.Write([]byte(m.ContentEncoding)) + size += n + if err != nil { + return size, err + } + } + + // ContentEncoding + { + n, err := w.Write([]byte{contentTypeTag}) + size += n + if err != nil { + return size, err + } + + n, err = writeVarint(len(m.ContentType)) + size += n + if err != nil { + return size, err + } + + n, err = w.Write([]byte(m.ContentType)) + size += n + if err != nil { + return size, err + } + } + return size, nil +} + // NestedMarshalTo allows a caller to avoid extra allocations during serialization of an Unknown // that will contain an object that implements ProtobufMarshaller or ProtobufReverseMarshaller. func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64) (int, error) { @@ -43,12 +162,12 @@ func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64 copy(data[i:], m.ContentType) i = encodeVarintGenerated(data, i, uint64(len(m.ContentType))) i-- - data[i] = 0x22 + data[i] = contentTypeTag i -= len(m.ContentEncoding) copy(data[i:], m.ContentEncoding) i = encodeVarintGenerated(data, i, uint64(len(m.ContentEncoding))) i-- - data[i] = 0x1a + data[i] = contentEncodingTag if b != nil { if r, ok := b.(ProtobufReverseMarshaller); ok { n1, err := r.MarshalToSizedBuffer(data[:i]) @@ -75,7 +194,7 @@ func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64 } i = encodeVarintGenerated(data, i, size) i-- - data[i] = 0x12 + data[i] = rawTag } n2, err := m.TypeMeta.MarshalToSizedBuffer(data[:i]) if err != nil { @@ -84,6 +203,6 @@ func (m *Unknown) NestedMarshalTo(data []byte, b ProtobufMarshaller, size uint64 i -= n2 i = encodeVarintGenerated(data, i, uint64(n2)) i-- - data[i] = 0xa + data[i] = typeMetaTag return msgSize - i, nil } diff --git a/vendor/k8s.io/apiserver/pkg/admission/audit.go b/vendor/k8s.io/apiserver/pkg/admission/audit.go index 7c0993f0908f..f9f90cd02475 100644 --- a/vendor/k8s.io/apiserver/pkg/admission/audit.go +++ b/vendor/k8s.io/apiserver/pkg/admission/audit.go @@ -83,7 +83,7 @@ func ensureAnnotationGetter(a Attributes) error { } func (handler *auditHandler) logAnnotations(ctx context.Context, a Attributes) { - ae := audit.AuditEventFrom(ctx) + ae := audit.AuditContextFrom(ctx) if ae == nil { return } @@ -91,9 +91,9 @@ func (handler *auditHandler) logAnnotations(ctx context.Context, a Attributes) { var annotations map[string]string switch a := a.(type) { case privateAnnotationsGetter: - annotations = a.getAnnotations(ae.Level) + annotations = a.getAnnotations(ae.GetEventLevel()) case AnnotationsGetter: - annotations = a.GetAnnotations(ae.Level) + annotations = a.GetAnnotations(ae.GetEventLevel()) default: // this will never happen, because we have already checked it in ensureAnnotationGetter } diff --git a/vendor/k8s.io/apiserver/pkg/audit/context.go b/vendor/k8s.io/apiserver/pkg/audit/context.go index 9648587378ec..5b93d594bffa 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/context.go +++ b/vendor/k8s.io/apiserver/pkg/audit/context.go @@ -18,10 +18,18 @@ package audit import ( "context" + "errors" + "maps" "sync" + "sync/atomic" + "time" + authnv1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" auditinternal "k8s.io/apiserver/pkg/apis/audit" + "k8s.io/apiserver/pkg/authentication/user" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/klog/v2" ) @@ -35,22 +43,223 @@ const auditKey key = iota // AuditContext holds the information for constructing the audit events for the current request. type AuditContext struct { - // RequestAuditConfig is the audit configuration that applies to the request - RequestAuditConfig RequestAuditConfig - - // Event is the audit Event object that is being captured to be written in + // initialized indicates whether requestAuditConfig and sink have been populated and are safe to read unguarded. + // This should only be set via Init(). + initialized atomic.Bool + // requestAuditConfig is the audit configuration that applies to the request. + // This should only be written via Init(RequestAuditConfig, Sink), and only read when initialized.Load() is true. + requestAuditConfig RequestAuditConfig + // sink is the sink to use when processing event stages. + // This should only be written via Init(RequestAuditConfig, Sink), and only read when initialized.Load() is true. + sink Sink + + // lock guards event + lock sync.Mutex + + // event is the audit Event object that is being captured to be written in // the API audit log. - Event auditinternal.Event + event auditinternal.Event - // annotationMutex guards event.Annotations - annotationMutex sync.Mutex + // unguarded copy of auditID from the event + auditID atomic.Value } // Enabled checks whether auditing is enabled for this audit context. func (ac *AuditContext) Enabled() bool { - // Note: An unset Level should be considered Enabled, so that request data (e.g. annotations) - // can still be captured before the audit policy is evaluated. - return ac != nil && ac.RequestAuditConfig.Level != auditinternal.LevelNone + if ac == nil { + // protect against nil pointers + return false + } + if !ac.initialized.Load() { + // Note: An unset Level should be considered Enabled, so that request data (e.g. annotations) + // can still be captured before the audit policy is evaluated. + return true + } + return ac.requestAuditConfig.Level != auditinternal.LevelNone +} + +func (ac *AuditContext) Init(requestAuditConfig RequestAuditConfig, sink Sink) error { + ac.lock.Lock() + defer ac.lock.Unlock() + if ac.initialized.Load() { + return errors.New("audit context was already initialized") + } + ac.requestAuditConfig = requestAuditConfig + ac.sink = sink + ac.event.Level = requestAuditConfig.Level + ac.initialized.Store(true) + return nil +} + +func (ac *AuditContext) AuditID() types.UID { + // return the unguarded copy of the auditID + id, _ := ac.auditID.Load().(types.UID) + return id +} + +func (ac *AuditContext) visitEvent(f func(event *auditinternal.Event)) { + ac.lock.Lock() + defer ac.lock.Unlock() + f(&ac.event) +} + +// ProcessEventStage returns true on success, false if there was an error processing the stage. +func (ac *AuditContext) ProcessEventStage(ctx context.Context, stage auditinternal.Stage) bool { + if ac == nil || !ac.initialized.Load() { + return true + } + if ac.sink == nil { + return true + } + for _, omitStage := range ac.requestAuditConfig.OmitStages { + if stage == omitStage { + return true + } + } + + processed := false + ac.visitEvent(func(event *auditinternal.Event) { + event.Stage = stage + if stage == auditinternal.StageRequestReceived { + event.StageTimestamp = event.RequestReceivedTimestamp + } else { + event.StageTimestamp = metav1.NewMicroTime(time.Now()) + } + + ObserveEvent(ctx) + processed = ac.sink.ProcessEvents(event) + }) + return processed +} + +func (ac *AuditContext) LogImpersonatedUser(user user.Info) { + ac.visitEvent(func(ev *auditinternal.Event) { + if ev == nil || ev.Level.Less(auditinternal.LevelMetadata) { + return + } + ev.ImpersonatedUser = &authnv1.UserInfo{ + Username: user.GetName(), + } + ev.ImpersonatedUser.Groups = user.GetGroups() + ev.ImpersonatedUser.UID = user.GetUID() + ev.ImpersonatedUser.Extra = map[string]authnv1.ExtraValue{} + for k, v := range user.GetExtra() { + ev.ImpersonatedUser.Extra[k] = authnv1.ExtraValue(v) + } + }) +} + +func (ac *AuditContext) LogResponseObject(status *metav1.Status, obj *runtime.Unknown) { + ac.visitEvent(func(ae *auditinternal.Event) { + if status != nil { + // selectively copy the bounded fields. + ae.ResponseStatus = &metav1.Status{ + Status: status.Status, + Message: status.Message, + Reason: status.Reason, + Details: status.Details, + Code: status.Code, + } + } + if ae.Level.Less(auditinternal.LevelRequestResponse) { + return + } + ae.ResponseObject = obj + }) +} + +// LogRequestPatch fills in the given patch as the request object into an audit event. +func (ac *AuditContext) LogRequestPatch(patch []byte) { + ac.visitEvent(func(ae *auditinternal.Event) { + ae.RequestObject = &runtime.Unknown{ + Raw: patch, + ContentType: runtime.ContentTypeJSON, + } + }) +} + +func (ac *AuditContext) GetEventAnnotation(key string) (string, bool) { + var val string + var ok bool + ac.visitEvent(func(event *auditinternal.Event) { + val, ok = event.Annotations[key] + }) + return val, ok +} + +func (ac *AuditContext) GetEventLevel() auditinternal.Level { + var level auditinternal.Level + ac.visitEvent(func(event *auditinternal.Event) { + level = event.Level + }) + return level +} + +func (ac *AuditContext) SetEventStage(stage auditinternal.Stage) { + ac.visitEvent(func(event *auditinternal.Event) { + event.Stage = stage + }) +} + +func (ac *AuditContext) GetEventStage() auditinternal.Stage { + var stage auditinternal.Stage + ac.visitEvent(func(event *auditinternal.Event) { + stage = event.Stage + }) + return stage +} + +func (ac *AuditContext) SetEventStageTimestamp(timestamp metav1.MicroTime) { + ac.visitEvent(func(event *auditinternal.Event) { + event.StageTimestamp = timestamp + }) +} + +func (ac *AuditContext) GetEventResponseStatus() *metav1.Status { + var status *metav1.Status + ac.visitEvent(func(event *auditinternal.Event) { + status = event.ResponseStatus + }) + return status +} + +func (ac *AuditContext) GetEventRequestReceivedTimestamp() metav1.MicroTime { + var timestamp metav1.MicroTime + ac.visitEvent(func(event *auditinternal.Event) { + timestamp = event.RequestReceivedTimestamp + }) + return timestamp +} + +func (ac *AuditContext) GetEventStageTimestamp() metav1.MicroTime { + var timestamp metav1.MicroTime + ac.visitEvent(func(event *auditinternal.Event) { + timestamp = event.StageTimestamp + }) + return timestamp +} + +func (ac *AuditContext) SetEventResponseStatus(status *metav1.Status) { + ac.visitEvent(func(event *auditinternal.Event) { + event.ResponseStatus = status + }) +} + +func (ac *AuditContext) SetEventResponseStatusCode(statusCode int32) { + ac.visitEvent(func(event *auditinternal.Event) { + if event.ResponseStatus == nil { + event.ResponseStatus = &metav1.Status{} + } + event.ResponseStatus.Code = statusCode + }) +} + +func (ac *AuditContext) GetEventAnnotations() map[string]string { + var annotations map[string]string + ac.visitEvent(func(event *auditinternal.Event) { + annotations = maps.Clone(event.Annotations) + }) + return annotations } // AddAuditAnnotation sets the audit annotation for the given key, value pair. @@ -66,8 +275,8 @@ func AddAuditAnnotation(ctx context.Context, key, value string) { return } - ac.annotationMutex.Lock() - defer ac.annotationMutex.Unlock() + ac.lock.Lock() + defer ac.lock.Unlock() addAuditAnnotationLocked(ac, key, value) } @@ -81,8 +290,8 @@ func AddAuditAnnotations(ctx context.Context, keysAndValues ...string) { return } - ac.annotationMutex.Lock() - defer ac.annotationMutex.Unlock() + ac.lock.Lock() + defer ac.lock.Unlock() if len(keysAndValues)%2 != 0 { klog.Errorf("Dropping mismatched audit annotation %q", keysAndValues[len(keysAndValues)-1]) @@ -100,8 +309,8 @@ func AddAuditAnnotationsMap(ctx context.Context, annotations map[string]string) return } - ac.annotationMutex.Lock() - defer ac.annotationMutex.Unlock() + ac.lock.Lock() + defer ac.lock.Unlock() for k, v := range annotations { addAuditAnnotationLocked(ac, k, v) @@ -110,8 +319,7 @@ func AddAuditAnnotationsMap(ctx context.Context, annotations map[string]string) // addAuditAnnotationLocked records the audit annotation on the event. func addAuditAnnotationLocked(ac *AuditContext, key, value string) { - ae := &ac.Event - + ae := &ac.event if ae.Annotations == nil { ae.Annotations = make(map[string]string) } @@ -128,15 +336,11 @@ func WithAuditContext(parent context.Context) context.Context { return parent // Avoid double registering. } - return genericapirequest.WithValue(parent, auditKey, &AuditContext{}) -} - -// AuditEventFrom returns the audit event struct on the ctx -func AuditEventFrom(ctx context.Context) *auditinternal.Event { - if ac := AuditContextFrom(ctx); ac.Enabled() { - return &ac.Event - } - return nil + return genericapirequest.WithValue(parent, auditKey, &AuditContext{ + event: auditinternal.Event{ + Stage: auditinternal.StageResponseStarted, + }, + }) } // AuditContextFrom returns the pair of the audit configuration object @@ -154,7 +358,10 @@ func WithAuditID(ctx context.Context, auditID types.UID) { return } if ac := AuditContextFrom(ctx); ac != nil { - ac.Event.AuditID = auditID + ac.visitEvent(func(event *auditinternal.Event) { + ac.auditID.Store(auditID) + event.AuditID = auditID + }) } } @@ -162,7 +369,8 @@ func WithAuditID(ctx context.Context, auditID types.UID) { // auditing is enabled. func AuditIDFrom(ctx context.Context) (types.UID, bool) { if ac := AuditContextFrom(ctx); ac != nil { - return ac.Event.AuditID, true + id, _ := ac.auditID.Load().(types.UID) + return id, true } return "", false } diff --git a/vendor/k8s.io/apiserver/pkg/audit/request.go b/vendor/k8s.io/apiserver/pkg/audit/request.go index 9185278f06fb..d5f9c730f518 100644 --- a/vendor/k8s.io/apiserver/pkg/audit/request.go +++ b/vendor/k8s.io/apiserver/pkg/audit/request.go @@ -40,110 +40,73 @@ const ( userAgentTruncateSuffix = "...TRUNCATED" ) -func LogRequestMetadata(ctx context.Context, req *http.Request, requestReceivedTimestamp time.Time, level auditinternal.Level, attribs authorizer.Attributes) { +func LogRequestMetadata(ctx context.Context, req *http.Request, requestReceivedTimestamp time.Time, attribs authorizer.Attributes) { ac := AuditContextFrom(ctx) if !ac.Enabled() { return } - ev := &ac.Event - - ev.RequestReceivedTimestamp = metav1.NewMicroTime(requestReceivedTimestamp) - ev.Verb = attribs.GetVerb() - ev.RequestURI = req.URL.RequestURI() - ev.UserAgent = maybeTruncateUserAgent(req) - ev.Level = level - - ips := utilnet.SourceIPs(req) - ev.SourceIPs = make([]string, len(ips)) - for i := range ips { - ev.SourceIPs[i] = ips[i].String() - } - if user := attribs.GetUser(); user != nil { - ev.User.Username = user.GetName() - ev.User.Extra = map[string]authnv1.ExtraValue{} - for k, v := range user.GetExtra() { - ev.User.Extra[k] = authnv1.ExtraValue(v) + ac.visitEvent(func(ev *auditinternal.Event) { + ev.RequestReceivedTimestamp = metav1.NewMicroTime(requestReceivedTimestamp) + ev.Verb = attribs.GetVerb() + ev.RequestURI = req.URL.RequestURI() + ev.UserAgent = maybeTruncateUserAgent(req) + + ips := utilnet.SourceIPs(req) + ev.SourceIPs = make([]string, len(ips)) + for i := range ips { + ev.SourceIPs[i] = ips[i].String() } - ev.User.Groups = user.GetGroups() - ev.User.UID = user.GetUID() - } - if attribs.IsResourceRequest() { - ev.ObjectRef = &auditinternal.ObjectReference{ - Namespace: attribs.GetNamespace(), - Name: attribs.GetName(), - Resource: attribs.GetResource(), - Subresource: attribs.GetSubresource(), - APIGroup: attribs.GetAPIGroup(), - APIVersion: attribs.GetAPIVersion(), + if user := attribs.GetUser(); user != nil { + ev.User.Username = user.GetName() + ev.User.Extra = map[string]authnv1.ExtraValue{} + for k, v := range user.GetExtra() { + ev.User.Extra[k] = authnv1.ExtraValue(v) + } + ev.User.Groups = user.GetGroups() + ev.User.UID = user.GetUID() } - } + + if attribs.IsResourceRequest() { + ev.ObjectRef = &auditinternal.ObjectReference{ + Namespace: attribs.GetNamespace(), + Name: attribs.GetName(), + Resource: attribs.GetResource(), + Subresource: attribs.GetSubresource(), + APIGroup: attribs.GetAPIGroup(), + APIVersion: attribs.GetAPIVersion(), + } + } + }) } // LogImpersonatedUser fills in the impersonated user attributes into an audit event. -func LogImpersonatedUser(ae *auditinternal.Event, user user.Info) { - if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) { +func LogImpersonatedUser(ctx context.Context, user user.Info) { + ac := AuditContextFrom(ctx) + if !ac.Enabled() { return } - ae.ImpersonatedUser = &authnv1.UserInfo{ - Username: user.GetName(), - } - ae.ImpersonatedUser.Groups = user.GetGroups() - ae.ImpersonatedUser.UID = user.GetUID() - ae.ImpersonatedUser.Extra = map[string]authnv1.ExtraValue{} - for k, v := range user.GetExtra() { - ae.ImpersonatedUser.Extra[k] = authnv1.ExtraValue(v) - } + ac.LogImpersonatedUser(user) } // LogRequestObject fills in the request object into an audit event. The passed runtime.Object // will be converted to the given gv. func LogRequestObject(ctx context.Context, obj runtime.Object, objGV schema.GroupVersion, gvr schema.GroupVersionResource, subresource string, s runtime.NegotiatedSerializer) { - ae := AuditEventFrom(ctx) - if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) { + ac := AuditContextFrom(ctx) + if !ac.Enabled() { return } - - // complete ObjectRef - if ae.ObjectRef == nil { - ae.ObjectRef = &auditinternal.ObjectReference{} - } - - // meta.Accessor is more general than ObjectMetaAccessor, but if it fails, we can just skip setting these bits - if meta, err := meta.Accessor(obj); err == nil { - if len(ae.ObjectRef.Namespace) == 0 { - ae.ObjectRef.Namespace = meta.GetNamespace() - } - if len(ae.ObjectRef.Name) == 0 { - ae.ObjectRef.Name = meta.GetName() - } - if len(ae.ObjectRef.UID) == 0 { - ae.ObjectRef.UID = meta.GetUID() - } - if len(ae.ObjectRef.ResourceVersion) == 0 { - ae.ObjectRef.ResourceVersion = meta.GetResourceVersion() - } - } - if len(ae.ObjectRef.APIVersion) == 0 { - ae.ObjectRef.APIGroup = gvr.Group - ae.ObjectRef.APIVersion = gvr.Version - } - if len(ae.ObjectRef.Resource) == 0 { - ae.ObjectRef.Resource = gvr.Resource - } - if len(ae.ObjectRef.Subresource) == 0 { - ae.ObjectRef.Subresource = subresource - } - - if ae.Level.Less(auditinternal.LevelRequest) { + if ac.GetEventLevel().Less(auditinternal.LevelMetadata) { return } - if shouldOmitManagedFields(ctx) { + // meta.Accessor is more general than ObjectMetaAccessor, but if it fails, we can just skip setting these bits + objMeta, _ := meta.Accessor(obj) + if shouldOmitManagedFields(ac) { copy, ok, err := copyWithoutManagedFields(obj) if err != nil { - klog.ErrorS(err, "Error while dropping managed fields from the request", "auditID", ae.AuditID) + klog.ErrorS(err, "Error while dropping managed fields from the request", "auditID", ac.AuditID()) } if ok { obj = copy @@ -151,54 +114,75 @@ func LogRequestObject(ctx context.Context, obj runtime.Object, objGV schema.Grou } // TODO(audit): hook into the serializer to avoid double conversion - var err error - ae.RequestObject, err = encodeObject(obj, objGV, s) + requestObject, err := encodeObject(obj, objGV, s) if err != nil { // TODO(audit): add error slice to audit event struct - klog.ErrorS(err, "Encoding failed of request object", "auditID", ae.AuditID, "gvr", gvr.String(), "obj", obj) + klog.ErrorS(err, "Encoding failed of request object", "auditID", ac.AuditID(), "gvr", gvr.String(), "obj", obj) return } + + ac.visitEvent(func(ae *auditinternal.Event) { + if ae.ObjectRef == nil { + ae.ObjectRef = &auditinternal.ObjectReference{} + } + + if objMeta != nil { + if len(ae.ObjectRef.Namespace) == 0 { + ae.ObjectRef.Namespace = objMeta.GetNamespace() + } + if len(ae.ObjectRef.Name) == 0 { + ae.ObjectRef.Name = objMeta.GetName() + } + if len(ae.ObjectRef.UID) == 0 { + ae.ObjectRef.UID = objMeta.GetUID() + } + if len(ae.ObjectRef.ResourceVersion) == 0 { + ae.ObjectRef.ResourceVersion = objMeta.GetResourceVersion() + } + } + if len(ae.ObjectRef.APIVersion) == 0 { + ae.ObjectRef.APIGroup = gvr.Group + ae.ObjectRef.APIVersion = gvr.Version + } + if len(ae.ObjectRef.Resource) == 0 { + ae.ObjectRef.Resource = gvr.Resource + } + if len(ae.ObjectRef.Subresource) == 0 { + ae.ObjectRef.Subresource = subresource + } + + if ae.Level.Less(auditinternal.LevelRequest) { + return + } + ae.RequestObject = requestObject + }) } // LogRequestPatch fills in the given patch as the request object into an audit event. func LogRequestPatch(ctx context.Context, patch []byte) { - ae := AuditEventFrom(ctx) - if ae == nil || ae.Level.Less(auditinternal.LevelRequest) { + ac := AuditContextFrom(ctx) + if ac.GetEventLevel().Less(auditinternal.LevelRequest) { return } - - ae.RequestObject = &runtime.Unknown{ - Raw: patch, - ContentType: runtime.ContentTypeJSON, - } + ac.LogRequestPatch(patch) } // LogResponseObject fills in the response object into an audit event. The passed runtime.Object // will be converted to the given gv. func LogResponseObject(ctx context.Context, obj runtime.Object, gv schema.GroupVersion, s runtime.NegotiatedSerializer) { - ae := AuditEventFrom(ctx) - if ae == nil || ae.Level.Less(auditinternal.LevelMetadata) { + ac := AuditContextFrom(WithAuditContext(ctx)) + status, _ := obj.(*metav1.Status) + if ac.GetEventLevel().Less(auditinternal.LevelMetadata) { return - } - if status, ok := obj.(*metav1.Status); ok { - // selectively copy the bounded fields. - ae.ResponseStatus = &metav1.Status{ - Status: status.Status, - Message: status.Message, - Reason: status.Reason, - Details: status.Details, - Code: status.Code, - } - } - - if ae.Level.Less(auditinternal.LevelRequestResponse) { + } else if ac.GetEventLevel().Less(auditinternal.LevelRequestResponse) { + ac.LogResponseObject(status, nil) return } - if shouldOmitManagedFields(ctx) { + if shouldOmitManagedFields(ac) { copy, ok, err := copyWithoutManagedFields(obj) if err != nil { - klog.ErrorS(err, "Error while dropping managed fields from the response", "auditID", ae.AuditID) + klog.ErrorS(err, "Error while dropping managed fields from the response", "auditID", ac.AuditID()) } if ok { obj = copy @@ -207,10 +191,11 @@ func LogResponseObject(ctx context.Context, obj runtime.Object, gv schema.GroupV // TODO(audit): hook into the serializer to avoid double conversion var err error - ae.ResponseObject, err = encodeObject(obj, gv, s) + responseObject, err := encodeObject(obj, gv, s) if err != nil { - klog.ErrorS(err, "Encoding failed of response object", "auditID", ae.AuditID, "obj", obj) + klog.ErrorS(err, "Encoding failed of response object", "auditID", ac.AuditID(), "obj", obj) } + ac.LogResponseObject(status, responseObject) } func encodeObject(obj runtime.Object, gv schema.GroupVersion, serializer runtime.NegotiatedSerializer) (*runtime.Unknown, error) { @@ -301,9 +286,9 @@ func removeManagedFields(obj runtime.Object) error { return nil } -func shouldOmitManagedFields(ctx context.Context) bool { - if auditContext := AuditContextFrom(ctx); auditContext != nil { - return auditContext.RequestAuditConfig.OmitManagedFields +func shouldOmitManagedFields(ac *AuditContext) bool { + if ac != nil && ac.initialized.Load() && ac.requestAuditConfig.OmitManagedFields { + return true } // If we can't decide, return false to maintain current behavior which is diff --git a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go index 18167dddc2bf..9d1556e63365 100644 --- a/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go +++ b/vendor/k8s.io/apiserver/pkg/authentication/token/cache/cached_token_authenticator.go @@ -33,7 +33,6 @@ import ( "golang.org/x/sync/singleflight" apierrors "k8s.io/apimachinery/pkg/api/errors" - auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/warning" @@ -199,12 +198,9 @@ func (a *cachedTokenAuthenticator) doAuthenticateToken(ctx context.Context, toke ctx = audit.WithAuditContext(ctx) ac := audit.AuditContextFrom(ctx) - // since this is shared work between multiple requests, we have no way of knowing if any - // particular request supports audit annotations. thus we always attempt to record them. - ac.Event.Level = auditinternal.LevelMetadata record.resp, record.ok, record.err = a.authenticator.AuthenticateToken(ctx, token) - record.annotations = ac.Event.Annotations + record.annotations = ac.GetEventAnnotations() record.warnings = recorder.extractWarnings() if !a.cacheErrs && record.err != nil { diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit.go index 6f850f728bfd..d25bf35ae3af 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/audit.go @@ -44,7 +44,7 @@ func WithAudit(handler http.Handler, sink audit.Sink, policy audit.PolicyRuleEva return handler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ac, err := evaluatePolicyAndCreateAuditEvent(req, policy) + ac, err := evaluatePolicyAndCreateAuditEvent(req, policy, sink) if err != nil { utilruntime.HandleError(fmt.Errorf("failed to create audit event: %v", err)) responsewriters.InternalError(w, req, errors.New("failed to create audit event")) @@ -55,41 +55,37 @@ func WithAudit(handler http.Handler, sink audit.Sink, policy audit.PolicyRuleEva handler.ServeHTTP(w, req) return } - ev := &ac.Event ctx := req.Context() - omitStages := ac.RequestAuditConfig.OmitStages - ev.Stage = auditinternal.StageRequestReceived - if processed := processAuditEvent(ctx, sink, ev, omitStages); !processed { + if processed := ac.ProcessEventStage(ctx, auditinternal.StageRequestReceived); !processed { audit.ApiserverAuditDroppedCounter.WithContext(ctx).Inc() responsewriters.InternalError(w, req, errors.New("failed to store audit event")) return } // intercept the status code - var longRunningSink audit.Sink + isLongRunning := false if longRunningCheck != nil { ri, _ := request.RequestInfoFrom(ctx) if longRunningCheck(req, ri) { - longRunningSink = sink + isLongRunning = true } } - respWriter := decorateResponseWriter(ctx, w, ev, longRunningSink, omitStages) + respWriter := decorateResponseWriter(ctx, w, isLongRunning) // send audit event when we leave this func, either via a panic or cleanly. In the case of long // running requests, this will be the second audit event. defer func() { if r := recover(); r != nil { defer panic(r) - ev.Stage = auditinternal.StagePanic - ev.ResponseStatus = &metav1.Status{ + ac.SetEventResponseStatus(&metav1.Status{ Code: http.StatusInternalServerError, Status: metav1.StatusFailure, Reason: metav1.StatusReasonInternalError, Message: fmt.Sprintf("APIServer panic'd: %v", r), - } - processAuditEvent(ctx, sink, ev, omitStages) + }) + ac.ProcessEventStage(ctx, auditinternal.StagePanic) return } @@ -100,27 +96,25 @@ func WithAudit(handler http.Handler, sink audit.Sink, policy audit.PolicyRuleEva Status: metav1.StatusSuccess, Message: "Connection closed early", } - if ev.ResponseStatus == nil && longRunningSink != nil { - ev.ResponseStatus = fakedSuccessStatus - ev.Stage = auditinternal.StageResponseStarted - processAuditEvent(ctx, longRunningSink, ev, omitStages) - } - - ev.Stage = auditinternal.StageResponseComplete - if ev.ResponseStatus == nil { - ev.ResponseStatus = fakedSuccessStatus + if ac.GetEventResponseStatus() == nil { + ac.SetEventResponseStatus(fakedSuccessStatus) + if isLongRunning { + // A nil ResponseStatus means the writer never processed the ResponseStarted stage, so do that now. + ac.ProcessEventStage(ctx, auditinternal.StageResponseStarted) + } } - processAuditEvent(ctx, sink, ev, omitStages) + writeLatencyToAnnotation(ctx) + ac.ProcessEventStage(ctx, auditinternal.StageResponseComplete) }() handler.ServeHTTP(respWriter, req) }) } // evaluatePolicyAndCreateAuditEvent is responsible for evaluating the audit -// policy configuration applicable to the request and create a new audit -// event that will be written to the API audit log. +// policy configuration applicable to the request and initializing the audit +// context with the audit config for the request, the sink to write to, and the request metadata. // - error if anything bad happened -func evaluatePolicyAndCreateAuditEvent(req *http.Request, policy audit.PolicyRuleEvaluator) (*audit.AuditContext, error) { +func evaluatePolicyAndCreateAuditEvent(req *http.Request, policy audit.PolicyRuleEvaluator, sink audit.Sink) (*audit.AuditContext, error) { ctx := req.Context() ac := audit.AuditContextFrom(ctx) if ac == nil { @@ -135,7 +129,10 @@ func evaluatePolicyAndCreateAuditEvent(req *http.Request, policy audit.PolicyRul rac := policy.EvaluatePolicyRule(attribs) audit.ObservePolicyLevel(ctx, rac.Level) - ac.RequestAuditConfig = rac + err = ac.Init(rac, sink) + if err != nil { + return nil, fmt.Errorf("failed to initialize audit context: %w", err) + } if rac.Level == auditinternal.LevelNone { // Don't audit. return ac, nil @@ -145,7 +142,7 @@ func evaluatePolicyAndCreateAuditEvent(req *http.Request, policy audit.PolicyRul if !ok { requestReceivedTimestamp = time.Now() } - audit.LogRequestMetadata(ctx, req, requestReceivedTimestamp, rac.Level, attribs) + audit.LogRequestMetadata(ctx, req, requestReceivedTimestamp, attribs) return ac, nil } @@ -153,13 +150,14 @@ func evaluatePolicyAndCreateAuditEvent(req *http.Request, policy audit.PolicyRul // writeLatencyToAnnotation writes the latency incurred in different // layers of the apiserver to the annotations of the audit object. // it should be invoked after ev.StageTimestamp has been set appropriately. -func writeLatencyToAnnotation(ctx context.Context, ev *auditinternal.Event) { +func writeLatencyToAnnotation(ctx context.Context) { + ac := audit.AuditContextFrom(ctx) // we will track latency in annotation only when the total latency // of the given request exceeds 500ms, this is in keeping with the // traces in rest/handlers for create, delete, update, // get, list, and deletecollection. const threshold = 500 * time.Millisecond - latency := ev.StageTimestamp.Time.Sub(ev.RequestReceivedTimestamp.Time) + latency := ac.GetEventStageTimestamp().Sub(ac.GetEventRequestReceivedTimestamp().Time) if latency <= threshold { return } @@ -177,34 +175,12 @@ func writeLatencyToAnnotation(ctx context.Context, ev *auditinternal.Event) { audit.AddAuditAnnotationsMap(ctx, layerLatencies) } -func processAuditEvent(ctx context.Context, sink audit.Sink, ev *auditinternal.Event, omitStages []auditinternal.Stage) bool { - for _, stage := range omitStages { - if ev.Stage == stage { - return true - } - } - - switch { - case ev.Stage == auditinternal.StageRequestReceived: - ev.StageTimestamp = metav1.NewMicroTime(ev.RequestReceivedTimestamp.Time) - case ev.Stage == auditinternal.StageResponseComplete: - ev.StageTimestamp = metav1.NewMicroTime(time.Now()) - writeLatencyToAnnotation(ctx, ev) - default: - ev.StageTimestamp = metav1.NewMicroTime(time.Now()) - } - - audit.ObserveEvent(ctx) - return sink.ProcessEvents(ev) -} - -func decorateResponseWriter(ctx context.Context, responseWriter http.ResponseWriter, ev *auditinternal.Event, sink audit.Sink, omitStages []auditinternal.Stage) http.ResponseWriter { +func decorateResponseWriter(ctx context.Context, responseWriter http.ResponseWriter, processResponseStartedStage bool) http.ResponseWriter { delegate := &auditResponseWriter{ ctx: ctx, ResponseWriter: responseWriter, - event: ev, - sink: sink, - omitStages: omitStages, + + processResponseStartedStage: processResponseStartedStage, } return responsewriter.WrapForHTTP1Or2(delegate) @@ -217,11 +193,10 @@ var _ responsewriter.UserProvidedDecorator = &auditResponseWriter{} // create immediately an event (for long running requests). type auditResponseWriter struct { http.ResponseWriter - ctx context.Context - event *auditinternal.Event - once sync.Once - sink audit.Sink - omitStages []auditinternal.Stage + ctx context.Context + once sync.Once + + processResponseStartedStage bool } func (a *auditResponseWriter) Unwrap() http.ResponseWriter { @@ -230,14 +205,10 @@ func (a *auditResponseWriter) Unwrap() http.ResponseWriter { func (a *auditResponseWriter) processCode(code int) { a.once.Do(func() { - if a.event.ResponseStatus == nil { - a.event.ResponseStatus = &metav1.Status{} - } - a.event.ResponseStatus.Code = int32(code) - a.event.Stage = auditinternal.StageResponseStarted - - if a.sink != nil { - processAuditEvent(a.ctx, a.sink, a.event, a.omitStages) + ac := audit.AuditContextFrom(a.ctx) + ac.SetEventResponseStatusCode(int32(code)) + if a.processResponseStartedStage { + ac.ProcessEventStage(a.ctx, auditinternal.StageResponseStarted) } }) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authn_audit.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authn_audit.go index 4bd6bbc13966..d9cdcd2d62d1 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/authn_audit.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/authn_audit.go @@ -24,7 +24,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - auditinternal "k8s.io/apiserver/pkg/apis/audit" "k8s.io/apiserver/pkg/audit" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" ) @@ -36,7 +35,7 @@ func WithFailedAuthenticationAudit(failedHandler http.Handler, sink audit.Sink, return failedHandler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ac, err := evaluatePolicyAndCreateAuditEvent(req, policy) + ac, err := evaluatePolicyAndCreateAuditEvent(req, policy, sink) if err != nil { utilruntime.HandleError(fmt.Errorf("failed to create audit event: %v", err)) responsewriters.InternalError(w, req, errors.New("failed to create audit event")) @@ -47,13 +46,11 @@ func WithFailedAuthenticationAudit(failedHandler http.Handler, sink audit.Sink, failedHandler.ServeHTTP(w, req) return } - ev := &ac.Event - ev.ResponseStatus = &metav1.Status{} - ev.ResponseStatus.Message = getAuthMethods(req) - ev.Stage = auditinternal.StageResponseStarted - - rw := decorateResponseWriter(req.Context(), w, ev, sink, ac.RequestAuditConfig.OmitStages) + ac.SetEventResponseStatus(&metav1.Status{ + Message: getAuthMethods(req), + }) + rw := decorateResponseWriter(req.Context(), w, true) failedHandler.ServeHTTP(rw, req) }) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go index a6d293a15908..aa47a7536d01 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/impersonation.go @@ -166,8 +166,7 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime. oldUser, _ := request.UserFrom(ctx) httplog.LogOf(req, w).Addf("%v is impersonating %v", userString(oldUser), userString(newUser)) - ae := audit.AuditEventFrom(ctx) - audit.LogImpersonatedUser(ae, newUser) + audit.LogImpersonatedUser(audit.WithAuditContext(ctx), newUser) // clear all the impersonation headers from the request req.Header.Del(authenticationv1.ImpersonateUserHeader) diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/filters/request_deadline.go b/vendor/k8s.io/apiserver/pkg/endpoints/filters/request_deadline.go index 7497bc38a424..066d670a2ad1 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/filters/request_deadline.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/filters/request_deadline.go @@ -108,7 +108,7 @@ func withFailedRequestAudit(failedHandler http.Handler, statusErr *apierrors.Sta return failedHandler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ac, err := evaluatePolicyAndCreateAuditEvent(req, policy) + ac, err := evaluatePolicyAndCreateAuditEvent(req, policy, sink) if err != nil { utilruntime.HandleError(fmt.Errorf("failed to create audit event: %v", err)) responsewriters.InternalError(w, req, errors.New("failed to create audit event")) @@ -119,15 +119,15 @@ func withFailedRequestAudit(failedHandler http.Handler, statusErr *apierrors.Sta failedHandler.ServeHTTP(w, req) return } - ev := &ac.Event - ev.ResponseStatus = &metav1.Status{} - ev.Stage = auditinternal.StageResponseStarted + respStatus := &metav1.Status{} if statusErr != nil { - ev.ResponseStatus.Message = statusErr.Error() + respStatus.Message = statusErr.Error() } + ac.SetEventResponseStatus(respStatus) + ac.SetEventStage(auditinternal.StageResponseStarted) - rw := decorateResponseWriter(req.Context(), w, ev, sink, ac.RequestAuditConfig.OmitStages) + rw := decorateResponseWriter(req.Context(), w, true) failedHandler.ServeHTTP(rw, req) }) } diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go index acd8f0357aaf..e6f566aa3a32 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go @@ -156,6 +156,9 @@ const ( // (usually the entire object), and if the size is smaller no gzipping will be performed // if the client requests it. defaultGzipThresholdBytes = 128 * 1024 + // Use the length of the first write to recognize streaming implementations. + // When streaming JSON first write is "{", while Kubernetes protobuf starts unique 4 byte header. + firstWriteStreamingThresholdBytes = 4 ) // negotiateContentEncoding returns a supported client-requested content encoding for the @@ -191,14 +194,53 @@ type deferredResponseWriter struct { statusCode int contentEncoding string - hasWritten bool - hw http.ResponseWriter - w io.Writer + hasBuffered bool + buffer []byte + hasWritten bool + hw http.ResponseWriter + w io.Writer ctx context.Context } func (w *deferredResponseWriter) Write(p []byte) (n int, err error) { + switch { + case w.hasWritten: + // already written, cannot buffer + return w.unbufferedWrite(p) + + case w.contentEncoding != "gzip": + // non-gzip, no need to buffer + return w.unbufferedWrite(p) + + case !w.hasBuffered && len(p) > defaultGzipThresholdBytes: + // not yet buffered, first write is long enough to trigger gzip, no need to buffer + return w.unbufferedWrite(p) + + case !w.hasBuffered && len(p) > firstWriteStreamingThresholdBytes: + // not yet buffered, first write is longer than expected for streaming scenarios that would require buffering, no need to buffer + return w.unbufferedWrite(p) + + default: + if !w.hasBuffered { + w.hasBuffered = true + // Start at 80 bytes to avoid rapid reallocation of the buffer. + // The minimum size of a 0-item serialized list object is 80 bytes: + // {"kind":"List","apiVersion":"v1","metadata":{"resourceVersion":"1"},"items":[]}\n + w.buffer = make([]byte, 0, max(80, len(p))) + } + w.buffer = append(w.buffer, p...) + var err error + if len(w.buffer) > defaultGzipThresholdBytes { + // we've accumulated enough to trigger gzip, write and clear buffer + _, err = w.unbufferedWrite(w.buffer) + w.buffer = nil + } + return len(p), err + } +} + +func (w *deferredResponseWriter) unbufferedWrite(p []byte) (n int, err error) { ctx := w.ctx span := tracing.SpanFromContext(ctx) // This Step usually wraps in-memory object serialization. @@ -244,11 +286,17 @@ func (w *deferredResponseWriter) Write(p []byte) (n int, err error) { return w.w.Write(p) } -func (w *deferredResponseWriter) Close() error { +func (w *deferredResponseWriter) Close() (err error) { if !w.hasWritten { - return nil + if !w.hasBuffered { + return nil + } + // never reached defaultGzipThresholdBytes, no need to do the gzip writer cleanup + _, err := w.unbufferedWrite(w.buffer) + w.buffer = nil + return err } - var err error + switch t := w.w.(type) { case *gzip.Writer: err = t.Close() diff --git a/vendor/k8s.io/apiserver/pkg/features/kube_features.go b/vendor/k8s.io/apiserver/pkg/features/kube_features.go index 4f51aef76852..9a119ba9410d 100644 --- a/vendor/k8s.io/apiserver/pkg/features/kube_features.go +++ b/vendor/k8s.io/apiserver/pkg/features/kube_features.go @@ -18,6 +18,7 @@ package features import ( "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/version" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/component-base/featuregate" ) @@ -265,6 +266,14 @@ const ( // document. StorageVersionHash featuregate.Feature = "StorageVersionHash" + // owner: @serathius + // Allow API server JSON encoder to encode collections item by item, instead of all at once. + StreamingCollectionEncodingToJSON featuregate.Feature = "StreamingCollectionEncodingToJSON" + + // owner: @serathius + // Allow API server Protobuf encoder to encode collections item by item, instead of all at once. + StreamingCollectionEncodingToProtobuf featuregate.Feature = "StreamingCollectionEncodingToProtobuf" + // owner: @aramase, @enj, @nabokihms // kep: https://kep.k8s.io/3331 // alpha: v1.29 @@ -345,6 +354,13 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate // EmulationVersion: { // {Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha}, // }, + StreamingCollectionEncodingToJSON: { + {Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta}, + }, + + StreamingCollectionEncodingToProtobuf: { + {Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta}, + }, } // defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys. diff --git a/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go b/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go index 27a3a110520b..86e179f60f62 100644 --- a/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/vendor/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -27,6 +27,7 @@ import ( "time" systemd "github.com/coreos/go-systemd/v22/daemon" + utilfeature "k8s.io/apiserver/pkg/util/feature" "golang.org/x/time/rate" apidiscoveryv2 "k8s.io/api/apidiscovery/v2" @@ -1021,6 +1022,17 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV // NewDefaultAPIGroupInfo returns an APIGroupInfo stubbed with "normal" values // exposed for easier composition from other packages func NewDefaultAPIGroupInfo(group string, scheme *runtime.Scheme, parameterCodec runtime.ParameterCodec, codecs serializer.CodecFactory) APIGroupInfo { + opts := []serializer.CodecFactoryOptionsMutator{} + if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) { + opts = append(opts, serializer.WithStreamingCollectionEncodingToJSON()) + } + if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf) { + opts = append(opts, serializer.WithStreamingCollectionEncodingToProtobuf()) + } + if len(opts) != 0 { + codecs = serializer.NewCodecFactory(scheme, opts...) + } + return APIGroupInfo{ PrioritizedVersions: scheme.PrioritizedVersionsForGroup(group), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, diff --git a/vendor/k8s.io/client-go/util/cert/cert.go b/vendor/k8s.io/client-go/util/cert/cert.go index 1220461264c6..48c78b595ef3 100644 --- a/vendor/k8s.io/client-go/util/cert/cert.go +++ b/vendor/k8s.io/client-go/util/cert/cert.go @@ -75,13 +75,15 @@ func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, erro CommonName: cfg.CommonName, Organization: cfg.Organization, }, - DNSNames: []string{cfg.CommonName}, NotBefore: notBefore, NotAfter: now.Add(duration365d * 10).UTC(), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, BasicConstraintsValid: true, IsCA: true, } + if len(cfg.CommonName) > 0 { + tmpl.DNSNames = []string{cfg.CommonName} + } certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &tmpl, &tmpl, key.Public(), key) if err != nil { diff --git a/vendor/k8s.io/kubernetes/openshift-kube-apiserver/filters/apirequestcount/deprecated.go b/vendor/k8s.io/kubernetes/openshift-kube-apiserver/filters/apirequestcount/deprecated.go index 060cc380db5c..edceb3c9bd0e 100644 --- a/vendor/k8s.io/kubernetes/openshift-kube-apiserver/filters/apirequestcount/deprecated.go +++ b/vendor/k8s.io/kubernetes/openshift-kube-apiserver/filters/apirequestcount/deprecated.go @@ -9,6 +9,12 @@ import ( var DeprecatedAPIRemovedRelease = map[schema.GroupVersionResource]uint{ {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Resource: "flowschemas"}: 32, {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Resource: "prioritylevelconfigurations"}: 32, + + // 4.17 shipped with admissionregistration.k8s.io/v1beta1 served under the default featureset. + {Group: "admissionregistration.k8s.io", Version: "v1beta1", Resource: "validatingwebhookconfigurations"}: 33, + {Group: "admissionregistration.k8s.io", Version: "v1beta1", Resource: "mutatingwebhookconfigurations"}: 33, + {Group: "admissionregistration.k8s.io", Version: "v1beta1", Resource: "validatingadmissionpolicies"}: 33, + {Group: "admissionregistration.k8s.io", Version: "v1beta1", Resource: "validatingadmissionpolicybindings"}: 33, } // removedRelease of a specified resource.version.group. diff --git a/vendor/k8s.io/kubernetes/pkg/features/kube_features.go b/vendor/k8s.io/kubernetes/pkg/features/kube_features.go index 44ab162a4b29..dbb2384b6a2b 100644 --- a/vendor/k8s.io/kubernetes/pkg/features/kube_features.go +++ b/vendor/k8s.io/kubernetes/pkg/features/kube_features.go @@ -817,6 +817,14 @@ const ( // Enables support for the StorageVersionMigrator controller. StorageVersionMigrator featuregate.Feature = "StorageVersionMigrator" + // owner: @serathius + // Allow API server JSON encoder to encode collections item by item, instead of all at once. + StreamingCollectionEncodingToJSON featuregate.Feature = "StreamingCollectionEncodingToJSON" + + // owner: serathius + // Allow API server Protobuf encoder to encode collections item by item, instead of all at once. + StreamingCollectionEncodingToProtobuf featuregate.Feature = "StreamingCollectionEncodingToProtobuf" + // owner: @robscott // kep: https://kep.k8s.io/2433 // alpha: v1.21 diff --git a/vendor/k8s.io/kubernetes/pkg/features/versioned_kube_features.go b/vendor/k8s.io/kubernetes/pkg/features/versioned_kube_features.go index 7ef53861822d..90dad73f7a3d 100644 --- a/vendor/k8s.io/kubernetes/pkg/features/versioned_kube_features.go +++ b/vendor/k8s.io/kubernetes/pkg/features/versioned_kube_features.go @@ -17,6 +17,7 @@ limitations under the License. package features import ( + "k8s.io/apimachinery/pkg/util/version" "k8s.io/component-base/featuregate" ) @@ -31,4 +32,11 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate // genericfeatures.EmulationVersion: { // {Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha}, // }, + StreamingCollectionEncodingToJSON: { + {Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta}, + }, + + StreamingCollectionEncodingToProtobuf: { + {Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta}, + }, } diff --git a/vendor/k8s.io/kubernetes/pkg/registry/core/rest/storage_core_generic.go b/vendor/k8s.io/kubernetes/pkg/registry/core/rest/storage_core_generic.go index 193b5b98f473..5e81e048d7f9 100644 --- a/vendor/k8s.io/kubernetes/pkg/registry/core/rest/storage_core_generic.go +++ b/vendor/k8s.io/kubernetes/pkg/registry/core/rest/storage_core_generic.go @@ -33,6 +33,9 @@ import ( "k8s.io/client-go/informers" restclient "k8s.io/client-go/rest" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apiserver/pkg/features" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" api "k8s.io/kubernetes/pkg/apis/core" configmapstore "k8s.io/kubernetes/pkg/registry/core/configmap/storage" @@ -69,6 +72,17 @@ func (c *GenericConfig) NewRESTStorage(apiResourceConfigSource serverstorage.API NegotiatedSerializer: legacyscheme.Codecs, } + opts := []serializer.CodecFactoryOptionsMutator{} + if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) { + opts = append(opts, serializer.WithStreamingCollectionEncodingToJSON()) + } + if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf) { + opts = append(opts, serializer.WithStreamingCollectionEncodingToProtobuf()) + } + if len(opts) != 0 { + apiGroupInfo.NegotiatedSerializer = serializer.NewCodecFactory(legacyscheme.Scheme, opts...) + } + eventStorage, err := eventstore.NewREST(restOptionsGetter, uint64(c.EventTTL.Seconds())) if err != nil { return genericapiserver.APIGroupInfo{}, err diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go index 28771b6df27c..5e000f93333e 100644 --- a/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/util.go @@ -17,6 +17,10 @@ limitations under the License. package securitycontext import ( + "fmt" + "os" + "sync" + v1 "k8s.io/api/core/v1" ) @@ -188,21 +192,32 @@ func AddNoNewPrivileges(sc *v1.SecurityContext) bool { var ( // These *must* be kept in sync with moby/moby. - // https://github.com/moby/moby/blob/master/oci/defaults.go#L105-L124 - // @jessfraz will watch changes to those files upstream. - defaultMaskedPaths = []string{ - "/proc/asound", - "/proc/acpi", - "/proc/kcore", - "/proc/keys", - "/proc/latency_stats", - "/proc/timer_list", - "/proc/timer_stats", - "/proc/sched_debug", - "/proc/scsi", - "/sys/firmware", - "/sys/devices/virtual/powercap", - } + // https://github.com/moby/moby/blob/ecb03c4cdae6f323150fc11b303dcc5dc4d82416/oci/defaults.go#L190-L218 + defaultMaskedPaths = sync.OnceValue(func() []string { + maskedPaths := []string{ + "/proc/asound", + "/proc/acpi", + "/proc/interrupts", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap", + } + + for _, cpu := range possibleCPUs() { + path := fmt.Sprintf("/sys/devices/system/cpu/cpu%d/thermal_throttle", cpu) + if _, err := os.Stat(path); err == nil { + maskedPaths = append(maskedPaths, path) + } + } + + return maskedPaths + }) defaultReadonlyPaths = []string{ "/proc/bus", "/proc/fs", @@ -221,7 +236,7 @@ func ConvertToRuntimeMaskedPaths(opt *v1.ProcMountType) []string { } // Otherwise, add the default masked paths to the runtime security context. - return defaultMaskedPaths + return defaultMaskedPaths() } // ConvertToRuntimeReadonlyPaths converts the ProcMountType to the specified or default diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/util_darwin.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/util_darwin.go new file mode 100644 index 000000000000..9d14502acb72 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/util_darwin.go @@ -0,0 +1,21 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package securitycontext + +func possibleCPUs() []int { + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/util_linux.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/util_linux.go new file mode 100644 index 000000000000..bcaab4eb3e17 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/util_linux.go @@ -0,0 +1,74 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package securitycontext + +import ( + "os" + "runtime" + "strconv" + "strings" + "sync" +) + +// possibleCPUs returns the number of possible CPUs on this host. +func possibleCPUs() (cpus []int) { + if ncpu := possibleCPUsParsed(); ncpu != nil { + return ncpu + } + + for i := range runtime.NumCPU() { + cpus = append(cpus, i) + } + + return cpus +} + +// possibleCPUsParsed is parsing the amount of possible CPUs on this host from +// /sys/devices. +var possibleCPUsParsed = sync.OnceValue(func() (cpus []int) { + data, err := os.ReadFile("/sys/devices/system/cpu/possible") + if err != nil { + return nil + } + + ranges := strings.Split(strings.TrimSpace(string(data)), ",") + + for _, r := range ranges { + if rStart, rEnd, ok := strings.Cut(r, "-"); !ok { + cpu, err := strconv.Atoi(rStart) + if err != nil { + return nil + } + cpus = append(cpus, cpu) + } else { + var start, end int + start, err := strconv.Atoi(rStart) + if err != nil { + return nil + } + end, err = strconv.Atoi(rEnd) + if err != nil { + return nil + } + for i := start; i <= end; i++ { + cpus = append(cpus, i) + } + } + } + + return cpus +}) diff --git a/vendor/k8s.io/kubernetes/pkg/securitycontext/util_windows.go b/vendor/k8s.io/kubernetes/pkg/securitycontext/util_windows.go new file mode 100644 index 000000000000..9d14502acb72 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/securitycontext/util_windows.go @@ -0,0 +1,21 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package securitycontext + +func possibleCPUs() []int { + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/volume/plugins.go b/vendor/k8s.io/kubernetes/pkg/volume/plugins.go index 8c9e7584bdae..e1b706ce224a 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/plugins.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/plugins.go @@ -624,9 +624,8 @@ func (pm *VolumePluginMgr) initProbedPlugin(probedPlugin VolumePlugin) error { // specification. If no plugins can support or more than one plugin can // support it, return error. func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) { - pm.mutex.RLock() - defer pm.mutex.RUnlock() - + pm.mutex.Lock() + defer pm.mutex.Unlock() if spec == nil { return nil, fmt.Errorf("could not find plugin because volume spec is nil") } @@ -639,8 +638,8 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) { matchedPluginNames = append(matchedPluginNames, v.GetPluginName()) } } - pm.refreshProbedPlugins() + for _, plugin := range pm.probedPlugins { if plugin.CanSupport(spec) { match = plugin @@ -660,14 +659,13 @@ func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) { // FindPluginByName fetches a plugin by name. If no plugin is found, returns error. func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) { - pm.mutex.RLock() - defer pm.mutex.RUnlock() + pm.mutex.Lock() + defer pm.mutex.Unlock() var match VolumePlugin if v, found := pm.plugins[name]; found { match = v } - pm.refreshProbedPlugins() if plugin, found := pm.probedPlugins[name]; found { if match != nil { @@ -694,6 +692,7 @@ func (pm *VolumePluginMgr) refreshProbedPlugins() { // because the probe function can return a list of valid plugins // even when an error is present we still must add the plugins // or they will be skipped because each event only fires once + for _, event := range events { if event.Op == ProbeAddOrUpdate { if err := pm.initProbedPlugin(event.Plugin); err != nil { @@ -984,7 +983,7 @@ func NewPersistentVolumeRecyclerPodTemplate() *v1.Pod { Containers: []v1.Container{ { Name: "pv-recycler", - Image: "registry.k8s.io/build-image/debian-base:bookworm-v1.0.3", + Image: "registry.k8s.io/build-image/debian-base:bookworm-v1.0.6", Command: []string{"/bin/sh"}, Args: []string{"-c", "test -e /scrub && find /scrub -mindepth 1 -delete && test -z \"$(ls -A /scrub)\" || exit 1"}, VolumeMounts: []v1.VolumeMount{ diff --git a/vendor/k8s.io/kubernetes/test/utils/image/manifest.go b/vendor/k8s.io/kubernetes/test/utils/image/manifest.go index 88b6034005ae..e4f740d0e465 100644 --- a/vendor/k8s.io/kubernetes/test/utils/image/manifest.go +++ b/vendor/k8s.io/kubernetes/test/utils/image/manifest.go @@ -229,7 +229,7 @@ func initImageConfigs(list RegistryList) (map[ImageID]Config, map[ImageID]Config configs[BusyBox] = Config{list.PromoterE2eRegistry, "busybox", "1.36.1-1"} configs[CudaVectorAdd] = Config{list.PromoterE2eRegistry, "cuda-vector-add", "1.0"} configs[CudaVectorAdd2] = Config{list.PromoterE2eRegistry, "cuda-vector-add", "2.3"} - configs[DistrolessIptables] = Config{list.BuildImageRegistry, "distroless-iptables", "v0.6.12"} + configs[DistrolessIptables] = Config{list.BuildImageRegistry, "distroless-iptables", "v0.7.11"} configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.15-0"} configs[Httpd] = Config{list.PromoterE2eRegistry, "httpd", "2.4.38-4"} configs[HttpdNew] = Config{list.PromoterE2eRegistry, "httpd", "2.4.39-4"} diff --git a/vendor/modules.txt b/vendor/modules.txt index b5b8eb6e4ace..e86335a2f764 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1816,7 +1816,7 @@ gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# k8s.io/api v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20250907190718-a4cad449903e +# k8s.io/api v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/api/admission/v1 k8s.io/api/admission/v1beta1 @@ -1876,7 +1876,7 @@ k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 k8s.io/api/storagemigration/v1alpha1 -# k8s.io/apiextensions-apiserver v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20250907190718-a4cad449903e +# k8s.io/apiextensions-apiserver v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/apiextensions-apiserver/pkg/apihelpers k8s.io/apiextensions-apiserver/pkg/apis/apiextensions @@ -1926,7 +1926,7 @@ k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition k8s.io/apiextensions-apiserver/test/integration k8s.io/apiextensions-apiserver/test/integration/fixtures -# k8s.io/apimachinery v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20250907190718-a4cad449903e +# k8s.io/apimachinery v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/apimachinery/pkg/api/apitesting k8s.io/apimachinery/pkg/api/equality @@ -1998,7 +1998,7 @@ k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/json k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/apiserver v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20250907190718-a4cad449903e +# k8s.io/apiserver v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/apiserver/pkg/admission k8s.io/apiserver/pkg/admission/configuration @@ -2175,13 +2175,13 @@ k8s.io/apiserver/plugin/pkg/authenticator/token/oidc k8s.io/apiserver/plugin/pkg/authenticator/token/webhook k8s.io/apiserver/plugin/pkg/authorizer/webhook k8s.io/apiserver/plugin/pkg/authorizer/webhook/metrics -# k8s.io/cli-runtime v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20250907190718-a4cad449903e +# k8s.io/cli-runtime v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/cli-runtime/pkg/genericclioptions k8s.io/cli-runtime/pkg/genericiooptions k8s.io/cli-runtime/pkg/printers k8s.io/cli-runtime/pkg/resource -# k8s.io/client-go v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20250907190718-a4cad449903e +# k8s.io/client-go v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/client-go/applyconfigurations k8s.io/client-go/applyconfigurations/admissionregistration/v1 @@ -2537,7 +2537,7 @@ k8s.io/client-go/util/retry k8s.io/client-go/util/testing k8s.io/client-go/util/watchlist k8s.io/client-go/util/workqueue -# k8s.io/cloud-provider v0.31.1 => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20250907190718-a4cad449903e +# k8s.io/cloud-provider v0.31.1 => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/cloud-provider k8s.io/cloud-provider/api @@ -2556,13 +2556,13 @@ k8s.io/cloud-provider/service/helpers k8s.io/cloud-provider/volume k8s.io/cloud-provider/volume/errors k8s.io/cloud-provider/volume/helpers -# k8s.io/cluster-bootstrap v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20250907190718-a4cad449903e +# k8s.io/cluster-bootstrap v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/cluster-bootstrap/token/api k8s.io/cluster-bootstrap/token/util k8s.io/cluster-bootstrap/util/secrets k8s.io/cluster-bootstrap/util/tokens -# k8s.io/component-base v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20250907190718-a4cad449903e +# k8s.io/component-base v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/component-base/cli/flag k8s.io/component-base/cli/globalflag @@ -2593,7 +2593,7 @@ k8s.io/component-base/tracing k8s.io/component-base/tracing/api/v1 k8s.io/component-base/version k8s.io/component-base/version/verflag -# k8s.io/component-helpers v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20250907190718-a4cad449903e +# k8s.io/component-helpers v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/component-helpers/apimachinery/lease k8s.io/component-helpers/apps/poddisruptionbudget @@ -2606,7 +2606,7 @@ k8s.io/component-helpers/scheduling/corev1 k8s.io/component-helpers/scheduling/corev1/nodeaffinity k8s.io/component-helpers/storage/ephemeral k8s.io/component-helpers/storage/volume -# k8s.io/controller-manager v0.31.1 => github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20250907190718-a4cad449903e +# k8s.io/controller-manager v0.31.1 => github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/controller-manager/config k8s.io/controller-manager/config/v1 @@ -2618,22 +2618,22 @@ k8s.io/controller-manager/pkg/features k8s.io/controller-manager/pkg/features/register k8s.io/controller-manager/pkg/leadermigration/config k8s.io/controller-manager/pkg/leadermigration/options -# k8s.io/cri-api v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20250907190718-a4cad449903e +# k8s.io/cri-api v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/cri-api/pkg/apis k8s.io/cri-api/pkg/apis/runtime/v1 k8s.io/cri-api/pkg/errors -# k8s.io/cri-client v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20250907190718-a4cad449903e +# k8s.io/cri-client v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/cri-client/pkg k8s.io/cri-client/pkg/internal k8s.io/cri-client/pkg/logs k8s.io/cri-client/pkg/util -# k8s.io/csi-translation-lib v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20250907190718-a4cad449903e +# k8s.io/csi-translation-lib v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/csi-translation-lib k8s.io/csi-translation-lib/plugins -# k8s.io/dynamic-resource-allocation v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20250907190718-a4cad449903e +# k8s.io/dynamic-resource-allocation v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/dynamic-resource-allocation/cel k8s.io/dynamic-resource-allocation/controller @@ -2660,7 +2660,7 @@ k8s.io/kms/apis/v1beta1 k8s.io/kms/apis/v2 k8s.io/kms/pkg/service k8s.io/kms/pkg/util -# k8s.io/kube-aggregator v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20250907190718-a4cad449903e +# k8s.io/kube-aggregator v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/kube-aggregator/pkg/apis/apiregistration k8s.io/kube-aggregator/pkg/apis/apiregistration/install @@ -2719,11 +2719,11 @@ k8s.io/kube-openapi/pkg/validation/spec k8s.io/kube-openapi/pkg/validation/strfmt k8s.io/kube-openapi/pkg/validation/strfmt/bson k8s.io/kube-openapi/pkg/validation/validate -# k8s.io/kube-scheduler v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20250907190718-a4cad449903e +# k8s.io/kube-scheduler v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/kube-scheduler/config/v1 k8s.io/kube-scheduler/extender/v1 -# k8s.io/kubectl v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20250907190718-a4cad449903e +# k8s.io/kubectl v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/kubectl/pkg/apps k8s.io/kubectl/pkg/cmd/util @@ -2748,7 +2748,7 @@ k8s.io/kubectl/pkg/util/storage k8s.io/kubectl/pkg/util/templates k8s.io/kubectl/pkg/util/term k8s.io/kubectl/pkg/validation -# k8s.io/kubelet v0.31.1 => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20250907190718-a4cad449903e +# k8s.io/kubelet v0.31.1 => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/kubelet/config/v1 k8s.io/kubelet/config/v1alpha1 @@ -2769,7 +2769,7 @@ k8s.io/kubelet/pkg/cri/streaming k8s.io/kubelet/pkg/cri/streaming/portforward k8s.io/kubelet/pkg/cri/streaming/remotecommand k8s.io/kubelet/pkg/types -# k8s.io/kubernetes v1.31.12 => github.com/openshift/kubernetes v1.30.1-0.20250907190718-a4cad449903e +# k8s.io/kubernetes v1.31.14 => github.com/openshift/kubernetes v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/kubernetes/cmd/kube-apiserver/app k8s.io/kubernetes/cmd/kube-apiserver/app/options @@ -3586,10 +3586,10 @@ k8s.io/kubernetes/third_party/forked/gonum/graph k8s.io/kubernetes/third_party/forked/gonum/graph/internal/linear k8s.io/kubernetes/third_party/forked/gonum/graph/simple k8s.io/kubernetes/third_party/forked/gonum/graph/traverse -# k8s.io/mount-utils v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20250907190718-a4cad449903e +# k8s.io/mount-utils v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/mount-utils -# k8s.io/pod-security-admission v0.31.12 => github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20250907190718-a4cad449903e +# k8s.io/pod-security-admission v0.31.14 => github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/pod-security-admission/admission k8s.io/pod-security-admission/admission/api @@ -3602,7 +3602,7 @@ k8s.io/pod-security-admission/admission/api/validation k8s.io/pod-security-admission/api k8s.io/pod-security-admission/metrics k8s.io/pod-security-admission/policy -# k8s.io/sample-apiserver v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20250907190718-a4cad449903e +# k8s.io/sample-apiserver v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20251128114408-436b373e7dec ## explicit; go 1.22.0 k8s.io/sample-apiserver/pkg/apis/wardle k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1 @@ -3846,33 +3846,33 @@ sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 sigs.k8s.io/yaml/goyaml.v3 # github.com/onsi/ginkgo/v2 => github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241008152707-25bf9f14db44 -# k8s.io/api => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20250907190718-a4cad449903e -# k8s.io/apiextensions-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20250907190718-a4cad449903e -# k8s.io/apimachinery => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20250907190718-a4cad449903e -# k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20250907190718-a4cad449903e -# k8s.io/cli-runtime => github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20250907190718-a4cad449903e -# k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20250907190718-a4cad449903e -# k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20250907190718-a4cad449903e -# k8s.io/cluster-bootstrap => github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20250907190718-a4cad449903e -# k8s.io/code-generator => github.com/openshift/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20250907190718-a4cad449903e -# k8s.io/component-base => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20250907190718-a4cad449903e -# k8s.io/component-helpers => github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20250907190718-a4cad449903e -# k8s.io/controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20250907190718-a4cad449903e -# k8s.io/cri-api => github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20250907190718-a4cad449903e -# k8s.io/cri-client => github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20250907190718-a4cad449903e -# k8s.io/csi-translation-lib => github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20250907190718-a4cad449903e -# k8s.io/dynamic-resource-allocation => github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20250907190718-a4cad449903e -# k8s.io/endpointslice => github.com/openshift/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20250907190718-a4cad449903e -# k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20250907190718-a4cad449903e -# k8s.io/kube-controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20250907190718-a4cad449903e -# k8s.io/kube-proxy => github.com/openshift/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20250907190718-a4cad449903e -# k8s.io/kube-scheduler => github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20250907190718-a4cad449903e -# k8s.io/kubectl => github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20250907190718-a4cad449903e -# k8s.io/kubelet => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20250907190718-a4cad449903e -# k8s.io/kubernetes => github.com/openshift/kubernetes v1.30.1-0.20250907190718-a4cad449903e -# k8s.io/metrics => github.com/openshift/kubernetes/staging/src/k8s.io/metrics v0.0.0-20250907190718-a4cad449903e -# k8s.io/mount-utils => github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20250907190718-a4cad449903e -# k8s.io/pod-security-admission => github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20250907190718-a4cad449903e -# k8s.io/sample-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20250907190718-a4cad449903e -# k8s.io/sample-cli-plugin => github.com/openshift/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20250907190718-a4cad449903e -# k8s.io/sample-controller => github.com/openshift/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20250907190718-a4cad449903e +# k8s.io/api => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20251128114408-436b373e7dec +# k8s.io/apiextensions-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251128114408-436b373e7dec +# k8s.io/apimachinery => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20251128114408-436b373e7dec +# k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20251128114408-436b373e7dec +# k8s.io/cli-runtime => github.com/openshift/kubernetes/staging/src/k8s.io/cli-runtime v0.0.0-20251128114408-436b373e7dec +# k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20251128114408-436b373e7dec +# k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20251128114408-436b373e7dec +# k8s.io/cluster-bootstrap => github.com/openshift/kubernetes/staging/src/k8s.io/cluster-bootstrap v0.0.0-20251128114408-436b373e7dec +# k8s.io/code-generator => github.com/openshift/kubernetes/staging/src/k8s.io/code-generator v0.0.0-20251128114408-436b373e7dec +# k8s.io/component-base => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20251128114408-436b373e7dec +# k8s.io/component-helpers => github.com/openshift/kubernetes/staging/src/k8s.io/component-helpers v0.0.0-20251128114408-436b373e7dec +# k8s.io/controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/controller-manager v0.0.0-20251128114408-436b373e7dec +# k8s.io/cri-api => github.com/openshift/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20251128114408-436b373e7dec +# k8s.io/cri-client => github.com/openshift/kubernetes/staging/src/k8s.io/cri-client v0.0.0-20251128114408-436b373e7dec +# k8s.io/csi-translation-lib => github.com/openshift/kubernetes/staging/src/k8s.io/csi-translation-lib v0.0.0-20251128114408-436b373e7dec +# k8s.io/dynamic-resource-allocation => github.com/openshift/kubernetes/staging/src/k8s.io/dynamic-resource-allocation v0.0.0-20251128114408-436b373e7dec +# k8s.io/endpointslice => github.com/openshift/kubernetes/staging/src/k8s.io/endpointslice v0.0.0-20251128114408-436b373e7dec +# k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20251128114408-436b373e7dec +# k8s.io/kube-controller-manager => github.com/openshift/kubernetes/staging/src/k8s.io/kube-controller-manager v0.0.0-20251128114408-436b373e7dec +# k8s.io/kube-proxy => github.com/openshift/kubernetes/staging/src/k8s.io/kube-proxy v0.0.0-20251128114408-436b373e7dec +# k8s.io/kube-scheduler => github.com/openshift/kubernetes/staging/src/k8s.io/kube-scheduler v0.0.0-20251128114408-436b373e7dec +# k8s.io/kubectl => github.com/openshift/kubernetes/staging/src/k8s.io/kubectl v0.0.0-20251128114408-436b373e7dec +# k8s.io/kubelet => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20251128114408-436b373e7dec +# k8s.io/kubernetes => github.com/openshift/kubernetes v0.0.0-20251128114408-436b373e7dec +# k8s.io/metrics => github.com/openshift/kubernetes/staging/src/k8s.io/metrics v0.0.0-20251128114408-436b373e7dec +# k8s.io/mount-utils => github.com/openshift/kubernetes/staging/src/k8s.io/mount-utils v0.0.0-20251128114408-436b373e7dec +# k8s.io/pod-security-admission => github.com/openshift/kubernetes/staging/src/k8s.io/pod-security-admission v0.0.0-20251128114408-436b373e7dec +# k8s.io/sample-apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/sample-apiserver v0.0.0-20251128114408-436b373e7dec +# k8s.io/sample-cli-plugin => github.com/openshift/kubernetes/staging/src/k8s.io/sample-cli-plugin v0.0.0-20251128114408-436b373e7dec +# k8s.io/sample-controller => github.com/openshift/kubernetes/staging/src/k8s.io/sample-controller v0.0.0-20251128114408-436b373e7dec