diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27d967f8..5e360769 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,10 +13,10 @@ jobs: name: Build runs-on: ubuntu-20.04 steps: - - name: Set up Go 1.20 + - name: Set up Go 1.21 uses: actions/setup-go@v1 with: - go-version: '1.20' + go-version: '1.21' id: go - uses: actions/checkout@v1 diff --git a/Makefile b/Makefile index dee5efa1..817c8063 100644 --- a/Makefile +++ b/Makefile @@ -68,8 +68,8 @@ TAG := $(VERSION)_$(OS)_$(ARCH) TAG_PROD := $(TAG) TAG_DBG := $(VERSION)-dbg_$(OS)_$(ARCH) -GO_VERSION ?= 1.20 -BUILD_IMAGE ?= appscode/golang-dev:$(GO_VERSION) +GO_VERSION ?= 1.21 +BUILD_IMAGE ?= ghcr.io/appscode/golang-dev:$(GO_VERSION) OUTBIN = bin/$(OS)_$(ARCH)/$(BIN) ifeq ($(OS),windows) @@ -262,7 +262,7 @@ unit-tests: $(BUILD_DIRS) ./hack/test.sh $(SRC_PKGS) \ " -ADDTL_LINTERS := goconst,gofmt,goimports,unparam +ADDTL_LINTERS := gofmt,goimports,unparam .PHONY: lint lint: $(BUILD_DIRS) diff --git a/go.mod b/go.mod index de7d9951..7d22693a 100644 --- a/go.mod +++ b/go.mod @@ -4,17 +4,17 @@ go 1.21.5 require ( github.com/spf13/cobra v1.7.0 - go.bytebuilders.dev/license-verifier/kubernetes v0.12.0 + go.bytebuilders.dev/license-verifier/kubernetes v0.13.4 gomodules.xyz/flags v0.1.3 gomodules.xyz/go-sh v0.1.0 - gomodules.xyz/logs v0.0.6 + gomodules.xyz/logs v0.0.7 gomodules.xyz/pointer v0.1.0 gomodules.xyz/x v0.0.15 k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 k8s.io/client-go v0.29.0 k8s.io/klog/v2 v2.110.1 - kmodules.xyz/client-go v0.29.3 + kmodules.xyz/client-go v0.29.5 kmodules.xyz/custom-resources v0.29.0 kmodules.xyz/offshoot-api v0.29.0 stash.appscode.dev/apimachinery v0.32.1-0.20240206075719-41610d0ce38f @@ -58,10 +58,10 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/yudai/gojsondiff v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect - go.bytebuilders.dev/license-proxyserver v0.0.3 // indirect - go.bytebuilders.dev/license-verifier v0.13.0 // indirect + go.bytebuilders.dev/license-proxyserver v0.0.5 // indirect + go.bytebuilders.dev/license-verifier v0.13.4 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index df312722..83c3b008 100644 --- a/go.sum +++ b/go.sum @@ -70,7 +70,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= @@ -266,6 +267,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -296,12 +298,12 @@ github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcm github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.bytebuilders.dev/license-proxyserver v0.0.3 h1:vAFMBWfrlmFKNspjBm2KfPXnxYnC17xLwZiHmVzUmzs= -go.bytebuilders.dev/license-proxyserver v0.0.3/go.mod h1:iMJbPzDf2R2EJOZwRi7ziEr5DBMfT9Cm75/XfPb/QnU= -go.bytebuilders.dev/license-verifier v0.13.0 h1:VyI8XydrZbzClSk45rPcjz9dVhyL0EfpWW4T08SXMGo= -go.bytebuilders.dev/license-verifier v0.13.0/go.mod h1:PTTlWgokzoisBezn2zt+JeGkhTJZ0flvLzdhHVBy86M= -go.bytebuilders.dev/license-verifier/kubernetes v0.12.0 h1:YJ/JWjeJgDOHzgI/RYMn60x+R7KpZ+3Nu8BHJLghYc8= -go.bytebuilders.dev/license-verifier/kubernetes v0.12.0/go.mod h1:XJUtMI5o0QQyaor1SAqL/2YTYU9LxYM6/Q8X8o/750w= +go.bytebuilders.dev/license-proxyserver v0.0.5 h1:ePI1efC9kzEXu9Eq0WagtSNM22azqr5pOP4nbLZj2H0= +go.bytebuilders.dev/license-proxyserver v0.0.5/go.mod h1:QfJGxwfLumnzehokbuzqya9FvE+dQt9yFGTxw9Bryzw= +go.bytebuilders.dev/license-verifier v0.13.4 h1:K4qSsTWTZc7lyRvRHfI23XRrbVrQVJ8Ew5afvSiMdBE= +go.bytebuilders.dev/license-verifier v0.13.4/go.mod h1:lcmFhUSBHp5G0YeZop3I8tOUBRegBrDvkW1aTsIRGcU= +go.bytebuilders.dev/license-verifier/kubernetes v0.13.4 h1:0uPgMbWSHHjB3ECxEGGTIoa4BytSnDSHfTwoxJWv2K4= +go.bytebuilders.dev/license-verifier/kubernetes v0.13.4/go.mod h1:shdo9aT7u3WPAWvFFDTVc/m25HgtYur3d/bknjpAc80= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -362,8 +364,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -433,8 +435,8 @@ gomodules.xyz/go-sh v0.1.0 h1:1BJAuGREh2RhePt7HRrpmjnkbgfpXlCzc42SiyZ5dkc= gomodules.xyz/go-sh v0.1.0/go.mod h1:N8IrjNiYppUI/rxENYrWD6FOrSxSyEZnIekPEWM7LP0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -gomodules.xyz/logs v0.0.6 h1:8+9Wkud5yBPtIvkVszubyTeFxNII30lWODom0+GZD8U= -gomodules.xyz/logs v0.0.6/go.mod h1:Q+fFtZFLEB5q86KmDehXCGuMP72Rv+Rwz0KuVxK+Gi4= +gomodules.xyz/logs v0.0.7 h1:dkhpdQuzj+pOS3S7VaOq+JV7BVU7f68/k3uDYufhPow= +gomodules.xyz/logs v0.0.7/go.mod h1:IEIZbRl9zua2jb35NU4KoqxUEDPmKvem3PhfRHqQI54= gomodules.xyz/mergo v0.3.13 h1:q6cL/MMXZH/MrR2+yjSihFFq6UifXqjwaqI48B6cMEM= gomodules.xyz/mergo v0.3.13/go.mod h1:F/2rKC7j0URTnHUKDiTiLcGdLMhdv8jK2Za3cRTUVmc= gomodules.xyz/pointer v0.1.0 h1:sG2UKrYVSo6E3r4itAjXfPfe4fuXMi0KdyTHpR3vGCg= @@ -511,7 +513,7 @@ k8s.io/apiserver v0.29.0 h1:Y1xEMjJkP+BIi0GSEv1BBrf1jLU9UPfAnnGGbbDdp7o= k8s.io/apiserver v0.29.0/go.mod h1:31n78PsRKPmfpee7/l9NYEv67u6hOL6AfcE761HapDM= k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= k8s.io/kube-aggregator v0.29.0 h1:N4fmtePxOZ+bwiK1RhVEztOU+gkoVkvterHgpwAuiTw= @@ -522,8 +524,8 @@ k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSn k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kmodules.xyz/apiversion v0.2.0 h1:vAQYqZFm4xu4pbB1cAdHbFEPES6EQkcR4wc06xdTOWk= kmodules.xyz/apiversion v0.2.0/go.mod h1:oPX8g8LvlPdPX3Yc5YvCzJHQnw3YF/X4/jdW0b1am80= -kmodules.xyz/client-go v0.29.3 h1:vkQz4zaqWZ5wk+YQwl+C2LhzTXuJZcCUMvPpwdAzGTo= -kmodules.xyz/client-go v0.29.3/go.mod h1:xWlS/1zWkx1sIKCAkzULy9570mHZYi2exDECEoP1ek4= +kmodules.xyz/client-go v0.29.5 h1:iRl4MoV+96TM1csInOCWjn5xSOXzuYlil6CO40vXLHU= +kmodules.xyz/client-go v0.29.5/go.mod h1:pHuzpwzEcDUIGjVVvwz9N8lY+6A7HXwvs2d7NtK7Hho= kmodules.xyz/custom-resources v0.29.0 h1:RaDM2+wSVXiwIvLqmkTVYpwoH83AC8wruXe2p2rOZNY= kmodules.xyz/custom-resources v0.29.0/go.mod h1:MzZyXtxdg1PDxGk3RTTO1Xv3KiVqZnIonSwmxVbagOY= kmodules.xyz/objectstore-api v0.29.1-0.20240205052451-a5cf0aa669f1 h1:k66vcGkx9SNka0tfmbeBiEgwj1E2+EKJHxnifOUsroA= diff --git a/pkg/util.go b/pkg/util.go index 873c573e..fc3ce076 100644 --- a/pkg/util.go +++ b/pkg/util.go @@ -142,7 +142,7 @@ func (opt *options) waitForDBReady(creds []string) error { args = append(args, "--endpoints", opt.etcd.endpoint, "endpoint", "health") - return wait.PollImmediate(time.Second*5, time.Second*time.Duration(opt.waitTimeout), func() (bool, error) { + return wait.PollUntilContextTimeout(context.TODO(), time.Second*5, time.Second*time.Duration(opt.waitTimeout), true, func(ctx context.Context) (bool, error) { err := sh.Command(EtcdBackupCMD, args).Run() if err != nil { return false, nil @@ -416,7 +416,7 @@ func (opt *options) execCommandOnPod(pod *corev1.Pod, containerName string, comm return nil, fmt.Errorf("failed to init executor: %v", err) } - err = exec.Stream(remotecommand.StreamOptions{ + err = exec.StreamWithContext(context.TODO(), remotecommand.StreamOptions{ Stdout: &execOut, Stderr: &execErr, Tty: true, @@ -430,7 +430,7 @@ func (opt *options) execCommandOnPod(pod *corev1.Pod, containerName string, comm } func waitUntilPodReady(c kubernetes.Interface, meta metav1.ObjectMeta) error { - return wait.PollImmediate(kutil.RetryInterval, 5*time.Minute, func() (bool, error) { + return wait.PollUntilContextTimeout(context.TODO(), kutil.RetryInterval, 5*time.Minute, true, func(ctx context.Context) (bool, error) { if obj, err := c.CoreV1().Pods(meta.Namespace).Get(context.TODO(), meta.Name, metav1.GetOptions{}); err == nil { return obj.Status.Phase == corev1.PodRunning, nil } @@ -439,7 +439,7 @@ func waitUntilPodReady(c kubernetes.Interface, meta metav1.ObjectMeta) error { } func (opt *options) waitUntilRestoreComplete(numberOfMembersInEtcdCluster int) error { - return wait.PollImmediate(1*time.Second, 2*time.Hour, func() (bool, error) { + return wait.PollUntilContextTimeout(context.TODO(), 1*time.Second, 2*time.Hour, true, func(ctx context.Context) (bool, error) { restoreSession, err := opt.stashClient.StashV1beta1().RestoreSessions(opt.namespace).Get(context.TODO(), opt.invokerName, metav1.GetOptions{}) if err != nil { return false, err @@ -465,7 +465,7 @@ func (opt *options) waitUntilRestoreComplete(numberOfMembersInEtcdCluster int) e func (opt *options) waitUntilScalingCompleted() error { switch opt.workloadKind { case apis.KindStatefulSet: - return wait.PollImmediate(kutil.RetryInterval, time.Second*time.Duration(opt.waitTimeout), func() (bool, error) { + return wait.PollUntilContextTimeout(context.TODO(), kutil.RetryInterval, time.Second*time.Duration(opt.waitTimeout), true, func(ctx context.Context) (bool, error) { ss, err := opt.kubeClient.AppsV1().StatefulSets(opt.namespace).Get(context.TODO(), opt.workloadName, metav1.GetOptions{}) if err != nil { return false, err diff --git a/vendor/go.bytebuilders.dev/license-verifier/Makefile b/vendor/go.bytebuilders.dev/license-verifier/Makefile index abdf90d5..ac51f271 100644 --- a/vendor/go.bytebuilders.dev/license-verifier/Makefile +++ b/vendor/go.bytebuilders.dev/license-verifier/Makefile @@ -21,7 +21,7 @@ COMPRESS ?= no # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:maxDescLen=0,generateEmbeddedObjectMeta=true,allowDangerousTypes=true" -CODE_GENERATOR_IMAGE ?= appscode/gengo:release-1.25 +CODE_GENERATOR_IMAGE ?= ghcr.io/appscode/gengo:release-1.25 API_GROUPS ?= licenses:v1alpha1 # Where to push the docker image. diff --git a/vendor/go.bytebuilders.dev/license-verifier/info/lib.go b/vendor/go.bytebuilders.dev/license-verifier/info/lib.go index db160134..060595e6 100644 --- a/vendor/go.bytebuilders.dev/license-verifier/info/lib.go +++ b/vendor/go.bytebuilders.dev/license-verifier/info/lib.go @@ -47,8 +47,9 @@ var ( ProductName string // This has been renamed to Features ProductUID string - prodDomain = "byte.builders" - qaDomain = "appscode.ninja" + QADomain = "appscode.ninja" + ProdDomain = "appscode.com" + DeprecatedProdDomain = "byte.builders" registrationAPIPath = "api/v1/register" LicenseIssuerAPIPath = "api/v1/license/issue" @@ -123,9 +124,9 @@ func APIServerAddress(override ...string) (*url.URL, error) { } if SkipLicenseVerification() { - return url.Parse("https://api." + qaDomain) + return url.Parse("https://api." + QADomain) } - return url.Parse("https://api." + prodDomain) + return url.Parse("https://api." + ProdDomain) } func HostedEndpoint(u string) (bool, error) { @@ -138,15 +139,16 @@ func HostedEndpoint(u string) (bool, error) { if err != nil { return false, err } - host := u2.Hostname() - return host == prodDomain || - host == qaDomain || - strings.HasSuffix(host, "."+prodDomain) || - strings.HasSuffix(host, "."+qaDomain), nil + return HostedDomain(u2.Hostname()), nil } func HostedDomain(d string) bool { - return d == prodDomain || d == qaDomain + return d == ProdDomain || + d == DeprecatedProdDomain || + d == QADomain || + strings.HasSuffix(d, "."+ProdDomain) || + strings.HasSuffix(d, "."+DeprecatedProdDomain) || + strings.HasSuffix(d, "."+QADomain) } func LoadLicenseCA() ([]byte, error) { diff --git a/vendor/go.bytebuilders.dev/license-verifier/kubernetes/Makefile b/vendor/go.bytebuilders.dev/license-verifier/kubernetes/Makefile index 5cd4a0b4..10b65999 100644 --- a/vendor/go.bytebuilders.dev/license-verifier/kubernetes/Makefile +++ b/vendor/go.bytebuilders.dev/license-verifier/kubernetes/Makefile @@ -64,8 +64,8 @@ ARCH := $(if $(GOARCH),$(GOARCH),$(shell go env GOARCH)) BASEIMAGE_PROD ?= gcr.io/distroless/static BASEIMAGE_DBG ?= debian:stretch -GO_VERSION ?= 1.19 -BUILD_IMAGE ?= appscode/golang-dev:$(GO_VERSION) +GO_VERSION ?= 1.20 +BUILD_IMAGE ?= ghcr.io/appscode/golang-dev:$(GO_VERSION) OUTBIN = bin/$(OS)_$(ARCH)/$(BIN) ifeq ($(OS),windows) diff --git a/vendor/go.bytebuilders.dev/license-verifier/kubernetes/lib.go b/vendor/go.bytebuilders.dev/license-verifier/kubernetes/lib.go index 04735ad6..3430a33d 100644 --- a/vendor/go.bytebuilders.dev/license-verifier/kubernetes/lib.go +++ b/vendor/go.bytebuilders.dev/license-verifier/kubernetes/lib.go @@ -20,7 +20,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -62,17 +62,17 @@ const ( ) type LicenseEnforcer struct { - opts verifier.VerifyOptions - config *rest.Config - kc kubernetes.Interface - getLicense func() ([]byte, error) + licenseFile string + opts verifier.VerifyOptions + config *rest.Config + kc kubernetes.Interface } // NewLicenseEnforcer returns a newly created license enforcer func NewLicenseEnforcer(config *rest.Config, licenseFile string) (*LicenseEnforcer, error) { le := LicenseEnforcer{ - getLicense: getLicense(config, licenseFile), - config: config, + config: config, + licenseFile: licenseFile, opts: verifier.VerifyOptions{ Features: info.ProductName, }, @@ -97,30 +97,38 @@ func MustLicenseEnforcer(config *rest.Config, licenseFile string) *LicenseEnforc return le } -func getLicense(cfg *rest.Config, licenseFile string) func() ([]byte, error) { - return func() ([]byte, error) { - licenseBytes, err := ioutil.ReadFile(licenseFile) - if errors.Is(err, os.ErrNotExist) { - req := proxyserver.LicenseRequest{ - TypeMeta: metav1.TypeMeta{}, - Request: &proxyserver.LicenseRequestRequest{ - Features: info.Features(), - }, - } - pc, err := proxyclient.NewForConfig(cfg) - if err != nil { - return nil, errors.Wrap(err, "failed create client for license-proxyserver") - } - resp, err := pc.ProxyserverV1alpha1().LicenseRequests().Create(context.TODO(), &req, metav1.CreateOptions{}) - if err != nil { - return nil, errors.Wrap(err, "failed to read license") - } - licenseBytes = []byte(resp.Response.License) - } else if err != nil { +func (le *LicenseEnforcer) getLicense() ([]byte, error) { + licenseBytes, err := os.ReadFile(le.licenseFile) + if errors.Is(err, os.ErrNotExist) || (err == nil && le.invalidLicense(licenseBytes)) { + req := proxyserver.LicenseRequest{ + TypeMeta: metav1.TypeMeta{}, + Request: &proxyserver.LicenseRequestRequest{ + Features: info.Features(), + }, + } + pc, err := proxyclient.NewForConfig(le.config) + if err != nil { + return nil, errors.Wrap(err, "failed create client for license-proxyserver") + } + resp, err := pc.ProxyserverV1alpha1().LicenseRequests().Create(context.TODO(), &req, metav1.CreateOptions{}) + if err != nil { return nil, errors.Wrap(err, "failed to read license") } - return licenseBytes, nil + licenseBytes = []byte(resp.Response.License) + } else if err != nil { + return nil, errors.Wrap(err, "failed to read license") } + return licenseBytes, nil +} + +func (le *LicenseEnforcer) invalidLicense(license []byte) bool { + le.opts.License = license + // We don't want to acquire license from license-proxyserver is the license file + // contains a valid license for a different product. + // We want to acquire license-proxyserver is a previously valid license has not expired. + // So, we don't check features in the license found is license file. + l, err := verifier.ParseLicense(le.opts.ParserOptions) + return sets.NewString(l.Features...).HasAny(info.ParseFeatures(le.opts.Features)...) && err != nil } func (le *LicenseEnforcer) createClients() (err error) { @@ -136,22 +144,13 @@ func (le *LicenseEnforcer) acquireLicense() (err error) { } func (le *LicenseEnforcer) readClusterUID() (err error) { + if le.opts.ClusterUID != "" { + return + } le.opts.ClusterUID, err = clusterid.ClusterUID(le.kc.CoreV1().Namespaces()) return err } -func (le *LicenseEnforcer) podName() (string, error) { - if name, ok := os.LookupEnv("MY_POD_NAME"); ok { - return name, nil - } - - if meta.PossiblyInCluster() { - // Read current pod name - return os.Hostname() - } - return "", errors.New("failed to detect pod name") -} - func (le *LicenseEnforcer) handleLicenseVerificationFailure(licenseErr error) error { // Send interrupt so that all go-routines shut-down gracefully // https://pracucci.com/graceful-shutdown-of-kubernetes-pods.html @@ -170,10 +169,6 @@ func (le *LicenseEnforcer) handleLicenseVerificationFailure(licenseErr error) er // Log licenseInfo verification failure klog.Errorln("Failed to verify license. Reason: ", licenseErr.Error()) - podName, err := le.podName() - if err != nil { - return err - } // Read the namespace of current pod namespace := meta.PodNamespace() @@ -183,7 +178,7 @@ func (le *LicenseEnforcer) handleLicenseVerificationFailure(licenseErr error) er le.config, core.SchemeGroupVersion.WithResource(core.ResourcePods.String()), namespace, - podName, + meta.PodName(), ) if err != nil { return err @@ -297,9 +292,6 @@ func verifyLicensePeriodically(le *LicenseEnforcer, licenseFile string, stopCh < return false, nil } - if _, err := os.Stat(licenseFile); os.IsNotExist(err) { - return errors.New("license file is missing") - } return wait.PollImmediateUntil(licenseCheckInterval, fn, stopCh) } @@ -382,7 +374,7 @@ func CheckLicenseEndpoint(config *rest.Config, apiServiceName string, features [ } defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) if err != nil { return err } diff --git a/vendor/golang.org/x/oauth2/deviceauth.go b/vendor/golang.org/x/oauth2/deviceauth.go new file mode 100644 index 00000000..e99c92f3 --- /dev/null +++ b/vendor/golang.org/x/oauth2/deviceauth.go @@ -0,0 +1,198 @@ +package oauth2 + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" + + "golang.org/x/oauth2/internal" +) + +// https://datatracker.ietf.org/doc/html/rfc8628#section-3.5 +const ( + errAuthorizationPending = "authorization_pending" + errSlowDown = "slow_down" + errAccessDenied = "access_denied" + errExpiredToken = "expired_token" +) + +// DeviceAuthResponse describes a successful RFC 8628 Device Authorization Response +// https://datatracker.ietf.org/doc/html/rfc8628#section-3.2 +type DeviceAuthResponse struct { + // DeviceCode + DeviceCode string `json:"device_code"` + // UserCode is the code the user should enter at the verification uri + UserCode string `json:"user_code"` + // VerificationURI is where user should enter the user code + VerificationURI string `json:"verification_uri"` + // VerificationURIComplete (if populated) includes the user code in the verification URI. This is typically shown to the user in non-textual form, such as a QR code. + VerificationURIComplete string `json:"verification_uri_complete,omitempty"` + // Expiry is when the device code and user code expire + Expiry time.Time `json:"expires_in,omitempty"` + // Interval is the duration in seconds that Poll should wait between requests + Interval int64 `json:"interval,omitempty"` +} + +func (d DeviceAuthResponse) MarshalJSON() ([]byte, error) { + type Alias DeviceAuthResponse + var expiresIn int64 + if !d.Expiry.IsZero() { + expiresIn = int64(time.Until(d.Expiry).Seconds()) + } + return json.Marshal(&struct { + ExpiresIn int64 `json:"expires_in,omitempty"` + *Alias + }{ + ExpiresIn: expiresIn, + Alias: (*Alias)(&d), + }) + +} + +func (c *DeviceAuthResponse) UnmarshalJSON(data []byte) error { + type Alias DeviceAuthResponse + aux := &struct { + ExpiresIn int64 `json:"expires_in"` + // workaround misspelling of verification_uri + VerificationURL string `json:"verification_url"` + *Alias + }{ + Alias: (*Alias)(c), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + if aux.ExpiresIn != 0 { + c.Expiry = time.Now().UTC().Add(time.Second * time.Duration(aux.ExpiresIn)) + } + if c.VerificationURI == "" { + c.VerificationURI = aux.VerificationURL + } + return nil +} + +// DeviceAuth returns a device auth struct which contains a device code +// and authorization information provided for users to enter on another device. +func (c *Config) DeviceAuth(ctx context.Context, opts ...AuthCodeOption) (*DeviceAuthResponse, error) { + // https://datatracker.ietf.org/doc/html/rfc8628#section-3.1 + v := url.Values{ + "client_id": {c.ClientID}, + } + if len(c.Scopes) > 0 { + v.Set("scope", strings.Join(c.Scopes, " ")) + } + for _, opt := range opts { + opt.setValue(v) + } + return retrieveDeviceAuth(ctx, c, v) +} + +func retrieveDeviceAuth(ctx context.Context, c *Config, v url.Values) (*DeviceAuthResponse, error) { + if c.Endpoint.DeviceAuthURL == "" { + return nil, errors.New("endpoint missing DeviceAuthURL") + } + + req, err := http.NewRequest("POST", c.Endpoint.DeviceAuthURL, strings.NewReader(v.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Accept", "application/json") + + t := time.Now() + r, err := internal.ContextClient(ctx).Do(req) + if err != nil { + return nil, err + } + + body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) + if err != nil { + return nil, fmt.Errorf("oauth2: cannot auth device: %v", err) + } + if code := r.StatusCode; code < 200 || code > 299 { + return nil, &RetrieveError{ + Response: r, + Body: body, + } + } + + da := &DeviceAuthResponse{} + err = json.Unmarshal(body, &da) + if err != nil { + return nil, fmt.Errorf("unmarshal %s", err) + } + + if !da.Expiry.IsZero() { + // Make a small adjustment to account for time taken by the request + da.Expiry = da.Expiry.Add(-time.Since(t)) + } + + return da, nil +} + +// DeviceAccessToken polls the server to exchange a device code for a token. +func (c *Config) DeviceAccessToken(ctx context.Context, da *DeviceAuthResponse, opts ...AuthCodeOption) (*Token, error) { + if !da.Expiry.IsZero() { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, da.Expiry) + defer cancel() + } + + // https://datatracker.ietf.org/doc/html/rfc8628#section-3.4 + v := url.Values{ + "client_id": {c.ClientID}, + "grant_type": {"urn:ietf:params:oauth:grant-type:device_code"}, + "device_code": {da.DeviceCode}, + } + if len(c.Scopes) > 0 { + v.Set("scope", strings.Join(c.Scopes, " ")) + } + for _, opt := range opts { + opt.setValue(v) + } + + // "If no value is provided, clients MUST use 5 as the default." + // https://datatracker.ietf.org/doc/html/rfc8628#section-3.2 + interval := da.Interval + if interval == 0 { + interval = 5 + } + + ticker := time.NewTicker(time.Duration(interval) * time.Second) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-ticker.C: + tok, err := retrieveToken(ctx, c, v) + if err == nil { + return tok, nil + } + + e, ok := err.(*RetrieveError) + if !ok { + return nil, err + } + switch e.ErrorCode { + case errSlowDown: + // https://datatracker.ietf.org/doc/html/rfc8628#section-3.5 + // "the interval MUST be increased by 5 seconds for this and all subsequent requests" + interval += 5 + ticker.Reset(time.Duration(interval) * time.Second) + case errAuthorizationPending: + // Do nothing. + case errAccessDenied, errExpiredToken: + fallthrough + default: + return tok, err + } + } + } +} diff --git a/vendor/golang.org/x/oauth2/internal/client_appengine.go b/vendor/golang.org/x/oauth2/internal/client_appengine.go index e1755d1d..d28140f7 100644 --- a/vendor/golang.org/x/oauth2/internal/client_appengine.go +++ b/vendor/golang.org/x/oauth2/internal/client_appengine.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build appengine -// +build appengine package internal diff --git a/vendor/golang.org/x/oauth2/internal/token.go b/vendor/golang.org/x/oauth2/internal/token.go index 58901bda..e83ddeef 100644 --- a/vendor/golang.org/x/oauth2/internal/token.go +++ b/vendor/golang.org/x/oauth2/internal/token.go @@ -18,6 +18,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" ) @@ -115,41 +116,60 @@ const ( AuthStyleInHeader AuthStyle = 2 ) -// authStyleCache is the set of tokenURLs we've successfully used via +// LazyAuthStyleCache is a backwards compatibility compromise to let Configs +// have a lazily-initialized AuthStyleCache. +// +// The two users of this, oauth2.Config and oauth2/clientcredentials.Config, +// both would ideally just embed an unexported AuthStyleCache but because both +// were historically allowed to be copied by value we can't retroactively add an +// uncopyable Mutex to them. +// +// We could use an atomic.Pointer, but that was added recently enough (in Go +// 1.18) that we'd break Go 1.17 users where the tests as of 2023-08-03 +// still pass. By using an atomic.Value, it supports both Go 1.17 and +// copying by value, even if that's not ideal. +type LazyAuthStyleCache struct { + v atomic.Value // of *AuthStyleCache +} + +func (lc *LazyAuthStyleCache) Get() *AuthStyleCache { + if c, ok := lc.v.Load().(*AuthStyleCache); ok { + return c + } + c := new(AuthStyleCache) + if !lc.v.CompareAndSwap(nil, c) { + c = lc.v.Load().(*AuthStyleCache) + } + return c +} + +// AuthStyleCache is the set of tokenURLs we've successfully used via // RetrieveToken and which style auth we ended up using. // It's called a cache, but it doesn't (yet?) shrink. It's expected that // the set of OAuth2 servers a program contacts over time is fixed and // small. -var authStyleCache struct { - sync.Mutex - m map[string]AuthStyle // keyed by tokenURL -} - -// ResetAuthCache resets the global authentication style cache used -// for AuthStyleUnknown token requests. -func ResetAuthCache() { - authStyleCache.Lock() - defer authStyleCache.Unlock() - authStyleCache.m = nil +type AuthStyleCache struct { + mu sync.Mutex + m map[string]AuthStyle // keyed by tokenURL } // lookupAuthStyle reports which auth style we last used with tokenURL // when calling RetrieveToken and whether we have ever done so. -func lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) { - authStyleCache.Lock() - defer authStyleCache.Unlock() - style, ok = authStyleCache.m[tokenURL] +func (c *AuthStyleCache) lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) { + c.mu.Lock() + defer c.mu.Unlock() + style, ok = c.m[tokenURL] return } // setAuthStyle adds an entry to authStyleCache, documented above. -func setAuthStyle(tokenURL string, v AuthStyle) { - authStyleCache.Lock() - defer authStyleCache.Unlock() - if authStyleCache.m == nil { - authStyleCache.m = make(map[string]AuthStyle) +func (c *AuthStyleCache) setAuthStyle(tokenURL string, v AuthStyle) { + c.mu.Lock() + defer c.mu.Unlock() + if c.m == nil { + c.m = make(map[string]AuthStyle) } - authStyleCache.m[tokenURL] = v + c.m[tokenURL] = v } // newTokenRequest returns a new *http.Request to retrieve a new token @@ -189,10 +209,10 @@ func cloneURLValues(v url.Values) url.Values { return v2 } -func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) { +func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle, styleCache *AuthStyleCache) (*Token, error) { needsAuthStyleProbe := authStyle == 0 if needsAuthStyleProbe { - if style, ok := lookupAuthStyle(tokenURL); ok { + if style, ok := styleCache.lookupAuthStyle(tokenURL); ok { authStyle = style needsAuthStyleProbe = false } else { @@ -222,7 +242,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, token, err = doTokenRoundTrip(ctx, req) } if needsAuthStyleProbe && err == nil { - setAuthStyle(tokenURL, authStyle) + styleCache.setAuthStyle(tokenURL, authStyle) } // Don't overwrite `RefreshToken` with an empty value // if this was a token refreshing request. diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go index 9085fabe..90a2c3d6 100644 --- a/vendor/golang.org/x/oauth2/oauth2.go +++ b/vendor/golang.org/x/oauth2/oauth2.go @@ -58,6 +58,10 @@ type Config struct { // Scope specifies optional requested permissions. Scopes []string + + // authStyleCache caches which auth style to use when Endpoint.AuthStyle is + // the zero value (AuthStyleAutoDetect). + authStyleCache internal.LazyAuthStyleCache } // A TokenSource is anything that can return a token. @@ -71,8 +75,9 @@ type TokenSource interface { // Endpoint represents an OAuth 2.0 provider's authorization and token // endpoint URLs. type Endpoint struct { - AuthURL string - TokenURL string + AuthURL string + DeviceAuthURL string + TokenURL string // AuthStyle optionally specifies how the endpoint wants the // client ID & client secret sent. The zero value means to @@ -139,15 +144,19 @@ func SetAuthURLParam(key, value string) AuthCodeOption { // AuthCodeURL returns a URL to OAuth 2.0 provider's consent page // that asks for permissions for the required scopes explicitly. // -// State is a token to protect the user from CSRF attacks. You must -// always provide a non-empty string and validate that it matches the -// state query parameter on your redirect callback. -// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info. +// State is an opaque value used by the client to maintain state between the +// request and callback. The authorization server includes this value when +// redirecting the user agent back to the client. // // Opts may include AccessTypeOnline or AccessTypeOffline, as well // as ApprovalForce. -// It can also be used to pass the PKCE challenge. -// See https://www.oauth.com/oauth2-servers/pkce/ for more info. +// +// To protect against CSRF attacks, opts should include a PKCE challenge +// (S256ChallengeOption). Not all servers support PKCE. An alternative is to +// generate a random state parameter and verify it after exchange. +// See https://datatracker.ietf.org/doc/html/rfc6749#section-10.12 (predating +// PKCE), https://www.oauth.com/oauth2-servers/pkce/ and +// https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.html#name-cross-site-request-forgery (describing both approaches) func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { var buf bytes.Buffer buf.WriteString(c.Endpoint.AuthURL) @@ -162,7 +171,6 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { v.Set("scope", strings.Join(c.Scopes, " ")) } if state != "" { - // TODO(light): Docs say never to omit state; don't allow empty. v.Set("state", state) } for _, opt := range opts { @@ -207,10 +215,11 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor // The provided context optionally controls which HTTP client is used. See the HTTPClient variable. // // The code will be in the *http.Request.FormValue("code"). Before -// calling Exchange, be sure to validate FormValue("state"). +// calling Exchange, be sure to validate FormValue("state") if you are +// using it to protect against CSRF attacks. // -// Opts may include the PKCE verifier code if previously used in AuthCodeURL. -// See https://www.oauth.com/oauth2-servers/pkce/ for more info. +// If using PKCE to protect against CSRF attacks, opts should include a +// VerifierOption. func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error) { v := url.Values{ "grant_type": {"authorization_code"}, diff --git a/vendor/golang.org/x/oauth2/pkce.go b/vendor/golang.org/x/oauth2/pkce.go new file mode 100644 index 00000000..50593b6d --- /dev/null +++ b/vendor/golang.org/x/oauth2/pkce.go @@ -0,0 +1,68 @@ +// Copyright 2023 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 oauth2 + +import ( + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "net/url" +) + +const ( + codeChallengeKey = "code_challenge" + codeChallengeMethodKey = "code_challenge_method" + codeVerifierKey = "code_verifier" +) + +// GenerateVerifier generates a PKCE code verifier with 32 octets of randomness. +// This follows recommendations in RFC 7636. +// +// A fresh verifier should be generated for each authorization. +// S256ChallengeOption(verifier) should then be passed to Config.AuthCodeURL +// (or Config.DeviceAccess) and VerifierOption(verifier) to Config.Exchange +// (or Config.DeviceAccessToken). +func GenerateVerifier() string { + // "RECOMMENDED that the output of a suitable random number generator be + // used to create a 32-octet sequence. The octet sequence is then + // base64url-encoded to produce a 43-octet URL-safe string to use as the + // code verifier." + // https://datatracker.ietf.org/doc/html/rfc7636#section-4.1 + data := make([]byte, 32) + if _, err := rand.Read(data); err != nil { + panic(err) + } + return base64.RawURLEncoding.EncodeToString(data) +} + +// VerifierOption returns a PKCE code verifier AuthCodeOption. It should be +// passed to Config.Exchange or Config.DeviceAccessToken only. +func VerifierOption(verifier string) AuthCodeOption { + return setParam{k: codeVerifierKey, v: verifier} +} + +// S256ChallengeFromVerifier returns a PKCE code challenge derived from verifier with method S256. +// +// Prefer to use S256ChallengeOption where possible. +func S256ChallengeFromVerifier(verifier string) string { + sha := sha256.Sum256([]byte(verifier)) + return base64.RawURLEncoding.EncodeToString(sha[:]) +} + +// S256ChallengeOption derives a PKCE code challenge derived from verifier with +// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAccess +// only. +func S256ChallengeOption(verifier string) AuthCodeOption { + return challengeOption{ + challenge_method: "S256", + challenge: S256ChallengeFromVerifier(verifier), + } +} + +type challengeOption struct{ challenge_method, challenge string } + +func (p challengeOption) setValue(m url.Values) { + m.Set(codeChallengeMethodKey, p.challenge_method) + m.Set(codeChallengeKey, p.challenge) +} diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go index 5ffce976..5bbb3321 100644 --- a/vendor/golang.org/x/oauth2/token.go +++ b/vendor/golang.org/x/oauth2/token.go @@ -164,7 +164,7 @@ func tokenFromInternal(t *internal.Token) *Token { // This token is then mapped from *internal.Token into an *oauth2.Token which is returned along // 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)) + tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle), c.authStyleCache.Get()) if err != nil { if rErr, ok := err.(*internal.RetrieveError); ok { return nil, (*RetrieveError)(rErr) diff --git a/vendor/gomodules.xyz/logs/lib.go b/vendor/gomodules.xyz/logs/lib.go index 3bec711b..03a8214f 100644 --- a/vendor/gomodules.xyz/logs/lib.go +++ b/vendor/gomodules.xyz/logs/lib.go @@ -37,9 +37,12 @@ const logFlushFreqFlagName = "log-flush-frequency" var logFlushFreq = pflag.Duration(logFlushFreqFlagName, 5*time.Second, "Maximum number of seconds between log flushes") -func init() { - _ = flag.Set("stderrthreshold", "INFO") -} +/* +panic: flag stderrthreshold set before being defined +*/ +// func init() { +// _ = flag.Set("stderrthreshold", "INFO") +// } // AddFlags registers this package's flags on arbitrary FlagSets, such that they point to the // same value as the global flags. diff --git a/vendor/kmodules.xyz/client-go/core/v1/pod_status.go b/vendor/kmodules.xyz/client-go/core/v1/pod_status.go index eab9e766..cf87120a 100644 --- a/vendor/kmodules.xyz/client-go/core/v1/pod_status.go +++ b/vendor/kmodules.xyz/client-go/core/v1/pod_status.go @@ -17,6 +17,8 @@ limitations under the License. package v1 import ( + "fmt" + core "k8s.io/api/core/v1" ) @@ -108,3 +110,127 @@ func UpsertPodReadinessGateConditionType(readinessGates []core.PodReadinessGate, ConditionType: conditionType, }) } + +const ( + // NodeUnreachablePodReason is the reason on a pod when its state cannot be confirmed as kubelet is unresponsive + // on the node it is (was) running. + NodeUnreachablePodReason = "NodeLost" +) + +// GetPodStatus returns pod status like kubectl +// Adapted from: https://github.com/kubernetes/kubernetes/blob/735804dc812ce647f8c130dced45b5ba4079b76e/pkg/printers/internalversion/printers.go#L825 +func GetPodStatus(pod *core.Pod) string { + reason := string(pod.Status.Phase) + if pod.Status.Reason != "" { + reason = pod.Status.Reason + } + + // If the Pod carries {type:PodScheduled, reason:WaitingForGates}, set reason to 'SchedulingGated'. + for _, condition := range pod.Status.Conditions { + if condition.Type == core.PodScheduled && condition.Reason == core.PodReasonSchedulingGated { + reason = core.PodReasonSchedulingGated + } + } + + initContainers := make(map[string]*core.Container) + for i := range pod.Spec.InitContainers { + initContainers[pod.Spec.InitContainers[i].Name] = &pod.Spec.InitContainers[i] + } + + initializing := false + for i := range pod.Status.InitContainerStatuses { + container := pod.Status.InitContainerStatuses[i] + switch { + case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0: + continue + case isRestartableInitContainer(initContainers[container.Name]) && + container.Started != nil && *container.Started: + continue + case container.State.Terminated != nil: + // initialization is failed + if len(container.State.Terminated.Reason) == 0 { + if container.State.Terminated.Signal != 0 { + reason = fmt.Sprintf("Init:Signal:%d", container.State.Terminated.Signal) + } else { + reason = fmt.Sprintf("Init:ExitCode:%d", container.State.Terminated.ExitCode) + } + } else { + reason = "Init:" + container.State.Terminated.Reason + } + initializing = true + case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing": + reason = "Init:" + container.State.Waiting.Reason + initializing = true + default: + reason = fmt.Sprintf("Init:%d/%d", i, len(pod.Spec.InitContainers)) + initializing = true + } + break + } + + if !initializing || isPodInitializedConditionTrue(&pod.Status) { + hasRunning := false + for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- { + container := pod.Status.ContainerStatuses[i] + + if container.State.Waiting != nil && container.State.Waiting.Reason != "" { + reason = container.State.Waiting.Reason + } else if container.State.Terminated != nil && container.State.Terminated.Reason != "" { + reason = container.State.Terminated.Reason + } else if container.State.Terminated != nil && container.State.Terminated.Reason == "" { + if container.State.Terminated.Signal != 0 { + reason = fmt.Sprintf("Signal:%d", container.State.Terminated.Signal) + } else { + reason = fmt.Sprintf("ExitCode:%d", container.State.Terminated.ExitCode) + } + } else if container.Ready && container.State.Running != nil { + hasRunning = true + } + } + + // change pod status back to "Running" if there is at least one container still reporting as "Running" status + if reason == "Completed" && hasRunning { + if hasPodReadyCondition(pod.Status.Conditions) { + reason = "Running" + } else { + reason = "NotReady" + } + } + } + + if pod.DeletionTimestamp != nil && pod.Status.Reason == NodeUnreachablePodReason { + reason = "Unknown" + } else if pod.DeletionTimestamp != nil { + reason = "Terminating" + } + + return reason +} + +func hasPodReadyCondition(conditions []core.PodCondition) bool { + for _, condition := range conditions { + if condition.Type == core.PodReady && condition.Status == core.ConditionTrue { + return true + } + } + return false +} + +func isRestartableInitContainer(initContainer *core.Container) bool { + if initContainer.RestartPolicy == nil { + return false + } + + return *initContainer.RestartPolicy == core.ContainerRestartPolicyAlways +} + +func isPodInitializedConditionTrue(status *core.PodStatus) bool { + for _, condition := range status.Conditions { + if condition.Type != core.PodInitialized { + continue + } + + return condition.Status == core.ConditionTrue + } + return false +} diff --git a/vendor/kmodules.xyz/client-go/meta/preconditions.go b/vendor/kmodules.xyz/client-go/meta/preconditions.go index 0f7d914b..5a5f597a 100644 --- a/vendor/kmodules.xyz/client-go/meta/preconditions.go +++ b/vendor/kmodules.xyz/client-go/meta/preconditions.go @@ -25,7 +25,7 @@ import ( ) type PreConditionSet struct { - sets.String + sets.Set[string] } func (s PreConditionSet) PreconditionFunc() []mergepatch.PreconditionFunc { @@ -36,7 +36,7 @@ func (s PreConditionSet) PreconditionFunc() []mergepatch.PreconditionFunc { mergepatch.RequireMetadataKeyUnchanged("namespace"), } - for _, field := range s.List() { + for _, field := range sets.List[string](s.Set) { preconditions = append(preconditions, RequireChainKeyUnchanged(field), ) @@ -45,7 +45,7 @@ func (s PreConditionSet) PreconditionFunc() []mergepatch.PreconditionFunc { } func (s PreConditionSet) Error() error { - strList := strings.Join(s.List(), "\n\t") + strList := strings.Join(sets.List[string](s.Set), "\n\t") return fmt.Errorf(strings.Join([]string{`At least one of the following was changed: apiVersion kind diff --git a/vendor/modules.txt b/vendor/modules.txt index 45900b9d..1315d2c0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -142,20 +142,20 @@ github.com/yudai/gojsondiff/formatter # github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 ## explicit github.com/yudai/golcs -# go.bytebuilders.dev/license-proxyserver v0.0.3 +# go.bytebuilders.dev/license-proxyserver v0.0.5 ## explicit; go 1.18 go.bytebuilders.dev/license-proxyserver/apis/proxyserver go.bytebuilders.dev/license-proxyserver/apis/proxyserver/v1alpha1 go.bytebuilders.dev/license-proxyserver/client/clientset/versioned go.bytebuilders.dev/license-proxyserver/client/clientset/versioned/scheme go.bytebuilders.dev/license-proxyserver/client/clientset/versioned/typed/proxyserver/v1alpha1 -# go.bytebuilders.dev/license-verifier v0.13.0 +# go.bytebuilders.dev/license-verifier v0.13.4 ## explicit; go 1.18 go.bytebuilders.dev/license-verifier go.bytebuilders.dev/license-verifier/apis/licenses go.bytebuilders.dev/license-verifier/apis/licenses/v1alpha1 go.bytebuilders.dev/license-verifier/info -# go.bytebuilders.dev/license-verifier/kubernetes v0.12.0 +# go.bytebuilders.dev/license-verifier/kubernetes v0.13.4 ## explicit; go 1.18 go.bytebuilders.dev/license-verifier/kubernetes # golang.org/x/net v0.17.0 @@ -170,8 +170,8 @@ golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/internal/socks golang.org/x/net/proxy -# golang.org/x/oauth2 v0.10.0 -## explicit; go 1.17 +# golang.org/x/oauth2 v0.13.0 +## explicit; go 1.18 golang.org/x/oauth2 golang.org/x/oauth2/internal # golang.org/x/sys v0.15.0 @@ -220,7 +220,7 @@ gomodules.xyz/go-sh # gomodules.xyz/jsonpatch/v2 v2.4.0 ## explicit; go 1.20 gomodules.xyz/jsonpatch/v2 -# gomodules.xyz/logs v0.0.6 +# gomodules.xyz/logs v0.0.7 ## explicit; go 1.16 gomodules.xyz/logs # gomodules.xyz/mergo v0.3.13 @@ -657,7 +657,7 @@ k8s.io/utils/trace # kmodules.xyz/apiversion v0.2.0 ## explicit; go 1.14 kmodules.xyz/apiversion -# kmodules.xyz/client-go v0.29.3 +# kmodules.xyz/client-go v0.29.5 ## explicit; go 1.21.5 kmodules.xyz/client-go kmodules.xyz/client-go/api/v1