diff --git a/compare.go b/compare.go index 3913ef6..193211f 100644 --- a/compare.go +++ b/compare.go @@ -41,11 +41,13 @@ func platformVector(platform specs.Platform) []specs.Platform { if amd64Version, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && amd64Version > 1 { for amd64Version--; amd64Version >= 1; amd64Version-- { vector = append(vector, specs.Platform{ - Architecture: platform.Architecture, - OS: platform.OS, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - Variant: "v" + strconv.Itoa(amd64Version), + Architecture: platform.Architecture, + OS: platform.OS, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Variant: "v" + strconv.Itoa(amd64Version), + Features: platform.Features, + Compatibilities: platform.Compatibilities, }) } } @@ -59,11 +61,13 @@ func platformVector(platform specs.Platform) []specs.Platform { if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 { for armVersion--; armVersion >= 5; armVersion-- { vector = append(vector, specs.Platform{ - Architecture: platform.Architecture, - OS: platform.OS, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - Variant: "v" + strconv.Itoa(armVersion), + Architecture: platform.Architecture, + OS: platform.OS, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Variant: "v" + strconv.Itoa(armVersion), + Features: platform.Features, + Compatibilities: platform.Compatibilities, }) } } @@ -73,11 +77,13 @@ func platformVector(platform specs.Platform) []specs.Platform { variant = "v8" } vector = append(vector, platformVector(specs.Platform{ - Architecture: "arm", - OS: platform.OS, - OSVersion: platform.OSVersion, - OSFeatures: platform.OSFeatures, - Variant: variant, + Architecture: "arm", + OS: platform.OS, + OSVersion: platform.OSVersion, + OSFeatures: platform.OSFeatures, + Variant: variant, + Features: platform.Features, + Compatibilities: platform.Compatibilities, })...) } diff --git a/database.go b/database.go index 2e26fd3..b79516d 100644 --- a/database.go +++ b/database.go @@ -107,3 +107,15 @@ func normalizeArch(arch, variant string) (string, string) { return arch, variant } + +func normalizeFeatures(features []string) { + for i, f := range features { + features[i] = strings.ToLower(f) + } +} + +func normalizeCompatibilities(compat map[string]string) { + for k, v := range compat { + compat[k] = strings.ToLower(v) + } +} diff --git a/go.mod b/go.mod index 81aa215..eb30eae 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,8 @@ require ( github.com/Microsoft/hcsshim v0.10.0 github.com/containerd/log v0.1.0 github.com/opencontainers/image-spec v1.1.0-rc5 - github.com/stretchr/testify v1.8.4 + github.com/pelletier/go-toml/v2 v2.2.2 + github.com/stretchr/testify v1.9.0 golang.org/x/sys v0.10.0 ) diff --git a/go.sum b/go.sum index a28ca24..0586260 100644 --- a/go.sum +++ b/go.sum @@ -9,14 +9,22 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= 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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/platforms.go b/platforms.go index 43e4ad3..28342b6 100644 --- a/platforms.go +++ b/platforms.go @@ -146,13 +146,37 @@ func NewMatcher(platform specs.Platform) Matcher { type matcher struct { specs.Platform + + // featuresSet contains normalized set of features built from platform.features + featuresSet map[string]bool } func (m *matcher) Match(platform specs.Platform) bool { normalized := Normalize(platform) - return m.OS == normalized.OS && + + mo := m.OS == normalized.OS && m.Architecture == normalized.Architecture && m.Variant == normalized.Variant + + mf := true + for _, f := range normalized.Features { + if !m.featuresSet[f] { + mf = false + break + } + } + + mc := true + for k, nv := range normalized.Compatibilities { + if v, ok := m.Compatibilities[k]; ok && v == nv { + continue + } + + mc = false + break + } + + return mo && mf && mc } func (m *matcher) String() string { @@ -285,6 +309,8 @@ func Format(platform specs.Platform) string { func Normalize(platform specs.Platform) specs.Platform { platform.OS = normalizeOS(platform.OS) platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant) + normalizeFeatures(platform.Features) + normalizeCompatibilities(platform.Compatibilities) return platform } diff --git a/platforms_config.go b/platforms_config.go new file mode 100644 index 0000000..8702292 --- /dev/null +++ b/platforms_config.go @@ -0,0 +1,53 @@ +/* + Copyright The containerd 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 platforms + +import ( + "os" + + toml "github.com/pelletier/go-toml/v2" +) + +const platformConfigPath = "/etc/containerd/platform-config.toml" + +var config *platformConfig + +type platformConfig struct { + Features []string `json:"features,omitempty"` + Compatibilities map[string]string `json:"compatibilities,omitempty"` +} + +func readConfig() (*platformConfig, error) { + if config == nil { + b, err := os.ReadFile(platformConfigPath) + if err != nil { + return nil, err + } + if err := toml.Unmarshal(b, config); err != nil { + return nil, err + } + } + return config, nil +} + +func mustReadConfig() *platformConfig { + p, err := readConfig() + if err != nil { + panic(err) + } + return p +} diff --git a/platforms_other.go b/platforms_other.go index 59beeb3..2c39b54 100644 --- a/platforms_other.go +++ b/platforms_other.go @@ -24,9 +24,22 @@ import ( // NewMatcher returns the default Matcher for containerd func newDefaultMatcher(platform specs.Platform) Matcher { - return &matcher{ + m := &matcher{ Platform: Normalize(platform), } + + p := mustReadConfig() + m.Platform.Features = p.Features + m.Platform.Compatibilities = p.Compatibilities + + if fs := m.Platform.Features; len(fs) > 0 { + m.featuresSet = make(map[string]bool, len(fs)) + for _, f := range fs { + m.featuresSet[f] = true + } + } + + return m } func GetWindowsOsVersion() string {