From bffcefbe7a7551f687aae400337114ee7c58247b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Feb 2023 19:11:33 +0000 Subject: [PATCH] Bump github.com/container-orchestrated-devices/container-device-interface Bumps [github.com/container-orchestrated-devices/container-device-interface](https://github.com/container-orchestrated-devices/container-device-interface) from 0.4.0 to 0.5.4. - [Release notes](https://github.com/container-orchestrated-devices/container-device-interface/releases) - [Commits](https://github.com/container-orchestrated-devices/container-device-interface/compare/v0.4.0...v0.5.4) --- updated-dependencies: - dependency-name: github.com/container-orchestrated-devices/container-device-interface dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +- go.sum | 13 +- vendor/github.com/blang/semver/.travis.yml | 21 - vendor/github.com/blang/semver/LICENSE | 22 - vendor/github.com/blang/semver/README.md | 194 -------- vendor/github.com/blang/semver/json.go | 23 - vendor/github.com/blang/semver/package.json | 17 - vendor/github.com/blang/semver/range.go | 416 ----------------- vendor/github.com/blang/semver/semver.go | 418 ------------------ vendor/github.com/blang/semver/sort.go | 28 -- vendor/github.com/blang/semver/sql.go | 30 -- .../internal/multierror/multierror.go | 82 ++++ .../pkg/cdi/annotations.go | 20 +- .../pkg/cdi/cache.go | 366 +++++++++++++-- .../pkg/cdi/cache_test_unix.go | 26 ++ .../pkg/cdi/cache_test_windows.go | 22 + .../pkg/cdi/container-edits.go | 59 +-- .../pkg/cdi/container-edits_unix.go | 57 +++ .../pkg/cdi/container-edits_windows.go | 27 ++ .../pkg/cdi/device.go | 7 +- .../container-device-interface/pkg/cdi/doc.go | 142 +++++- .../pkg/cdi/qualified-device.go | 44 +- .../pkg/cdi/registry.go | 13 + .../pkg/cdi/spec-dirs.go | 12 +- .../pkg/cdi/spec.go | 188 ++++++-- .../pkg/cdi/spec_linux.go | 48 ++ .../pkg/cdi/spec_other.go | 39 ++ .../pkg/cdi/version.go | 160 +++++++ .../specs-go/config.go | 3 +- .../runtime-spec/specs-go/config.go | 46 +- .../runtime-tools/generate/generate.go | 38 +- .../generate/seccomp/seccomp_default.go | 17 +- .../generate/seccomp/seccomp_default_linux.go | 15 +- .../validate/capabilities/validate.go | 31 ++ .../validate/capabilities/validate_linux.go | 16 + .../capabilities/validate_unsupported.go | 13 + .../runtime-tools/validate/validate.go | 36 +- .../runtime-tools/validate/validate_linux.go | 15 +- vendor/golang.org/x/mod/LICENSE | 27 ++ vendor/golang.org/x/mod/PATENTS | 22 + vendor/golang.org/x/mod/semver/semver.go | 401 +++++++++++++++++ vendor/modules.txt | 12 +- 42 files changed, 1789 insertions(+), 1403 deletions(-) delete mode 100644 vendor/github.com/blang/semver/.travis.yml delete mode 100644 vendor/github.com/blang/semver/LICENSE delete mode 100644 vendor/github.com/blang/semver/README.md delete mode 100644 vendor/github.com/blang/semver/json.go delete mode 100644 vendor/github.com/blang/semver/package.json delete mode 100644 vendor/github.com/blang/semver/range.go delete mode 100644 vendor/github.com/blang/semver/semver.go delete mode 100644 vendor/github.com/blang/semver/sort.go delete mode 100644 vendor/github.com/blang/semver/sql.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/internal/multierror/multierror.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_unix.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_windows.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_unix.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_windows.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_linux.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_other.go create mode 100644 vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/version.go create mode 100644 vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go create mode 100644 vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go create mode 100644 vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go create mode 100644 vendor/golang.org/x/mod/LICENSE create mode 100644 vendor/golang.org/x/mod/PATENTS create mode 100644 vendor/golang.org/x/mod/semver/semver.go diff --git a/go.mod b/go.mod index 978e475a84..44db72fac9 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/buger/goterm v1.0.4 github.com/checkpoint-restore/checkpointctl v0.0.0-20220321135231-33f4a66335f0 github.com/checkpoint-restore/go-criu/v5 v5.3.0 - github.com/container-orchestrated-devices/container-device-interface v0.4.0 + github.com/container-orchestrated-devices/container-device-interface v0.5.4 github.com/containernetworking/cni v1.1.1 github.com/containernetworking/plugins v1.1.1 github.com/containers/buildah v1.26.1-0.20220716095526-d31d27c357ab @@ -47,8 +47,8 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 github.com/opencontainers/runc v1.1.3 - github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab - github.com/opencontainers/runtime-tools v0.9.1-0.20220714195903-17b3287fafb7 + github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb + github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 github.com/opencontainers/selinux v1.10.1 github.com/rootless-containers/rootlesskit v1.0.1 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index 7d28490f2b..533156f70d 100644 --- a/go.sum +++ b/go.sum @@ -280,8 +280,8 @@ github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= -github.com/container-orchestrated-devices/container-device-interface v0.4.0 h1:b/mROkfDr1W8fJ25T66iVheHFnWixgyxTOSbO8i7jp4= -github.com/container-orchestrated-devices/container-device-interface v0.4.0/go.mod h1:E1zcucIkq9P3eyNmY+68dBQsTcsXJh9cgRo2IVNScKQ= +github.com/container-orchestrated-devices/container-device-interface v0.5.4 h1:PqQGqJqQttMP5oJ/qNGEg8JttlHqGY3xDbbcKb5T9E8= +github.com/container-orchestrated-devices/container-device-interface v0.5.4/go.mod h1:DjE95rfPiiSmG7uVXtg0z6MnPm/Lx4wxKCIts0ZE0vg= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -1300,13 +1300,13 @@ github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/ github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20201121164853-7413a7f753e1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab h1:YQZXa3elcHgKXAa2GjVFC9M3JeP7ZPyFD1YByDx/dgQ= -github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb h1:1xSVPOd7/UA+39/hXEGnBJ13p6JFB0E1EvQFlrRDOXI= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/opencontainers/runtime-tools v0.9.1-0.20220714195903-17b3287fafb7 h1:Rf+QsQGxrYCia8mVyOPnoQZ+vJkZGL+ESWBDUM5s9cQ= github.com/opencontainers/runtime-tools v0.9.1-0.20220714195903-17b3287fafb7/go.mod h1:/tgP02fPXGHkU3/qKK1Y0Db4yqNyGm03vLq/mzHzcS4= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= @@ -1797,6 +1797,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/vendor/github.com/blang/semver/.travis.yml b/vendor/github.com/blang/semver/.travis.yml deleted file mode 100644 index 102fb9a691..0000000000 --- a/vendor/github.com/blang/semver/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go -matrix: - include: - - go: 1.4.3 - - go: 1.5.4 - - go: 1.6.3 - - go: 1.7 - - go: tip - allow_failures: - - go: tip -install: -- go get golang.org/x/tools/cmd/cover -- go get github.com/mattn/goveralls -script: -- echo "Test and track coverage" ; $HOME/gopath/bin/goveralls -package "." -service=travis-ci - -repotoken $COVERALLS_TOKEN -- echo "Build examples" ; cd examples && go build -- echo "Check if gofmt'd" ; diff -u <(echo -n) <(gofmt -d -s .) -env: - global: - secure: HroGEAUQpVq9zX1b1VIkraLiywhGbzvNnTZq2TMxgK7JHP8xqNplAeF1izrR2i4QLL9nsY+9WtYss4QuPvEtZcVHUobw6XnL6radF7jS1LgfYZ9Y7oF+zogZ2I5QUMRLGA7rcxQ05s7mKq3XZQfeqaNts4bms/eZRefWuaFZbkw= diff --git a/vendor/github.com/blang/semver/LICENSE b/vendor/github.com/blang/semver/LICENSE deleted file mode 100644 index 5ba5c86fcb..0000000000 --- a/vendor/github.com/blang/semver/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License - -Copyright (c) 2014 Benedikt Lang - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/vendor/github.com/blang/semver/README.md b/vendor/github.com/blang/semver/README.md deleted file mode 100644 index 08b2e4a3d7..0000000000 --- a/vendor/github.com/blang/semver/README.md +++ /dev/null @@ -1,194 +0,0 @@ -semver for golang [![Build Status](https://travis-ci.org/blang/semver.svg?branch=master)](https://travis-ci.org/blang/semver) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) -====== - -semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`. - -Usage ------ -```bash -$ go get github.com/blang/semver -``` -Note: Always vendor your dependencies or fix on a specific version tag. - -```go -import github.com/blang/semver -v1, err := semver.Make("1.0.0-beta") -v2, err := semver.Make("2.0.0-beta") -v1.Compare(v2) -``` - -Also check the [GoDocs](http://godoc.org/github.com/blang/semver). - -Why should I use this lib? ------ - -- Fully spec compatible -- No reflection -- No regex -- Fully tested (Coverage >99%) -- Readable parsing/validation errors -- Fast (See [Benchmarks](#benchmarks)) -- Only Stdlib -- Uses values instead of pointers -- Many features, see below - - -Features ------ - -- Parsing and validation at all levels -- Comparator-like comparisons -- Compare Helper Methods -- InPlace manipulation -- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1` -- Wildcards `>=1.x`, `<=2.5.x` -- Sortable (implements sort.Interface) -- database/sql compatible (sql.Scanner/Valuer) -- encoding/json compatible (json.Marshaler/Unmarshaler) - -Ranges ------- - -A `Range` is a set of conditions which specify which versions satisfy the range. - -A condition is composed of an operator and a version. The supported operators are: - -- `<1.0.0` Less than `1.0.0` -- `<=1.0.0` Less than or equal to `1.0.0` -- `>1.0.0` Greater than `1.0.0` -- `>=1.0.0` Greater than or equal to `1.0.0` -- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0` -- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`. - -Note that spaces between the operator and the version will be gracefully tolerated. - -A `Range` can link multiple `Ranges` separated by space: - -Ranges can be linked by logical AND: - - - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0` - - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2` - -Ranges can also be linked by logical OR: - - - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x` - -AND has a higher precedence than OR. It's not possible to use brackets. - -Ranges can be combined by both AND and OR - - - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` - -Range usage: - -``` -v, err := semver.Parse("1.2.3") -range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0") -if range(v) { - //valid -} - -``` - -Example ------ - -Have a look at full examples in [examples/main.go](examples/main.go) - -```go -import github.com/blang/semver - -v, err := semver.Make("0.0.1-alpha.preview+123.github") -fmt.Printf("Major: %d\n", v.Major) -fmt.Printf("Minor: %d\n", v.Minor) -fmt.Printf("Patch: %d\n", v.Patch) -fmt.Printf("Pre: %s\n", v.Pre) -fmt.Printf("Build: %s\n", v.Build) - -// Prerelease versions array -if len(v.Pre) > 0 { - fmt.Println("Prerelease versions:") - for i, pre := range v.Pre { - fmt.Printf("%d: %q\n", i, pre) - } -} - -// Build meta data array -if len(v.Build) > 0 { - fmt.Println("Build meta data:") - for i, build := range v.Build { - fmt.Printf("%d: %q\n", i, build) - } -} - -v001, err := semver.Make("0.0.1") -// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE -v001.GT(v) == true -v.LT(v001) == true -v.GTE(v) == true -v.LTE(v) == true - -// Or use v.Compare(v2) for comparisons (-1, 0, 1): -v001.Compare(v) == 1 -v.Compare(v001) == -1 -v.Compare(v) == 0 - -// Manipulate Version in place: -v.Pre[0], err = semver.NewPRVersion("beta") -if err != nil { - fmt.Printf("Error parsing pre release version: %q", err) -} - -fmt.Println("\nValidate versions:") -v.Build[0] = "?" - -err = v.Validate() -if err != nil { - fmt.Printf("Validation failed: %s\n", err) -} -``` - - -Benchmarks ------ - - BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op - BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op - BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op - BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op - BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op - BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op - BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op - BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op - BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op - BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op - BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op - BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op - BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op - BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op - BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op - BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op - BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op - BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op - BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op - BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op - -See benchmark cases at [semver_test.go](semver_test.go) - - -Motivation ------ - -I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like. - - -Contribution ------ - -Feel free to make a pull request. For bigger changes create a issue first to discuss about it. - - -License ------ - -See [LICENSE](LICENSE) file. diff --git a/vendor/github.com/blang/semver/json.go b/vendor/github.com/blang/semver/json.go deleted file mode 100644 index a74bf7c449..0000000000 --- a/vendor/github.com/blang/semver/json.go +++ /dev/null @@ -1,23 +0,0 @@ -package semver - -import ( - "encoding/json" -) - -// MarshalJSON implements the encoding/json.Marshaler interface. -func (v Version) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -// UnmarshalJSON implements the encoding/json.Unmarshaler interface. -func (v *Version) UnmarshalJSON(data []byte) (err error) { - var versionString string - - if err = json.Unmarshal(data, &versionString); err != nil { - return - } - - *v, err = Parse(versionString) - - return -} diff --git a/vendor/github.com/blang/semver/package.json b/vendor/github.com/blang/semver/package.json deleted file mode 100644 index 1cf8ebdd9c..0000000000 --- a/vendor/github.com/blang/semver/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "author": "blang", - "bugs": { - "URL": "https://github.com/blang/semver/issues", - "url": "https://github.com/blang/semver/issues" - }, - "gx": { - "dvcsimport": "github.com/blang/semver" - }, - "gxVersion": "0.10.0", - "language": "go", - "license": "MIT", - "name": "semver", - "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "3.5.1" -} - diff --git a/vendor/github.com/blang/semver/range.go b/vendor/github.com/blang/semver/range.go deleted file mode 100644 index fca406d479..0000000000 --- a/vendor/github.com/blang/semver/range.go +++ /dev/null @@ -1,416 +0,0 @@ -package semver - -import ( - "fmt" - "strconv" - "strings" - "unicode" -) - -type wildcardType int - -const ( - noneWildcard wildcardType = iota - majorWildcard wildcardType = 1 - minorWildcard wildcardType = 2 - patchWildcard wildcardType = 3 -) - -func wildcardTypefromInt(i int) wildcardType { - switch i { - case 1: - return majorWildcard - case 2: - return minorWildcard - case 3: - return patchWildcard - default: - return noneWildcard - } -} - -type comparator func(Version, Version) bool - -var ( - compEQ comparator = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == 0 - } - compNE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) != 0 - } - compGT = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == 1 - } - compGE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) >= 0 - } - compLT = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) == -1 - } - compLE = func(v1 Version, v2 Version) bool { - return v1.Compare(v2) <= 0 - } -) - -type versionRange struct { - v Version - c comparator -} - -// rangeFunc creates a Range from the given versionRange. -func (vr *versionRange) rangeFunc() Range { - return Range(func(v Version) bool { - return vr.c(v, vr.v) - }) -} - -// Range represents a range of versions. -// A Range can be used to check if a Version satisfies it: -// -// range, err := semver.ParseRange(">1.0.0 <2.0.0") -// range(semver.MustParse("1.1.1") // returns true -type Range func(Version) bool - -// OR combines the existing Range with another Range using logical OR. -func (rf Range) OR(f Range) Range { - return Range(func(v Version) bool { - return rf(v) || f(v) - }) -} - -// AND combines the existing Range with another Range using logical AND. -func (rf Range) AND(f Range) Range { - return Range(func(v Version) bool { - return rf(v) && f(v) - }) -} - -// ParseRange parses a range and returns a Range. -// If the range could not be parsed an error is returned. -// -// Valid ranges are: -// - "<1.0.0" -// - "<=1.0.0" -// - ">1.0.0" -// - ">=1.0.0" -// - "1.0.0", "=1.0.0", "==1.0.0" -// - "!1.0.0", "!=1.0.0" -// -// A Range can consist of multiple ranges separated by space: -// Ranges can be linked by logical AND: -// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" -// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 -// -// Ranges can also be linked by logical OR: -// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" -// -// AND has a higher precedence than OR. It's not possible to use brackets. -// -// Ranges can be combined by both AND and OR -// -// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` -func ParseRange(s string) (Range, error) { - parts := splitAndTrim(s) - orParts, err := splitORParts(parts) - if err != nil { - return nil, err - } - expandedParts, err := expandWildcardVersion(orParts) - if err != nil { - return nil, err - } - var orFn Range - for _, p := range expandedParts { - var andFn Range - for _, ap := range p { - opStr, vStr, err := splitComparatorVersion(ap) - if err != nil { - return nil, err - } - vr, err := buildVersionRange(opStr, vStr) - if err != nil { - return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) - } - rf := vr.rangeFunc() - - // Set function - if andFn == nil { - andFn = rf - } else { // Combine with existing function - andFn = andFn.AND(rf) - } - } - if orFn == nil { - orFn = andFn - } else { - orFn = orFn.OR(andFn) - } - - } - return orFn, nil -} - -// splitORParts splits the already cleaned parts by '||'. -// Checks for invalid positions of the operator and returns an -// error if found. -func splitORParts(parts []string) ([][]string, error) { - var ORparts [][]string - last := 0 - for i, p := range parts { - if p == "||" { - if i == 0 { - return nil, fmt.Errorf("First element in range is '||'") - } - ORparts = append(ORparts, parts[last:i]) - last = i + 1 - } - } - if last == len(parts) { - return nil, fmt.Errorf("Last element in range is '||'") - } - ORparts = append(ORparts, parts[last:]) - return ORparts, nil -} - -// buildVersionRange takes a slice of 2: operator and version -// and builds a versionRange, otherwise an error. -func buildVersionRange(opStr, vStr string) (*versionRange, error) { - c := parseComparator(opStr) - if c == nil { - return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) - } - v, err := Parse(vStr) - if err != nil { - return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) - } - - return &versionRange{ - v: v, - c: c, - }, nil - -} - -// inArray checks if a byte is contained in an array of bytes -func inArray(s byte, list []byte) bool { - for _, el := range list { - if el == s { - return true - } - } - return false -} - -// splitAndTrim splits a range string by spaces and cleans whitespaces -func splitAndTrim(s string) (result []string) { - last := 0 - var lastChar byte - excludeFromSplit := []byte{'>', '<', '='} - for i := 0; i < len(s); i++ { - if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) { - if last < i-1 { - result = append(result, s[last:i]) - } - last = i + 1 - } else if s[i] != ' ' { - lastChar = s[i] - } - } - if last < len(s)-1 { - result = append(result, s[last:]) - } - - for i, v := range result { - result[i] = strings.Replace(v, " ", "", -1) - } - - // parts := strings.Split(s, " ") - // for _, x := range parts { - // if s := strings.TrimSpace(x); len(s) != 0 { - // result = append(result, s) - // } - // } - return -} - -// splitComparatorVersion splits the comparator from the version. -// Input must be free of leading or trailing spaces. -func splitComparatorVersion(s string) (string, string, error) { - i := strings.IndexFunc(s, unicode.IsDigit) - if i == -1 { - return "", "", fmt.Errorf("Could not get version from string: %q", s) - } - return strings.TrimSpace(s[0:i]), s[i:], nil -} - -// getWildcardType will return the type of wildcard that the -// passed version contains -func getWildcardType(vStr string) wildcardType { - parts := strings.Split(vStr, ".") - nparts := len(parts) - wildcard := parts[nparts-1] - - possibleWildcardType := wildcardTypefromInt(nparts) - if wildcard == "x" { - return possibleWildcardType - } - - return noneWildcard -} - -// createVersionFromWildcard will convert a wildcard version -// into a regular version, replacing 'x's with '0's, handling -// special cases like '1.x.x' and '1.x' -func createVersionFromWildcard(vStr string) string { - // handle 1.x.x - vStr2 := strings.Replace(vStr, ".x.x", ".x", 1) - vStr2 = strings.Replace(vStr2, ".x", ".0", 1) - parts := strings.Split(vStr2, ".") - - // handle 1.x - if len(parts) == 2 { - return vStr2 + ".0" - } - - return vStr2 -} - -// incrementMajorVersion will increment the major version -// of the passed version -func incrementMajorVersion(vStr string) (string, error) { - parts := strings.Split(vStr, ".") - i, err := strconv.Atoi(parts[0]) - if err != nil { - return "", err - } - parts[0] = strconv.Itoa(i + 1) - - return strings.Join(parts, "."), nil -} - -// incrementMajorVersion will increment the minor version -// of the passed version -func incrementMinorVersion(vStr string) (string, error) { - parts := strings.Split(vStr, ".") - i, err := strconv.Atoi(parts[1]) - if err != nil { - return "", err - } - parts[1] = strconv.Itoa(i + 1) - - return strings.Join(parts, "."), nil -} - -// expandWildcardVersion will expand wildcards inside versions -// following these rules: -// -// * when dealing with patch wildcards: -// >= 1.2.x will become >= 1.2.0 -// <= 1.2.x will become < 1.3.0 -// > 1.2.x will become >= 1.3.0 -// < 1.2.x will become < 1.2.0 -// != 1.2.x will become < 1.2.0 >= 1.3.0 -// -// * when dealing with minor wildcards: -// >= 1.x will become >= 1.0.0 -// <= 1.x will become < 2.0.0 -// > 1.x will become >= 2.0.0 -// < 1.0 will become < 1.0.0 -// != 1.x will become < 1.0.0 >= 2.0.0 -// -// * when dealing with wildcards without -// version operator: -// 1.2.x will become >= 1.2.0 < 1.3.0 -// 1.x will become >= 1.0.0 < 2.0.0 -func expandWildcardVersion(parts [][]string) ([][]string, error) { - var expandedParts [][]string - for _, p := range parts { - var newParts []string - for _, ap := range p { - if strings.Index(ap, "x") != -1 { - opStr, vStr, err := splitComparatorVersion(ap) - if err != nil { - return nil, err - } - - versionWildcardType := getWildcardType(vStr) - flatVersion := createVersionFromWildcard(vStr) - - var resultOperator string - var shouldIncrementVersion bool - switch opStr { - case ">": - resultOperator = ">=" - shouldIncrementVersion = true - case ">=": - resultOperator = ">=" - case "<": - resultOperator = "<" - case "<=": - resultOperator = "<" - shouldIncrementVersion = true - case "", "=", "==": - newParts = append(newParts, ">="+flatVersion) - resultOperator = "<" - shouldIncrementVersion = true - case "!=", "!": - newParts = append(newParts, "<"+flatVersion) - resultOperator = ">=" - shouldIncrementVersion = true - } - - var resultVersion string - if shouldIncrementVersion { - switch versionWildcardType { - case patchWildcard: - resultVersion, _ = incrementMinorVersion(flatVersion) - case minorWildcard: - resultVersion, _ = incrementMajorVersion(flatVersion) - } - } else { - resultVersion = flatVersion - } - - ap = resultOperator + resultVersion - } - newParts = append(newParts, ap) - } - expandedParts = append(expandedParts, newParts) - } - - return expandedParts, nil -} - -func parseComparator(s string) comparator { - switch s { - case "==": - fallthrough - case "": - fallthrough - case "=": - return compEQ - case ">": - return compGT - case ">=": - return compGE - case "<": - return compLT - case "<=": - return compLE - case "!": - fallthrough - case "!=": - return compNE - } - - return nil -} - -// MustParseRange is like ParseRange but panics if the range cannot be parsed. -func MustParseRange(s string) Range { - r, err := ParseRange(s) - if err != nil { - panic(`semver: ParseRange(` + s + `): ` + err.Error()) - } - return r -} diff --git a/vendor/github.com/blang/semver/semver.go b/vendor/github.com/blang/semver/semver.go deleted file mode 100644 index 8ee0842e6a..0000000000 --- a/vendor/github.com/blang/semver/semver.go +++ /dev/null @@ -1,418 +0,0 @@ -package semver - -import ( - "errors" - "fmt" - "strconv" - "strings" -) - -const ( - numbers string = "0123456789" - alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" - alphanum = alphas + numbers -) - -// SpecVersion is the latest fully supported spec version of semver -var SpecVersion = Version{ - Major: 2, - Minor: 0, - Patch: 0, -} - -// Version represents a semver compatible version -type Version struct { - Major uint64 - Minor uint64 - Patch uint64 - Pre []PRVersion - Build []string //No Precendence -} - -// Version to string -func (v Version) String() string { - b := make([]byte, 0, 5) - b = strconv.AppendUint(b, v.Major, 10) - b = append(b, '.') - b = strconv.AppendUint(b, v.Minor, 10) - b = append(b, '.') - b = strconv.AppendUint(b, v.Patch, 10) - - if len(v.Pre) > 0 { - b = append(b, '-') - b = append(b, v.Pre[0].String()...) - - for _, pre := range v.Pre[1:] { - b = append(b, '.') - b = append(b, pre.String()...) - } - } - - if len(v.Build) > 0 { - b = append(b, '+') - b = append(b, v.Build[0]...) - - for _, build := range v.Build[1:] { - b = append(b, '.') - b = append(b, build...) - } - } - - return string(b) -} - -// Equals checks if v is equal to o. -func (v Version) Equals(o Version) bool { - return (v.Compare(o) == 0) -} - -// EQ checks if v is equal to o. -func (v Version) EQ(o Version) bool { - return (v.Compare(o) == 0) -} - -// NE checks if v is not equal to o. -func (v Version) NE(o Version) bool { - return (v.Compare(o) != 0) -} - -// GT checks if v is greater than o. -func (v Version) GT(o Version) bool { - return (v.Compare(o) == 1) -} - -// GTE checks if v is greater than or equal to o. -func (v Version) GTE(o Version) bool { - return (v.Compare(o) >= 0) -} - -// GE checks if v is greater than or equal to o. -func (v Version) GE(o Version) bool { - return (v.Compare(o) >= 0) -} - -// LT checks if v is less than o. -func (v Version) LT(o Version) bool { - return (v.Compare(o) == -1) -} - -// LTE checks if v is less than or equal to o. -func (v Version) LTE(o Version) bool { - return (v.Compare(o) <= 0) -} - -// LE checks if v is less than or equal to o. -func (v Version) LE(o Version) bool { - return (v.Compare(o) <= 0) -} - -// Compare compares Versions v to o: -// -1 == v is less than o -// 0 == v is equal to o -// 1 == v is greater than o -func (v Version) Compare(o Version) int { - if v.Major != o.Major { - if v.Major > o.Major { - return 1 - } - return -1 - } - if v.Minor != o.Minor { - if v.Minor > o.Minor { - return 1 - } - return -1 - } - if v.Patch != o.Patch { - if v.Patch > o.Patch { - return 1 - } - return -1 - } - - // Quick comparison if a version has no prerelease versions - if len(v.Pre) == 0 && len(o.Pre) == 0 { - return 0 - } else if len(v.Pre) == 0 && len(o.Pre) > 0 { - return 1 - } else if len(v.Pre) > 0 && len(o.Pre) == 0 { - return -1 - } - - i := 0 - for ; i < len(v.Pre) && i < len(o.Pre); i++ { - if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { - continue - } else if comp == 1 { - return 1 - } else { - return -1 - } - } - - // If all pr versions are the equal but one has further prversion, this one greater - if i == len(v.Pre) && i == len(o.Pre) { - return 0 - } else if i == len(v.Pre) && i < len(o.Pre) { - return -1 - } else { - return 1 - } - -} - -// Validate validates v and returns error in case -func (v Version) Validate() error { - // Major, Minor, Patch already validated using uint64 - - for _, pre := range v.Pre { - if !pre.IsNum { //Numeric prerelease versions already uint64 - if len(pre.VersionStr) == 0 { - return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) - } - if !containsOnly(pre.VersionStr, alphanum) { - return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) - } - } - } - - for _, build := range v.Build { - if len(build) == 0 { - return fmt.Errorf("Build meta data can not be empty %q", build) - } - if !containsOnly(build, alphanum) { - return fmt.Errorf("Invalid character(s) found in build meta data %q", build) - } - } - - return nil -} - -// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error -func New(s string) (vp *Version, err error) { - v, err := Parse(s) - vp = &v - return -} - -// Make is an alias for Parse, parses version string and returns a validated Version or error -func Make(s string) (Version, error) { - return Parse(s) -} - -// ParseTolerant allows for certain version specifications that do not strictly adhere to semver -// specs to be parsed by this library. It does so by normalizing versions before passing them to -// Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions -// with only major and minor components specified -func ParseTolerant(s string) (Version, error) { - s = strings.TrimSpace(s) - s = strings.TrimPrefix(s, "v") - - // Split into major.minor.(patch+pr+meta) - parts := strings.SplitN(s, ".", 3) - if len(parts) < 3 { - if strings.ContainsAny(parts[len(parts)-1], "+-") { - return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data") - } - for len(parts) < 3 { - parts = append(parts, "0") - } - s = strings.Join(parts, ".") - } - - return Parse(s) -} - -// Parse parses version string and returns a validated Version or error -func Parse(s string) (Version, error) { - if len(s) == 0 { - return Version{}, errors.New("Version string empty") - } - - // Split into major.minor.(patch+pr+meta) - parts := strings.SplitN(s, ".", 3) - if len(parts) != 3 { - return Version{}, errors.New("No Major.Minor.Patch elements found") - } - - // Major - if !containsOnly(parts[0], numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) - } - if hasLeadingZeroes(parts[0]) { - return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) - } - major, err := strconv.ParseUint(parts[0], 10, 64) - if err != nil { - return Version{}, err - } - - // Minor - if !containsOnly(parts[1], numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) - } - if hasLeadingZeroes(parts[1]) { - return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) - } - minor, err := strconv.ParseUint(parts[1], 10, 64) - if err != nil { - return Version{}, err - } - - v := Version{} - v.Major = major - v.Minor = minor - - var build, prerelease []string - patchStr := parts[2] - - if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { - build = strings.Split(patchStr[buildIndex+1:], ".") - patchStr = patchStr[:buildIndex] - } - - if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { - prerelease = strings.Split(patchStr[preIndex+1:], ".") - patchStr = patchStr[:preIndex] - } - - if !containsOnly(patchStr, numbers) { - return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) - } - if hasLeadingZeroes(patchStr) { - return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) - } - patch, err := strconv.ParseUint(patchStr, 10, 64) - if err != nil { - return Version{}, err - } - - v.Patch = patch - - // Prerelease - for _, prstr := range prerelease { - parsedPR, err := NewPRVersion(prstr) - if err != nil { - return Version{}, err - } - v.Pre = append(v.Pre, parsedPR) - } - - // Build meta data - for _, str := range build { - if len(str) == 0 { - return Version{}, errors.New("Build meta data is empty") - } - if !containsOnly(str, alphanum) { - return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) - } - v.Build = append(v.Build, str) - } - - return v, nil -} - -// MustParse is like Parse but panics if the version cannot be parsed. -func MustParse(s string) Version { - v, err := Parse(s) - if err != nil { - panic(`semver: Parse(` + s + `): ` + err.Error()) - } - return v -} - -// PRVersion represents a PreRelease Version -type PRVersion struct { - VersionStr string - VersionNum uint64 - IsNum bool -} - -// NewPRVersion creates a new valid prerelease version -func NewPRVersion(s string) (PRVersion, error) { - if len(s) == 0 { - return PRVersion{}, errors.New("Prerelease is empty") - } - v := PRVersion{} - if containsOnly(s, numbers) { - if hasLeadingZeroes(s) { - return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) - } - num, err := strconv.ParseUint(s, 10, 64) - - // Might never be hit, but just in case - if err != nil { - return PRVersion{}, err - } - v.VersionNum = num - v.IsNum = true - } else if containsOnly(s, alphanum) { - v.VersionStr = s - v.IsNum = false - } else { - return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) - } - return v, nil -} - -// IsNumeric checks if prerelease-version is numeric -func (v PRVersion) IsNumeric() bool { - return v.IsNum -} - -// Compare compares two PreRelease Versions v and o: -// -1 == v is less than o -// 0 == v is equal to o -// 1 == v is greater than o -func (v PRVersion) Compare(o PRVersion) int { - if v.IsNum && !o.IsNum { - return -1 - } else if !v.IsNum && o.IsNum { - return 1 - } else if v.IsNum && o.IsNum { - if v.VersionNum == o.VersionNum { - return 0 - } else if v.VersionNum > o.VersionNum { - return 1 - } else { - return -1 - } - } else { // both are Alphas - if v.VersionStr == o.VersionStr { - return 0 - } else if v.VersionStr > o.VersionStr { - return 1 - } else { - return -1 - } - } -} - -// PreRelease version to string -func (v PRVersion) String() string { - if v.IsNum { - return strconv.FormatUint(v.VersionNum, 10) - } - return v.VersionStr -} - -func containsOnly(s string, set string) bool { - return strings.IndexFunc(s, func(r rune) bool { - return !strings.ContainsRune(set, r) - }) == -1 -} - -func hasLeadingZeroes(s string) bool { - return len(s) > 1 && s[0] == '0' -} - -// NewBuildVersion creates a new valid build version -func NewBuildVersion(s string) (string, error) { - if len(s) == 0 { - return "", errors.New("Buildversion is empty") - } - if !containsOnly(s, alphanum) { - return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) - } - return s, nil -} diff --git a/vendor/github.com/blang/semver/sort.go b/vendor/github.com/blang/semver/sort.go deleted file mode 100644 index e18f880826..0000000000 --- a/vendor/github.com/blang/semver/sort.go +++ /dev/null @@ -1,28 +0,0 @@ -package semver - -import ( - "sort" -) - -// Versions represents multiple versions. -type Versions []Version - -// Len returns length of version collection -func (s Versions) Len() int { - return len(s) -} - -// Swap swaps two versions inside the collection by its indices -func (s Versions) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -// Less checks if version at index i is less than version at index j -func (s Versions) Less(i, j int) bool { - return s[i].LT(s[j]) -} - -// Sort sorts a slice of versions -func Sort(versions []Version) { - sort.Sort(Versions(versions)) -} diff --git a/vendor/github.com/blang/semver/sql.go b/vendor/github.com/blang/semver/sql.go deleted file mode 100644 index eb4d802666..0000000000 --- a/vendor/github.com/blang/semver/sql.go +++ /dev/null @@ -1,30 +0,0 @@ -package semver - -import ( - "database/sql/driver" - "fmt" -) - -// Scan implements the database/sql.Scanner interface. -func (v *Version) Scan(src interface{}) (err error) { - var str string - switch src := src.(type) { - case string: - str = src - case []byte: - str = string(src) - default: - return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) - } - - if t, err := Parse(str); err == nil { - *v = t - } - - return -} - -// Value implements the database/sql/driver.Valuer interface. -func (v Version) Value() (driver.Value, error) { - return v.String(), nil -} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/internal/multierror/multierror.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/internal/multierror/multierror.go new file mode 100644 index 0000000000..07aca4a1d3 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/internal/multierror/multierror.go @@ -0,0 +1,82 @@ +/* + Copyright © 2022 The CDI 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 multierror + +import ( + "strings" +) + +// New combines several errors into a single error. Parameters that are nil are +// ignored. If no errors are passed in or all parameters are nil, then the +// result is also nil. +func New(errors ...error) error { + // Filter out nil entries. + numErrors := 0 + for _, err := range errors { + if err != nil { + errors[numErrors] = err + numErrors++ + } + } + if numErrors == 0 { + return nil + } + return multiError(errors[0:numErrors]) +} + +// multiError is the underlying implementation used by New. +// +// Beware that a null multiError is not the same as a nil error. +type multiError []error + +// multiError returns all individual error strings concatenated with "\n" +func (e multiError) Error() string { + var builder strings.Builder + for i, err := range e { + if i > 0 { + _, _ = builder.WriteString("\n") + } + _, _ = builder.WriteString(err.Error()) + } + return builder.String() +} + +// Append returns a new multi error all errors concatenated. Errors that are +// multi errors get flattened, nil is ignored. +func Append(err error, errors ...error) error { + var result multiError + if m, ok := err.(multiError); ok { + result = m + } else if err != nil { + result = append(result, err) + } + + for _, e := range errors { + if e == nil { + continue + } + if m, ok := e.(multiError); ok { + result = append(result, m...) + } else { + result = append(result, e) + } + } + if len(result) == 0 { + return nil + } + return result +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/annotations.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/annotations.go index 1055c7df8f..c512ea09cd 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/annotations.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/annotations.go @@ -17,9 +17,9 @@ package cdi import ( + "errors" + "fmt" "strings" - - "github.com/pkg/errors" ) const ( @@ -34,14 +34,14 @@ const ( func UpdateAnnotations(annotations map[string]string, plugin string, deviceID string, devices []string) (map[string]string, error) { key, err := AnnotationKey(plugin, deviceID) if err != nil { - return annotations, errors.Wrap(err, "CDI annotation failed") + return annotations, fmt.Errorf("CDI annotation failed: %w", err) } if _, ok := annotations[key]; ok { - return annotations, errors.Errorf("CDI annotation failed, key %q used", key) + return annotations, fmt.Errorf("CDI annotation failed, key %q used", key) } value, err := AnnotationValue(devices) if err != nil { - return annotations, errors.Wrap(err, "CDI annotation failed") + return annotations, fmt.Errorf("CDI annotation failed: %w", err) } if annotations == nil { @@ -70,7 +70,7 @@ func ParseAnnotations(annotations map[string]string) ([]string, []string, error) } for _, d := range strings.Split(value, ",") { if !IsQualifiedName(d) { - return nil, nil, errors.Errorf("invalid CDI device name %q", d) + return nil, nil, fmt.Errorf("invalid CDI device name %q", d) } devices = append(devices, d) } @@ -98,11 +98,11 @@ func AnnotationKey(pluginName, deviceID string) (string, error) { name := pluginName + "_" + strings.ReplaceAll(deviceID, "/", "_") if len(name) > maxNameLen { - return "", errors.Errorf("invalid plugin+deviceID %q, too long", name) + return "", fmt.Errorf("invalid plugin+deviceID %q, too long", name) } if c := rune(name[0]); !isAlphaNumeric(c) { - return "", errors.Errorf("invalid name %q, first '%c' should be alphanumeric", + return "", fmt.Errorf("invalid name %q, first '%c' should be alphanumeric", name, c) } if len(name) > 2 { @@ -111,13 +111,13 @@ func AnnotationKey(pluginName, deviceID string) (string, error) { case isAlphaNumeric(c): case c == '_' || c == '-' || c == '.': default: - return "", errors.Errorf("invalid name %q, invalid charcter '%c'", + return "", fmt.Errorf("invalid name %q, invalid charcter '%c'", name, c) } } } if c := rune(name[len(name)-1]); !isAlphaNumeric(c) { - return "", errors.Errorf("invalid name %q, last '%c' should be alphanumeric", + return "", fmt.Errorf("invalid name %q, last '%c' should be alphanumeric", name, c) } diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go index 5c3f803f43..cb495ebb36 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go @@ -17,14 +17,19 @@ package cdi import ( + "errors" + "fmt" + "io/fs" + "os" "path/filepath" "sort" "strings" "sync" - "github.com/hashicorp/go-multierror" + "github.com/container-orchestrated-devices/container-device-interface/internal/multierror" + cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go" + "github.com/fsnotify/fsnotify" oci "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" ) // Option is an option to change some aspect of default CDI behavior. @@ -33,30 +38,46 @@ type Option func(*Cache) error // Cache stores CDI Specs loaded from Spec directories. type Cache struct { sync.Mutex - specDirs []string - specs map[string][]*Spec - devices map[string]*Device - errors map[string][]error + specDirs []string + specs map[string][]*Spec + devices map[string]*Device + errors map[string][]error + dirErrors map[string]error + + autoRefresh bool + watch *watch +} + +// WithAutoRefresh returns an option to control automatic Cache refresh. +// By default auto-refresh is enabled, the list of Spec directories are +// monitored and the Cache is automatically refreshed whenever a change +// is detected. This option can be used to disable this behavior when a +// manually refreshed mode is preferable. +func WithAutoRefresh(autoRefresh bool) Option { + return func(c *Cache) error { + c.autoRefresh = autoRefresh + return nil + } } // NewCache creates a new CDI Cache. The cache is populated from a set // of CDI Spec directories. These can be specified using a WithSpecDirs // option. The default set of directories is exposed in DefaultSpecDirs. func NewCache(options ...Option) (*Cache, error) { - c := &Cache{} - - if err := c.Configure(options...); err != nil { - return nil, err - } - if len(c.specDirs) == 0 { - c.Configure(WithSpecDirs(DefaultSpecDirs...)) + c := &Cache{ + autoRefresh: true, + watch: &watch{}, } - return c, c.Refresh() + WithSpecDirs(DefaultSpecDirs...)(c) + c.Lock() + defer c.Unlock() + + return c, c.configure(options...) } -// Configure applies options to the cache. Updates the cache if options have -// changed. +// Configure applies options to the Cache. Updates and refreshes the +// Cache if options have changed. func (c *Cache) Configure(options ...Option) error { if len(options) == 0 { return nil @@ -65,17 +86,54 @@ func (c *Cache) Configure(options ...Option) error { c.Lock() defer c.Unlock() + return c.configure(options...) +} + +// Configure the Cache. Start/stop CDI Spec directory watch, refresh +// the Cache if necessary. +func (c *Cache) configure(options ...Option) error { + var err error + for _, o := range options { - if err := o(c); err != nil { - return errors.Wrapf(err, "failed to apply cache options") + if err = o(c); err != nil { + return fmt.Errorf("failed to apply cache options: %w", err) } } + c.dirErrors = make(map[string]error) + + c.watch.stop() + if c.autoRefresh { + c.watch.setup(c.specDirs, c.dirErrors) + c.watch.start(&c.Mutex, c.refresh, c.dirErrors) + } + c.refresh() + return nil } // Refresh rescans the CDI Spec directories and refreshes the Cache. +// In manual refresh mode the cache is always refreshed. In auto- +// refresh mode the cache is only refreshed if it is out of date. func (c *Cache) Refresh() error { + c.Lock() + defer c.Unlock() + + // force a refresh in manual mode + if refreshed, err := c.refreshIfRequired(!c.autoRefresh); refreshed { + return err + } + + // collect and return cached errors, much like refresh() does it + var result error + for _, errors := range c.errors { + result = multierror.Append(result, errors...) + } + return result +} + +// Refresh the Cache by rescanning CDI Spec directories and files. +func (c *Cache) refresh() error { var ( specs = map[string][]*Spec{} devices = map[string]*Device{} @@ -100,7 +158,7 @@ func (c *Cache) Refresh() error { return false case devPrio == oldPrio: devPath, oldPath := devSpec.GetPath(), oldSpec.GetPath() - collectError(errors.Errorf("conflicting device %q (specs %q, %q)", + collectError(fmt.Errorf("conflicting device %q (specs %q, %q)", name, devPath, oldPath), devPath, oldPath) conflicts[name] = struct{}{} } @@ -110,7 +168,7 @@ func (c *Cache) Refresh() error { _ = scanSpecDirs(c.specDirs, func(path string, priority int, spec *Spec, err error) error { path = filepath.Clean(path) if err != nil { - collectError(errors.Wrapf(err, "failed to load CDI Spec"), path) + collectError(fmt.Errorf("failed to load CDI Spec %w", err), path) return nil } @@ -135,18 +193,22 @@ func (c *Cache) Refresh() error { delete(devices, conflict) } - c.Lock() - defer c.Unlock() - c.specs = specs c.devices = devices c.errors = specErrors - if len(result) > 0 { - return multierror.Append(nil, result...) - } + return multierror.New(result...) +} - return nil +// RefreshIfRequired triggers a refresh if necessary. +func (c *Cache) refreshIfRequired(force bool) (bool, error) { + // We need to refresh if + // - it's forced by an explicitly call to Refresh() in manual mode + // - a missing Spec dir appears (added to watch) in auto-refresh mode + if force || (c.autoRefresh && c.watch.update(c.dirErrors)) { + return true, c.refresh() + } + return false, nil } // InjectDevices injects the given qualified devices to an OCI Spec. It @@ -156,12 +218,14 @@ func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, e var unresolved []string if ociSpec == nil { - return devices, errors.Errorf("can't inject devices, nil OCI Spec") + return devices, fmt.Errorf("can't inject devices, nil OCI Spec") } c.Lock() defer c.Unlock() + c.refreshIfRequired(false) + edits := &ContainerEdits{} specs := map[*Spec]struct{}{} @@ -179,22 +243,96 @@ func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, e } if unresolved != nil { - return unresolved, errors.Errorf("unresolvable CDI devices %s", + return unresolved, fmt.Errorf("unresolvable CDI devices %s", strings.Join(devices, ", ")) } if err := edits.Apply(ociSpec); err != nil { - return nil, errors.Wrap(err, "failed to inject devices") + return nil, fmt.Errorf("failed to inject devices: %w", err) } return nil, nil } +// highestPrioritySpecDir returns the Spec directory with highest priority +// and its priority. +func (c *Cache) highestPrioritySpecDir() (string, int) { + if len(c.specDirs) == 0 { + return "", -1 + } + + prio := len(c.specDirs) - 1 + dir := c.specDirs[prio] + + return dir, prio +} + +// WriteSpec writes a Spec file with the given content into the highest +// priority Spec directory. If name has a "json" or "yaml" extension it +// choses the encoding. Otherwise the default YAML encoding is used. +func (c *Cache) WriteSpec(raw *cdi.Spec, name string) error { + var ( + specDir string + path string + prio int + spec *Spec + err error + ) + + specDir, prio = c.highestPrioritySpecDir() + if specDir == "" { + return errors.New("no Spec directories to write to") + } + + path = filepath.Join(specDir, name) + if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" { + path += defaultSpecExt + } + + spec, err = newSpec(raw, path, prio) + if err != nil { + return err + } + + return spec.write(true) +} + +// RemoveSpec removes a Spec with the given name from the highest +// priority Spec directory. This function can be used to remove a +// Spec previously written by WriteSpec(). If the file exists and +// its removal fails RemoveSpec returns an error. +func (c *Cache) RemoveSpec(name string) error { + var ( + specDir string + path string + err error + ) + + specDir, _ = c.highestPrioritySpecDir() + if specDir == "" { + return errors.New("no Spec directories to remove from") + } + + path = filepath.Join(specDir, name) + if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" { + path += defaultSpecExt + } + + err = os.Remove(path) + if err != nil && errors.Is(err, fs.ErrNotExist) { + err = nil + } + + return err +} + // GetDevice returns the cached device for the given qualified name. func (c *Cache) GetDevice(device string) *Device { c.Lock() defer c.Unlock() + c.refreshIfRequired(false) + return c.devices[device] } @@ -205,6 +343,8 @@ func (c *Cache) ListDevices() []string { c.Lock() defer c.Unlock() + c.refreshIfRequired(false) + for name := range c.devices { devices = append(devices, name) } @@ -220,6 +360,8 @@ func (c *Cache) ListVendors() []string { c.Lock() defer c.Unlock() + c.refreshIfRequired(false) + for vendor := range c.specs { vendors = append(vendors, vendor) } @@ -238,6 +380,8 @@ func (c *Cache) ListClasses() []string { c.Lock() defer c.Unlock() + c.refreshIfRequired(false) + for _, specs := range c.specs { for _, spec := range specs { cmap[spec.GetClass()] = struct{}{} @@ -256,24 +400,182 @@ func (c *Cache) GetVendorSpecs(vendor string) []*Spec { c.Lock() defer c.Unlock() + c.refreshIfRequired(false) + return c.specs[vendor] } // GetSpecErrors returns all errors encountered for the spec during the // last cache refresh. func (c *Cache) GetSpecErrors(spec *Spec) []error { - return c.errors[spec.GetPath()] + var errors []error + + c.Lock() + defer c.Unlock() + + if errs, ok := c.errors[spec.GetPath()]; ok { + errors = make([]error, len(errs)) + copy(errors, errs) + } + + return errors } // GetErrors returns all errors encountered during the last // cache refresh. func (c *Cache) GetErrors() map[string][]error { - return c.errors + c.Lock() + defer c.Unlock() + + errors := map[string][]error{} + for path, errs := range c.errors { + errors[path] = errs + } + for path, err := range c.dirErrors { + errors[path] = []error{err} + } + + return errors } // GetSpecDirectories returns the CDI Spec directories currently in use. func (c *Cache) GetSpecDirectories() []string { + c.Lock() + defer c.Unlock() + dirs := make([]string, len(c.specDirs)) copy(dirs, c.specDirs) return dirs } + +// GetSpecDirErrors returns any errors related to configured Spec directories. +func (c *Cache) GetSpecDirErrors() map[string]error { + if c.dirErrors == nil { + return nil + } + + c.Lock() + defer c.Unlock() + + errors := make(map[string]error) + for dir, err := range c.dirErrors { + errors[dir] = err + } + return errors +} + +// Our fsnotify helper wrapper. +type watch struct { + watcher *fsnotify.Watcher + tracked map[string]bool +} + +// Setup monitoring for the given Spec directories. +func (w *watch) setup(dirs []string, dirErrors map[string]error) { + var ( + dir string + err error + ) + w.tracked = make(map[string]bool) + for _, dir = range dirs { + w.tracked[dir] = false + } + + w.watcher, err = fsnotify.NewWatcher() + if err != nil { + for _, dir := range dirs { + dirErrors[dir] = fmt.Errorf("failed to create watcher: %w", err) + } + return + } + + w.update(dirErrors) +} + +// Start watching Spec directories for relevant changes. +func (w *watch) start(m *sync.Mutex, refresh func() error, dirErrors map[string]error) { + go w.watch(w.watcher, m, refresh, dirErrors) +} + +// Stop watching directories. +func (w *watch) stop() { + if w.watcher == nil { + return + } + + w.watcher.Close() + w.tracked = nil +} + +// Watch Spec directory changes, triggering a refresh if necessary. +func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error, dirErrors map[string]error) { + watch := fsw + if watch == nil { + return + } + for { + select { + case event, ok := <-watch.Events: + if !ok { + return + } + + if (event.Op & (fsnotify.Rename | fsnotify.Remove | fsnotify.Write)) == 0 { + continue + } + if event.Op == fsnotify.Write { + if ext := filepath.Ext(event.Name); ext != ".json" && ext != ".yaml" { + continue + } + } + + m.Lock() + if event.Op == fsnotify.Remove && w.tracked[event.Name] { + w.update(dirErrors, event.Name) + } else { + w.update(dirErrors) + } + refresh() + m.Unlock() + + case _, ok := <-watch.Errors: + if !ok { + return + } + } + } +} + +// Update watch with pending/missing or removed directories. +func (w *watch) update(dirErrors map[string]error, removed ...string) bool { + var ( + dir string + ok bool + err error + update bool + ) + + for dir, ok = range w.tracked { + if ok { + continue + } + + err = w.watcher.Add(dir) + if err == nil { + w.tracked[dir] = true + delete(dirErrors, dir) + update = true + } else { + w.tracked[dir] = false + dirErrors[dir] = fmt.Errorf("failed to monitor for changes: %w", err) + } + } + + for _, dir = range removed { + w.tracked[dir] = false + dirErrors[dir] = errors.New("directory removed") + update = true + } + + return update +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_unix.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_unix.go new file mode 100644 index 0000000000..0ee5fb86f5 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_unix.go @@ -0,0 +1,26 @@ +//go:build !windows +// +build !windows + +/* + Copyright © 2021 The CDI 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 cdi + +import "syscall" + +func osSync() { + syscall.Sync() +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_windows.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_windows.go new file mode 100644 index 0000000000..c6dabf5fa8 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache_test_windows.go @@ -0,0 +1,22 @@ +//go:build windows +// +build windows + +/* + Copyright © 2021 The CDI 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 cdi + +func osSync() {} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits.go index 80d88b118a..3e0d24ed8e 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits.go @@ -17,18 +17,16 @@ package cdi import ( + "errors" + "fmt" "os" "path/filepath" "sort" "strings" - "github.com/pkg/errors" - "github.com/container-orchestrated-devices/container-device-interface/specs-go" oci "github.com/opencontainers/runtime-spec/specs-go" ocigen "github.com/opencontainers/runtime-tools/generate" - - runc "github.com/opencontainers/runc/libcontainer/devices" ) const ( @@ -85,11 +83,13 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error { } for _, d := range e.DeviceNodes { - dev := d.ToOCI() - if err := fillMissingInfo(&dev); err != nil { + dn := DeviceNode{d} + + err := dn.fillMissingInfo() + if err != nil { return err } - + dev := d.ToOCI() if dev.UID == nil && spec.Process != nil { if uid := spec.Process.User.UID; uid > 0 { dev.UID = &uid @@ -140,7 +140,7 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error { ensureOCIHooks(spec) spec.Hooks.StartContainer = append(spec.Hooks.StartContainer, h.ToOCI()) default: - return errors.Errorf("unknown hook name %q", h.HookName) + return fmt.Errorf("unknown hook name %q", h.HookName) } } @@ -154,7 +154,7 @@ func (e *ContainerEdits) Validate() error { } if err := ValidateEnv(e.Env); err != nil { - return errors.Wrap(err, "invalid container edits") + return fmt.Errorf("invalid container edits: %w", err) } for _, d := range e.DeviceNodes { if err := (&DeviceNode{d}).Validate(); err != nil { @@ -209,7 +209,7 @@ func (e *ContainerEdits) isEmpty() bool { func ValidateEnv(env []string) error { for _, v := range env { if strings.IndexByte(v, byte('=')) <= 0 { - return errors.Errorf("invalid environment variable %q", v) + return fmt.Errorf("invalid environment variable %q", v) } } return nil @@ -234,11 +234,11 @@ func (d *DeviceNode) Validate() error { return errors.New("invalid (empty) device path") } if _, ok := validTypes[d.Type]; !ok { - return errors.Errorf("device %q: invalid type %q", d.Path, d.Type) + return fmt.Errorf("device %q: invalid type %q", d.Path, d.Type) } for _, bit := range d.Permissions { if bit != 'r' && bit != 'w' && bit != 'm' { - return errors.Errorf("device %q: invalid persmissions %q", + return fmt.Errorf("device %q: invalid persmissions %q", d.Path, d.Permissions) } } @@ -253,13 +253,13 @@ type Hook struct { // Validate a hook. func (h *Hook) Validate() error { if _, ok := validHookNames[h.HookName]; !ok { - return errors.Errorf("invalid hook name %q", h.HookName) + return fmt.Errorf("invalid hook name %q", h.HookName) } if h.Path == "" { - return errors.Errorf("invalid hook %q with empty path", h.HookName) + return fmt.Errorf("invalid hook %q with empty path", h.HookName) } if err := ValidateEnv(h.Env); err != nil { - return errors.Wrapf(err, "invalid hook %q", h.HookName) + return fmt.Errorf("invalid hook %q: %w", h.HookName, err) } return nil } @@ -287,32 +287,6 @@ func ensureOCIHooks(spec *oci.Spec) { } } -// fillMissingInfo fills in missing mandatory attributes from the host device. -func fillMissingInfo(dev *oci.LinuxDevice) error { - if dev.Type != "" && (dev.Major != 0 || dev.Type == "p") { - return nil - } - hostDev, err := runc.DeviceFromPath(dev.Path, "rwm") - if err != nil { - return errors.Wrapf(err, "failed to stat CDI host device %q", dev.Path) - } - - if dev.Type == "" { - dev.Type = string(hostDev.Type) - } else { - if dev.Type != string(hostDev.Type) { - return errors.Errorf("CDI device %q, host type mismatch (%s, %s)", - dev.Path, dev.Type, string(hostDev.Type)) - } - } - if dev.Major == 0 && dev.Type != "p" { - dev.Major = hostDev.Major - dev.Minor = hostDev.Minor - } - - return nil -} - // sortMounts sorts the mounts in the given OCI Spec. func sortMounts(specgen *ocigen.Generator) { mounts := specgen.Mounts() @@ -324,7 +298,8 @@ func sortMounts(specgen *ocigen.Generator) { // orderedMounts defines how to sort an OCI Spec Mount slice. // This is the almost the same implementation sa used by CRI-O and Docker, // with a minor tweak for stable sorting order (easier to test): -// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26 +// +// https://github.com/moby/moby/blob/17.05.x/daemon/volumes.go#L26 type orderedMounts []oci.Mount // Len returns the number of mounts. Used in sorting. diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_unix.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_unix.go new file mode 100644 index 0000000000..11a4cfe8c1 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_unix.go @@ -0,0 +1,57 @@ +//go:build !windows +// +build !windows + +/* + Copyright © 2021 The CDI 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 cdi + +import ( + "fmt" + + runc "github.com/opencontainers/runc/libcontainer/devices" +) + +// fillMissingInfo fills in missing mandatory attributes from the host device. +func (d *DeviceNode) fillMissingInfo() error { + if d.HostPath == "" { + d.HostPath = d.Path + } + + if d.Type != "" && (d.Major != 0 || d.Type == "p") { + return nil + } + + hostDev, err := runc.DeviceFromPath(d.HostPath, "rwm") + if err != nil { + return fmt.Errorf("failed to stat CDI host device %q: %w", d.HostPath, err) + } + + if d.Type == "" { + d.Type = string(hostDev.Type) + } else { + if d.Type != string(hostDev.Type) { + return fmt.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)", + d.Path, d.HostPath, d.Type, string(hostDev.Type)) + } + } + if d.Major == 0 && d.Type != "p" { + d.Major = hostDev.Major + d.Minor = hostDev.Minor + } + + return nil +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_windows.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_windows.go new file mode 100644 index 0000000000..fd91afa926 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits_windows.go @@ -0,0 +1,27 @@ +//go:build windows +// +build windows + +/* + Copyright © 2021 The CDI 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 cdi + +import "fmt" + +// fillMissingInfo fills in missing mandatory attributes from the host device. +func (d *DeviceNode) fillMissingInfo() error { + return fmt.Errorf("unimplemented") +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/device.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/device.go index 0bb1f531bd..7b16a3134d 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/device.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/device.go @@ -17,9 +17,10 @@ package cdi import ( + "fmt" + cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go" oci "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" ) // Device represents a CDI device of a Spec. @@ -69,10 +70,10 @@ func (d *Device) validate() error { } edits := d.edits() if edits.isEmpty() { - return errors.Errorf("invalid device, empty device edits") + return fmt.Errorf("invalid device, empty device edits") } if err := edits.Validate(); err != nil { - return errors.Wrapf(err, "invalid device %q", d.Name) + return fmt.Errorf("invalid device %q: %w", d.Name, err) } return nil } diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go index a9017259c8..ab063a138f 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go @@ -46,7 +46,6 @@ // "fmt" // "strings" // -// "github.com/pkg/errors" // log "github.com/sirupsen/logrus" // // "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" @@ -58,7 +57,7 @@ // // unresolved, err := cdi.GetRegistry().InjectDevices(spec, devices) // if err != nil { -// return errors.Wrap(err, "CDI device injection failed") +// return fmt.Errorf("CDI device injection failed: %w", err) // } // // log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec)) @@ -67,6 +66,21 @@ // // Cache Refresh // +// By default the CDI Spec cache monitors the configured Spec directories +// and automatically refreshes itself when necessary. This behavior can be +// disabled using the WithAutoRefresh(false) option. +// +// Failure to set up monitoring for a Spec directory causes the directory to +// get ignored and an error to be recorded among the Spec directory errors. +// These errors can be queried using the GetSpecDirErrors() function. If the +// error condition is transient, for instance a missing directory which later +// gets created, the corresponding error will be removed once the condition +// is over. +// +// With auto-refresh enabled injecting any CDI devices can be done without +// an explicit call to Refresh(), using a code snippet similar to the +// following: +// // In a runtime implementation one typically wants to make sure the // CDI Spec cache is up to date before performing device injection. // A code snippet similar to the following accmplishes that: @@ -75,7 +89,6 @@ // "fmt" // "strings" // -// "github.com/pkg/errors" // log "github.com/sirupsen/logrus" // // "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" @@ -100,7 +113,7 @@ // // unresolved, err := registry.InjectDevices(spec, devices) // if err != nil { -// return errors.Wrap(err, "CDI device injection failed") +// return fmt.Errorf("CDI device injection failed: %w", err) // } // // log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec)) @@ -109,10 +122,15 @@ // // Generated Spec Files, Multiple Directories, Device Precedence // -// There are systems where the set of available or usable CDI devices -// changes dynamically and this needs to be reflected in the CDI Specs. -// This is done by dynamically regenerating CDI Spec files which are -// affected by these changes. +// It is often necessary to generate Spec files dynamically. On some +// systems the available or usable set of CDI devices might change +// dynamically which then needs to be reflected in CDI Specs. For +// some device classes it makes sense to enumerate the available +// devices at every boot and generate Spec file entries for each +// device found. Some CDI devices might need special client- or +// request-specific configuration which can only be fulfilled by +// dynamically generated client-specific entries in transient Spec +// files. // // CDI can collect Spec files from multiple directories. Spec files are // automatically assigned priorities according to which directory they @@ -126,7 +144,111 @@ // separating dynamically generated CDI Spec files from static ones. // The default directories are '/etc/cdi' and '/var/run/cdi'. By putting // dynamically generated Spec files under '/var/run/cdi', those take -// precedence over static ones in '/etc/cdi'. +// precedence over static ones in '/etc/cdi'. With this scheme, static +// Spec files, typically installed by distro-specific packages, go into +// '/etc/cdi' while all the dynamically generated Spec files, transient +// or other, go into '/var/run/cdi'. +// +// Spec File Generation +// +// CDI offers two functions for writing and removing dynamically generated +// Specs from CDI Spec directories. These functions, WriteSpec() and +// RemoveSpec() implicitly follow the principle of separating dynamic Specs +// from the rest and therefore always write to and remove Specs from the +// last configured directory. +// +// Corresponding functions are also provided for generating names for Spec +// files. These functions follow a simple naming convention to ensure that +// multiple entities generating Spec files simultaneously on the same host +// do not end up using conflicting Spec file names. GenerateSpecName(), +// GenerateNameForSpec(), GenerateTransientSpecName(), and +// GenerateTransientNameForSpec() all generate names which can be passed +// as such to WriteSpec() and subsequently to RemoveSpec(). +// +// Generating a Spec file for a vendor/device class can be done with a +// code snippet similar to the following: +// +// import ( +// "fmt" +// ... +// "github.com/container-orchestrated-devices/container-device-interface/specs-go" +// "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" +// ) +// +// func generateDeviceSpecs() error { +// registry := cdi.GetRegistry() +// spec := &specs.Spec{ +// Version: specs.CurrentVersion, +// Kind: vendor+"/"+class, +// } +// +// for _, dev := range enumerateDevices() { +// spec.Devices = append(spec.Devices, specs.Device{ +// Name: dev.Name, +// ContainerEdits: getContainerEditsForDevice(dev), +// }) +// } +// +// specName, err := cdi.GenerateNameForSpec(spec) +// if err != nil { +// return fmt.Errorf("failed to generate Spec name: %w", err) +// } +// +// return registry.SpecDB().WriteSpec(spec, specName) +// } +// +// Similary, generating and later cleaning up transient Spec files can be +// done with code fragments similar to the following. These transient Spec +// files are temporary Spec files with container-specific parametrization. +// They are typically created before the associated container is created +// and removed once that container is removed. +// +// import ( +// "fmt" +// ... +// "github.com/container-orchestrated-devices/container-device-interface/specs-go" +// "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi" +// ) +// +// func generateTransientSpec(ctr Container) error { +// registry := cdi.GetRegistry() +// devices := getContainerDevs(ctr, vendor, class) +// spec := &specs.Spec{ +// Version: specs.CurrentVersion, +// Kind: vendor+"/"+class, +// } +// +// for _, dev := range devices { +// spec.Devices = append(spec.Devices, specs.Device{ +// // the generated name needs to be unique within the +// // vendor/class domain on the host/node. +// Name: generateUniqueDevName(dev, ctr), +// ContainerEdits: getEditsForContainer(dev), +// }) +// } +// +// // transientID is expected to guarantee that the Spec file name +// // generated using is unique within +// // the host/node. If more than one device is allocated with the +// // same vendor/class domain, either all generated Spec entries +// // should go to a single Spec file (like in this sample snippet), +// // or transientID should be unique for each generated Spec file. +// transientID := getSomeSufficientlyUniqueIDForContainer(ctr) +// specName, err := cdi.GenerateNameForTransientSpec(vendor, class, transientID) +// if err != nil { +// return fmt.Errorf("failed to generate Spec name: %w", err) +// } +// +// return registry.SpecDB().WriteSpec(spec, specName) +// } +// +// func removeTransientSpec(ctr Container) error { +// registry := cdi.GetRegistry() +// transientID := getSomeSufficientlyUniqueIDForContainer(ctr) +// specName := cdi.GenerateNameForTransientSpec(vendor, class, transientID) +// +// return registry.SpecDB().RemoveSpec(specName) +// } // // CDI Spec Validation // @@ -146,5 +268,5 @@ // schema names which switch the used schema to the in-repo validation // schema embedded into the binary or the now default no-op schema // correspondingly. Other names are interpreted as the path to the actual -/// validation schema to load and use. +// validation schema to load and use. package cdi diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/qualified-device.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/qualified-device.go index 54f19143c6..4fe3cfe47f 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/qualified-device.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/qualified-device.go @@ -17,9 +17,8 @@ package cdi import ( + "fmt" "strings" - - "github.com/pkg/errors" ) // QualifiedName returns the qualified name for a device. @@ -50,23 +49,23 @@ func ParseQualifiedName(device string) (string, string, string, error) { vendor, class, name := ParseDevice(device) if vendor == "" { - return "", "", device, errors.Errorf("unqualified device %q, missing vendor", device) + return "", "", device, fmt.Errorf("unqualified device %q, missing vendor", device) } if class == "" { - return "", "", device, errors.Errorf("unqualified device %q, missing class", device) + return "", "", device, fmt.Errorf("unqualified device %q, missing class", device) } if name == "" { - return "", "", device, errors.Errorf("unqualified device %q, missing device name", device) + return "", "", device, fmt.Errorf("unqualified device %q, missing device name", device) } if err := ValidateVendorName(vendor); err != nil { - return "", "", device, errors.Wrapf(err, "invalid device %q", device) + return "", "", device, fmt.Errorf("invalid device %q: %w", device, err) } if err := ValidateClassName(class); err != nil { - return "", "", device, errors.Wrapf(err, "invalid device %q", device) + return "", "", device, fmt.Errorf("invalid device %q: %w", device, err) } if err := ValidateDeviceName(name); err != nil { - return "", "", device, errors.Wrapf(err, "invalid device %q", device) + return "", "", device, fmt.Errorf("invalid device %q: %w", device, err) } return vendor, class, name, nil @@ -115,22 +114,22 @@ func ParseQualifier(kind string) (string, string) { // - underscore, dash, and dot ('_', '-', and '.') func ValidateVendorName(vendor string) error { if vendor == "" { - return errors.Errorf("invalid (empty) vendor name") + return fmt.Errorf("invalid (empty) vendor name") } if !isLetter(rune(vendor[0])) { - return errors.Errorf("invalid vendor %q, should start with letter", vendor) + return fmt.Errorf("invalid vendor %q, should start with letter", vendor) } for _, c := range string(vendor[1 : len(vendor)-1]) { switch { case isAlphaNumeric(c): case c == '_' || c == '-' || c == '.': default: - return errors.Errorf("invalid character '%c' in vendor name %q", + return fmt.Errorf("invalid character '%c' in vendor name %q", c, vendor) } } if !isAlphaNumeric(rune(vendor[len(vendor)-1])) { - return errors.Errorf("invalid vendor %q, should end with letter", vendor) + return fmt.Errorf("invalid vendor %q, should end with a letter or digit", vendor) } return nil @@ -143,22 +142,22 @@ func ValidateVendorName(vendor string) error { // - underscore and dash ('_', '-') func ValidateClassName(class string) error { if class == "" { - return errors.Errorf("invalid (empty) device class") + return fmt.Errorf("invalid (empty) device class") } if !isLetter(rune(class[0])) { - return errors.Errorf("invalid class %q, should start with letter", class) + return fmt.Errorf("invalid class %q, should start with letter", class) } for _, c := range string(class[1 : len(class)-1]) { switch { case isAlphaNumeric(c): case c == '_' || c == '-': default: - return errors.Errorf("invalid character '%c' in device class %q", + return fmt.Errorf("invalid character '%c' in device class %q", c, class) } } if !isAlphaNumeric(rune(class[len(class)-1])) { - return errors.Errorf("invalid class %q, should end with letter", class) + return fmt.Errorf("invalid class %q, should end with a letter or digit", class) } return nil } @@ -170,22 +169,25 @@ func ValidateClassName(class string) error { // - underscore, dash, dot, colon ('_', '-', '.', ':') func ValidateDeviceName(name string) error { if name == "" { - return errors.Errorf("invalid (empty) device name") + return fmt.Errorf("invalid (empty) device name") + } + if !isAlphaNumeric(rune(name[0])) { + return fmt.Errorf("invalid class %q, should start with a letter or digit", name) } - if !isLetter(rune(name[0])) { - return errors.Errorf("invalid name %q, should start with letter", name) + if len(name) == 1 { + return nil } for _, c := range string(name[1 : len(name)-1]) { switch { case isAlphaNumeric(c): case c == '_' || c == '-' || c == '.' || c == ':': default: - return errors.Errorf("invalid character '%c' in device name %q", + return fmt.Errorf("invalid character '%c' in device name %q", c, name) } } if !isAlphaNumeric(rune(name[len(name)-1])) { - return errors.Errorf("invalid name %q, should start with letter", name) + return fmt.Errorf("invalid name %q, should end with a letter or digit", name) } return nil } diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/registry.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/registry.go index fa6e0af693..10fab8997e 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/registry.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/registry.go @@ -19,6 +19,7 @@ package cdi import ( "sync" + cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go" oci "github.com/opencontainers/runtime-spec/specs-go" ) @@ -40,6 +41,8 @@ type Registry interface { // RegistryRefresher is the registry interface for refreshing the // cache of CDI Specs and devices. // +// Configure reconfigures the registry with the given options. +// // Refresh rescans all CDI Spec directories and updates the // state of the cache to reflect any changes. It returns any // errors encountered during the refresh. @@ -50,10 +53,15 @@ type Registry interface { // GetSpecDirectories returns the set up CDI Spec directories // currently in use. The directories are returned in the scan // order of Refresh(). +// +// GetSpecDirErrors returns any errors related to the configured +// Spec directories. type RegistryRefresher interface { + Configure(...Option) error Refresh() error GetErrors() map[string][]error GetSpecDirectories() []string + GetSpecDirErrors() map[string]error } // RegistryResolver is the registry interface for injecting CDI @@ -90,11 +98,16 @@ type RegistryDeviceDB interface { // // GetSpecErrors returns any errors for the Spec encountered during // the last cache refresh. +// +// WriteSpec writes the Spec with the given content and name to the +// last Spec directory. type RegistrySpecDB interface { ListVendors() []string ListClasses() []string GetVendorSpecs(vendor string) []*Spec GetSpecErrors(*Spec) []error + WriteSpec(raw *cdi.Spec, name string) error + RemoveSpec(name string) error } type registry struct { diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec-dirs.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec-dirs.go index ad017fec7e..f339349bba 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec-dirs.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec-dirs.go @@ -17,10 +17,10 @@ package cdi import ( + "errors" + "io/fs" "os" "path/filepath" - - "github.com/pkg/errors" ) const ( @@ -45,10 +45,11 @@ var ( // WithSpecDirs returns an option to override the CDI Spec directories. func WithSpecDirs(dirs ...string) Option { return func(c *Cache) error { - c.specDirs = make([]string, len(dirs)) + specDirs := make([]string, len(dirs)) for i, dir := range dirs { - c.specDirs[i] = filepath.Clean(dir) + specDirs[i] = filepath.Clean(dir) } + c.specDirs = specDirs return nil } } @@ -78,6 +79,9 @@ func scanSpecDirs(dirs []string, scanFn scanSpecFunc) error { err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { // for initial stat failure Walk calls us with nil info if info == nil { + if errors.Is(err, fs.ErrNotExist) { + return nil + } return err } // first call from Walk is for dir itself, others we skip diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go index 46fca2dacd..fe20e6dd12 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go @@ -17,28 +17,29 @@ package cdi import ( + "encoding/json" + "fmt" "io/ioutil" "os" "path/filepath" + "strings" + "sync" oci "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" "sigs.k8s.io/yaml" cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go" ) -var ( - // Valid CDI Spec versions. - validSpecVersions = map[string]struct{}{ - "0.1.0": {}, - "0.2.0": {}, - "0.3.0": {}, - "0.4.0": {}, - } +const ( + // defaultSpecExt is the file extension for the default encoding. + defaultSpecExt = ".yaml" +) +var ( // Externally set CDI Spec validation function. specValidator func(*cdi.Spec) error + validatorLock sync.RWMutex ) // Spec represents a single CDI Spec. It is usually loaded from a @@ -65,18 +66,18 @@ func ReadSpec(path string, priority int) (*Spec, error) { case os.IsNotExist(err): return nil, err case err != nil: - return nil, errors.Wrapf(err, "failed to read CDI Spec %q", path) + return nil, fmt.Errorf("failed to read CDI Spec %q: %w", path, err) } - raw, err := parseSpec(data) + raw, err := ParseSpec(data) if err != nil { - return nil, errors.Wrapf(err, "failed to parse CDI Spec %q", path) + return nil, fmt.Errorf("failed to parse CDI Spec %q: %w", path, err) } if raw == nil { - return nil, errors.Errorf("failed to parse CDI Spec %q, no Spec data", path) + return nil, fmt.Errorf("failed to parse CDI Spec %q, no Spec data", path) } - spec, err := NewSpec(raw, path, priority) + spec, err := newSpec(raw, path, priority) if err != nil { return nil, err } @@ -84,11 +85,11 @@ func ReadSpec(path string, priority int) (*Spec, error) { return spec, nil } -// NewSpec creates a new Spec from the given CDI Spec data. The +// newSpec creates a new Spec from the given CDI Spec data. The // Spec is marked as loaded from the given path with the given -// priority. If Spec data validation fails NewSpec returns a nil +// priority. If Spec data validation fails newSpec returns a nil // Spec and an error. -func NewSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) { +func newSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) { err := validateSpec(raw) if err != nil { return nil, err @@ -100,15 +101,69 @@ func NewSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) { priority: priority, } + if ext := filepath.Ext(spec.path); ext != ".yaml" && ext != ".json" { + spec.path += defaultSpecExt + } + spec.vendor, spec.class = ParseQualifier(spec.Kind) if spec.devices, err = spec.validate(); err != nil { - return nil, errors.Wrap(err, "invalid CDI Spec") + return nil, fmt.Errorf("invalid CDI Spec: %w", err) } return spec, nil } +// Write the CDI Spec to the file associated with it during instantiation +// by newSpec() or ReadSpec(). +func (s *Spec) write(overwrite bool) error { + var ( + data []byte + dir string + tmp *os.File + err error + ) + + err = validateSpec(s.Spec) + if err != nil { + return err + } + + if filepath.Ext(s.path) == ".yaml" { + data, err = yaml.Marshal(s.Spec) + } else { + data, err = json.Marshal(s.Spec) + } + if err != nil { + return fmt.Errorf("failed to marshal Spec file: %w", err) + } + + dir = filepath.Dir(s.path) + err = os.MkdirAll(dir, 0o755) + if err != nil { + return fmt.Errorf("failed to create Spec dir: %w", err) + } + + tmp, err = os.CreateTemp(dir, "spec.*.tmp") + if err != nil { + return fmt.Errorf("failed to create Spec file: %w", err) + } + _, err = tmp.Write(data) + tmp.Close() + if err != nil { + return fmt.Errorf("failed to write Spec file: %w", err) + } + + err = renameIn(dir, filepath.Base(tmp.Name()), filepath.Base(s.path), overwrite) + + if err != nil { + os.Remove(tmp.Name()) + err = fmt.Errorf("failed to write Spec file: %w", err) + } + + return err +} + // GetVendor returns the vendor of this Spec. func (s *Spec) GetVendor() string { return s.vendor @@ -149,6 +204,15 @@ func (s *Spec) validate() (map[string]*Device, error) { if err := validateVersion(s.Version); err != nil { return nil, err } + + minVersion, err := MinimumRequiredVersion(s.Spec) + if err != nil { + return nil, fmt.Errorf("could not determine minumum required version: %v", err) + } + if newVersion(minVersion).IsGreaterThan(newVersion(s.Version)) { + return nil, fmt.Errorf("the spec version must be at least v%v", minVersion) + } + if err := ValidateVendorName(s.vendor); err != nil { return nil, err } @@ -163,10 +227,10 @@ func (s *Spec) validate() (map[string]*Device, error) { for _, d := range s.Devices { dev, err := newDevice(s, d) if err != nil { - return nil, errors.Wrapf(err, "failed add device %q", d.Name) + return nil, fmt.Errorf("failed add device %q: %w", d.Name, err) } if _, conflict := devices[d.Name]; conflict { - return nil, errors.Errorf("invalid spec, multiple device %q", d.Name) + return nil, fmt.Errorf("invalid spec, multiple device %q", d.Name) } devices[d.Name] = dev } @@ -176,38 +240,108 @@ func (s *Spec) validate() (map[string]*Device, error) { // validateVersion checks whether the specified spec version is supported. func validateVersion(version string) error { - if _, ok := validSpecVersions[version]; !ok { - return errors.Errorf("invalid version %q", version) + if !validSpecVersions.isValidVersion(version) { + return fmt.Errorf("invalid version %q", version) } return nil } -// Parse raw CDI Spec file data. -func parseSpec(data []byte) (*cdi.Spec, error) { +// ParseSpec parses CDI Spec data into a raw CDI Spec. +func ParseSpec(data []byte) (*cdi.Spec, error) { var raw *cdi.Spec err := yaml.UnmarshalStrict(data, &raw) if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal CDI Spec") + return nil, fmt.Errorf("failed to unmarshal CDI Spec: %w", err) } return raw, nil } // SetSpecValidator sets a CDI Spec validator function. This function // is used for extra CDI Spec content validation whenever a Spec file -// loaded (using ReadSpec() or NewSpec()) or written (Spec.Write()). +// loaded (using ReadSpec() or written (using WriteSpec()). func SetSpecValidator(fn func(*cdi.Spec) error) { + validatorLock.Lock() + defer validatorLock.Unlock() specValidator = fn } // validateSpec validates the Spec using the extneral validator. func validateSpec(raw *cdi.Spec) error { + validatorLock.RLock() + defer validatorLock.RUnlock() + if specValidator == nil { return nil } err := specValidator(raw) if err != nil { - return errors.Wrap(err, "Spec validation failed") + return fmt.Errorf("Spec validation failed: %w", err) } return nil } + +// GenerateSpecName generates a vendor+class scoped Spec file name. The +// name can be passed to WriteSpec() to write a Spec file to the file +// system. +// +// vendor and class should match the vendor and class of the CDI Spec. +// The file name is generated without a ".json" or ".yaml" extension. +// The caller can append the desired extension to choose a particular +// encoding. Otherwise WriteSpec() will use its default encoding. +// +// This function always returns the same name for the same vendor/class +// combination. Therefore it cannot be used as such to generate multiple +// Spec file names for a single vendor and class. +func GenerateSpecName(vendor, class string) string { + return vendor + "-" + class +} + +// GenerateTransientSpecName generates a vendor+class scoped transient +// Spec file name. The name can be passed to WriteSpec() to write a Spec +// file to the file system. +// +// Transient Specs are those whose lifecycle is tied to that of some +// external entity, for instance a container. vendor and class should +// match the vendor and class of the CDI Spec. transientID should be +// unique among all CDI users on the same host that might generate +// transient Spec files using the same vendor/class combination. If +// the external entity to which the lifecycle of the tranient Spec +// is tied to has a unique ID of its own, then this is usually a +// good choice for transientID. +// +// The file name is generated without a ".json" or ".yaml" extension. +// The caller can append the desired extension to choose a particular +// encoding. Otherwise WriteSpec() will use its default encoding. +func GenerateTransientSpecName(vendor, class, transientID string) string { + transientID = strings.ReplaceAll(transientID, "/", "_") + return GenerateSpecName(vendor, class) + "_" + transientID +} + +// GenerateNameForSpec generates a name for the given Spec using +// GenerateSpecName with the vendor and class taken from the Spec. +// On success it returns the generated name and a nil error. If +// the Spec does not contain a valid vendor or class, it returns +// an empty name and a non-nil error. +func GenerateNameForSpec(raw *cdi.Spec) (string, error) { + vendor, class := ParseQualifier(raw.Kind) + if vendor == "" { + return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind) + } + + return GenerateSpecName(vendor, class), nil +} + +// GenerateNameForTransientSpec generates a name for the given transient +// Spec using GenerateTransientSpecName with the vendor and class taken +// from the Spec. On success it returns the generated name and a nil error. +// If the Spec does not contain a valid vendor or class, it returns an +// an empty name and a non-nil error. +func GenerateNameForTransientSpec(raw *cdi.Spec, transientID string) (string, error) { + vendor, class := ParseQualifier(raw.Kind) + if vendor == "" { + return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind) + } + + return GenerateTransientSpecName(vendor, class, transientID), nil +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_linux.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_linux.go new file mode 100644 index 0000000000..9ad2739256 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_linux.go @@ -0,0 +1,48 @@ +/* + Copyright © 2022 The CDI 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 cdi + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +// Rename src to dst, both relative to the directory dir. If dst already exists +// refuse renaming with an error unless overwrite is explicitly asked for. +func renameIn(dir, src, dst string, overwrite bool) error { + var flags uint + + dirf, err := os.Open(dir) + if err != nil { + return fmt.Errorf("rename failed: %w", err) + } + defer dirf.Close() + + if !overwrite { + flags = unix.RENAME_NOREPLACE + } + + dirFd := int(dirf.Fd()) + err = unix.Renameat2(dirFd, src, dirFd, dst, flags) + if err != nil { + return fmt.Errorf("rename failed: %w", err) + } + + return nil +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_other.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_other.go new file mode 100644 index 0000000000..285e04e27a --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec_other.go @@ -0,0 +1,39 @@ +//go:build !linux +// +build !linux + +/* + Copyright © 2022 The CDI 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 cdi + +import ( + "os" + "path/filepath" +) + +// Rename src to dst, both relative to the directory dir. If dst already exists +// refuse renaming with an error unless overwrite is explicitly asked for. +func renameIn(dir, src, dst string, overwrite bool) error { + src = filepath.Join(dir, src) + dst = filepath.Join(dir, dst) + + _, err := os.Stat(dst) + if err == nil && !overwrite { + return os.ErrExist + } + + return os.Rename(src, dst) +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/version.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/version.go new file mode 100644 index 0000000000..08b36a3205 --- /dev/null +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/version.go @@ -0,0 +1,160 @@ +/* + Copyright © The CDI 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 cdi + +import ( + "strings" + + "golang.org/x/mod/semver" + + cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go" +) + +const ( + // CurrentVersion is the current version of the CDI Spec. + CurrentVersion = cdi.CurrentVersion + + // vCurrent is the current version as a semver-comparable type + vCurrent version = "v" + CurrentVersion + + // These represent the released versions of the CDI specification + v010 version = "v0.1.0" + v020 version = "v0.2.0" + v030 version = "v0.3.0" + v040 version = "v0.4.0" + v050 version = "v0.5.0" + + // vEarliest is the earliest supported version of the CDI specification + vEarliest version = v030 +) + +// validSpecVersions stores a map of spec versions to functions to check the required versions. +// Adding new fields / spec versions requires that a `requiredFunc` be implemented and +// this map be updated. +var validSpecVersions = requiredVersionMap{ + v010: nil, + v020: nil, + v030: nil, + v040: requiresV040, + v050: requiresV050, +} + +// MinimumRequiredVersion determines the minumum spec version for the input spec. +func MinimumRequiredVersion(spec *cdi.Spec) (string, error) { + minVersion := validSpecVersions.requiredVersion(spec) + return minVersion.String(), nil +} + +// version represents a semantic version string +type version string + +// newVersion creates a version that can be used for semantic version comparisons. +func newVersion(v string) version { + return version("v" + strings.TrimPrefix(v, "v")) +} + +// String returns the string representation of the version. +// This trims a leading v if present. +func (v version) String() string { + return strings.TrimPrefix(string(v), "v") +} + +// IsGreaterThan checks with a version is greater than the specified version. +func (v version) IsGreaterThan(o version) bool { + return semver.Compare(string(v), string(o)) > 0 +} + +// IsLatest checks whether the version is the latest supported version +func (v version) IsLatest() bool { + return v == vCurrent +} + +type requiredFunc func(*cdi.Spec) bool + +type requiredVersionMap map[version]requiredFunc + +// isValidVersion checks whether the specified version is valid. +// A version is valid if it is contained in the required version map. +func (r requiredVersionMap) isValidVersion(specVersion string) bool { + _, ok := validSpecVersions[newVersion(specVersion)] + + return ok +} + +// requiredVersion returns the minimum version required for the given spec +func (r requiredVersionMap) requiredVersion(spec *cdi.Spec) version { + minVersion := vEarliest + + for v, isRequired := range validSpecVersions { + if isRequired == nil { + continue + } + if isRequired(spec) && v.IsGreaterThan(minVersion) { + minVersion = v + } + // If we have already detected the latest version then no later version could be detected + if minVersion.IsLatest() { + break + } + } + + return minVersion +} + +// requiresV050 returns true if the spec uses v0.5.0 features +func requiresV050(spec *cdi.Spec) bool { + var edits []*cdi.ContainerEdits + + for _, d := range spec.Devices { + // The v0.5.0 spec allowed device names to start with a digit instead of requiring a letter + if len(d.Name) > 0 && !isLetter(rune(d.Name[0])) { + return true + } + edits = append(edits, &d.ContainerEdits) + } + + edits = append(edits, &spec.ContainerEdits) + for _, e := range edits { + for _, dn := range e.DeviceNodes { + // The HostPath field was added in v0.5.0 + if dn.HostPath != "" { + return true + } + } + } + return false +} + +// requiresV040 returns true if the spec uses v0.4.0 features +func requiresV040(spec *cdi.Spec) bool { + var edits []*cdi.ContainerEdits + + for _, d := range spec.Devices { + edits = append(edits, &d.ContainerEdits) + } + + edits = append(edits, &spec.ContainerEdits) + for _, e := range edits { + for _, m := range e.Mounts { + // The Type field was added in v0.4.0 + if m.Type != "" { + return true + } + } + } + return false +} diff --git a/vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/config.go b/vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/config.go index e16174f9d1..3fa2e814bd 100644 --- a/vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/config.go +++ b/vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/config.go @@ -3,7 +3,7 @@ package specs import "os" // CurrentVersion is the current version of the Spec. -const CurrentVersion = "0.4.0" +const CurrentVersion = "0.5.0" // Spec is the base configuration for CDI type Spec struct { @@ -31,6 +31,7 @@ type ContainerEdits struct { // DeviceNode represents a device node that needs to be added to the OCI spec. type DeviceNode struct { Path string `json:"path"` + HostPath string `json:"hostPath,omitempty"` Type string `json:"type,omitempty"` Major int64 `json:"major,omitempty"` Minor int64 `json:"minor,omitempty"` diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go index c0e8794482..7e9122103c 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go @@ -12,6 +12,8 @@ type Spec struct { Root *Root `json:"root,omitempty"` // Hostname configures the container's hostname. Hostname string `json:"hostname,omitempty"` + // Domainname configures the container's domainname. + Domainname string `json:"domainname,omitempty"` // Mounts configures additional mounts (on top of Root). Mounts []Mount `json:"mounts,omitempty"` // Hooks configures callbacks for container lifecycle events. @@ -117,6 +119,11 @@ type Mount struct { Source string `json:"source,omitempty"` // Options are fstab style mount options. Options []string `json:"options,omitempty"` + + // UID/GID mappings used for changing file owners w/o calling chown, fs should support it. + // Every mount point could have its own mapping. + UIDMappings []LinuxIDMapping `json:"uidMappings,omitempty" platform:"linux"` + GIDMappings []LinuxIDMapping `json:"gidMappings,omitempty" platform:"linux"` } // Hook specifies a command that is run at a particular event in the lifecycle of a container @@ -252,8 +259,8 @@ type LinuxInterfacePriority struct { Priority uint32 `json:"priority"` } -// linuxBlockIODevice holds major:minor format supported in blkio cgroup -type linuxBlockIODevice struct { +// LinuxBlockIODevice holds major:minor format supported in blkio cgroup +type LinuxBlockIODevice struct { // Major is the device's major number. Major int64 `json:"major"` // Minor is the device's minor number. @@ -262,7 +269,7 @@ type linuxBlockIODevice struct { // LinuxWeightDevice struct holds a `major:minor weight` pair for weightDevice type LinuxWeightDevice struct { - linuxBlockIODevice + LinuxBlockIODevice // Weight is the bandwidth rate for the device. Weight *uint16 `json:"weight,omitempty"` // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, CFQ scheduler only @@ -271,7 +278,7 @@ type LinuxWeightDevice struct { // LinuxThrottleDevice struct holds a `major:minor rate_per_second` pair type LinuxThrottleDevice struct { - linuxBlockIODevice + LinuxBlockIODevice // Rate is the IO rate limit per cgroup per device Rate uint64 `json:"rate"` } @@ -330,6 +337,8 @@ type LinuxCPU struct { Cpus string `json:"cpus,omitempty"` // List of memory nodes in the cpuset. Default is to use any available memory node. Mems string `json:"mems,omitempty"` + // cgroups are configured with minimum weight, 0: default behavior, 1: SCHED_IDLE. + Idle *int64 `json:"idle,omitempty"` } // LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3) @@ -524,11 +533,21 @@ type WindowsMemoryResources struct { // WindowsCPUResources contains CPU resource management settings. type WindowsCPUResources struct { - // Number of CPUs available to the container. + // Count is the number of CPUs available to the container. It represents the + // fraction of the configured processor `count` in a container in relation + // to the processors available in the host. The fraction ultimately + // determines the portion of processor cycles that the threads in a + // container can use during each scheduling interval, as the number of + // cycles per 10,000 cycles. Count *uint64 `json:"count,omitempty"` - // CPU shares (relative weight to other containers with cpu shares). + // Shares limits the share of processor time given to the container relative + // to other workloads on the processor. The processor `shares` (`weight` at + // the platform level) is a value between 0 and 10000. Shares *uint16 `json:"shares,omitempty"` - // Specifies the portion of processor cycles that this container can use as a percentage times 100. + // Maximum determines the portion of processor cycles that the threads in a + // container can use during each scheduling interval, as the number of + // cycles per 10,000 cycles. Set processor `maximum` to a percentage times + // 100. Maximum *uint16 `json:"maximum,omitempty"` } @@ -615,6 +634,19 @@ type Arch string // LinuxSeccompFlag is a flag to pass to seccomp(2). type LinuxSeccompFlag string +const ( + // LinuxSeccompFlagLog is a seccomp flag to request all returned + // actions except SECCOMP_RET_ALLOW to be logged. An administrator may + // override this filter flag by preventing specific actions from being + // logged via the /proc/sys/kernel/seccomp/actions_logged file. (since + // Linux 4.14) + LinuxSeccompFlagLog LinuxSeccompFlag = "SECCOMP_FILTER_FLAG_LOG" + + // LinuxSeccompFlagSpecAllow can be used to disable Speculative Store + // Bypass mitigation. (since Linux 4.17) + LinuxSeccompFlagSpecAllow LinuxSeccompFlag = "SECCOMP_FILTER_FLAG_SPEC_ALLOW" +) + // Additional architectures permitted to be used for system calls // By default only the native architecture of the kernel is permitted const ( diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go index f4e77ee1e9..4d66b320dc 100644 --- a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go +++ b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go @@ -10,7 +10,7 @@ import ( rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate/seccomp" - "github.com/opencontainers/runtime-tools/validate" + capsCheck "github.com/opencontainers/runtime-tools/validate/capabilities" "github.com/syndtr/gocapability/capability" ) @@ -264,10 +264,6 @@ func New(os string) (generator Generator, err error) { // NewFromSpec creates a configuration Generator from a given // configuration. -// -// Deprecated: Replace with: -// -// generator := Generator{Config: config} func NewFromSpec(config *rspec.Spec) Generator { envCache := map[string]int{} if config != nil && config.Process != nil { @@ -1140,7 +1136,7 @@ func (g *Generator) SetupPrivileged(privileged bool) { if privileged { // Add all capabilities in privileged mode. var finalCapList []string for _, cap := range capability.List() { - if g.HostSpecific && cap > validate.LastCap() { + if g.HostSpecific && cap > capsCheck.LastCap() { continue } finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))) @@ -1174,7 +1170,7 @@ func (g *Generator) ClearProcessCapabilities() { // AddProcessCapability adds a process capability into all 5 capability sets. func (g *Generator) AddProcessCapability(c string) error { cp := strings.ToUpper(c) - if err := validate.CapValid(cp, g.HostSpecific); err != nil { + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { return err } @@ -1237,7 +1233,7 @@ func (g *Generator) AddProcessCapability(c string) error { // AddProcessCapabilityAmbient adds a process capability into g.Config.Process.Capabilities.Ambient. func (g *Generator) AddProcessCapabilityAmbient(c string) error { cp := strings.ToUpper(c) - if err := validate.CapValid(cp, g.HostSpecific); err != nil { + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { return err } @@ -1261,7 +1257,7 @@ func (g *Generator) AddProcessCapabilityAmbient(c string) error { // AddProcessCapabilityBounding adds a process capability into g.Config.Process.Capabilities.Bounding. func (g *Generator) AddProcessCapabilityBounding(c string) error { cp := strings.ToUpper(c) - if err := validate.CapValid(cp, g.HostSpecific); err != nil { + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { return err } @@ -1284,7 +1280,7 @@ func (g *Generator) AddProcessCapabilityBounding(c string) error { // AddProcessCapabilityEffective adds a process capability into g.Config.Process.Capabilities.Effective. func (g *Generator) AddProcessCapabilityEffective(c string) error { cp := strings.ToUpper(c) - if err := validate.CapValid(cp, g.HostSpecific); err != nil { + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { return err } @@ -1307,7 +1303,7 @@ func (g *Generator) AddProcessCapabilityEffective(c string) error { // AddProcessCapabilityInheritable adds a process capability into g.Config.Process.Capabilities.Inheritable. func (g *Generator) AddProcessCapabilityInheritable(c string) error { cp := strings.ToUpper(c) - if err := validate.CapValid(cp, g.HostSpecific); err != nil { + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { return err } @@ -1330,7 +1326,7 @@ func (g *Generator) AddProcessCapabilityInheritable(c string) error { // AddProcessCapabilityPermitted adds a process capability into g.Config.Process.Capabilities.Permitted. func (g *Generator) AddProcessCapabilityPermitted(c string) error { cp := strings.ToUpper(c) - if err := validate.CapValid(cp, g.HostSpecific); err != nil { + if err := capsCheck.CapValid(cp, g.HostSpecific); err != nil { return err } @@ -1383,7 +1379,7 @@ func (g *Generator) DropProcessCapability(c string) error { } } - return validate.CapValid(cp, false) + return capsCheck.CapValid(cp, false) } // DropProcessCapabilityAmbient drops a process capability from g.Config.Process.Capabilities.Ambient. @@ -1399,7 +1395,7 @@ func (g *Generator) DropProcessCapabilityAmbient(c string) error { } } - return validate.CapValid(cp, false) + return capsCheck.CapValid(cp, false) } // DropProcessCapabilityBounding drops a process capability from g.Config.Process.Capabilities.Bounding. @@ -1415,7 +1411,7 @@ func (g *Generator) DropProcessCapabilityBounding(c string) error { } } - return validate.CapValid(cp, false) + return capsCheck.CapValid(cp, false) } // DropProcessCapabilityEffective drops a process capability from g.Config.Process.Capabilities.Effective. @@ -1431,7 +1427,7 @@ func (g *Generator) DropProcessCapabilityEffective(c string) error { } } - return validate.CapValid(cp, false) + return capsCheck.CapValid(cp, false) } // DropProcessCapabilityInheritable drops a process capability from g.Config.Process.Capabilities.Inheritable. @@ -1447,7 +1443,7 @@ func (g *Generator) DropProcessCapabilityInheritable(c string) error { } } - return validate.CapValid(cp, false) + return capsCheck.CapValid(cp, false) } // DropProcessCapabilityPermitted drops a process capability from g.Config.Process.Capabilities.Permitted. @@ -1463,7 +1459,7 @@ func (g *Generator) DropProcessCapabilityPermitted(c string) error { } } - return validate.CapValid(cp, false) + return capsCheck.CapValid(cp, false) } func mapStrToNamespace(ns string, path string) (rspec.LinuxNamespace, error) { @@ -1621,6 +1617,12 @@ func (g *Generator) SetDefaultSeccompActionForce(action string) error { return seccomp.ParseDefaultActionForce(action, g.Config.Linux.Seccomp) } +// SetDomainName sets g.Config.Domainname +func (g *Generator) SetDomainName(domain string) { + g.initConfig() + g.Config.Domainname = domain +} + // SetSeccompArchitecture sets the supported seccomp architectures func (g *Generator) SetSeccompArchitecture(architecture string) error { g.initConfigLinuxSeccomp() diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go index 12bc44d6d5..345a32a61d 100644 --- a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go @@ -151,6 +151,9 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp { "io_submit", "ipc", "kill", + "landlock_add_rule", + "landlock_create_ruleset", + "landlock_restrict_self", "lchown", "lchown32", "lgetxattr", @@ -354,11 +357,23 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp { Value: 0x0, Op: rspec.OpEqualTo, }, + }, + }, + { + Names: []string{"personality"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ { Index: 0, Value: 0x0008, Op: rspec.OpEqualTo, }, + }, + }, + { + Names: []string{"personality"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ { Index: 0, Value: 0xffffffff, @@ -513,7 +528,7 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp { Args: []rspec.LinuxSeccompArg{ { Index: sysCloneFlagsIndex, - Value: CloneNewNS | CloneNewUTS | CloneNewIPC | CloneNewUser | CloneNewPID | CloneNewNet, + Value: CloneNewNS | CloneNewUTS | CloneNewIPC | CloneNewUser | CloneNewPID | CloneNewNet | CloneNewCgroup, ValueTwo: 0, Op: rspec.OpMaskedEqual, }, diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go index 93472fba07..5ca9a6daee 100644 --- a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go @@ -3,14 +3,15 @@ package seccomp -import "syscall" +import "golang.org/x/sys/unix" // System values passed through on linux const ( - CloneNewIPC = syscall.CLONE_NEWIPC - CloneNewNet = syscall.CLONE_NEWNET - CloneNewNS = syscall.CLONE_NEWNS - CloneNewPID = syscall.CLONE_NEWPID - CloneNewUser = syscall.CLONE_NEWUSER - CloneNewUTS = syscall.CLONE_NEWUTS + CloneNewIPC = unix.CLONE_NEWIPC + CloneNewNet = unix.CLONE_NEWNET + CloneNewNS = unix.CLONE_NEWNS + CloneNewPID = unix.CLONE_NEWPID + CloneNewUser = unix.CLONE_NEWUSER + CloneNewUTS = unix.CLONE_NEWUTS + CloneNewCgroup = unix.CLONE_NEWCGROUP ) diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go new file mode 100644 index 0000000000..7fa47b77cc --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go @@ -0,0 +1,31 @@ +package capabilities + +import ( + "fmt" + "strings" + + "github.com/syndtr/gocapability/capability" +) + +// CapValid checks whether a capability is valid +func CapValid(c string, hostSpecific bool) error { + isValid := false + + if !strings.HasPrefix(c, "CAP_") { + return fmt.Errorf("capability %s must start with CAP_", c) + } + for _, cap := range capability.List() { + if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) { + if hostSpecific && cap > LastCap() { + return fmt.Errorf("%s is not supported on the current host", c) + } + isValid = true + break + } + } + + if !isValid { + return fmt.Errorf("invalid capability: %s", c) + } + return nil +} diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go new file mode 100644 index 0000000000..f6cb0d550a --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go @@ -0,0 +1,16 @@ +package capabilities + +import ( + "github.com/syndtr/gocapability/capability" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + last := capability.CAP_LAST_CAP + // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap + if last == capability.Cap(63) { + last = capability.CAP_BLOCK_SUSPEND + } + + return last +} diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go new file mode 100644 index 0000000000..e4aed632ce --- /dev/null +++ b/vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_unsupported.go @@ -0,0 +1,13 @@ +//go:build !linux +// +build !linux + +package capabilities + +import ( + "github.com/syndtr/gocapability/capability" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + return capability.Cap(-1) +} diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/validate.go b/vendor/github.com/opencontainers/runtime-tools/validate/validate.go index 2d3d42bce2..b8297faffa 100644 --- a/vendor/github.com/opencontainers/runtime-tools/validate/validate.go +++ b/vendor/github.com/opencontainers/runtime-tools/validate/validate.go @@ -16,12 +16,12 @@ import ( "unicode" "unicode/utf8" - "github.com/blang/semver" + "github.com/blang/semver/v4" "github.com/hashicorp/go-multierror" rspec "github.com/opencontainers/runtime-spec/specs-go" osFilepath "github.com/opencontainers/runtime-tools/filepath" + capsCheck "github.com/opencontainers/runtime-tools/validate/capabilities" "github.com/sirupsen/logrus" - "github.com/syndtr/gocapability/capability" "github.com/opencontainers/runtime-tools/specerror" "github.com/xeipuuv/gojsonschema" @@ -170,8 +170,8 @@ func (v *Validator) CheckJSONSchema() (errs error) { func (v *Validator) CheckRoot() (errs error) { logrus.Debugf("check root") - if v.platform == "windows" && v.spec.Windows != nil { - if v.spec.Windows.HyperV != nil { + if v.platform == "windows" { + if v.spec.Windows != nil && v.spec.Windows.HyperV != nil { if v.spec.Root != nil { errs = multierror.Append(errs, specerror.NewError(specerror.RootOnHyperVNotSet, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version)) @@ -179,12 +179,12 @@ func (v *Validator) CheckRoot() (errs error) { return } else if v.spec.Root == nil { errs = multierror.Append(errs, - specerror.NewError(specerror.RootOnWindowsRequired, fmt.Errorf("on Windows, for Windows Server Containers, this field is REQUIRED"), rspec.Version)) + specerror.NewError(specerror.RootOnWindowsRequired, fmt.Errorf("on Windows, for Windows Server Containers, Root is REQUIRED"), rspec.Version)) return } - } else if v.platform != "windows" && v.spec.Root == nil { + } else if v.spec.Root == nil { errs = multierror.Append(errs, - specerror.NewError(specerror.RootOnNonWindowsRequired, fmt.Errorf("on all other platforms, this field is REQUIRED"), rspec.Version)) + specerror.NewError(specerror.RootOnNonWindowsRequired, fmt.Errorf("on all other platforms, Root is REQUIRED"), rspec.Version)) return } @@ -687,26 +687,10 @@ func (v *Validator) CheckAnnotations() (errs error) { } // CapValid checks whether a capability is valid +// +// Deprecated: use github.com/opencontainers/runtime-tools/validate/capabilities.CapValid directly. func CapValid(c string, hostSpecific bool) error { - isValid := false - - if !strings.HasPrefix(c, "CAP_") { - return fmt.Errorf("capability %s must start with CAP_", c) - } - for _, cap := range capability.List() { - if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) { - if hostSpecific && cap > LastCap() { - return fmt.Errorf("%s is not supported on the current host", c) - } - isValid = true - break - } - } - - if !isValid { - return fmt.Errorf("invalid capability: %s", c) - } - return nil + return capsCheck.CapValid(c, hostSpecific) } func envValid(env string) bool { diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go b/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go index 6f1b28218d..756f85e515 100644 --- a/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go +++ b/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go @@ -11,26 +11,19 @@ import ( "strings" "syscall" - "github.com/syndtr/gocapability/capability" - multierror "github.com/hashicorp/go-multierror" rspec "github.com/opencontainers/runtime-spec/specs-go" osFilepath "github.com/opencontainers/runtime-tools/filepath" "github.com/opencontainers/runtime-tools/specerror" + capsCheck "github.com/opencontainers/runtime-tools/validate/capabilities" "github.com/opencontainers/selinux/go-selinux/label" "github.com/sirupsen/logrus" ) // LastCap return last cap of system -func LastCap() capability.Cap { - last := capability.CAP_LAST_CAP - // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap - if last == capability.Cap(63) { - last = capability.CAP_BLOCK_SUSPEND - } - - return last -} +// +// Deprecated: use github.com/opencontainers/runtime-tools/validate/capabilities.LastCap directly. +var LastCap = capsCheck.LastCap func deviceValid(d rspec.LinuxDevice) bool { switch d.Type { diff --git a/vendor/golang.org/x/mod/LICENSE b/vendor/golang.org/x/mod/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/golang.org/x/mod/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. 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/golang.org/x/mod/PATENTS b/vendor/golang.org/x/mod/PATENTS new file mode 100644 index 0000000000..733099041f --- /dev/null +++ b/vendor/golang.org/x/mod/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/mod/semver/semver.go b/vendor/golang.org/x/mod/semver/semver.go new file mode 100644 index 0000000000..a30a22bf20 --- /dev/null +++ b/vendor/golang.org/x/mod/semver/semver.go @@ -0,0 +1,401 @@ +// Copyright 2018 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 semver implements comparison of semantic version strings. +// In this package, semantic version strings must begin with a leading "v", +// as in "v1.0.0". +// +// The general form of a semantic version string accepted by this package is +// +// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]] +// +// where square brackets indicate optional parts of the syntax; +// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros; +// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers +// using only alphanumeric characters and hyphens; and +// all-numeric PRERELEASE identifiers must not have leading zeros. +// +// This package follows Semantic Versioning 2.0.0 (see semver.org) +// with two exceptions. First, it requires the "v" prefix. Second, it recognizes +// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes) +// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. +package semver + +import "sort" + +// parsed returns the parsed form of a semantic version string. +type parsed struct { + major string + minor string + patch string + short string + prerelease string + build string +} + +// IsValid reports whether v is a valid semantic version string. +func IsValid(v string) bool { + _, ok := parse(v) + return ok +} + +// Canonical returns the canonical formatting of the semantic version v. +// It fills in any missing .MINOR or .PATCH and discards build metadata. +// Two semantic versions compare equal only if their canonical formattings +// are identical strings. +// The canonical invalid semantic version is the empty string. +func Canonical(v string) string { + p, ok := parse(v) + if !ok { + return "" + } + if p.build != "" { + return v[:len(v)-len(p.build)] + } + if p.short != "" { + return v + p.short + } + return v +} + +// Major returns the major version prefix of the semantic version v. +// For example, Major("v2.1.0") == "v2". +// If v is an invalid semantic version string, Major returns the empty string. +func Major(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return v[:1+len(pv.major)] +} + +// MajorMinor returns the major.minor version prefix of the semantic version v. +// For example, MajorMinor("v2.1.0") == "v2.1". +// If v is an invalid semantic version string, MajorMinor returns the empty string. +func MajorMinor(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + i := 1 + len(pv.major) + if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor { + return v[:j] + } + return v[:i] + "." + pv.minor +} + +// Prerelease returns the prerelease suffix of the semantic version v. +// For example, Prerelease("v2.1.0-pre+meta") == "-pre". +// If v is an invalid semantic version string, Prerelease returns the empty string. +func Prerelease(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return pv.prerelease +} + +// Build returns the build suffix of the semantic version v. +// For example, Build("v2.1.0+meta") == "+meta". +// If v is an invalid semantic version string, Build returns the empty string. +func Build(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return pv.build +} + +// Compare returns an integer comparing two versions according to +// semantic version precedence. +// The result will be 0 if v == w, -1 if v < w, or +1 if v > w. +// +// An invalid semantic version string is considered less than a valid one. +// All invalid semantic version strings compare equal to each other. +func Compare(v, w string) int { + pv, ok1 := parse(v) + pw, ok2 := parse(w) + if !ok1 && !ok2 { + return 0 + } + if !ok1 { + return -1 + } + if !ok2 { + return +1 + } + if c := compareInt(pv.major, pw.major); c != 0 { + return c + } + if c := compareInt(pv.minor, pw.minor); c != 0 { + return c + } + if c := compareInt(pv.patch, pw.patch); c != 0 { + return c + } + return comparePrerelease(pv.prerelease, pw.prerelease) +} + +// Max canonicalizes its arguments and then returns the version string +// that compares greater. +// +// Deprecated: use Compare instead. In most cases, returning a canonicalized +// version is not expected or desired. +func Max(v, w string) string { + v = Canonical(v) + w = Canonical(w) + if Compare(v, w) > 0 { + return v + } + return w +} + +// ByVersion implements sort.Interface for sorting semantic version strings. +type ByVersion []string + +func (vs ByVersion) Len() int { return len(vs) } +func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] } +func (vs ByVersion) Less(i, j int) bool { + cmp := Compare(vs[i], vs[j]) + if cmp != 0 { + return cmp < 0 + } + return vs[i] < vs[j] +} + +// Sort sorts a list of semantic version strings using ByVersion. +func Sort(list []string) { + sort.Sort(ByVersion(list)) +} + +func parse(v string) (p parsed, ok bool) { + if v == "" || v[0] != 'v' { + return + } + p.major, v, ok = parseInt(v[1:]) + if !ok { + return + } + if v == "" { + p.minor = "0" + p.patch = "0" + p.short = ".0.0" + return + } + if v[0] != '.' { + ok = false + return + } + p.minor, v, ok = parseInt(v[1:]) + if !ok { + return + } + if v == "" { + p.patch = "0" + p.short = ".0" + return + } + if v[0] != '.' { + ok = false + return + } + p.patch, v, ok = parseInt(v[1:]) + if !ok { + return + } + if len(v) > 0 && v[0] == '-' { + p.prerelease, v, ok = parsePrerelease(v) + if !ok { + return + } + } + if len(v) > 0 && v[0] == '+' { + p.build, v, ok = parseBuild(v) + if !ok { + return + } + } + if v != "" { + ok = false + return + } + ok = true + return +} + +func parseInt(v string) (t, rest string, ok bool) { + if v == "" { + return + } + if v[0] < '0' || '9' < v[0] { + return + } + i := 1 + for i < len(v) && '0' <= v[i] && v[i] <= '9' { + i++ + } + if v[0] == '0' && i != 1 { + return + } + return v[:i], v[i:], true +} + +func parsePrerelease(v string) (t, rest string, ok bool) { + // "A pre-release version MAY be denoted by appending a hyphen and + // a series of dot separated identifiers immediately following the patch version. + // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. + // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes." + if v == "" || v[0] != '-' { + return + } + i := 1 + start := 1 + for i < len(v) && v[i] != '+' { + if !isIdentChar(v[i]) && v[i] != '.' { + return + } + if v[i] == '.' { + if start == i || isBadNum(v[start:i]) { + return + } + start = i + 1 + } + i++ + } + if start == i || isBadNum(v[start:i]) { + return + } + return v[:i], v[i:], true +} + +func parseBuild(v string) (t, rest string, ok bool) { + if v == "" || v[0] != '+' { + return + } + i := 1 + start := 1 + for i < len(v) { + if !isIdentChar(v[i]) && v[i] != '.' { + return + } + if v[i] == '.' { + if start == i { + return + } + start = i + 1 + } + i++ + } + if start == i { + return + } + return v[:i], v[i:], true +} + +func isIdentChar(c byte) bool { + return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' +} + +func isBadNum(v string) bool { + i := 0 + for i < len(v) && '0' <= v[i] && v[i] <= '9' { + i++ + } + return i == len(v) && i > 1 && v[0] == '0' +} + +func isNum(v string) bool { + i := 0 + for i < len(v) && '0' <= v[i] && v[i] <= '9' { + i++ + } + return i == len(v) +} + +func compareInt(x, y string) int { + if x == y { + return 0 + } + if len(x) < len(y) { + return -1 + } + if len(x) > len(y) { + return +1 + } + if x < y { + return -1 + } else { + return +1 + } +} + +func comparePrerelease(x, y string) int { + // "When major, minor, and patch are equal, a pre-release version has + // lower precedence than a normal version. + // Example: 1.0.0-alpha < 1.0.0. + // Precedence for two pre-release versions with the same major, minor, + // and patch version MUST be determined by comparing each dot separated + // identifier from left to right until a difference is found as follows: + // identifiers consisting of only digits are compared numerically and + // identifiers with letters or hyphens are compared lexically in ASCII + // sort order. Numeric identifiers always have lower precedence than + // non-numeric identifiers. A larger set of pre-release fields has a + // higher precedence than a smaller set, if all of the preceding + // identifiers are equal. + // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < + // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0." + if x == y { + return 0 + } + if x == "" { + return +1 + } + if y == "" { + return -1 + } + for x != "" && y != "" { + x = x[1:] // skip - or . + y = y[1:] // skip - or . + var dx, dy string + dx, x = nextIdent(x) + dy, y = nextIdent(y) + if dx != dy { + ix := isNum(dx) + iy := isNum(dy) + if ix != iy { + if ix { + return -1 + } else { + return +1 + } + } + if ix { + if len(dx) < len(dy) { + return -1 + } + if len(dx) > len(dy) { + return +1 + } + } + if dx < dy { + return -1 + } else { + return +1 + } + } + } + if x == "" { + return -1 + } else { + return +1 + } +} + +func nextIdent(x string) (dx, rest string) { + i := 0 + for i < len(x) && x[i] != '.' { + i++ + } + return x[:i], x[i:] +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d7edfabe77..be697be468 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -40,8 +40,6 @@ github.com/VividCortex/ewma github.com/acarl005/stripansi # github.com/beorn7/perks v1.0.1 github.com/beorn7/perks/quantile -# github.com/blang/semver v3.5.1+incompatible -github.com/blang/semver # github.com/blang/semver/v4 v4.0.0 ## explicit github.com/blang/semver/v4 @@ -61,8 +59,9 @@ github.com/checkpoint-restore/go-criu/v5/rpc github.com/checkpoint-restore/go-criu/v5/stats # github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/chzyer/readline -# github.com/container-orchestrated-devices/container-device-interface v0.4.0 +# github.com/container-orchestrated-devices/container-device-interface v0.5.4 ## explicit +github.com/container-orchestrated-devices/container-device-interface/internal/multierror github.com/container-orchestrated-devices/container-device-interface/pkg/cdi github.com/container-orchestrated-devices/container-device-interface/specs-go # github.com/containerd/cgroups v1.0.3 @@ -595,10 +594,10 @@ github.com/opencontainers/runc/libcontainer/devices github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/userns github.com/opencontainers/runc/libcontainer/utils -# github.com/opencontainers/runtime-spec v1.0.3-0.20211214071223-8958f93039ab +# github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb ## explicit github.com/opencontainers/runtime-spec/specs-go -# github.com/opencontainers/runtime-tools v0.9.1-0.20220714195903-17b3287fafb7 +# github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 ## explicit github.com/opencontainers/runtime-tools/error github.com/opencontainers/runtime-tools/filepath @@ -606,6 +605,7 @@ github.com/opencontainers/runtime-tools/generate github.com/opencontainers/runtime-tools/generate/seccomp github.com/opencontainers/runtime-tools/specerror github.com/opencontainers/runtime-tools/validate +github.com/opencontainers/runtime-tools/validate/capabilities # github.com/opencontainers/selinux v1.10.1 ## explicit github.com/opencontainers/selinux/go-selinux @@ -764,6 +764,8 @@ golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/knownhosts +# golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 +golang.org/x/mod/semver # golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e golang.org/x/net/context golang.org/x/net/html