diff --git a/go.mod b/go.mod index 13d3ed4..8f5b22e 100644 --- a/go.mod +++ b/go.mod @@ -12,17 +12,17 @@ exclude ( require ( code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6 - code.cloudfoundry.org/cli v0.0.0-20240609151540-b78406a9b0ce + code.cloudfoundry.org/cli v0.0.0-20250410033454-7ef8a48b9bb3 ) require ( - code.cloudfoundry.org/bytefmt v0.34.0 // indirect + code.cloudfoundry.org/bytefmt v0.39.0 // indirect code.cloudfoundry.org/cli-plugin-repo v0.0.0-20240520170503-e7ed9c7432a0 // indirect - code.cloudfoundry.org/clock v1.32.0 // indirect + code.cloudfoundry.org/clock v1.37.0 // indirect code.cloudfoundry.org/go-log-cache/v2 v2.0.7 // indirect code.cloudfoundry.org/go-loggregator/v9 v9.2.1 // indirect code.cloudfoundry.org/jsonry v1.1.4 // indirect - code.cloudfoundry.org/tlsconfig v0.22.0 // indirect + code.cloudfoundry.org/tlsconfig v0.26.0 // indirect code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/SermoDigital/jose v0.9.2-0.20161205224733-f6df55f235c2 // indirect @@ -38,7 +38,7 @@ require ( github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/jessevdk/go-flags v1.6.1 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -57,25 +57,26 @@ require ( github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 // indirect github.com/vito/go-interact v1.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/oauth2 v0.29.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.11.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect - google.golang.org/grpc v1.71.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect + google.golang.org/grpc v1.72.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apimachinery v0.32.3 // indirect - k8s.io/client-go v0.32.3 // indirect + k8s.io/apimachinery v0.33.0 // indirect + k8s.io/client-go v0.33.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect + k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 379bed9..e4ec79d 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ -code.cloudfoundry.org/bytefmt v0.34.0 h1:ErjbaXWjKm6BwdataJUrQxOdtR3uvUoKIXlMaA/smV0= -code.cloudfoundry.org/bytefmt v0.34.0/go.mod h1:U3iZQ5YdK0/0QVYYW+QMLXGjBNXfmZmKt/J2V1eKHvc= +code.cloudfoundry.org/bytefmt v0.39.0 h1:N2h3ADKCTbxrVfWLP/YVx1QHnXQnVozqQuEtMjjecwc= +code.cloudfoundry.org/bytefmt v0.39.0/go.mod h1:1SmOxWKuMQMBDg4w6VOHq3xFT57aX0lZNLR52Eq8+JU= code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6 h1:Yc9r1p21kEpni9WlG4mwOZw87TB2QlyS9sAEebZ3+ak= code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6/go.mod h1:u5FovqC5GGAEbFPz+IdjycDA+gIjhUwqxnu0vbHwVeM= -code.cloudfoundry.org/cli v0.0.0-20240609151540-b78406a9b0ce h1:Lg/u08txpuLjC7FQ4Q7DtQB2VZbmCXBbgyZbmBiwvI8= -code.cloudfoundry.org/cli v0.0.0-20240609151540-b78406a9b0ce/go.mod h1:I6bhATQKPAMQ5fdUxioHxt95aTfqJ3NibHnMIO2N0Kk= +code.cloudfoundry.org/cli v0.0.0-20250410033454-7ef8a48b9bb3 h1:C0OnliQ83Z6FNhNu6u1UriYwEo+npBlSyOnB/9Ljs4M= +code.cloudfoundry.org/cli v0.0.0-20250410033454-7ef8a48b9bb3/go.mod h1:NZUvc2yoa/aNmaZ1Ci5w5q5FuKkO0HT/ORManPgaOr4= code.cloudfoundry.org/cli-plugin-repo v0.0.0-20240520170503-e7ed9c7432a0 h1:AqfPzPhykvxSpxMkDdZMSJrCbxMQ0rugvDB3BuqD0DE= code.cloudfoundry.org/cli-plugin-repo v0.0.0-20240520170503-e7ed9c7432a0/go.mod h1:R1EiyOAr7lW0l/YkZNqItUNZ01Q/dYUfbTn4X4Z+82M= -code.cloudfoundry.org/clock v1.32.0 h1:GlGItvgiaemkPwxb+2/GNUfxiCs+1rjGiqTI8qZKJY8= -code.cloudfoundry.org/clock v1.32.0/go.mod h1:LJLHnDAxkJnhZVx+pbDv2POHvj40W++Skiirqo7Jgbo= +code.cloudfoundry.org/clock v1.37.0 h1:7e/FmrQ8f3cJW1aR4jhKWaEimBp5Ub39dOeNXQHq8HM= +code.cloudfoundry.org/clock v1.37.0/go.mod h1:9bvV2riUok6o34gOGGVIkX1v37wwsZbuSCBx8Y4laL0= code.cloudfoundry.org/diego-ssh v0.0.0-20230810200140-af9d79fe9c82 h1:Bns1y0jSlcvfP0u8ael+TUlnyNHsNX808zuo58bf5so= code.cloudfoundry.org/diego-ssh v0.0.0-20230810200140-af9d79fe9c82/go.mod h1:L2/glHnSK+wKnsG8oZZqdV2sgYY9NDo/I1aDJGhcWaM= code.cloudfoundry.org/go-log-cache/v2 v2.0.7 h1:yR/JjQ/RscO1n4xVAT9HDYcpx5ET/3Cq2/RhpJml6ZU= @@ -18,10 +18,10 @@ code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f h1:UrKzEwTg code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI= code.cloudfoundry.org/jsonry v1.1.4 h1:P9N7IlH1/4aRCLcXLgLFj1hkcBmV7muijJzY+K6U4hE= code.cloudfoundry.org/jsonry v1.1.4/go.mod h1:6aKilShQP7w/Ez76h1El2/n9y2OkHuU56nKSBB9Gp0A= -code.cloudfoundry.org/lager/v3 v3.0.3 h1:/UTmadZfIaKuT/whEinSxK1mzRfNu1uPfvjFfGqiwzM= -code.cloudfoundry.org/lager/v3 v3.0.3/go.mod h1:Zn5q1SrIuuHjEUE7xerMKt3ztunrJQCZETAo7rV0CH8= -code.cloudfoundry.org/tlsconfig v0.22.0 h1:zgzDd4lp++vov8azKP1LdAOBEViPRwm1lg67FHJ4W7Q= -code.cloudfoundry.org/tlsconfig v0.22.0/go.mod h1:RX++v+3sJ7bCv0rhFAMryoDAeQeGWJv7bXdwK7DfIzo= +code.cloudfoundry.org/lager/v3 v3.32.0 h1:2OmBpTkX17PSFhkPny1P9K642Anwq5OsdpU5vGyerVc= +code.cloudfoundry.org/lager/v3 v3.32.0/go.mod h1:8agmjq9SQseFS7XGTm4iAf6Rn76V7JKfRe60wEMvkCQ= +code.cloudfoundry.org/tlsconfig v0.26.0 h1:M8mdkKbOv+y6I6bOIsVCJzYl0BGykIhf9o4EOb096ME= +code.cloudfoundry.org/tlsconfig v0.26.0/go.mod h1:NOe+islgBrrY5Z/kzbTTb4P9xmjXhcSwHNSKRYB1PYs= code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d h1:M+zXqtXJqcsmpL76aU0tdl1ho23eYa4axYoM4gD62UA= code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d/go.mod h1:YUJiVOr5xl0N/RjMxM1tHmgSpBbi5UM+KoVR5AoejO0= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -50,10 +50,10 @@ github.com/cloudfoundry/bosh-utils v0.0.538/go.mod h1:ohCt2Llxkj8/sgG3zipUhpHdB2 github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/cppforlife/go-patch v0.2.0 h1:Y14MnCQjDlbw7WXT4k+u6DPAA9XnygN4BfrSpI/19RU= github.com/cppforlife/go-patch v0.2.0/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaAG1yGxpUoFD8= -github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= -github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= -github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -96,8 +96,8 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -109,11 +109,9 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4= +github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= @@ -169,28 +167,27 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= -github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v0.0.0-20171105031654-1eecca0ba8e6/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= -github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= -github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= -github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA= -github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= +github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0= github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -200,6 +197,8 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/square/certstrap v1.3.0 h1:N9P0ZRA+DjT8pq5fGDj0z3FjafRKnBDypP0QHpMlaAk= github.com/square/certstrap v1.3.0/go.mod h1:wGZo9eE1B7WX2GKBn0htJ+B3OuRl2UsdCFySNooy9hU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -227,15 +226,17 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= -go.step.sm/crypto v0.59.2 h1:pW6qsBW03hd/OFHi2j7hF4sWnEJ0u7rn3reDSqPb46c= -go.step.sm/crypto v0.59.2/go.mod h1:bPwUACtYU1CR5ohZTetjBz9CfyF9qql3LllAjw+t3rs= +go.step.sm/crypto v0.62.0 h1:ulZjt+7tkE4f+sUdGevnRqh5/6GRkex8/lWbpNKLDZY= +go.step.sm/crypto v0.62.0/go.mod h1:mEI+M+m1s4AKiqTm6NBX5+X3uQE2hO4bhEUJBdIQZpQ= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -252,10 +253,10 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= +golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -282,18 +283,18 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -303,18 +304,18 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 h1:hE3bRWtU6uceqlh4fhrSnUyjKHMKB9KrTLLG+bc0ddM= -google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1:0PeQib/pH3nB/5pEmFeVQJotzGohV0dq4Vcp09H5yhE= +google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -349,22 +350,24 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.4.0-0.dev/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= +k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= +k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= +k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= +k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= +k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= -k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg= +k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/session.go b/session.go index c45c45c..d5e8479 100644 --- a/session.go +++ b/session.go @@ -138,9 +138,9 @@ func (s *Session) init(config *configv3.Config, configUaa *configv3.Config, conf SkipSSLValidation: config.SkipSSLValidation(), DialTimeout: config.DialTimeout(), }) - info, _, err := ccClientV3.GetInfo() + root, _, err := ccClientV3.GetRoot() if err != nil { - return fmt.Errorf("could not fetch api root informations: %s", err) + return fmt.Errorf("could not fetch api root information: %s", err) } // create an uaa client with cf_username/cf_password or client_id/client secret @@ -150,7 +150,7 @@ func (s *Session) init(config *configv3.Config, configUaa *configv3.Config, conf uaaAuthWrapper := uaaWrapper.NewUAAAuthentication(nil, configUaa) uaaClient.WrapConnection(uaaAuthWrapper) uaaClient.WrapConnection(uaaWrapper.NewRetryRequest(config.RequestRetryCount())) - err = uaaClient.SetupResources(info.UAA(), info.Login()) + err = uaaClient.SetupResources(root.UAA(), root.Login()) if err != nil { return fmt.Errorf("error setup resource uaa: %s", err) } @@ -200,7 +200,7 @@ func (s *Session) init(config *configv3.Config, configUaa *configv3.Config, conf uaaAuthWrapperSess := uaaWrapper.NewUAAAuthentication(nil, configUaa) uaaClientSess.WrapConnection(uaaAuthWrapperSess) uaaClientSess.WrapConnection(uaaWrapper.NewRetryRequest(config.RequestRetryCount())) - err = uaaClientSess.SetupResources(info.UAA(), info.Login()) + err = uaaClientSess.SetupResources(root.UAA(), root.Login()) if err != nil { return fmt.Errorf("error setup resource uaa: %s", err) } @@ -282,7 +282,7 @@ func (s *Session) init(config *configv3.Config, configUaa *configv3.Config, conf DialTimeout: config.DialTimeout(), SkipSSLValidation: config.SkipSSLValidation(), }, - RoutingEndpoint: info.Routing(), + RoutingEndpoint: root.Routing(), } routerWrappers := []router.ConnectionWrapper{} diff --git a/vendor/code.cloudfoundry.org/cli/actor/actionerror/route_option_error.go b/vendor/code.cloudfoundry.org/cli/actor/actionerror/route_option_error.go new file mode 100644 index 0000000..005633e --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/actor/actionerror/route_option_error.go @@ -0,0 +1,22 @@ +package actionerror + +import "fmt" + +// RouteOptionError is returned when a route option was specified in the wrong format +type RouteOptionError struct { + Name string + Host string + DomainName string + Path string +} + +func (e RouteOptionError) Error() string { + return fmt.Sprintf("Route option '%s' for route with host '%s', domain '%s', and path '%s' was specified incorrectly. Please use key-value pair format key=value.", e.Name, e.Host, e.DomainName, e.path()) +} + +func (e RouteOptionError) path() string { + if e.Path == "" { + return "/" + } + return e.Path +} diff --git a/vendor/code.cloudfoundry.org/cli/actor/actionerror/route_option_support_error.go b/vendor/code.cloudfoundry.org/cli/actor/actionerror/route_option_support_error.go new file mode 100644 index 0000000..9fcffbb --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/actor/actionerror/route_option_support_error.go @@ -0,0 +1,12 @@ +package actionerror + +import "fmt" + +// RouteOptionSupportError is returned when route options are not supported +type RouteOptionSupportError struct { + ErrorText string +} + +func (e RouteOptionSupportError) Error() string { + return fmt.Sprintf("Route option support: '%s'", e.ErrorText) +} diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/application.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/application.go index 6847009..e86ca01 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/application.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/application.go @@ -162,6 +162,7 @@ func (actor Actor) CreateApplicationInSpace(app resources.Application, spaceGUID LifecycleBuildpacks: app.LifecycleBuildpacks, StackName: app.StackName, Name: app.Name, + Credentials: app.Credentials, SpaceGUID: spaceGUID, }) @@ -298,9 +299,9 @@ func (actor Actor) PollStart(app resources.Application, noWait bool, handleInsta } } -// PollStartForRolling polls a deploying application's processes until some are started. It does the same thing as PollStart, except it accounts for rolling deployments and whether +// PollStartForDeployment polls a deploying application's processes until some are started. It does the same thing as PollStart, except it accounts for rolling/canary deployments and whether // they have failed or been canceled during polling. -func (actor Actor) PollStartForRolling(app resources.Application, deploymentGUID string, noWait bool, handleInstanceDetails func(string)) (Warnings, error) { +func (actor Actor) PollStartForDeployment(app resources.Application, deploymentGUID string, noWait bool, handleInstanceDetails func(string)) (Warnings, error) { var ( deployment resources.Deployment processes []resources.Process @@ -321,7 +322,7 @@ func (actor Actor) PollStartForRolling(app resources.Application, deploymentGUID } return allWarnings, actionerror.StartupTimeoutError{Name: app.Name} case <-timer.C(): - if !isDeployed(deployment) { + if !isDeployProcessed(deployment) { ccDeployment, warnings, err := actor.getDeployment(deploymentGUID) allWarnings = append(allWarnings, warnings...) if err != nil { @@ -335,7 +336,7 @@ func (actor Actor) PollStartForRolling(app resources.Application, deploymentGUID } } - if noWait || isDeployed(deployment) { + if noWait || isDeployProcessed(deployment) { stopPolling, warnings, err := actor.PollProcesses(processes, handleInstanceDetails) allWarnings = append(allWarnings, warnings...) if stopPolling || err != nil { @@ -348,7 +349,12 @@ func (actor Actor) PollStartForRolling(app resources.Application, deploymentGUID } } -func isDeployed(d resources.Deployment) bool { +func isDeployProcessed(d resources.Deployment) bool { + if d.Strategy == constant.DeploymentStrategyCanary { + return d.StatusValue == constant.DeploymentStatusValueActive && d.StatusReason == constant.DeploymentStatusReasonPaused || + d.StatusValue == constant.DeploymentStatusValueFinalized && d.StatusReason == constant.DeploymentStatusReasonDeployed + } + return d.StatusValue == constant.DeploymentStatusValueFinalized && d.StatusReason == constant.DeploymentStatusReasonDeployed } @@ -439,7 +445,7 @@ func (actor Actor) getProcesses(deployment resources.Deployment, appGUID string, // if the deployment is deployed we know web are all running and PollProcesses will see those as stable // so just getting all processes is equivalent to just getting non-web ones and polling those - if isDeployed(deployment) { + if isDeployProcessed(deployment) { processes, warnings, err := actor.CloudControllerClient.GetApplicationProcesses(appGUID) if err != nil { return processes, Warnings(warnings), err diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/application_summary.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/application_summary.go index d33be9d..7837205 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/application_summary.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/application_summary.go @@ -1,6 +1,8 @@ package v7action import ( + "errors" + "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" @@ -18,6 +20,7 @@ type ApplicationSummary struct { type DetailedApplicationSummary struct { ApplicationSummary CurrentDroplet resources.Droplet + Deployment resources.Deployment } func (a ApplicationSummary) GetIsolationSegmentName() (string, bool) { @@ -120,6 +123,12 @@ func (actor Actor) GetDetailedAppSummary(appName, spaceGUID string, withObfuscat return DetailedApplicationSummary{}, allWarnings, err } + detailedSummary, warnings, err = actor.addDeployment(detailedSummary) + allWarnings = append(allWarnings, warnings...) + if err != nil { + return DetailedApplicationSummary{}, allWarnings, err + } + return detailedSummary, allWarnings, err } @@ -206,6 +215,19 @@ func (actor Actor) addDroplet(summary ApplicationSummary) (DetailedApplicationSu }, allWarnings, nil } +func (actor Actor) addDeployment(detailedSummary DetailedApplicationSummary) (DetailedApplicationSummary, Warnings, error) { + var allWarnings Warnings + + deployment, warnings, err := actor.GetLatestActiveDeploymentForApp(detailedSummary.GUID) + allWarnings = append(allWarnings, warnings...) + if err != nil && !errors.Is(err, actionerror.ActiveDeploymentNotFoundError{}) { + return DetailedApplicationSummary{}, allWarnings, err + } + + detailedSummary.Deployment = deployment + return detailedSummary, allWarnings, nil +} + func toAppGUIDs(apps []resources.Application) []string { guids := make([]string, len(apps)) diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/auth.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/auth.go index aef734c..6c03cc4 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/auth.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/auth.go @@ -25,7 +25,7 @@ func NewDefaultAuthActor(config Config, uaaClient UAAClient) AuthActor { } func (actor defaultAuthActor) Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error { - if grantType == constant.GrantTypePassword && actor.config.UAAGrantType() == string(constant.GrantTypeClientCredentials) { + if (grantType == constant.GrantTypePassword || grantType == constant.GrantTypeJwtBearer) && actor.config.UAAGrantType() == string(constant.GrantTypeClientCredentials) { return actionerror.PasswordGrantTypeLogoutRequiredError{} } @@ -45,7 +45,7 @@ func (actor defaultAuthActor) Authenticate(credentials map[string]string, origin actor.config.SetUAAGrantType(string(grantType)) } - if grantType == constant.GrantTypeClientCredentials { + if (grantType == constant.GrantTypeClientCredentials || grantType == constant.GrantTypeJwtBearer) && credentials["client_id"] != "" { actor.config.SetUAAClientCredentials(credentials["client_id"], "") } diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/cloud_controller_client.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/cloud_controller_client.go index 8884901..34b1d3e 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/cloud_controller_client.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/cloud_controller_client.go @@ -18,10 +18,10 @@ type CloudControllerClient interface { ApplySpaceQuota(quotaGUID string, spaceGUID string) (resources.RelationshipList, ccv3.Warnings, error) CheckRoute(domainGUID string, hostname string, path string, port int) (bool, ccv3.Warnings, error) CancelDeployment(deploymentGUID string) (ccv3.Warnings, error) + ContinueDeployment(deploymentGUID string) (ccv3.Warnings, error) CopyPackage(sourcePackageGUID string, targetAppGUID string) (resources.Package, ccv3.Warnings, error) CreateApplication(app resources.Application) (resources.Application, ccv3.Warnings, error) - CreateApplicationDeployment(appGUID string, dropletGUID string) (string, ccv3.Warnings, error) - CreateApplicationDeploymentByRevision(appGUID string, revisionGUID string) (string, ccv3.Warnings, error) + CreateApplicationDeployment(dep resources.Deployment) (string, ccv3.Warnings, error) CreateApplicationProcessScale(appGUID string, process resources.Process) (resources.Process, ccv3.Warnings, error) CreateApplicationTask(appGUID string, task resources.Task) (resources.Task, ccv3.Warnings, error) CreateBuild(build resources.Build) (resources.Build, ccv3.Warnings, error) @@ -84,9 +84,11 @@ type CloudControllerClient interface { GetDroplet(guid string) (resources.Droplet, ccv3.Warnings, error) GetDroplets(query ...ccv3.Query) ([]resources.Droplet, ccv3.Warnings, error) GetEnvironmentVariableGroup(group constant.EnvironmentVariableGroupName) (resources.EnvironmentVariables, ccv3.Warnings, error) + GetEnvironmentVariablesByURL(url string) (resources.EnvironmentVariables, ccv3.Warnings, error) GetEvents(query ...ccv3.Query) ([]ccv3.Event, ccv3.Warnings, error) GetFeatureFlag(featureFlagName string) (resources.FeatureFlag, ccv3.Warnings, error) GetFeatureFlags() ([]resources.FeatureFlag, ccv3.Warnings, error) + GetRoot() (ccv3.Root, ccv3.Warnings, error) GetInfo() (ccv3.Info, ccv3.Warnings, error) GetIsolationSegment(guid string) (resources.IsolationSegment, ccv3.Warnings, error) GetIsolationSegmentOrganizations(isolationSegmentGUID string) ([]resources.Organization, ccv3.Warnings, error) @@ -147,7 +149,7 @@ type CloudControllerClient interface { PollJobToEventStream(jobURL ccv3.JobURL) chan ccv3.PollJobEvent PurgeServiceOffering(serviceOfferingGUID string) (ccv3.Warnings, error) ResourceMatch(resources []ccv3.Resource) ([]ccv3.Resource, ccv3.Warnings, error) - RootResponse() (ccv3.Info, ccv3.Warnings, error) + RootResponse() (ccv3.Root, ccv3.Warnings, error) SetApplicationDroplet(appGUID string, dropletGUID string) (resources.Relationship, ccv3.Warnings, error) SharePrivateDomainToOrgs(domainGuid string, sharedOrgs ccv3.SharedOrgs) (ccv3.Warnings, error) ShareServiceInstanceToSpaces(serviceInstanceGUID string, spaceGUIDs []string) (resources.RelationshipList, ccv3.Warnings, error) @@ -176,6 +178,7 @@ type CloudControllerClient interface { UpdateOrganizationQuota(orgQuota resources.OrganizationQuota) (resources.OrganizationQuota, ccv3.Warnings, error) UpdateProcess(process resources.Process) (resources.Process, ccv3.Warnings, error) UpdateResourceMetadata(resource string, resourceGUID string, metadata resources.Metadata) (ccv3.JobURL, ccv3.Warnings, error) + UpdateRoute(routeGUID string, options map[string]*string) (resources.Route, ccv3.Warnings, error) UpdateSecurityGroupRunningSpace(securityGroupGUID string, spaceGUIDs []string) (ccv3.Warnings, error) UpdateSecurityGroupStagingSpace(securityGroupGUID string, spaceGUIDs []string) (ccv3.Warnings, error) UpdateSecurityGroup(securityGroup resources.SecurityGroup) (resources.SecurityGroup, ccv3.Warnings, error) diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/deployment.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/deployment.go index d707b57..95faadb 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/deployment.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/deployment.go @@ -7,15 +7,8 @@ import ( "code.cloudfoundry.org/cli/resources" ) -func (actor Actor) CreateDeploymentByApplicationAndDroplet(appGUID string, dropletGUID string) (string, Warnings, error) { - deploymentGUID, warnings, err := actor.CloudControllerClient.CreateApplicationDeployment(appGUID, dropletGUID) - - return deploymentGUID, Warnings(warnings), err -} - -func (actor Actor) CreateDeploymentByApplicationAndRevision(appGUID string, revisionGUID string) (string, Warnings, error) { - deploymentGUID, warnings, err := actor.CloudControllerClient.CreateApplicationDeploymentByRevision(appGUID, revisionGUID) - +func (actor Actor) CreateDeployment(dep resources.Deployment) (string, Warnings, error) { + deploymentGUID, warnings, err := actor.CloudControllerClient.CreateApplicationDeployment(dep) return deploymentGUID, Warnings(warnings), err } @@ -36,10 +29,15 @@ func (actor Actor) GetLatestActiveDeploymentForApp(appGUID string) (resources.De return resources.Deployment{}, Warnings(warnings), actionerror.ActiveDeploymentNotFoundError{} } - return resources.Deployment(ccDeployments[0]), Warnings(warnings), nil + return ccDeployments[0], Warnings(warnings), nil } func (actor Actor) CancelDeployment(deploymentGUID string) (Warnings, error) { warnings, err := actor.CloudControllerClient.CancelDeployment(deploymentGUID) return Warnings(warnings), err } + +func (actor Actor) ContinueDeployment(deploymentGUID string) (Warnings, error) { + warnings, err := actor.CloudControllerClient.ContinueDeployment(deploymentGUID) + return Warnings(warnings), err +} diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/info.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/info.go index 723c1b5..909f0c6 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/info.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/info.go @@ -2,9 +2,18 @@ package v7action import "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" +type Root ccv3.Root type Info ccv3.Info -func (actor Actor) GetRootResponse() (Info, Warnings, error) { +func (actor Actor) GetRootResponse() (Root, Warnings, error) { + root, warnings, err := actor.CloudControllerClient.GetRoot() + if err != nil { + return Root{}, Warnings(warnings), err + } + return Root(root), Warnings(warnings), nil +} + +func (actor Actor) GetInfoResponse() (Info, Warnings, error) { info, warnings, err := actor.CloudControllerClient.GetInfo() if err != nil { return Info{}, Warnings(warnings), err diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/process_readiness_health_check.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/process_readiness_health_check.go new file mode 100644 index 0000000..4dbe860 --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/process_readiness_health_check.go @@ -0,0 +1,72 @@ +package v7action + +import ( + "sort" + + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" +) + +type ProcessReadinessHealthCheck struct { + ProcessType string + HealthCheckType constant.HealthCheckType + Endpoint string + InvocationTimeout int64 + Interval int64 +} + +type ProcessReadinessHealthChecks []ProcessReadinessHealthCheck + +func (phs ProcessReadinessHealthChecks) Sort() { + sort.Slice(phs, func(i int, j int) bool { + var iScore int + var jScore int + + switch phs[i].ProcessType { + case constant.ProcessTypeWeb: + iScore = 0 + default: + iScore = 1 + } + + switch phs[j].ProcessType { + case constant.ProcessTypeWeb: + jScore = 0 + default: + jScore = 1 + } + + if iScore == 1 && jScore == 1 { + return phs[i].ProcessType < phs[j].ProcessType + } + return iScore < jScore + }) +} + +func (actor Actor) GetApplicationProcessReadinessHealthChecksByNameAndSpace(appName string, spaceGUID string) ([]ProcessReadinessHealthCheck, Warnings, error) { + app, allWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID) + if err != nil { + return nil, allWarnings, err + } + + ccv3Processes, warnings, err := actor.CloudControllerClient.GetApplicationProcesses(app.GUID) + allWarnings = append(allWarnings, Warnings(warnings)...) + if err != nil { + return nil, allWarnings, err + } + + var processReadinessHealthChecks ProcessReadinessHealthChecks + for _, ccv3Process := range ccv3Processes { + processReadinessHealthCheck := ProcessReadinessHealthCheck{ + ProcessType: ccv3Process.Type, + HealthCheckType: ccv3Process.ReadinessHealthCheckType, + Endpoint: ccv3Process.ReadinessHealthCheckEndpoint, + InvocationTimeout: ccv3Process.ReadinessHealthCheckInvocationTimeout, + Interval: ccv3Process.ReadinessHealthCheckInterval, + } + processReadinessHealthChecks = append(processReadinessHealthChecks, processReadinessHealthCheck) + } + + processReadinessHealthChecks.Sort() + + return processReadinessHealthChecks, allWarnings, nil +} diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/revisions.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/revisions.go index c2109c8..f159ab6 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/revisions.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/revisions.go @@ -76,6 +76,20 @@ func (actor Actor) GetRevisionByApplicationAndVersion(appGUID string, revisionVe return revisions[0], Warnings(warnings), nil } +func (actor Actor) GetEnvironmentVariableGroupByRevision(revision resources.Revision) (EnvironmentVariableGroup, bool, Warnings, error) { + envVarApiLink, isPresent := revision.Links["environment_variables"] + if !isPresent { + return EnvironmentVariableGroup{}, isPresent, Warnings{"Unable to retrieve environment variables for revision."}, nil + } + + environmentVariables, warnings, err := actor.CloudControllerClient.GetEnvironmentVariablesByURL(envVarApiLink.HREF) + if err != nil { + return EnvironmentVariableGroup{}, false, Warnings(warnings), err + } + + return EnvironmentVariableGroup(environmentVariables), true, Warnings(warnings), nil +} + func (actor Actor) setRevisionsDeployableByDropletStateForApp(appGUID string, revisions []resources.Revision) ([]resources.Revision, Warnings, error) { droplets, warnings, err := actor.CloudControllerClient.GetDroplets( ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{appGUID}}, diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/route.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/route.go index 7bccf6b..2f2c2f7 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/route.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/route.go @@ -26,7 +26,7 @@ type RouteSummary struct { ServiceInstanceName string } -func (actor Actor) CreateRoute(spaceGUID, domainName, hostname, path string, port int) (resources.Route, Warnings, error) { +func (actor Actor) CreateRoute(spaceGUID, domainName, hostname, path string, port int, options map[string]*string) (resources.Route, Warnings, error) { allWarnings := Warnings{} domain, warnings, err := actor.GetDomainByName(domainName) allWarnings = append(allWarnings, warnings...) @@ -41,6 +41,7 @@ func (actor Actor) CreateRoute(spaceGUID, domainName, hostname, path string, por Host: hostname, Path: path, Port: port, + Options: options, }) actorWarnings := Warnings(apiWarnings) @@ -401,6 +402,11 @@ func (actor Actor) MapRoute(routeGUID string, appGUID string, destinationProtoco return Warnings(warnings), err } +func (actor Actor) UpdateRoute(routeGUID string, options map[string]*string) (resources.Route, Warnings, error) { + route, warnings, err := actor.CloudControllerClient.UpdateRoute(routeGUID, options) + return route, Warnings(warnings), err +} + func (actor Actor) UpdateDestination(routeGUID string, destinationGUID string, protocol string) (Warnings, error) { warnings, err := actor.CloudControllerClient.UpdateDestination(routeGUID, destinationGUID, protocol) return Warnings(warnings), err diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/ssh.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/ssh.go index 30fcc6f..67f1ecd 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/ssh.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/ssh.go @@ -25,7 +25,7 @@ func (actor Actor) GetSecureShellConfigurationByApplicationNameSpaceProcessTypeA ) (SSHAuthentication, Warnings, error) { var allWarnings Warnings - rootInfo, warnings, err := actor.CloudControllerClient.GetInfo() + rootInfo, warnings, err := actor.CloudControllerClient.GetRoot() allWarnings = append(allWarnings, warnings...) if err != nil { return SSHAuthentication{}, allWarnings, err diff --git a/vendor/code.cloudfoundry.org/cli/actor/v7action/target.go b/vendor/code.cloudfoundry.org/cli/actor/v7action/target.go index a63a027..01c076a 100644 --- a/vendor/code.cloudfoundry.org/cli/actor/v7action/target.go +++ b/vendor/code.cloudfoundry.org/cli/actor/v7action/target.go @@ -14,7 +14,7 @@ func (actor Actor) SetTarget(settings TargetSettings) (Warnings, error) { actor.CloudControllerClient.TargetCF(ccv3.TargetSettings(settings)) - rootInfo, warnings, err := actor.CloudControllerClient.GetInfo() + rootInfo, warnings, err := actor.CloudControllerClient.GetRoot() allWarnings = append(allWarnings, warnings...) if err != nil { return allWarnings, err diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/client.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/client.go index ffb7ef5..148b2b2 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/client.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/client.go @@ -7,7 +7,7 @@ // may include features and endpoints of later API versions. // // For more information on the Cloud Controller API see -// https://apidocs.cloudfoundry.org/ +// https://v2-apidocs.cloudfoundry.org/ // // # Method Naming Conventions // @@ -86,7 +86,7 @@ type Warnings []string // Client can be used to talk to a Cloud Controller's V3 Endpoints. type Client struct { - Info + Root CloudControllerURL string Requester diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/application.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/application.go index b0acd64..dca0b70 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/application.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/application.go @@ -9,6 +9,9 @@ const ( // AppLifecycleTypeDocker will pull a docker image from a registry to run an // app. AppLifecycleTypeDocker AppLifecycleType = "docker" + // AppLifecycleTypeCNB will use a droplet (created with cloud native buildpacks) + // and a rootfs to run the app. + AppLifecycleTypeCNB AppLifecycleType = "cnb" ) // ApplicationAction represents the action being taken on an application diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment.go index d324cb9..2ae6159 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment.go @@ -5,51 +5,29 @@ package constant type DeploymentState string const ( - // DeploymentDeploying means the deployment is in state 'DEPLOYING' DeploymentDeploying DeploymentState = "DEPLOYING" - - // DeploymentCanceled means the deployment is in state 'CANCELED' - DeploymentCanceled DeploymentState = "CANCELED" - - // DeploymentDeployed means the deployment is in state 'DEPLOYED' - DeploymentDeployed DeploymentState = "DEPLOYED" - - // DeploymentCanceled means the deployment is in state 'CANCELING' + DeploymentCanceled DeploymentState = "CANCELED" + DeploymentDeployed DeploymentState = "DEPLOYED" DeploymentCanceling DeploymentState = "CANCELING" - - // DeploymentFailing means the deployment is in state 'FAILING' - DeploymentFailing DeploymentState = "FAILING" - - // DeploymentFailed means the deployment is in state 'FAILED' - DeploymentFailed DeploymentState = "FAILED" + DeploymentFailing DeploymentState = "FAILING" + DeploymentFailed DeploymentState = "FAILED" ) // DeploymentStatusReason describes the status reasons a deployment can have type DeploymentStatusReason string const ( - // DeploymentStatusReasonDeployed means the deployment's status.value is - // 'DEPLOYED' - DeploymentStatusReasonDeployed DeploymentStatusReason = "DEPLOYED" - - // DeploymentStatusReasonCanceled means the deployment's status.value is - // 'CANCELED' - DeploymentStatusReasonCanceled DeploymentStatusReason = "CANCELED" - - // DeploymentStatusReasonSuperseded means the deployment's status.value is - // 'SUPERSEDED' + DeploymentStatusReasonDeploying DeploymentStatusReason = "DEPLOYING" + DeploymentStatusReasonCanceling DeploymentStatusReason = "CANCELING" + DeploymentStatusReasonDeployed DeploymentStatusReason = "DEPLOYED" + DeploymentStatusReasonCanceled DeploymentStatusReason = "CANCELED" DeploymentStatusReasonSuperseded DeploymentStatusReason = "SUPERSEDED" + DeploymentStatusReasonPaused DeploymentStatusReason = "PAUSED" ) -// DeploymentStatusValue describes the status values a deployment can have type DeploymentStatusValue string const ( - // DeploymentStatusValueActive means the deployment's status.value is - // 'ACTIVE' - DeploymentStatusValueActive DeploymentStatusValue = "ACTIVE" - - // DeploymentStatusValueFinalized means the deployment's status.value is - // 'FINALIZED' + DeploymentStatusValueActive DeploymentStatusValue = "ACTIVE" DeploymentStatusValueFinalized DeploymentStatusValue = "FINALIZED" ) diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment_strategy.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment_strategy.go index 2e607f6..de513bc 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment_strategy.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/deployment_strategy.go @@ -9,4 +9,7 @@ const ( // Rolling means a new web process will be created for the app and instances will roll from the old one to the new one. DeploymentStrategyRolling DeploymentStrategy = "rolling" + + // Canary means after a web process is created for the app the deployment will pause for evaluation until it is continued or canceled. + DeploymentStrategyCanary DeploymentStrategy = "canary" ) diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/relationships.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/relationships.go index 6a8b3c1..06e4eb3 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/relationships.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant/relationships.go @@ -21,4 +21,7 @@ const ( // RelationshipTypeQuota is a relationship with a Cloud Controller quota (org quota or space quota). RelationshipTypeQuota RelationshipType = "quota" + + // RelationshipTypeCurrentDroplet is a relationship with a Droplet. + RelationshipTypeCurrentDroplet RelationshipType = "current_droplet" ) diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/deployment.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/deployment.go index a4dc7da..3d72e47 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/deployment.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/deployment.go @@ -1,42 +1,29 @@ package ccv3 import ( - "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal" "code.cloudfoundry.org/cli/resources" ) -func (client *Client) CancelDeployment(deploymentGUID string) (Warnings, error) { +func (client *Client) ContinueDeployment(deploymentGUID string) (Warnings, error) { _, warnings, err := client.MakeRequest(RequestParams{ - RequestName: internal.PostApplicationDeploymentActionCancelRequest, + RequestName: internal.PostApplicationDeploymentActionContinueRequest, URIParams: internal.Params{"deployment_guid": deploymentGUID}, }) return warnings, err } -func (client *Client) CreateApplicationDeployment(appGUID string, dropletGUID string) (string, Warnings, error) { - dep := resources.Deployment{ - DropletGUID: dropletGUID, - Relationships: resources.Relationships{constant.RelationshipTypeApplication: resources.Relationship{GUID: appGUID}}, - } - - var responseBody resources.Deployment - +func (client *Client) CancelDeployment(deploymentGUID string) (Warnings, error) { _, warnings, err := client.MakeRequest(RequestParams{ - RequestName: internal.PostApplicationDeploymentRequest, - RequestBody: dep, - ResponseBody: &responseBody, + RequestName: internal.PostApplicationDeploymentActionCancelRequest, + URIParams: internal.Params{"deployment_guid": deploymentGUID}, }) - return responseBody.GUID, warnings, err + return warnings, err } -func (client *Client) CreateApplicationDeploymentByRevision(appGUID string, revisionGUID string) (string, Warnings, error) { - dep := resources.Deployment{ - RevisionGUID: revisionGUID, - Relationships: resources.Relationships{constant.RelationshipTypeApplication: resources.Relationship{GUID: appGUID}}, - } +func (client *Client) CreateApplicationDeployment(dep resources.Deployment) (string, Warnings, error) { var responseBody resources.Deployment diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/included_resources.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/included_resources.go index 0044707..24f3b5a 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/included_resources.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/included_resources.go @@ -12,3 +12,14 @@ type IncludedResources struct { ServicePlans []resources.ServicePlan `json:"service_plans,omitempty"` Apps []resources.Application `json:"apps,omitempty"` } + +func (i *IncludedResources) Merge(resources IncludedResources) { + i.Apps = append(i.Apps, resources.Apps...) + i.Users = append(i.Users, resources.Users...) + i.Organizations = append(i.Organizations, resources.Organizations...) + i.Spaces = append(i.Spaces, resources.Spaces...) + i.ServiceBrokers = append(i.ServiceBrokers, resources.ServiceBrokers...) + i.ServiceInstances = append(i.ServiceInstances, resources.ServiceInstances...) + i.ServiceOfferings = append(i.ServiceOfferings, resources.ServiceOfferings...) + i.ServicePlans = append(i.ServicePlans, resources.ServicePlans...) +} diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/info.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/info.go index 564834a..8434eb6 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/info.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/info.go @@ -3,134 +3,22 @@ package ccv3 import ( "net/http" - "code.cloudfoundry.org/cli/api/cloudcontroller" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" - "code.cloudfoundry.org/cli/resources" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal" ) -type InfoLinks struct { - // AppSSH is the link for application ssh info. - AppSSH resources.APILink `json:"app_ssh"` - - // CCV3 is the link to the Cloud Controller V3 API. - CCV3 resources.APILink `json:"cloud_controller_v3"` - - // Logging is the link to the Logging API. - Logging resources.APILink `json:"logging"` - - // Logging is the link to the Logging API. - LogCache resources.APILink `json:"log_cache"` - - // NetworkPolicyV1 is the link to the Container to Container Networking - // API. - NetworkPolicyV1 resources.APILink `json:"network_policy_v1"` - - // Routing is the link to the routing API - Routing resources.APILink `json:"routing"` - - // UAA is the link to the UAA API. - UAA resources.APILink `json:"uaa"` - - // Login is the link to the Login API. - Login resources.APILink `json:"login"` -} - -// Info represents a GET response from the '/' endpoint of the cloud -// controller API. type Info struct { - // Links is a list of top level Cloud Controller APIs. - Links InfoLinks `json:"links"` - CFOnK8s bool `json:"cf_on_k8s"` -} - -// AppSSHEndpoint returns the HREF for SSHing into an app container. -func (info Info) AppSSHEndpoint() string { - return info.Links.AppSSH.HREF -} - -// AppSSHHostKeyFingerprint returns the SSH key fingerprint of the SSH proxy -// that brokers connections to application instances. -func (info Info) AppSSHHostKeyFingerprint() string { - return info.Links.AppSSH.Meta.HostKeyFingerprint -} - -// CloudControllerAPIVersion returns the version of the CloudController. -func (info Info) CloudControllerAPIVersion() string { - return info.Links.CCV3.Meta.Version -} - -// LogCache returns the HREF of the Loggregator Traffic Controller. -func (info Info) LogCache() string { - return info.Links.LogCache.HREF -} - -// Logging returns the HREF of the Loggregator Traffic Controller. -func (info Info) Logging() string { - return info.Links.Logging.HREF -} - -// NetworkPolicyV1 returns the HREF of the Container Networking v1 Policy API -func (info Info) NetworkPolicyV1() string { - return info.Links.NetworkPolicyV1.HREF + Name string `json:"name"` + Build string `json:"build"` + OSBAPIVersion string `json:"osbapi_version"` } -// OAuthClient returns the oauth client ID of the SSH proxy that brokers -// connections to application instances. -func (info Info) OAuthClient() string { - return info.Links.AppSSH.Meta.OAuthClient -} - -// Routing returns the HREF of the routing API. -func (info Info) Routing() string { - return info.Links.Routing.HREF -} - -// UAA returns the HREF of the UAA server. -func (info Info) UAA() string { - return info.Links.UAA.HREF -} - -// Login returns the HREF of the login server. -func (info Info) Login() string { - return info.Links.Login.HREF -} - -// ResourceLinks represents the information returned back from /v3. -type ResourceLinks map[string]resources.APILink - -// UnmarshalJSON helps unmarshal a Cloud Controller /v3 response. -func (links ResourceLinks) UnmarshalJSON(data []byte) error { - var ccResourceLinks struct { - Links map[string]resources.APILink `json:"links"` - } - err := cloudcontroller.DecodeJSON(data, &ccResourceLinks) - if err != nil { - return err - } - - for key, val := range ccResourceLinks.Links { - links[key] = val - } - - return nil -} - -// GetInfo returns endpoint and API information from /v3. +// GetRoot returns the /v3/info response func (client *Client) GetInfo() (Info, Warnings, error) { - rootResponse, warnings, err := client.RootResponse() - if err != nil { - return Info{}, warnings, err - } - - return rootResponse, warnings, err -} - -// rootResponse returns the CC API root document. -func (client *Client) RootResponse() (Info, Warnings, error) { var responseBody Info _, warnings, err := client.MakeRequest(RequestParams{ - URL: client.CloudControllerURL, + RequestName: internal.Info, ResponseBody: &responseBody, }) diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal/api_routes.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal/api_routes.go index c095b2d..5ba7ded 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal/api_routes.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal/api_routes.go @@ -138,6 +138,7 @@ const ( PostApplicationActionStartRequest = "PostApplicationActionStart" PostApplicationActionStopRequest = "PostApplicationActionStop" PostApplicationDeploymentActionCancelRequest = "PostApplicationDeploymentActionCancel" + PostApplicationDeploymentActionContinueRequest = "PostApplicationDeploymentActionContinue" PostApplicationDeploymentRequest = "PostApplicationDeployment" PostApplicationProcessActionScaleRequest = "PostApplicationProcessActionScale" PostApplicationRequest = "PostApplication" @@ -178,7 +179,9 @@ const ( ShareRouteRequest = "ShareRouteRequest" UnmapRouteRequest = "UnmapRoute" UnshareRouteRequest = "UnshareRoute" + UpdateRouteRequest = "UpdateRoute" WhoAmI = "WhoAmI" + Info = "Info" ) // APIRoutes is a list of routes used by the router to construct request URLs. @@ -219,6 +222,7 @@ var APIRoutes = map[string]Route{ PostApplicationDeploymentRequest: {Path: "/v3/deployments", Method: http.MethodPost}, GetDeploymentRequest: {Path: "/v3/deployments/:deployment_guid", Method: http.MethodGet}, PostApplicationDeploymentActionCancelRequest: {Path: "/v3/deployments/:deployment_guid/actions/cancel", Method: http.MethodPost}, + PostApplicationDeploymentActionContinueRequest: {Path: "/v3/deployments/:deployment_guid/actions/continue", Method: http.MethodPost}, GetDomainsRequest: {Path: "/v3/domains", Method: http.MethodGet}, PostDomainRequest: {Path: "/v3/domains", Method: http.MethodPost}, DeleteDomainRequest: {Path: "/v3/domains/:domain_guid", Method: http.MethodDelete}, @@ -280,6 +284,7 @@ var APIRoutes = map[string]Route{ PatchRouteRequest: {Path: "/v3/routes/:route_guid", Method: http.MethodPatch}, GetRouteDestinationsRequest: {Path: "/v3/routes/:route_guid/destinations", Method: http.MethodGet}, MapRouteRequest: {Path: "/v3/routes/:route_guid/destinations", Method: http.MethodPost}, + UpdateRouteRequest: {Path: "/v3/routes/:route_guid", Method: http.MethodPatch}, UnmapRouteRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodDelete}, PatchDestinationRequest: {Path: "/v3/routes/:route_guid/destinations/:destination_guid", Method: http.MethodPatch}, ShareRouteRequest: {Path: "/v3/routes/:route_guid/relationships/shared_spaces", Method: http.MethodPost}, @@ -353,4 +358,5 @@ var APIRoutes = map[string]Route{ PostUserRequest: {Path: "/v3/users", Method: http.MethodPost}, DeleteUserRequest: {Path: "/v3/users/:user_guid", Method: http.MethodDelete}, WhoAmI: {Path: "/whoami", Method: http.MethodGet}, + Info: {Path: "/v3/info", Method: http.MethodGet}, } diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/paginate.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/paginate.go index bf87cce..a31fe0e 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/paginate.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/paginate.go @@ -17,14 +17,7 @@ func (requester RealRequester) paginate(request *cloudcontroller.Request, obj in return IncludedResources{}, fullWarningsList, err } - includes.Apps = append(includes.Apps, wrapper.IncludedResources.Apps...) - includes.Users = append(includes.Users, wrapper.IncludedResources.Users...) - includes.Organizations = append(includes.Organizations, wrapper.IncludedResources.Organizations...) - includes.Spaces = append(includes.Spaces, wrapper.IncludedResources.Spaces...) - includes.ServiceBrokers = append(includes.ServiceBrokers, wrapper.IncludedResources.ServiceBrokers...) - includes.ServiceInstances = append(includes.ServiceInstances, wrapper.IncludedResources.ServiceInstances...) - includes.ServiceOfferings = append(includes.ServiceOfferings, wrapper.IncludedResources.ServiceOfferings...) - includes.ServicePlans = append(includes.ServicePlans, wrapper.IncludedResources.ServicePlans...) + includes.Merge(wrapper.IncludedResources) if specificPage || wrapper.NextPage() == "" { break diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/request.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/request.go index dc799fc..65b988a 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/request.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/request.go @@ -3,6 +3,7 @@ package ccv3 import ( "io" "net/http" + "strings" "code.cloudfoundry.org/cli/api/cloudcontroller" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal" @@ -57,6 +58,7 @@ func (requester *RealRequester) newHTTPRequest(passedRequest requestOptions) (*c } request.Header = http.Header{} + if passedRequest.Header != nil { request.Header = passedRequest.Header } @@ -69,9 +71,15 @@ func (requester *RealRequester) newHTTPRequest(passedRequest requestOptions) (*c request.Header.Set("Accept", "application/json") } - if request.Header.Get("Content-Type") == "" { + if !isDownloadDroplet(passedRequest.URL, passedRequest.RequestName) && request.Header.Get("Content-Type") == "" { request.Header.Set("Content-Type", "application/json") + } else if isDownloadDroplet(passedRequest.URL, passedRequest.RequestName) && request.Header.Get("Content-Type") != "" { + request.Header.Del("Content-Type") } return cloudcontroller.NewRequest(request, passedRequest.Body), nil } + +func isDownloadDroplet(URL string, requestName string) bool { + return (strings.Contains(URL, "droplet") && strings.Contains(URL, "download")) || (requestName == internal.GetDropletBitsRequest) +} diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/revisions.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/revisions.go index 67b14a0..d50fca2 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/revisions.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/revisions.go @@ -35,3 +35,14 @@ func (client *Client) GetApplicationRevisionsDeployed(appGUID string) ([]resourc }) return revisions, warnings, err } + +func (client *Client) GetEnvironmentVariablesByURL(url string) (resources.EnvironmentVariables, Warnings, error) { + environmentVariables := make(resources.EnvironmentVariables) + + _, warnings, err := client.MakeRequest(RequestParams{ + URL: url, + ResponseBody: &environmentVariables, + }) + + return environmentVariables, warnings, err +} diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/root.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/root.go new file mode 100644 index 0000000..79eed50 --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/root.go @@ -0,0 +1,143 @@ +package ccv3 + +import ( + "net/http" + + "code.cloudfoundry.org/cli/api/cloudcontroller" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" + "code.cloudfoundry.org/cli/resources" +) + +type RootLinks struct { + // AppSSH is the link for application ssh info. + AppSSH resources.APILink `json:"app_ssh"` + + // CCV3 is the link to the Cloud Controller V3 API. + CCV3 resources.APILink `json:"cloud_controller_v3"` + + // Logging is the link to the Logging API. + Logging resources.APILink `json:"logging"` + + // Logging is the link to the Logging API. + LogCache resources.APILink `json:"log_cache"` + + // NetworkPolicyV1 is the link to the Container to Container Networking + // API. + NetworkPolicyV1 resources.APILink `json:"network_policy_v1"` + + // Routing is the link to the routing API + Routing resources.APILink `json:"routing"` + + // UAA is the link to the UAA API. + UAA resources.APILink `json:"uaa"` + + // Login is the link to the Login API. + Login resources.APILink `json:"login"` +} + +// Root represents a GET response from the '/' endpoint of the cloud +// controller API. +type Root struct { + // Links is a list of top level Cloud Controller APIs. + Links RootLinks `json:"links"` + CFOnK8s bool `json:"cf_on_k8s"` +} + +// AppSSHEndpoint returns the HREF for SSHing into an app container. +func (info Root) AppSSHEndpoint() string { + return info.Links.AppSSH.HREF +} + +// AppSSHHostKeyFingerprint returns the SSH key fingerprint of the SSH proxy +// that brokers connections to application instances. +func (info Root) AppSSHHostKeyFingerprint() string { + return info.Links.AppSSH.Meta.HostKeyFingerprint +} + +// CloudControllerAPIVersion returns the version of the CloudController. +func (info Root) CloudControllerAPIVersion() string { + return info.Links.CCV3.Meta.Version +} + +// LogCache returns the HREF of the Loggregator Traffic Controller. +func (info Root) LogCache() string { + return info.Links.LogCache.HREF +} + +// Logging returns the HREF of the Loggregator Traffic Controller. +func (info Root) Logging() string { + return info.Links.Logging.HREF +} + +// NetworkPolicyV1 returns the HREF of the Container Networking v1 Policy API +func (info Root) NetworkPolicyV1() string { + return info.Links.NetworkPolicyV1.HREF +} + +// OAuthClient returns the oauth client ID of the SSH proxy that brokers +// connections to application instances. +func (info Root) OAuthClient() string { + return info.Links.AppSSH.Meta.OAuthClient +} + +// Routing returns the HREF of the routing API. +func (info Root) Routing() string { + return info.Links.Routing.HREF +} + +// UAA returns the HREF of the UAA server. +func (info Root) UAA() string { + return info.Links.UAA.HREF +} + +// Login returns the HREF of the login server. +func (info Root) Login() string { + return info.Links.Login.HREF +} + +// ResourceLinks represents the information returned back from /v3. +type ResourceLinks map[string]resources.APILink + +// UnmarshalJSON helps unmarshal a Cloud Controller /v3 response. +func (links ResourceLinks) UnmarshalJSON(data []byte) error { + var ccResourceLinks struct { + Links map[string]resources.APILink `json:"links"` + } + err := cloudcontroller.DecodeJSON(data, &ccResourceLinks) + if err != nil { + return err + } + + for key, val := range ccResourceLinks.Links { + links[key] = val + } + + return nil +} + +// GetRoot returns endpoint and API information from /v3. +func (client *Client) GetRoot() (Root, Warnings, error) { + rootResponse, warnings, err := client.RootResponse() + if err != nil { + return Root{}, warnings, err + } + + return rootResponse, warnings, err +} + +// RootResponse returns the CC API root document. +func (client *Client) RootResponse() (Root, Warnings, error) { + var responseBody Root + + _, warnings, err := client.MakeRequest(RequestParams{ + URL: client.CloudControllerURL, + ResponseBody: &responseBody, + }) + + unknownSourceErr, ok := err.(ccerror.UnknownHTTPSourceError) + if ok && unknownSourceErr.StatusCode == http.StatusNotFound { + return Root{}, nil, ccerror.APINotFoundError{URL: client.CloudControllerURL} + } + + return responseBody, warnings, err +} diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/route.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/route.go index afff0af..399bee2 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/route.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/route.go @@ -82,6 +82,24 @@ func (client Client) GetRoutes(query ...Query) ([]resources.Route, Warnings, err return routes, warnings, err } +func (client Client) UpdateRoute(routeGUID string, options map[string]*string) (resources.Route, Warnings, error) { + var responseBody resources.Route + var route = resources.Route{} + var uriParams = internal.Params{"route_guid": routeGUID} + + route.Options = options + + _, warnings, err := client.MakeRequest(RequestParams{ + RequestName: internal.UpdateRouteRequest, + URIParams: uriParams, + RequestBody: route, + ResponseBody: &responseBody, + }) + + return responseBody, warnings, err + +} + func (client Client) MapRoute(routeGUID string, appGUID string, destinationProtocol string) (Warnings, error) { type destinationProcess struct { ProcessType string `json:"process_type"` diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/task.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/task.go index 359ee92..91c9981 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/task.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/task.go @@ -25,6 +25,16 @@ func (client *Client) CreateApplicationTask(appGUID string, task resources.Task) func (client *Client) GetApplicationTasks(appGUID string, query ...Query) ([]resources.Task, Warnings, error) { var tasks []resources.Task + foundPerPageQuery := false + for _, keyVal := range query { + if keyVal.Key == PerPage { + foundPerPageQuery = true + } + } + if !foundPerPageQuery { + query = append(query, Query{Key: PerPage, Values: []string{MaxPerPage}}) + } + _, warnings, err := client.MakeListRequest(RequestParams{ RequestName: internal.GetApplicationTasksRequest, URIParams: internal.Params{"app_guid": appGUID}, diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccversion/minimum_version.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccversion/minimum_version.go index 5158ab1..68f6d37 100644 --- a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccversion/minimum_version.go +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/ccversion/minimum_version.go @@ -15,4 +15,9 @@ const ( MinVersionSpaceSupporterV3 = "3.104.0" MinVersionLogRateLimitingV3 = "3.124.0" // TODO: update this when we have a CAPI release + + MinVersionCNB = "3.168.0" + MinVersionPerRouteOpts = "3.183.0" + + MinVersionCanarySteps = "3.189.0" ) diff --git a/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/wrapper/trace_request.go b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/wrapper/trace_request.go new file mode 100644 index 0000000..73f6fe4 --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/api/cloudcontroller/wrapper/trace_request.go @@ -0,0 +1,31 @@ +package wrapper + +import ( + "code.cloudfoundry.org/cli/api/cloudcontroller" + "code.cloudfoundry.org/cli/api/shared" +) + +// CCTraceHeaderRequest is a wrapper that adds b3 trace headers to requests. +type CCTraceHeaderRequest struct { + headers *shared.TraceHeaders + connection cloudcontroller.Connection +} + +// NewCCTraceHeaderRequest returns a pointer to a CCTraceHeaderRequest wrapper. +func NewCCTraceHeaderRequest(trace string) *CCTraceHeaderRequest { + return &CCTraceHeaderRequest{ + headers: shared.NewTraceHeaders(trace), + } +} + +// Add tracing headers +func (t *CCTraceHeaderRequest) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error { + t.headers.SetHeaders(request.Request) + return t.connection.Make(request, passedResponse) +} + +// Wrap sets the connection in the CCTraceHeaderRequest and returns itself. +func (t *CCTraceHeaderRequest) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection { + t.connection = innerconnection + return t +} diff --git a/vendor/code.cloudfoundry.org/cli/api/router/wrapper/trace_request.go b/vendor/code.cloudfoundry.org/cli/api/router/wrapper/trace_request.go new file mode 100644 index 0000000..a96a1ce --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/api/router/wrapper/trace_request.go @@ -0,0 +1,31 @@ +package wrapper + +import ( + "code.cloudfoundry.org/cli/api/router" + "code.cloudfoundry.org/cli/api/shared" +) + +// RoutingTraceHeaderRequest is a wrapper that adds b3 trace headers to requests. +type RoutingTraceHeaderRequest struct { + headers *shared.TraceHeaders + connection router.Connection +} + +// NewRoutingTraceHeaderRequest returns a pointer to a RoutingTraceHeaderRequest wrapper. +func NewRoutingTraceHeaderRequest(trace string) *RoutingTraceHeaderRequest { + return &RoutingTraceHeaderRequest{ + headers: shared.NewTraceHeaders(trace), + } +} + +// Add tracing headers +func (t *RoutingTraceHeaderRequest) Make(request *router.Request, passedResponse *router.Response) error { + t.headers.SetHeaders(request.Request) + return t.connection.Make(request, passedResponse) +} + +// Wrap sets the connection in the RoutingTraceHeaderRequest and returns itself. +func (t *RoutingTraceHeaderRequest) Wrap(innerconnection router.Connection) router.Connection { + t.connection = innerconnection + return t +} diff --git a/vendor/code.cloudfoundry.org/cli/api/shared/trace_headers.go b/vendor/code.cloudfoundry.org/cli/api/shared/trace_headers.go new file mode 100644 index 0000000..e913b5c --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/api/shared/trace_headers.go @@ -0,0 +1,37 @@ +package shared + +import ( + "net/http" + + "code.cloudfoundry.org/cli/util/trace" +) + +const ( + B3TraceIDHeader = "X-B3-TraceId" + B3SpanIDHeader = "X-B3-SpanId" +) + +// TraceHeaders sets b3 trace headers to requests. +type TraceHeaders struct { + b3trace string +} + +// NewTraceHeaders returns a pointer to a TraceHeaderRequest. +func NewTraceHeaders(trace string) *TraceHeaders { + return &TraceHeaders{ + b3trace: trace, + } +} + +// Add tracing headers if they are not already set. +func (t *TraceHeaders) SetHeaders(request *http.Request) { + // only override the trace headers if they are not already set (e.g. already explicitly set by cf curl) + if request.Header.Get(B3TraceIDHeader) == "" { + request.Header.Add(B3TraceIDHeader, t.b3trace) + } + if request.Header.Get(B3SpanIDHeader) == "" { + request.Header.Add(B3SpanIDHeader, trace.GenerateRandomTraceID(16)) + } + + // request.Header.Add(("B3", request.Header.Get(B3TraceIDHeader)+request.Header.Get(B3SpanIDHeader))) +} diff --git a/vendor/code.cloudfoundry.org/cli/api/uaa/auth.go b/vendor/code.cloudfoundry.org/cli/api/uaa/auth.go index 1e9ddf6..42e7c7c 100644 --- a/vendor/code.cloudfoundry.org/cli/api/uaa/auth.go +++ b/vendor/code.cloudfoundry.org/cli/api/uaa/auth.go @@ -62,6 +62,17 @@ func (client Client) Authenticate(creds map[string]string, origin string, grantT if grantType == constant.GrantTypePassword { request.SetBasicAuth(client.config.UAAOAuthClient(), client.config.UAAOAuthClientSecret()) + } else if grantType == constant.GrantTypeJwtBearer { + // overwrite client authentication in case of provided parameters in cf auth clientid clientsecret or use defaults as done in password grant + clientId := client.config.UAAOAuthClient() + clientSecret := client.config.UAAOAuthClientSecret() + if creds["client_id"] != "" { + clientId = creds["client_id"] + } + if creds["client_secret"] != "" { + clientSecret = creds["client_secret"] + } + request.SetBasicAuth(clientId, clientSecret) } responseBody := AuthResponse{} diff --git a/vendor/code.cloudfoundry.org/cli/api/uaa/constant/grant_type.go b/vendor/code.cloudfoundry.org/cli/api/uaa/constant/grant_type.go index e302d2f..7cc92cc 100644 --- a/vendor/code.cloudfoundry.org/cli/api/uaa/constant/grant_type.go +++ b/vendor/code.cloudfoundry.org/cli/api/uaa/constant/grant_type.go @@ -10,4 +10,6 @@ const ( // GrantTypePassword is used for user's username/password authentication. GrantTypePassword GrantType = "password" GrantTypeRefreshToken GrantType = "refresh_token" + // GrantTypeJwtBearer is used for token based user authentication + GrantTypeJwtBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer" ) diff --git a/vendor/code.cloudfoundry.org/cli/api/uaa/error_converter.go b/vendor/code.cloudfoundry.org/cli/api/uaa/error_converter.go index ebbe950..c5ecb29 100644 --- a/vendor/code.cloudfoundry.org/cli/api/uaa/error_converter.go +++ b/vendor/code.cloudfoundry.org/cli/api/uaa/error_converter.go @@ -53,7 +53,7 @@ func convert(rawHTTPStatusErr RawHTTPStatusError) error { if uaaErrorResponse.Type == "invalid_token" { return InvalidAuthTokenError{Message: uaaErrorResponse.Description} } - if uaaErrorResponse.Type == "unauthorized" { + if uaaErrorResponse.Type == "unauthorized" || uaaErrorResponse.Type == "invalid_client" { if uaaErrorResponse.Description == "Your account has been locked because of too many failed attempts to login." { return AccountLockedError{Message: "Your account has been locked because of too many failed attempts to login."} } diff --git a/vendor/code.cloudfoundry.org/cli/api/uaa/refresh_token.go b/vendor/code.cloudfoundry.org/cli/api/uaa/refresh_token.go index fba19e2..1840714 100644 --- a/vendor/code.cloudfoundry.org/cli/api/uaa/refresh_token.go +++ b/vendor/code.cloudfoundry.org/cli/api/uaa/refresh_token.go @@ -29,7 +29,7 @@ func (client *Client) RefreshAccessToken(refreshToken string) (RefreshedTokens, switch client.config.UAAGrantType() { case string(constant.GrantTypeClientCredentials): values = client.clientCredentialRefreshBody() - case "", string(constant.GrantTypePassword): // CLI used to write empty string for grant type in the case of password; preserve compatibility with old config.json files + case "", string(constant.GrantTypePassword), string(constant.GrantTypeJwtBearer): // CLI used to write empty string for grant type in the case of password; preserve compatibility with old config.json files values = client.refreshTokenBody(refreshToken) } diff --git a/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/trace_request.go b/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/trace_request.go new file mode 100644 index 0000000..dedebf6 --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/trace_request.go @@ -0,0 +1,33 @@ +package wrapper + +import ( + "net/http" + + "code.cloudfoundry.org/cli/api/shared" + "code.cloudfoundry.org/cli/api/uaa" +) + +// UAATraceHeaderRequest is a wrapper that adds b3 trace headers to requests. +type UAATraceHeaderRequest struct { + headers *shared.TraceHeaders + connection uaa.Connection +} + +// NewUAATraceHeaderRequest returns a pointer to a UAATraceHeaderRequest wrapper. +func NewUAATraceHeaderRequest(trace string) *UAATraceHeaderRequest { + return &UAATraceHeaderRequest{ + headers: shared.NewTraceHeaders(trace), + } +} + +// Add tracing headers +func (t *UAATraceHeaderRequest) Make(request *http.Request, passedResponse *uaa.Response) error { + t.headers.SetHeaders(request) + return t.connection.Make(request, passedResponse) +} + +// Wrap sets the connection in the UAATraceHeaderRequest and returns itself. +func (t *UAATraceHeaderRequest) Wrap(innerconnection uaa.Connection) uaa.Connection { + t.connection = innerconnection + return t +} diff --git a/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/uaa_authentication.go b/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/uaa_authentication.go index 96bc7e6..25f25c5 100644 --- a/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/uaa_authentication.go +++ b/vendor/code.cloudfoundry.org/cli/api/uaa/wrapper/uaa_authentication.go @@ -109,5 +109,6 @@ func skipAuthenticationHeader(request *http.Request, body []byte) bool { request.Method == http.MethodPost && (strings.Contains(stringBody, "grant_type=refresh_token") || strings.Contains(stringBody, "grant_type=password") || + strings.Contains(stringBody, "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer") || strings.Contains(stringBody, "grant_type=client_credentials")) } diff --git a/vendor/code.cloudfoundry.org/cli/cf/configuration/coreconfig/config_data.go b/vendor/code.cloudfoundry.org/cli/cf/configuration/coreconfig/config_data.go index a5314a1..f017333 100644 --- a/vendor/code.cloudfoundry.org/cli/cf/configuration/coreconfig/config_data.go +++ b/vendor/code.cloudfoundry.org/cli/cf/configuration/coreconfig/config_data.go @@ -33,6 +33,7 @@ type Data struct { LogCacheEndPoint string MinCLIVersion string MinRecommendedCLIVersion string + NetworkPolicyV1Endpoint string OrganizationFields models.OrganizationFields PluginRepos []models.PluginRepo RefreshToken string diff --git a/vendor/code.cloudfoundry.org/cli/command/config.go b/vendor/code.cloudfoundry.org/cli/command/config.go index 44b30e5..bde3b4a 100644 --- a/vendor/code.cloudfoundry.org/cli/command/config.go +++ b/vendor/code.cloudfoundry.org/cli/command/config.go @@ -15,6 +15,7 @@ type Config interface { AddPluginRepository(name string, url string) AuthorizationEndpoint() string APIVersion() string + B3TraceID() string BinaryName() string BinaryVersion() string CFPassword() string @@ -24,6 +25,7 @@ type Config interface { CurrentUserName() (string, error) DialTimeout() time.Duration DockerPassword() string + CNBCredentials() (map[string]interface{}, error) Experimental() bool GetPlugin(pluginName string) (configv3.Plugin, bool) GetPluginCaseInsensitive(pluginName string) (configv3.Plugin, bool) diff --git a/vendor/code.cloudfoundry.org/cli/command/translatableerror/convert_to_translatable_error.go b/vendor/code.cloudfoundry.org/cli/command/translatableerror/convert_to_translatable_error.go index 4bcacac..f8636a7 100644 --- a/vendor/code.cloudfoundry.org/cli/command/translatableerror/convert_to_translatable_error.go +++ b/vendor/code.cloudfoundry.org/cli/command/translatableerror/convert_to_translatable_error.go @@ -188,6 +188,13 @@ func ConvertToTranslatableError(err error) error { return RunTaskError{Message: "App is not staged."} } + if strings.Contains(e.Message, "Unknown field(s): 'options'") { + return MinimumCFAPIVersionNotMetError{ + Command: "'--max-in-flight' flag", + MinimumVersion: "3.173.0", + } + } + // JSON Errors case *json.SyntaxError: return JSONSyntaxError{Err: e} diff --git a/vendor/code.cloudfoundry.org/cli/command/ui.go b/vendor/code.cloudfoundry.org/cli/command/ui.go index 6c479b8..424c71d 100644 --- a/vendor/code.cloudfoundry.org/cli/command/ui.go +++ b/vendor/code.cloudfoundry.org/cli/command/ui.go @@ -33,6 +33,7 @@ type UI interface { DisplayPasswordPrompt(template string, templateValues ...map[string]interface{}) (string, error) DisplayTableWithHeader(prefix string, table [][]string, padding int) DisplayText(template string, data ...map[string]interface{}) + DisplayTextLiteral(text string) DisplayTextMenu(choices []string, promptTemplate string, templateValues ...map[string]interface{}) (string, error) DisplayTextPrompt(template string, templateValues ...map[string]interface{}) (string, error) DisplayTextWithBold(text string, keys ...map[string]interface{}) diff --git a/vendor/code.cloudfoundry.org/cli/resources/application_resource.go b/vendor/code.cloudfoundry.org/cli/resources/application_resource.go index b7b5c78..2212c19 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/application_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/application_resource.go @@ -25,6 +25,10 @@ type Application struct { SpaceGUID string // State is the desired state of the application. State constant.ApplicationState + // Credentials are used by Cloud Native Buildpacks lifecycle to pull buildpacks + Credentials map[string]interface{} + // CurrentDropletGUID is the unique identifier of the droplet currently attached to the application. + CurrentDropletGUID string } // ApplicationNameOnly represents only the name field of a Cloud Controller V3 Application @@ -40,15 +44,19 @@ func (a Application) MarshalJSON() ([]byte, error) { Metadata: a.Metadata, } + ccApp.Relationships = Relationships{} + if a.SpaceGUID != "" { - ccApp.Relationships = Relationships{ - constant.RelationshipTypeSpace: Relationship{GUID: a.SpaceGUID}, - } + ccApp.Relationships[constant.RelationshipTypeSpace] = Relationship{GUID: a.SpaceGUID} + } + + if a.CurrentDropletGUID != "" { + ccApp.Relationships[constant.RelationshipTypeCurrentDroplet] = Relationship{GUID: a.CurrentDropletGUID} } if a.LifecycleType == constant.AppLifecycleTypeDocker { ccApp.setDockerLifecycle() - } else if a.LifecycleType == constant.AppLifecycleTypeBuildpack { + } else if a.LifecycleType == constant.AppLifecycleTypeBuildpack || a.LifecycleType == constant.AppLifecycleTypeCNB { if len(a.LifecycleBuildpacks) > 0 || a.StackName != "" { if a.hasAutodetectedBuildpack() { ccApp.setAutodetectedBuildpackLifecycle(a) @@ -79,6 +87,9 @@ func (a *Application) UnmarshalJSON(data []byte) error { a.LifecycleType = lifecycle.Type a.Name = ccApp.Name a.SpaceGUID = ccApp.Relationships[constant.RelationshipTypeSpace].GUID + if _, ok := ccApp.Relationships[constant.RelationshipTypeCurrentDroplet]; ok { + a.CurrentDropletGUID = ccApp.Relationships[constant.RelationshipTypeCurrentDroplet].GUID + } a.State = ccApp.State a.Metadata = ccApp.Metadata @@ -100,11 +111,18 @@ func (a Application) hasAutodetectedBuildpack() bool { return a.LifecycleBuildpacks[0] == constant.AutodetectBuildpackValueDefault || a.LifecycleBuildpacks[0] == constant.AutodetectBuildpackValueNull } +type ccCredentials map[string]interface{} + +func (ccCredentials) UnmarshalJSON(data []byte) error { + return nil +} + type ccLifecycle struct { Type constant.AppLifecycleType `json:"type,omitempty"` Data struct { - Buildpacks []string `json:"buildpacks,omitempty"` - Stack string `json:"stack,omitempty"` + Buildpacks []string `json:"buildpacks,omitempty"` + Stack string `json:"stack,omitempty"` + Credentials ccCredentials `json:"credentials,omitempty"` } `json:"data"` } @@ -135,6 +153,7 @@ func (ccApp *ccApplication) setBuildpackLifecycle(a Application) { lifecycle.Type = a.LifecycleType lifecycle.Data.Buildpacks = a.LifecycleBuildpacks lifecycle.Data.Stack = a.StackName + lifecycle.Data.Credentials = a.Credentials ccApp.Lifecycle = lifecycle } diff --git a/vendor/code.cloudfoundry.org/cli/resources/deployment_resource.go b/vendor/code.cloudfoundry.org/cli/resources/deployment_resource.go index 144ac07..65f9755 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/deployment_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/deployment_resource.go @@ -8,16 +8,37 @@ import ( ) type Deployment struct { - GUID string - State constant.DeploymentState - StatusValue constant.DeploymentStatusValue - StatusReason constant.DeploymentStatusReason - RevisionGUID string - DropletGUID string - CreatedAt string - UpdatedAt string - Relationships Relationships - NewProcesses []Process + GUID string + State constant.DeploymentState + StatusValue constant.DeploymentStatusValue + StatusReason constant.DeploymentStatusReason + CanaryStatus CanaryStatus + LastStatusChange string + Options DeploymentOpts + RevisionGUID string + DropletGUID string + CreatedAt string + UpdatedAt string + Relationships Relationships + NewProcesses []Process + Strategy constant.DeploymentStrategy +} + +type DeploymentOpts struct { + MaxInFlight int `json:"max_in_flight,omitempty"` + CanaryDeploymentOptions *CanaryDeploymentOptions `json:"canary,omitempty"` +} + +func (d DeploymentOpts) IsEmpty() bool { + return d.MaxInFlight == 0 && (d.CanaryDeploymentOptions == nil || len(d.CanaryDeploymentOptions.Steps) == 0) +} + +type CanaryDeploymentOptions struct { + Steps []CanaryStep `json:"steps"` +} + +type CanaryStep struct { + InstanceWeight int64 `json:"instance_weight"` } // MarshalJSON converts a Deployment into a Cloud Controller Deployment. @@ -30,9 +51,11 @@ func (d Deployment) MarshalJSON() ([]byte, error) { } var ccDeployment struct { - Droplet *Droplet `json:"droplet,omitempty"` - Revision *Revision `json:"revision,omitempty"` - Relationships Relationships `json:"relationships,omitempty"` + Droplet *Droplet `json:"droplet,omitempty"` + Options *DeploymentOpts `json:"options,omitempty"` + Revision *Revision `json:"revision,omitempty"` + Strategy constant.DeploymentStrategy `json:"strategy,omitempty"` + Relationships Relationships `json:"relationships,omitempty"` } if d.DropletGUID != "" { @@ -43,11 +66,28 @@ func (d Deployment) MarshalJSON() ([]byte, error) { ccDeployment.Revision = &Revision{d.RevisionGUID} } + if d.Strategy != "" { + ccDeployment.Strategy = d.Strategy + } + + if !d.Options.IsEmpty() { + ccDeployment.Options = &d.Options + } + ccDeployment.Relationships = d.Relationships return json.Marshal(ccDeployment) } +type CanaryStepStatus struct { + CurrentStep int `json:"current"` + TotalSteps int `json:"total"` +} + +type CanaryStatus struct { + Steps CanaryStepStatus `json:"steps"` +} + // UnmarshalJSON helps unmarshal a Cloud Controller Deployment response. func (d *Deployment) UnmarshalJSON(data []byte) error { var ccDeployment struct { @@ -56,12 +96,19 @@ func (d *Deployment) UnmarshalJSON(data []byte) error { Relationships Relationships `json:"relationships,omitempty"` State constant.DeploymentState `json:"state,omitempty"` Status struct { - Value constant.DeploymentStatusValue `json:"value"` - Reason constant.DeploymentStatusReason `json:"reason"` + Details struct { + LastStatusChange string `json:"last_status_change"` + } + Value constant.DeploymentStatusValue `json:"value"` + Reason constant.DeploymentStatusReason `json:"reason"` + CanaryStatus CanaryStatus `json:"canary,omitempty"` } `json:"status"` - Droplet Droplet `json:"droplet,omitempty"` - NewProcesses []Process `json:"new_processes,omitempty"` + Droplet Droplet `json:"droplet,omitempty"` + NewProcesses []Process `json:"new_processes,omitempty"` + Strategy constant.DeploymentStrategy `json:"strategy"` + Options DeploymentOpts `json:"options,omitempty"` } + err := cloudcontroller.DecodeJSON(data, &ccDeployment) if err != nil { return err @@ -73,8 +120,12 @@ func (d *Deployment) UnmarshalJSON(data []byte) error { d.State = ccDeployment.State d.StatusValue = ccDeployment.Status.Value d.StatusReason = ccDeployment.Status.Reason + d.CanaryStatus = ccDeployment.Status.CanaryStatus + d.LastStatusChange = ccDeployment.Status.Details.LastStatusChange d.DropletGUID = ccDeployment.Droplet.GUID d.NewProcesses = ccDeployment.NewProcesses + d.Strategy = ccDeployment.Strategy + d.Options = ccDeployment.Options return nil } diff --git a/vendor/code.cloudfoundry.org/cli/resources/droplet_resource.go b/vendor/code.cloudfoundry.org/cli/resources/droplet_resource.go index 27dc257..acd9f1f 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/droplet_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/droplet_resource.go @@ -1,12 +1,17 @@ package resources import ( + "encoding/json" + + "code.cloudfoundry.org/cli/api/cloudcontroller" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" ) // Droplet represents a Cloud Controller droplet's metadata. A droplet is a set of // compiled bits for a given application. type Droplet struct { + // AppGUID is the unique identifier of the application associated with the droplet. + AppGUID string `json:"app_guid"` //Buildpacks are the detected buildpacks from the staging process. Buildpacks []DropletBuildpack `json:"buildpacks,omitempty"` // CreatedAt is the timestamp that the Cloud Controller created the droplet. @@ -35,3 +40,87 @@ type DropletBuildpack struct { // Version is the version of the detected buildpack. Version string `json:"version"` } + +func (d Droplet) MarshallJSON() ([]byte, error) { + type ccDroplet struct { + GUID string `json:"guid,omitempty"` + Buildpacks []DropletBuildpack `json:"buildpacks,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Image string `json:"image,omitempty"` + Stack string `json:"stack,omitempty"` + State constant.DropletState `json:"state,omitempty"` + Relationships *struct { + App struct { + Data struct { + GUID string `json:"guid,omitempty"` + } `json:"data,omitempty"` + } `json:"app,omitempty"` + } `json:"relationships,omitempty"` + } + + ccD := ccDroplet{ + GUID: d.GUID, + Buildpacks: d.Buildpacks, + CreatedAt: d.CreatedAt, + Image: d.Image, + Stack: d.Stack, + State: d.State, + } + + if d.AppGUID != "" { + ccD.Relationships = &struct { + App struct { + Data struct { + GUID string `json:"guid,omitempty"` + } `json:"data,omitempty"` + } `json:"app,omitempty"` + }{ + App: struct { + Data struct { + GUID string `json:"guid,omitempty"` + } `json:"data,omitempty"` + }{ + Data: struct { + GUID string `json:"guid,omitempty"` + }{ + GUID: d.AppGUID, + }, + }, + } + } + + return json.Marshal(ccD) +} + +func (d *Droplet) UnmarshalJSON(data []byte) error { + var alias struct { + GUID string `json:"guid,omitempty"` + Buildpacks []DropletBuildpack `json:"buildpacks,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + Image string `json:"image,omitempty"` + Stack string `json:"stack,omitempty"` + State constant.DropletState `json:"state,omitempty"` + Relationships struct { + App struct { + Data struct { + GUID string `json:"guid,omitempty"` + } `json:"data,omitempty"` + } `json:"app,omitempty"` + } + } + + err := cloudcontroller.DecodeJSON(data, &alias) + if err != nil { + return err + } + + d.GUID = alias.GUID + d.Buildpacks = alias.Buildpacks + d.CreatedAt = alias.CreatedAt + d.Image = alias.Image + d.Stack = alias.Stack + d.State = alias.State + d.AppGUID = alias.Relationships.App.Data.GUID + + return nil +} diff --git a/vendor/code.cloudfoundry.org/cli/resources/metadata_resource.go b/vendor/code.cloudfoundry.org/cli/resources/metadata_resource.go index 414fe14..afa1c18 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/metadata_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/metadata_resource.go @@ -3,7 +3,8 @@ package resources import "code.cloudfoundry.org/cli/types" type Metadata struct { - Labels map[string]types.NullString `json:"labels,omitempty"` + Annotations map[string]types.NullString `json:"annotations,omitempty"` + Labels map[string]types.NullString `json:"labels,omitempty"` } type ResourceMetadata struct { diff --git a/vendor/code.cloudfoundry.org/cli/resources/options_resource.go b/vendor/code.cloudfoundry.org/cli/resources/options_resource.go new file mode 100644 index 0000000..1730b9d --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/resources/options_resource.go @@ -0,0 +1,24 @@ +package resources + +import "strings" + +func CreateRouteOptions(options []string) (map[string]*string, *string) { + routeOptions := map[string]*string{} + for _, option := range options { + key, value, found := strings.Cut(option, "=") + if found { + routeOptions[key] = &value + } else { + return routeOptions, &option + } + } + return routeOptions, nil +} + +func RemoveRouteOptions(options []string) map[string]*string { + routeOptions := map[string]*string{} + for _, option := range options { + routeOptions[option] = nil + } + return routeOptions +} diff --git a/vendor/code.cloudfoundry.org/cli/resources/process_resource.go b/vendor/code.cloudfoundry.org/cli/resources/process_resource.go index afbf20a..8eb5916 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/process_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/process_resource.go @@ -13,16 +13,20 @@ type Process struct { GUID string Type string // Command is the process start command. Note: This value will be obfuscated when obtained from listing. - Command types.FilteredString - HealthCheckType constant.HealthCheckType - HealthCheckEndpoint string - HealthCheckInvocationTimeout int64 - HealthCheckTimeout int64 - Instances types.NullInt - MemoryInMB types.NullUint64 - DiskInMB types.NullUint64 - LogRateLimitInBPS types.NullInt - AppGUID string + Command types.FilteredString + HealthCheckType constant.HealthCheckType + HealthCheckEndpoint string + HealthCheckInvocationTimeout int64 + HealthCheckTimeout int64 + ReadinessHealthCheckType constant.HealthCheckType + ReadinessHealthCheckEndpoint string + ReadinessHealthCheckInvocationTimeout int64 + ReadinessHealthCheckInterval int64 + Instances types.NullInt + MemoryInMB types.NullUint64 + DiskInMB types.NullUint64 + LogRateLimitInBPS types.NullInt + AppGUID string } func (p Process) MarshalJSON() ([]byte, error) { @@ -34,6 +38,7 @@ func (p Process) MarshalJSON() ([]byte, error) { marshalDisk(p, &ccProcess) marshalLogRateLimit(p, &ccProcess) marshalHealthCheck(p, &ccProcess) + marshalReadinessHealthCheck(p, &ccProcess) return json.Marshal(ccProcess) } @@ -57,6 +62,15 @@ func (p *Process) UnmarshalJSON(data []byte) error { Timeout int64 `json:"timeout"` } `json:"data"` } `json:"health_check"` + + ReadinessHealthCheck struct { + Type constant.HealthCheckType `json:"type"` + Data struct { + Endpoint string `json:"endpoint"` + InvocationTimeout int64 `json:"invocation_timeout"` + Interval int64 `json:"interval"` + } `json:"data"` + } `json:"readiness_health_check"` } err := cloudcontroller.DecodeJSON(data, &ccProcess) @@ -71,6 +85,10 @@ func (p *Process) UnmarshalJSON(data []byte) error { p.HealthCheckInvocationTimeout = ccProcess.HealthCheck.Data.InvocationTimeout p.HealthCheckTimeout = ccProcess.HealthCheck.Data.Timeout p.HealthCheckType = ccProcess.HealthCheck.Type + p.ReadinessHealthCheckEndpoint = ccProcess.ReadinessHealthCheck.Data.Endpoint + p.ReadinessHealthCheckType = ccProcess.ReadinessHealthCheck.Type + p.ReadinessHealthCheckInvocationTimeout = ccProcess.ReadinessHealthCheck.Data.InvocationTimeout + p.ReadinessHealthCheckInterval = ccProcess.ReadinessHealthCheck.Data.Interval p.Instances = ccProcess.Instances p.MemoryInMB = ccProcess.MemoryInMB p.LogRateLimitInBPS = ccProcess.LogRateLimitInBPS @@ -89,6 +107,15 @@ type healthCheck struct { } `json:"data"` } +type readinessHealthCheck struct { + Type constant.HealthCheckType `json:"type,omitempty"` + Data struct { + Endpoint interface{} `json:"endpoint,omitempty"` + InvocationTimeout int64 `json:"invocation_timeout,omitempty"` + Interval int64 `json:"interval,omitempty"` + } `json:"data"` +} + type marshalProcess struct { Command interface{} `json:"command,omitempty"` Instances json.Number `json:"instances,omitempty"` @@ -96,7 +123,8 @@ type marshalProcess struct { DiskInMB json.Number `json:"disk_in_mb,omitempty"` LogRateLimitInBPS json.Number `json:"log_rate_limit_in_bytes_per_second,omitempty"` - HealthCheck *healthCheck `json:"health_check,omitempty"` + HealthCheck *healthCheck `json:"health_check,omitempty"` + ReadinessHealthCheck *readinessHealthCheck `json:"readiness_health_check,omitempty"` } func marshalCommand(p Process, ccProcess *marshalProcess) { @@ -123,6 +151,18 @@ func marshalHealthCheck(p Process, ccProcess *marshalProcess) { } } +func marshalReadinessHealthCheck(p Process, ccProcess *marshalProcess) { + if p.ReadinessHealthCheckType != "" || p.ReadinessHealthCheckEndpoint != "" || p.ReadinessHealthCheckInvocationTimeout != 0 { + ccProcess.ReadinessHealthCheck = new(readinessHealthCheck) + ccProcess.ReadinessHealthCheck.Type = p.ReadinessHealthCheckType + ccProcess.ReadinessHealthCheck.Data.InvocationTimeout = p.ReadinessHealthCheckInvocationTimeout + ccProcess.ReadinessHealthCheck.Data.Interval = p.ReadinessHealthCheckInterval + if p.ReadinessHealthCheckEndpoint != "" { + ccProcess.ReadinessHealthCheck.Data.Endpoint = p.ReadinessHealthCheckEndpoint + } + } +} + func marshalInstances(p Process, ccProcess *marshalProcess) { if p.Instances.IsSet { ccProcess.Instances = json.Number(fmt.Sprint(p.Instances.Value)) diff --git a/vendor/code.cloudfoundry.org/cli/resources/revision_resource.go b/vendor/code.cloudfoundry.org/cli/resources/revision_resource.go index 39d577a..e187c95 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/revision_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/revision_resource.go @@ -1,11 +1,13 @@ package resources type Revision struct { - GUID string `json:"guid"` - Version int `json:"version"` - Deployable bool `json:"deployable"` - Description string `json:"description"` - Droplet Droplet `json:"droplet"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` + GUID string `json:"guid"` + Version int `json:"version"` + Deployable bool `json:"deployable"` + Description string `json:"description"` + Droplet Droplet `json:"droplet"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + Links APILinks `json:"links"` + Metadata *Metadata `json:"metadata,omitempty"` } diff --git a/vendor/code.cloudfoundry.org/cli/resources/route_resource.go b/vendor/code.cloudfoundry.org/cli/resources/route_resource.go index 5bf31b4..6ec9efc 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/route_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/route_resource.go @@ -2,6 +2,7 @@ package resources import ( "encoding/json" + "strings" "code.cloudfoundry.org/cli/api/cloudcontroller" ) @@ -31,6 +32,7 @@ type Route struct { URL string Destinations []RouteDestination Metadata *Metadata + Options map[string]*string } func (r Route) MarshalJSON() ([]byte, error) { @@ -49,12 +51,13 @@ func (r Route) MarshalJSON() ([]byte, error) { // Building up the request body in ccRoute type ccRoute struct { - GUID string `json:"guid,omitempty"` - Host string `json:"host,omitempty"` - Path string `json:"path,omitempty"` - Protocol string `json:"protocol,omitempty"` - Port int `json:"port,omitempty"` - Relationships *Relationships `json:"relationships,omitempty"` + GUID string `json:"guid,omitempty"` + Host string `json:"host,omitempty"` + Path string `json:"path,omitempty"` + Protocol string `json:"protocol,omitempty"` + Port int `json:"port,omitempty"` + Relationships *Relationships `json:"relationships,omitempty"` + Options map[string]*string `json:"options,omitempty"` } ccR := ccRoute{ @@ -63,6 +66,7 @@ func (r Route) MarshalJSON() ([]byte, error) { Path: r.Path, Protocol: r.Protocol, Port: r.Port, + Options: r.Options, } if r.SpaceGUID != "" { @@ -85,6 +89,7 @@ func (r *Route) UnmarshalJSON(data []byte) error { URL string `json:"url,omitempty"` Destinations []RouteDestination `json:"destinations,omitempty"` Metadata *Metadata `json:"metadata,omitempty"` + Options map[string]*string `json:"options,omitempty"` Relationships struct { Space struct { @@ -115,6 +120,19 @@ func (r *Route) UnmarshalJSON(data []byte) error { r.URL = alias.URL r.Destinations = alias.Destinations r.Metadata = alias.Metadata + r.Options = alias.Options return nil } + +func (r *Route) FormattedOptions() string { + var routeOpts = []string{} + formattedOptions := "" + if r.Options != nil && len(r.Options) > 0 { + for optKey, optVal := range r.Options { + routeOpts = append(routeOpts, optKey+"="+*optVal) + } + formattedOptions = " {" + strings.Join(routeOpts, ", ") + "}" + } + return formattedOptions +} diff --git a/vendor/code.cloudfoundry.org/cli/resources/task_resource.go b/vendor/code.cloudfoundry.org/cli/resources/task_resource.go index 62f1f50..6a0184f 100644 --- a/vendor/code.cloudfoundry.org/cli/resources/task_resource.go +++ b/vendor/code.cloudfoundry.org/cli/resources/task_resource.go @@ -32,6 +32,9 @@ type Task struct { // Using a pointer so that it can be set to nil to prevent // json serialization when no template is used Template *TaskTemplate `json:"template,omitempty"` + + // Result contains the task result + Result *TaskResult `json:"result,omitempty"` } type TaskTemplate struct { @@ -41,3 +44,7 @@ type TaskTemplate struct { type TaskProcessTemplate struct { Guid string `json:"guid,omitempty"` } + +type TaskResult struct { + FailureReason string `json:"failure_reason,omitempty"` +} diff --git a/vendor/code.cloudfoundry.org/cli/util/clissh/ssh.go b/vendor/code.cloudfoundry.org/cli/util/clissh/ssh.go index a6f32ce..b4f2921 100644 --- a/vendor/code.cloudfoundry.org/cli/util/clissh/ssh.go +++ b/vendor/code.cloudfoundry.org/cli/util/clissh/ssh.go @@ -5,6 +5,7 @@ import ( "crypto/sha1" "crypto/sha256" "encoding/base64" + "encoding/hex" "errors" "fmt" "io" @@ -28,6 +29,7 @@ const ( md5FingerprintLength = 47 // inclusive of space between bytes hexSha1FingerprintLength = 59 // inclusive of space between bytes base64Sha256FingerprintLength = 43 + sha256FingerprintLength = 64 DefaultKeepAliveInterval = 30 * time.Second ) @@ -331,9 +333,12 @@ func (c *SecureShell) terminalType() string { return term } -func base64Sha256Fingerprint(key ssh.PublicKey) string { +func sha256Fingerprint(key ssh.PublicKey, encode bool) string { sum := sha256.Sum256(key.Marshal()) - return base64.RawStdEncoding.EncodeToString(sum[:]) + if encode { + return base64.RawStdEncoding.EncodeToString(sum[:]) + } + return hex.EncodeToString(sum[:]) } func copyAndClose(wg *sync.WaitGroup, dest io.WriteCloser, src io.Reader) { @@ -364,8 +369,10 @@ func fingerprintCallback(skipHostValidation bool, expectedFingerprint string) ss var fingerprint string switch len(expectedFingerprint) { + case sha256FingerprintLength: + fingerprint = sha256Fingerprint(key, false) case base64Sha256FingerprintLength: - fingerprint = base64Sha256Fingerprint(key) + fingerprint = sha256Fingerprint(key, true) case hexSha1FingerprintLength: fingerprint = hexSha1Fingerprint(key) case md5FingerprintLength: diff --git a/vendor/code.cloudfoundry.org/cli/util/configv3/env.go b/vendor/code.cloudfoundry.org/cli/util/configv3/env.go index efd935e..75e198c 100644 --- a/vendor/code.cloudfoundry.org/cli/util/configv3/env.go +++ b/vendor/code.cloudfoundry.org/cli/util/configv3/env.go @@ -1,9 +1,12 @@ package configv3 import ( + "encoding/json" "strconv" "strings" "time" + + "code.cloudfoundry.org/cli/util/trace" ) // EnvOverride represents all the environment variables read by the CF CLI @@ -19,7 +22,9 @@ type EnvOverride struct { CFStartupTimeout string CFTrace string CFUsername string + CFB3TraceID string DockerPassword string + CNBCredentials string Experimental string ForceTTY string HTTPSProxy string @@ -61,6 +66,21 @@ func (config *Config) DockerPassword() string { return config.ENV.DockerPassword } +// CNBCredentials retrurns CNB credentials from the environment +func (config *Config) CNBCredentials() (map[string]interface{}, error) { + if config.ENV.CNBCredentials == "" { + return nil, nil + } + + creds := map[string]interface{}{} + + if err := json.Unmarshal([]byte(config.ENV.CNBCredentials), &creds); err != nil { + return nil, err + } + + return creds, nil +} + // Experimental returns whether or not to run experimental CLI commands. This // is based on the following: // 1. The $CF_CLI_EXPERIMENTAL environment variable if set @@ -143,3 +163,10 @@ func (config *Config) StartupTimeout() time.Duration { return DefaultStartupTimeout } + +func (config *Config) B3TraceID() string { + if config.ENV.CFB3TraceID == "" { + config.ENV.CFB3TraceID = trace.GenerateUUIDTraceID() + } + return config.ENV.CFB3TraceID +} diff --git a/vendor/code.cloudfoundry.org/cli/util/configv3/load_config.go b/vendor/code.cloudfoundry.org/cli/util/configv3/load_config.go index c57b845..b6ee0fa 100644 --- a/vendor/code.cloudfoundry.org/cli/util/configv3/load_config.go +++ b/vendor/code.cloudfoundry.org/cli/util/configv3/load_config.go @@ -127,7 +127,9 @@ func LoadConfig(flags ...FlagOverride) (*Config, error) { CFStartupTimeout: os.Getenv("CF_STARTUP_TIMEOUT"), CFTrace: os.Getenv("CF_TRACE"), CFUsername: os.Getenv("CF_USERNAME"), + CFB3TraceID: os.Getenv("CF_B3_TRACE_ID"), DockerPassword: os.Getenv("CF_DOCKER_PASSWORD"), + CNBCredentials: os.Getenv("CF_CNB_REGISTRY_CREDS"), Experimental: os.Getenv("CF_CLI_EXPERIMENTAL"), ForceTTY: os.Getenv("FORCE_TTY"), HTTPSProxy: os.Getenv("https_proxy"), diff --git a/vendor/code.cloudfoundry.org/cli/util/trace/trace.go b/vendor/code.cloudfoundry.org/cli/util/trace/trace.go new file mode 100644 index 0000000..3bd530f --- /dev/null +++ b/vendor/code.cloudfoundry.org/cli/util/trace/trace.go @@ -0,0 +1,25 @@ +package trace + +import ( + "crypto/rand" + "encoding/hex" + "strings" + + "github.com/google/uuid" +) + +// GenerateUUIDTraceID returns a UUID v4 string with the dashes removed as a 32 lower-hex encoded string. +func GenerateUUIDTraceID() string { + uuidV4 := uuid.New() + return strings.ReplaceAll(uuidV4.String(), "-", "") +} + +// GenerateRandomTraceID returns a random hex string of the given length. +func GenerateRandomTraceID(length int) string { + b := make([]byte, length/2) + if _, err := rand.Read(b); err != nil { + panic(err) + } + + return hex.EncodeToString(b) +} diff --git a/vendor/code.cloudfoundry.org/cli/util/ui/request_logger_file_writer.go b/vendor/code.cloudfoundry.org/cli/util/ui/request_logger_file_writer.go index a2d7aca..347c556 100644 --- a/vendor/code.cloudfoundry.org/cli/util/ui/request_logger_file_writer.go +++ b/vendor/code.cloudfoundry.org/cli/util/ui/request_logger_file_writer.go @@ -29,7 +29,7 @@ func newRequestLoggerFileWriter(ui *UI, lock *sync.Mutex, filePaths []string) *R func (display *RequestLoggerFileWriter) DisplayBody([]byte) error { for _, logFile := range display.logFiles { - _, err := logFile.WriteString(RedactedValue) + _, err := logFile.WriteString(fmt.Sprintf("%s\n", RedactedValue)) if err != nil { return err } diff --git a/vendor/code.cloudfoundry.org/cli/util/ui/ui.go b/vendor/code.cloudfoundry.org/cli/util/ui/ui.go index c2a634a..7d51d6b 100644 --- a/vendor/code.cloudfoundry.org/cli/util/ui/ui.go +++ b/vendor/code.cloudfoundry.org/cli/util/ui/ui.go @@ -248,6 +248,15 @@ func (ui *UI) DisplayText(template string, templateValues ...map[string]interfac fmt.Fprintf(ui.Out, "%s\n", ui.TranslateText(template, templateValues...)) } +// DisplayTextLiteral outputs the text to ui.Out without modification. +// This function should only be used when no translation or templating is required. +func (ui *UI) DisplayTextLiteral(text string) { + ui.terminalLock.Lock() + defer ui.terminalLock.Unlock() + + fmt.Fprintf(ui.Out, "%s\n", text) +} + // DisplayTextWithBold translates the template, bolds the templateValues, // substitutes templateValues into the template, and outputs // the result to ui.Out. Only the first map in templateValues is used. diff --git a/vendor/code.cloudfoundry.org/cli/version/version.go b/vendor/code.cloudfoundry.org/cli/version/version.go index 47a77f8..4878c51 100644 --- a/vendor/code.cloudfoundry.org/cli/version/version.go +++ b/vendor/code.cloudfoundry.org/cli/version/version.go @@ -1,6 +1,10 @@ package version -import "github.com/blang/semver/v4" +import ( + "strings" + + "github.com/blang/semver/v4" +) const DefaultVersion = "0.0.0-unknown-version" @@ -11,6 +15,8 @@ var ( ) func VersionString() string { + // Remove the "v" prefix from the binary in case it is present + binaryVersion = strings.TrimPrefix(binaryVersion, "v") versionString, err := semver.Make(binaryVersion) if err != nil { versionString = semver.MustParse(DefaultVersion) diff --git a/vendor/github.com/google/gofuzz/.travis.yml b/vendor/github.com/google/gofuzz/.travis.yml deleted file mode 100644 index 061d72a..0000000 --- a/vendor/github.com/google/gofuzz/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go - -go: - - 1.11.x - - 1.12.x - - 1.13.x - - master - -script: - - go test -cover diff --git a/vendor/github.com/google/gofuzz/CONTRIBUTING.md b/vendor/github.com/google/gofuzz/CONTRIBUTING.md deleted file mode 100644 index 97c1b34..0000000 --- a/vendor/github.com/google/gofuzz/CONTRIBUTING.md +++ /dev/null @@ -1,67 +0,0 @@ -# How to contribute # - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - - -## Contributor License Agreement ## - -Contributions to any Google project must be accompanied by a Contributor -License Agreement. This is not a copyright **assignment**, it simply gives -Google permission to use and redistribute your contributions as part of the -project. - - * If you are an individual writing original source code and you're sure you - own the intellectual property, then you'll need to sign an [individual - CLA][]. - - * If you work for a company that wants to allow you to contribute your work, - then you'll need to sign a [corporate CLA][]. - -You generally only need to submit a CLA once, so if you've already submitted -one (even if it was for a different project), you probably don't need to do it -again. - -[individual CLA]: https://developers.google.com/open-source/cla/individual -[corporate CLA]: https://developers.google.com/open-source/cla/corporate - - -## Submitting a patch ## - - 1. It's generally best to start by opening a new issue describing the bug or - feature you're intending to fix. Even if you think it's relatively minor, - it's helpful to know what people are working on. Mention in the initial - issue that you are planning to work on that bug or feature so that it can - be assigned to you. - - 1. Follow the normal process of [forking][] the project, and setup a new - branch to work in. It's important that each group of changes be done in - separate branches in order to ensure that a pull request only includes the - commits related to that bug or feature. - - 1. Go makes it very simple to ensure properly formatted code, so always run - `go fmt` on your code before committing it. You should also run - [golint][] over your code. As noted in the [golint readme][], it's not - strictly necessary that your code be completely "lint-free", but this will - help you find common style issues. - - 1. Any significant changes should almost always be accompanied by tests. The - project already has good test coverage, so look at some of the existing - tests if you're unsure how to go about it. [gocov][] and [gocov-html][] - are invaluable tools for seeing which parts of your code aren't being - exercised by your tests. - - 1. Do your best to have [well-formed commit messages][] for each change. - This provides consistency throughout the project, and ensures that commit - messages are able to be formatted properly by various git tools. - - 1. Finally, push the commits to your fork and submit a [pull request][]. - -[forking]: https://help.github.com/articles/fork-a-repo -[golint]: https://github.com/golang/lint -[golint readme]: https://github.com/golang/lint/blob/master/README -[gocov]: https://github.com/axw/gocov -[gocov-html]: https://github.com/matm/gocov-html -[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits -[pull request]: https://help.github.com/articles/creating-a-pull-request diff --git a/vendor/github.com/google/gofuzz/doc.go b/vendor/github.com/google/gofuzz/doc.go deleted file mode 100644 index 9f9956d..0000000 --- a/vendor/github.com/google/gofuzz/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -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 fuzz is a library for populating go objects with random values. -package fuzz diff --git a/vendor/github.com/google/gofuzz/fuzz.go b/vendor/github.com/google/gofuzz/fuzz.go deleted file mode 100644 index 761520a..0000000 --- a/vendor/github.com/google/gofuzz/fuzz.go +++ /dev/null @@ -1,605 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -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 fuzz - -import ( - "fmt" - "math/rand" - "reflect" - "regexp" - "time" - - "github.com/google/gofuzz/bytesource" - "strings" -) - -// fuzzFuncMap is a map from a type to a fuzzFunc that handles that type. -type fuzzFuncMap map[reflect.Type]reflect.Value - -// Fuzzer knows how to fill any object with random fields. -type Fuzzer struct { - fuzzFuncs fuzzFuncMap - defaultFuzzFuncs fuzzFuncMap - r *rand.Rand - nilChance float64 - minElements int - maxElements int - maxDepth int - skipFieldPatterns []*regexp.Regexp -} - -// New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs, -// RandSource, NilChance, or NumElements in any order. -func New() *Fuzzer { - return NewWithSeed(time.Now().UnixNano()) -} - -func NewWithSeed(seed int64) *Fuzzer { - f := &Fuzzer{ - defaultFuzzFuncs: fuzzFuncMap{ - reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime), - }, - - fuzzFuncs: fuzzFuncMap{}, - r: rand.New(rand.NewSource(seed)), - nilChance: .2, - minElements: 1, - maxElements: 10, - maxDepth: 100, - } - return f -} - -// NewFromGoFuzz is a helper function that enables using gofuzz (this -// project) with go-fuzz (https://github.com/dvyukov/go-fuzz) for continuous -// fuzzing. Essentially, it enables translating the fuzzing bytes from -// go-fuzz to any Go object using this library. -// -// This implementation promises a constant translation from a given slice of -// bytes to the fuzzed objects. This promise will remain over future -// versions of Go and of this library. -// -// Note: the returned Fuzzer should not be shared between multiple goroutines, -// as its deterministic output will no longer be available. -// -// Example: use go-fuzz to test the function `MyFunc(int)` in the package -// `mypackage`. Add the file: "mypacakge_fuzz.go" with the content: -// -// // +build gofuzz -// package mypacakge -// import fuzz "github.com/google/gofuzz" -// func Fuzz(data []byte) int { -// var i int -// fuzz.NewFromGoFuzz(data).Fuzz(&i) -// MyFunc(i) -// return 0 -// } -func NewFromGoFuzz(data []byte) *Fuzzer { - return New().RandSource(bytesource.New(data)) -} - -// Funcs adds each entry in fuzzFuncs as a custom fuzzing function. -// -// Each entry in fuzzFuncs must be a function taking two parameters. -// The first parameter must be a pointer or map. It is the variable that -// function will fill with random data. The second parameter must be a -// fuzz.Continue, which will provide a source of randomness and a way -// to automatically continue fuzzing smaller pieces of the first parameter. -// -// These functions are called sensibly, e.g., if you wanted custom string -// fuzzing, the function `func(s *string, c fuzz.Continue)` would get -// called and passed the address of strings. Maps and pointers will always -// be made/new'd for you, ignoring the NilChange option. For slices, it -// doesn't make much sense to pre-create them--Fuzzer doesn't know how -// long you want your slice--so take a pointer to a slice, and make it -// yourself. (If you don't want your map/pointer type pre-made, take a -// pointer to it, and make it yourself.) See the examples for a range of -// custom functions. -func (f *Fuzzer) Funcs(fuzzFuncs ...interface{}) *Fuzzer { - for i := range fuzzFuncs { - v := reflect.ValueOf(fuzzFuncs[i]) - if v.Kind() != reflect.Func { - panic("Need only funcs!") - } - t := v.Type() - if t.NumIn() != 2 || t.NumOut() != 0 { - panic("Need 2 in and 0 out params!") - } - argT := t.In(0) - switch argT.Kind() { - case reflect.Ptr, reflect.Map: - default: - panic("fuzzFunc must take pointer or map type") - } - if t.In(1) != reflect.TypeOf(Continue{}) { - panic("fuzzFunc's second parameter must be type fuzz.Continue") - } - f.fuzzFuncs[argT] = v - } - return f -} - -// RandSource causes f to get values from the given source of randomness. -// Use if you want deterministic fuzzing. -func (f *Fuzzer) RandSource(s rand.Source) *Fuzzer { - f.r = rand.New(s) - return f -} - -// NilChance sets the probability of creating a nil pointer, map, or slice to -// 'p'. 'p' should be between 0 (no nils) and 1 (all nils), inclusive. -func (f *Fuzzer) NilChance(p float64) *Fuzzer { - if p < 0 || p > 1 { - panic("p should be between 0 and 1, inclusive.") - } - f.nilChance = p - return f -} - -// NumElements sets the minimum and maximum number of elements that will be -// added to a non-nil map or slice. -func (f *Fuzzer) NumElements(atLeast, atMost int) *Fuzzer { - if atLeast > atMost { - panic("atLeast must be <= atMost") - } - if atLeast < 0 { - panic("atLeast must be >= 0") - } - f.minElements = atLeast - f.maxElements = atMost - return f -} - -func (f *Fuzzer) genElementCount() int { - if f.minElements == f.maxElements { - return f.minElements - } - return f.minElements + f.r.Intn(f.maxElements-f.minElements+1) -} - -func (f *Fuzzer) genShouldFill() bool { - return f.r.Float64() >= f.nilChance -} - -// MaxDepth sets the maximum number of recursive fuzz calls that will be made -// before stopping. This includes struct members, pointers, and map and slice -// elements. -func (f *Fuzzer) MaxDepth(d int) *Fuzzer { - f.maxDepth = d - return f -} - -// Skip fields which match the supplied pattern. Call this multiple times if needed -// This is useful to skip XXX_ fields generated by protobuf -func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer { - f.skipFieldPatterns = append(f.skipFieldPatterns, pattern) - return f -} - -// Fuzz recursively fills all of obj's fields with something random. First -// this tries to find a custom fuzz function (see Funcs). If there is no -// custom function this tests whether the object implements fuzz.Interface and, -// if so, calls Fuzz on it to fuzz itself. If that fails, this will see if -// there is a default fuzz function provided by this package. If all of that -// fails, this will generate random values for all primitive fields and then -// recurse for all non-primitives. -// -// This is safe for cyclic or tree-like structs, up to a limit. Use the -// MaxDepth method to adjust how deep you need it to recurse. -// -// obj must be a pointer. Only exported (public) fields can be set (thanks, -// golang :/ ) Intended for tests, so will panic on bad input or unimplemented -// fields. -func (f *Fuzzer) Fuzz(obj interface{}) { - v := reflect.ValueOf(obj) - if v.Kind() != reflect.Ptr { - panic("needed ptr!") - } - v = v.Elem() - f.fuzzWithContext(v, 0) -} - -// FuzzNoCustom is just like Fuzz, except that any custom fuzz function for -// obj's type will not be called and obj will not be tested for fuzz.Interface -// conformance. This applies only to obj and not other instances of obj's -// type. -// Not safe for cyclic or tree-like structs! -// obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ ) -// Intended for tests, so will panic on bad input or unimplemented fields. -func (f *Fuzzer) FuzzNoCustom(obj interface{}) { - v := reflect.ValueOf(obj) - if v.Kind() != reflect.Ptr { - panic("needed ptr!") - } - v = v.Elem() - f.fuzzWithContext(v, flagNoCustomFuzz) -} - -const ( - // Do not try to find a custom fuzz function. Does not apply recursively. - flagNoCustomFuzz uint64 = 1 << iota -) - -func (f *Fuzzer) fuzzWithContext(v reflect.Value, flags uint64) { - fc := &fuzzerContext{fuzzer: f} - fc.doFuzz(v, flags) -} - -// fuzzerContext carries context about a single fuzzing run, which lets Fuzzer -// be thread-safe. -type fuzzerContext struct { - fuzzer *Fuzzer - curDepth int -} - -func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) { - if fc.curDepth >= fc.fuzzer.maxDepth { - return - } - fc.curDepth++ - defer func() { fc.curDepth-- }() - - if !v.CanSet() { - return - } - - if flags&flagNoCustomFuzz == 0 { - // Check for both pointer and non-pointer custom functions. - if v.CanAddr() && fc.tryCustom(v.Addr()) { - return - } - if fc.tryCustom(v) { - return - } - } - - if fn, ok := fillFuncMap[v.Kind()]; ok { - fn(v, fc.fuzzer.r) - return - } - - switch v.Kind() { - case reflect.Map: - if fc.fuzzer.genShouldFill() { - v.Set(reflect.MakeMap(v.Type())) - n := fc.fuzzer.genElementCount() - for i := 0; i < n; i++ { - key := reflect.New(v.Type().Key()).Elem() - fc.doFuzz(key, 0) - val := reflect.New(v.Type().Elem()).Elem() - fc.doFuzz(val, 0) - v.SetMapIndex(key, val) - } - return - } - v.Set(reflect.Zero(v.Type())) - case reflect.Ptr: - if fc.fuzzer.genShouldFill() { - v.Set(reflect.New(v.Type().Elem())) - fc.doFuzz(v.Elem(), 0) - return - } - v.Set(reflect.Zero(v.Type())) - case reflect.Slice: - if fc.fuzzer.genShouldFill() { - n := fc.fuzzer.genElementCount() - v.Set(reflect.MakeSlice(v.Type(), n, n)) - for i := 0; i < n; i++ { - fc.doFuzz(v.Index(i), 0) - } - return - } - v.Set(reflect.Zero(v.Type())) - case reflect.Array: - if fc.fuzzer.genShouldFill() { - n := v.Len() - for i := 0; i < n; i++ { - fc.doFuzz(v.Index(i), 0) - } - return - } - v.Set(reflect.Zero(v.Type())) - case reflect.Struct: - for i := 0; i < v.NumField(); i++ { - skipField := false - fieldName := v.Type().Field(i).Name - for _, pattern := range fc.fuzzer.skipFieldPatterns { - if pattern.MatchString(fieldName) { - skipField = true - break - } - } - if !skipField { - fc.doFuzz(v.Field(i), 0) - } - } - case reflect.Chan: - fallthrough - case reflect.Func: - fallthrough - case reflect.Interface: - fallthrough - default: - panic(fmt.Sprintf("Can't handle %#v", v.Interface())) - } -} - -// tryCustom searches for custom handlers, and returns true iff it finds a match -// and successfully randomizes v. -func (fc *fuzzerContext) tryCustom(v reflect.Value) bool { - // First: see if we have a fuzz function for it. - doCustom, ok := fc.fuzzer.fuzzFuncs[v.Type()] - if !ok { - // Second: see if it can fuzz itself. - if v.CanInterface() { - intf := v.Interface() - if fuzzable, ok := intf.(Interface); ok { - fuzzable.Fuzz(Continue{fc: fc, Rand: fc.fuzzer.r}) - return true - } - } - // Finally: see if there is a default fuzz function. - doCustom, ok = fc.fuzzer.defaultFuzzFuncs[v.Type()] - if !ok { - return false - } - } - - switch v.Kind() { - case reflect.Ptr: - if v.IsNil() { - if !v.CanSet() { - return false - } - v.Set(reflect.New(v.Type().Elem())) - } - case reflect.Map: - if v.IsNil() { - if !v.CanSet() { - return false - } - v.Set(reflect.MakeMap(v.Type())) - } - default: - return false - } - - doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{ - fc: fc, - Rand: fc.fuzzer.r, - })}) - return true -} - -// Interface represents an object that knows how to fuzz itself. Any time we -// find a type that implements this interface we will delegate the act of -// fuzzing itself. -type Interface interface { - Fuzz(c Continue) -} - -// Continue can be passed to custom fuzzing functions to allow them to use -// the correct source of randomness and to continue fuzzing their members. -type Continue struct { - fc *fuzzerContext - - // For convenience, Continue implements rand.Rand via embedding. - // Use this for generating any randomness if you want your fuzzing - // to be repeatable for a given seed. - *rand.Rand -} - -// Fuzz continues fuzzing obj. obj must be a pointer. -func (c Continue) Fuzz(obj interface{}) { - v := reflect.ValueOf(obj) - if v.Kind() != reflect.Ptr { - panic("needed ptr!") - } - v = v.Elem() - c.fc.doFuzz(v, 0) -} - -// FuzzNoCustom continues fuzzing obj, except that any custom fuzz function for -// obj's type will not be called and obj will not be tested for fuzz.Interface -// conformance. This applies only to obj and not other instances of obj's -// type. -func (c Continue) FuzzNoCustom(obj interface{}) { - v := reflect.ValueOf(obj) - if v.Kind() != reflect.Ptr { - panic("needed ptr!") - } - v = v.Elem() - c.fc.doFuzz(v, flagNoCustomFuzz) -} - -// RandString makes a random string up to 20 characters long. The returned string -// may include a variety of (valid) UTF-8 encodings. -func (c Continue) RandString() string { - return randString(c.Rand) -} - -// RandUint64 makes random 64 bit numbers. -// Weirdly, rand doesn't have a function that gives you 64 random bits. -func (c Continue) RandUint64() uint64 { - return randUint64(c.Rand) -} - -// RandBool returns true or false randomly. -func (c Continue) RandBool() bool { - return randBool(c.Rand) -} - -func fuzzInt(v reflect.Value, r *rand.Rand) { - v.SetInt(int64(randUint64(r))) -} - -func fuzzUint(v reflect.Value, r *rand.Rand) { - v.SetUint(randUint64(r)) -} - -func fuzzTime(t *time.Time, c Continue) { - var sec, nsec int64 - // Allow for about 1000 years of random time values, which keeps things - // like JSON parsing reasonably happy. - sec = c.Rand.Int63n(1000 * 365 * 24 * 60 * 60) - c.Fuzz(&nsec) - *t = time.Unix(sec, nsec) -} - -var fillFuncMap = map[reflect.Kind]func(reflect.Value, *rand.Rand){ - reflect.Bool: func(v reflect.Value, r *rand.Rand) { - v.SetBool(randBool(r)) - }, - reflect.Int: fuzzInt, - reflect.Int8: fuzzInt, - reflect.Int16: fuzzInt, - reflect.Int32: fuzzInt, - reflect.Int64: fuzzInt, - reflect.Uint: fuzzUint, - reflect.Uint8: fuzzUint, - reflect.Uint16: fuzzUint, - reflect.Uint32: fuzzUint, - reflect.Uint64: fuzzUint, - reflect.Uintptr: fuzzUint, - reflect.Float32: func(v reflect.Value, r *rand.Rand) { - v.SetFloat(float64(r.Float32())) - }, - reflect.Float64: func(v reflect.Value, r *rand.Rand) { - v.SetFloat(r.Float64()) - }, - reflect.Complex64: func(v reflect.Value, r *rand.Rand) { - v.SetComplex(complex128(complex(r.Float32(), r.Float32()))) - }, - reflect.Complex128: func(v reflect.Value, r *rand.Rand) { - v.SetComplex(complex(r.Float64(), r.Float64())) - }, - reflect.String: func(v reflect.Value, r *rand.Rand) { - v.SetString(randString(r)) - }, - reflect.UnsafePointer: func(v reflect.Value, r *rand.Rand) { - panic("unimplemented") - }, -} - -// randBool returns true or false randomly. -func randBool(r *rand.Rand) bool { - return r.Int31()&(1<<30) == 0 -} - -type int63nPicker interface { - Int63n(int64) int64 -} - -// UnicodeRange describes a sequential range of unicode characters. -// Last must be numerically greater than First. -type UnicodeRange struct { - First, Last rune -} - -// UnicodeRanges describes an arbitrary number of sequential ranges of unicode characters. -// To be useful, each range must have at least one character (First <= Last) and -// there must be at least one range. -type UnicodeRanges []UnicodeRange - -// choose returns a random unicode character from the given range, using the -// given randomness source. -func (ur UnicodeRange) choose(r int63nPicker) rune { - count := int64(ur.Last - ur.First + 1) - return ur.First + rune(r.Int63n(count)) -} - -// CustomStringFuzzFunc constructs a FuzzFunc which produces random strings. -// Each character is selected from the range ur. If there are no characters -// in the range (cr.Last < cr.First), this will panic. -func (ur UnicodeRange) CustomStringFuzzFunc() func(s *string, c Continue) { - ur.check() - return func(s *string, c Continue) { - *s = ur.randString(c.Rand) - } -} - -// check is a function that used to check whether the first of ur(UnicodeRange) -// is greater than the last one. -func (ur UnicodeRange) check() { - if ur.Last < ur.First { - panic("The last encoding must be greater than the first one.") - } -} - -// randString of UnicodeRange makes a random string up to 20 characters long. -// Each character is selected form ur(UnicodeRange). -func (ur UnicodeRange) randString(r *rand.Rand) string { - n := r.Intn(20) - sb := strings.Builder{} - sb.Grow(n) - for i := 0; i < n; i++ { - sb.WriteRune(ur.choose(r)) - } - return sb.String() -} - -// defaultUnicodeRanges sets a default unicode range when user do not set -// CustomStringFuzzFunc() but wants fuzz string. -var defaultUnicodeRanges = UnicodeRanges{ - {' ', '~'}, // ASCII characters - {'\u00a0', '\u02af'}, // Multi-byte encoded characters - {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) -} - -// CustomStringFuzzFunc constructs a FuzzFunc which produces random strings. -// Each character is selected from one of the ranges of ur(UnicodeRanges). -// Each range has an equal probability of being chosen. If there are no ranges, -// or a selected range has no characters (.Last < .First), this will panic. -// Do not modify any of the ranges in ur after calling this function. -func (ur UnicodeRanges) CustomStringFuzzFunc() func(s *string, c Continue) { - // Check unicode ranges slice is empty. - if len(ur) == 0 { - panic("UnicodeRanges is empty.") - } - // if not empty, each range should be checked. - for i := range ur { - ur[i].check() - } - return func(s *string, c Continue) { - *s = ur.randString(c.Rand) - } -} - -// randString of UnicodeRanges makes a random string up to 20 characters long. -// Each character is selected form one of the ranges of ur(UnicodeRanges), -// and each range has an equal probability of being chosen. -func (ur UnicodeRanges) randString(r *rand.Rand) string { - n := r.Intn(20) - sb := strings.Builder{} - sb.Grow(n) - for i := 0; i < n; i++ { - sb.WriteRune(ur[r.Intn(len(ur))].choose(r)) - } - return sb.String() -} - -// randString makes a random string up to 20 characters long. The returned string -// may include a variety of (valid) UTF-8 encodings. -func randString(r *rand.Rand) string { - return defaultUnicodeRanges.randString(r) -} - -// randUint64 makes random 64 bit numbers. -// Weirdly, rand doesn't have a function that gives you 64 random bits. -func randUint64(r *rand.Rand) uint64 { - return uint64(r.Uint32())<<32 | uint64(r.Uint32()) -} diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md new file mode 100644 index 0000000..7ec5ac7 --- /dev/null +++ b/vendor/github.com/google/uuid/CHANGELOG.md @@ -0,0 +1,41 @@ +# Changelog + +## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) + + +### Features + +* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) + + +### Bug Fixes + +* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) +* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) + +## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) + + +### Features + +* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) + +## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) + + +### Features + +* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) + +### Fixes + +* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) + +## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) + + +### Bug Fixes + +* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0)) + +## Changelog diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md new file mode 100644 index 0000000..a502fdc --- /dev/null +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# How to contribute + +We definitely welcome patches and contribution to this project! + +### Tips + +Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org). + +Always try to include a test case! If it is not possible or not necessary, +please explain why in the pull request description. + +### Releasing + +Commits that would precipitate a SemVer change, as described in the Conventional +Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) +to create a release candidate pull request. Once submitted, `release-please` +will create a release. + +For tips on how to work with `release-please`, see its documentation. + +### Legal requirements + +In order to protect both you and ourselves, you will need to sign the +[Contributor License Agreement](https://cla.developers.google.com/clas). + +You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS new file mode 100644 index 0000000..b4bb97f --- /dev/null +++ b/vendor/github.com/google/uuid/CONTRIBUTORS @@ -0,0 +1,9 @@ +Paul Borman +bmatsuo +shawnps +theory +jboverfelt +dsymonds +cd1 +wallclockbuilder +dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE new file mode 100644 index 0000000..5dc6826 --- /dev/null +++ b/vendor/github.com/google/uuid/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009,2014 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md new file mode 100644 index 0000000..3e9a618 --- /dev/null +++ b/vendor/github.com/google/uuid/README.md @@ -0,0 +1,21 @@ +# uuid +The uuid package generates and inspects UUIDs based on +[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) +and DCE 1.1: Authentication and Security Services. + +This package is based on the github.com/pborman/uuid package (previously named +code.google.com/p/go-uuid). It differs from these earlier packages in that +a UUID is a 16 byte array rather than a byte slice. One loss due to this +change is the ability to represent an invalid UUID (vs a NIL UUID). + +###### Install +```sh +go get github.com/google/uuid +``` + +###### Documentation +[![Go Reference](https://pkg.go.dev/badge/github.com/google/uuid.svg)](https://pkg.go.dev/github.com/google/uuid) + +Full `go doc` style documentation for the package can be viewed online without +installing this package by using the GoDoc site here: +http://pkg.go.dev/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go new file mode 100644 index 0000000..fa820b9 --- /dev/null +++ b/vendor/github.com/google/uuid/dce.go @@ -0,0 +1,80 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "fmt" + "os" +) + +// A Domain represents a Version 2 domain +type Domain byte + +// Domain constants for DCE Security (Version 2) UUIDs. +const ( + Person = Domain(0) + Group = Domain(1) + Org = Domain(2) +) + +// NewDCESecurity returns a DCE Security (Version 2) UUID. +// +// The domain should be one of Person, Group or Org. +// On a POSIX system the id should be the users UID for the Person +// domain and the users GID for the Group. The meaning of id for +// the domain Org or on non-POSIX systems is site defined. +// +// For a given domain/id pair the same token may be returned for up to +// 7 minutes and 10 seconds. +func NewDCESecurity(domain Domain, id uint32) (UUID, error) { + uuid, err := NewUUID() + if err == nil { + uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 + uuid[9] = byte(domain) + binary.BigEndian.PutUint32(uuid[0:], id) + } + return uuid, err +} + +// NewDCEPerson returns a DCE Security (Version 2) UUID in the person +// domain with the id returned by os.Getuid. +// +// NewDCESecurity(Person, uint32(os.Getuid())) +func NewDCEPerson() (UUID, error) { + return NewDCESecurity(Person, uint32(os.Getuid())) +} + +// NewDCEGroup returns a DCE Security (Version 2) UUID in the group +// domain with the id returned by os.Getgid. +// +// NewDCESecurity(Group, uint32(os.Getgid())) +func NewDCEGroup() (UUID, error) { + return NewDCESecurity(Group, uint32(os.Getgid())) +} + +// Domain returns the domain for a Version 2 UUID. Domains are only defined +// for Version 2 UUIDs. +func (uuid UUID) Domain() Domain { + return Domain(uuid[9]) +} + +// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 +// UUIDs. +func (uuid UUID) ID() uint32 { + return binary.BigEndian.Uint32(uuid[0:4]) +} + +func (d Domain) String() string { + switch d { + case Person: + return "Person" + case Group: + return "Group" + case Org: + return "Org" + } + return fmt.Sprintf("Domain%d", int(d)) +} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go new file mode 100644 index 0000000..5b8a4b9 --- /dev/null +++ b/vendor/github.com/google/uuid/doc.go @@ -0,0 +1,12 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package uuid generates and inspects UUIDs. +// +// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security +// Services. +// +// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to +// maps or compared directly. +package uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go new file mode 100644 index 0000000..dc60082 --- /dev/null +++ b/vendor/github.com/google/uuid/hash.go @@ -0,0 +1,59 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "crypto/md5" + "crypto/sha1" + "hash" +) + +// Well known namespace IDs and UUIDs +var ( + NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) + Nil UUID // empty UUID, all zeros + + // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. + Max = UUID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + } +) + +// NewHash returns a new UUID derived from the hash of space concatenated with +// data generated by h. The hash should be at least 16 byte in length. The +// first 16 bytes of the hash are used to form the UUID. The version of the +// UUID will be the lower 4 bits of version. NewHash is used to implement +// NewMD5 and NewSHA1. +func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { + h.Reset() + h.Write(space[:]) //nolint:errcheck + h.Write(data) //nolint:errcheck + s := h.Sum(nil) + var uuid UUID + copy(uuid[:], s) + uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) + uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant + return uuid +} + +// NewMD5 returns a new MD5 (Version 3) UUID based on the +// supplied name space and data. It is the same as calling: +// +// NewHash(md5.New(), space, data, 3) +func NewMD5(space UUID, data []byte) UUID { + return NewHash(md5.New(), space, data, 3) +} + +// NewSHA1 returns a new SHA1 (Version 5) UUID based on the +// supplied name space and data. It is the same as calling: +// +// NewHash(sha1.New(), space, data, 5) +func NewSHA1(space UUID, data []byte) UUID { + return NewHash(sha1.New(), space, data, 5) +} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go new file mode 100644 index 0000000..14bd340 --- /dev/null +++ b/vendor/github.com/google/uuid/marshal.go @@ -0,0 +1,38 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "fmt" + +// MarshalText implements encoding.TextMarshaler. +func (uuid UUID) MarshalText() ([]byte, error) { + var js [36]byte + encodeHex(js[:], uuid) + return js[:], nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (uuid *UUID) UnmarshalText(data []byte) error { + id, err := ParseBytes(data) + if err != nil { + return err + } + *uuid = id + return nil +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (uuid UUID) MarshalBinary() ([]byte, error) { + return uuid[:], nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (uuid *UUID) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + copy(uuid[:], data) + return nil +} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go new file mode 100644 index 0000000..d651a2b --- /dev/null +++ b/vendor/github.com/google/uuid/node.go @@ -0,0 +1,90 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "sync" +) + +var ( + nodeMu sync.Mutex + ifname string // name of interface being used + nodeID [6]byte // hardware for version 1 UUIDs + zeroID [6]byte // nodeID with only 0's +) + +// NodeInterface returns the name of the interface from which the NodeID was +// derived. The interface "user" is returned if the NodeID was set by +// SetNodeID. +func NodeInterface() string { + defer nodeMu.Unlock() + nodeMu.Lock() + return ifname +} + +// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. +// If name is "" then the first usable interface found will be used or a random +// Node ID will be generated. If a named interface cannot be found then false +// is returned. +// +// SetNodeInterface never fails when name is "". +func SetNodeInterface(name string) bool { + defer nodeMu.Unlock() + nodeMu.Lock() + return setNodeInterface(name) +} + +func setNodeInterface(name string) bool { + iname, addr := getHardwareInterface(name) // null implementation for js + if iname != "" && addr != nil { + ifname = iname + copy(nodeID[:], addr) + return true + } + + // We found no interfaces with a valid hardware address. If name + // does not specify a specific interface generate a random Node ID + // (section 4.1.6) + if name == "" { + ifname = "random" + randomBits(nodeID[:]) + return true + } + return false +} + +// NodeID returns a slice of a copy of the current Node ID, setting the Node ID +// if not already set. +func NodeID() []byte { + defer nodeMu.Unlock() + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + nid := nodeID + return nid[:] +} + +// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes +// of id are used. If id is less than 6 bytes then false is returned and the +// Node ID is not set. +func SetNodeID(id []byte) bool { + if len(id) < 6 { + return false + } + defer nodeMu.Unlock() + nodeMu.Lock() + copy(nodeID[:], id) + ifname = "user" + return true +} + +// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is +// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) NodeID() []byte { + var node [6]byte + copy(node[:], uuid[10:]) + return node[:] +} diff --git a/vendor/github.com/google/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go new file mode 100644 index 0000000..b2a0bc8 --- /dev/null +++ b/vendor/github.com/google/uuid/node_js.go @@ -0,0 +1,12 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build js + +package uuid + +// getHardwareInterface returns nil values for the JS version of the code. +// This removes the "net" dependency, because it is not used in the browser. +// Using the "net" library inflates the size of the transpiled JS code by 673k bytes. +func getHardwareInterface(name string) (string, []byte) { return "", nil } diff --git a/vendor/github.com/google/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go new file mode 100644 index 0000000..0cbbcdd --- /dev/null +++ b/vendor/github.com/google/uuid/node_net.go @@ -0,0 +1,33 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !js + +package uuid + +import "net" + +var interfaces []net.Interface // cached list of interfaces + +// getHardwareInterface returns the name and hardware address of interface name. +// If name is "" then the name and hardware address of one of the system's +// interfaces is returned. If no interfaces are found (name does not exist or +// there are no interfaces) then "", nil is returned. +// +// Only addresses of at least 6 bytes are returned. +func getHardwareInterface(name string) (string, []byte) { + if interfaces == nil { + var err error + interfaces, err = net.Interfaces() + if err != nil { + return "", nil + } + } + for _, ifs := range interfaces { + if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { + return ifs.Name, ifs.HardwareAddr + } + } + return "", nil +} diff --git a/vendor/github.com/google/uuid/null.go b/vendor/github.com/google/uuid/null.go new file mode 100644 index 0000000..d7fcbf2 --- /dev/null +++ b/vendor/github.com/google/uuid/null.go @@ -0,0 +1,118 @@ +// Copyright 2021 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" +) + +var jsonNull = []byte("null") + +// NullUUID represents a UUID that may be null. +// NullUUID implements the SQL driver.Scanner interface so +// it can be used as a scan destination: +// +// var u uuid.NullUUID +// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) +// ... +// if u.Valid { +// // use u.UUID +// } else { +// // NULL value +// } +// +type NullUUID struct { + UUID UUID + Valid bool // Valid is true if UUID is not NULL +} + +// Scan implements the SQL driver.Scanner interface. +func (nu *NullUUID) Scan(value interface{}) error { + if value == nil { + nu.UUID, nu.Valid = Nil, false + return nil + } + + err := nu.UUID.Scan(value) + if err != nil { + nu.Valid = false + return err + } + + nu.Valid = true + return nil +} + +// Value implements the driver Valuer interface. +func (nu NullUUID) Value() (driver.Value, error) { + if !nu.Valid { + return nil, nil + } + // Delegate to UUID Value function + return nu.UUID.Value() +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (nu NullUUID) MarshalBinary() ([]byte, error) { + if nu.Valid { + return nu.UUID[:], nil + } + + return []byte(nil), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (nu *NullUUID) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + copy(nu.UUID[:], data) + nu.Valid = true + return nil +} + +// MarshalText implements encoding.TextMarshaler. +func (nu NullUUID) MarshalText() ([]byte, error) { + if nu.Valid { + return nu.UUID.MarshalText() + } + + return jsonNull, nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (nu *NullUUID) UnmarshalText(data []byte) error { + id, err := ParseBytes(data) + if err != nil { + nu.Valid = false + return err + } + nu.UUID = id + nu.Valid = true + return nil +} + +// MarshalJSON implements json.Marshaler. +func (nu NullUUID) MarshalJSON() ([]byte, error) { + if nu.Valid { + return json.Marshal(nu.UUID) + } + + return jsonNull, nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (nu *NullUUID) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, jsonNull) { + *nu = NullUUID{} + return nil // valid null UUID + } + err := json.Unmarshal(data, &nu.UUID) + nu.Valid = err == nil + return err +} diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go new file mode 100644 index 0000000..2e02ec0 --- /dev/null +++ b/vendor/github.com/google/uuid/sql.go @@ -0,0 +1,59 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "database/sql/driver" + "fmt" +) + +// Scan implements sql.Scanner so UUIDs can be read from databases transparently. +// Currently, database types that map to string and []byte are supported. Please +// consult database-specific driver documentation for matching types. +func (uuid *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case nil: + return nil + + case string: + // if an empty UUID comes from a table, we return a null UUID + if src == "" { + return nil + } + + // see Parse for required string format + u, err := Parse(src) + if err != nil { + return fmt.Errorf("Scan: %v", err) + } + + *uuid = u + + case []byte: + // if an empty UUID comes from a table, we return a null UUID + if len(src) == 0 { + return nil + } + + // assumes a simple slice of bytes if 16 bytes + // otherwise attempts to parse + if len(src) != 16 { + return uuid.Scan(string(src)) + } + copy((*uuid)[:], src) + + default: + return fmt.Errorf("Scan: unable to scan type %T into UUID", src) + } + + return nil +} + +// Value implements sql.Valuer so that UUIDs can be written to databases +// transparently. Currently, UUIDs map to strings. Please consult +// database-specific driver documentation for matching types. +func (uuid UUID) Value() (driver.Value, error) { + return uuid.String(), nil +} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go new file mode 100644 index 0000000..c351129 --- /dev/null +++ b/vendor/github.com/google/uuid/time.go @@ -0,0 +1,134 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "sync" + "time" +) + +// A Time represents a time as the number of 100's of nanoseconds since 15 Oct +// 1582. +type Time int64 + +const ( + lillian = 2299160 // Julian day of 15 Oct 1582 + unix = 2440587 // Julian day of 1 Jan 1970 + epoch = unix - lillian // Days between epochs + g1582 = epoch * 86400 // seconds between epochs + g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs +) + +var ( + timeMu sync.Mutex + lasttime uint64 // last time we returned + clockSeq uint16 // clock sequence for this run + + timeNow = time.Now // for testing +) + +// UnixTime converts t the number of seconds and nanoseconds using the Unix +// epoch of 1 Jan 1970. +func (t Time) UnixTime() (sec, nsec int64) { + sec = int64(t - g1582ns100) + nsec = (sec % 10000000) * 100 + sec /= 10000000 + return sec, nsec +} + +// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and +// clock sequence as well as adjusting the clock sequence as needed. An error +// is returned if the current time cannot be determined. +func GetTime() (Time, uint16, error) { + defer timeMu.Unlock() + timeMu.Lock() + return getTime() +} + +func getTime() (Time, uint16, error) { + t := timeNow() + + // If we don't have a clock sequence already, set one. + if clockSeq == 0 { + setClockSequence(-1) + } + now := uint64(t.UnixNano()/100) + g1582ns100 + + // If time has gone backwards with this clock sequence then we + // increment the clock sequence + if now <= lasttime { + clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 + } + lasttime = now + return Time(now), clockSeq, nil +} + +// ClockSequence returns the current clock sequence, generating one if not +// already set. The clock sequence is only used for Version 1 UUIDs. +// +// The uuid package does not use global static storage for the clock sequence or +// the last time a UUID was generated. Unless SetClockSequence is used, a new +// random clock sequence is generated the first time a clock sequence is +// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) +func ClockSequence() int { + defer timeMu.Unlock() + timeMu.Lock() + return clockSequence() +} + +func clockSequence() int { + if clockSeq == 0 { + setClockSequence(-1) + } + return int(clockSeq & 0x3fff) +} + +// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to +// -1 causes a new sequence to be generated. +func SetClockSequence(seq int) { + defer timeMu.Unlock() + timeMu.Lock() + setClockSequence(seq) +} + +func setClockSequence(seq int) { + if seq == -1 { + var b [2]byte + randomBits(b[:]) // clock sequence + seq = int(b[0])<<8 | int(b[1]) + } + oldSeq := clockSeq + clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant + if oldSeq != clockSeq { + lasttime = 0 + } +} + +// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in +// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. +func (uuid UUID) Time() Time { + var t Time + switch uuid.Version() { + case 6: + time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 + t = Time(time) + case 7: + time := binary.BigEndian.Uint64(uuid[:8]) + t = Time((time>>16)*10000 + g1582ns100) + default: // forward compatible + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + t = Time(time) + } + return t +} + +// ClockSequence returns the clock sequence encoded in uuid. +// The clock sequence is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) ClockSequence() int { + return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff +} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go new file mode 100644 index 0000000..5ea6c73 --- /dev/null +++ b/vendor/github.com/google/uuid/util.go @@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// randomBits completely fills slice b with random data. +func randomBits(b []byte) { + if _, err := io.ReadFull(rander, b); err != nil { + panic(err.Error()) // rand should never fail + } +} + +// xvalues returns the value of a byte as a hexadecimal digit or 255. +var xvalues = [256]byte{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +} + +// xtob converts hex characters x1 and x2 into a byte. +func xtob(x1, x2 byte) (byte, bool) { + b1 := xvalues[x1] + b2 := xvalues[x2] + return (b1 << 4) | b2, b1 != 255 && b2 != 255 +} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go new file mode 100644 index 0000000..5232b48 --- /dev/null +++ b/vendor/github.com/google/uuid/uuid.go @@ -0,0 +1,365 @@ +// Copyright 2018 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "errors" + "fmt" + "io" + "strings" + "sync" +) + +// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC +// 4122. +type UUID [16]byte + +// A Version represents a UUID's version. +type Version byte + +// A Variant represents a UUID's variant. +type Variant byte + +// Constants returned by Variant. +const ( + Invalid = Variant(iota) // Invalid UUID + RFC4122 // The variant specified in RFC4122 + Reserved // Reserved, NCS backward compatibility. + Microsoft // Reserved, Microsoft Corporation backward compatibility. + Future // Reserved for future definition. +) + +const randPoolSize = 16 * 16 + +var ( + rander = rand.Reader // random function + poolEnabled = false + poolMu sync.Mutex + poolPos = randPoolSize // protected with poolMu + pool [randPoolSize]byte // protected with poolMu +) + +type invalidLengthError struct{ len int } + +func (err invalidLengthError) Error() string { + return fmt.Sprintf("invalid UUID length: %d", err.len) +} + +// IsInvalidLengthError is matcher function for custom error invalidLengthError +func IsInvalidLengthError(err error) bool { + _, ok := err.(invalidLengthError) + return ok +} + +// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both +// the standard UUID forms defined in RFC 4122 +// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, +// Parse accepts non-standard strings such as the raw hex encoding +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, +// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are +// examined in the latter case. Parse should not be used to validate strings as +// it parses non-standard encodings as indicated above. +func Parse(s string) (UUID, error) { + var uuid UUID + switch len(s) { + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36: + + // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36 + 9: + if !strings.EqualFold(s[:9], "urn:uuid:") { + return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + case 36 + 2: + s = s[1:] + + // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + case 32: + var ok bool + for i := range uuid { + uuid[i], ok = xtob(s[i*2], s[i*2+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + } + return uuid, nil + default: + return uuid, invalidLengthError{len(s)} + } + // s is now at least 36 bytes long + // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return uuid, errors.New("invalid UUID format") + } + for i, x := range [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } { + v, ok := xtob(s[x], s[x+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + uuid[i] = v + } + return uuid, nil +} + +// ParseBytes is like Parse, except it parses a byte slice instead of a string. +func ParseBytes(b []byte) (UUID, error) { + var uuid UUID + switch len(b) { + case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) { + return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) + } + b = b[9:] + case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + b = b[1:] + case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + var ok bool + for i := 0; i < 32; i += 2 { + uuid[i/2], ok = xtob(b[i], b[i+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + } + return uuid, nil + default: + return uuid, invalidLengthError{len(b)} + } + // s is now at least 36 bytes long + // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { + return uuid, errors.New("invalid UUID format") + } + for i, x := range [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } { + v, ok := xtob(b[x], b[x+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + uuid[i] = v + } + return uuid, nil +} + +// MustParse is like Parse but panics if the string cannot be parsed. +// It simplifies safe initialization of global variables holding compiled UUIDs. +func MustParse(s string) UUID { + uuid, err := Parse(s) + if err != nil { + panic(`uuid: Parse(` + s + `): ` + err.Error()) + } + return uuid +} + +// FromBytes creates a new UUID from a byte slice. Returns an error if the slice +// does not have a length of 16. The bytes are copied from the slice. +func FromBytes(b []byte) (uuid UUID, err error) { + err = uuid.UnmarshalBinary(b) + return uuid, err +} + +// Must returns uuid if err is nil and panics otherwise. +func Must(uuid UUID, err error) UUID { + if err != nil { + panic(err) + } + return uuid +} + +// Validate returns an error if s is not a properly formatted UUID in one of the following formats: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// It returns an error if the format is invalid, otherwise nil. +func Validate(s string) error { + switch len(s) { + // Standard UUID format + case 36: + + // UUID with "urn:uuid:" prefix + case 36 + 9: + if !strings.EqualFold(s[:9], "urn:uuid:") { + return fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // UUID enclosed in braces + case 36 + 2: + if s[0] != '{' || s[len(s)-1] != '}' { + return fmt.Errorf("invalid bracketed UUID format") + } + s = s[1 : len(s)-1] + + // UUID without hyphens + case 32: + for i := 0; i < len(s); i += 2 { + _, ok := xtob(s[i], s[i+1]) + if !ok { + return errors.New("invalid UUID format") + } + } + + default: + return invalidLengthError{len(s)} + } + + // Check for standard UUID format + if len(s) == 36 { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return errors.New("invalid UUID format") + } + for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { + if _, ok := xtob(s[x], s[x+1]); !ok { + return errors.New("invalid UUID format") + } + } + } + + return nil +} + +// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// , or "" if uuid is invalid. +func (uuid UUID) String() string { + var buf [36]byte + encodeHex(buf[:], uuid) + return string(buf[:]) +} + +// URN returns the RFC 2141 URN form of uuid, +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. +func (uuid UUID) URN() string { + var buf [36 + 9]byte + copy(buf[:], "urn:uuid:") + encodeHex(buf[9:], uuid) + return string(buf[:]) +} + +func encodeHex(dst []byte, uuid UUID) { + hex.Encode(dst, uuid[:4]) + dst[8] = '-' + hex.Encode(dst[9:13], uuid[4:6]) + dst[13] = '-' + hex.Encode(dst[14:18], uuid[6:8]) + dst[18] = '-' + hex.Encode(dst[19:23], uuid[8:10]) + dst[23] = '-' + hex.Encode(dst[24:], uuid[10:]) +} + +// Variant returns the variant encoded in uuid. +func (uuid UUID) Variant() Variant { + switch { + case (uuid[8] & 0xc0) == 0x80: + return RFC4122 + case (uuid[8] & 0xe0) == 0xc0: + return Microsoft + case (uuid[8] & 0xe0) == 0xe0: + return Future + default: + return Reserved + } +} + +// Version returns the version of uuid. +func (uuid UUID) Version() Version { + return Version(uuid[6] >> 4) +} + +func (v Version) String() string { + if v > 15 { + return fmt.Sprintf("BAD_VERSION_%d", v) + } + return fmt.Sprintf("VERSION_%d", v) +} + +func (v Variant) String() string { + switch v { + case RFC4122: + return "RFC4122" + case Reserved: + return "Reserved" + case Microsoft: + return "Microsoft" + case Future: + return "Future" + case Invalid: + return "Invalid" + } + return fmt.Sprintf("BadVariant%d", int(v)) +} + +// SetRand sets the random number generator to r, which implements io.Reader. +// If r.Read returns an error when the package requests random data then +// a panic will be issued. +// +// Calling SetRand with nil sets the random number generator to the default +// generator. +func SetRand(r io.Reader) { + if r == nil { + rander = rand.Reader + return + } + rander = r +} + +// EnableRandPool enables internal randomness pool used for Random +// (Version 4) UUID generation. The pool contains random bytes read from +// the random number generator on demand in batches. Enabling the pool +// may improve the UUID generation throughput significantly. +// +// Since the pool is stored on the Go heap, this feature may be a bad fit +// for security sensitive applications. +// +// Both EnableRandPool and DisableRandPool are not thread-safe and should +// only be called when there is no possibility that New or any other +// UUID Version 4 generation function will be called concurrently. +func EnableRandPool() { + poolEnabled = true +} + +// DisableRandPool disables the randomness pool if it was previously +// enabled with EnableRandPool. +// +// Both EnableRandPool and DisableRandPool are not thread-safe and should +// only be called when there is no possibility that New or any other +// UUID Version 4 generation function will be called concurrently. +func DisableRandPool() { + poolEnabled = false + defer poolMu.Unlock() + poolMu.Lock() + poolPos = randPoolSize +} + +// UUIDs is a slice of UUID types. +type UUIDs []UUID + +// Strings returns a string slice containing the string form of each UUID in uuids. +func (uuids UUIDs) Strings() []string { + var uuidStrs = make([]string, len(uuids)) + for i, uuid := range uuids { + uuidStrs[i] = uuid.String() + } + return uuidStrs +} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go new file mode 100644 index 0000000..4631096 --- /dev/null +++ b/vendor/github.com/google/uuid/version1.go @@ -0,0 +1,44 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" +) + +// NewUUID returns a Version 1 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewUUID returns nil. If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewUUID returns nil and an error. +// +// In most cases, New should be used. +func NewUUID() (UUID, error) { + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + timeLow := uint32(now & 0xffffffff) + timeMid := uint16((now >> 32) & 0xffff) + timeHi := uint16((now >> 48) & 0x0fff) + timeHi |= 0x1000 // Version 1 + + binary.BigEndian.PutUint32(uuid[0:], timeLow) + binary.BigEndian.PutUint16(uuid[4:], timeMid) + binary.BigEndian.PutUint16(uuid[6:], timeHi) + binary.BigEndian.PutUint16(uuid[8:], seq) + + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + copy(uuid[10:], nodeID[:]) + nodeMu.Unlock() + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go new file mode 100644 index 0000000..7697802 --- /dev/null +++ b/vendor/github.com/google/uuid/version4.go @@ -0,0 +1,76 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "io" + +// New creates a new random UUID or panics. New is equivalent to +// the expression +// +// uuid.Must(uuid.NewRandom()) +func New() UUID { + return Must(NewRandom()) +} + +// NewString creates a new random UUID and returns it as a string or panics. +// NewString is equivalent to the expression +// +// uuid.New().String() +func NewString() string { + return Must(NewRandom()).String() +} + +// NewRandom returns a Random (Version 4) UUID. +// +// The strength of the UUIDs is based on the strength of the crypto/rand +// package. +// +// Uses the randomness pool if it was enabled with EnableRandPool. +// +// A note about uniqueness derived from the UUID Wikipedia entry: +// +// Randomly generated UUIDs have 122 random bits. One's annual risk of being +// hit by a meteorite is estimated to be one chance in 17 billion, that +// means the probability is about 0.00000000006 (6 Ă— 10−11), +// equivalent to the odds of creating a few tens of trillions of UUIDs in a +// year and having one duplicate. +func NewRandom() (UUID, error) { + if !poolEnabled { + return NewRandomFromReader(rander) + } + return newRandomFromPool() +} + +// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. +func NewRandomFromReader(r io.Reader) (UUID, error) { + var uuid UUID + _, err := io.ReadFull(r, uuid[:]) + if err != nil { + return Nil, err + } + uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 + uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 + return uuid, nil +} + +func newRandomFromPool() (UUID, error) { + var uuid UUID + poolMu.Lock() + if poolPos == randPoolSize { + _, err := io.ReadFull(rander, pool[:]) + if err != nil { + poolMu.Unlock() + return Nil, err + } + poolPos = 0 + } + copy(uuid[:], pool[poolPos:(poolPos+16)]) + poolPos += 16 + poolMu.Unlock() + + uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 + uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go new file mode 100644 index 0000000..339a959 --- /dev/null +++ b/vendor/github.com/google/uuid/version6.go @@ -0,0 +1,56 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "encoding/binary" + +// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. +// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. +// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 +// +// NewV6 returns a Version 6 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewV6 returns Nil and an error. +func NewV6() (UUID, error) { + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_high | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_mid | time_low_and_version | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |clk_seq_hi_res | clk_seq_low | node (0-1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | node (2-5) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + binary.BigEndian.PutUint64(uuid[0:], uint64(now)) + binary.BigEndian.PutUint16(uuid[8:], seq) + + uuid[6] = 0x60 | (uuid[6] & 0x0F) + uuid[8] = 0x80 | (uuid[8] & 0x3F) + + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + copy(uuid[10:], nodeID[:]) + nodeMu.Unlock() + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go new file mode 100644 index 0000000..3167b64 --- /dev/null +++ b/vendor/github.com/google/uuid/version7.go @@ -0,0 +1,104 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// UUID version 7 features a time-ordered value field derived from the widely +// implemented and well known Unix Epoch timestamp source, +// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. +// As well as improved entropy characteristics over versions 1 or 6. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 +// +// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. +// +// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). +// Uses the randomness pool if it was enabled with EnableRandPool. +// On error, NewV7 returns Nil and an error +func NewV7() (UUID, error) { + uuid, err := NewRandom() + if err != nil { + return uuid, err + } + makeV7(uuid[:]) + return uuid, nil +} + +// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). +// it use NewRandomFromReader fill random bits. +// On error, NewV7FromReader returns Nil and an error. +func NewV7FromReader(r io.Reader) (UUID, error) { + uuid, err := NewRandomFromReader(r) + if err != nil { + return uuid, err + } + + makeV7(uuid[:]) + return uuid, nil +} + +// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) +// uuid[8] already has the right version number (Variant is 10) +// see function NewV7 and NewV7FromReader +func makeV7(uuid []byte) { + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | ver | rand_a (12 bit seq) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |var| rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + _ = uuid[15] // bounds check + + t, s := getV7Time() + + uuid[0] = byte(t >> 40) + uuid[1] = byte(t >> 32) + uuid[2] = byte(t >> 24) + uuid[3] = byte(t >> 16) + uuid[4] = byte(t >> 8) + uuid[5] = byte(t) + + uuid[6] = 0x70 | (0x0F & byte(s>>8)) + uuid[7] = byte(s) +} + +// lastV7time is the last time we returned stored as: +// +// 52 bits of time in milliseconds since epoch +// 12 bits of (fractional nanoseconds) >> 8 +var lastV7time int64 + +const nanoPerMilli = 1000000 + +// getV7Time returns the time in milliseconds and nanoseconds / 256. +// The returned (milli << 12 + seq) is guarenteed to be greater than +// (milli << 12 + seq) returned by any previous call to getV7Time. +func getV7Time() (milli, seq int64) { + timeMu.Lock() + defer timeMu.Unlock() + + nano := timeNow().UnixNano() + milli = nano / nanoPerMilli + // Sequence number is between 0 and 3906 (nanoPerMilli>>8) + seq = (nano - milli*nanoPerMilli) >> 8 + now := milli<<12 + seq + if now <= lastV7time { + now = lastV7time + 1 + milli = now >> 12 + seq = now & 0xfff + } + lastV7time = now + return milli, seq +} diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go index bd896bd..8d99551 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (!amd64 && !ppc64le && !ppc64 && !s390x) || !gc || purego +//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego package poly1305 diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go similarity index 94% rename from vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go rename to vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go index 164cd47..315b84a 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build gc && !purego +//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le) package poly1305 diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s new file mode 100644 index 0000000..bc8361d --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s @@ -0,0 +1,123 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +// func update(state *macState, msg []byte) +TEXT ·update(SB), $0-32 + MOVV state+0(FP), R4 + MOVV msg_base+8(FP), R5 + MOVV msg_len+16(FP), R6 + + MOVV $0x10, R7 + + MOVV (R4), R8 // h0 + MOVV 8(R4), R9 // h1 + MOVV 16(R4), R10 // h2 + MOVV 24(R4), R11 // r0 + MOVV 32(R4), R12 // r1 + + BLT R6, R7, bytes_between_0_and_15 + +loop: + MOVV (R5), R14 // msg[0:8] + MOVV 8(R5), R16 // msg[8:16] + ADDV R14, R8, R8 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow) + ADDV R16, R9, R27 + SGTU R14, R8, R24 // h0.carry + SGTU R9, R27, R28 + ADDV R27, R24, R9 // h1 + SGTU R27, R9, R24 + OR R24, R28, R24 // h1.carry + ADDV $0x01, R24, R24 + ADDV R10, R24, R10 // h2 + + ADDV $16, R5, R5 // msg = msg[16:] + +multiply: + MULV R8, R11, R14 // h0r0.lo + MULHVU R8, R11, R15 // h0r0.hi + MULV R9, R11, R13 // h1r0.lo + MULHVU R9, R11, R16 // h1r0.hi + ADDV R13, R15, R15 + SGTU R13, R15, R24 + ADDV R24, R16, R16 + MULV R10, R11, R25 + ADDV R16, R25, R25 + MULV R8, R12, R13 // h0r1.lo + MULHVU R8, R12, R16 // h0r1.hi + ADDV R13, R15, R15 + SGTU R13, R15, R24 + ADDV R24, R16, R16 + MOVV R16, R8 + MULV R10, R12, R26 // h2r1 + MULV R9, R12, R13 // h1r1.lo + MULHVU R9, R12, R16 // h1r1.hi + ADDV R13, R25, R25 + ADDV R16, R26, R27 + SGTU R13, R25, R24 + ADDV R27, R24, R26 + ADDV R8, R25, R25 + SGTU R8, R25, R24 + ADDV R24, R26, R26 + AND $3, R25, R10 + AND $-4, R25, R17 + ADDV R17, R14, R8 + ADDV R26, R15, R27 + SGTU R17, R8, R24 + SGTU R26, R27, R28 + ADDV R27, R24, R9 + SGTU R27, R9, R24 + OR R24, R28, R24 + ADDV R24, R10, R10 + SLLV $62, R26, R27 + SRLV $2, R25, R28 + SRLV $2, R26, R26 + OR R27, R28, R25 + ADDV R25, R8, R8 + ADDV R26, R9, R27 + SGTU R25, R8, R24 + SGTU R26, R27, R28 + ADDV R27, R24, R9 + SGTU R27, R9, R24 + OR R24, R28, R24 + ADDV R24, R10, R10 + + SUBV $16, R6, R6 + BGE R6, R7, loop + +bytes_between_0_and_15: + BEQ R6, R0, done + MOVV $1, R14 + XOR R15, R15 + ADDV R6, R5, R5 + +flush_buffer: + MOVBU -1(R5), R25 + SRLV $56, R14, R24 + SLLV $8, R15, R28 + SLLV $8, R14, R14 + OR R24, R28, R15 + XOR R25, R14, R14 + SUBV $1, R6, R6 + SUBV $1, R5, R5 + BNE R6, R0, flush_buffer + + ADDV R14, R8, R8 + SGTU R14, R8, R24 + ADDV R15, R9, R27 + SGTU R15, R27, R28 + ADDV R27, R24, R9 + SGTU R27, R9, R24 + OR R24, R28, R24 + ADDV R10, R24, R10 + + MOVV $16, R6 + JMP multiply + +done: + MOVV R8, (R4) + MOVV R9, 8(R4) + MOVV R10, 16(R4) + RET diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go deleted file mode 100644 index 1a1679a..0000000 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego && (ppc64 || ppc64le) - -package poly1305 - -//go:noescape -func update(state *macState, msg []byte) - -// mac is a wrapper for macGeneric that redirects calls that would have gone to -// updateGeneric to update. -// -// Its Write and Sum methods are otherwise identical to the macGeneric ones, but -// using function pointers would carry a major performance cost. -type mac struct{ macGeneric } - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - update(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - update(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -func (h *mac) Sum(out *[16]byte) { - state := h.macState - if h.offset > 0 { - update(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go index c9202b0..b6bf546 100644 --- a/vendor/golang.org/x/crypto/ssh/handshake.go +++ b/vendor/golang.org/x/crypto/ssh/handshake.go @@ -5,7 +5,6 @@ package ssh import ( - "crypto/rand" "errors" "fmt" "io" @@ -501,7 +500,7 @@ func (t *handshakeTransport) sendKexInit() error { CompressionClientServer: supportedCompressions, CompressionServerClient: supportedCompressions, } - io.ReadFull(rand.Reader, msg.Cookie[:]) + io.ReadFull(t.config.Rand, msg.Cookie[:]) // We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm, // and possibly to add the ext-info extension algorithm. Since the slice may be the diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go index 109997d..8c31136 100644 --- a/vendor/golang.org/x/oauth2/token.go +++ b/vendor/golang.org/x/oauth2/token.go @@ -169,7 +169,7 @@ func tokenFromInternal(t *internal.Token) *Token { // retrieveToken takes a *Config and uses that to retrieve an *internal.Token. // This token is then mapped from *internal.Token into an *oauth2.Token which is returned along -// with an error.. +// with an error. func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) { tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle), c.authStyleCache.Get()) if err != nil { diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go index 9c105f2..2e73ee1 100644 --- a/vendor/golang.org/x/sys/cpu/cpu.go +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -149,6 +149,18 @@ var ARM struct { _ CacheLinePad } +// The booleans in Loong64 contain the correspondingly named cpu feature bit. +// The struct is padded to avoid false sharing. +var Loong64 struct { + _ CacheLinePad + HasLSX bool // support 128-bit vector extension + HasLASX bool // support 256-bit vector extension + HasCRC32 bool // support CRC instruction + HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction + HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction + _ CacheLinePad +} + // MIPS64X contains the supported CPU features of the current mips64/mips64le // platforms. If the current platform is not mips64/mips64le or the current // operating system is not Linux then all feature flags are false. diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go new file mode 100644 index 0000000..4f34114 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go @@ -0,0 +1,22 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel. +const ( + hwcap_LOONGARCH_LSX = 1 << 4 + hwcap_LOONGARCH_LASX = 1 << 5 +) + +func doinit() { + // TODO: Features that require kernel support like LSX and LASX can + // be detected here once needed in std library or by the compiler. + Loong64.HasLSX = hwcIsSet(hwCap, hwcap_LOONGARCH_LSX) + Loong64.HasLASX = hwcIsSet(hwCap, hwcap_LOONGARCH_LASX) +} + +func hwcIsSet(hwc uint, val uint) bool { + return hwc&val != 0 +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go index 7d902b6..a428dec 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go +++ b/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 +//go:build linux && !arm && !arm64 && !loong64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 package cpu diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/vendor/golang.org/x/sys/cpu/cpu_loong64.go index 5586358..45ecb29 100644 --- a/vendor/golang.org/x/sys/cpu/cpu_loong64.go +++ b/vendor/golang.org/x/sys/cpu/cpu_loong64.go @@ -8,5 +8,43 @@ package cpu const cacheLineSize = 64 +// Bit fields for CPUCFG registers, Related reference documents: +// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg +const ( + // CPUCFG1 bits + cpucfg1_CRC32 = 1 << 25 + + // CPUCFG2 bits + cpucfg2_LAM_BH = 1 << 27 + cpucfg2_LAMCAS = 1 << 28 +) + func initOptions() { + options = []option{ + {Name: "lsx", Feature: &Loong64.HasLSX}, + {Name: "lasx", Feature: &Loong64.HasLASX}, + {Name: "crc32", Feature: &Loong64.HasCRC32}, + {Name: "lam_bh", Feature: &Loong64.HasLAM_BH}, + {Name: "lamcas", Feature: &Loong64.HasLAMCAS}, + } + + // The CPUCFG data on Loong64 only reflects the hardware capabilities, + // not the kernel support status, so features such as LSX and LASX that + // require kernel support cannot be obtained from the CPUCFG data. + // + // These features only require hardware capability support and do not + // require kernel specific support, so they can be obtained directly + // through CPUCFG + cfg1 := get_cpucfg(1) + cfg2 := get_cpucfg(2) + + Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32) + Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS) + Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH) +} + +func get_cpucfg(reg uint32) uint32 + +func cfgIsSet(cfg uint32, val uint32) bool { + return cfg&val != 0 } diff --git a/vendor/golang.org/x/sys/cpu/cpu_loong64.s b/vendor/golang.org/x/sys/cpu/cpu_loong64.s new file mode 100644 index 0000000..71cbaf1 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_loong64.s @@ -0,0 +1,13 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +// func get_cpucfg(reg uint32) uint32 +TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0 + MOVW reg+0(FP), R5 + // CPUCFG R5, R4 = 0x00006ca4 + WORD $0x00006ca4 + MOVW R4, ret+8(FP) + RET diff --git a/vendor/golang.org/x/sys/cpu/parse.go b/vendor/golang.org/x/sys/cpu/parse.go index 762b63d..56a7e1a 100644 --- a/vendor/golang.org/x/sys/cpu/parse.go +++ b/vendor/golang.org/x/sys/cpu/parse.go @@ -13,7 +13,7 @@ import "strconv" // https://golang.org/cl/209597. func parseRelease(rel string) (major, minor, patch int, ok bool) { // Strip anything after a dash or plus. - for i := 0; i < len(rel); i++ { + for i := range len(rel) { if rel[i] == '-' || rel[i] == '+' { rel = rel[:i] break @@ -21,7 +21,7 @@ func parseRelease(rel string) (major, minor, patch int, ok bool) { } next := func() (int, bool) { - for i := 0; i < len(rel); i++ { + for i := range len(rel) { if rel[i] == '.' { ver, err := strconv.Atoi(rel[:i]) rel = rel[i+1:] diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 099867d..798f61a 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -602,7 +602,150 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI return } -//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) +// sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) +const minIovec = 8 + +func Readv(fd int, iovs [][]byte) (n int, err error) { + if !darwinKernelVersionMin(11, 0, 0) { + return 0, ENOSYS + } + + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + n, err = readv(fd, iovecs) + readvRacedetect(iovecs, n, err) + return n, err +} + +func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) { + if !darwinKernelVersionMin(11, 0, 0) { + return 0, ENOSYS + } + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + n, err = preadv(fd, iovecs, offset) + readvRacedetect(iovecs, n, err) + return n, err +} + +func Writev(fd int, iovs [][]byte) (n int, err error) { + if !darwinKernelVersionMin(11, 0, 0) { + return 0, ENOSYS + } + + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + n, err = writev(fd, iovecs) + writevRacedetect(iovecs, n) + return n, err +} + +func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) { + if !darwinKernelVersionMin(11, 0, 0) { + return 0, ENOSYS + } + + iovecs := make([]Iovec, 0, minIovec) + iovecs = appendBytes(iovecs, iovs) + if raceenabled { + raceReleaseMerge(unsafe.Pointer(&ioSync)) + } + n, err = pwritev(fd, iovecs, offset) + writevRacedetect(iovecs, n) + return n, err +} + +func appendBytes(vecs []Iovec, bs [][]byte) []Iovec { + for _, b := range bs { + var v Iovec + v.SetLen(len(b)) + if len(b) > 0 { + v.Base = &b[0] + } else { + v.Base = (*byte)(unsafe.Pointer(&_zero)) + } + vecs = append(vecs, v) + } + return vecs +} + +func writevRacedetect(iovecs []Iovec, n int) { + if !raceenabled { + return + } + for i := 0; n > 0 && i < len(iovecs); i++ { + m := int(iovecs[i].Len) + if m > n { + m = n + } + n -= m + if m > 0 { + raceReadRange(unsafe.Pointer(iovecs[i].Base), m) + } + } +} + +func readvRacedetect(iovecs []Iovec, n int, err error) { + if !raceenabled { + return + } + for i := 0; n > 0 && i < len(iovecs); i++ { + m := int(iovecs[i].Len) + if m > n { + m = n + } + n -= m + if m > 0 { + raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) + } + } + if err == nil { + raceAcquire(unsafe.Pointer(&ioSync)) + } +} + +func darwinMajorMinPatch() (maj, min, patch int, err error) { + var un Utsname + err = Uname(&un) + if err != nil { + return + } + + var mmp [3]int + c := 0 +Loop: + for _, b := range un.Release[:] { + switch { + case b >= '0' && b <= '9': + mmp[c] = 10*mmp[c] + int(b-'0') + case b == '.': + c++ + if c > 2 { + return 0, 0, 0, ENOTSUP + } + case b == 0: + break Loop + default: + return 0, 0, 0, ENOTSUP + } + } + if c != 2 { + return 0, 0, 0, ENOTSUP + } + return mmp[0], mmp[1], mmp[2], nil +} + +func darwinKernelVersionMin(maj, min, patch int) bool { + actualMaj, actualMin, actualPatch, err := darwinMajorMinPatch() + if err != nil { + return false + } + return actualMaj > maj || actualMaj == maj && (actualMin > min || actualMin == min && actualPatch >= patch) +} + //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) @@ -705,3 +848,7 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI //sys write(fd int, p []byte) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys munmap(addr uintptr, length uintptr) (err error) +//sys readv(fd int, iovecs []Iovec) (n int, err error) +//sys preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) +//sys writev(fd int, iovecs []Iovec) (n int, err error) +//sys pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 230a945..4958a65 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -13,6 +13,7 @@ package unix import ( "encoding/binary" + "slices" "strconv" "syscall" "time" @@ -417,7 +418,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { return nil, 0, EINVAL } sa.raw.Family = AF_UNIX - for i := 0; i < n; i++ { + for i := range n { sa.raw.Path[i] = int8(name[i]) } // length is family (uint16), name, NUL. @@ -507,7 +508,7 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) { psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm)) psm[0] = byte(sa.PSM) psm[1] = byte(sa.PSM >> 8) - for i := 0; i < len(sa.Addr); i++ { + for i := range len(sa.Addr) { sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i] } cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid)) @@ -589,11 +590,11 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_CAN sa.raw.Ifindex = int32(sa.Ifindex) rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) - for i := 0; i < 4; i++ { + for i := range 4 { sa.raw.Addr[i] = rx[i] } tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) - for i := 0; i < 4; i++ { + for i := range 4 { sa.raw.Addr[i+4] = tx[i] } return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil @@ -618,11 +619,11 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_CAN sa.raw.Ifindex = int32(sa.Ifindex) n := (*[8]byte)(unsafe.Pointer(&sa.Name)) - for i := 0; i < 8; i++ { + for i := range 8 { sa.raw.Addr[i] = n[i] } p := (*[4]byte)(unsafe.Pointer(&sa.PGN)) - for i := 0; i < 4; i++ { + for i := range 4 { sa.raw.Addr[i+8] = p[i] } sa.raw.Addr[12] = sa.Addr @@ -911,7 +912,7 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) { // These are EBCDIC encoded by the kernel, but we still need to pad them // with blanks. Initializing with blanks allows the caller to feed in either // a padded or an unpadded string. - for i := 0; i < 8; i++ { + for i := range 8 { sa.raw.Nodeid[i] = ' ' sa.raw.User_id[i] = ' ' sa.raw.Name[i] = ' ' @@ -1148,7 +1149,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { var user [8]byte var name [8]byte - for i := 0; i < 8; i++ { + for i := range 8 { user[i] = byte(pp.User_id[i]) name[i] = byte(pp.Name[i]) } @@ -1173,11 +1174,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { Ifindex: int(pp.Ifindex), } name := (*[8]byte)(unsafe.Pointer(&sa.Name)) - for i := 0; i < 8; i++ { + for i := range 8 { name[i] = pp.Addr[i] } pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN)) - for i := 0; i < 4; i++ { + for i := range 4 { pgn[i] = pp.Addr[i+8] } addr := (*[1]byte)(unsafe.Pointer(&sa.Addr)) @@ -1188,11 +1189,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { Ifindex: int(pp.Ifindex), } rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) - for i := 0; i < 4; i++ { + for i := range 4 { rx[i] = pp.Addr[i] } tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) - for i := 0; i < 4; i++ { + for i := range 4 { tx[i] = pp.Addr[i+4] } return sa, nil @@ -2216,10 +2217,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) { return } for i := 0; n > 0 && i < len(iovecs); i++ { - m := int(iovecs[i].Len) - if m > n { - m = n - } + m := min(int(iovecs[i].Len), n) n -= m if m > 0 { raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) @@ -2270,10 +2268,7 @@ func writevRacedetect(iovecs []Iovec, n int) { return } for i := 0; n > 0 && i < len(iovecs); i++ { - m := int(iovecs[i].Len) - if m > n { - m = n - } + m := min(int(iovecs[i].Len), n) n -= m if m > 0 { raceReadRange(unsafe.Pointer(iovecs[i].Base), m) @@ -2320,12 +2315,7 @@ func isGroupMember(gid int) bool { return false } - for _, g := range groups { - if g == gid { - return true - } - } - return false + return slices.Contains(groups, gid) } func isCapDacOverrideSet() bool { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go index 24b346e..813c05b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go @@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func readv(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_readv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_preadv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writev(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_writev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pwritev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstat(fd int, stat *Stat_t) (err error) { _, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s index ebd2131..fda3285 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s @@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) +TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readv(SB) +GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB) + +TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_preadv(SB) +GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB) + +TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_writev(SB) +GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB) + +TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pwritev(SB) +GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB) + TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstat64(SB) GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go index 824b9c2..e6f58f3 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go @@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func readv(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_readv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_preadv_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writev(fd int, iovecs []Iovec) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_writev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(iovecs) > 0 { + _p0 = unsafe.Pointer(&iovecs[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +var libc_pwritev_trampoline_addr uintptr + +//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstat(fd int, stat *Stat_t) (err error) { _, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) if e1 != 0 { diff --git a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s index 4f178a2..7f8998b 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s +++ b/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s @@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0 GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) +TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_readv(SB) +GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB) + +TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_preadv(SB) +GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8 +DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB) + +TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_writev(SB) +GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB) + +TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0 + JMP libc_pwritev(SB) +GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8 +DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB) + TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0 JMP libc_fstat(SB) GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8 diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index 9d138de..ad67df2 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -1074,6 +1074,7 @@ const ( IP_ADD_MEMBERSHIP = 0xc IP_DROP_MEMBERSHIP = 0xd IP_PKTINFO = 0x13 + IP_MTU_DISCOVER = 0x47 IPV6_V6ONLY = 0x1b IPV6_UNICAST_HOPS = 0x4 @@ -1083,6 +1084,7 @@ const ( IPV6_JOIN_GROUP = 0xc IPV6_LEAVE_GROUP = 0xd IPV6_PKTINFO = 0x13 + IPV6_MTU_DISCOVER = 0x47 MSG_OOB = 0x1 MSG_PEEK = 0x2 @@ -1132,6 +1134,15 @@ const ( WSASYS_STATUS_LEN = 128 ) +// enum PMTUD_STATE from ws2ipdef.h +const ( + IP_PMTUDISC_NOT_SET = 0 + IP_PMTUDISC_DO = 1 + IP_PMTUDISC_DONT = 2 + IP_PMTUDISC_PROBE = 3 + IP_PMTUDISC_MAX = 4 +) + type WSABuf struct { Len uint32 Buf *byte @@ -1146,6 +1157,22 @@ type WSAMsg struct { Flags uint32 } +type WSACMSGHDR struct { + Len uintptr + Level int32 + Type int32 +} + +type IN_PKTINFO struct { + Addr [4]byte + Ifindex uint32 +} + +type IN6_PKTINFO struct { + Addr [16]byte + Ifindex uint32 +} + // Flags for WSASocket const ( WSA_FLAG_OVERLAPPED = 0x01 diff --git a/vendor/golang.org/x/term/terminal.go b/vendor/golang.org/x/term/terminal.go index f636667..14f8947 100644 --- a/vendor/golang.org/x/term/terminal.go +++ b/vendor/golang.org/x/term/terminal.go @@ -44,6 +44,8 @@ type Terminal struct { // bytes, as an index into |line|). If it returns ok=false, the key // press is processed normally. Otherwise it returns a replacement line // and the new cursor position. + // + // This will be disabled during ReadPassword. AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) // Escape contains a pointer to the escape codes for this terminal. @@ -692,6 +694,8 @@ func (t *Terminal) Write(buf []byte) (n int, err error) { // ReadPassword temporarily changes the prompt and reads a password, without // echo, from the terminal. +// +// The AutoCompleteCallback is disabled during this call. func (t *Terminal) ReadPassword(prompt string) (line string, err error) { t.lock.Lock() defer t.lock.Unlock() @@ -699,6 +703,11 @@ func (t *Terminal) ReadPassword(prompt string) (line string, err error) { oldPrompt := t.prompt t.prompt = []rune(prompt) t.echo = false + oldAutoCompleteCallback := t.AutoCompleteCallback + t.AutoCompleteCallback = nil + defer func() { + t.AutoCompleteCallback = oldAutoCompleteCallback + }() line, err = t.readLine() diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go index d5ed172..4d57687 100644 --- a/vendor/google.golang.org/grpc/balancer/base/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go @@ -41,7 +41,7 @@ func (bb *baseBuilder) Build(cc balancer.ClientConn, _ balancer.BuildOptions) ba cc: cc, pickerBuilder: bb.pickerBuilder, - subConns: resolver.NewAddressMap(), + subConns: resolver.NewAddressMapV2[balancer.SubConn](), scStates: make(map[balancer.SubConn]connectivity.State), csEvltr: &balancer.ConnectivityStateEvaluator{}, config: bb.config, @@ -65,7 +65,7 @@ type baseBalancer struct { csEvltr *balancer.ConnectivityStateEvaluator state connectivity.State - subConns *resolver.AddressMap + subConns *resolver.AddressMapV2[balancer.SubConn] scStates map[balancer.SubConn]connectivity.State picker balancer.Picker config Config @@ -100,7 +100,7 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error { // Successful resolution; clear resolver error and ensure we return nil. b.resolverErr = nil // addrsSet is the set converted from addrs, it's used for quick lookup of an address. - addrsSet := resolver.NewAddressMap() + addrsSet := resolver.NewAddressMapV2[any]() for _, a := range s.ResolverState.Addresses { addrsSet.Set(a, nil) if _, ok := b.subConns.Get(a); !ok { @@ -122,8 +122,7 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error { } } for _, a := range b.subConns.Keys() { - sci, _ := b.subConns.Get(a) - sc := sci.(balancer.SubConn) + sc, _ := b.subConns.Get(a) // a was removed by resolver. if _, ok := addrsSet.Get(a); !ok { sc.Shutdown() @@ -173,8 +172,7 @@ func (b *baseBalancer) regeneratePicker() { // Filter out all ready SCs from full subConn map. for _, addr := range b.subConns.Keys() { - sci, _ := b.subConns.Get(addr) - sc := sci.(balancer.SubConn) + sc, _ := b.subConns.Get(addr) if st, ok := b.scStates[sc]; ok && st == connectivity.Ready { readySCs[sc] = SubConnInfo{Address: addr} } diff --git a/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go b/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go index 421c4fe..cc606f4 100644 --- a/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go +++ b/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go @@ -73,7 +73,7 @@ func NewBalancer(cc balancer.ClientConn, opts balancer.BuildOptions, childBuilde esOpts: esOpts, childBuilder: childBuilder, } - es.children.Store(resolver.NewEndpointMap()) + es.children.Store(resolver.NewEndpointMap[*balancerWrapper]()) return es } @@ -90,7 +90,7 @@ type endpointSharding struct { // calls into a child. To avoid deadlocks, do not acquire childMu while // holding mu. childMu sync.Mutex - children atomic.Pointer[resolver.EndpointMap] // endpoint -> *balancerWrapper + children atomic.Pointer[resolver.EndpointMap[*balancerWrapper]] // inhibitChildUpdates is set during UpdateClientConnState/ResolverError // calls (calls to children will each produce an update, only want one @@ -122,7 +122,7 @@ func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState var ret error children := es.children.Load() - newChildren := resolver.NewEndpointMap() + newChildren := resolver.NewEndpointMap[*balancerWrapper]() // Update/Create new children. for _, endpoint := range state.ResolverState.Endpoints { @@ -131,9 +131,8 @@ func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState // update. continue } - var childBalancer *balancerWrapper - if val, ok := children.Get(endpoint); ok { - childBalancer = val.(*balancerWrapper) + childBalancer, ok := children.Get(endpoint) + if ok { // Endpoint attributes may have changed, update the stored endpoint. es.mu.Lock() childBalancer.childState.Endpoint = endpoint @@ -166,7 +165,7 @@ func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState for _, e := range children.Keys() { child, _ := children.Get(e) if _, ok := newChildren.Get(e); !ok { - child.(*balancerWrapper).closeLocked() + child.closeLocked() } } es.children.Store(newChildren) @@ -189,7 +188,7 @@ func (es *endpointSharding) ResolverError(err error) { }() children := es.children.Load() for _, child := range children.Values() { - child.(*balancerWrapper).resolverErrorLocked(err) + child.resolverErrorLocked(err) } } @@ -202,7 +201,7 @@ func (es *endpointSharding) Close() { defer es.childMu.Unlock() children := es.children.Load() for _, child := range children.Values() { - child.(*balancerWrapper).closeLocked() + child.closeLocked() } } @@ -222,8 +221,7 @@ func (es *endpointSharding) updateState() { childStates := make([]ChildState, 0, children.Len()) for _, child := range children.Values() { - bw := child.(*balancerWrapper) - childState := bw.childState + childState := child.childState childStates = append(childStates, childState) childPicker := childState.State.Picker switch childState.State.ConnectivityState { diff --git a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go index 113181e..494314f 100644 --- a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go +++ b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go @@ -122,7 +122,7 @@ func (pickfirstBuilder) Build(cc balancer.ClientConn, bo balancer.BuildOptions) target: bo.Target.String(), metricsRecorder: cc.MetricsRecorder(), - subConns: resolver.NewAddressMap(), + subConns: resolver.NewAddressMapV2[*scData](), state: connectivity.Connecting, cancelConnectionTimer: func() {}, } @@ -220,7 +220,7 @@ type pickfirstBalancer struct { // updates. state connectivity.State // scData for active subonns mapped by address. - subConns *resolver.AddressMap + subConns *resolver.AddressMapV2[*scData] addressList addressList firstPass bool numTF int @@ -319,7 +319,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState prevAddr := b.addressList.currentAddress() prevSCData, found := b.subConns.Get(prevAddr) prevAddrsCount := b.addressList.size() - isPrevRawConnectivityStateReady := found && prevSCData.(*scData).rawConnectivityState == connectivity.Ready + isPrevRawConnectivityStateReady := found && prevSCData.rawConnectivityState == connectivity.Ready b.addressList.updateAddrs(newAddrs) // If the previous ready SubConn exists in new address list, @@ -381,21 +381,21 @@ func (b *pickfirstBalancer) startFirstPassLocked() { b.numTF = 0 // Reset the connection attempt record for existing SubConns. for _, sd := range b.subConns.Values() { - sd.(*scData).connectionFailedInFirstPass = false + sd.connectionFailedInFirstPass = false } b.requestConnectionLocked() } func (b *pickfirstBalancer) closeSubConnsLocked() { for _, sd := range b.subConns.Values() { - sd.(*scData).subConn.Shutdown() + sd.subConn.Shutdown() } - b.subConns = resolver.NewAddressMap() + b.subConns = resolver.NewAddressMapV2[*scData]() } // deDupAddresses ensures that each address appears only once in the slice. func deDupAddresses(addrs []resolver.Address) []resolver.Address { - seenAddrs := resolver.NewAddressMap() + seenAddrs := resolver.NewAddressMapV2[*scData]() retAddrs := []resolver.Address{} for _, addr := range addrs { @@ -481,7 +481,7 @@ func addressFamily(address string) ipAddrFamily { // This ensures that the subchannel map accurately reflects the current set of // addresses received from the name resolver. func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address) { - newAddrsMap := resolver.NewAddressMap() + newAddrsMap := resolver.NewAddressMapV2[bool]() for _, addr := range newAddrs { newAddrsMap.Set(addr, true) } @@ -491,7 +491,7 @@ func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address) continue } val, _ := b.subConns.Get(oldAddr) - val.(*scData).subConn.Shutdown() + val.subConn.Shutdown() b.subConns.Delete(oldAddr) } } @@ -500,13 +500,12 @@ func (b *pickfirstBalancer) reconcileSubConnsLocked(newAddrs []resolver.Address) // becomes ready, which means that all other subConn must be shutdown. func (b *pickfirstBalancer) shutdownRemainingLocked(selected *scData) { b.cancelConnectionTimer() - for _, v := range b.subConns.Values() { - sd := v.(*scData) + for _, sd := range b.subConns.Values() { if sd.subConn != selected.subConn { sd.subConn.Shutdown() } } - b.subConns = resolver.NewAddressMap() + b.subConns = resolver.NewAddressMapV2[*scData]() b.subConns.Set(selected.addr, selected) } @@ -539,18 +538,17 @@ func (b *pickfirstBalancer) requestConnectionLocked() { b.subConns.Set(curAddr, sd) } - scd := sd.(*scData) - switch scd.rawConnectivityState { + switch sd.rawConnectivityState { case connectivity.Idle: - scd.subConn.Connect() + sd.subConn.Connect() b.scheduleNextConnectionLocked() return case connectivity.TransientFailure: // The SubConn is being re-used and failed during a previous pass // over the addressList. It has not completed backoff yet. // Mark it as having failed and try the next address. - scd.connectionFailedInFirstPass = true - lastErr = scd.lastErr + sd.connectionFailedInFirstPass = true + lastErr = sd.lastErr continue case connectivity.Connecting: // Wait for the connection attempt to complete or the timer to fire @@ -558,7 +556,7 @@ func (b *pickfirstBalancer) requestConnectionLocked() { b.scheduleNextConnectionLocked() return default: - b.logger.Errorf("SubConn with unexpected state %v present in SubConns map.", scd.rawConnectivityState) + b.logger.Errorf("SubConn with unexpected state %v present in SubConns map.", sd.rawConnectivityState) return } @@ -753,8 +751,7 @@ func (b *pickfirstBalancer) endFirstPassIfPossibleLocked(lastErr error) { } // Connect() has been called on all the SubConns. The first pass can be // ended if all the SubConns have reported a failure. - for _, v := range b.subConns.Values() { - sd := v.(*scData) + for _, sd := range b.subConns.Values() { if !sd.connectionFailedInFirstPass { return } @@ -765,8 +762,7 @@ func (b *pickfirstBalancer) endFirstPassIfPossibleLocked(lastErr error) { Picker: &picker{err: lastErr}, }) // Start re-connecting all the SubConns that are already in IDLE. - for _, v := range b.subConns.Values() { - sd := v.(*scData) + for _, sd := range b.subConns.Values() { if sd.rawConnectivityState == connectivity.Idle { sd.subConn.Connect() } @@ -927,6 +923,5 @@ func (al *addressList) hasNext() bool { // fields that are meaningful to the SubConn. func equalAddressIgnoringBalAttributes(a, b *resolver.Address) bool { return a.Addr == b.Addr && a.ServerName == b.ServerName && - a.Attributes.Equal(b.Attributes) && - a.Metadata == b.Metadata + a.Attributes.Equal(b.Attributes) } diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go index b2f8fc7..825c317 100644 --- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -18,7 +18,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.4 +// protoc-gen-go v1.36.5 // protoc v5.27.1 // source: grpc/binlog/v1/binarylog.proto diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index a319ef9..4f350ca 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -1231,8 +1231,7 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error) // adjustParams updates parameters used to create transports upon // receiving a GoAway. func (ac *addrConn) adjustParams(r transport.GoAwayReason) { - switch r { - case transport.GoAwayTooManyPings: + if r == transport.GoAwayTooManyPings { v := 2 * ac.dopts.copts.KeepaliveParams.Time ac.cc.mu.Lock() if v > ac.cc.keepaliveParams.Time { diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go index 94177b0..faa59e4 100644 --- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go +++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.4 +// protoc-gen-go v1.36.5 // protoc v5.27.1 // source: grpc/health/v1/health.proto @@ -178,6 +178,87 @@ func (x *HealthCheckResponse) GetStatus() HealthCheckResponse_ServingStatus { return HealthCheckResponse_UNKNOWN } +type HealthListRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HealthListRequest) Reset() { + *x = HealthListRequest{} + mi := &file_grpc_health_v1_health_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HealthListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthListRequest) ProtoMessage() {} + +func (x *HealthListRequest) ProtoReflect() protoreflect.Message { + mi := &file_grpc_health_v1_health_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthListRequest.ProtoReflect.Descriptor instead. +func (*HealthListRequest) Descriptor() ([]byte, []int) { + return file_grpc_health_v1_health_proto_rawDescGZIP(), []int{2} +} + +type HealthListResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // statuses contains all the services and their respective status. + Statuses map[string]*HealthCheckResponse `protobuf:"bytes,1,rep,name=statuses,proto3" json:"statuses,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *HealthListResponse) Reset() { + *x = HealthListResponse{} + mi := &file_grpc_health_v1_health_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *HealthListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HealthListResponse) ProtoMessage() {} + +func (x *HealthListResponse) ProtoReflect() protoreflect.Message { + mi := &file_grpc_health_v1_health_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HealthListResponse.ProtoReflect.Descriptor instead. +func (*HealthListResponse) Descriptor() ([]byte, []int) { + return file_grpc_health_v1_health_proto_rawDescGZIP(), []int{3} +} + +func (x *HealthListResponse) GetStatuses() map[string]*HealthCheckResponse { + if x != nil { + return x.Statuses + } + return nil +} + var File_grpc_health_v1_health_proto protoreflect.FileDescriptor var file_grpc_health_v1_health_proto_rawDesc = string([]byte{ @@ -198,25 +279,44 @@ var file_grpc_health_v1_health_proto_rawDesc = string([]byte{ 0x0a, 0x07, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4e, 0x4f, 0x54, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x03, 0x32, 0xae, 0x01, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x50, 0x0a, 0x05, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, + 0x03, 0x22, 0x13, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xc4, 0x01, 0x0a, 0x12, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, + 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, + 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x1a, 0x60, 0x0a, 0x0d, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xfd, 0x01, + 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x50, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, + 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, - 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x30, 0x01, 0x42, 0x70, 0x0a, 0x11, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, - 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, - 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x68, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x5f, 0x76, 0x31, 0xa2, 0x02, 0x0c, 0x47, 0x72, 0x70, 0x63, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x56, 0x31, 0xaa, 0x02, 0x0e, 0x47, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, - 0x68, 0x2e, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x04, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x05, 0x57, 0x61, 0x74, + 0x63, 0x68, 0x12, 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x70, 0x0a, + 0x11, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, + 0x76, 0x31, 0x42, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x2c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x5f, 0x76, 0x31, 0xa2, + 0x02, 0x0c, 0x47, 0x72, 0x70, 0x63, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x56, 0x31, 0xaa, 0x02, + 0x0e, 0x47, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x56, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -232,23 +332,30 @@ func file_grpc_health_v1_health_proto_rawDescGZIP() []byte { } var file_grpc_health_v1_health_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_grpc_health_v1_health_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_grpc_health_v1_health_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_grpc_health_v1_health_proto_goTypes = []any{ (HealthCheckResponse_ServingStatus)(0), // 0: grpc.health.v1.HealthCheckResponse.ServingStatus (*HealthCheckRequest)(nil), // 1: grpc.health.v1.HealthCheckRequest (*HealthCheckResponse)(nil), // 2: grpc.health.v1.HealthCheckResponse + (*HealthListRequest)(nil), // 3: grpc.health.v1.HealthListRequest + (*HealthListResponse)(nil), // 4: grpc.health.v1.HealthListResponse + nil, // 5: grpc.health.v1.HealthListResponse.StatusesEntry } var file_grpc_health_v1_health_proto_depIdxs = []int32{ 0, // 0: grpc.health.v1.HealthCheckResponse.status:type_name -> grpc.health.v1.HealthCheckResponse.ServingStatus - 1, // 1: grpc.health.v1.Health.Check:input_type -> grpc.health.v1.HealthCheckRequest - 1, // 2: grpc.health.v1.Health.Watch:input_type -> grpc.health.v1.HealthCheckRequest - 2, // 3: grpc.health.v1.Health.Check:output_type -> grpc.health.v1.HealthCheckResponse - 2, // 4: grpc.health.v1.Health.Watch:output_type -> grpc.health.v1.HealthCheckResponse - 3, // [3:5] is the sub-list for method output_type - 1, // [1:3] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 5, // 1: grpc.health.v1.HealthListResponse.statuses:type_name -> grpc.health.v1.HealthListResponse.StatusesEntry + 2, // 2: grpc.health.v1.HealthListResponse.StatusesEntry.value:type_name -> grpc.health.v1.HealthCheckResponse + 1, // 3: grpc.health.v1.Health.Check:input_type -> grpc.health.v1.HealthCheckRequest + 3, // 4: grpc.health.v1.Health.List:input_type -> grpc.health.v1.HealthListRequest + 1, // 5: grpc.health.v1.Health.Watch:input_type -> grpc.health.v1.HealthCheckRequest + 2, // 6: grpc.health.v1.Health.Check:output_type -> grpc.health.v1.HealthCheckResponse + 4, // 7: grpc.health.v1.Health.List:output_type -> grpc.health.v1.HealthListResponse + 2, // 8: grpc.health.v1.Health.Watch:output_type -> grpc.health.v1.HealthCheckResponse + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_grpc_health_v1_health_proto_init() } @@ -262,7 +369,7 @@ func file_grpc_health_v1_health_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_grpc_health_v1_health_proto_rawDesc), len(file_grpc_health_v1_health_proto_rawDesc)), NumEnums: 1, - NumMessages: 2, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go index f96b8ab..9313661 100644 --- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go +++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go @@ -37,6 +37,7 @@ const _ = grpc.SupportPackageIsVersion9 const ( Health_Check_FullMethodName = "/grpc.health.v1.Health/Check" + Health_List_FullMethodName = "/grpc.health.v1.Health/List" Health_Watch_FullMethodName = "/grpc.health.v1.Health/Watch" ) @@ -55,9 +56,19 @@ type HealthClient interface { // // Clients should set a deadline when calling Check, and can declare the // server unhealthy if they do not receive a timely response. - // - // Check implementations should be idempotent and side effect free. Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) + // List provides a non-atomic snapshot of the health of all the available + // services. + // + // The server may respond with a RESOURCE_EXHAUSTED error if too many services + // exist. + // + // Clients should set a deadline when calling List, and can declare the server + // unhealthy if they do not receive a timely response. + // + // Clients should keep in mind that the list of health services exposed by an + // application can change over the lifetime of the process. + List(ctx context.Context, in *HealthListRequest, opts ...grpc.CallOption) (*HealthListResponse, error) // Performs a watch for the serving status of the requested service. // The server will immediately send back a message indicating the current // serving status. It will then subsequently send a new message whenever @@ -94,6 +105,16 @@ func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts . return out, nil } +func (c *healthClient) List(ctx context.Context, in *HealthListRequest, opts ...grpc.CallOption) (*HealthListResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(HealthListResponse) + err := c.cc.Invoke(ctx, Health_List_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *healthClient) Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[HealthCheckResponse], error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) stream, err := c.cc.NewStream(ctx, &Health_ServiceDesc.Streams[0], Health_Watch_FullMethodName, cOpts...) @@ -128,9 +149,19 @@ type HealthServer interface { // // Clients should set a deadline when calling Check, and can declare the // server unhealthy if they do not receive a timely response. - // - // Check implementations should be idempotent and side effect free. Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) + // List provides a non-atomic snapshot of the health of all the available + // services. + // + // The server may respond with a RESOURCE_EXHAUSTED error if too many services + // exist. + // + // Clients should set a deadline when calling List, and can declare the server + // unhealthy if they do not receive a timely response. + // + // Clients should keep in mind that the list of health services exposed by an + // application can change over the lifetime of the process. + List(context.Context, *HealthListRequest) (*HealthListResponse, error) // Performs a watch for the serving status of the requested service. // The server will immediately send back a message indicating the current // serving status. It will then subsequently send a new message whenever @@ -159,6 +190,9 @@ type UnimplementedHealthServer struct{} func (UnimplementedHealthServer) Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Check not implemented") } +func (UnimplementedHealthServer) List(context.Context, *HealthListRequest) (*HealthListResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method List not implemented") +} func (UnimplementedHealthServer) Watch(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckResponse]) error { return status.Errorf(codes.Unimplemented, "method Watch not implemented") } @@ -200,6 +234,24 @@ func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Health_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HealthListRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HealthServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Health_List_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HealthServer).List(ctx, req.(*HealthListRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Health_Watch_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(HealthCheckRequest) if err := stream.RecvMsg(m); err != nil { @@ -222,6 +274,10 @@ var Health_ServiceDesc = grpc.ServiceDesc{ MethodName: "Check", Handler: _Health_Check_Handler, }, + { + MethodName: "List", + Handler: _Health_List_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 1e42b6f..cc5713f 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -51,10 +51,24 @@ var ( // xDS server in the list of server configs will be used. XDSFallbackSupport = boolFromEnv("GRPC_EXPERIMENTAL_XDS_FALLBACK", true) // NewPickFirstEnabled is set if the new pickfirst leaf policy is to be used - // instead of the exiting pickfirst implementation. This can be enabled by + // instead of the exiting pickfirst implementation. This can be disabled by // setting the environment variable "GRPC_EXPERIMENTAL_ENABLE_NEW_PICK_FIRST" - // to "true". - NewPickFirstEnabled = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_NEW_PICK_FIRST", false) + // to "false". + NewPickFirstEnabled = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_NEW_PICK_FIRST", true) + + // XDSEndpointHashKeyBackwardCompat controls the parsing of the endpoint hash + // key from EDS LbEndpoint metadata. Endpoint hash keys can be disabled by + // setting "GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT" to "true". When the + // implementation of A76 is stable, we will flip the default value to false + // in a subsequent release. A final release will remove this environment + // variable, enabling the new behavior unconditionally. + XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", true) + + // RingHashSetRequestHashKey is set if the ring hash balancer can get the + // request hash header by setting the "requestHashHeader" field, according + // to gRFC A76. It can be enabled by setting the environment variable + // "GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY" to "true". + RingHashSetRequestHashKey = boolFromEnv("GRPC_EXPERIMENTAL_RING_HASH_SET_REQUEST_HASH_KEY", false) ) func boolFromEnv(envVar string, def bool) bool { diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go index 13e1f38..2ce012c 100644 --- a/vendor/google.golang.org/grpc/internal/internal.go +++ b/vendor/google.golang.org/grpc/internal/internal.go @@ -259,6 +259,13 @@ var ( // SetBufferPoolingThresholdForTesting updates the buffer pooling threshold, for // testing purposes. SetBufferPoolingThresholdForTesting any // func(int) + + // TimeAfterFunc is used to create timers. During tests the function is + // replaced to track allocated timers and fail the test if a timer isn't + // cancelled. + TimeAfterFunc = func(d time.Duration, f func()) Timer { + return time.AfterFunc(d, f) + } ) // HealthChecker defines the signature of the client-side LB channel health @@ -300,3 +307,9 @@ type EnforceSubConnEmbedding interface { type EnforceClientConnEmbedding interface { enforceClientConnEmbedding() } + +// Timer is an interface to allow injecting different time.Timer implementations +// during tests. +type Timer interface { + Stop() bool +} diff --git a/vendor/google.golang.org/grpc/internal/metadata/metadata.go b/vendor/google.golang.org/grpc/internal/metadata/metadata.go index 900bfb7..c4055bc 100644 --- a/vendor/google.golang.org/grpc/internal/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/internal/metadata/metadata.go @@ -97,13 +97,11 @@ func hasNotPrintable(msg string) bool { return false } -// ValidatePair validate a key-value pair with the following rules (the pseudo-header will be skipped) : -// -// - key must contain one or more characters. -// - the characters in the key must be contained in [0-9 a-z _ - .]. -// - if the key ends with a "-bin" suffix, no validation of the corresponding value is performed. -// - the characters in the every value must be printable (in [%x20-%x7E]). -func ValidatePair(key string, vals ...string) error { +// ValidateKey validates a key with the following rules (pseudo-headers are +// skipped): +// - the key must contain one or more characters. +// - the characters in the key must be in [0-9 a-z _ - .]. +func ValidateKey(key string) error { // key should not be empty if key == "" { return fmt.Errorf("there is an empty key in the header") @@ -119,6 +117,20 @@ func ValidatePair(key string, vals ...string) error { return fmt.Errorf("header key %q contains illegal characters not in [0-9a-z-_.]", key) } } + return nil +} + +// ValidatePair validates a key-value pair with the following rules +// (pseudo-header are skipped): +// - the key must contain one or more characters. +// - the characters in the key must be in [0-9 a-z _ - .]. +// - if the key ends with a "-bin" suffix, no validation of the corresponding +// value is performed. +// - the characters in every value must be printable (in [%x20-%x7E]). +func ValidatePair(key string, vals ...string) error { + if err := ValidateKey(key); err != nil { + return err + } if strings.HasSuffix(key, "-bin") { return nil } diff --git a/vendor/google.golang.org/grpc/internal/resolver/delegatingresolver/delegatingresolver.go b/vendor/google.golang.org/grpc/internal/resolver/delegatingresolver/delegatingresolver.go index a6c6470..7b93f69 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/delegatingresolver/delegatingresolver.go +++ b/vendor/google.golang.org/grpc/internal/resolver/delegatingresolver/delegatingresolver.go @@ -44,15 +44,19 @@ var ( // // It implements the [resolver.Resolver] interface. type delegatingResolver struct { - target resolver.Target // parsed target URI to be resolved - cc resolver.ClientConn // gRPC ClientConn - targetResolver resolver.Resolver // resolver for the target URI, based on its scheme - proxyResolver resolver.Resolver // resolver for the proxy URI; nil if no proxy is configured - proxyURL *url.URL // proxy URL, derived from proxy environment and target + target resolver.Target // parsed target URI to be resolved + cc resolver.ClientConn // gRPC ClientConn + proxyURL *url.URL // proxy URL, derived from proxy environment and target mu sync.Mutex // protects all the fields below targetResolverState *resolver.State // state of the target resolver proxyAddrs []resolver.Address // resolved proxy addresses; empty if no proxy is configured + + // childMu serializes calls into child resolvers. It also protects access to + // the following fields. + childMu sync.Mutex + targetResolver resolver.Resolver // resolver for the target URI, based on its scheme + proxyResolver resolver.Resolver // resolver for the proxy URI; nil if no proxy is configured } // nopResolver is a resolver that does nothing. @@ -111,6 +115,10 @@ func New(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOpti logger.Infof("Proxy URL detected : %s", r.proxyURL) } + // Resolver updates from one child may trigger calls into the other. Block + // updates until the children are initialized. + r.childMu.Lock() + defer r.childMu.Unlock() // When the scheme is 'dns' and target resolution on client is not enabled, // resolution should be handled by the proxy, not the client. Therefore, we // bypass the target resolver and store the unresolved target address. @@ -165,11 +173,15 @@ func (r *delegatingResolver) proxyURIResolver(opts resolver.BuildOptions) (resol } func (r *delegatingResolver) ResolveNow(o resolver.ResolveNowOptions) { + r.childMu.Lock() + defer r.childMu.Unlock() r.targetResolver.ResolveNow(o) r.proxyResolver.ResolveNow(o) } func (r *delegatingResolver) Close() { + r.childMu.Lock() + defer r.childMu.Unlock() r.targetResolver.Close() r.targetResolver = nil @@ -267,11 +279,17 @@ func (r *delegatingResolver) updateProxyResolverState(state resolver.State) erro err := r.updateClientConnStateLocked() // Another possible approach was to block until updates are received from // both resolvers. But this is not used because calling `New()` triggers - // `Build()` for the first resolver, which calls `UpdateState()`. And the + // `Build()` for the first resolver, which calls `UpdateState()`. And the // second resolver hasn't sent an update yet, so it would cause `New()` to // block indefinitely. if err != nil { - r.targetResolver.ResolveNow(resolver.ResolveNowOptions{}) + go func() { + r.childMu.Lock() + defer r.childMu.Unlock() + if r.targetResolver != nil { + r.targetResolver.ResolveNow(resolver.ResolveNowOptions{}) + } + }() } return err } @@ -291,7 +309,13 @@ func (r *delegatingResolver) updateTargetResolverState(state resolver.State) err r.targetResolverState = &state err := r.updateClientConnStateLocked() if err != nil { - r.proxyResolver.ResolveNow(resolver.ResolveNowOptions{}) + go func() { + r.childMu.Lock() + defer r.childMu.Unlock() + if r.proxyResolver != nil { + r.proxyResolver.ResolveNow(resolver.ResolveNowOptions{}) + } + }() } return nil } diff --git a/vendor/google.golang.org/grpc/internal/transport/client_stream.go b/vendor/google.golang.org/grpc/internal/transport/client_stream.go index 8ed347c..ccc0e01 100644 --- a/vendor/google.golang.org/grpc/internal/transport/client_stream.go +++ b/vendor/google.golang.org/grpc/internal/transport/client_stream.go @@ -59,7 +59,7 @@ func (s *ClientStream) Read(n int) (mem.BufferSlice, error) { return b, err } -// Close closes the stream and popagates err to any readers. +// Close closes the stream and propagates err to any readers. func (s *ClientStream) Close(err error) { var ( rst bool diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 513dbb9..ae93166 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -1390,8 +1390,7 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) error { // the caller. func (t *http2Client) setGoAwayReason(f *http2.GoAwayFrame) { t.goAwayReason = GoAwayNoReason - switch f.ErrCode { - case http2.ErrCodeEnhanceYourCalm: + if f.ErrCode == http2.ErrCodeEnhanceYourCalm { if string(f.DebugData()) == "too_many_pings" { t.goAwayReason = GoAwayTooManyPings } diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index 997b0a5..7e53eb1 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -35,6 +35,7 @@ import ( "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" + "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcutil" "google.golang.org/grpc/internal/pretty" @@ -598,6 +599,22 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade if len(t.activeStreams) == 1 { t.idle = time.Time{} } + // Start a timer to close the stream on reaching the deadline. + if timeoutSet { + // We need to wait for s.cancel to be updated before calling + // t.closeStream to avoid data races. + cancelUpdated := make(chan struct{}) + timer := internal.TimeAfterFunc(timeout, func() { + <-cancelUpdated + t.closeStream(s, true, http2.ErrCodeCancel, false) + }) + oldCancel := s.cancel + s.cancel = func() { + oldCancel() + timer.Stop() + } + close(cancelUpdated) + } t.mu.Unlock() if channelz.IsOn() { t.channelz.SocketMetrics.StreamsStarted.Add(1) @@ -1274,7 +1291,6 @@ func (t *http2Server) Close(err error) { // deleteStream deletes the stream s from transport's active streams. func (t *http2Server) deleteStream(s *ServerStream, eosReceived bool) { - t.mu.Lock() if _, ok := t.activeStreams[s.id]; ok { delete(t.activeStreams, s.id) @@ -1324,7 +1340,10 @@ func (t *http2Server) closeStream(s *ServerStream, rst bool, rstCode http2.ErrCo // called to interrupt the potential blocking on other goroutines. s.cancel() - s.swapState(streamDone) + oldState := s.swapState(streamDone) + if oldState == streamDone { + return + } t.deleteStream(s, eosReceived) t.controlBuf.put(&cleanupStream{ diff --git a/vendor/google.golang.org/grpc/internal/transport/server_stream.go b/vendor/google.golang.org/grpc/internal/transport/server_stream.go index a22a901..cf8da0b 100644 --- a/vendor/google.golang.org/grpc/internal/transport/server_stream.go +++ b/vendor/google.golang.org/grpc/internal/transport/server_stream.go @@ -35,8 +35,10 @@ type ServerStream struct { *Stream // Embed for common stream functionality. st internalServerTransport - ctxDone <-chan struct{} // closed at the end of stream. Cache of ctx.Done() (for performance) - cancel context.CancelFunc // invoked at the end of stream to cancel ctx. + ctxDone <-chan struct{} // closed at the end of stream. Cache of ctx.Done() (for performance) + // cancel is invoked at the end of stream to cancel ctx. It also stops the + // timer for monitoring the rpc deadline if configured. + cancel func() // Holds compressor names passed in grpc-accept-encoding metadata from the // client. diff --git a/vendor/google.golang.org/grpc/resolver/map.go b/vendor/google.golang.org/grpc/resolver/map.go index ada5b9b..c3c15ac 100644 --- a/vendor/google.golang.org/grpc/resolver/map.go +++ b/vendor/google.golang.org/grpc/resolver/map.go @@ -18,16 +18,28 @@ package resolver -type addressMapEntry struct { +import ( + "encoding/base64" + "sort" + "strings" +) + +type addressMapEntry[T any] struct { addr Address - value any + value T } -// AddressMap is a map of addresses to arbitrary values taking into account +// AddressMap is an AddressMapV2[any]. It will be deleted in an upcoming +// release of grpc-go. +// +// Deprecated: use the generic AddressMapV2 type instead. +type AddressMap = AddressMapV2[any] + +// AddressMapV2 is a map of addresses to arbitrary values taking into account // Attributes. BalancerAttributes are ignored, as are Metadata and Type. // Multiple accesses may not be performed concurrently. Must be created via // NewAddressMap; do not construct directly. -type AddressMap struct { +type AddressMapV2[T any] struct { // The underlying map is keyed by an Address with fields that we don't care // about being set to their zero values. The only fields that we care about // are `Addr`, `ServerName` and `Attributes`. Since we need to be able to @@ -41,23 +53,30 @@ type AddressMap struct { // The value type of the map contains a slice of addresses which match the key // in their `Addr` and `ServerName` fields and contain the corresponding value // associated with them. - m map[Address]addressMapEntryList + m map[Address]addressMapEntryList[T] } func toMapKey(addr *Address) Address { return Address{Addr: addr.Addr, ServerName: addr.ServerName} } -type addressMapEntryList []*addressMapEntry +type addressMapEntryList[T any] []*addressMapEntry[T] -// NewAddressMap creates a new AddressMap. +// NewAddressMap creates a new AddressMapV2[any]. +// +// Deprecated: use the generic NewAddressMapV2 constructor instead. func NewAddressMap() *AddressMap { - return &AddressMap{m: make(map[Address]addressMapEntryList)} + return NewAddressMapV2[any]() +} + +// NewAddressMapV2 creates a new AddressMapV2. +func NewAddressMapV2[T any]() *AddressMapV2[T] { + return &AddressMapV2[T]{m: make(map[Address]addressMapEntryList[T])} } // find returns the index of addr in the addressMapEntry slice, or -1 if not // present. -func (l addressMapEntryList) find(addr Address) int { +func (l addressMapEntryList[T]) find(addr Address) int { for i, entry := range l { // Attributes are the only thing to match on here, since `Addr` and // `ServerName` are already equal. @@ -69,28 +88,28 @@ func (l addressMapEntryList) find(addr Address) int { } // Get returns the value for the address in the map, if present. -func (a *AddressMap) Get(addr Address) (value any, ok bool) { +func (a *AddressMapV2[T]) Get(addr Address) (value T, ok bool) { addrKey := toMapKey(&addr) entryList := a.m[addrKey] if entry := entryList.find(addr); entry != -1 { return entryList[entry].value, true } - return nil, false + return value, false } // Set updates or adds the value to the address in the map. -func (a *AddressMap) Set(addr Address, value any) { +func (a *AddressMapV2[T]) Set(addr Address, value T) { addrKey := toMapKey(&addr) entryList := a.m[addrKey] if entry := entryList.find(addr); entry != -1 { entryList[entry].value = value return } - a.m[addrKey] = append(entryList, &addressMapEntry{addr: addr, value: value}) + a.m[addrKey] = append(entryList, &addressMapEntry[T]{addr: addr, value: value}) } // Delete removes addr from the map. -func (a *AddressMap) Delete(addr Address) { +func (a *AddressMapV2[T]) Delete(addr Address) { addrKey := toMapKey(&addr) entryList := a.m[addrKey] entry := entryList.find(addr) @@ -107,7 +126,7 @@ func (a *AddressMap) Delete(addr Address) { } // Len returns the number of entries in the map. -func (a *AddressMap) Len() int { +func (a *AddressMapV2[T]) Len() int { ret := 0 for _, entryList := range a.m { ret += len(entryList) @@ -116,7 +135,7 @@ func (a *AddressMap) Len() int { } // Keys returns a slice of all current map keys. -func (a *AddressMap) Keys() []Address { +func (a *AddressMapV2[T]) Keys() []Address { ret := make([]Address, 0, a.Len()) for _, entryList := range a.m { for _, entry := range entryList { @@ -127,8 +146,8 @@ func (a *AddressMap) Keys() []Address { } // Values returns a slice of all current map values. -func (a *AddressMap) Values() []any { - ret := make([]any, 0, a.Len()) +func (a *AddressMapV2[T]) Values() []T { + ret := make([]T, 0, a.Len()) for _, entryList := range a.m { for _, entry := range entryList { ret = append(ret, entry.value) @@ -137,70 +156,65 @@ func (a *AddressMap) Values() []any { return ret } -type endpointNode struct { - addrs map[string]struct{} -} - -// Equal returns whether the unordered set of addrs are the same between the -// endpoint nodes. -func (en *endpointNode) Equal(en2 *endpointNode) bool { - if len(en.addrs) != len(en2.addrs) { - return false - } - for addr := range en.addrs { - if _, ok := en2.addrs[addr]; !ok { - return false - } - } - return true -} - -func toEndpointNode(endpoint Endpoint) endpointNode { - en := make(map[string]struct{}) - for _, addr := range endpoint.Addresses { - en[addr.Addr] = struct{}{} - } - return endpointNode{ - addrs: en, - } -} +type endpointMapKey string // EndpointMap is a map of endpoints to arbitrary values keyed on only the // unordered set of address strings within an endpoint. This map is not thread // safe, thus it is unsafe to access concurrently. Must be created via // NewEndpointMap; do not construct directly. -type EndpointMap struct { - endpoints map[*endpointNode]any +type EndpointMap[T any] struct { + endpoints map[endpointMapKey]endpointData[T] +} + +type endpointData[T any] struct { + // decodedKey stores the original key to avoid decoding when iterating on + // EndpointMap keys. + decodedKey Endpoint + value T } // NewEndpointMap creates a new EndpointMap. -func NewEndpointMap() *EndpointMap { - return &EndpointMap{ - endpoints: make(map[*endpointNode]any), +func NewEndpointMap[T any]() *EndpointMap[T] { + return &EndpointMap[T]{ + endpoints: make(map[endpointMapKey]endpointData[T]), } } +// encodeEndpoint returns a string that uniquely identifies the unordered set of +// addresses within an endpoint. +func encodeEndpoint(e Endpoint) endpointMapKey { + addrs := make([]string, 0, len(e.Addresses)) + // base64 encoding the address strings restricts the characters present + // within the strings. This allows us to use a delimiter without the need of + // escape characters. + for _, addr := range e.Addresses { + addrs = append(addrs, base64.StdEncoding.EncodeToString([]byte(addr.Addr))) + } + sort.Strings(addrs) + // " " should not appear in base64 encoded strings. + return endpointMapKey(strings.Join(addrs, " ")) +} + // Get returns the value for the address in the map, if present. -func (em *EndpointMap) Get(e Endpoint) (value any, ok bool) { - en := toEndpointNode(e) - if endpoint := em.find(en); endpoint != nil { - return em.endpoints[endpoint], true +func (em *EndpointMap[T]) Get(e Endpoint) (value T, ok bool) { + val, found := em.endpoints[encodeEndpoint(e)] + if found { + return val.value, true } - return nil, false + return value, false } // Set updates or adds the value to the address in the map. -func (em *EndpointMap) Set(e Endpoint, value any) { - en := toEndpointNode(e) - if endpoint := em.find(en); endpoint != nil { - em.endpoints[endpoint] = value - return +func (em *EndpointMap[T]) Set(e Endpoint, value T) { + en := encodeEndpoint(e) + em.endpoints[en] = endpointData[T]{ + decodedKey: Endpoint{Addresses: e.Addresses}, + value: value, } - em.endpoints[&en] = value } // Len returns the number of entries in the map. -func (em *EndpointMap) Len() int { +func (em *EndpointMap[T]) Len() int { return len(em.endpoints) } @@ -209,43 +223,25 @@ func (em *EndpointMap) Len() int { // the unordered set of addresses. Thus, endpoint information returned is not // the full endpoint data (drops duplicated addresses and attributes) but can be // used for EndpointMap accesses. -func (em *EndpointMap) Keys() []Endpoint { +func (em *EndpointMap[T]) Keys() []Endpoint { ret := make([]Endpoint, 0, len(em.endpoints)) - for en := range em.endpoints { - var endpoint Endpoint - for addr := range en.addrs { - endpoint.Addresses = append(endpoint.Addresses, Address{Addr: addr}) - } - ret = append(ret, endpoint) + for _, en := range em.endpoints { + ret = append(ret, en.decodedKey) } return ret } // Values returns a slice of all current map values. -func (em *EndpointMap) Values() []any { - ret := make([]any, 0, len(em.endpoints)) +func (em *EndpointMap[T]) Values() []T { + ret := make([]T, 0, len(em.endpoints)) for _, val := range em.endpoints { - ret = append(ret, val) + ret = append(ret, val.value) } return ret } -// find returns a pointer to the endpoint node in em if the endpoint node is -// already present. If not found, nil is returned. The comparisons are done on -// the unordered set of addresses within an endpoint. -func (em EndpointMap) find(e endpointNode) *endpointNode { - for endpoint := range em.endpoints { - if e.Equal(endpoint) { - return endpoint - } - } - return nil -} - // Delete removes the specified endpoint from the map. -func (em *EndpointMap) Delete(e Endpoint) { - en := toEndpointNode(e) - if entry := em.find(en); entry != nil { - delete(em.endpoints, entry) - } +func (em *EndpointMap[T]) Delete(e Endpoint) { + en := encodeEndpoint(e) + delete(em.endpoints, en) } diff --git a/vendor/google.golang.org/grpc/resolver_wrapper.go b/vendor/google.golang.org/grpc/resolver_wrapper.go index 945e24f..80e16a3 100644 --- a/vendor/google.golang.org/grpc/resolver_wrapper.go +++ b/vendor/google.golang.org/grpc/resolver_wrapper.go @@ -134,12 +134,7 @@ func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error { return nil } if s.Endpoints == nil { - s.Endpoints = make([]resolver.Endpoint, 0, len(s.Addresses)) - for _, a := range s.Addresses { - ep := resolver.Endpoint{Addresses: []resolver.Address{a}, Attributes: a.BalancerAttributes} - ep.Addresses[0].BalancerAttributes = nil - s.Endpoints = append(s.Endpoints, ep) - } + s.Endpoints = addressesToEndpoints(s.Addresses) } ccr.addChannelzTraceEvent(s) ccr.curState = s @@ -172,7 +167,11 @@ func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) { ccr.cc.mu.Unlock() return } - s := resolver.State{Addresses: addrs, ServiceConfig: ccr.curState.ServiceConfig} + s := resolver.State{ + Addresses: addrs, + ServiceConfig: ccr.curState.ServiceConfig, + Endpoints: addressesToEndpoints(addrs), + } ccr.addChannelzTraceEvent(s) ccr.curState = s ccr.mu.Unlock() @@ -210,3 +209,13 @@ func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) { } channelz.Infof(logger, ccr.cc.channelz, "Resolver state updated: %s (%v)", pretty.ToJSON(s), strings.Join(updates, "; ")) } + +func addressesToEndpoints(addrs []resolver.Address) []resolver.Endpoint { + endpoints := make([]resolver.Endpoint, 0, len(addrs)) + for _, a := range addrs { + ep := resolver.Endpoint{Addresses: []resolver.Address{a}, Attributes: a.BalancerAttributes} + ep.Addresses[0].BalancerAttributes = nil + endpoints = append(endpoints, ep) + } + return endpoints +} diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index a8ddb0a..ad20e9d 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -870,13 +870,19 @@ func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompress return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err) } - out, err := mem.ReadAll(io.LimitReader(dcReader, int64(maxReceiveMessageSize)), pool) + // Read at most one byte more than the limit from the decompressor. + // Unless the limit is MaxInt64, in which case, that's impossible, so + // apply no limit. + if limit := int64(maxReceiveMessageSize); limit < math.MaxInt64 { + dcReader = io.LimitReader(dcReader, limit+1) + } + out, err := mem.ReadAll(dcReader, pool) if err != nil { out.Free() return nil, status.Errorf(codes.Internal, "grpc: failed to read decompressed data: %v", err) } - if out.Len() == maxReceiveMessageSize && !atEOF(dcReader) { + if out.Len() > maxReceiveMessageSize { out.Free() return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max %d", maxReceiveMessageSize) } @@ -885,12 +891,6 @@ func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompress return nil, status.Errorf(codes.Internal, "grpc: no decompressor available for compressed payload") } -// atEOF reads data from r and returns true if zero bytes could be read and r.Read returns EOF. -func atEOF(dcReader io.Reader) bool { - n, err := dcReader.Read(make([]byte, 1)) - return n == 0 && err == io.EOF -} - type recvCompressor interface { RecvCompress() string } diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go index 6f20d2d..baf7740 100644 --- a/vendor/google.golang.org/grpc/stats/stats.go +++ b/vendor/google.golang.org/grpc/stats/stats.go @@ -36,7 +36,12 @@ type RPCStats interface { IsClient() bool } -// Begin contains stats when an RPC attempt begins. +// Begin contains stats for the start of an RPC attempt. +// +// - Server-side: Triggered after `InHeader`, as headers are processed +// before the RPC lifecycle begins. +// - Client-side: The first stats event recorded. +// // FailFast is only valid if this Begin is from client side. type Begin struct { // Client is true if this Begin is from client side. @@ -69,7 +74,7 @@ func (*PickerUpdated) IsClient() bool { return true } func (*PickerUpdated) isRPCStats() {} -// InPayload contains the information for an incoming payload. +// InPayload contains stats about an incoming payload. type InPayload struct { // Client is true if this InPayload is from client side. Client bool @@ -98,7 +103,9 @@ func (s *InPayload) IsClient() bool { return s.Client } func (s *InPayload) isRPCStats() {} -// InHeader contains stats when a header is received. +// InHeader contains stats about header reception. +// +// - Server-side: The first stats event after the RPC request is received. type InHeader struct { // Client is true if this InHeader is from client side. Client bool @@ -123,7 +130,7 @@ func (s *InHeader) IsClient() bool { return s.Client } func (s *InHeader) isRPCStats() {} -// InTrailer contains stats when a trailer is received. +// InTrailer contains stats about trailer reception. type InTrailer struct { // Client is true if this InTrailer is from client side. Client bool @@ -139,7 +146,7 @@ func (s *InTrailer) IsClient() bool { return s.Client } func (s *InTrailer) isRPCStats() {} -// OutPayload contains the information for an outgoing payload. +// OutPayload contains stats about an outgoing payload. type OutPayload struct { // Client is true if this OutPayload is from client side. Client bool @@ -166,7 +173,10 @@ func (s *OutPayload) IsClient() bool { return s.Client } func (s *OutPayload) isRPCStats() {} -// OutHeader contains stats when a header is sent. +// OutHeader contains stats about header transmission. +// +// - Client-side: Only occurs after 'Begin', as headers are always the first +// thing sent on a stream. type OutHeader struct { // Client is true if this OutHeader is from client side. Client bool @@ -189,14 +199,15 @@ func (s *OutHeader) IsClient() bool { return s.Client } func (s *OutHeader) isRPCStats() {} -// OutTrailer contains stats when a trailer is sent. +// OutTrailer contains stats about trailer transmission. type OutTrailer struct { // Client is true if this OutTrailer is from client side. Client bool // WireLength is the wire length of trailer. // - // Deprecated: This field is never set. The length is not known when this message is - // emitted because the trailer fields are compressed with hpack after that. + // Deprecated: This field is never set. The length is not known when this + // message is emitted because the trailer fields are compressed with hpack + // after that. WireLength int // Trailer contains the trailer metadata sent to the client. This // field is only valid if this OutTrailer is from the server side. @@ -208,7 +219,7 @@ func (s *OutTrailer) IsClient() bool { return s.Client } func (s *OutTrailer) isRPCStats() {} -// End contains stats when an RPC ends. +// End contains stats about RPC completion. type End struct { // Client is true if this End is from client side. Client bool @@ -238,7 +249,7 @@ type ConnStats interface { IsClient() bool } -// ConnBegin contains the stats of a connection when it is established. +// ConnBegin contains stats about connection establishment. type ConnBegin struct { // Client is true if this ConnBegin is from client side. Client bool @@ -249,7 +260,7 @@ func (s *ConnBegin) IsClient() bool { return s.Client } func (s *ConnBegin) isConnStats() {} -// ConnEnd contains the stats of a connection when it ends. +// ConnEnd contains stats about connection termination. type ConnEnd struct { // Client is true if this ConnEnd is from client side. Client bool diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 783c41f..90237b1 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.71.0" +const Version = "1.72.0" diff --git a/vendor/k8s.io/apimachinery/pkg/api/errors/doc.go b/vendor/k8s.io/apimachinery/pkg/api/errors/doc.go index 167baf6..58751ed 100644 --- a/vendor/k8s.io/apimachinery/pkg/api/errors/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/api/errors/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package errors provides detailed error types for api field validation. -package errors // import "k8s.io/apimachinery/pkg/api/errors" +package errors diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/doc.go b/vendor/k8s.io/apimachinery/pkg/api/meta/doc.go index b6d42ac..a3b18a5 100644 --- a/vendor/k8s.io/apimachinery/pkg/api/meta/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package meta provides functions for retrieving API metadata from objects // belonging to the Kubernetes API -package meta // import "k8s.io/apimachinery/pkg/api/meta" +package meta diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/help.go b/vendor/k8s.io/apimachinery/pkg/api/meta/help.go index 1fdd32c..468afd0 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/api/operation/operation.go b/vendor/k8s.io/apimachinery/pkg/api/operation/operation.go new file mode 100644 index 0000000..9f5ae7a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/operation/operation.go @@ -0,0 +1,56 @@ +/* +Copyright 2024 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 operation + +import "k8s.io/apimachinery/pkg/util/sets" + +// Operation provides contextual information about a validation request and the API +// operation being validated. +// This type is intended for use with generate validation code and may be enhanced +// in the future to include other information needed to validate requests. +type Operation struct { + // Type is the category of operation being validated. This does not + // differentiate between HTTP verbs like PUT and PATCH, but rather merges + // those into a single "Update" category. + Type Type + + // Options declare the options enabled for validation. + // + // Options should be set according to a resource validation strategy before validation + // is performed, and must be treated as read-only during validation. + // + // Options are identified by string names. Option string names may match the name of a feature + // gate, in which case the presence of the name in the set indicates that the feature is + // considered enabled for the resource being validated. Note that a resource may have a + // feature enabled even when the feature gate is disabled. This can happen when feature is + // already in-use by a resource, often because the feature gate was enabled when the + // resource first began using the feature. + // + // Unset options are disabled/false. + Options sets.Set[string] +} + +// Code is the request operation to be validated. +type Type uint32 + +const ( + // Create indicates the request being validated is for a resource create operation. + Create Type = iota + + // Update indicates the request being validated is for a resource update operation. + Update +) diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go index 7736753..617b9a5 100644 --- a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go @@ -21,4 +21,4 @@ limitations under the License. // +groupName=meta.k8s.io -package v1 // import "k8s.io/apimachinery/pkg/apis/meta/v1" +package v1 diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_fuzz.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_fuzz.go index 3cf9d48..a5f437b 100644 --- a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_fuzz.go +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_fuzz.go @@ -20,21 +20,22 @@ limitations under the License. package v1 import ( + "math/rand" "time" - fuzz "github.com/google/gofuzz" + "sigs.k8s.io/randfill" ) -// Fuzz satisfies fuzz.Interface. -func (t *MicroTime) Fuzz(c fuzz.Continue) { +// Fuzz satisfies randfill.SimpleSelfFiller. +func (t *MicroTime) RandFill(r *rand.Rand) { if t == nil { return } // Allow for about 1000 years of randomness. Accurate to a tenth of // micro second. Leave off nanoseconds because JSON doesn't // represent them so they can't round-trip properly. - t.Time = time.Unix(c.Rand.Int63n(1000*365*24*60*60), 1000*c.Rand.Int63n(1000000)) + t.Time = time.Unix(r.Int63n(1000*365*24*60*60), 1000*r.Int63n(1000000)) } -// ensure MicroTime implements fuzz.Interface -var _ fuzz.Interface = &MicroTime{} +// ensure MicroTime implements randfill.Interface +var _ randfill.SimpleSelfFiller = &MicroTime{} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_fuzz.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_fuzz.go index bf9e21b..48fb978 100644 --- a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_fuzz.go +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_fuzz.go @@ -20,21 +20,22 @@ limitations under the License. package v1 import ( + "math/rand" "time" - fuzz "github.com/google/gofuzz" + "sigs.k8s.io/randfill" ) -// Fuzz satisfies fuzz.Interface. -func (t *Time) Fuzz(c fuzz.Continue) { +// Fuzz satisfies randfill.SimpleSelfFiller. +func (t *Time) RandFill(r *rand.Rand) { if t == nil { return } // Allow for about 1000 years of randomness. Leave off nanoseconds // because JSON doesn't represent them so they can't round-trip // properly. - t.Time = time.Unix(c.Rand.Int63n(1000*365*24*60*60), 0) + t.Time = time.Unix(r.Int63n(1000*365*24*60*60), 0) } -// ensure Time implements fuzz.Interface -var _ fuzz.Interface = &Time{} +// ensure Time implements randfill.SimpleSelfFiller +var _ randfill.SimpleSelfFiller = &Time{} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go index 71f7b16..59f43b7 100644 --- a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go @@ -188,7 +188,7 @@ func NestedSlice(obj map[string]interface{}, fields ...string) ([]interface{}, b // NestedStringMap returns a copy of map[string]string value of a nested field. // Returns false if value is not found and an error if not a map[string]interface{} or contains non-string values in the map. func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]string, bool, error) { - m, found, err := nestedMapNoCopy(obj, fields...) + m, found, err := nestedMapNoCopy(obj, false, fields...) if !found || err != nil { return nil, found, err } @@ -203,10 +203,32 @@ func NestedStringMap(obj map[string]interface{}, fields ...string) (map[string]s return strMap, true, nil } +// NestedNullCoercingStringMap returns a copy of map[string]string value of a nested field. +// Returns `nil, true, nil` if the value exists and is explicitly null. +// Returns `nil, false, err` if the value is not a map or a null value, or is a map and contains non-string non-null values. +// Null values in the map are coerced to "" to match json decoding behavior. +func NestedNullCoercingStringMap(obj map[string]interface{}, fields ...string) (map[string]string, bool, error) { + m, found, err := nestedMapNoCopy(obj, true, fields...) + if !found || err != nil || m == nil { + return nil, found, err + } + strMap := make(map[string]string, len(m)) + for k, v := range m { + if str, ok := v.(string); ok { + strMap[k] = str + } else if v == nil { + strMap[k] = "" + } else { + return nil, false, fmt.Errorf("%v accessor error: contains non-string value in the map under key %q: %v is of the type %T, expected string", jsonPath(fields), k, v, v) + } + } + return strMap, true, nil +} + // NestedMap returns a deep copy of map[string]interface{} value of a nested field. // Returns false if value is not found and an error if not a map[string]interface{}. func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) { - m, found, err := nestedMapNoCopy(obj, fields...) + m, found, err := nestedMapNoCopy(obj, false, fields...) if !found || err != nil { return nil, found, err } @@ -215,11 +237,14 @@ func NestedMap(obj map[string]interface{}, fields ...string) (map[string]interfa // nestedMapNoCopy returns a map[string]interface{} value of a nested field. // Returns false if value is not found and an error if not a map[string]interface{}. -func nestedMapNoCopy(obj map[string]interface{}, fields ...string) (map[string]interface{}, bool, error) { +func nestedMapNoCopy(obj map[string]interface{}, tolerateNil bool, fields ...string) (map[string]interface{}, bool, error) { val, found, err := NestedFieldNoCopy(obj, fields...) if !found || err != nil { return nil, found, err } + if val == nil && tolerateNil { + return nil, true, nil + } m, ok := val.(map[string]interface{}) if !ok { return nil, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected map[string]interface{}", jsonPath(fields), val, val) diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured.go index 5e36a91..fdb0c86 100644 --- a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured.go +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured.go @@ -397,7 +397,7 @@ func (u *Unstructured) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds } func (u *Unstructured) GetLabels() map[string]string { - m, _, _ := NestedStringMap(u.Object, "metadata", "labels") + m, _, _ := NestedNullCoercingStringMap(u.Object, "metadata", "labels") return m } @@ -410,7 +410,7 @@ func (u *Unstructured) SetLabels(labels map[string]string) { } func (u *Unstructured) GetAnnotations() map[string]string { - m, _, _ := NestedStringMap(u.Object, "metadata", "annotations") + m, _, _ := NestedNullCoercingStringMap(u.Object, "metadata", "annotations") return m } diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/doc.go b/vendor/k8s.io/apimachinery/pkg/conversion/doc.go index 7415d81..0c46ef2 100644 --- a/vendor/k8s.io/apimachinery/pkg/conversion/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/conversion/doc.go @@ -21,4 +21,4 @@ limitations under the License. // but for the fields which did not change, copying is automated. This makes it // easy to modify the structures you use in memory without affecting the format // you store on disk or respond to in your external API calls. -package conversion // import "k8s.io/apimachinery/pkg/conversion" +package conversion diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go index 7b763de..4c1002a 100644 --- a/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package queryparams provides conversion from versioned // runtime objects to URL query values -package queryparams // import "k8s.io/apimachinery/pkg/conversion/queryparams" +package queryparams diff --git a/vendor/k8s.io/apimachinery/pkg/fields/doc.go b/vendor/k8s.io/apimachinery/pkg/fields/doc.go index c39b803..49059e2 100644 --- a/vendor/k8s.io/apimachinery/pkg/fields/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/fields/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package fields implements a simple field system, parsing and matching // selectors with sets of fields. -package fields // import "k8s.io/apimachinery/pkg/fields" +package fields diff --git a/vendor/k8s.io/apimachinery/pkg/labels/doc.go b/vendor/k8s.io/apimachinery/pkg/labels/doc.go index 82de005..35ba788 100644 --- a/vendor/k8s.io/apimachinery/pkg/labels/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/labels/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package labels implements a simple label system, parsing and matching // selectors with sets of labels. -package labels // import "k8s.io/apimachinery/pkg/labels" +package labels diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/doc.go b/vendor/k8s.io/apimachinery/pkg/runtime/doc.go index 89feb40..b54429b 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/doc.go @@ -48,4 +48,4 @@ limitations under the License. // // As a bonus, a few common types useful from all api objects and versions // are provided in types.go. -package runtime // import "k8s.io/apimachinery/pkg/runtime" +package runtime diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go b/vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go index 2703300..202bf4f 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/interfaces.go @@ -259,6 +259,7 @@ type ObjectDefaulter interface { type ObjectVersioner interface { ConvertToVersion(in Object, gv GroupVersioner) (out Object, err error) + PrioritizedVersionsForGroup(group string) []schema.GroupVersion } // ObjectConvertor converts an object to a different version. diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go b/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go index a5b1167..fde87f1 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/scheme.go @@ -17,15 +17,18 @@ limitations under the License. package runtime import ( + "context" "fmt" "reflect" "strings" + "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/naming" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation/field" ) // Scheme defines methods for serializing and deserializing API objects, a type @@ -68,6 +71,12 @@ type Scheme struct { // the provided object must be a pointer. defaulterFuncs map[reflect.Type]func(interface{}) + // validationFuncs is a map to funcs to be called with an object to perform validation. + // The provided object must be a pointer. + // If oldObject is non-nil, update validation is performed and may perform additional + // validation such as transition rules and immutability checks. + validationFuncs map[reflect.Type]func(ctx context.Context, op operation.Operation, object, oldObject interface{}, subresources ...string) field.ErrorList + // converter stores all registered conversion functions. It also has // default converting behavior. converter *conversion.Converter @@ -96,6 +105,7 @@ func NewScheme() *Scheme { unversionedKinds: map[string]reflect.Type{}, fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{}, defaulterFuncs: map[reflect.Type]func(interface{}){}, + validationFuncs: map[reflect.Type]func(ctx context.Context, op operation.Operation, object, oldObject interface{}, subresource ...string) field.ErrorList{}, versionPriority: map[string][]string{}, schemeName: naming.GetNameFromCallsite(internalPackages...), } @@ -347,6 +357,35 @@ func (s *Scheme) Default(src Object) { } } +// AddValidationFunc registered a function that can validate the object, and +// oldObject. These functions will be invoked when Validate() or ValidateUpdate() +// is called. The function will never be called unless the validated object +// matches srcType. If this function is invoked twice with the same srcType, the +// fn passed to the later call will be used instead. +func (s *Scheme) AddValidationFunc(srcType Object, fn func(ctx context.Context, op operation.Operation, object, oldObject interface{}, subresources ...string) field.ErrorList) { + s.validationFuncs[reflect.TypeOf(srcType)] = fn +} + +// Validate validates the provided Object according to the generated declarative validation code. +// WARNING: This does not validate all objects! The handwritten validation code in validation.go +// is not run when this is called. Only the generated zz_generated.validations.go validation code is run. +func (s *Scheme) Validate(ctx context.Context, options sets.Set[string], object Object, subresources ...string) field.ErrorList { + if fn, ok := s.validationFuncs[reflect.TypeOf(object)]; ok { + return fn(ctx, operation.Operation{Type: operation.Create, Options: options}, object, nil, subresources...) + } + return nil +} + +// ValidateUpdate validates the provided object and oldObject according to the generated declarative validation code. +// WARNING: This does not validate all objects! The handwritten validation code in validation.go +// is not run when this is called. Only the generated zz_generated.validations.go validation code is run. +func (s *Scheme) ValidateUpdate(ctx context.Context, options sets.Set[string], object, oldObject Object, subresources ...string) field.ErrorList { + if fn, ok := s.validationFuncs[reflect.TypeOf(object)]; ok { + return fn(ctx, operation.Operation{Type: operation.Update, Options: options}, object, oldObject, subresources...) + } + return nil +} + // Convert will attempt to convert in into out. Both must be pointers. For easy // testing of conversion functions. Returns an error if the conversion isn't // possible. You can call this with types that haven't been registered (for example, diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go index 858529e..e550ea3 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/cbor/internal/modes/custom.go @@ -140,7 +140,7 @@ func (cache *checkers) getCheckerInternal(rt reflect.Type, parent *path) (c chec var wg sync.WaitGroup wg.Add(1) defer wg.Done() - c = checker{ + placeholder := checker{ safe: func() bool { wg.Wait() return c.safe() @@ -150,7 +150,7 @@ func (cache *checkers) getCheckerInternal(rt reflect.Type, parent *path) (c chec return c.check(rv, depth) }, } - if actual, loaded := cache.m.LoadOrStore(rt, &c); loaded { + if actual, loaded := cache.m.LoadOrStore(rt, &placeholder); loaded { // Someone else stored an entry for this type, use it. return *actual.(*checker) } 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 77bb307..81286fc 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go @@ -28,7 +28,7 @@ import ( func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []runtime.SerializerInfo { 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 := runtime.SerializerInfo{ MediaType: runtime.ContentTypeJSON, @@ -38,7 +38,7 @@ func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, option Serializer: jsonSerializer, StrictSerializer: json.NewSerializerWithOptions( mf, scheme, scheme, - json.SerializerOptions{Yaml: false, Pretty: false, Strict: true}, + json.SerializerOptions{Yaml: false, Pretty: false, Strict: true, StreamingCollectionsEncoding: options.StreamingCollectionsEncodingToJSON}, ), StreamSerializer: &runtime.StreamSerializerInfo{ EncodesAsText: true, @@ -61,7 +61,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 := []runtime.SerializerInfo{ @@ -113,6 +115,9 @@ type CodecFactoryOptions struct { // Pretty includes a pretty serializer along with the non-pretty one Pretty bool + StreamingCollectionsEncodingToJSON bool + StreamingCollectionsEncodingToProtobuf bool + serializers []func(runtime.ObjectCreater, runtime.ObjectTyper) runtime.SerializerInfo } @@ -147,6 +152,18 @@ func WithSerializer(f func(runtime.ObjectCreater, runtime.ObjectTyper) runtime.S } } +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 0000000..075163d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/collections.go @@ -0,0 +1,230 @@ +/* +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" + "maps" + "slices" + "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 := slices.Collect(maps.Keys(list.Object)) + 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 1ae4a32..24f66a1 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 0000000..754a808 --- /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/doc.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/doc.go index 72d0ac7..381748d 100644 --- a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package protobuf provides a Kubernetes serializer for the protobuf format. -package protobuf // import "k8s.io/apimachinery/pkg/runtime/serializer/protobuf" +package protobuf 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 c63e6dc..c66c49a 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 a82227b..27a2064 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/apimachinery/pkg/types/doc.go b/vendor/k8s.io/apimachinery/pkg/types/doc.go index 5667fa9..783cbcd 100644 --- a/vendor/k8s.io/apimachinery/pkg/types/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/types/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package types implements various generic types used throughout kubernetes. -package types // import "k8s.io/apimachinery/pkg/types" +package types diff --git a/vendor/k8s.io/apimachinery/pkg/util/errors/doc.go b/vendor/k8s.io/apimachinery/pkg/util/errors/doc.go index 5d4d625..b3b39bc 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/errors/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/util/errors/doc.go @@ -15,4 +15,4 @@ limitations under the License. */ // Package errors implements various utility functions and types around errors. -package errors // import "k8s.io/apimachinery/pkg/util/errors" +package errors diff --git a/vendor/k8s.io/apimachinery/pkg/util/framer/framer.go b/vendor/k8s.io/apimachinery/pkg/util/framer/framer.go index 1ab8fd3..f18845a 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/framer/framer.go +++ b/vendor/k8s.io/apimachinery/pkg/util/framer/framer.go @@ -91,12 +91,12 @@ func (r *lengthDelimitedFrameReader) Read(data []byte) (int, error) { } n, err := io.ReadAtLeast(r.r, data[:max], int(max)) r.remaining -= n - if err == io.ErrShortBuffer || r.remaining > 0 { - return n, io.ErrShortBuffer - } if err != nil { return n, err } + if r.remaining > 0 { + return n, io.ErrShortBuffer + } if n != expect { return n, io.ErrUnexpectedEOF } diff --git a/vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go b/vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go index a502b5a..2d6f6a0 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go +++ b/vendor/k8s.io/apimachinery/pkg/util/intstr/instr_fuzz.go @@ -20,24 +20,24 @@ limitations under the License. package intstr import ( - fuzz "github.com/google/gofuzz" + "sigs.k8s.io/randfill" ) -// Fuzz satisfies fuzz.Interface -func (intstr *IntOrString) Fuzz(c fuzz.Continue) { +// RandFill satisfies randfill.NativeSelfFiller +func (intstr *IntOrString) RandFill(c randfill.Continue) { if intstr == nil { return } - if c.RandBool() { + if c.Bool() { intstr.Type = Int - c.Fuzz(&intstr.IntVal) + c.Fill(&intstr.IntVal) intstr.StrVal = "" } else { intstr.Type = String intstr.IntVal = 0 - c.Fuzz(&intstr.StrVal) + c.Fill(&intstr.StrVal) } } // ensure IntOrString implements fuzz.Interface -var _ fuzz.Interface = &IntOrString{} +var _ randfill.NativeSelfFiller = &IntOrString{} diff --git a/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go index df37494..de97dea 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go +++ b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go @@ -36,6 +36,11 @@ var ( ) // PanicHandlers is a list of functions which will be invoked when a panic happens. +// +// The code invoking these handlers prepares a contextual logger so that +// klog.FromContext(ctx) already skips over the panic handler itself and +// several other intermediate functions, ideally such that the log output +// is attributed to the code which triggered the panic. var PanicHandlers = []func(context.Context, interface{}){logPanic} // HandleCrash simply catches a crash and logs an error. Meant to be called via @@ -45,7 +50,7 @@ var PanicHandlers = []func(context.Context, interface{}){logPanic} // // E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully. // -// Contextual logging: HandleCrashWithContext should be used instead of HandleCrash in code which supports contextual logging. +// Contextual logging: HandleCrashWithContext or HandleCrashWithLogger should be used instead of HandleCrash in code which supports contextual logging. func HandleCrash(additionalHandlers ...func(interface{})) { if r := recover(); r != nil { additionalHandlersWithContext := make([]func(context.Context, interface{}), len(additionalHandlers)) @@ -74,10 +79,30 @@ func HandleCrashWithContext(ctx context.Context, additionalHandlers ...func(cont } } -// handleCrash is the common implementation of HandleCrash and HandleCrash. +// HandleCrashWithLogger simply catches a crash and logs an error. Meant to be called via +// defer. Additional context-specific handlers can be provided, and will be +// called in case of panic. HandleCrash actually crashes, after calling the +// handlers and logging the panic message. +// +// E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully. +func HandleCrashWithLogger(logger klog.Logger, additionalHandlers ...func(context.Context, interface{})) { + if r := recover(); r != nil { + ctx := klog.NewContext(context.Background(), logger) + handleCrash(ctx, r, additionalHandlers...) + } +} + +// handleCrash is the common implementation of the HandleCrash* variants. // Having those call a common implementation ensures that the stack depth // is the same regardless through which path the handlers get invoked. func handleCrash(ctx context.Context, r any, additionalHandlers ...func(context.Context, interface{})) { + // We don't really know how many call frames to skip because the Go + // panic handler is between us and the code where the panic occurred. + // If it's one function (as in Go 1.21), then skipping four levels + // gets us to the function which called the `defer HandleCrashWithontext(...)`. + logger := klog.FromContext(ctx).WithCallDepth(4) + ctx = klog.NewContext(ctx, logger) + for _, fn := range PanicHandlers { fn(ctx, r) } @@ -106,11 +131,7 @@ func logPanic(ctx context.Context, r interface{}) { stacktrace := make([]byte, size) stacktrace = stacktrace[:runtime.Stack(stacktrace, false)] - // We don't really know how many call frames to skip because the Go - // panic handler is between us and the code where the panic occurred. - // If it's one function (as in Go 1.21), then skipping four levels - // gets us to the function which called the `defer HandleCrashWithontext(...)`. - logger := klog.FromContext(ctx).WithCallDepth(4) + logger := klog.FromContext(ctx) // For backwards compatibility, conversion to string // is handled here instead of defering to the logging @@ -176,12 +197,19 @@ func HandleError(err error) { // and key/value pairs. // // This variant should be used instead of HandleError because it supports -// structured, contextual logging. +// structured, contextual logging. Alternatively, [HandleErrorWithLogger] can +// be used if a logger is available instead of a context. func HandleErrorWithContext(ctx context.Context, err error, msg string, keysAndValues ...interface{}) { handleError(ctx, err, msg, keysAndValues...) } -// handleError is the common implementation of HandleError and HandleErrorWithContext. +// HandleErrorWithLogger is an alternative to [HandlerErrorWithContext] which accepts +// a logger for contextual logging. +func HandleErrorWithLogger(logger klog.Logger, err error, msg string, keysAndValues ...interface{}) { + handleError(klog.NewContext(context.Background(), logger), err, msg, keysAndValues...) +} + +// handleError is the common implementation of the HandleError* variants. // Using this common implementation ensures that the stack depth // is the same regardless through which path the handlers get invoked. func handleError(ctx context.Context, err error, msg string, keysAndValues ...interface{}) { diff --git a/vendor/k8s.io/apimachinery/pkg/util/sets/doc.go b/vendor/k8s.io/apimachinery/pkg/util/sets/doc.go index fd281bd..1948833 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/sets/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/util/sets/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package sets has generic set and specified sets. Generic set will // replace specified ones over time. And specific ones are deprecated. -package sets // import "k8s.io/apimachinery/pkg/util/sets" +package sets diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/field/error_matcher.go b/vendor/k8s.io/apimachinery/pkg/util/validation/field/error_matcher.go new file mode 100644 index 0000000..1d15dea --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/field/error_matcher.go @@ -0,0 +1,212 @@ +/* +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 field + +import ( + "fmt" + "reflect" + "regexp" + "strings" +) + +// ErrorMatcher is a helper for comparing Error objects. +type ErrorMatcher struct { + // TODO(thockin): consider whether type is ever NOT required, maybe just + // assume it. + matchType bool + // TODO(thockin): consider whether field could be assumed - if the + // "want" error has a nil field, don't match on field. + matchField bool + // TODO(thockin): consider whether value could be assumed - if the + // "want" error has a nil value, don't match on field. + matchValue bool + matchOrigin bool + matchDetail func(want, got string) bool + requireOriginWhenInvalid bool +} + +// Matches returns true if the two Error objects match according to the +// configured criteria. +func (m ErrorMatcher) Matches(want, got *Error) bool { + if m.matchType && want.Type != got.Type { + return false + } + if m.matchField && want.Field != got.Field { + return false + } + if m.matchValue && !reflect.DeepEqual(want.BadValue, got.BadValue) { + return false + } + if m.matchOrigin { + if want.Origin != got.Origin { + return false + } + if m.requireOriginWhenInvalid && want.Type == ErrorTypeInvalid { + if want.Origin == "" || got.Origin == "" { + return false + } + } + } + if m.matchDetail != nil && !m.matchDetail(want.Detail, got.Detail) { + return false + } + return true +} + +// Render returns a string representation of the specified Error object, +// according to the criteria configured in the ErrorMatcher. +func (m ErrorMatcher) Render(e *Error) string { + buf := strings.Builder{} + + comma := func() { + if buf.Len() > 0 { + buf.WriteString(", ") + } + } + + if m.matchType { + comma() + buf.WriteString(fmt.Sprintf("Type=%q", e.Type)) + } + if m.matchField { + comma() + buf.WriteString(fmt.Sprintf("Field=%q", e.Field)) + } + if m.matchValue { + comma() + buf.WriteString(fmt.Sprintf("Value=%v", e.BadValue)) + } + if m.matchOrigin || m.requireOriginWhenInvalid && e.Type == ErrorTypeInvalid { + comma() + buf.WriteString(fmt.Sprintf("Origin=%q", e.Origin)) + } + if m.matchDetail != nil { + comma() + buf.WriteString(fmt.Sprintf("Detail=%q", e.Detail)) + } + return "{" + buf.String() + "}" +} + +// Exactly returns a derived ErrorMatcher which matches all fields exactly. +func (m ErrorMatcher) Exactly() ErrorMatcher { + return m.ByType().ByField().ByValue().ByOrigin().ByDetailExact() +} + +// ByType returns a derived ErrorMatcher which also matches by type. +func (m ErrorMatcher) ByType() ErrorMatcher { + m.matchType = true + return m +} + +// ByField returns a derived ErrorMatcher which also matches by field path. +func (m ErrorMatcher) ByField() ErrorMatcher { + m.matchField = true + return m +} + +// ByValue returns a derived ErrorMatcher which also matches by the errant +// value. +func (m ErrorMatcher) ByValue() ErrorMatcher { + m.matchValue = true + return m +} + +// ByOrigin returns a derived ErrorMatcher which also matches by the origin. +func (m ErrorMatcher) ByOrigin() ErrorMatcher { + m.matchOrigin = true + return m +} + +// RequireOriginWhenInvalid returns a derived ErrorMatcher which also requires +// the Origin field to be set when the Type is Invalid and the matcher is +// matching by Origin. +func (m ErrorMatcher) RequireOriginWhenInvalid() ErrorMatcher { + m.requireOriginWhenInvalid = true + return m +} + +// ByDetailExact returns a derived ErrorMatcher which also matches errors by +// the exact detail string. +func (m ErrorMatcher) ByDetailExact() ErrorMatcher { + m.matchDetail = func(want, got string) bool { + return got == want + } + return m +} + +// ByDetailSubstring returns a derived ErrorMatcher which also matches errors +// by a substring of the detail string. +func (m ErrorMatcher) ByDetailSubstring() ErrorMatcher { + m.matchDetail = func(want, got string) bool { + return strings.Contains(got, want) + } + return m +} + +// ByDetailRegexp returns a derived ErrorMatcher which also matches errors by a +// regular expression of the detail string, where the "want" string is assumed +// to be a valid regular expression. +func (m ErrorMatcher) ByDetailRegexp() ErrorMatcher { + m.matchDetail = func(want, got string) bool { + return regexp.MustCompile(want).MatchString(got) + } + return m +} + +// TestIntf lets users pass a testing.T while not coupling this package to Go's +// testing package. +type TestIntf interface { + Helper() + Errorf(format string, args ...any) + Logf(format string, args ...any) +} + +// Test compares two ErrorLists by the criteria configured in this matcher, and +// fails the test if they don't match. If a given "want" error matches multiple +// "got" errors, they will all be consumed. This might be OK (e.g. if there are +// multiple errors on the same field from the same origin) or it might be an +// insufficiently specific matcher, so these will be logged. +func (m ErrorMatcher) Test(tb TestIntf, want, got ErrorList) { + tb.Helper() + + remaining := got + for _, w := range want { + tmp := make(ErrorList, 0, len(remaining)) + n := 0 + for _, g := range remaining { + if m.Matches(w, g) { + n++ + } else { + tmp = append(tmp, g) + } + } + if n == 0 { + tb.Errorf("expected an error matching:\n%s", m.Render(w)) + } else if n > 1 { + // This is not necessarily and error, but it's worth logging in + // case it's not what the test author intended. + tb.Logf("multiple errors matched:\n%s", m.Render(w)) + } + remaining = tmp + } + if len(remaining) > 0 { + for _, e := range remaining { + exactly := m.Exactly() // makes a copy + tb.Errorf("unmatched error:\n%s", exactly.Render(e)) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go b/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go index f1634bc..840d645 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors.go @@ -33,13 +33,35 @@ type Error struct { Field string BadValue interface{} Detail string + + // Origin uniquely identifies where this error was generated from. It is used in testing to + // compare expected errors against actual errors without relying on exact detail string matching. + // This allows tests to verify the correct validation logic triggered the error + // regardless of how the error message might be formatted or localized. + // + // The value should be either: + // - A simple camelCase identifier (e.g., "maximum", "maxItems") + // - A structured format using "format=" for validation errors related to specific formats + // (e.g., "format=dns-label", "format=qualified-name") + // + // If the Origin corresponds to an existing declarative validation tag or JSON Schema keyword, + // use that same name for consistency. + // + // Origin should be set in the most deeply nested validation function that + // can still identify the unique source of the error. + Origin string + + // CoveredByDeclarative is true when this error is covered by declarative + // validation. This field is to identify errors from imperative validation + // that should also be caught by declarative validation. + CoveredByDeclarative bool } var _ error = &Error{} // Error implements the error interface. -func (v *Error) Error() string { - return fmt.Sprintf("%s: %s", v.Field, v.ErrorBody()) +func (e *Error) Error() string { + return fmt.Sprintf("%s: %s", e.Field, e.ErrorBody()) } type OmitValueType struct{} @@ -48,21 +70,21 @@ var omitValue = OmitValueType{} // ErrorBody returns the error message without the field name. This is useful // for building nice-looking higher-level error reporting. -func (v *Error) ErrorBody() string { +func (e *Error) ErrorBody() string { var s string switch { - case v.Type == ErrorTypeRequired: - s = v.Type.String() - case v.Type == ErrorTypeForbidden: - s = v.Type.String() - case v.Type == ErrorTypeTooLong: - s = v.Type.String() - case v.Type == ErrorTypeInternal: - s = v.Type.String() - case v.BadValue == omitValue: - s = v.Type.String() + case e.Type == ErrorTypeRequired: + s = e.Type.String() + case e.Type == ErrorTypeForbidden: + s = e.Type.String() + case e.Type == ErrorTypeTooLong: + s = e.Type.String() + case e.Type == ErrorTypeInternal: + s = e.Type.String() + case e.BadValue == omitValue: + s = e.Type.String() default: - value := v.BadValue + value := e.BadValue valueType := reflect.TypeOf(value) if value == nil || valueType == nil { value = "null" @@ -76,26 +98,38 @@ func (v *Error) ErrorBody() string { switch t := value.(type) { case int64, int32, float64, float32, bool: // use simple printer for simple types - s = fmt.Sprintf("%s: %v", v.Type, value) + s = fmt.Sprintf("%s: %v", e.Type, value) case string: - s = fmt.Sprintf("%s: %q", v.Type, t) + s = fmt.Sprintf("%s: %q", e.Type, t) case fmt.Stringer: // anything that defines String() is better than raw struct - s = fmt.Sprintf("%s: %s", v.Type, t.String()) + s = fmt.Sprintf("%s: %s", e.Type, t.String()) default: // fallback to raw struct // TODO: internal types have panic guards against json.Marshalling to prevent // accidental use of internal types in external serialized form. For now, use // %#v, although it would be better to show a more expressive output in the future - s = fmt.Sprintf("%s: %#v", v.Type, value) + s = fmt.Sprintf("%s: %#v", e.Type, value) } } - if len(v.Detail) != 0 { - s += fmt.Sprintf(": %s", v.Detail) + if len(e.Detail) != 0 { + s += fmt.Sprintf(": %s", e.Detail) } return s } +// WithOrigin adds origin information to the FieldError +func (e *Error) WithOrigin(o string) *Error { + e.Origin = o + return e +} + +// MarkCoveredByDeclarative marks the error as covered by declarative validation. +func (e *Error) MarkCoveredByDeclarative() *Error { + e.CoveredByDeclarative = true + return e +} + // ErrorType is a machine readable value providing more detail about why // a field is invalid. These values are expected to match 1-1 with // CauseType in api/types.go. @@ -169,32 +203,32 @@ func (t ErrorType) String() string { // TypeInvalid returns a *Error indicating "type is invalid" func TypeInvalid(field *Path, value interface{}, detail string) *Error { - return &Error{ErrorTypeTypeInvalid, field.String(), value, detail} + return &Error{ErrorTypeTypeInvalid, field.String(), value, detail, "", false} } // NotFound returns a *Error indicating "value not found". This is // used to report failure to find a requested value (e.g. looking up an ID). func NotFound(field *Path, value interface{}) *Error { - return &Error{ErrorTypeNotFound, field.String(), value, ""} + return &Error{ErrorTypeNotFound, field.String(), value, "", "", false} } // Required returns a *Error indicating "value required". This is used // to report required values that are not provided (e.g. empty strings, null // values, or empty arrays). func Required(field *Path, detail string) *Error { - return &Error{ErrorTypeRequired, field.String(), "", detail} + return &Error{ErrorTypeRequired, field.String(), "", detail, "", false} } // Duplicate returns a *Error indicating "duplicate value". This is // used to report collisions of values that must be unique (e.g. names or IDs). func Duplicate(field *Path, value interface{}) *Error { - return &Error{ErrorTypeDuplicate, field.String(), value, ""} + return &Error{ErrorTypeDuplicate, field.String(), value, "", "", false} } // Invalid returns a *Error indicating "invalid value". This is used // to report malformed values (e.g. failed regex match, too long, out of bounds). func Invalid(field *Path, value interface{}, detail string) *Error { - return &Error{ErrorTypeInvalid, field.String(), value, detail} + return &Error{ErrorTypeInvalid, field.String(), value, detail, "", false} } // NotSupported returns a *Error indicating "unsupported value". @@ -209,7 +243,7 @@ func NotSupported[T ~string](field *Path, value interface{}, validValues []T) *E } detail = "supported values: " + strings.Join(quotedValues, ", ") } - return &Error{ErrorTypeNotSupported, field.String(), value, detail} + return &Error{ErrorTypeNotSupported, field.String(), value, detail, "", false} } // Forbidden returns a *Error indicating "forbidden". This is used to @@ -217,7 +251,7 @@ func NotSupported[T ~string](field *Path, value interface{}, validValues []T) *E // some conditions, but which are not permitted by current conditions (e.g. // security policy). func Forbidden(field *Path, detail string) *Error { - return &Error{ErrorTypeForbidden, field.String(), "", detail} + return &Error{ErrorTypeForbidden, field.String(), "", detail, "", false} } // TooLong returns a *Error indicating "too long". This is used to report that @@ -231,7 +265,7 @@ func TooLong(field *Path, value interface{}, maxLength int) *Error { } else { msg = "value is too long" } - return &Error{ErrorTypeTooLong, field.String(), "", msg} + return &Error{ErrorTypeTooLong, field.String(), "", msg, "", false} } // TooLongMaxLength returns a *Error indicating "too long". @@ -259,14 +293,14 @@ func TooMany(field *Path, actualQuantity, maxQuantity int) *Error { actual = omitValue } - return &Error{ErrorTypeTooMany, field.String(), actual, msg} + return &Error{ErrorTypeTooMany, field.String(), actual, msg, "", false} } // InternalError returns a *Error indicating "internal error". This is used // to signal that an error was found that was not directly related to user // input. The err argument must be non-nil. func InternalError(field *Path, err error) *Error { - return &Error{ErrorTypeInternal, field.String(), nil, err.Error()} + return &Error{ErrorTypeInternal, field.String(), nil, err.Error(), "", false} } // ErrorList holds a set of Errors. It is plausible that we might one day have @@ -285,6 +319,22 @@ func NewErrorTypeMatcher(t ErrorType) utilerrors.Matcher { } } +// WithOrigin sets the origin for all errors in the list and returns the updated list. +func (list ErrorList) WithOrigin(origin string) ErrorList { + for _, err := range list { + err.Origin = origin + } + return list +} + +// MarkCoveredByDeclarative marks all errors in the list as covered by declarative validation. +func (list ErrorList) MarkCoveredByDeclarative() ErrorList { + for _, err := range list { + err.CoveredByDeclarative = true + } + return list +} + // ToAggregate converts the ErrorList into an errors.Aggregate. func (list ErrorList) ToAggregate() utilerrors.Aggregate { if len(list) == 0 { @@ -321,3 +371,25 @@ func (list ErrorList) Filter(fns ...utilerrors.Matcher) ErrorList { // FilterOut takes an Aggregate and returns an Aggregate return fromAggregate(err.(utilerrors.Aggregate)) } + +// ExtractCoveredByDeclarative returns a new ErrorList containing only the errors that should be covered by declarative validation. +func (list ErrorList) ExtractCoveredByDeclarative() ErrorList { + newList := ErrorList{} + for _, err := range list { + if err.CoveredByDeclarative { + newList = append(newList, err) + } + } + return newList +} + +// RemoveCoveredByDeclarative returns a new ErrorList containing only the errors that should not be covered by declarative validation. +func (list ErrorList) RemoveCoveredByDeclarative() ErrorList { + newList := ErrorList{} + for _, err := range list { + if !err.CoveredByDeclarative { + newList = append(newList, err) + } + } + return newList +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/ip.go b/vendor/k8s.io/apimachinery/pkg/util/validation/ip.go new file mode 100644 index 0000000..6e947c7 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/ip.go @@ -0,0 +1,278 @@ +/* +Copyright 2023 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 validation + +import ( + "fmt" + "net" + "net/netip" + "slices" + + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/klog/v2" + netutils "k8s.io/utils/net" +) + +func parseIP(fldPath *field.Path, value string, strictValidation bool) (net.IP, field.ErrorList) { + var allErrors field.ErrorList + + ip := netutils.ParseIPSloppy(value) + if ip == nil { + allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)")) + return nil, allErrors + } + + if strictValidation { + addr, err := netip.ParseAddr(value) + if err != nil { + // If netutils.ParseIPSloppy parsed it, but netip.ParseAddr + // doesn't, then it must have illegal leading 0s. + allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have leading 0s")) + } + if addr.Is4In6() { + allErrors = append(allErrors, field.Invalid(fldPath, value, "must not be an IPv4-mapped IPv6 address")) + } + } + + return ip, allErrors +} + +// IsValidIPForLegacyField tests that the argument is a valid IP address for a "legacy" +// API field that predates strict IP validation. In particular, this allows IPs that are +// not in canonical form (e.g., "FE80:0:0:0:0:0:0:0abc" instead of "fe80::abc"). +// +// If strictValidation is false, this also allows IPs in certain invalid or ambiguous +// formats: +// +// 1. IPv4 IPs are allowed to have leading "0"s in octets (e.g. "010.002.003.004"). +// Historically, net.ParseIP (and later netutils.ParseIPSloppy) simply ignored leading +// "0"s in IPv4 addresses, but most libc-based software treats 0-prefixed IPv4 octets +// as octal, meaning different software might interpret the same string as two +// different IPs, potentially leading to security issues. (Current net.ParseIP and +// netip.ParseAddr simply reject inputs with leading "0"s.) +// +// 2. IPv4-mapped IPv6 IPs (e.g. "::ffff:1.2.3.4") are allowed. These can also lead to +// different software interpreting the value in different ways, because they may be +// treated as IPv4 by some software and IPv6 by other software. (net.ParseIP and +// netip.ParseAddr both allow these, but there are no use cases for representing IPv4 +// addresses as IPv4-mapped IPv6 addresses in Kubernetes.) +// +// Alternatively, when validating an update to an existing field, you can pass a list of +// IP values from the old object that should be accepted if they appear in the new object +// even if they are not valid. +// +// This function should only be used to validate the existing fields that were +// historically validated in this way, and strictValidation should be true unless the +// StrictIPCIDRValidation feature gate is disabled. Use IsValidIP for parsing new fields. +func IsValidIPForLegacyField(fldPath *field.Path, value string, strictValidation bool, validOldIPs []string) field.ErrorList { + if slices.Contains(validOldIPs, value) { + return nil + } + _, allErrors := parseIP(fldPath, value, strictValidation) + return allErrors.WithOrigin("format=ip-sloppy") +} + +// IsValidIP tests that the argument is a valid IP address, according to current +// Kubernetes standards for IP address validation. +func IsValidIP(fldPath *field.Path, value string) field.ErrorList { + ip, allErrors := parseIP(fldPath, value, true) + if len(allErrors) != 0 { + return allErrors.WithOrigin("format=ip-strict") + } + + if value != ip.String() { + allErrors = append(allErrors, field.Invalid(fldPath, value, fmt.Sprintf("must be in canonical form (%q)", ip.String()))) + } + return allErrors.WithOrigin("format=ip-strict") +} + +// GetWarningsForIP returns warnings for IP address values in non-standard forms. This +// should only be used with fields that are validated with IsValidIPForLegacyField(). +func GetWarningsForIP(fldPath *field.Path, value string) []string { + ip := netutils.ParseIPSloppy(value) + if ip == nil { + klog.ErrorS(nil, "GetWarningsForIP called on value that was not validated with IsValidIPForLegacyField", "field", fldPath, "value", value) + return nil + } + + addr, _ := netip.ParseAddr(value) + if !addr.IsValid() || addr.Is4In6() { + // This catches 2 cases: leading 0s (if ParseIPSloppy() accepted it but + // ParseAddr() doesn't) or IPv4-mapped IPv6 (.Is4In6()). Either way, + // re-stringifying the net.IP value will give the preferred form. + return []string{ + fmt.Sprintf("%s: non-standard IP address %q will be considered invalid in a future Kubernetes release: use %q", fldPath, value, ip.String()), + } + } + + // If ParseIPSloppy() and ParseAddr() both accept it then it's fully valid, though + // it may be non-canonical. + if addr.Is6() && addr.String() != value { + return []string{ + fmt.Sprintf("%s: IPv6 address %q should be in RFC 5952 canonical format (%q)", fldPath, value, addr.String()), + } + } + + return nil +} + +func parseCIDR(fldPath *field.Path, value string, strictValidation bool) (*net.IPNet, field.ErrorList) { + var allErrors field.ErrorList + + _, ipnet, err := netutils.ParseCIDRSloppy(value) + if err != nil { + allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)")) + return nil, allErrors + } + + if strictValidation { + prefix, err := netip.ParsePrefix(value) + if err != nil { + // If netutils.ParseCIDRSloppy parsed it, but netip.ParsePrefix + // doesn't, then it must have illegal leading 0s (either in the + // IP part or the prefix). + allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have leading 0s in IP or prefix length")) + } else if prefix.Addr().Is4In6() { + allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have an IPv4-mapped IPv6 address")) + } else if prefix.Addr() != prefix.Masked().Addr() { + allErrors = append(allErrors, field.Invalid(fldPath, value, "must not have bits set beyond the prefix length")) + } + } + + return ipnet, allErrors +} + +// IsValidCIDRForLegacyField tests that the argument is a valid CIDR value for a "legacy" +// API field that predates strict IP validation. In particular, this allows IPs that are +// not in canonical form (e.g., "FE80:0abc:0:0:0:0:0:0/64" instead of "fe80:abc::/64"). +// +// If strictValidation is false, this also allows CIDR values in certain invalid or +// ambiguous formats: +// +// 1. The IP part of the CIDR value is parsed as with IsValidIPForLegacyField with +// strictValidation=false. +// +// 2. The CIDR value is allowed to be either a "subnet"/"mask" (with the lower bits after +// the prefix length all being 0), or an "interface address" as with `ip addr` (with a +// complete IP address and associated subnet length). With strict validation, the +// value is required to be in "subnet"/"mask" form. +// +// 3. The prefix length is allowed to have leading 0s. +// +// Alternatively, when validating an update to an existing field, you can pass a list of +// CIDR values from the old object that should be accepted if they appear in the new +// object even if they are not valid. +// +// This function should only be used to validate the existing fields that were +// historically validated in this way, and strictValidation should be true unless the +// StrictIPCIDRValidation feature gate is disabled. Use IsValidCIDR or +// IsValidInterfaceAddress for parsing new fields. +func IsValidCIDRForLegacyField(fldPath *field.Path, value string, strictValidation bool, validOldCIDRs []string) field.ErrorList { + if slices.Contains(validOldCIDRs, value) { + return nil + } + + _, allErrors := parseCIDR(fldPath, value, strictValidation) + return allErrors +} + +// IsValidCIDR tests that the argument is a valid CIDR value, according to current +// Kubernetes standards for CIDR validation. This function is only for +// "subnet"/"mask"-style CIDR values (e.g., "192.168.1.0/24", with no bits set beyond the +// prefix length). Use IsValidInterfaceAddress for "ifaddr"-style CIDR values. +func IsValidCIDR(fldPath *field.Path, value string) field.ErrorList { + ipnet, allErrors := parseCIDR(fldPath, value, true) + if len(allErrors) != 0 { + return allErrors + } + + if value != ipnet.String() { + allErrors = append(allErrors, field.Invalid(fldPath, value, fmt.Sprintf("must be in canonical form (%q)", ipnet.String()))) + } + return allErrors +} + +// GetWarningsForCIDR returns warnings for CIDR values in non-standard forms. This should +// only be used with fields that are validated with IsValidCIDRForLegacyField(). +func GetWarningsForCIDR(fldPath *field.Path, value string) []string { + ip, ipnet, err := netutils.ParseCIDRSloppy(value) + if err != nil { + klog.ErrorS(err, "GetWarningsForCIDR called on value that was not validated with IsValidCIDRForLegacyField", "field", fldPath, "value", value) + return nil + } + + var warnings []string + + // Check for bits set after prefix length + if !ip.Equal(ipnet.IP) { + _, addrlen := ipnet.Mask.Size() + singleIPCIDR := fmt.Sprintf("%s/%d", ip.String(), addrlen) + warnings = append(warnings, + fmt.Sprintf("%s: CIDR value %q is ambiguous in this context (should be %q or %q?)", fldPath, value, ipnet.String(), singleIPCIDR), + ) + } + + prefix, _ := netip.ParsePrefix(value) + addr := prefix.Addr() + if !prefix.IsValid() || addr.Is4In6() { + // This catches 2 cases: leading 0s (if ParseCIDRSloppy() accepted it but + // ParsePrefix() doesn't) or IPv4-mapped IPv6 (.Is4In6()). Either way, + // re-stringifying the net.IPNet value will give the preferred form. + warnings = append(warnings, + fmt.Sprintf("%s: non-standard CIDR value %q will be considered invalid in a future Kubernetes release: use %q", fldPath, value, ipnet.String()), + ) + } + + // If ParseCIDRSloppy() and ParsePrefix() both accept it then it's fully valid, + // though it may be non-canonical. But only check this if there are no other + // warnings, since either of the other warnings would also cause a round-trip + // failure. + if len(warnings) == 0 && addr.Is6() && prefix.String() != value { + warnings = append(warnings, + fmt.Sprintf("%s: IPv6 CIDR value %q should be in RFC 5952 canonical format (%q)", fldPath, value, prefix.String()), + ) + } + + return warnings +} + +// IsValidInterfaceAddress tests that the argument is a valid "ifaddr"-style CIDR value in +// canonical form (e.g., "192.168.1.5/24", with a complete IP address and associated +// subnet length). Use IsValidCIDR for "subnet"/"mask"-style CIDR values (e.g., +// "192.168.1.0/24"). +func IsValidInterfaceAddress(fldPath *field.Path, value string) field.ErrorList { + var allErrors field.ErrorList + ip, ipnet, err := netutils.ParseCIDRSloppy(value) + if err != nil { + allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid address in CIDR form, (e.g. 10.9.8.7/24 or 2001:db8::1/64)")) + return allErrors + } + + // The canonical form of `value` is not `ipnet.String()`, because `ipnet` doesn't + // include the bits after the prefix. We need to construct the canonical form + // ourselves from `ip` and `ipnet.Mask`. + maskSize, _ := ipnet.Mask.Size() + if netutils.IsIPv4(ip) && maskSize > net.IPv4len*8 { + // "::ffff:192.168.0.1/120" -> "192.168.0.1/24" + maskSize -= (net.IPv6len - net.IPv4len) * 8 + } + canonical := fmt.Sprintf("%s/%d", ip.String(), maskSize) + if value != canonical { + allErrors = append(allErrors, field.Invalid(fldPath, value, fmt.Sprintf("must be in canonical form (%q)", canonical))) + } + return allErrors +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/validation.go b/vendor/k8s.io/apimachinery/pkg/util/validation/validation.go index 9bc393c..b6be7af 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/validation/validation.go +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/validation.go @@ -24,7 +24,6 @@ import ( "unicode" "k8s.io/apimachinery/pkg/util/validation/field" - netutils "k8s.io/utils/net" ) const qnameCharFmt string = "[A-Za-z0-9]" @@ -369,45 +368,6 @@ func IsValidPortName(port string) []string { return errs } -// IsValidIP tests that the argument is a valid IP address. -func IsValidIP(fldPath *field.Path, value string) field.ErrorList { - var allErrors field.ErrorList - if netutils.ParseIPSloppy(value) == nil { - allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)")) - } - return allErrors -} - -// IsValidIPv4Address tests that the argument is a valid IPv4 address. -func IsValidIPv4Address(fldPath *field.Path, value string) field.ErrorList { - var allErrors field.ErrorList - ip := netutils.ParseIPSloppy(value) - if ip == nil || ip.To4() == nil { - allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv4 address")) - } - return allErrors -} - -// IsValidIPv6Address tests that the argument is a valid IPv6 address. -func IsValidIPv6Address(fldPath *field.Path, value string) field.ErrorList { - var allErrors field.ErrorList - ip := netutils.ParseIPSloppy(value) - if ip == nil || ip.To4() != nil { - allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IPv6 address")) - } - return allErrors -} - -// IsValidCIDR tests that the argument is a valid CIDR value. -func IsValidCIDR(fldPath *field.Path, value string) field.ErrorList { - var allErrors field.ErrorList - _, _, err := netutils.ParseCIDRSloppy(value) - if err != nil { - allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid CIDR value, (e.g. 10.9.8.0/24 or 2001:db8::/64)")) - } - return allErrors -} - const percentFmt string = "[0-9]+%" const percentErrMsg string = "a valid percent string must be a numeric string followed by an ending '%'" diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go b/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go index 4187619..177be09 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go +++ b/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go @@ -157,6 +157,8 @@ func (b Backoff) DelayWithReset(c clock.Clock, resetInterval time.Duration) Dela // Until is syntactic sugar on top of JitterUntil with zero jitter factor and // with sliding = true (which means the timer for period starts after the f // completes). +// +// Contextual logging: UntilWithContext should be used instead of Until in code which supports contextual logging. func Until(f func(), period time.Duration, stopCh <-chan struct{}) { JitterUntil(f, period, 0.0, true, stopCh) } @@ -176,6 +178,8 @@ func UntilWithContext(ctx context.Context, f func(context.Context), period time. // NonSlidingUntil is syntactic sugar on top of JitterUntil with zero jitter // factor, with sliding = false (meaning the timer for period starts at the same // time as the function starts). +// +// Contextual logging: NonSlidingUntilWithContext should be used instead of NonSlidingUntil in code which supports contextual logging. func NonSlidingUntil(f func(), period time.Duration, stopCh <-chan struct{}) { JitterUntil(f, period, 0.0, false, stopCh) } @@ -200,19 +204,44 @@ func NonSlidingUntilWithContext(ctx context.Context, f func(context.Context), pe // // Close stopCh to stop. f may not be invoked if stop channel is already // closed. Pass NeverStop to if you don't want it stop. +// +// Contextual logging: JitterUntilWithContext should be used instead of JitterUntil in code which supports contextual logging. func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding bool, stopCh <-chan struct{}) { BackoffUntil(f, NewJitteredBackoffManager(period, jitterFactor, &clock.RealClock{}), sliding, stopCh) } +// JitterUntilWithContext loops until context is done, running f every period. +// +// If jitterFactor is positive, the period is jittered before every run of f. +// If jitterFactor is not positive, the period is unchanged and not jittered. +// +// If sliding is true, the period is computed after f runs. If it is false then +// period includes the runtime for f. +// +// Cancel context to stop. f may not be invoked if context is already done. +func JitterUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration, jitterFactor float64, sliding bool) { + BackoffUntilWithContext(ctx, f, NewJitteredBackoffManager(period, jitterFactor, &clock.RealClock{}), sliding) +} + // BackoffUntil loops until stop channel is closed, run f every duration given by BackoffManager. // // If sliding is true, the period is computed after f runs. If it is false then // period includes the runtime for f. +// +// Contextual logging: BackoffUntilWithContext should be used instead of BackoffUntil in code which supports contextual logging. func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan struct{}) { + BackoffUntilWithContext(ContextForChannel(stopCh), func(context.Context) { f() }, backoff, sliding) +} + +// BackoffUntilWithContext loops until context is done, run f every duration given by BackoffManager. +// +// If sliding is true, the period is computed after f runs. If it is false then +// period includes the runtime for f. +func BackoffUntilWithContext(ctx context.Context, f func(ctx context.Context), backoff BackoffManager, sliding bool) { var t clock.Timer for { select { - case <-stopCh: + case <-ctx.Done(): return default: } @@ -222,8 +251,8 @@ func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan } func() { - defer runtime.HandleCrash() - f() + defer runtime.HandleCrashWithContext(ctx) + f(ctx) }() if sliding { @@ -236,7 +265,7 @@ func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan // In order to mitigate we re-check stopCh at the beginning // of every loop to prevent extra executions of f(). select { - case <-stopCh: + case <-ctx.Done(): if !t.Stop() { <-t.C() } @@ -246,19 +275,6 @@ func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan } } -// JitterUntilWithContext loops until context is done, running f every period. -// -// If jitterFactor is positive, the period is jittered before every run of f. -// If jitterFactor is not positive, the period is unchanged and not jittered. -// -// If sliding is true, the period is computed after f runs. If it is false then -// period includes the runtime for f. -// -// Cancel context to stop. f may not be invoked if context is already expired. -func JitterUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration, jitterFactor float64, sliding bool) { - JitterUntil(func() { f(ctx) }, period, jitterFactor, sliding, ctx.Done()) -} - // backoffManager provides simple backoff behavior in a threadsafe manner to a caller. type backoffManager struct { backoff Backoff diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go b/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go index 3f0c968..ff89dc1 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package wait provides tools for polling or listening for changes // to a condition. -package wait // import "k8s.io/apimachinery/pkg/util/wait" +package wait diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go b/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go index 107bfc1..9f9b929 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go +++ b/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go @@ -49,7 +49,7 @@ func loopConditionUntilContext(ctx context.Context, t Timer, immediate, sliding // if we haven't requested immediate execution, delay once if immediate { if ok, err := func() (bool, error) { - defer runtime.HandleCrash() + defer runtime.HandleCrashWithContext(ctx) return condition(ctx) }(); err != nil || ok { return err @@ -83,7 +83,7 @@ func loopConditionUntilContext(ctx context.Context, t Timer, immediate, sliding t.Next() } if ok, err := func() (bool, error) { - defer runtime.HandleCrash() + defer runtime.HandleCrashWithContext(ctx) return condition(ctx) }(); err != nil || ok { return err diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go b/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go index 6805e8c..7379a8d 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go +++ b/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go @@ -80,6 +80,10 @@ func Forever(f func(), period time.Duration) { Until(f, period, NeverStop) } +// jitterRand is a dedicated random source for jitter calculations. +// It defaults to rand.Float64, but is a package variable so it can be overridden to make unit tests deterministic. +var jitterRand = rand.Float64 + // Jitter returns a time.Duration between duration and duration + maxFactor * // duration. // @@ -89,7 +93,7 @@ func Jitter(duration time.Duration, maxFactor float64) time.Duration { if maxFactor <= 0.0 { maxFactor = 1.0 } - wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration)) + wait := duration + time.Duration(jitterRand()*maxFactor*float64(duration)) return wait } @@ -141,6 +145,7 @@ func (c channelContext) Value(key any) any { return nil } // // Deprecated: Will be removed when the legacy polling methods are removed. func runConditionWithCrashProtection(condition ConditionFunc) (bool, error) { + //nolint:logcheck // Already deprecated. defer runtime.HandleCrash() return condition() } @@ -150,7 +155,7 @@ func runConditionWithCrashProtection(condition ConditionFunc) (bool, error) { // // Deprecated: Will be removed when the legacy polling methods are removed. func runConditionWithCrashProtectionWithContext(ctx context.Context, condition ConditionWithContextFunc) (bool, error) { - defer runtime.HandleCrash() + defer runtime.HandleCrashWithContext(ctx) return condition(ctx) } diff --git a/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go b/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go index 9837b3d..7342f8d 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go +++ b/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder.go @@ -20,10 +20,12 @@ import ( "bufio" "bytes" "encoding/json" + "errors" "fmt" "io" "strings" "unicode" + "unicode/utf8" jsonutil "k8s.io/apimachinery/pkg/util/json" @@ -92,7 +94,7 @@ func UnmarshalStrict(data []byte, v interface{}) error { // YAML decoding path is not used (so that error messages are // JSON specific). func ToJSON(data []byte) ([]byte, error) { - if hasJSONPrefix(data) { + if IsJSONBuffer(data) { return data, nil } return yaml.YAMLToJSON(data) @@ -102,7 +104,8 @@ func ToJSON(data []byte) ([]byte, error) { // separating individual documents. It first converts the YAML // body to JSON, then unmarshals the JSON. type YAMLToJSONDecoder struct { - reader Reader + reader Reader + inputOffset int } // NewYAMLToJSONDecoder decodes YAML documents from the provided @@ -121,7 +124,7 @@ func NewYAMLToJSONDecoder(r io.Reader) *YAMLToJSONDecoder { // yaml.Unmarshal. func (d *YAMLToJSONDecoder) Decode(into interface{}) error { bytes, err := d.reader.Read() - if err != nil && err != io.EOF { + if err != nil && err != io.EOF { //nolint:errorlint return err } @@ -131,9 +134,14 @@ func (d *YAMLToJSONDecoder) Decode(into interface{}) error { return YAMLSyntaxError{err} } } + d.inputOffset += len(bytes) return err } +func (d *YAMLToJSONDecoder) InputOffset() int { + return d.inputOffset +} + // YAMLDecoder reads chunks of objects and returns ErrShortBuffer if // the data is not sufficient. type YAMLDecoder struct { @@ -229,18 +237,20 @@ func splitYAMLDocument(data []byte, atEOF bool) (advance int, token []byte, err return 0, nil, nil } -// decoder is a convenience interface for Decode. -type decoder interface { - Decode(into interface{}) error -} - -// YAMLOrJSONDecoder attempts to decode a stream of JSON documents or -// YAML documents by sniffing for a leading { character. +// YAMLOrJSONDecoder attempts to decode a stream of JSON or YAML documents. +// While JSON is YAML, the way Go's JSON decode defines a multi-document stream +// is a series of JSON objects (e.g. {}{}), but YAML defines a multi-document +// stream as a series of documents separated by "---". +// +// This decoder will attempt to decode the stream as JSON first, and if that +// fails, it will switch to YAML. Once it determines the stream is JSON (by +// finding a non-YAML-delimited series of objects), it will not switch to YAML. +// Once it switches to YAML it will not switch back to JSON. type YAMLOrJSONDecoder struct { - r io.Reader - bufferSize int - - decoder decoder + json *json.Decoder + yaml *YAMLToJSONDecoder + stream *StreamReader + count int // how many objects have been decoded } type JSONSyntaxError struct { @@ -265,31 +275,108 @@ func (e YAMLSyntaxError) Error() string { // how far into the stream the decoder will look to figure out whether this // is a JSON stream (has whitespace followed by an open brace). func NewYAMLOrJSONDecoder(r io.Reader, bufferSize int) *YAMLOrJSONDecoder { - return &YAMLOrJSONDecoder{ - r: r, - bufferSize: bufferSize, + d := &YAMLOrJSONDecoder{} + + reader, _, mightBeJSON := GuessJSONStream(r, bufferSize) + d.stream = reader + if mightBeJSON { + d.json = json.NewDecoder(reader) + } else { + d.yaml = NewYAMLToJSONDecoder(reader) } + return d } // Decode unmarshals the next object from the underlying stream into the // provide object, or returns an error. func (d *YAMLOrJSONDecoder) Decode(into interface{}) error { - if d.decoder == nil { - buffer, _, isJSON := GuessJSONStream(d.r, d.bufferSize) - if isJSON { - d.decoder = json.NewDecoder(buffer) + // Because we don't know if this is a JSON or YAML stream, a failure from + // both decoders is ambiguous. When in doubt, it will return the error from + // the JSON decoder. Unfortunately, this means that if the first document + // is invalid YAML, the error won't be awesome. + // TODO: the errors from YAML are not great, we could improve them a lot. + var firstErr error + if d.json != nil { + err := d.json.Decode(into) + if err == nil { + d.stream.Consume(int(d.json.InputOffset()) - d.stream.Consumed()) + d.count++ + return nil + } + if err == io.EOF { //nolint:errorlint + return err + } + var syntax *json.SyntaxError + if ok := errors.As(err, &syntax); ok { + firstErr = JSONSyntaxError{ + Offset: syntax.Offset, + Err: syntax, + } } else { - d.decoder = NewYAMLToJSONDecoder(buffer) + firstErr = err + } + if d.count > 1 { + // If we found 0 or 1 JSON object(s), this stream is still + // ambiguous. But if we found more than 1 JSON object, then this + // is an unambiguous JSON stream, and we should not switch to YAML. + return err + } + // If JSON decoding hits the end of one object and then fails on the + // next, it leaves any leading whitespace in the buffer, which can + // confuse the YAML decoder. We just eat any whitespace we find, up to + // and including the first newline. + d.stream.Rewind() + if err := d.consumeWhitespace(); err == nil { + d.yaml = NewYAMLToJSONDecoder(d.stream) + } + d.json = nil + } + if d.yaml != nil { + err := d.yaml.Decode(into) + if err == nil { + d.stream.Consume(d.yaml.InputOffset() - d.stream.Consumed()) + d.count++ + return nil + } + if err == io.EOF { //nolint:errorlint + return err + } + if firstErr == nil { + firstErr = err } } - err := d.decoder.Decode(into) - if syntax, ok := err.(*json.SyntaxError); ok { - return JSONSyntaxError{ - Offset: syntax.Offset, - Err: syntax, + if firstErr != nil { + return firstErr + } + return fmt.Errorf("decoding failed as both JSON and YAML") +} + +func (d *YAMLOrJSONDecoder) consumeWhitespace() error { + consumed := 0 + for { + buf, err := d.stream.ReadN(4) + if err != nil && err == io.EOF { //nolint:errorlint + return err + } + r, sz := utf8.DecodeRune(buf) + if r == utf8.RuneError || sz == 0 { + return fmt.Errorf("invalid utf8 rune") + } + d.stream.RewindN(len(buf) - sz) + if !unicode.IsSpace(r) { + d.stream.RewindN(sz) + d.stream.Consume(consumed) + return nil + } + if r == '\n' { + d.stream.Consume(consumed) + return nil + } + if err == io.EOF { //nolint:errorlint + break } } - return err + return io.EOF } type Reader interface { @@ -311,7 +398,7 @@ func (r *YAMLReader) Read() ([]byte, error) { var buffer bytes.Buffer for { line, err := r.reader.Read() - if err != nil && err != io.EOF { + if err != nil && err != io.EOF { //nolint:errorlint return nil, err } @@ -329,11 +416,11 @@ func (r *YAMLReader) Read() ([]byte, error) { if buffer.Len() != 0 { return buffer.Bytes(), nil } - if err == io.EOF { + if err == io.EOF { //nolint:errorlint return nil, err } } - if err == io.EOF { + if err == io.EOF { //nolint:errorlint if buffer.Len() != 0 { // If we're at EOF, we have a final, non-terminated line. Return it. return buffer.Bytes(), nil @@ -369,26 +456,20 @@ func (r *LineReader) Read() ([]byte, error) { // GuessJSONStream scans the provided reader up to size, looking // for an open brace indicating this is JSON. It will return the // bufio.Reader it creates for the consumer. -func GuessJSONStream(r io.Reader, size int) (io.Reader, []byte, bool) { - buffer := bufio.NewReaderSize(r, size) +func GuessJSONStream(r io.Reader, size int) (*StreamReader, []byte, bool) { + buffer := NewStreamReader(r, size) b, _ := buffer.Peek(size) - return buffer, b, hasJSONPrefix(b) + return buffer, b, IsJSONBuffer(b) } // IsJSONBuffer scans the provided buffer, looking // for an open brace indicating this is JSON. func IsJSONBuffer(buf []byte) bool { - return hasJSONPrefix(buf) + return hasPrefix(buf, jsonPrefix) } var jsonPrefix = []byte("{") -// hasJSONPrefix returns true if the provided buffer appears to start with -// a JSON open brace. -func hasJSONPrefix(buf []byte) bool { - return hasPrefix(buf, jsonPrefix) -} - // Return true if the first non-whitespace bytes in buf is // prefix. func hasPrefix(buf []byte, prefix []byte) bool { diff --git a/vendor/k8s.io/apimachinery/pkg/util/yaml/stream_reader.go b/vendor/k8s.io/apimachinery/pkg/util/yaml/stream_reader.go new file mode 100644 index 0000000..d069910 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/yaml/stream_reader.go @@ -0,0 +1,130 @@ +/* +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 yaml + +import "io" + +// StreamReader is a reader designed for consuming streams of variable-length +// messages. It buffers data until it is explicitly consumed, and can be +// rewound to re-read previous data. +type StreamReader struct { + r io.Reader + buf []byte + head int // current read offset into buf + ttlConsumed int // number of bytes which have been consumed +} + +// NewStreamReader creates a new StreamReader wrapping the provided +// io.Reader. +func NewStreamReader(r io.Reader, size int) *StreamReader { + if size == 0 { + size = 4096 + } + return &StreamReader{ + r: r, + buf: make([]byte, 0, size), // Start with a reasonable capacity + } +} + +// Read implements io.Reader. It first returns any buffered data after the +// current offset, and if that's exhausted, reads from the underlying reader +// and buffers the data. The returned data is not considered consumed until the +// Consume method is called. +func (r *StreamReader) Read(p []byte) (n int, err error) { + // If we have buffered data, return it + if r.head < len(r.buf) { + n = copy(p, r.buf[r.head:]) + r.head += n + return n, nil + } + + // If we've already hit EOF, return it + if r.r == nil { + return 0, io.EOF + } + + // Read from the underlying reader + n, err = r.r.Read(p) + if n > 0 { + r.buf = append(r.buf, p[:n]...) + r.head += n + } + if err == nil { + return n, nil + } + if err == io.EOF { + // Store that we've hit EOF by setting r to nil + r.r = nil + } + return n, err +} + +// ReadN reads exactly n bytes from the reader, blocking until all bytes are +// read or an error occurs. If an error occurs, the number of bytes read is +// returned along with the error. If EOF is hit before n bytes are read, this +// will return the bytes read so far, along with io.EOF. The returned data is +// not considered consumed until the Consume method is called. +func (r *StreamReader) ReadN(want int) ([]byte, error) { + ret := make([]byte, want) + off := 0 + for off < want { + n, err := r.Read(ret[off:]) + if err != nil { + return ret[:off+n], err + } + off += n + } + return ret, nil +} + +// Peek returns the next n bytes without advancing the reader. The returned +// bytes are valid until the next call to Consume. +func (r *StreamReader) Peek(n int) ([]byte, error) { + buf, err := r.ReadN(n) + r.RewindN(len(buf)) + if err != nil { + return buf, err + } + return buf, nil +} + +// Rewind resets the reader to the beginning of the buffered data. +func (r *StreamReader) Rewind() { + r.head = 0 +} + +// RewindN rewinds the reader by n bytes. If n is greater than the current +// buffer, the reader is rewound to the beginning of the buffer. +func (r *StreamReader) RewindN(n int) { + r.head -= min(n, r.head) +} + +// Consume discards up to n bytes of previously read data from the beginning of +// the buffer. Once consumed, that data is no longer available for rewinding. +// If n is greater than the current buffer, the buffer is cleared. Consume +// never consume data from the underlying reader. +func (r *StreamReader) Consume(n int) { + n = min(n, len(r.buf)) + r.buf = r.buf[n:] + r.head -= n + r.ttlConsumed += n +} + +// Consumed returns the number of bytes consumed from the input reader. +func (r *StreamReader) Consumed() int { + return r.ttlConsumed +} diff --git a/vendor/k8s.io/apimachinery/pkg/version/doc.go b/vendor/k8s.io/apimachinery/pkg/version/doc.go index 29574fd..5f446a4 100644 --- a/vendor/k8s.io/apimachinery/pkg/version/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/version/doc.go @@ -16,5 +16,5 @@ limitations under the License. // +k8s:openapi-gen=true -// Package version supplies the type for version information collected at build time. -package version // import "k8s.io/apimachinery/pkg/version" +// Package version supplies the type for version information. +package version diff --git a/vendor/k8s.io/apimachinery/pkg/version/types.go b/vendor/k8s.io/apimachinery/pkg/version/types.go index 72727b5..6a18f9e 100644 --- a/vendor/k8s.io/apimachinery/pkg/version/types.go +++ b/vendor/k8s.io/apimachinery/pkg/version/types.go @@ -20,15 +20,25 @@ package version // TODO: Add []string of api versions supported? It's still unclear // how we'll want to distribute that information. type Info struct { - Major string `json:"major"` - Minor string `json:"minor"` - GitVersion string `json:"gitVersion"` - GitCommit string `json:"gitCommit"` - GitTreeState string `json:"gitTreeState"` - BuildDate string `json:"buildDate"` - GoVersion string `json:"goVersion"` - Compiler string `json:"compiler"` - Platform string `json:"platform"` + // Major is the major version of the binary version + Major string `json:"major"` + // Minor is the minor version of the binary version + Minor string `json:"minor"` + // EmulationMajor is the major version of the emulation version + EmulationMajor string `json:"emulationMajor,omitempty"` + // EmulationMinor is the minor version of the emulation version + EmulationMinor string `json:"emulationMinor,omitempty"` + // MinCompatibilityMajor is the major version of the minimum compatibility version + MinCompatibilityMajor string `json:"minCompatibilityMajor,omitempty"` + // MinCompatibilityMinor is the minor version of the minimum compatibility version + MinCompatibilityMinor string `json:"minCompatibilityMinor,omitempty"` + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit"` + GitTreeState string `json:"gitTreeState"` + BuildDate string `json:"buildDate"` + GoVersion string `json:"goVersion"` + Compiler string `json:"compiler"` + Platform string `json:"platform"` } // String returns info as a human-friendly version string. diff --git a/vendor/k8s.io/apimachinery/pkg/watch/doc.go b/vendor/k8s.io/apimachinery/pkg/watch/doc.go index 7e6bf3f..5fde5e7 100644 --- a/vendor/k8s.io/apimachinery/pkg/watch/doc.go +++ b/vendor/k8s.io/apimachinery/pkg/watch/doc.go @@ -16,4 +16,4 @@ limitations under the License. // Package watch contains a generic watchable interface, and a fake for // testing code that uses the watch interface. -package watch // import "k8s.io/apimachinery/pkg/watch" +package watch diff --git a/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go b/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go index 42dcac2..b422ca9 100644 --- a/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go +++ b/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher.go @@ -51,6 +51,7 @@ type Reporter interface { // StreamWatcher turns any stream for which you can write a Decoder interface // into a watch.Interface. type StreamWatcher struct { + logger klog.Logger sync.Mutex source Decoder reporter Reporter @@ -59,8 +60,16 @@ type StreamWatcher struct { } // NewStreamWatcher creates a StreamWatcher from the given decoder. +// +// Contextual logging: NewStreamWatcherWithLogger should be used instead of NewStreamWatcher in code which supports contextual logging. func NewStreamWatcher(d Decoder, r Reporter) *StreamWatcher { + return NewStreamWatcherWithLogger(klog.Background(), d, r) +} + +// NewStreamWatcherWithLogger creates a StreamWatcher from the given decoder and logger. +func NewStreamWatcherWithLogger(logger klog.Logger, d Decoder, r Reporter) *StreamWatcher { sw := &StreamWatcher{ + logger: logger, source: d, reporter: r, // It's easy for a consumer to add buffering via an extra @@ -98,7 +107,7 @@ func (sw *StreamWatcher) Stop() { // receive reads result from the decoder in a loop and sends down the result channel. func (sw *StreamWatcher) receive() { - defer utilruntime.HandleCrash() + defer utilruntime.HandleCrashWithLogger(sw.logger) defer close(sw.result) defer sw.Stop() for { @@ -108,10 +117,10 @@ func (sw *StreamWatcher) receive() { case io.EOF: // watch closed normally case io.ErrUnexpectedEOF: - klog.V(1).Infof("Unexpected EOF during watch stream event decoding: %v", err) + sw.logger.V(1).Info("Unexpected EOF during watch stream event decoding", "err", err) default: if net.IsProbableEOF(err) || net.IsTimeout(err) { - klog.V(5).Infof("Unable to decode an event from the watch stream: %v", err) + sw.logger.V(5).Info("Unable to decode an event from the watch stream", "err", err) } else { select { case <-sw.done: diff --git a/vendor/k8s.io/apimachinery/pkg/watch/watch.go b/vendor/k8s.io/apimachinery/pkg/watch/watch.go index ce37fd8..2514598 100644 --- a/vendor/k8s.io/apimachinery/pkg/watch/watch.go +++ b/vendor/k8s.io/apimachinery/pkg/watch/watch.go @@ -23,6 +23,7 @@ import ( "k8s.io/klog/v2" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" ) // Interface can be implemented by anything that knows how to watch and report changes. @@ -103,29 +104,42 @@ func (w emptyWatch) ResultChan() <-chan Event { // FakeWatcher lets you test anything that consumes a watch.Interface; threadsafe. type FakeWatcher struct { + logger klog.Logger result chan Event stopped bool sync.Mutex } +var _ Interface = &FakeWatcher{} + +// Contextual logging: NewFakeWithOptions and a logger in the FakeOptions should be used instead in code which supports contextual logging. func NewFake() *FakeWatcher { - return &FakeWatcher{ - result: make(chan Event), - } + return NewFakeWithOptions(FakeOptions{}) } +// Contextual logging: NewFakeWithOptions and a logger in the FakeOptions should be used instead in code which supports contextual logging. func NewFakeWithChanSize(size int, blocking bool) *FakeWatcher { + return NewFakeWithOptions(FakeOptions{ChannelSize: size}) +} + +func NewFakeWithOptions(options FakeOptions) *FakeWatcher { return &FakeWatcher{ - result: make(chan Event, size), + logger: ptr.Deref(options.Logger, klog.Background()), + result: make(chan Event, options.ChannelSize), } } +type FakeOptions struct { + Logger *klog.Logger + ChannelSize int +} + // Stop implements Interface.Stop(). func (f *FakeWatcher) Stop() { f.Lock() defer f.Unlock() if !f.stopped { - klog.V(4).Infof("Stopping fake watcher.") + f.logger.V(4).Info("Stopping fake watcher") close(f.result) f.stopped = true } @@ -176,13 +190,22 @@ func (f *FakeWatcher) Action(action EventType, obj runtime.Object) { // RaceFreeFakeWatcher lets you test anything that consumes a watch.Interface; threadsafe. type RaceFreeFakeWatcher struct { + logger klog.Logger result chan Event Stopped bool sync.Mutex } +var _ Interface = &RaceFreeFakeWatcher{} + +// Contextual logging: RaceFreeFakeWatcherWithLogger should be used instead of NewRaceFreeFake in code which supports contextual logging. func NewRaceFreeFake() *RaceFreeFakeWatcher { + return NewRaceFreeFakeWithLogger(klog.Background()) +} + +func NewRaceFreeFakeWithLogger(logger klog.Logger) *RaceFreeFakeWatcher { return &RaceFreeFakeWatcher{ + logger: logger, result: make(chan Event, DefaultChanSize), } } @@ -192,7 +215,7 @@ func (f *RaceFreeFakeWatcher) Stop() { f.Lock() defer f.Unlock() if !f.Stopped { - klog.V(4).Infof("Stopping fake watcher.") + f.logger.V(4).Info("Stopping fake watcher") close(f.result) f.Stopped = true } diff --git a/vendor/k8s.io/client-go/features/known_features.go b/vendor/k8s.io/client-go/features/known_features.go index a74f6a8..344d2eb 100644 --- a/vendor/k8s.io/client-go/features/known_features.go +++ b/vendor/k8s.io/client-go/features/known_features.go @@ -53,6 +53,12 @@ const ( // alpha: v1.30 InformerResourceVersion Feature = "InformerResourceVersion" + // owner: @deads2k + // beta: v1.33 + // + // Refactor informers to deliver watch stream events in order instead of out of order. + InOrderInformers Feature = "InOrderInformers" + // owner: @p0lyn0mial // beta: v1.30 // @@ -73,5 +79,6 @@ var defaultKubernetesFeatureGates = map[Feature]FeatureSpec{ ClientsAllowCBOR: {Default: false, PreRelease: Alpha}, ClientsPreferCBOR: {Default: false, PreRelease: Alpha}, InformerResourceVersion: {Default: false, PreRelease: Alpha}, + InOrderInformers: {Default: true, PreRelease: Beta}, WatchListClient: {Default: false, PreRelease: Beta}, } diff --git a/vendor/k8s.io/client-go/pkg/apis/clientauthentication/doc.go b/vendor/k8s.io/client-go/pkg/apis/clientauthentication/doc.go index b994597..486790f 100644 --- a/vendor/k8s.io/client-go/pkg/apis/clientauthentication/doc.go +++ b/vendor/k8s.io/client-go/pkg/apis/clientauthentication/doc.go @@ -17,4 +17,4 @@ limitations under the License. // +k8s:deepcopy-gen=package // +groupName=client.authentication.k8s.io -package clientauthentication // import "k8s.io/client-go/pkg/apis/clientauthentication" +package clientauthentication diff --git a/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go b/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go index 94ca35c..e378b75 100644 --- a/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go +++ b/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go @@ -21,4 +21,4 @@ limitations under the License. // +groupName=client.authentication.k8s.io -package v1 // import "k8s.io/client-go/pkg/apis/clientauthentication/v1" +package v1 diff --git a/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/doc.go b/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/doc.go index 22d1c58..6eb6a98 100644 --- a/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/doc.go +++ b/vendor/k8s.io/client-go/pkg/apis/clientauthentication/v1beta1/doc.go @@ -21,4 +21,4 @@ limitations under the License. // +groupName=client.authentication.k8s.io -package v1beta1 // import "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" +package v1beta1 diff --git a/vendor/k8s.io/client-go/pkg/version/doc.go b/vendor/k8s.io/client-go/pkg/version/doc.go index 05e997e..c3ace74 100644 --- a/vendor/k8s.io/client-go/pkg/version/doc.go +++ b/vendor/k8s.io/client-go/pkg/version/doc.go @@ -18,4 +18,4 @@ limitations under the License. // Package version supplies version information collected at build time to // kubernetes components. -package version // import "k8s.io/client-go/pkg/version" +package version diff --git a/vendor/k8s.io/client-go/rest/.mockery.yaml b/vendor/k8s.io/client-go/rest/.mockery.yaml new file mode 100644 index 0000000..e21d7b5 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/.mockery.yaml @@ -0,0 +1,10 @@ +--- +dir: . +filename: "mock_{{.InterfaceName | snakecase}}_test.go" +boilerplate-file: ../../../../../hack/boilerplate/boilerplate.generatego.txt +outpkg: rest +with-expecter: true +packages: + k8s.io/client-go/rest: + interfaces: + BackoffManager: diff --git a/vendor/k8s.io/client-go/rest/client.go b/vendor/k8s.io/client-go/rest/client.go index 159caa1..a085c33 100644 --- a/vendor/k8s.io/client-go/rest/client.go +++ b/vendor/k8s.io/client-go/rest/client.go @@ -93,7 +93,7 @@ type RESTClient struct { content requestClientContentConfigProvider // creates BackoffManager that is passed to requests. - createBackoffMgr func() BackoffManager + createBackoffMgr func() BackoffManagerWithContext // rateLimiter is shared among all requests created by this client unless specifically // overridden. @@ -101,7 +101,7 @@ type RESTClient struct { // warningHandler is shared among all requests created by this client. // If not set, defaultWarningHandler is used. - warningHandler WarningHandler + warningHandler WarningHandlerWithContext // Set specific behavior of the client. If not set http.DefaultClient will be used. Client *http.Client @@ -178,7 +178,7 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter { // readExpBackoffConfig handles the internal logic of determining what the // backoff policy is. By default if no information is available, NoBackoff. // TODO Generalize this see #17727 . -func readExpBackoffConfig() BackoffManager { +func readExpBackoffConfig() BackoffManagerWithContext { backoffBase := os.Getenv(envBackoffBase) backoffDuration := os.Getenv(envBackoffDuration) diff --git a/vendor/k8s.io/client-go/rest/config.go b/vendor/k8s.io/client-go/rest/config.go index f2e813d..82d4f71 100644 --- a/vendor/k8s.io/client-go/rest/config.go +++ b/vendor/k8s.io/client-go/rest/config.go @@ -129,10 +129,23 @@ type Config struct { RateLimiter flowcontrol.RateLimiter // WarningHandler handles warnings in server responses. - // If not set, the default warning handler is used. - // See documentation for SetDefaultWarningHandler() for details. + // If this and WarningHandlerWithContext are not set, the + // default warning handler is used. If both are set, + // WarningHandlerWithContext is used. + // + // See documentation for [SetDefaultWarningHandler] for details. + // + //logcheck:context // WarningHandlerWithContext should be used instead of WarningHandler in code which supports contextual logging. WarningHandler WarningHandler + // WarningHandlerWithContext handles warnings in server responses. + // If this and WarningHandler are not set, the + // default warning handler is used. If both are set, + // WarningHandlerWithContext is used. + // + // See documentation for [SetDefaultWarningHandler] for details. + WarningHandlerWithContext WarningHandlerWithContext + // The maximum length of time to wait before giving up on a server request. A value of zero means no timeout. Timeout time.Duration @@ -381,12 +394,27 @@ func RESTClientForConfigAndClient(config *Config, httpClient *http.Client) (*RES } restClient, err := NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient) - if err == nil && config.WarningHandler != nil { - restClient.warningHandler = config.WarningHandler - } + maybeSetWarningHandler(restClient, config.WarningHandler, config.WarningHandlerWithContext) return restClient, err } +// maybeSetWarningHandler sets the handlerWithContext if non-nil, +// otherwise the handler with a wrapper if non-nil, +// and does nothing if both are nil. +// +// May be called for a nil client. +func maybeSetWarningHandler(c *RESTClient, handler WarningHandler, handlerWithContext WarningHandlerWithContext) { + if c == nil { + return + } + switch { + case handlerWithContext != nil: + c.warningHandler = handlerWithContext + case handler != nil: + c.warningHandler = warningLoggerNopContext{l: handler} + } +} + // UnversionedRESTClientFor is the same as RESTClientFor, except that it allows // the config.Version to be empty. func UnversionedRESTClientFor(config *Config) (*RESTClient, error) { @@ -448,9 +476,7 @@ func UnversionedRESTClientForConfigAndClient(config *Config, httpClient *http.Cl } restClient, err := NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient) - if err == nil && config.WarningHandler != nil { - restClient.warningHandler = config.WarningHandler - } + maybeSetWarningHandler(restClient, config.WarningHandler, config.WarningHandlerWithContext) return restClient, err } @@ -532,6 +558,7 @@ func InClusterConfig() (*Config, error) { tlsClientConfig := TLSClientConfig{} if _, err := certutil.NewPool(rootCAFile); err != nil { + //nolint:logcheck // The decision to log this instead of returning an error goes back to ~2016. It's part of the client-go API now, so not changing it just to support contextual logging. klog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err) } else { tlsClientConfig.CAFile = rootCAFile @@ -616,15 +643,16 @@ func AnonymousClientConfig(config *Config) *Config { CAData: config.TLSClientConfig.CAData, NextProtos: config.TLSClientConfig.NextProtos, }, - RateLimiter: config.RateLimiter, - WarningHandler: config.WarningHandler, - UserAgent: config.UserAgent, - DisableCompression: config.DisableCompression, - QPS: config.QPS, - Burst: config.Burst, - Timeout: config.Timeout, - Dial: config.Dial, - Proxy: config.Proxy, + RateLimiter: config.RateLimiter, + WarningHandler: config.WarningHandler, + WarningHandlerWithContext: config.WarningHandlerWithContext, + UserAgent: config.UserAgent, + DisableCompression: config.DisableCompression, + QPS: config.QPS, + Burst: config.Burst, + Timeout: config.Timeout, + Dial: config.Dial, + Proxy: config.Proxy, } } @@ -658,17 +686,18 @@ func CopyConfig(config *Config) *Config { CAData: config.TLSClientConfig.CAData, NextProtos: config.TLSClientConfig.NextProtos, }, - UserAgent: config.UserAgent, - DisableCompression: config.DisableCompression, - Transport: config.Transport, - WrapTransport: config.WrapTransport, - QPS: config.QPS, - Burst: config.Burst, - RateLimiter: config.RateLimiter, - WarningHandler: config.WarningHandler, - Timeout: config.Timeout, - Dial: config.Dial, - Proxy: config.Proxy, + UserAgent: config.UserAgent, + DisableCompression: config.DisableCompression, + Transport: config.Transport, + WrapTransport: config.WrapTransport, + QPS: config.QPS, + Burst: config.Burst, + RateLimiter: config.RateLimiter, + WarningHandler: config.WarningHandler, + WarningHandlerWithContext: config.WarningHandlerWithContext, + Timeout: config.Timeout, + Dial: config.Dial, + Proxy: config.Proxy, } if config.ExecProvider != nil && config.ExecProvider.Config != nil { c.ExecProvider.Config = config.ExecProvider.Config.DeepCopyObject() diff --git a/vendor/k8s.io/client-go/rest/plugin.go b/vendor/k8s.io/client-go/rest/plugin.go index ae5cbdc..f7a4e4f 100644 --- a/vendor/k8s.io/client-go/rest/plugin.go +++ b/vendor/k8s.io/client-go/rest/plugin.go @@ -21,8 +21,6 @@ import ( "net/http" "sync" - "k8s.io/klog/v2" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) @@ -65,7 +63,10 @@ func RegisterAuthProviderPlugin(name string, plugin Factory) error { if _, found := plugins[name]; found { return fmt.Errorf("auth Provider Plugin %q was registered twice", name) } - klog.V(4).Infof("Registered Auth Provider Plugin %q", name) + // RegisterAuthProviderPlugin gets called during the init phase before + // logging is initialized and therefore should not emit logs. If you + // need this message for debugging something, then uncomment it. + // klog.V(4).Infof("Registered Auth Provider Plugin %q", name) plugins[name] = plugin return nil } diff --git a/vendor/k8s.io/client-go/rest/request.go b/vendor/k8s.io/client-go/rest/request.go index 0ec90ad..1eb2f9b 100644 --- a/vendor/k8s.io/client-go/rest/request.go +++ b/vendor/k8s.io/client-go/rest/request.go @@ -54,7 +54,7 @@ import ( "k8s.io/utils/clock" ) -var ( +const ( // longThrottleLatency defines threshold for logging requests. All requests being // throttled (via the provided rateLimiter) for more than longThrottleLatency will // be logged. @@ -103,10 +103,10 @@ type Request struct { contentConfig ClientContentConfig contentTypeNotSet bool - warningHandler WarningHandler + warningHandler WarningHandlerWithContext rateLimiter flowcontrol.RateLimiter - backoff BackoffManager + backoff BackoffManagerWithContext timeout time.Duration maxRetries int @@ -136,7 +136,7 @@ type Request struct { // NewRequest creates a new request helper object for accessing runtime.Objects on a server. func NewRequest(c *RESTClient) *Request { - var backoff BackoffManager + var backoff BackoffManagerWithContext if c.createBackoffMgr != nil { backoff = c.createBackoffMgr() } @@ -259,20 +259,47 @@ func (r *Request) Resource(resource string) *Request { } // BackOff sets the request's backoff manager to the one specified, -// or defaults to the stub implementation if nil is provided +// or defaults to the stub implementation if nil is provided. +// +// Deprecated: BackoffManager.Sleep ignores the caller's context. Use BackOffWithContext and BackoffManagerWithContext instead. func (r *Request) BackOff(manager BackoffManager) *Request { if manager == nil { r.backoff = &NoBackoff{} return r } + r.backoff = &backoffManagerNopContext{BackoffManager: manager} + return r +} + +// BackOffWithContext sets the request's backoff manager to the one specified, +// or defaults to the stub implementation if nil is provided. +func (r *Request) BackOffWithContext(manager BackoffManagerWithContext) *Request { + if manager == nil { + r.backoff = &NoBackoff{} + return r + } + r.backoff = manager return r } // WarningHandler sets the handler this client uses when warning headers are encountered. -// If set to nil, this client will use the default warning handler (see SetDefaultWarningHandler). +// If set to nil, this client will use the default warning handler (see [SetDefaultWarningHandler]). +// +//logcheck:context // WarningHandlerWithContext should be used instead of WarningHandler in code which supports contextual logging. func (r *Request) WarningHandler(handler WarningHandler) *Request { + if handler == nil { + r.warningHandler = nil + return r + } + r.warningHandler = warningLoggerNopContext{l: handler} + return r +} + +// WarningHandlerWithContext sets the handler this client uses when warning headers are encountered. +// If set to nil, this client will use the default warning handler (see [SetDefaultWarningHandlerWithContext]). +func (r *Request) WarningHandlerWithContext(handler WarningHandlerWithContext) *Request { r.warningHandler = handler return r } @@ -649,21 +676,17 @@ func (r *Request) tryThrottleWithInfo(ctx context.Context, retryInfo string) err } latency := time.Since(now) - var message string - switch { - case len(retryInfo) > 0: - message = fmt.Sprintf("Waited for %v, %s - request: %s:%s", latency, retryInfo, r.verb, r.URL().String()) - default: - message = fmt.Sprintf("Waited for %v due to client-side throttling, not priority and fairness, request: %s:%s", latency, r.verb, r.URL().String()) - } - if latency > longThrottleLatency { - klog.V(3).Info(message) - } - if latency > extraLongThrottleLatency { - // If the rate limiter latency is very high, the log message should be printed at a higher log level, - // but we use a throttled logger to prevent spamming. - globalThrottledLogger.Infof("%s", message) + if retryInfo == "" { + retryInfo = "client-side throttling, not priority and fairness" + } + klog.FromContext(ctx).V(3).Info("Waited before sending request", "delay", latency, "reason", retryInfo, "verb", r.verb, "URL", r.URL()) + + if latency > extraLongThrottleLatency { + // If the rate limiter latency is very high, the log message should be printed at a higher log level, + // but we use a throttled logger to prevent spamming. + globalThrottledLogger.info(klog.FromContext(ctx), "Waited before sending request", "delay", latency, "reason", retryInfo, "verb", r.verb, "URL", r.URL()) + } } metrics.RateLimiterLatency.Observe(ctx, r.verb, r.finalURLTemplate(), latency) @@ -675,7 +698,7 @@ func (r *Request) tryThrottle(ctx context.Context) error { } type throttleSettings struct { - logLevel klog.Level + logLevel int minLogInterval time.Duration lastLogTime time.Time @@ -700,9 +723,9 @@ var globalThrottledLogger = &throttledLogger{ }, } -func (b *throttledLogger) attemptToLog() (klog.Level, bool) { +func (b *throttledLogger) attemptToLog(logger klog.Logger) (int, bool) { for _, setting := range b.settings { - if bool(klog.V(setting.logLevel).Enabled()) { + if bool(logger.V(setting.logLevel).Enabled()) { // Return early without write locking if possible. if func() bool { setting.lock.RLock() @@ -724,9 +747,9 @@ func (b *throttledLogger) attemptToLog() (klog.Level, bool) { // Infof will write a log message at each logLevel specified by the receiver's throttleSettings // as long as it hasn't written a log message more recently than minLogInterval. -func (b *throttledLogger) Infof(message string, args ...interface{}) { - if logLevel, ok := b.attemptToLog(); ok { - klog.V(logLevel).Infof(message, args...) +func (b *throttledLogger) info(logger klog.Logger, message string, kv ...any) { + if logLevel, ok := b.attemptToLog(logger); ok { + logger.V(logLevel).Info(message, kv...) } } @@ -739,7 +762,7 @@ func (r *Request) Watch(ctx context.Context) (watch.Interface, error) { func (r *Request) watchInternal(ctx context.Context) (watch.Interface, runtime.Decoder, error) { if r.body == nil { - logBody(ctx, 2, "Request Body", r.bodyBytes) + logBody(klog.FromContext(ctx), 2, "Request Body", r.bodyBytes) } // We specifically don't want to rate limit watches, so we @@ -776,7 +799,7 @@ func (r *Request) watchInternal(ctx context.Context) (watch.Interface, runtime.D resp, err := client.Do(req) retry.After(ctx, r, resp, err) if err == nil && resp.StatusCode == http.StatusOK { - return r.newStreamWatcher(resp) + return r.newStreamWatcher(ctx, resp) } done, transformErr := func() (bool, error) { @@ -898,7 +921,7 @@ func (r WatchListResult) Into(obj runtime.Object) error { // to see what parameters are currently required. func (r *Request) WatchList(ctx context.Context) WatchListResult { if r.body == nil { - logBody(ctx, 2, "Request Body", r.bodyBytes) + logBody(klog.FromContext(ctx), 2, "Request Body", r.bodyBytes) } if !clientfeatures.FeatureGates().Enabled(clientfeatures.WatchListClient) { @@ -969,23 +992,24 @@ func (r *Request) handleWatchList(ctx context.Context, w watch.Interface, negoti } } -func (r *Request) newStreamWatcher(resp *http.Response) (watch.Interface, runtime.Decoder, error) { +func (r *Request) newStreamWatcher(ctx context.Context, resp *http.Response) (watch.Interface, runtime.Decoder, error) { contentType := resp.Header.Get("Content-Type") mediaType, params, err := mime.ParseMediaType(contentType) if err != nil { - klog.V(4).Infof("Unexpected content type from the server: %q: %v", contentType, err) + klog.FromContext(ctx).V(4).Info("Unexpected content type from the server", "contentType", contentType, "err", err) } objectDecoder, streamingSerializer, framer, err := r.contentConfig.Negotiator.StreamDecoder(mediaType, params) if err != nil { return nil, nil, err } - handleWarnings(resp.Header, r.warningHandler) + handleWarnings(ctx, resp.Header, r.warningHandler) frameReader := framer.NewFrameReader(resp.Body) watchEventDecoder := streaming.NewDecoder(frameReader, streamingSerializer) - return watch.NewStreamWatcher( + return watch.NewStreamWatcherWithLogger( + klog.FromContext(ctx), restclientwatch.NewDecoder(watchEventDecoder, objectDecoder), // use 500 to indicate that the cause of the error is unknown - other error codes // are more specific to HTTP interactions, and set a reason @@ -1031,7 +1055,7 @@ func sanitize(req *Request, resp *http.Response, err error) (string, string) { // If we can, we return that as an error. Otherwise, we create an error that lists the http status and the content of the response. func (r *Request) Stream(ctx context.Context) (io.ReadCloser, error) { if r.body == nil { - logBody(ctx, 2, "Request Body", r.bodyBytes) + logBody(klog.FromContext(ctx), 2, "Request Body", r.bodyBytes) } if r.err != nil { @@ -1067,7 +1091,7 @@ func (r *Request) Stream(ctx context.Context) (io.ReadCloser, error) { switch { case (resp.StatusCode >= 200) && (resp.StatusCode < 300): - handleWarnings(resp.Header, r.warningHandler) + handleWarnings(ctx, resp.Header, r.warningHandler) return resp.Body, nil default: @@ -1175,7 +1199,7 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp }() if r.err != nil { - klog.V(4).Infof("Error in request: %v", r.err) + klog.FromContext(ctx).V(4).Info("Error in request", "err", r.err) return r.err } @@ -1267,8 +1291,9 @@ func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Resp // - If the server responds with a status: *errors.StatusError or *errors.UnexpectedObjectError // - http.Client.Do errors are returned directly. func (r *Request) Do(ctx context.Context) Result { + logger := klog.FromContext(ctx) if r.body == nil { - logBody(ctx, 2, "Request Body", r.bodyBytes) + logBody(logger, 2, "Request Body", r.bodyBytes) } var result Result @@ -1276,7 +1301,7 @@ func (r *Request) Do(ctx context.Context) Result { result = r.transformResponse(ctx, resp, req) }) if err != nil { - return Result{err: err} + return Result{err: err, logger: logger} } if result.err == nil || len(result.body) > 0 { metrics.ResponseSize.Observe(ctx, r.verb, r.URL().Host, float64(len(result.body))) @@ -1286,14 +1311,15 @@ func (r *Request) Do(ctx context.Context) Result { // DoRaw executes the request but does not process the response body. func (r *Request) DoRaw(ctx context.Context) ([]byte, error) { + logger := klog.FromContext(ctx) if r.body == nil { - logBody(ctx, 2, "Request Body", r.bodyBytes) + logBody(logger, 2, "Request Body", r.bodyBytes) } var result Result err := r.request(ctx, func(req *http.Request, resp *http.Response) { result.body, result.err = io.ReadAll(resp.Body) - logBody(ctx, 2, "Response Body", result.body) + logBody(logger, 2, "Response Body", result.body) if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent { result.err = r.transformUnstructuredResponseError(resp, req, result.body) } @@ -1309,6 +1335,7 @@ func (r *Request) DoRaw(ctx context.Context) ([]byte, error) { // transformResponse converts an API response into a structured API object func (r *Request) transformResponse(ctx context.Context, resp *http.Response, req *http.Request) Result { + logger := klog.FromContext(ctx) var body []byte if resp.Body != nil { data, err := io.ReadAll(resp.Body) @@ -1323,22 +1350,24 @@ func (r *Request) transformResponse(ctx context.Context, resp *http.Response, re // 2. Apiserver sends back the headers and then part of the body // 3. Apiserver closes connection. // 4. client-go should catch this and return an error. - klog.V(2).Infof("Stream error %#v when reading response body, may be caused by closed connection.", err) + logger.V(2).Info("Stream error when reading response body, may be caused by closed connection", "err", err) streamErr := fmt.Errorf("stream error when reading response body, may be caused by closed connection. Please retry. Original error: %w", err) return Result{ - err: streamErr, + err: streamErr, + logger: logger, } default: - klog.Errorf("Unexpected error when reading response body: %v", err) + logger.Error(err, "Unexpected error when reading response body") unexpectedErr := fmt.Errorf("unexpected error when reading response body. Please retry. Original error: %w", err) return Result{ - err: unexpectedErr, + err: unexpectedErr, + logger: logger, } } } // Call depth is tricky. This one is okay for Do and DoRaw. - logBody(ctx, 7, "Response Body", body) + logBody(logger, 7, "Response Body", body) // verify the content type is accurate var decoder runtime.Decoder @@ -1350,7 +1379,7 @@ func (r *Request) transformResponse(ctx context.Context, resp *http.Response, re var err error mediaType, params, err := mime.ParseMediaType(contentType) if err != nil { - return Result{err: errors.NewInternalError(err)} + return Result{err: errors.NewInternalError(err), logger: logger} } decoder, err = r.contentConfig.Negotiator.Decoder(mediaType, params) if err != nil { @@ -1359,13 +1388,14 @@ func (r *Request) transformResponse(ctx context.Context, resp *http.Response, re case resp.StatusCode == http.StatusSwitchingProtocols: // no-op, we've been upgraded case resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent: - return Result{err: r.transformUnstructuredResponseError(resp, req, body)} + return Result{err: r.transformUnstructuredResponseError(resp, req, body), logger: logger} } return Result{ body: body, contentType: contentType, statusCode: resp.StatusCode, - warnings: handleWarnings(resp.Header, r.warningHandler), + warnings: handleWarnings(ctx, resp.Header, r.warningHandler), + logger: logger, } } } @@ -1384,7 +1414,8 @@ func (r *Request) transformResponse(ctx context.Context, resp *http.Response, re statusCode: resp.StatusCode, decoder: decoder, err: err, - warnings: handleWarnings(resp.Header, r.warningHandler), + warnings: handleWarnings(ctx, resp.Header, r.warningHandler), + logger: logger, } } @@ -1393,7 +1424,8 @@ func (r *Request) transformResponse(ctx context.Context, resp *http.Response, re contentType: contentType, statusCode: resp.StatusCode, decoder: decoder, - warnings: handleWarnings(resp.Header, r.warningHandler), + warnings: handleWarnings(ctx, resp.Header, r.warningHandler), + logger: logger, } } @@ -1421,8 +1453,7 @@ func truncateBody(logger klog.Logger, body string) string { // whether the body is printable. // // It needs to be called by all functions which send or receive the data. -func logBody(ctx context.Context, callDepth int, prefix string, body []byte) { - logger := klog.FromContext(ctx) +func logBody(logger klog.Logger, callDepth int, prefix string, body []byte) { if loggerV := logger.V(8); loggerV.Enabled() { loggerV := loggerV.WithCallDepth(callDepth) if bytes.IndexFunc(body, func(r rune) bool { @@ -1524,6 +1555,7 @@ type Result struct { contentType string err error statusCode int + logger klog.Logger decoder runtime.Decoder } @@ -1629,7 +1661,7 @@ func (r Result) Error() error { // to be backwards compatible with old servers that do not return a version, default to "v1" out, _, err := r.decoder.Decode(r.body, &schema.GroupVersionKind{Version: "v1"}, nil) if err != nil { - klog.V(5).Infof("body was not decodable (unable to check for Status): %v", err) + r.logger.V(5).Info("Body was not decodable (unable to check for Status)", "err", err) return r.err } switch t := out.(type) { diff --git a/vendor/k8s.io/client-go/rest/urlbackoff.go b/vendor/k8s.io/client-go/rest/urlbackoff.go index 2f9962d..5b7b4e2 100644 --- a/vendor/k8s.io/client-go/rest/urlbackoff.go +++ b/vendor/k8s.io/client-go/rest/urlbackoff.go @@ -17,6 +17,8 @@ limitations under the License. package rest import ( + "context" + "fmt" "net/url" "time" @@ -32,12 +34,24 @@ import ( var serverIsOverloadedSet = sets.NewInt(429) var maxResponseCode = 499 +//go:generate mockery + +// Deprecated: BackoffManager.Sleep ignores the caller's context. Use BackoffManagerWithContext instead. type BackoffManager interface { - UpdateBackoff(actualUrl *url.URL, err error, responseCode int) - CalculateBackoff(actualUrl *url.URL) time.Duration + UpdateBackoff(actualURL *url.URL, err error, responseCode int) + CalculateBackoff(actualURL *url.URL) time.Duration Sleep(d time.Duration) } +type BackoffManagerWithContext interface { + UpdateBackoffWithContext(ctx context.Context, actualURL *url.URL, err error, responseCode int) + CalculateBackoffWithContext(ctx context.Context, actualURL *url.URL) time.Duration + SleepWithContext(ctx context.Context, d time.Duration) +} + +var _ BackoffManager = &URLBackoff{} +var _ BackoffManagerWithContext = &URLBackoff{} + // URLBackoff struct implements the semantics on top of Backoff which // we need for URL specific exponential backoff. type URLBackoff struct { @@ -49,11 +63,19 @@ type URLBackoff struct { type NoBackoff struct { } -func (n *NoBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) { +func (n *NoBackoff) UpdateBackoff(actualURL *url.URL, err error, responseCode int) { // do nothing. } -func (n *NoBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration { +func (n *NoBackoff) UpdateBackoffWithContext(ctx context.Context, actualURL *url.URL, err error, responseCode int) { + // do nothing. +} + +func (n *NoBackoff) CalculateBackoff(actualURL *url.URL) time.Duration { + return 0 * time.Second +} + +func (n *NoBackoff) CalculateBackoffWithContext(ctx context.Context, actualURL *url.URL) time.Duration { return 0 * time.Second } @@ -61,10 +83,21 @@ func (n *NoBackoff) Sleep(d time.Duration) { time.Sleep(d) } +func (n *NoBackoff) SleepWithContext(ctx context.Context, d time.Duration) { + if d == 0 { + return + } + t := time.NewTimer(d) + defer t.Stop() + select { + case <-ctx.Done(): + case <-t.C: + } +} + // Disable makes the backoff trivial, i.e., sets it to zero. This might be used // by tests which want to run 1000s of mock requests without slowing down. func (b *URLBackoff) Disable() { - klog.V(4).Infof("Disabling backoff strategy") b.Backoff = flowcontrol.NewBackOff(0*time.Second, 0*time.Second) } @@ -76,32 +109,74 @@ func (b *URLBackoff) baseUrlKey(rawurl *url.URL) string { // in the future. host, err := url.Parse(rawurl.String()) if err != nil { - klog.V(4).Infof("Error extracting url: %v", rawurl) - panic("bad url!") + panic(fmt.Sprintf("Error parsing bad URL %q: %v", rawurl, err)) } return host.Host } // UpdateBackoff updates backoff metadata -func (b *URLBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) { +func (b *URLBackoff) UpdateBackoff(actualURL *url.URL, err error, responseCode int) { + b.UpdateBackoffWithContext(context.Background(), actualURL, err, responseCode) +} + +// UpdateBackoffWithContext updates backoff metadata +func (b *URLBackoff) UpdateBackoffWithContext(ctx context.Context, actualURL *url.URL, err error, responseCode int) { // range for retry counts that we store is [0,13] if responseCode > maxResponseCode || serverIsOverloadedSet.Has(responseCode) { - b.Backoff.Next(b.baseUrlKey(actualUrl), b.Backoff.Clock.Now()) + b.Backoff.Next(b.baseUrlKey(actualURL), b.Backoff.Clock.Now()) return } else if responseCode >= 300 || err != nil { - klog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err) + klog.FromContext(ctx).V(4).Info("Client is returning errors", "code", responseCode, "err", err) } //If we got this far, there is no backoff required for this URL anymore. - b.Backoff.Reset(b.baseUrlKey(actualUrl)) + b.Backoff.Reset(b.baseUrlKey(actualURL)) } // CalculateBackoff takes a url and back's off exponentially, // based on its knowledge of existing failures. -func (b *URLBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration { - return b.Backoff.Get(b.baseUrlKey(actualUrl)) +func (b *URLBackoff) CalculateBackoff(actualURL *url.URL) time.Duration { + return b.Backoff.Get(b.baseUrlKey(actualURL)) +} + +// CalculateBackoffWithContext takes a url and back's off exponentially, +// based on its knowledge of existing failures. +func (b *URLBackoff) CalculateBackoffWithContext(ctx context.Context, actualURL *url.URL) time.Duration { + return b.Backoff.Get(b.baseUrlKey(actualURL)) } func (b *URLBackoff) Sleep(d time.Duration) { b.Backoff.Clock.Sleep(d) } + +func (b *URLBackoff) SleepWithContext(ctx context.Context, d time.Duration) { + if d == 0 { + return + } + t := b.Backoff.Clock.NewTimer(d) + defer t.Stop() + select { + case <-ctx.Done(): + case <-t.C(): + } +} + +// backoffManagerNopContext wraps a BackoffManager and adds the *WithContext methods. +type backoffManagerNopContext struct { + BackoffManager +} + +var _ BackoffManager = &backoffManagerNopContext{} +var _ BackoffManagerWithContext = &backoffManagerNopContext{} + +func (b *backoffManagerNopContext) UpdateBackoffWithContext(ctx context.Context, actualURL *url.URL, err error, responseCode int) { + b.UpdateBackoff(actualURL, err, responseCode) +} + +func (b *backoffManagerNopContext) CalculateBackoffWithContext(ctx context.Context, actualURL *url.URL) time.Duration { + return b.CalculateBackoff(actualURL) +} + +func (b *backoffManagerNopContext) SleepWithContext(ctx context.Context, d time.Duration) { + b.Sleep(d) +} diff --git a/vendor/k8s.io/client-go/rest/warnings.go b/vendor/k8s.io/client-go/rest/warnings.go index ad49365..713b2d6 100644 --- a/vendor/k8s.io/client-go/rest/warnings.go +++ b/vendor/k8s.io/client-go/rest/warnings.go @@ -17,6 +17,7 @@ limitations under the License. package rest import ( + "context" "fmt" "io" "net/http" @@ -33,8 +34,15 @@ type WarningHandler interface { HandleWarningHeader(code int, agent string, text string) } +// WarningHandlerWithContext is an interface for handling warning headers with +// support for contextual logging. +type WarningHandlerWithContext interface { + // HandleWarningHeaderWithContext is called with the warn code, agent, and text when a warning header is countered. + HandleWarningHeaderWithContext(ctx context.Context, code int, agent string, text string) +} + var ( - defaultWarningHandler WarningHandler = WarningLogger{} + defaultWarningHandler WarningHandlerWithContext = WarningLogger{} defaultWarningHandlerLock sync.RWMutex ) @@ -43,33 +51,68 @@ var ( // - NoWarnings suppresses warnings. // - WarningLogger logs warnings. // - NewWarningWriter() outputs warnings to the provided writer. +// +// logcheck:context // SetDefaultWarningHandlerWithContext should be used instead of SetDefaultWarningHandler in code which supports contextual logging. func SetDefaultWarningHandler(l WarningHandler) { + if l == nil { + SetDefaultWarningHandlerWithContext(nil) + return + } + SetDefaultWarningHandlerWithContext(warningLoggerNopContext{l: l}) +} + +// SetDefaultWarningHandlerWithContext is a variant of [SetDefaultWarningHandler] which supports contextual logging. +func SetDefaultWarningHandlerWithContext(l WarningHandlerWithContext) { defaultWarningHandlerLock.Lock() defer defaultWarningHandlerLock.Unlock() defaultWarningHandler = l } -func getDefaultWarningHandler() WarningHandler { + +func getDefaultWarningHandler() WarningHandlerWithContext { defaultWarningHandlerLock.RLock() defer defaultWarningHandlerLock.RUnlock() l := defaultWarningHandler return l } -// NoWarnings is an implementation of WarningHandler that suppresses warnings. +type warningLoggerNopContext struct { + l WarningHandler +} + +func (w warningLoggerNopContext) HandleWarningHeaderWithContext(_ context.Context, code int, agent string, message string) { + w.l.HandleWarningHeader(code, agent, message) +} + +// NoWarnings is an implementation of [WarningHandler] and [WarningHandlerWithContext] that suppresses warnings. type NoWarnings struct{} func (NoWarnings) HandleWarningHeader(code int, agent string, message string) {} +func (NoWarnings) HandleWarningHeaderWithContext(ctx context.Context, code int, agent string, message string) { +} + +var _ WarningHandler = NoWarnings{} +var _ WarningHandlerWithContext = NoWarnings{} -// WarningLogger is an implementation of WarningHandler that logs code 299 warnings +// WarningLogger is an implementation of [WarningHandler] and [WarningHandlerWithContext] that logs code 299 warnings type WarningLogger struct{} func (WarningLogger) HandleWarningHeader(code int, agent string, message string) { if code != 299 || len(message) == 0 { return } - klog.Warning(message) + klog.Background().Info("Warning: " + message) } +func (WarningLogger) HandleWarningHeaderWithContext(ctx context.Context, code int, agent string, message string) { + if code != 299 || len(message) == 0 { + return + } + klog.FromContext(ctx).Info("Warning: " + message) +} + +var _ WarningHandler = WarningLogger{} +var _ WarningHandlerWithContext = WarningLogger{} + type warningWriter struct { // out is the writer to output warnings to out io.Writer @@ -134,14 +177,14 @@ func (w *warningWriter) WarningCount() int { return w.writtenCount } -func handleWarnings(headers http.Header, handler WarningHandler) []net.WarningHeader { +func handleWarnings(ctx context.Context, headers http.Header, handler WarningHandlerWithContext) []net.WarningHeader { if handler == nil { handler = getDefaultWarningHandler() } warnings, _ := net.ParseWarningHeaders(headers["Warning"]) for _, warning := range warnings { - handler.HandleWarningHeader(warning.Code, warning.Agent, warning.Text) + handler.HandleWarningHeaderWithContext(ctx, warning.Code, warning.Agent, warning.Text) } return warnings } diff --git a/vendor/k8s.io/client-go/rest/with_retry.go b/vendor/k8s.io/client-go/rest/with_retry.go index eaaadc6..e211c39 100644 --- a/vendor/k8s.io/client-go/rest/with_retry.go +++ b/vendor/k8s.io/client-go/rest/with_retry.go @@ -209,18 +209,18 @@ func (r *withRetry) Before(ctx context.Context, request *Request) error { // we do a backoff sleep before the first attempt is made, // (preserving current behavior). if request.backoff != nil { - request.backoff.Sleep(request.backoff.CalculateBackoff(url)) + request.backoff.SleepWithContext(ctx, request.backoff.CalculateBackoffWithContext(ctx, url)) } return nil } // if we are here, we have made attempt(s) at least once before. if request.backoff != nil { - delay := request.backoff.CalculateBackoff(url) + delay := request.backoff.CalculateBackoffWithContext(ctx, url) if r.retryAfter.Wait > delay { delay = r.retryAfter.Wait } - request.backoff.Sleep(delay) + request.backoff.SleepWithContext(ctx, delay) } // We are retrying the request that we already send to @@ -231,7 +231,7 @@ func (r *withRetry) Before(ctx context.Context, request *Request) error { return err } - klog.V(4).Infof("Got a Retry-After %s response for attempt %d to %v", r.retryAfter.Wait, r.retryAfter.Attempt, request.URL().String()) + klog.FromContext(ctx).V(4).Info("Got a Retry-After response", "delay", r.retryAfter.Wait, "attempt", r.retryAfter.Attempt, "url", request.URL()) return nil } @@ -258,9 +258,9 @@ func (r *withRetry) After(ctx context.Context, request *Request, resp *http.Resp if request.c.base != nil { if err != nil { - request.backoff.UpdateBackoff(request.URL(), err, 0) + request.backoff.UpdateBackoffWithContext(ctx, request.URL(), err, 0) } else { - request.backoff.UpdateBackoff(request.URL(), err, resp.StatusCode) + request.backoff.UpdateBackoffWithContext(ctx, request.URL(), err, resp.StatusCode) } } } diff --git a/vendor/k8s.io/client-go/tools/clientcmd/api/doc.go b/vendor/k8s.io/client-go/tools/clientcmd/api/doc.go index fd913a3..5871575 100644 --- a/vendor/k8s.io/client-go/tools/clientcmd/api/doc.go +++ b/vendor/k8s.io/client-go/tools/clientcmd/api/doc.go @@ -16,4 +16,4 @@ limitations under the License. // +k8s:deepcopy-gen=package -package api // import "k8s.io/client-go/tools/clientcmd/api" +package api diff --git a/vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go b/vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go index 9e483e9..3ccdebc 100644 --- a/vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go +++ b/vendor/k8s.io/client-go/tools/clientcmd/api/v1/doc.go @@ -18,4 +18,4 @@ limitations under the License. // +k8s:deepcopy-gen=package // +k8s:defaulter-gen=Kind -package v1 // import "k8s.io/client-go/tools/clientcmd/api/v1" +package v1 diff --git a/vendor/k8s.io/client-go/tools/clientcmd/doc.go b/vendor/k8s.io/client-go/tools/clientcmd/doc.go index 424311e..c07ace6 100644 --- a/vendor/k8s.io/client-go/tools/clientcmd/doc.go +++ b/vendor/k8s.io/client-go/tools/clientcmd/doc.go @@ -34,4 +34,4 @@ Sample usage from merged .kubeconfig files (local directory, home directory) client, err := metav1.New(config) // ... */ -package clientcmd // import "k8s.io/client-go/tools/clientcmd" +package clientcmd diff --git a/vendor/k8s.io/client-go/transport/cache.go b/vendor/k8s.io/client-go/transport/cache.go index 7c7f1b3..b8dd866 100644 --- a/vendor/k8s.io/client-go/transport/cache.go +++ b/vendor/k8s.io/client-go/transport/cache.go @@ -28,6 +28,7 @@ import ( utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/metrics" + "k8s.io/klog/v2" ) // TlsTransportCache caches TLS http.RoundTrippers different configurations. The @@ -116,10 +117,13 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { // If we use are reloading files, we need to handle certificate rotation properly // TODO(jackkleeman): We can also add rotation here when config.HasCertCallback() is true if config.TLS.ReloadTLSFiles && tlsConfig != nil && tlsConfig.GetClientCertificate != nil { - dynamicCertDialer := certRotatingDialer(tlsConfig.GetClientCertificate, dial) + // The TLS cache is a singleton, so sharing the same name for all of its + // background activity seems okay. + logger := klog.Background().WithName("tls-transport-cache") + dynamicCertDialer := certRotatingDialer(logger, tlsConfig.GetClientCertificate, dial) tlsConfig.GetClientCertificate = dynamicCertDialer.GetClientCertificate dial = dynamicCertDialer.connDialer.DialContext - go dynamicCertDialer.Run(DialerStopCh) + go dynamicCertDialer.run(DialerStopCh) } proxy := http.ProxyFromEnvironment diff --git a/vendor/k8s.io/client-go/transport/cert_rotation.go b/vendor/k8s.io/client-go/transport/cert_rotation.go index e76f658..e343f42 100644 --- a/vendor/k8s.io/client-go/transport/cert_rotation.go +++ b/vendor/k8s.io/client-go/transport/cert_rotation.go @@ -19,7 +19,6 @@ package transport import ( "bytes" "crypto/tls" - "fmt" "reflect" "sync" "time" @@ -40,6 +39,7 @@ var CertCallbackRefreshDuration = 5 * time.Minute type reloadFunc func(*tls.CertificateRequestInfo) (*tls.Certificate, error) type dynamicClientCert struct { + logger klog.Logger clientCert *tls.Certificate certMtx sync.RWMutex @@ -50,8 +50,9 @@ type dynamicClientCert struct { queue workqueue.TypedRateLimitingInterface[string] } -func certRotatingDialer(reload reloadFunc, dial utilnet.DialFunc) *dynamicClientCert { +func certRotatingDialer(logger klog.Logger, reload reloadFunc, dial utilnet.DialFunc) *dynamicClientCert { d := &dynamicClientCert{ + logger: logger, reload: reload, connDialer: connrotation.NewDialer(connrotation.DialFunc(dial)), queue: workqueue.NewTypedRateLimitingQueueWithConfig( @@ -88,7 +89,7 @@ func (c *dynamicClientCert) loadClientCert() (*tls.Certificate, error) { return cert, nil } - klog.V(1).Infof("certificate rotation detected, shutting down client connections to start using new credentials") + c.logger.V(1).Info("Certificate rotation detected, shutting down client connections to start using new credentials") c.connDialer.CloseAll() return cert, nil @@ -133,12 +134,12 @@ func byteMatrixEqual(left, right [][]byte) bool { } // run starts the controller and blocks until stopCh is closed. -func (c *dynamicClientCert) Run(stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() +func (c *dynamicClientCert) run(stopCh <-chan struct{}) { + defer utilruntime.HandleCrashWithLogger(c.logger) defer c.queue.ShutDown() - klog.V(3).Infof("Starting client certificate rotation controller") - defer klog.V(3).Infof("Shutting down client certificate rotation controller") + c.logger.V(3).Info("Starting client certificate rotation controller") + defer c.logger.V(3).Info("Shutting down client certificate rotation controller") go wait.Until(c.runWorker, time.Second, stopCh) @@ -168,7 +169,7 @@ func (c *dynamicClientCert) processNextWorkItem() bool { return true } - utilruntime.HandleError(fmt.Errorf("%v failed with : %v", dsKey, err)) + utilruntime.HandleErrorWithLogger(c.logger, err, "Loading client cert failed", "key", dsKey) c.queue.AddRateLimited(dsKey) return true diff --git a/vendor/k8s.io/client-go/transport/round_trippers.go b/vendor/k8s.io/client-go/transport/round_trippers.go index 52fefb5..39fcebd 100644 --- a/vendor/k8s.io/client-go/transport/round_trippers.go +++ b/vendor/k8s.io/client-go/transport/round_trippers.go @@ -21,10 +21,12 @@ import ( "fmt" "net/http" "net/http/httptrace" + "sort" "strings" "sync" "time" + "github.com/go-logr/logr" "golang.org/x/oauth2" utilnet "k8s.io/apimachinery/pkg/util/net" @@ -68,19 +70,16 @@ func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTrip return rt, nil } -// DebugWrappers wraps a round tripper and logs based on the current log level. +// DebugWrappers potentially wraps a round tripper with a wrapper that logs +// based on the log level in the context of each individual request. +// +// At the moment, wrapping depends on the global log verbosity and is done +// if that verbosity is >= 6. This may change in the future. func DebugWrappers(rt http.RoundTripper) http.RoundTripper { - switch { - case bool(klog.V(9).Enabled()): - rt = NewDebuggingRoundTripper(rt, DebugCurlCommand, DebugURLTiming, DebugDetailedTiming, DebugResponseHeaders) - case bool(klog.V(8).Enabled()): - rt = NewDebuggingRoundTripper(rt, DebugJustURL, DebugRequestHeaders, DebugResponseStatus, DebugResponseHeaders) - case bool(klog.V(7).Enabled()): - rt = NewDebuggingRoundTripper(rt, DebugJustURL, DebugRequestHeaders, DebugResponseStatus) - case bool(klog.V(6).Enabled()): - rt = NewDebuggingRoundTripper(rt, DebugURLTiming) + //nolint:logcheck // The actual logging is done with a different logger, so only checking here is okay. + if klog.V(6).Enabled() { + rt = NewDebuggingRoundTripper(rt, DebugByContext) } - return rt } @@ -380,14 +379,17 @@ func (r *requestInfo) toCurl() string { } } - return fmt.Sprintf("curl -v -X%s %s '%s'", r.RequestVerb, headers, r.RequestURL) + // Newline at the end makes this look better in the text log output (the + // only usage of this method) because it becomes a multi-line string with + // no quoting. + return fmt.Sprintf("curl -v -X%s %s '%s'\n", r.RequestVerb, headers, r.RequestURL) } // debuggingRoundTripper will display information about the requests passing // through it based on what is configured type debuggingRoundTripper struct { delegatedRoundTripper http.RoundTripper - levels map[DebugLevel]bool + levels int } var _ utilnet.RoundTripperWrapper = &debuggingRoundTripper{} @@ -412,6 +414,26 @@ const ( DebugResponseHeaders // DebugDetailedTiming will add to the debug output the duration of the HTTP requests events. DebugDetailedTiming + // DebugByContext will add any of the above depending on the verbosity of the per-request logger obtained from the requests context. + // + // Can be combined in NewDebuggingRoundTripper with some of the other options, in which case the + // debug roundtripper will always log what is requested there plus the information that gets + // enabled by the context's log verbosity. + DebugByContext +) + +// Different log levels include different sets of information. +// +// Not exported because the exact content of log messages is not part +// of of the package API. +const ( + levelsV6 = (1 << DebugURLTiming) + // Logging *less* information for the response at level 7 compared to 6 replicates prior behavior: + // https://github.com/kubernetes/kubernetes/blob/2b472fe4690c83a2b343995f88050b2a3e9ff0fa/staging/src/k8s.io/client-go/transport/round_trippers.go#L79 + // Presumably that was done because verb and URL are already in the request log entry. + levelsV7 = (1 << DebugJustURL) | (1 << DebugRequestHeaders) | (1 << DebugResponseStatus) + levelsV8 = (1 << DebugJustURL) | (1 << DebugRequestHeaders) | (1 << DebugResponseStatus) | (1 << DebugResponseHeaders) + levelsV9 = (1 << DebugCurlCommand) | (1 << DebugURLTiming) | (1 << DebugDetailedTiming) | (1 << DebugResponseHeaders) ) // NewDebuggingRoundTripper allows to display in the logs output debug information @@ -419,10 +441,9 @@ const ( func NewDebuggingRoundTripper(rt http.RoundTripper, levels ...DebugLevel) http.RoundTripper { drt := &debuggingRoundTripper{ delegatedRoundTripper: rt, - levels: make(map[DebugLevel]bool, len(levels)), } for _, v := range levels { - drt.levels[v] = true + drt.levels |= 1 << v } return drt } @@ -464,27 +485,51 @@ func maskValue(key string, value string) string { } func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + logger := klog.FromContext(req.Context()) + levels := rt.levels + + // When logging depends on the context, it uses the verbosity of the per-context logger + // and a hard-coded mapping of verbosity to debug details. Otherwise all messages + // are logged as V(0). + if levels&(1< 0 { + logger.Info("Request", kvs...) } startTime := time.Now() - if rt.levels[DebugDetailedTiming] { + if levels&(1< 0 { + logger.Info("Response", kvs...) + } + + return response, err +} - if rt.levels[DebugResponseStatus] { - klog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond)) +// headerMap formats headers sorted and across multiple lines with no quoting +// when using string output and as JSON when using zapr. +type headersMap http.Header + +// newHeadersMap masks all sensitive values. This has to be done before +// passing the map to a logger because while in practice all loggers +// either use String or MarshalLog, that is not guaranteed. +func newHeadersMap(header http.Header) headersMap { + h := make(headersMap, len(header)) + for key, values := range header { + maskedValues := make([]string, 0, len(values)) + for _, value := range values { + maskedValues = append(maskedValues, maskValue(key, value)) + } + h[key] = maskedValues } - if rt.levels[DebugResponseHeaders] { - klog.Info("Response Headers:") - for key, values := range reqInfo.ResponseHeaders { - for _, value := range values { - klog.Infof(" %s: %s", key, value) - } + return h +} + +var _ fmt.Stringer = headersMap{} +var _ logr.Marshaler = headersMap{} + +func (h headersMap) String() string { + // The fixed size typically avoids memory allocations when it is large enough. + keys := make([]string, 0, 20) + for key := range h { + keys = append(keys, key) + } + sort.Strings(keys) + var buffer strings.Builder + for _, key := range keys { + for _, value := range h[key] { + _, _ = buffer.WriteString(key) + _, _ = buffer.WriteString(": ") + _, _ = buffer.WriteString(value) + _, _ = buffer.WriteString("\n") } } + return buffer.String() +} - return response, err +func (h headersMap) MarshalLog() any { + return map[string][]string(h) } func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper { diff --git a/vendor/k8s.io/client-go/transport/token_source.go b/vendor/k8s.io/client-go/transport/token_source.go index 8e31280..469dd81 100644 --- a/vendor/k8s.io/client-go/transport/token_source.go +++ b/vendor/k8s.io/client-go/transport/token_source.go @@ -182,7 +182,10 @@ func (ts *cachingTokenSource) Token() (*oauth2.Token, error) { if ts.tok == nil { return nil, err } - klog.Errorf("Unable to rotate token: %v", err) + // Not using a caller-provided logger isn't ideal, but impossible to fix + // without new APIs that go up all the way to HTTPWrappersForConfig. + // This is currently deemed not worth changing (too much effort, not enough benefit). + klog.TODO().Error(err, "Unable to rotate token") return ts.tok, nil } diff --git a/vendor/k8s.io/client-go/transport/transport.go b/vendor/k8s.io/client-go/transport/transport.go index 4770331..8fdcc57 100644 --- a/vendor/k8s.io/client-go/transport/transport.go +++ b/vendor/k8s.io/client-go/transport/transport.go @@ -353,7 +353,7 @@ func tryCancelRequest(rt http.RoundTripper, req *http.Request) { case utilnet.RoundTripperWrapper: tryCancelRequest(rt.WrappedRoundTripper(), req) default: - klog.Warningf("Unable to cancel request for %T", rt) + klog.FromContext(req.Context()).Info("Warning: unable to cancel request", "roundTripperType", fmt.Sprintf("%T", rt)) } } diff --git a/vendor/k8s.io/client-go/util/cert/cert.go b/vendor/k8s.io/client-go/util/cert/cert.go index 91e1712..1220461 100644 --- a/vendor/k8s.io/client-go/util/cert/cert.go +++ b/vendor/k8s.io/client-go/util/cert/cert.go @@ -90,11 +90,37 @@ func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, erro return x509.ParseCertificate(certDERBytes) } +// SelfSignedCertKeyOptions contains configuration parameters for generating self-signed certificates. +type SelfSignedCertKeyOptions struct { + // Host is required, and identifies the host of the serving certificate. Can be a DNS name or IP address. + Host string + // AlternateIPs is optional, and identifies additional IPs the serving certificate should be valid for. + AlternateIPs []net.IP + // AlternateDNS is optional, and identifies additional DNS names the serving certificate should be valid for. + AlternateDNS []string + + // MaxAge controls the duration of the issued certificate. + // Defaults to 1 year if unset. + // Ignored if FixtureDirectory is set. + MaxAge time.Duration + + // FixtureDirectory is intended for use in tests. + // If non-empty, it is a directory path which can contain pre-generated certs. The format is: + // _-_-.crt + // _-_-.key + // Certs/keys not existing in that directory are created with a duration of 100 years. + FixtureDirectory string +} + // GenerateSelfSignedCertKey creates a self-signed certificate and key for the given host. // Host may be an IP or a DNS name // You may also specify additional subject alt names (either ip or dns names) for the certificate. func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS []string) ([]byte, []byte, error) { - return GenerateSelfSignedCertKeyWithFixtures(host, alternateIPs, alternateDNS, "") + return GenerateSelfSignedCertKeyWithOptions(SelfSignedCertKeyOptions{ + Host: host, + AlternateIPs: alternateIPs, + AlternateDNS: alternateDNS, + }) } // GenerateSelfSignedCertKeyWithFixtures creates a self-signed certificate and key for the given host. @@ -106,8 +132,26 @@ func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS // _-_-.key // Certs/keys not existing in that directory are created. func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, alternateDNS []string, fixtureDirectory string) ([]byte, []byte, error) { + return GenerateSelfSignedCertKeyWithOptions(SelfSignedCertKeyOptions{ + Host: host, + AlternateIPs: alternateIPs, + AlternateDNS: alternateDNS, + FixtureDirectory: fixtureDirectory, + }) +} + +// GenerateSelfSignedCertKeyWithOptions generates a self-signed certificate and key based on the provided options. +func GenerateSelfSignedCertKeyWithOptions(opts SelfSignedCertKeyOptions) ([]byte, []byte, error) { + host := opts.Host + alternateIPs := opts.AlternateIPs + alternateDNS := opts.AlternateDNS + fixtureDirectory := opts.FixtureDirectory + maxAge := opts.MaxAge + if maxAge == 0 { + maxAge = 365 * 24 * time.Hour + } + validFrom := time.Now().Add(-time.Hour) // valid an hour earlier to avoid flakes due to clock skew - maxAge := time.Hour * 24 * 365 // one year self-signed certs baseName := fmt.Sprintf("%s_%s_%s", host, strings.Join(ipsToStrings(alternateIPs), "-"), strings.Join(alternateDNS, "-")) certFixturePath := filepath.Join(fixtureDirectory, baseName+".crt") diff --git a/vendor/k8s.io/client-go/util/flowcontrol/backoff.go b/vendor/k8s.io/client-go/util/flowcontrol/backoff.go index 899b8e3..7cb4671 100644 --- a/vendor/k8s.io/client-go/util/flowcontrol/backoff.go +++ b/vendor/k8s.io/client-go/util/flowcontrol/backoff.go @@ -22,7 +22,6 @@ import ( "time" "k8s.io/utils/clock" - testingclock "k8s.io/utils/clock/testing" ) type backoffEntry struct { @@ -49,7 +48,7 @@ type Backoff struct { maxJitterFactor float64 } -func NewFakeBackOff(initial, max time.Duration, tc *testingclock.FakeClock) *Backoff { +func NewFakeBackOff(initial, max time.Duration, tc clock.Clock) *Backoff { return newBackoff(tc, initial, max, 0.0) } @@ -57,7 +56,7 @@ func NewBackOff(initial, max time.Duration) *Backoff { return NewBackOffWithJitter(initial, max, 0.0) } -func NewFakeBackOffWithJitter(initial, max time.Duration, tc *testingclock.FakeClock, maxJitterFactor float64) *Backoff { +func NewFakeBackOffWithJitter(initial, max time.Duration, tc clock.Clock, maxJitterFactor float64) *Backoff { return newBackoff(tc, initial, max, maxJitterFactor) } diff --git a/vendor/k8s.io/client-go/util/workqueue/delaying_queue.go b/vendor/k8s.io/client-go/util/workqueue/delaying_queue.go index e33a6c6..da444f4 100644 --- a/vendor/k8s.io/client-go/util/workqueue/delaying_queue.go +++ b/vendor/k8s.io/client-go/util/workqueue/delaying_queue.go @@ -22,6 +22,7 @@ import ( "time" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/klog/v2" "k8s.io/utils/clock" ) @@ -46,6 +47,10 @@ type DelayingQueueConfig = TypedDelayingQueueConfig[any] // TypedDelayingQueueConfig specifies optional configurations to customize a DelayingInterface. type TypedDelayingQueueConfig[T comparable] struct { + // An optional logger. The name of the queue does *not* get added to it, this should + // be done by the caller if desired. + Logger *klog.Logger + // Name for the queue. If unnamed, the metrics will not be registered. Name string @@ -94,6 +99,10 @@ func TypedNewDelayingQueue[T comparable]() TypedDelayingInterface[T] { // NewTypedDelayingQueueWithConfig constructs a new workqueue with options to // customize different properties. func NewTypedDelayingQueueWithConfig[T comparable](config TypedDelayingQueueConfig[T]) TypedDelayingInterface[T] { + logger := klog.Background() + if config.Logger != nil { + logger = *config.Logger + } if config.Clock == nil { config.Clock = clock.RealClock{} } @@ -106,7 +115,7 @@ func NewTypedDelayingQueueWithConfig[T comparable](config TypedDelayingQueueConf }) } - return newDelayingQueue(config.Clock, config.Queue, config.Name, config.MetricsProvider) + return newDelayingQueue(logger, config.Clock, config.Queue, config.Name, config.MetricsProvider) } // NewDelayingQueueWithCustomQueue constructs a new workqueue with ability to @@ -135,7 +144,7 @@ func NewDelayingQueueWithCustomClock(clock clock.WithTicker, name string) Delayi }) } -func newDelayingQueue[T comparable](clock clock.WithTicker, q TypedInterface[T], name string, provider MetricsProvider) *delayingType[T] { +func newDelayingQueue[T comparable](logger klog.Logger, clock clock.WithTicker, q TypedInterface[T], name string, provider MetricsProvider) *delayingType[T] { ret := &delayingType[T]{ TypedInterface: q, clock: clock, @@ -145,7 +154,7 @@ func newDelayingQueue[T comparable](clock clock.WithTicker, q TypedInterface[T], metrics: newRetryMetrics(name, provider), } - go ret.waitingLoop() + go ret.waitingLoop(logger) return ret } @@ -264,8 +273,8 @@ func (q *delayingType[T]) AddAfter(item T, duration time.Duration) { const maxWait = 10 * time.Second // waitingLoop runs until the workqueue is shutdown and keeps a check on the list of items to be added. -func (q *delayingType[T]) waitingLoop() { - defer utilruntime.HandleCrash() +func (q *delayingType[T]) waitingLoop(logger klog.Logger) { + defer utilruntime.HandleCrashWithLogger(logger) // Make a placeholder channel to use when there are no items in our list never := make(<-chan time.Time) diff --git a/vendor/k8s.io/client-go/util/workqueue/doc.go b/vendor/k8s.io/client-go/util/workqueue/doc.go index 8555aa9..a76d830 100644 --- a/vendor/k8s.io/client-go/util/workqueue/doc.go +++ b/vendor/k8s.io/client-go/util/workqueue/doc.go @@ -23,4 +23,4 @@ limitations under the License. // - Multiple consumers and producers. In particular, it is allowed for an // item to be reenqueued while it is being processed. // - Shutdown notifications. -package workqueue // import "k8s.io/client-go/util/workqueue" +package workqueue diff --git a/vendor/k8s.io/client-go/util/workqueue/parallelizer.go b/vendor/k8s.io/client-go/util/workqueue/parallelizer.go index 366bf20..9f986a2 100644 --- a/vendor/k8s.io/client-go/util/workqueue/parallelizer.go +++ b/vendor/k8s.io/client-go/util/workqueue/parallelizer.go @@ -74,7 +74,7 @@ func ParallelizeUntil(ctx context.Context, workers, pieces int, doWorkPiece DoWo wg.Add(workers) for i := 0; i < workers; i++ { go func() { - defer utilruntime.HandleCrash() + defer utilruntime.HandleCrashWithContext(ctx) defer wg.Done() for chunk := range toProcess { start := chunk * chunkSize diff --git a/vendor/k8s.io/utils/clock/testing/fake_clock.go b/vendor/k8s.io/utils/clock/testing/fake_clock.go deleted file mode 100644 index 462c40c..0000000 --- a/vendor/k8s.io/utils/clock/testing/fake_clock.go +++ /dev/null @@ -1,362 +0,0 @@ -/* -Copyright 2014 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 testing - -import ( - "sync" - "time" - - "k8s.io/utils/clock" -) - -var ( - _ = clock.PassiveClock(&FakePassiveClock{}) - _ = clock.WithTicker(&FakeClock{}) - _ = clock.Clock(&IntervalClock{}) -) - -// FakePassiveClock implements PassiveClock, but returns an arbitrary time. -type FakePassiveClock struct { - lock sync.RWMutex - time time.Time -} - -// FakeClock implements clock.Clock, but returns an arbitrary time. -type FakeClock struct { - FakePassiveClock - - // waiters are waiting for the fake time to pass their specified time - waiters []*fakeClockWaiter -} - -type fakeClockWaiter struct { - targetTime time.Time - stepInterval time.Duration - skipIfBlocked bool - destChan chan time.Time - afterFunc func() -} - -// NewFakePassiveClock returns a new FakePassiveClock. -func NewFakePassiveClock(t time.Time) *FakePassiveClock { - return &FakePassiveClock{ - time: t, - } -} - -// NewFakeClock constructs a fake clock set to the provided time. -func NewFakeClock(t time.Time) *FakeClock { - return &FakeClock{ - FakePassiveClock: *NewFakePassiveClock(t), - } -} - -// Now returns f's time. -func (f *FakePassiveClock) Now() time.Time { - f.lock.RLock() - defer f.lock.RUnlock() - return f.time -} - -// Since returns time since the time in f. -func (f *FakePassiveClock) Since(ts time.Time) time.Duration { - f.lock.RLock() - defer f.lock.RUnlock() - return f.time.Sub(ts) -} - -// SetTime sets the time on the FakePassiveClock. -func (f *FakePassiveClock) SetTime(t time.Time) { - f.lock.Lock() - defer f.lock.Unlock() - f.time = t -} - -// After is the fake version of time.After(d). -func (f *FakeClock) After(d time.Duration) <-chan time.Time { - f.lock.Lock() - defer f.lock.Unlock() - stopTime := f.time.Add(d) - ch := make(chan time.Time, 1) // Don't block! - f.waiters = append(f.waiters, &fakeClockWaiter{ - targetTime: stopTime, - destChan: ch, - }) - return ch -} - -// NewTimer constructs a fake timer, akin to time.NewTimer(d). -func (f *FakeClock) NewTimer(d time.Duration) clock.Timer { - f.lock.Lock() - defer f.lock.Unlock() - stopTime := f.time.Add(d) - ch := make(chan time.Time, 1) // Don't block! - timer := &fakeTimer{ - fakeClock: f, - waiter: fakeClockWaiter{ - targetTime: stopTime, - destChan: ch, - }, - } - f.waiters = append(f.waiters, &timer.waiter) - return timer -} - -// AfterFunc is the Fake version of time.AfterFunc(d, cb). -func (f *FakeClock) AfterFunc(d time.Duration, cb func()) clock.Timer { - f.lock.Lock() - defer f.lock.Unlock() - stopTime := f.time.Add(d) - ch := make(chan time.Time, 1) // Don't block! - - timer := &fakeTimer{ - fakeClock: f, - waiter: fakeClockWaiter{ - targetTime: stopTime, - destChan: ch, - afterFunc: cb, - }, - } - f.waiters = append(f.waiters, &timer.waiter) - return timer -} - -// Tick constructs a fake ticker, akin to time.Tick -func (f *FakeClock) Tick(d time.Duration) <-chan time.Time { - if d <= 0 { - return nil - } - f.lock.Lock() - defer f.lock.Unlock() - tickTime := f.time.Add(d) - ch := make(chan time.Time, 1) // hold one tick - f.waiters = append(f.waiters, &fakeClockWaiter{ - targetTime: tickTime, - stepInterval: d, - skipIfBlocked: true, - destChan: ch, - }) - - return ch -} - -// NewTicker returns a new Ticker. -func (f *FakeClock) NewTicker(d time.Duration) clock.Ticker { - f.lock.Lock() - defer f.lock.Unlock() - tickTime := f.time.Add(d) - ch := make(chan time.Time, 1) // hold one tick - f.waiters = append(f.waiters, &fakeClockWaiter{ - targetTime: tickTime, - stepInterval: d, - skipIfBlocked: true, - destChan: ch, - }) - - return &fakeTicker{ - c: ch, - } -} - -// Step moves the clock by Duration and notifies anyone that's called After, -// Tick, or NewTimer. -func (f *FakeClock) Step(d time.Duration) { - f.lock.Lock() - defer f.lock.Unlock() - f.setTimeLocked(f.time.Add(d)) -} - -// SetTime sets the time. -func (f *FakeClock) SetTime(t time.Time) { - f.lock.Lock() - defer f.lock.Unlock() - f.setTimeLocked(t) -} - -// Actually changes the time and checks any waiters. f must be write-locked. -func (f *FakeClock) setTimeLocked(t time.Time) { - f.time = t - newWaiters := make([]*fakeClockWaiter, 0, len(f.waiters)) - for i := range f.waiters { - w := f.waiters[i] - if !w.targetTime.After(t) { - if w.skipIfBlocked { - select { - case w.destChan <- t: - default: - } - } else { - w.destChan <- t - } - - if w.afterFunc != nil { - w.afterFunc() - } - - if w.stepInterval > 0 { - for !w.targetTime.After(t) { - w.targetTime = w.targetTime.Add(w.stepInterval) - } - newWaiters = append(newWaiters, w) - } - - } else { - newWaiters = append(newWaiters, f.waiters[i]) - } - } - f.waiters = newWaiters -} - -// HasWaiters returns true if After or AfterFunc has been called on f but not yet satisfied (so you can -// write race-free tests). -func (f *FakeClock) HasWaiters() bool { - f.lock.RLock() - defer f.lock.RUnlock() - return len(f.waiters) > 0 -} - -// Sleep is akin to time.Sleep -func (f *FakeClock) Sleep(d time.Duration) { - f.Step(d) -} - -// IntervalClock implements clock.PassiveClock, but each invocation of Now steps the clock forward the specified duration. -// IntervalClock technically implements the other methods of clock.Clock, but each implementation is just a panic. -// -// Deprecated: See SimpleIntervalClock for an alternative that only has the methods of PassiveClock. -type IntervalClock struct { - Time time.Time - Duration time.Duration -} - -// Now returns i's time. -func (i *IntervalClock) Now() time.Time { - i.Time = i.Time.Add(i.Duration) - return i.Time -} - -// Since returns time since the time in i. -func (i *IntervalClock) Since(ts time.Time) time.Duration { - return i.Time.Sub(ts) -} - -// After is unimplemented, will panic. -// TODO: make interval clock use FakeClock so this can be implemented. -func (*IntervalClock) After(d time.Duration) <-chan time.Time { - panic("IntervalClock doesn't implement After") -} - -// NewTimer is unimplemented, will panic. -// TODO: make interval clock use FakeClock so this can be implemented. -func (*IntervalClock) NewTimer(d time.Duration) clock.Timer { - panic("IntervalClock doesn't implement NewTimer") -} - -// AfterFunc is unimplemented, will panic. -// TODO: make interval clock use FakeClock so this can be implemented. -func (*IntervalClock) AfterFunc(d time.Duration, f func()) clock.Timer { - panic("IntervalClock doesn't implement AfterFunc") -} - -// Tick is unimplemented, will panic. -// TODO: make interval clock use FakeClock so this can be implemented. -func (*IntervalClock) Tick(d time.Duration) <-chan time.Time { - panic("IntervalClock doesn't implement Tick") -} - -// NewTicker has no implementation yet and is omitted. -// TODO: make interval clock use FakeClock so this can be implemented. -func (*IntervalClock) NewTicker(d time.Duration) clock.Ticker { - panic("IntervalClock doesn't implement NewTicker") -} - -// Sleep is unimplemented, will panic. -func (*IntervalClock) Sleep(d time.Duration) { - panic("IntervalClock doesn't implement Sleep") -} - -var _ = clock.Timer(&fakeTimer{}) - -// fakeTimer implements clock.Timer based on a FakeClock. -type fakeTimer struct { - fakeClock *FakeClock - waiter fakeClockWaiter -} - -// C returns the channel that notifies when this timer has fired. -func (f *fakeTimer) C() <-chan time.Time { - return f.waiter.destChan -} - -// Stop prevents the Timer from firing. It returns true if the call stops the -// timer, false if the timer has already expired or been stopped. -func (f *fakeTimer) Stop() bool { - f.fakeClock.lock.Lock() - defer f.fakeClock.lock.Unlock() - - active := false - newWaiters := make([]*fakeClockWaiter, 0, len(f.fakeClock.waiters)) - for i := range f.fakeClock.waiters { - w := f.fakeClock.waiters[i] - if w != &f.waiter { - newWaiters = append(newWaiters, w) - continue - } - // If timer is found, it has not been fired yet. - active = true - } - - f.fakeClock.waiters = newWaiters - - return active -} - -// Reset changes the timer to expire after duration d. It returns true if the -// timer had been active, false if the timer had expired or been stopped. -func (f *fakeTimer) Reset(d time.Duration) bool { - f.fakeClock.lock.Lock() - defer f.fakeClock.lock.Unlock() - - active := false - - f.waiter.targetTime = f.fakeClock.time.Add(d) - - for i := range f.fakeClock.waiters { - w := f.fakeClock.waiters[i] - if w == &f.waiter { - // If timer is found, it has not been fired yet. - active = true - break - } - } - if !active { - f.fakeClock.waiters = append(f.fakeClock.waiters, &f.waiter) - } - - return active -} - -type fakeTicker struct { - c <-chan time.Time -} - -func (t *fakeTicker) C() <-chan time.Time { - return t.c -} - -func (t *fakeTicker) Stop() { -} diff --git a/vendor/k8s.io/utils/clock/testing/simple_interval_clock.go b/vendor/k8s.io/utils/clock/testing/simple_interval_clock.go deleted file mode 100644 index 951ca4d..0000000 --- a/vendor/k8s.io/utils/clock/testing/simple_interval_clock.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2021 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 testing - -import ( - "time" - - "k8s.io/utils/clock" -) - -var ( - _ = clock.PassiveClock(&SimpleIntervalClock{}) -) - -// SimpleIntervalClock implements clock.PassiveClock, but each invocation of Now steps the clock forward the specified duration -type SimpleIntervalClock struct { - Time time.Time - Duration time.Duration -} - -// Now returns i's time. -func (i *SimpleIntervalClock) Now() time.Time { - i.Time = i.Time.Add(i.Duration) - return i.Time -} - -// Since returns time since the time in i. -func (i *SimpleIntervalClock) Since(ts time.Time) time.Duration { - return i.Time.Sub(ts) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 7e652f6..045f526 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# code.cloudfoundry.org/bytefmt v0.34.0 +# code.cloudfoundry.org/bytefmt v0.39.0 ## explicit; go 1.23.0 code.cloudfoundry.org/bytefmt # code.cloudfoundry.org/cfnetworking-cli-api v0.0.0-20190103195135-4b04f26287a6 @@ -8,8 +8,8 @@ code.cloudfoundry.org/cfnetworking-cli-api/cfnetworking/cfnetv1 code.cloudfoundry.org/cfnetworking-cli-api/cfnetworking/cfnetv1/internal code.cloudfoundry.org/cfnetworking-cli-api/cfnetworking/networkerror code.cloudfoundry.org/cfnetworking-cli-api/cfnetworking/wrapper -# code.cloudfoundry.org/cli v0.0.0-20240609151540-b78406a9b0ce -## explicit; go 1.22 +# code.cloudfoundry.org/cli v0.0.0-20250410033454-7ef8a48b9bb3 +## explicit; go 1.23.6 code.cloudfoundry.org/cli/actor/actionerror code.cloudfoundry.org/cli/actor/sharedaction code.cloudfoundry.org/cli/actor/v7action @@ -55,12 +55,13 @@ code.cloudfoundry.org/cli/util/lookuptable code.cloudfoundry.org/cli/util/manifest code.cloudfoundry.org/cli/util/railway code.cloudfoundry.org/cli/util/sorting +code.cloudfoundry.org/cli/util/trace code.cloudfoundry.org/cli/util/ui code.cloudfoundry.org/cli/util/unique code.cloudfoundry.org/cli/version # code.cloudfoundry.org/cli-plugin-repo v0.0.0-20240520170503-e7ed9c7432a0 ## explicit; go 1.12 -# code.cloudfoundry.org/clock v1.32.0 +# code.cloudfoundry.org/clock v1.37.0 ## explicit; go 1.23.0 code.cloudfoundry.org/clock # code.cloudfoundry.org/go-log-cache/v2 v2.0.7 @@ -77,7 +78,7 @@ code.cloudfoundry.org/jsonry code.cloudfoundry.org/jsonry/internal/errorcontext code.cloudfoundry.org/jsonry/internal/path code.cloudfoundry.org/jsonry/internal/tree -# code.cloudfoundry.org/tlsconfig v0.22.0 +# code.cloudfoundry.org/tlsconfig v0.26.0 ## explicit; go 1.23.0 code.cloudfoundry.org/tlsconfig # code.cloudfoundry.org/ykk v0.0.0-20170424192843-e4df4ce2fd4d @@ -132,10 +133,9 @@ github.com/go-logr/logr ## explicit; go 1.15 github.com/gogo/protobuf/proto github.com/gogo/protobuf/sortkeys -# github.com/google/gofuzz v1.2.0 -## explicit; go 1.12 -github.com/google/gofuzz -github.com/google/gofuzz/bytesource +# github.com/google/uuid v1.6.0 +## explicit +github.com/google/uuid # github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 ## explicit; go 1.23.0 github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule @@ -194,7 +194,7 @@ github.com/vito/go-interact/interact/terminal # github.com/x448/float16 v0.8.4 ## explicit; go 1.11 github.com/x448/float16 -# golang.org/x/crypto v0.36.0 +# golang.org/x/crypto v0.37.0 ## explicit; go 1.23.0 golang.org/x/crypto/blowfish golang.org/x/crypto/chacha20 @@ -204,7 +204,7 @@ golang.org/x/crypto/internal/poly1305 golang.org/x/crypto/ssh golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/terminal -# golang.org/x/net v0.38.0 +# golang.org/x/net v0.39.0 ## explicit; go 1.23.0 golang.org/x/net/http/httpguts golang.org/x/net/http2 @@ -215,20 +215,20 @@ golang.org/x/net/internal/socks golang.org/x/net/internal/timeseries golang.org/x/net/proxy golang.org/x/net/trace -# golang.org/x/oauth2 v0.28.0 +# golang.org/x/oauth2 v0.29.0 ## explicit; go 1.23.0 golang.org/x/oauth2 golang.org/x/oauth2/internal -# golang.org/x/sys v0.31.0 +# golang.org/x/sys v0.32.0 ## explicit; go 1.23.0 golang.org/x/sys/cpu golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.30.0 +# golang.org/x/term v0.31.0 ## explicit; go 1.23.0 golang.org/x/term -# golang.org/x/text v0.23.0 +# golang.org/x/text v0.24.0 ## explicit; go 1.23.0 golang.org/x/text/internal/language golang.org/x/text/internal/language/compact @@ -241,16 +241,16 @@ golang.org/x/text/unicode/norm # golang.org/x/time v0.11.0 ## explicit; go 1.23.0 golang.org/x/time/rate -# google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 +# google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 ## explicit; go 1.23.0 google.golang.org/genproto/googleapis/api google.golang.org/genproto/googleapis/api/annotations google.golang.org/genproto/googleapis/api/httpbody -# google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 +# google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 ## explicit; go 1.23.0 google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.71.0 -## explicit; go 1.22.0 +# google.golang.org/grpc v1.72.0 +## explicit; go 1.23 google.golang.org/grpc google.golang.org/grpc/attributes google.golang.org/grpc/backoff @@ -360,10 +360,11 @@ gopkg.in/inf.v0 # gopkg.in/yaml.v2 v2.4.0 ## explicit; go 1.15 gopkg.in/yaml.v2 -# k8s.io/apimachinery v0.32.3 -## explicit; go 1.23.0 +# k8s.io/apimachinery v0.33.0 +## explicit; go 1.24.0 k8s.io/apimachinery/pkg/api/errors k8s.io/apimachinery/pkg/api/meta +k8s.io/apimachinery/pkg/api/operation k8s.io/apimachinery/pkg/api/resource k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/apimachinery/pkg/apis/meta/v1/unstructured @@ -400,8 +401,8 @@ k8s.io/apimachinery/pkg/util/yaml k8s.io/apimachinery/pkg/version k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/client-go v0.32.3 -## explicit; go 1.23.0 +# k8s.io/client-go v0.33.0 +## explicit; go 1.24.0 k8s.io/client-go/features k8s.io/client-go/pkg/apis/clientauthentication k8s.io/client-go/pkg/apis/clientauthentication/install @@ -436,10 +437,9 @@ k8s.io/klog/v2/internal/dbg k8s.io/klog/v2/internal/serialize k8s.io/klog/v2/internal/severity k8s.io/klog/v2/internal/sloghandler -# k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e +# k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 ## explicit; go 1.18 k8s.io/utils/clock -k8s.io/utils/clock/testing k8s.io/utils/internal/third_party/forked/golang/net k8s.io/utils/net k8s.io/utils/ptr @@ -447,7 +447,11 @@ k8s.io/utils/ptr ## explicit; go 1.23 sigs.k8s.io/json sigs.k8s.io/json/internal/golang/encoding/json -# sigs.k8s.io/structured-merge-diff/v4 v4.6.0 +# sigs.k8s.io/randfill v1.0.0 +## explicit; go 1.18 +sigs.k8s.io/randfill +sigs.k8s.io/randfill/bytesource +# sigs.k8s.io/structured-merge-diff/v4 v4.7.0 ## explicit; go 1.13 sigs.k8s.io/structured-merge-diff/v4/value # sigs.k8s.io/yaml v1.4.0 diff --git a/vendor/sigs.k8s.io/randfill/CONTRIBUTING.md b/vendor/sigs.k8s.io/randfill/CONTRIBUTING.md new file mode 100644 index 0000000..7566c87 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/CONTRIBUTING.md @@ -0,0 +1,43 @@ +# Contributing Guidelines + +Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://git.k8s.io/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt: + +_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._ + +## Getting Started + +We have full documentation on how to get started contributing here: + + + +- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests +- [Kubernetes Contributor Guide](https://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](https://git.k8s.io/community/contributors/guide#contributing) +- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet) - Common resources for existing developers + +## Mentorship + +- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers! + + + +## Project Management + +The [maintainers](https://github.com/kubernetes-sigs/randfill/blob/main/OWNERS_ALIASES#L12) of this project (and often others who have official positions on the [contributor ladder](https://github.com/kubernetes-sigs/randfill/blob/main/OWNERS_ALIASES)) are responsible for performing project management which oversees development and maintenance of the API, tests, tools, e.t.c. While we try to be generally flexible when it comes to the management of individual pieces (such as Issues or PRs), we have some rules and guidelines which help us plan, coordinate and reduce waste. In this section you'll find some rules/guidelines for contributors related to project management which may extend or go beyond what you would find in the standard [Kubernetes Contributor Guide](https://git.k8s.io/community/contributors/guide). + +### Bumping stale and closed Issues & PRs + +Maintainers are ultimately responsible for triaging new issues and PRs, accepting or declining them, deciding priority and fitting them into milestones intended for future releases. Bots are responsible for marking issues and PRs which stagnate as stale, or closing them if progress does not continue for a long period of time. Due to the nature of this community-driven development effort (we do not have dedicated engineering resources, we rely on the community which is effectively "volunteer time") **not all issues can be accepted, prioritized or completed**. + +You may find times when an issue you're subscribed to and interested in seems to stagnate, or perhaps gets auto-closed. Prior to bumping or directly re-opening issues yourself, we generally ask that you bring these up for discussion on the agenda for one of our community syncs if possible, or bring them up for discussion in Slack or the mailing list as this gives us a better opportunity to discuss the issue and determine viability and logistics. If feasible we **highly recommend being ready to contribute directly** to any stale or unprioritized effort that you want to see move forward, as **the best way to ensure progress is to engage with the community and personally invest time**. + +We (the community) aren't opposed to making exceptions in some cases, but when in doubt please follow the above guidelines before bumping closed or stale issues if you're not ready to personally invest time in them. We are responsible for managing these and without further context or engagement we may set these back to how they were previously organized. diff --git a/vendor/github.com/google/gofuzz/LICENSE b/vendor/sigs.k8s.io/randfill/LICENSE similarity index 99% rename from vendor/github.com/google/gofuzz/LICENSE rename to vendor/sigs.k8s.io/randfill/LICENSE index d645695..9dd2927 100644 --- a/vendor/github.com/google/gofuzz/LICENSE +++ b/vendor/sigs.k8s.io/randfill/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -179,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -187,7 +186,8 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2014 The gofuzz Authors + 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. diff --git a/vendor/sigs.k8s.io/randfill/NOTICE b/vendor/sigs.k8s.io/randfill/NOTICE new file mode 100644 index 0000000..6984e71 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/NOTICE @@ -0,0 +1,24 @@ +When donating the randfill project to the CNCF, we could not reach all the +gofuzz contributors to sign the CNCF CLA. As such, according to the CNCF rules +to donate a repository, we must add a NOTICE referencing section 7 of the CLA +with a list of developers who could not be reached. + +`7. Should You wish to submit work that is not Your original creation, You may +submit it to the Foundation separately from any Contribution, identifying the +complete details of its source and of any license or other restriction +(including, but not limited to, related patents, trademarks, and license +agreements) of which you are personally aware, and conspicuously marking the +work as "Submitted on behalf of a third-party: [named here]".` + +Submitted on behalf of a third-party: @dnephin (Daniel Nephin) +Submitted on behalf of a third-party: @AlekSi (Alexey Palazhchenko) +Submitted on behalf of a third-party: @bbigras (Bruno Bigras) +Submitted on behalf of a third-party: @samirkut (Samir) +Submitted on behalf of a third-party: @posener (Eyal Posener) +Submitted on behalf of a third-party: @Ashikpaul (Ashik Paul) +Submitted on behalf of a third-party: @kwongtailau (Kwongtai) +Submitted on behalf of a third-party: @ericcornelissen (Eric Cornelissen) +Submitted on behalf of a third-party: @eclipseo (Robert-AndrĂ© Mauchin) +Submitted on behalf of a third-party: @yanzhoupan (Andrew Pan) +Submitted on behalf of a third-party: @STRRL (Zhiqiang ZHOU) +Submitted on behalf of a third-party: @disconnect3d (Disconnect3d) diff --git a/vendor/sigs.k8s.io/randfill/OWNERS b/vendor/sigs.k8s.io/randfill/OWNERS new file mode 100644 index 0000000..59f6a50 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/OWNERS @@ -0,0 +1,8 @@ +# See the OWNERS docs at https://go.k8s.io/owners +# See the OWNERS_ALIASES file at https://github.com/kubernetes-sigs/randfill/blob/main/OWNERS_ALIASES for a list of members for each alias. + +approvers: + - sig-testing-leads + - thockin + +reviewers: [] diff --git a/vendor/sigs.k8s.io/randfill/OWNERS_ALIASES b/vendor/sigs.k8s.io/randfill/OWNERS_ALIASES new file mode 100644 index 0000000..927f120 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/OWNERS_ALIASES @@ -0,0 +1,14 @@ +# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md +# This file should be kept in sync with k/org. + +aliases: + # Reference: https://github.com/kubernetes/org/blob/main/OWNERS_ALIASES + sig-testing-leads: + - BenTheElder + - alvaroaleman + - aojea + - cjwagner + - jbpratt + - michelle192837 + - pohly + - xmcqueen diff --git a/vendor/github.com/google/gofuzz/README.md b/vendor/sigs.k8s.io/randfill/README.md similarity index 53% rename from vendor/github.com/google/gofuzz/README.md rename to vendor/sigs.k8s.io/randfill/README.md index b503aae..d892fc9 100644 --- a/vendor/github.com/google/gofuzz/README.md +++ b/vendor/sigs.k8s.io/randfill/README.md @@ -1,39 +1,46 @@ -gofuzz +randfill ====== -gofuzz is a library for populating go objects with random values. +randfill is a library for populating go objects with random values. -[![GoDoc](https://godoc.org/github.com/google/gofuzz?status.svg)](https://godoc.org/github.com/google/gofuzz) -[![Travis](https://travis-ci.org/google/gofuzz.svg?branch=master)](https://travis-ci.org/google/gofuzz) +This is a fork of github.com/google/gofuzz, which was archived. + +NOTE: This repo is supported only for use within Kubernetes. It is not our +intention to support general use. That said, if it works for you, that's +great! If you have a problem, please feel free to file an issue, but be aware +that it may not be a priority for us to fix it unless it is affecting +Kubernetes. PRs are welcome, within reason. + +[![GoDoc](https://godoc.org/sigs.k8s.io/randfill?status.svg)](https://godoc.org/sigs.k8s.io/randfill) This is useful for testing: * Do your project's objects really serialize/unserialize correctly in all cases? * Is there an incorrectly formatted object that will cause your project to panic? -Import with ```import "github.com/google/gofuzz"``` +Import with ```import "sigs.k8s.io/randfill"``` You can use it on single variables: ```go -f := fuzz.New() +f := randfill.New() var myInt int -f.Fuzz(&myInt) // myInt gets a random value. +f.Fill(&myInt) // myInt gets a random value. ``` You can use it on maps: ```go -f := fuzz.New().NilChance(0).NumElements(1, 1) +f := randfill.New().NilChance(0).NumElements(1, 1) var myMap map[ComplexKeyType]string -f.Fuzz(&myMap) // myMap will have exactly one element. +f.Fill(&myMap) // myMap will have exactly one element. ``` Customize the chance of getting a nil pointer: ```go -f := fuzz.New().NilChance(.5) +f := randfill.New().NilChance(.5) var fancyStruct struct { A, B, C, D *string } -f.Fuzz(&fancyStruct) // About half the pointers should be set. +f.Fill(&fancyStruct) // About half the pointers should be set. ``` You can even customize the randomization completely if needed: @@ -49,25 +56,27 @@ type MyInfo struct { BInfo *string } -f := fuzz.New().NilChance(0).Funcs( - func(e *MyInfo, c fuzz.Continue) { +f := randfill.New().NilChance(0).Funcs( + func(e *MyInfo, c randfill.Continue) { switch c.Intn(2) { case 0: e.Type = A - c.Fuzz(&e.AInfo) + c.Fill(&e.AInfo) case 1: e.Type = B - c.Fuzz(&e.BInfo) + c.Fill(&e.BInfo) } }, ) var myObject MyInfo -f.Fuzz(&myObject) // Type will correspond to whether A or B info is set. +f.Fill(&myObject) // Type will correspond to whether A or B info is set. ``` See more examples in ```example_test.go```. +## dvyukov/go-fuzz integration + You can use this library for easier [go-fuzz](https://github.com/dvyukov/go-fuzz)ing. go-fuzz provides the user a byte-slice, which should be converted to different inputs for the tested function. This library can help convert the byte slice. Consider for @@ -76,11 +85,11 @@ example a fuzz test for a the function `mypackage.MyFunc` that takes an int argu // +build gofuzz package mypackage -import fuzz "github.com/google/gofuzz" +import "sigs.k8s.io/randfill" func Fuzz(data []byte) int { var i int - fuzz.NewFromGoFuzz(data).Fuzz(&i) + randfill.NewFromGoFuzz(data).Fill(&i) MyFunc(i) return 0 } diff --git a/vendor/sigs.k8s.io/randfill/SECURITY_CONTACTS b/vendor/sigs.k8s.io/randfill/SECURITY_CONTACTS new file mode 100644 index 0000000..91d7853 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/SECURITY_CONTACTS @@ -0,0 +1,16 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Committee to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +thockin +BenTheElder +aojea +pohly diff --git a/vendor/github.com/google/gofuzz/bytesource/bytesource.go b/vendor/sigs.k8s.io/randfill/bytesource/bytesource.go similarity index 100% rename from vendor/github.com/google/gofuzz/bytesource/bytesource.go rename to vendor/sigs.k8s.io/randfill/bytesource/bytesource.go diff --git a/vendor/sigs.k8s.io/randfill/code-of-conduct.md b/vendor/sigs.k8s.io/randfill/code-of-conduct.md new file mode 100644 index 0000000..0d15c00 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/vendor/sigs.k8s.io/randfill/randfill.go b/vendor/sigs.k8s.io/randfill/randfill.go new file mode 100644 index 0000000..b734824 --- /dev/null +++ b/vendor/sigs.k8s.io/randfill/randfill.go @@ -0,0 +1,682 @@ +/* +Copyright 2014 Google Inc. All rights reserved. +Copyright 2014 The gofuzz Authors. +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 randfill is a library for populating go objects with random values. +package randfill + +import ( + "fmt" + "math/rand" + "reflect" + "regexp" + "sync" + "time" + "unsafe" + + "strings" + + "sigs.k8s.io/randfill/bytesource" +) + +// funcMap is a map from a type to a function that randfills that type. The +// function is a reflect.Value because the type being filled is different for +// each func. +type funcMap map[reflect.Type]reflect.Value + +// Filler knows how to fill any object with random fields. +type Filler struct { + customFuncs funcMap + defaultFuncs funcMap + r *rand.Rand + nilChance float64 + minElements int + maxElements int + maxDepth int + allowUnexportedFields bool + skipFieldPatterns []*regexp.Regexp + + lock sync.Mutex +} + +// New returns a new Filler. Customize your Filler further by calling Funcs, +// RandSource, NilChance, or NumElements in any order. +func New() *Filler { + return NewWithSeed(time.Now().UnixNano()) +} + +func NewWithSeed(seed int64) *Filler { + f := &Filler{ + defaultFuncs: funcMap{ + reflect.TypeOf(&time.Time{}): reflect.ValueOf(randfillTime), + }, + + customFuncs: funcMap{}, + r: rand.New(rand.NewSource(seed)), + nilChance: .2, + minElements: 1, + maxElements: 10, + maxDepth: 100, + allowUnexportedFields: false, + } + return f +} + +// NewFromGoFuzz is a helper function that enables using randfill (this +// project) with go-fuzz (https://github.com/dvyukov/go-fuzz) for continuous +// fuzzing. Essentially, it enables translating the fuzzing bytes from +// go-fuzz to any Go object using this library. +// +// This implementation promises a constant translation from a given slice of +// bytes to the fuzzed objects. This promise will remain over future +// versions of Go and of this library. +// +// Note: the returned Filler should not be shared between multiple goroutines, +// as its deterministic output will no longer be available. +// +// Example: use go-fuzz to test the function `MyFunc(int)` in the package +// `mypackage`. Add the file: "mypackage_fuzz.go" with the content: +// +// // +build gofuzz +// package mypackage +// import "sigs.k8s.io/randfill" +// +// func Fuzz(data []byte) int { +// var i int +// randfill.NewFromGoFuzz(data).Fill(&i) +// MyFunc(i) +// return 0 +// } +func NewFromGoFuzz(data []byte) *Filler { + return New().RandSource(bytesource.New(data)) +} + +// Funcs registers custom fill functions for this Filler. +// +// Each entry in customFuncs must be a function taking two parameters. +// The first parameter must be a pointer or map. It is the variable that +// function will fill with random data. The second parameter must be a +// randfill.Continue, which will provide a source of randomness and a way +// to automatically continue filling smaller pieces of the first parameter. +// +// These functions are called sensibly, e.g., if you wanted custom string +// filling, the function `func(s *string, c randfill.Continue)` would get +// called and passed the address of strings. Maps and pointers will always +// be made/new'd for you, ignoring the NilChance option. For slices, it +// doesn't make much sense to pre-create them--Filler doesn't know how +// long you want your slice--so take a pointer to a slice, and make it +// yourself. (If you don't want your map/pointer type pre-made, take a +// pointer to it, and make it yourself.) See the examples for a range of +// custom functions. +// +// If a function is already registered for a type, and a new function is +// provided, the previous function will be replaced with the new one. +func (f *Filler) Funcs(customFuncs ...interface{}) *Filler { + for i := range customFuncs { + v := reflect.ValueOf(customFuncs[i]) + if v.Kind() != reflect.Func { + panic("Filler.Funcs: all arguments must be functions") + } + t := v.Type() + if t.NumIn() != 2 || t.NumOut() != 0 { + panic("Filler.Funcs: all customFuncs must have 2 arguments and 0 returns") + } + argT := t.In(0) + switch argT.Kind() { + case reflect.Ptr, reflect.Map: + default: + panic("Filler.Funcs: customFuncs' first argument must be a pointer or map type") + } + if t.In(1) != reflect.TypeOf(Continue{}) { + panic("Filler.Funcs: customFuncs' second argument must be a randfill.Continue") + } + f.customFuncs[argT] = v + } + return f +} + +// RandSource causes this Filler to get values from the given source of +// randomness. Use this if you want deterministic filling. +func (f *Filler) RandSource(s rand.Source) *Filler { + f.r = rand.New(s) + return f +} + +// NilChance sets the probability of creating a nil pointer, map, or slice to +// 'p'. 'p' should be between 0 (no nils) and 1 (all nils), inclusive. +func (f *Filler) NilChance(p float64) *Filler { + if p < 0 || p > 1 { + panic("Filler.NilChance: p must be between 0 and 1, inclusive") + } + f.nilChance = p + return f +} + +// NumElements sets the minimum and maximum number of elements that will be +// added to a non-nil map or slice. +func (f *Filler) NumElements(min, max int) *Filler { + if min < 0 { + panic("Filler.NumElements: min must be >= 0") + } + if min > max { + panic("Filler.NumElements: min must be <= max") + } + f.minElements = min + f.maxElements = max + return f +} + +func (f *Filler) genElementCount() int { + if f.minElements == f.maxElements { + return f.minElements + } + return f.minElements + f.r.Intn(f.maxElements-f.minElements+1) +} + +func (f *Filler) genShouldFill() bool { + return f.r.Float64() >= f.nilChance +} + +// MaxDepth sets the maximum number of recursive fill calls that will be made +// before stopping. This includes struct members, pointers, and map and slice +// elements. +func (f *Filler) MaxDepth(d int) *Filler { + f.maxDepth = d + return f +} + +// AllowUnexportedFields defines whether to fill unexported fields. +func (f *Filler) AllowUnexportedFields(flag bool) *Filler { + f.allowUnexportedFields = flag + return f +} + +// SkipFieldsWithPattern tells this Filler to skip any field whose name matches +// the supplied pattern. Call this multiple times if needed. This is useful to +// skip XXX_ fields generated by protobuf. +func (f *Filler) SkipFieldsWithPattern(pattern *regexp.Regexp) *Filler { + f.skipFieldPatterns = append(f.skipFieldPatterns, pattern) + return f +} + +// SimpleSelfFiller represents an object that knows how to randfill itself. +// +// Unlike NativeSelfFiller, this interface does not cause the type in question +// to depend on the randfill package. This is most useful for simple types. For +// more complex types, consider using NativeSelfFiller. +type SimpleSelfFiller interface { + // RandFill fills the current object with random data. + RandFill(r *rand.Rand) +} + +// NativeSelfFiller represents an object that knows how to randfill itself. +// +// Unlike SimpleSelfFiller, this interface allows for recursive filling of +// child objects with the same rules as the parent Filler. +type NativeSelfFiller interface { + // RandFill fills the current object with random data. + RandFill(c Continue) +} + +// Fill recursively fills all of obj's fields with something random. First +// this tries to find a custom fill function (see Funcs). If there is no +// custom function, this tests whether the object implements SimpleSelfFiller +// or NativeSelfFiller and if so, calls RandFill on it to fill itself. If that +// fails, this will see if there is a default fill function provided by this +// package. If all of that fails, this will generate random values for all +// primitive fields and then recurse for all non-primitives. +// +// This is safe for cyclic or tree-like structs, up to a limit. Use the +// MaxDepth method to adjust how deep you need it to recurse. +// +// obj must be a pointer. Exported (public) fields can always be set, and if +// the AllowUnexportedFields() modifier was called it can try to set unexported +// (private) fields, too. +// +// This is intended for tests, so will panic on bad input or unimplemented +// types. This method takes a lock for the whole Filler, so it is not +// reentrant. See Continue. +func (f *Filler) Fill(obj interface{}) { + f.lock.Lock() + defer f.lock.Unlock() + + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("Filler.Fill: obj must be a pointer") + } + v = v.Elem() + f.fillWithContext(v, 0) +} + +// FillNoCustom is just like Fill, except that any custom fill function for +// obj's type will not be called and obj will not be tested for +// SimpleSelfFiller or NativeSelfFiller. This applies only to obj and not other +// instances of obj's type or to obj's child fields. +// +// obj must be a pointer. Exported (public) fields can always be set, and if +// the AllowUnexportedFields() modifier was called it can try to set unexported +// (private) fields, too. +// +// This is intended for tests, so will panic on bad input or unimplemented +// types. This method takes a lock for the whole Filler, so it is not +// reentrant. See Continue. +func (f *Filler) FillNoCustom(obj interface{}) { + f.lock.Lock() + defer f.lock.Unlock() + + v := reflect.ValueOf(obj) + if v.Kind() != reflect.Ptr { + panic("Filler.FillNoCustom: obj must be a pointer") + } + v = v.Elem() + f.fillWithContext(v, flagNoCustomFill) +} + +const ( + // Do not try to find a custom fill function. Does not apply recursively. + flagNoCustomFill uint64 = 1 << iota +) + +func (f *Filler) fillWithContext(v reflect.Value, flags uint64) { + fc := &fillerContext{filler: f} + fc.doFill(v, flags) +} + +// fillerContext carries context about a single filling run, which lets Filler +// be thread-safe. +type fillerContext struct { + filler *Filler + curDepth int +} + +func (fc *fillerContext) doFill(v reflect.Value, flags uint64) { + if fc.curDepth >= fc.filler.maxDepth { + return + } + fc.curDepth++ + defer func() { fc.curDepth-- }() + + if !v.CanSet() { + if !fc.filler.allowUnexportedFields || !v.CanAddr() { + return + } + v = reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem() + } + + if flags&flagNoCustomFill == 0 { + // Check for both pointer and non-pointer custom functions. + if v.CanAddr() && fc.tryCustom(v.Addr()) { + return + } + if fc.tryCustom(v) { + return + } + } + + if fn, ok := fillFuncMap[v.Kind()]; ok { + fn(v, fc.filler.r) + return + } + + switch v.Kind() { + case reflect.Map: + if fc.filler.genShouldFill() { + v.Set(reflect.MakeMap(v.Type())) + n := fc.filler.genElementCount() + for i := 0; i < n; i++ { + key := reflect.New(v.Type().Key()).Elem() + fc.doFill(key, 0) + val := reflect.New(v.Type().Elem()).Elem() + fc.doFill(val, 0) + v.SetMapIndex(key, val) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Ptr: + if fc.filler.genShouldFill() { + v.Set(reflect.New(v.Type().Elem())) + fc.doFill(v.Elem(), 0) + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Slice: + if fc.filler.genShouldFill() { + n := fc.filler.genElementCount() + v.Set(reflect.MakeSlice(v.Type(), n, n)) + for i := 0; i < n; i++ { + fc.doFill(v.Index(i), 0) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Array: + if fc.filler.genShouldFill() { + n := v.Len() + for i := 0; i < n; i++ { + fc.doFill(v.Index(i), 0) + } + return + } + v.Set(reflect.Zero(v.Type())) + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + skipField := false + fieldName := v.Type().Field(i).Name + for _, pattern := range fc.filler.skipFieldPatterns { + if pattern.MatchString(fieldName) { + skipField = true + break + } + } + if !skipField { + fc.doFill(v.Field(i), 0) + } + } + case reflect.Chan: + fallthrough + case reflect.Func: + fallthrough + case reflect.Interface: + fallthrough + default: + panic(fmt.Sprintf("can't fill type %v, kind %v", v.Type(), v.Kind())) + } +} + +// tryCustom searches for custom handlers, and returns true iff it finds a match +// and successfully randomizes v. +func (fc *fillerContext) tryCustom(v reflect.Value) bool { + // First: see if we have a fill function for it. + doCustom, ok := fc.filler.customFuncs[v.Type()] + if !ok { + // Second: see if it can fill itself. + if v.CanInterface() { + intf := v.Interface() + if fillable, ok := intf.(SimpleSelfFiller); ok { + fillable.RandFill(fc.filler.r) + return true + } + if fillable, ok := intf.(NativeSelfFiller); ok { + fillable.RandFill(Continue{fc: fc, Rand: fc.filler.r}) + return true + } + } + // Finally: see if there is a default fill function. + doCustom, ok = fc.filler.defaultFuncs[v.Type()] + if !ok { + return false + } + } + + switch v.Kind() { + case reflect.Ptr: + if v.IsNil() { + if !v.CanSet() { + return false + } + v.Set(reflect.New(v.Type().Elem())) + } + case reflect.Map: + if v.IsNil() { + if !v.CanSet() { + return false + } + v.Set(reflect.MakeMap(v.Type())) + } + default: + return false + } + + doCustom.Call([]reflect.Value{ + v, + reflect.ValueOf(Continue{ + fc: fc, + Rand: fc.filler.r, + }), + }) + return true +} + +// Continue can be passed to custom fill functions to allow them to use +// the correct source of randomness and to continue filling their members. +type Continue struct { + fc *fillerContext + + // For convenience, Continue implements rand.Rand via embedding. + // Use this for generating any randomness if you want your filling + // to be repeatable for a given seed. + *rand.Rand +} + +// Fill continues filling obj. obj must be a pointer or a reflect.Value of a +// pointer. See Filler.Fill. +func (c Continue) Fill(obj interface{}) { + v, ok := obj.(reflect.Value) + if !ok { + v = reflect.ValueOf(obj) + } + if v.Kind() != reflect.Ptr { + panic("Continue.Fill: obj must be a pointer") + } + v = v.Elem() + c.fc.doFill(v, 0) +} + +// FillNoCustom continues filling obj, except that any custom fill function for +// obj's type will not be called and obj will not be tested for +// SimpleSelfFiller or NativeSelfFiller. See Filler.FillNoCustom. +func (c Continue) FillNoCustom(obj interface{}) { + v, ok := obj.(reflect.Value) + if !ok { + v = reflect.ValueOf(obj) + } + if v.Kind() != reflect.Ptr { + panic("Continue.FillNoCustom: obj must be a pointer") + } + v = v.Elem() + c.fc.doFill(v, flagNoCustomFill) +} + +const defaultStringMaxLen = 20 + +// String makes a random string up to n characters long. If n is 0, the default +// size range is [0-20). The returned string may include a variety of (valid) +// UTF-8 encodings. +func (c Continue) String(n int) string { + return randString(c.Rand, n) +} + +// Uint64 makes random 64 bit numbers. +// Weirdly, rand doesn't have a function that gives you 64 random bits. +func (c Continue) Uint64() uint64 { + return randUint64(c.Rand) +} + +// Bool returns true or false randomly. +func (c Continue) Bool() bool { + return randBool(c.Rand) +} + +func fillInt(v reflect.Value, r *rand.Rand) { + v.SetInt(int64(randUint64(r))) +} + +func fillUint(v reflect.Value, r *rand.Rand) { + v.SetUint(randUint64(r)) +} + +func randfillTime(t *time.Time, c Continue) { + var sec, nsec int64 + // Allow for about 1000 years of random time values, which keeps things + // like JSON parsing reasonably happy. + sec = c.Rand.Int63n(1000 * 365 * 24 * 60 * 60) + // Nanosecond values greater than 1Bn are technically allowed but result in + // time.Time values with invalid timezone offsets. + nsec = c.Rand.Int63n(999999999) + *t = time.Unix(sec, nsec) +} + +var fillFuncMap = map[reflect.Kind]func(reflect.Value, *rand.Rand){ + reflect.Bool: func(v reflect.Value, r *rand.Rand) { + v.SetBool(randBool(r)) + }, + reflect.Int: fillInt, + reflect.Int8: fillInt, + reflect.Int16: fillInt, + reflect.Int32: fillInt, + reflect.Int64: fillInt, + reflect.Uint: fillUint, + reflect.Uint8: fillUint, + reflect.Uint16: fillUint, + reflect.Uint32: fillUint, + reflect.Uint64: fillUint, + reflect.Uintptr: fillUint, + reflect.Float32: func(v reflect.Value, r *rand.Rand) { + v.SetFloat(float64(r.Float32())) + }, + reflect.Float64: func(v reflect.Value, r *rand.Rand) { + v.SetFloat(r.Float64()) + }, + reflect.Complex64: func(v reflect.Value, r *rand.Rand) { + v.SetComplex(complex128(complex(r.Float32(), r.Float32()))) + }, + reflect.Complex128: func(v reflect.Value, r *rand.Rand) { + v.SetComplex(complex(r.Float64(), r.Float64())) + }, + reflect.String: func(v reflect.Value, r *rand.Rand) { + v.SetString(randString(r, 0)) + }, + reflect.UnsafePointer: func(v reflect.Value, r *rand.Rand) { + panic("filling of UnsafePointers is not implemented") + }, +} + +// randBool returns true or false randomly. +func randBool(r *rand.Rand) bool { + return r.Int31()&(1<<30) == 0 +} + +type int63nPicker interface { + Int63n(int64) int64 +} + +// UnicodeRange describes a sequential range of unicode characters. +// Last must be numerically greater than First. +type UnicodeRange struct { + First, Last rune +} + +// UnicodeRanges describes an arbitrary number of sequential ranges of unicode characters. +// To be useful, each range must have at least one character (First <= Last) and +// there must be at least one range. +type UnicodeRanges []UnicodeRange + +// choose returns a random unicode character from the given range, using the +// given randomness source. +func (ur UnicodeRange) choose(r int63nPicker) rune { + count := int64(ur.Last - ur.First + 1) + return ur.First + rune(r.Int63n(count)) +} + +// CustomStringFillFunc constructs a FillFunc which produces random strings. +// Each character is selected from the range ur. If there are no characters +// in the range (cr.Last < cr.First), this will panic. +func (ur UnicodeRange) CustomStringFillFunc(n int) func(s *string, c Continue) { + ur.check() + return func(s *string, c Continue) { + *s = ur.randString(c.Rand, n) + } +} + +// check is a function that used to check whether the first of ur(UnicodeRange) +// is greater than the last one. +func (ur UnicodeRange) check() { + if ur.Last < ur.First { + panic("UnicodeRange.check: the last encoding must be greater than the first") + } +} + +// randString of UnicodeRange makes a random string up to 20 characters long. +// Each character is selected form ur(UnicodeRange). +func (ur UnicodeRange) randString(r *rand.Rand, max int) string { + if max == 0 { + max = defaultStringMaxLen + } + n := r.Intn(max) + sb := strings.Builder{} + sb.Grow(n) + for i := 0; i < n; i++ { + sb.WriteRune(ur.choose(r)) + } + return sb.String() +} + +// defaultUnicodeRanges sets a default unicode range when users do not set +// CustomStringFillFunc() but want to fill strings. +var defaultUnicodeRanges = UnicodeRanges{ + {' ', '~'}, // ASCII characters + {'\u00a0', '\u02af'}, // Multi-byte encoded characters + {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) +} + +// CustomStringFillFunc constructs a FillFunc which produces random strings. +// Each character is selected from one of the ranges of ur(UnicodeRanges). +// Each range has an equal probability of being chosen. If there are no ranges, +// or a selected range has no characters (.Last < .First), this will panic. +// Do not modify any of the ranges in ur after calling this function. +func (ur UnicodeRanges) CustomStringFillFunc(n int) func(s *string, c Continue) { + // Check unicode ranges slice is empty. + if len(ur) == 0 { + panic("UnicodeRanges is empty") + } + // if not empty, each range should be checked. + for i := range ur { + ur[i].check() + } + return func(s *string, c Continue) { + *s = ur.randString(c.Rand, n) + } +} + +// randString of UnicodeRanges makes a random string up to 20 characters long. +// Each character is selected form one of the ranges of ur(UnicodeRanges), +// and each range has an equal probability of being chosen. +func (ur UnicodeRanges) randString(r *rand.Rand, max int) string { + if max == 0 { + max = defaultStringMaxLen + } + n := r.Intn(max) + sb := strings.Builder{} + sb.Grow(n) + for i := 0; i < n; i++ { + sb.WriteRune(ur[r.Intn(len(ur))].choose(r)) + } + return sb.String() +} + +// randString makes a random string up to 20 characters long. The returned string +// may include a variety of (valid) UTF-8 encodings. +func randString(r *rand.Rand, max int) string { + return defaultUnicodeRanges.randString(r, max) +} + +// randUint64 makes random 64 bit numbers. +// Weirdly, rand doesn't have a function that gives you 64 random bits. +func randUint64(r *rand.Rand) uint64 { + return uint64(r.Uint32())<<32 | uint64(r.Uint32()) +} diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go index d4adb8f..3aadceb 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go @@ -22,22 +22,77 @@ import ( "strings" ) +type isZeroer interface { + IsZero() bool +} + +var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem() + +func reflectIsZero(dv reflect.Value) bool { + return dv.IsZero() +} + +// OmitZeroFunc returns a function for a type for a given struct field +// which determines if the value for that field is a zero value, matching +// how the stdlib JSON implementation. +func OmitZeroFunc(t reflect.Type) func(reflect.Value) bool { + // Provide a function that uses a type's IsZero method. + // This matches the go 1.24 custom IsZero() implementation matching + switch { + case t.Kind() == reflect.Interface && t.Implements(isZeroerType): + return func(v reflect.Value) bool { + // Avoid panics calling IsZero on a nil interface or + // non-nil interface with nil pointer. + return safeIsNil(v) || + (v.Elem().Kind() == reflect.Pointer && v.Elem().IsNil()) || + v.Interface().(isZeroer).IsZero() + } + case t.Kind() == reflect.Pointer && t.Implements(isZeroerType): + return func(v reflect.Value) bool { + // Avoid panics calling IsZero on nil pointer. + return safeIsNil(v) || v.Interface().(isZeroer).IsZero() + } + case t.Implements(isZeroerType): + return func(v reflect.Value) bool { + return v.Interface().(isZeroer).IsZero() + } + case reflect.PointerTo(t).Implements(isZeroerType): + return func(v reflect.Value) bool { + if !v.CanAddr() { + // Temporarily box v so we can take the address. + v2 := reflect.New(v.Type()).Elem() + v2.Set(v) + v = v2 + } + return v.Addr().Interface().(isZeroer).IsZero() + } + default: + // default to the reflect.IsZero implementation + return reflectIsZero + } +} + // TODO: This implements the same functionality as https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L236 // but is based on the highly efficient approach from https://golang.org/src/encoding/json/encode.go -func lookupJsonTags(f reflect.StructField) (name string, omit bool, inline bool, omitempty bool) { +func lookupJsonTags(f reflect.StructField) (name string, omit bool, inline bool, omitempty bool, omitzero func(reflect.Value) bool) { tag := f.Tag.Get("json") if tag == "-" { - return "", true, false, false + return "", true, false, false, nil } name, opts := parseTag(tag) if name == "" { name = f.Name } - return name, false, opts.Contains("inline"), opts.Contains("omitempty") + + if opts.Contains("omitzero") { + omitzero = OmitZeroFunc(f.Type) + } + + return name, false, opts.Contains("inline"), opts.Contains("omitempty"), omitzero } -func isZero(v reflect.Value) bool { +func isEmpty(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go index 88693b8..3b4a402 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go @@ -59,6 +59,8 @@ type FieldCacheEntry struct { JsonName string // isOmitEmpty is true if the field has the json 'omitempty' tag. isOmitEmpty bool + // omitzero is set if the field has the json 'omitzero' tag. + omitzero func(reflect.Value) bool // fieldPath is a list of field indices (see FieldByIndex) to lookup the value of // a field in a reflect.Value struct. The field indices in the list form a path used // to traverse through intermediary 'inline' fields. @@ -69,7 +71,13 @@ type FieldCacheEntry struct { } func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool { - return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal)) + if f.isOmitEmpty && (safeIsNil(fieldVal) || isEmpty(fieldVal)) { + return true + } + if f.omitzero != nil && f.omitzero(fieldVal) { + return true + } + return false } // GetFrom returns the field identified by this FieldCacheEntry from the provided struct. @@ -147,7 +155,7 @@ func typeReflectEntryOf(cm reflectCacheMap, t reflect.Type, updates reflectCache func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fieldPath [][]int) { for i := 0; i < t.NumField(); i++ { field := t.Field(i) - jsonName, omit, isInline, isOmitempty := lookupJsonTags(field) + jsonName, omit, isInline, isOmitempty, omitzero := lookupJsonTags(field) if omit { continue } @@ -161,7 +169,7 @@ func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fi } continue } - info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type} + info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, omitzero: omitzero, fieldPath: append(fieldPath, field.Index), fieldType: field.Type} infos[jsonName] = info } }