diff --git a/go.mod b/go.mod index 90157f0..7e444e0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,9 @@ module github.com/siderolabs/go-kubernetes go 1.21.1 require ( + github.com/blang/semver/v4 v4.0.0 github.com/cosi-project/runtime v0.3.9 + github.com/google/go-containerregistry v0.16.1 github.com/hashicorp/go-version v1.6.0 github.com/hexops/gotextdiff v1.0.3 github.com/siderolabs/gen v0.4.7 @@ -46,6 +48,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect diff --git a/go.sum b/go.sum index 80ccb4a..fec4d4b 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/ProtonMail/gopenpgp/v2 v2.7.3 h1:AJu1OI/1UWVYZl6QcCLKGu9OTngS2r52618u github.com/ProtonMail/gopenpgp/v2 v2.7.3/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/brianvoe/gofakeit/v6 v6.17.0 h1:obbQTJeHfktJtiZzq0Q1bEpsNUs+yHrYlPVWt7BtmJ4= github.com/brianvoe/gofakeit/v6 v6.17.0/go.mod h1:Ow6qC71xtwm79anlwKRlWZW6zVq9D2XHE4QSSMP/rU8= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= @@ -70,6 +72,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= +github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= 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= @@ -139,6 +143,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -278,8 +284,8 @@ 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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= 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= diff --git a/kubernetes/compatibility/compatibility.go b/kubernetes/compatibility/compatibility.go new file mode 100644 index 0000000..13d5396 --- /dev/null +++ b/kubernetes/compatibility/compatibility.go @@ -0,0 +1,51 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package compatibility provides some a way to enable/disable features based on Kubernetes version. +package compatibility + +import ( + "strings" + + "github.com/blang/semver/v4" + "github.com/google/go-containerregistry/pkg/name" +) + +// Version is the Kubernetes version to have running. +type Version semver.Version + +// latest is used if the version can't be parsed. +var latest = Version{ + Major: 1, + Minor: 99, +} + +// VersionFromImageRef parses container image ref to return just Kubernetes version. +// +// If the version can't be parsed, assume latest version. +func VersionFromImageRef(imageRef string) Version { + // try to parse as tagged + ref, err := name.NewTag(imageRef) + if err != nil { + // try to cut digest part + var ok bool + + imageRef, _, ok = strings.Cut(imageRef, "@") + + if ok { + ref, err = name.NewTag(imageRef) + } + + if err != nil { + return latest + } + } + + v, err := semver.ParseTolerant(ref.TagStr()) + if err != nil { + return latest + } + + return Version(v) +} diff --git a/kubernetes/compatibility/compatibility_test.go b/kubernetes/compatibility/compatibility_test.go new file mode 100644 index 0000000..155beb8 --- /dev/null +++ b/kubernetes/compatibility/compatibility_test.go @@ -0,0 +1,64 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package compatibility_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/siderolabs/go-kubernetes/kubernetes/compatibility" +) + +func TestVersionFromImageRef(t *testing.T) { + for _, test := range []struct { + name string + imageRef string + + expectedVersion compatibility.Version + }{ + { + name: "just tag", + imageRef: "k8s.gcr.io/kube-apiserver:v1.18.0", + + expectedVersion: compatibility.Version{Major: 1, Minor: 18}, + }, + { + name: "just tag 2", + imageRef: "ghcr.io/siderolabs/kubelet:v1.27.9", + + expectedVersion: compatibility.Version{Major: 1, Minor: 27, Patch: 9}, + }, + { + name: "tag and digest", + imageRef: "ghcr.io/siderolabs/kubelet:v1.27.9@sha256:3f226f5b385960e311f19d6c9c3ea1778e86e6ad2e98a7bbbf1b1a63fe963916", + + expectedVersion: compatibility.Version{Major: 1, Minor: 27, Patch: 9}, + }, + { + name: "only digest", + imageRef: "ghcr.io/siderolabs/kubelet@sha256:3f226f5b385960e311f19d6c9c3ea1778e86e6ad2e98a7bbbf1b1a63fe963916", + + expectedVersion: compatibility.Version{Major: 1, Minor: 99}, + }, + { + name: "no tag or digest", + imageRef: "ghcr.io/siderolabs/kubelet", + + expectedVersion: compatibility.Version{Major: 1, Minor: 99}, + }, + { + name: "invalid version", + imageRef: "ghcr.io/siderolabs/kubelet:alpha", + + expectedVersion: compatibility.Version{Major: 1, Minor: 99}, + }, + } { + t.Run(test.name, func(t *testing.T) { + actualVersion := compatibility.VersionFromImageRef(test.imageRef) + assert.Equal(t, test.expectedVersion, actualVersion) + }) + } +} diff --git a/kubernetes/compatibility/features.go b/kubernetes/compatibility/features.go new file mode 100644 index 0000000..9a0df85 --- /dev/null +++ b/kubernetes/compatibility/features.go @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package compatibility + +import "github.com/blang/semver/v4" + +// SupportsKubeletConfigContainerRuntimeEndpoint returns true if kubelet supports ContainerRuntimEndpoint in kubelet config. +func (v Version) SupportsKubeletConfigContainerRuntimeEndpoint() bool { + // see https://github.com/kubernetes/kubernetes/pull/112136 + return semver.Version(v).GTE(semver.Version{Major: 1, Minor: 27}) +} + +// FeatureFlagSeccompDefaultEnabledByDefault returns true if a SeccompDefault feature flag is enabled by default. +func (v Version) FeatureFlagSeccompDefaultEnabledByDefault() bool { + // see https://github.com/kubernetes/kubernetes/pull/110805 + return semver.Version(v).GTE(semver.Version{Major: 1, Minor: 25}) +}