mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2025-06-26 18:18:24 +00:00
21
vendor/github.com/blang/semver/.travis.yml
generated
vendored
21
vendor/github.com/blang/semver/.travis.yml
generated
vendored
@@ -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=
|
||||
22
vendor/github.com/blang/semver/LICENSE
generated
vendored
22
vendor/github.com/blang/semver/LICENSE
generated
vendored
@@ -1,22 +0,0 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014 Benedikt Lang <github at benediktlang.de>
|
||||
|
||||
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.
|
||||
|
||||
194
vendor/github.com/blang/semver/README.md
generated
vendored
194
vendor/github.com/blang/semver/README.md
generated
vendored
@@ -1,194 +0,0 @@
|
||||
semver for golang [](https://travis-ci.org/blang/semver) [](https://godoc.org/github.com/blang/semver) [](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.
|
||||
23
vendor/github.com/blang/semver/json.go
generated
vendored
23
vendor/github.com/blang/semver/json.go
generated
vendored
@@ -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
|
||||
}
|
||||
17
vendor/github.com/blang/semver/package.json
generated
vendored
17
vendor/github.com/blang/semver/package.json
generated
vendored
@@ -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"
|
||||
}
|
||||
|
||||
416
vendor/github.com/blang/semver/range.go
generated
vendored
416
vendor/github.com/blang/semver/range.go
generated
vendored
@@ -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
|
||||
}
|
||||
418
vendor/github.com/blang/semver/semver.go
generated
vendored
418
vendor/github.com/blang/semver/semver.go
generated
vendored
@@ -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
|
||||
}
|
||||
28
vendor/github.com/blang/semver/sort.go
generated
vendored
28
vendor/github.com/blang/semver/sort.go
generated
vendored
@@ -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))
|
||||
}
|
||||
30
vendor/github.com/blang/semver/sql.go
generated
vendored
30
vendor/github.com/blang/semver/sql.go
generated
vendored
@@ -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
|
||||
}
|
||||
82
vendor/github.com/container-orchestrated-devices/container-device-interface/internal/multierror/multierror.go
generated
vendored
Normal file
82
vendor/github.com/container-orchestrated-devices/container-device-interface/internal/multierror/multierror.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
106
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go
generated
vendored
106
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go
generated
vendored
@@ -17,16 +17,19 @@
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Option is an option to change some aspect of default CDI behavior.
|
||||
@@ -93,7 +96,7 @@ func (c *Cache) configure(options ...Option) error {
|
||||
|
||||
for _, o := range options {
|
||||
if err = o(c); err != nil {
|
||||
return errors.Wrapf(err, "failed to apply cache options")
|
||||
return fmt.Errorf("failed to apply cache options: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +126,8 @@ func (c *Cache) Refresh() error {
|
||||
|
||||
// collect and return cached errors, much like refresh() does it
|
||||
var result error
|
||||
for _, err := range c.errors {
|
||||
result = multierror.Append(result, err...)
|
||||
for _, errors := range c.errors {
|
||||
result = multierror.Append(result, errors...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -155,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{}{}
|
||||
}
|
||||
@@ -165,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
|
||||
}
|
||||
|
||||
@@ -194,11 +197,7 @@ func (c *Cache) refresh() error {
|
||||
c.devices = devices
|
||||
c.errors = specErrors
|
||||
|
||||
if len(result) > 0 {
|
||||
return multierror.Append(nil, result...)
|
||||
}
|
||||
|
||||
return nil
|
||||
return multierror.New(result...)
|
||||
}
|
||||
|
||||
// RefreshIfRequired triggers a refresh if necessary.
|
||||
@@ -219,7 +218,7 @@ 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()
|
||||
@@ -244,22 +243,33 @@ 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
|
||||
}
|
||||
|
||||
// WriteSpec writes a Spec file with the given content. Priority is used
|
||||
// as an index into the list of Spec directories to pick a directory for
|
||||
// the file, adjusting for any under- or overflows. If name has a "json"
|
||||
// or "yaml" extension it choses the encoding. Otherwise JSON encoding
|
||||
// is used with a "json" extension.
|
||||
// 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
|
||||
@@ -269,23 +279,51 @@ func (c *Cache) WriteSpec(raw *cdi.Spec, name string) error {
|
||||
err error
|
||||
)
|
||||
|
||||
if len(c.specDirs) == 0 {
|
||||
specDir, prio = c.highestPrioritySpecDir()
|
||||
if specDir == "" {
|
||||
return errors.New("no Spec directories to write to")
|
||||
}
|
||||
|
||||
prio = len(c.specDirs) - 1
|
||||
specDir = c.specDirs[prio]
|
||||
path = filepath.Join(specDir, name)
|
||||
if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" {
|
||||
path += ".json"
|
||||
path += defaultSpecExt
|
||||
}
|
||||
|
||||
spec, err = NewSpec(raw, path, prio)
|
||||
spec, err = newSpec(raw, path, prio)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return spec.Write(true)
|
||||
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.
|
||||
@@ -370,7 +408,17 @@ func (c *Cache) GetVendorSpecs(vendor string) []*Spec {
|
||||
// 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
|
||||
@@ -436,7 +484,7 @@ func (w *watch) setup(dirs []string, dirErrors map[string]error) {
|
||||
w.watcher, err = fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
for _, dir := range dirs {
|
||||
dirErrors[dir] = errors.Wrap(err, "failed to create watcher")
|
||||
dirErrors[dir] = fmt.Errorf("failed to create watcher: %w", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -519,7 +567,7 @@ func (w *watch) update(dirErrors map[string]error, removed ...string) bool {
|
||||
update = true
|
||||
} else {
|
||||
w.tracked[dir] = false
|
||||
dirErrors[dir] = errors.Wrap(err, "failed to monitor for changes")
|
||||
dirErrors[dir] = fmt.Errorf("failed to monitor for changes: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
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"
|
||||
@@ -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
|
||||
}
|
||||
@@ -298,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.
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
runc "github.com/opencontainers/runc/libcontainer/devices"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// fillMissingInfo fills in missing mandatory attributes from the host device.
|
||||
@@ -36,14 +37,14 @@ func (d *DeviceNode) fillMissingInfo() error {
|
||||
|
||||
hostDev, err := runc.DeviceFromPath(d.HostPath, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat CDI host device %q", d.HostPath)
|
||||
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 errors.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
|
||||
return fmt.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
|
||||
d.Path, d.HostPath, d.Type, string(hostDev.Type))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
125
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go
generated
vendored
125
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go
generated
vendored
@@ -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))
|
||||
@@ -90,7 +89,6 @@
|
||||
// "fmt"
|
||||
// "strings"
|
||||
//
|
||||
// "github.com/pkg/errors"
|
||||
// log "github.com/sirupsen/logrus"
|
||||
//
|
||||
// "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
@@ -115,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))
|
||||
@@ -124,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
|
||||
@@ -141,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 <vendor, class, transientID> 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
|
||||
//
|
||||
|
||||
@@ -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 a letter or digit", 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 a letter or digit", class)
|
||||
return fmt.Errorf("invalid class %q, should end with a letter or digit", class)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -170,10 +169,10 @@ 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 errors.Errorf("invalid class %q, should start with a letter or digit", name)
|
||||
return fmt.Errorf("invalid class %q, should start with a letter or digit", name)
|
||||
}
|
||||
if len(name) == 1 {
|
||||
return nil
|
||||
@@ -183,12 +182,12 @@ func ValidateDeviceName(name string) error {
|
||||
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 end with a letter or digit", name)
|
||||
return fmt.Errorf("invalid name %q, should end with a letter or digit", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ type RegistrySpecDB interface {
|
||||
GetVendorSpecs(vendor string) []*Spec
|
||||
GetSpecErrors(*Spec) []error
|
||||
WriteSpec(raw *cdi.Spec, name string) error
|
||||
RemoveSpec(name string) error
|
||||
}
|
||||
|
||||
type registry struct {
|
||||
|
||||
139
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go
generated
vendored
139
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go
generated
vendored
@@ -18,28 +18,25 @@ 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": {},
|
||||
"0.5.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
|
||||
@@ -69,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)
|
||||
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
|
||||
}
|
||||
@@ -88,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
|
||||
@@ -104,18 +101,22 @@ 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 {
|
||||
// by newSpec() or ReadSpec().
|
||||
func (s *Spec) write(overwrite bool) error {
|
||||
var (
|
||||
data []byte
|
||||
dir string
|
||||
@@ -134,30 +135,30 @@ func (s *Spec) Write(overwrite bool) error {
|
||||
data, err = json.Marshal(s.Spec)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to marshal Spec file")
|
||||
return fmt.Errorf("failed to marshal Spec file: %w", err)
|
||||
}
|
||||
|
||||
dir = filepath.Dir(s.path)
|
||||
err = os.MkdirAll(dir, 0o755)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create Spec dir")
|
||||
return fmt.Errorf("failed to create Spec dir: %w", err)
|
||||
}
|
||||
|
||||
tmp, err = os.CreateTemp(dir, "spec.*.tmp")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create Spec file")
|
||||
return fmt.Errorf("failed to create Spec file: %w", err)
|
||||
}
|
||||
_, err = tmp.Write(data)
|
||||
tmp.Close()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to write Spec file")
|
||||
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 = errors.Wrap(err, "failed to write Spec file")
|
||||
err = fmt.Errorf("failed to write Spec file: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -203,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
|
||||
}
|
||||
@@ -217,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
|
||||
}
|
||||
@@ -230,8 +240,8 @@ 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
|
||||
@@ -242,14 +252,14 @@ 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()
|
||||
@@ -266,7 +276,72 @@ func validateSpec(raw *cdi.Spec) error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -30,7 +30,7 @@ func renameIn(dir, src, dst string, overwrite bool) error {
|
||||
|
||||
dirf, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "rename failed")
|
||||
return fmt.Errorf("rename failed: %w", err)
|
||||
}
|
||||
defer dirf.Close()
|
||||
|
||||
@@ -41,7 +41,7 @@ func renameIn(dir, src, dst string, overwrite bool) error {
|
||||
dirFd := int(dirf.Fd())
|
||||
err = unix.Renameat2(dirFd, src, dirFd, dst, flags)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "rename failed")
|
||||
return fmt.Errorf("rename failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
160
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/version.go
generated
vendored
Normal file
160
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/version.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
354
vendor/github.com/hashicorp/errwrap/LICENSE
generated
vendored
354
vendor/github.com/hashicorp/errwrap/LICENSE
generated
vendored
@@ -1,354 +0,0 @@
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. “Contributor”
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. “Contributor Version”
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor’s Contribution.
|
||||
|
||||
1.3. “Contribution”
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. “Covered Software”
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. “Incompatible With Secondary Licenses”
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of version
|
||||
1.1 or earlier of the License, but not also under the terms of a
|
||||
Secondary License.
|
||||
|
||||
1.6. “Executable Form”
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. “Larger Work”
|
||||
|
||||
means a work that combines Covered Software with other material, in a separate
|
||||
file or files, that is not Covered Software.
|
||||
|
||||
1.8. “License”
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. “Licensable”
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether at the
|
||||
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||
this License.
|
||||
|
||||
1.10. “Modifications”
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to, deletion
|
||||
from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. “Patent Claims” of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method, process,
|
||||
and apparatus claims, in any patent Licensable by such Contributor that
|
||||
would be infringed, but for the grant of the License, by the making,
|
||||
using, selling, offering for sale, having made, import, or transfer of
|
||||
either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. “Secondary License”
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. “Source Code Form”
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. “You” (or “Your”)
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, “You” includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, “control” means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or as
|
||||
part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its Contributions
|
||||
or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||
effective for each Contribution on the date the Contributor first distributes
|
||||
such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under this
|
||||
License. No additional rights or licenses will be implied from the distribution
|
||||
or licensing of Covered Software under this License. Notwithstanding Section
|
||||
2.1(b) above, no patent license is granted by a Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party’s
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||
Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks, or
|
||||
logos of any Contributor (except as may be necessary to comply with the
|
||||
notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this License
|
||||
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||
under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its Contributions
|
||||
are its original creation(s) or it has sufficient rights to grant the
|
||||
rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under applicable
|
||||
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under the
|
||||
terms of this License. You must inform recipients that the Source Code Form
|
||||
of the Covered Software is governed by the terms of this License, and how
|
||||
they can obtain a copy of this License. You may not attempt to alter or
|
||||
restrict the recipients’ rights in the Source Code Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this License,
|
||||
or sublicense it under different terms, provided that the license for
|
||||
the Executable Form does not attempt to limit or alter the recipients’
|
||||
rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for the
|
||||
Covered Software. If the Larger Work is a combination of Covered Software
|
||||
with a work governed by one or more Secondary Licenses, and the Covered
|
||||
Software is not Incompatible With Secondary Licenses, this License permits
|
||||
You to additionally distribute such Covered Software under the terms of
|
||||
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||
their option, further distribute the Covered Software under the terms of
|
||||
either this License or such Secondary License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices (including
|
||||
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||
of liability) contained within the Source Code Form of the Covered
|
||||
Software, except that You may alter any license notices to the extent
|
||||
required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||
of any Contributor. You must make it absolutely clear that any such
|
||||
warranty, support, indemnity, or liability obligation is offered by You
|
||||
alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute, judicial
|
||||
order, or regulation then You must: (a) comply with the terms of this License
|
||||
to the maximum extent possible; and (b) describe the limitations and the code
|
||||
they affect. Such description must be placed in a text file included with all
|
||||
distributions of the Covered Software under this License. Except to the
|
||||
extent prohibited by statute or regulation, such description must be
|
||||
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||
understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||
if such Contributor fails to notify You of the non-compliance by some
|
||||
reasonable means prior to 60 days after You have come back into compliance.
|
||||
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||
some reasonable means, this is the first time You have received notice of
|
||||
non-compliance with this License from such Contributor, and You become
|
||||
compliant prior to 30 days after Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||
and cross-claims) alleging that a Contributor Version directly or
|
||||
indirectly infringes any patent, then the rights granted to You by any and
|
||||
all Contributors for the Covered Software under Section 2.1 of this License
|
||||
shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an “as is” basis, without
|
||||
warranty of any kind, either expressed, implied, or statutory, including,
|
||||
without limitation, warranties that the Covered Software is free of defects,
|
||||
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
risk as to the quality and performance of the Covered Software is with You.
|
||||
Should any Covered Software prove defective in any respect, You (not any
|
||||
Contributor) assume the cost of any necessary servicing, repair, or
|
||||
correction. This disclaimer of warranty constitutes an essential part of this
|
||||
License. No use of any Covered Software is authorized under this License
|
||||
except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from such
|
||||
party’s negligence to the extent applicable law prohibits such limitation.
|
||||
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||
consequential damages, so this exclusion and limitation may not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts of
|
||||
a jurisdiction where the defendant maintains its principal place of business
|
||||
and such litigation shall be governed by laws of that jurisdiction, without
|
||||
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject matter
|
||||
hereof. If any provision of this License is held to be unenforceable, such
|
||||
provision shall be reformed only to the extent necessary to make it
|
||||
enforceable. Any law or regulation which provides that the language of a
|
||||
contract shall be construed against the drafter shall not be used to construe
|
||||
this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version of
|
||||
the License under which You originally received the Covered Software, or
|
||||
under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a modified
|
||||
version of this License if you rename the license and remove any
|
||||
references to the name of the license steward (except to note that such
|
||||
modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||
directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||
|
||||
This Source Code Form is “Incompatible
|
||||
With Secondary Licenses”, as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
|
||||
89
vendor/github.com/hashicorp/errwrap/README.md
generated
vendored
89
vendor/github.com/hashicorp/errwrap/README.md
generated
vendored
@@ -1,89 +0,0 @@
|
||||
# errwrap
|
||||
|
||||
`errwrap` is a package for Go that formalizes the pattern of wrapping errors
|
||||
and checking if an error contains another error.
|
||||
|
||||
There is a common pattern in Go of taking a returned `error` value and
|
||||
then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
|
||||
with this pattern is that you completely lose the original `error` structure.
|
||||
|
||||
Arguably the _correct_ approach is that you should make a custom structure
|
||||
implementing the `error` interface, and have the original error as a field
|
||||
on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
|
||||
This is a good approach, but you have to know the entire chain of possible
|
||||
rewrapping that happens, when you might just care about one.
|
||||
|
||||
`errwrap` formalizes this pattern (it doesn't matter what approach you use
|
||||
above) by giving a single interface for wrapping errors, checking if a specific
|
||||
error is wrapped, and extracting that error.
|
||||
|
||||
## Installation and Docs
|
||||
|
||||
Install using `go get github.com/hashicorp/errwrap`.
|
||||
|
||||
Full documentation is available at
|
||||
http://godoc.org/github.com/hashicorp/errwrap
|
||||
|
||||
## Usage
|
||||
|
||||
#### Basic Usage
|
||||
|
||||
Below is a very basic example of its usage:
|
||||
|
||||
```go
|
||||
// A function that always returns an error, but wraps it, like a real
|
||||
// function might.
|
||||
func tryOpen() error {
|
||||
_, err := os.Open("/i/dont/exist")
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("Doesn't exist: {{err}}", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := tryOpen()
|
||||
|
||||
// We can use the Contains helpers to check if an error contains
|
||||
// another error. It is safe to do this with a nil error, or with
|
||||
// an error that doesn't even use the errwrap package.
|
||||
if errwrap.Contains(err, "does not exist") {
|
||||
// Do something
|
||||
}
|
||||
if errwrap.ContainsType(err, new(os.PathError)) {
|
||||
// Do something
|
||||
}
|
||||
|
||||
// Or we can use the associated `Get` functions to just extract
|
||||
// a specific error. This would return nil if that specific error doesn't
|
||||
// exist.
|
||||
perr := errwrap.GetType(err, new(os.PathError))
|
||||
}
|
||||
```
|
||||
|
||||
#### Custom Types
|
||||
|
||||
If you're already making custom types that properly wrap errors, then
|
||||
you can get all the functionality of `errwraps.Contains` and such by
|
||||
implementing the `Wrapper` interface with just one function. Example:
|
||||
|
||||
```go
|
||||
type AppError {
|
||||
Code ErrorCode
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *AppError) WrappedErrors() []error {
|
||||
return []error{e.Err}
|
||||
}
|
||||
```
|
||||
|
||||
Now this works:
|
||||
|
||||
```go
|
||||
err := &AppError{Err: fmt.Errorf("an error")}
|
||||
if errwrap.ContainsType(err, fmt.Errorf("")) {
|
||||
// This will work!
|
||||
}
|
||||
```
|
||||
178
vendor/github.com/hashicorp/errwrap/errwrap.go
generated
vendored
178
vendor/github.com/hashicorp/errwrap/errwrap.go
generated
vendored
@@ -1,178 +0,0 @@
|
||||
// Package errwrap implements methods to formalize error wrapping in Go.
|
||||
//
|
||||
// All of the top-level functions that take an `error` are built to be able
|
||||
// to take any error, not just wrapped errors. This allows you to use errwrap
|
||||
// without having to type-check and type-cast everywhere.
|
||||
package errwrap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// WalkFunc is the callback called for Walk.
|
||||
type WalkFunc func(error)
|
||||
|
||||
// Wrapper is an interface that can be implemented by custom types to
|
||||
// have all the Contains, Get, etc. functions in errwrap work.
|
||||
//
|
||||
// When Walk reaches a Wrapper, it will call the callback for every
|
||||
// wrapped error in addition to the wrapper itself. Since all the top-level
|
||||
// functions in errwrap use Walk, this means that all those functions work
|
||||
// with your custom type.
|
||||
type Wrapper interface {
|
||||
WrappedErrors() []error
|
||||
}
|
||||
|
||||
// Wrap defines that outer wraps inner, returning an error type that
|
||||
// can be cleanly used with the other methods in this package, such as
|
||||
// Contains, GetAll, etc.
|
||||
//
|
||||
// This function won't modify the error message at all (the outer message
|
||||
// will be used).
|
||||
func Wrap(outer, inner error) error {
|
||||
return &wrappedError{
|
||||
Outer: outer,
|
||||
Inner: inner,
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf wraps an error with a formatting message. This is similar to using
|
||||
// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
|
||||
// errors, you should replace it with this.
|
||||
//
|
||||
// format is the format of the error message. The string '{{err}}' will
|
||||
// be replaced with the original error message.
|
||||
//
|
||||
// Deprecated: Use fmt.Errorf()
|
||||
func Wrapf(format string, err error) error {
|
||||
outerMsg := "<nil>"
|
||||
if err != nil {
|
||||
outerMsg = err.Error()
|
||||
}
|
||||
|
||||
outer := errors.New(strings.Replace(
|
||||
format, "{{err}}", outerMsg, -1))
|
||||
|
||||
return Wrap(outer, err)
|
||||
}
|
||||
|
||||
// Contains checks if the given error contains an error with the
|
||||
// message msg. If err is not a wrapped error, this will always return
|
||||
// false unless the error itself happens to match this msg.
|
||||
func Contains(err error, msg string) bool {
|
||||
return len(GetAll(err, msg)) > 0
|
||||
}
|
||||
|
||||
// ContainsType checks if the given error contains an error with
|
||||
// the same concrete type as v. If err is not a wrapped error, this will
|
||||
// check the err itself.
|
||||
func ContainsType(err error, v interface{}) bool {
|
||||
return len(GetAllType(err, v)) > 0
|
||||
}
|
||||
|
||||
// Get is the same as GetAll but returns the deepest matching error.
|
||||
func Get(err error, msg string) error {
|
||||
es := GetAll(err, msg)
|
||||
if len(es) > 0 {
|
||||
return es[len(es)-1]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetType is the same as GetAllType but returns the deepest matching error.
|
||||
func GetType(err error, v interface{}) error {
|
||||
es := GetAllType(err, v)
|
||||
if len(es) > 0 {
|
||||
return es[len(es)-1]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAll gets all the errors that might be wrapped in err with the
|
||||
// given message. The order of the errors is such that the outermost
|
||||
// matching error (the most recent wrap) is index zero, and so on.
|
||||
func GetAll(err error, msg string) []error {
|
||||
var result []error
|
||||
|
||||
Walk(err, func(err error) {
|
||||
if err.Error() == msg {
|
||||
result = append(result, err)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// GetAllType gets all the errors that are the same type as v.
|
||||
//
|
||||
// The order of the return value is the same as described in GetAll.
|
||||
func GetAllType(err error, v interface{}) []error {
|
||||
var result []error
|
||||
|
||||
var search string
|
||||
if v != nil {
|
||||
search = reflect.TypeOf(v).String()
|
||||
}
|
||||
Walk(err, func(err error) {
|
||||
var needle string
|
||||
if err != nil {
|
||||
needle = reflect.TypeOf(err).String()
|
||||
}
|
||||
|
||||
if needle == search {
|
||||
result = append(result, err)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Walk walks all the wrapped errors in err and calls the callback. If
|
||||
// err isn't a wrapped error, this will be called once for err. If err
|
||||
// is a wrapped error, the callback will be called for both the wrapper
|
||||
// that implements error as well as the wrapped error itself.
|
||||
func Walk(err error, cb WalkFunc) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch e := err.(type) {
|
||||
case *wrappedError:
|
||||
cb(e.Outer)
|
||||
Walk(e.Inner, cb)
|
||||
case Wrapper:
|
||||
cb(err)
|
||||
|
||||
for _, err := range e.WrappedErrors() {
|
||||
Walk(err, cb)
|
||||
}
|
||||
case interface{ Unwrap() error }:
|
||||
cb(err)
|
||||
Walk(e.Unwrap(), cb)
|
||||
default:
|
||||
cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
// wrappedError is an implementation of error that has both the
|
||||
// outer and inner errors.
|
||||
type wrappedError struct {
|
||||
Outer error
|
||||
Inner error
|
||||
}
|
||||
|
||||
func (w *wrappedError) Error() string {
|
||||
return w.Outer.Error()
|
||||
}
|
||||
|
||||
func (w *wrappedError) WrappedErrors() []error {
|
||||
return []error{w.Outer, w.Inner}
|
||||
}
|
||||
|
||||
func (w *wrappedError) Unwrap() error {
|
||||
return w.Inner
|
||||
}
|
||||
353
vendor/github.com/hashicorp/go-multierror/LICENSE
generated
vendored
353
vendor/github.com/hashicorp/go-multierror/LICENSE
generated
vendored
@@ -1,353 +0,0 @@
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. “Contributor”
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. “Contributor Version”
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor’s Contribution.
|
||||
|
||||
1.3. “Contribution”
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. “Covered Software”
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. “Incompatible With Secondary Licenses”
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of version
|
||||
1.1 or earlier of the License, but not also under the terms of a
|
||||
Secondary License.
|
||||
|
||||
1.6. “Executable Form”
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. “Larger Work”
|
||||
|
||||
means a work that combines Covered Software with other material, in a separate
|
||||
file or files, that is not Covered Software.
|
||||
|
||||
1.8. “License”
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. “Licensable”
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether at the
|
||||
time of the initial grant or subsequently, any and all of the rights conveyed by
|
||||
this License.
|
||||
|
||||
1.10. “Modifications”
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to, deletion
|
||||
from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. “Patent Claims” of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method, process,
|
||||
and apparatus claims, in any patent Licensable by such Contributor that
|
||||
would be infringed, but for the grant of the License, by the making,
|
||||
using, selling, offering for sale, having made, import, or transfer of
|
||||
either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. “Secondary License”
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. “Source Code Form”
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. “You” (or “Your”)
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, “You” includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, “control” means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or as
|
||||
part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its Contributions
|
||||
or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||
effective for each Contribution on the date the Contributor first distributes
|
||||
such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under this
|
||||
License. No additional rights or licenses will be implied from the distribution
|
||||
or licensing of Covered Software under this License. Notwithstanding Section
|
||||
2.1(b) above, no patent license is granted by a Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party’s
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of its
|
||||
Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks, or
|
||||
logos of any Contributor (except as may be necessary to comply with the
|
||||
notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this License
|
||||
(see Section 10.2) or under the terms of a Secondary License (if permitted
|
||||
under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its Contributions
|
||||
are its original creation(s) or it has sufficient rights to grant the
|
||||
rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under applicable
|
||||
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under the
|
||||
terms of this License. You must inform recipients that the Source Code Form
|
||||
of the Covered Software is governed by the terms of this License, and how
|
||||
they can obtain a copy of this License. You may not attempt to alter or
|
||||
restrict the recipients’ rights in the Source Code Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this License,
|
||||
or sublicense it under different terms, provided that the license for
|
||||
the Executable Form does not attempt to limit or alter the recipients’
|
||||
rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for the
|
||||
Covered Software. If the Larger Work is a combination of Covered Software
|
||||
with a work governed by one or more Secondary Licenses, and the Covered
|
||||
Software is not Incompatible With Secondary Licenses, this License permits
|
||||
You to additionally distribute such Covered Software under the terms of
|
||||
such Secondary License(s), so that the recipient of the Larger Work may, at
|
||||
their option, further distribute the Covered Software under the terms of
|
||||
either this License or such Secondary License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices (including
|
||||
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||
of liability) contained within the Source Code Form of the Covered
|
||||
Software, except that You may alter any license notices to the extent
|
||||
required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on behalf
|
||||
of any Contributor. You must make it absolutely clear that any such
|
||||
warranty, support, indemnity, or liability obligation is offered by You
|
||||
alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute, judicial
|
||||
order, or regulation then You must: (a) comply with the terms of this License
|
||||
to the maximum extent possible; and (b) describe the limitations and the code
|
||||
they affect. Such description must be placed in a text file included with all
|
||||
distributions of the Covered Software under this License. Except to the
|
||||
extent prohibited by statute or regulation, such description must be
|
||||
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||
understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing basis,
|
||||
if such Contributor fails to notify You of the non-compliance by some
|
||||
reasonable means prior to 60 days after You have come back into compliance.
|
||||
Moreover, Your grants from a particular Contributor are reinstated on an
|
||||
ongoing basis if such Contributor notifies You of the non-compliance by
|
||||
some reasonable means, this is the first time You have received notice of
|
||||
non-compliance with this License from such Contributor, and You become
|
||||
compliant prior to 30 days after Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions, counter-claims,
|
||||
and cross-claims) alleging that a Contributor Version directly or
|
||||
indirectly infringes any patent, then the rights granted to You by any and
|
||||
all Contributors for the Covered Software under Section 2.1 of this License
|
||||
shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an “as is” basis, without
|
||||
warranty of any kind, either expressed, implied, or statutory, including,
|
||||
without limitation, warranties that the Covered Software is free of defects,
|
||||
merchantable, fit for a particular purpose or non-infringing. The entire
|
||||
risk as to the quality and performance of the Covered Software is with You.
|
||||
Should any Covered Software prove defective in any respect, You (not any
|
||||
Contributor) assume the cost of any necessary servicing, repair, or
|
||||
correction. This disclaimer of warranty constitutes an essential part of this
|
||||
License. No use of any Covered Software is authorized under this License
|
||||
except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from such
|
||||
party’s negligence to the extent applicable law prohibits such limitation.
|
||||
Some jurisdictions do not allow the exclusion or limitation of incidental or
|
||||
consequential damages, so this exclusion and limitation may not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts of
|
||||
a jurisdiction where the defendant maintains its principal place of business
|
||||
and such litigation shall be governed by laws of that jurisdiction, without
|
||||
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||
prevent a party’s ability to bring cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject matter
|
||||
hereof. If any provision of this License is held to be unenforceable, such
|
||||
provision shall be reformed only to the extent necessary to make it
|
||||
enforceable. Any law or regulation which provides that the language of a
|
||||
contract shall be construed against the drafter shall not be used to construe
|
||||
this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version of
|
||||
the License under which You originally received the Covered Software, or
|
||||
under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a modified
|
||||
version of this License if you rename the license and remove any
|
||||
references to the name of the license steward (except to note that such
|
||||
modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a relevant
|
||||
directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||
|
||||
This Source Code Form is “Incompatible
|
||||
With Secondary Licenses”, as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
31
vendor/github.com/hashicorp/go-multierror/Makefile
generated
vendored
31
vendor/github.com/hashicorp/go-multierror/Makefile
generated
vendored
@@ -1,31 +0,0 @@
|
||||
TEST?=./...
|
||||
|
||||
default: test
|
||||
|
||||
# test runs the test suite and vets the code.
|
||||
test: generate
|
||||
@echo "==> Running tests..."
|
||||
@go list $(TEST) \
|
||||
| grep -v "/vendor/" \
|
||||
| xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS}
|
||||
|
||||
# testrace runs the race checker
|
||||
testrace: generate
|
||||
@echo "==> Running tests (race)..."
|
||||
@go list $(TEST) \
|
||||
| grep -v "/vendor/" \
|
||||
| xargs -n1 go test -timeout=60s -race ${TESTARGS}
|
||||
|
||||
# updatedeps installs all the dependencies needed to run and build.
|
||||
updatedeps:
|
||||
@sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'"
|
||||
|
||||
# generate runs `go generate` to build the dynamically generated source files.
|
||||
generate:
|
||||
@echo "==> Generating..."
|
||||
@find . -type f -name '.DS_Store' -delete
|
||||
@go list ./... \
|
||||
| grep -v "/vendor/" \
|
||||
| xargs -n1 go generate
|
||||
|
||||
.PHONY: default test testrace updatedeps generate
|
||||
150
vendor/github.com/hashicorp/go-multierror/README.md
generated
vendored
150
vendor/github.com/hashicorp/go-multierror/README.md
generated
vendored
@@ -1,150 +0,0 @@
|
||||
# go-multierror
|
||||
|
||||
[](https://circleci.com/gh/hashicorp/go-multierror)
|
||||
[](https://pkg.go.dev/github.com/hashicorp/go-multierror)
|
||||

|
||||
|
||||
[circleci]: https://app.circleci.com/pipelines/github/hashicorp/go-multierror
|
||||
[godocs]: https://pkg.go.dev/github.com/hashicorp/go-multierror
|
||||
|
||||
`go-multierror` is a package for Go that provides a mechanism for
|
||||
representing a list of `error` values as a single `error`.
|
||||
|
||||
This allows a function in Go to return an `error` that might actually
|
||||
be a list of errors. If the caller knows this, they can unwrap the
|
||||
list and access the errors. If the caller doesn't know, the error
|
||||
formats to a nice human-readable format.
|
||||
|
||||
`go-multierror` is fully compatible with the Go standard library
|
||||
[errors](https://golang.org/pkg/errors/) package, including the
|
||||
functions `As`, `Is`, and `Unwrap`. This provides a standardized approach
|
||||
for introspecting on error values.
|
||||
|
||||
## Installation and Docs
|
||||
|
||||
Install using `go get github.com/hashicorp/go-multierror`.
|
||||
|
||||
Full documentation is available at
|
||||
https://pkg.go.dev/github.com/hashicorp/go-multierror
|
||||
|
||||
### Requires go version 1.13 or newer
|
||||
|
||||
`go-multierror` requires go version 1.13 or newer. Go 1.13 introduced
|
||||
[error wrapping](https://golang.org/doc/go1.13#error_wrapping), which
|
||||
this library takes advantage of.
|
||||
|
||||
If you need to use an earlier version of go, you can use the
|
||||
[v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0)
|
||||
tag, which doesn't rely on features in go 1.13.
|
||||
|
||||
If you see compile errors that look like the below, it's likely that
|
||||
you're on an older version of go:
|
||||
|
||||
```
|
||||
/go/src/github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As
|
||||
/go/src/github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
go-multierror is easy to use and purposely built to be unobtrusive in
|
||||
existing Go applications/libraries that may not be aware of it.
|
||||
|
||||
**Building a list of errors**
|
||||
|
||||
The `Append` function is used to create a list of errors. This function
|
||||
behaves a lot like the Go built-in `append` function: it doesn't matter
|
||||
if the first argument is nil, a `multierror.Error`, or any other `error`,
|
||||
the function behaves as you would expect.
|
||||
|
||||
```go
|
||||
var result error
|
||||
|
||||
if err := step1(); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
if err := step2(); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
**Customizing the formatting of the errors**
|
||||
|
||||
By specifying a custom `ErrorFormat`, you can customize the format
|
||||
of the `Error() string` function:
|
||||
|
||||
```go
|
||||
var result *multierror.Error
|
||||
|
||||
// ... accumulate errors here, maybe using Append
|
||||
|
||||
if result != nil {
|
||||
result.ErrorFormat = func([]error) string {
|
||||
return "errors!"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Accessing the list of errors**
|
||||
|
||||
`multierror.Error` implements `error` so if the caller doesn't know about
|
||||
multierror, it will work just fine. But if you're aware a multierror might
|
||||
be returned, you can use type switches to access the list of errors:
|
||||
|
||||
```go
|
||||
if err := something(); err != nil {
|
||||
if merr, ok := err.(*multierror.Error); ok {
|
||||
// Use merr.Errors
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap)
|
||||
function. This will continue to unwrap into subsequent errors until none exist.
|
||||
|
||||
**Extracting an error**
|
||||
|
||||
The standard library [`errors.As`](https://golang.org/pkg/errors/#As)
|
||||
function can be used directly with a multierror to extract a specific error:
|
||||
|
||||
```go
|
||||
// Assume err is a multierror value
|
||||
err := somefunc()
|
||||
|
||||
// We want to know if "err" has a "RichErrorType" in it and extract it.
|
||||
var errRich RichErrorType
|
||||
if errors.As(err, &errRich) {
|
||||
// It has it, and now errRich is populated.
|
||||
}
|
||||
```
|
||||
|
||||
**Checking for an exact error value**
|
||||
|
||||
Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables)
|
||||
error in the `os` package. You can check if this error is present by using
|
||||
the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function.
|
||||
|
||||
```go
|
||||
// Assume err is a multierror value
|
||||
err := somefunc()
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// err contains os.ErrNotExist
|
||||
}
|
||||
```
|
||||
|
||||
**Returning a multierror only if there are errors**
|
||||
|
||||
If you build a `multierror.Error`, you can use the `ErrorOrNil` function
|
||||
to return an `error` implementation only if there are errors to return:
|
||||
|
||||
```go
|
||||
var result *multierror.Error
|
||||
|
||||
// ... accumulate errors here
|
||||
|
||||
// Return the `error` only if errors were added to the multierror, otherwise
|
||||
// return nil since there are no errors.
|
||||
return result.ErrorOrNil()
|
||||
```
|
||||
43
vendor/github.com/hashicorp/go-multierror/append.go
generated
vendored
43
vendor/github.com/hashicorp/go-multierror/append.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
package multierror
|
||||
|
||||
// Append is a helper function that will append more errors
|
||||
// onto an Error in order to create a larger multi-error.
|
||||
//
|
||||
// If err is not a multierror.Error, then it will be turned into
|
||||
// one. If any of the errs are multierr.Error, they will be flattened
|
||||
// one level into err.
|
||||
// Any nil errors within errs will be ignored. If err is nil, a new
|
||||
// *Error will be returned.
|
||||
func Append(err error, errs ...error) *Error {
|
||||
switch err := err.(type) {
|
||||
case *Error:
|
||||
// Typed nils can reach here, so initialize if we are nil
|
||||
if err == nil {
|
||||
err = new(Error)
|
||||
}
|
||||
|
||||
// Go through each error and flatten
|
||||
for _, e := range errs {
|
||||
switch e := e.(type) {
|
||||
case *Error:
|
||||
if e != nil {
|
||||
err.Errors = append(err.Errors, e.Errors...)
|
||||
}
|
||||
default:
|
||||
if e != nil {
|
||||
err.Errors = append(err.Errors, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
default:
|
||||
newErrs := make([]error, 0, len(errs)+1)
|
||||
if err != nil {
|
||||
newErrs = append(newErrs, err)
|
||||
}
|
||||
newErrs = append(newErrs, errs...)
|
||||
|
||||
return Append(&Error{}, newErrs...)
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/hashicorp/go-multierror/flatten.go
generated
vendored
26
vendor/github.com/hashicorp/go-multierror/flatten.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
package multierror
|
||||
|
||||
// Flatten flattens the given error, merging any *Errors together into
|
||||
// a single *Error.
|
||||
func Flatten(err error) error {
|
||||
// If it isn't an *Error, just return the error as-is
|
||||
if _, ok := err.(*Error); !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// Otherwise, make the result and flatten away!
|
||||
flatErr := new(Error)
|
||||
flatten(err, flatErr)
|
||||
return flatErr
|
||||
}
|
||||
|
||||
func flatten(err error, flatErr *Error) {
|
||||
switch err := err.(type) {
|
||||
case *Error:
|
||||
for _, e := range err.Errors {
|
||||
flatten(e, flatErr)
|
||||
}
|
||||
default:
|
||||
flatErr.Errors = append(flatErr.Errors, err)
|
||||
}
|
||||
}
|
||||
27
vendor/github.com/hashicorp/go-multierror/format.go
generated
vendored
27
vendor/github.com/hashicorp/go-multierror/format.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package multierror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrorFormatFunc is a function callback that is called by Error to
|
||||
// turn the list of errors into a string.
|
||||
type ErrorFormatFunc func([]error) string
|
||||
|
||||
// ListFormatFunc is a basic formatter that outputs the number of errors
|
||||
// that occurred along with a bullet point list of the errors.
|
||||
func ListFormatFunc(es []error) string {
|
||||
if len(es) == 1 {
|
||||
return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
|
||||
}
|
||||
|
||||
points := make([]string, len(es))
|
||||
for i, err := range es {
|
||||
points[i] = fmt.Sprintf("* %s", err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%d errors occurred:\n\t%s\n\n",
|
||||
len(es), strings.Join(points, "\n\t"))
|
||||
}
|
||||
38
vendor/github.com/hashicorp/go-multierror/group.go
generated
vendored
38
vendor/github.com/hashicorp/go-multierror/group.go
generated
vendored
@@ -1,38 +0,0 @@
|
||||
package multierror
|
||||
|
||||
import "sync"
|
||||
|
||||
// Group is a collection of goroutines which return errors that need to be
|
||||
// coalesced.
|
||||
type Group struct {
|
||||
mutex sync.Mutex
|
||||
err *Error
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// Go calls the given function in a new goroutine.
|
||||
//
|
||||
// If the function returns an error it is added to the group multierror which
|
||||
// is returned by Wait.
|
||||
func (g *Group) Go(f func() error) {
|
||||
g.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer g.wg.Done()
|
||||
|
||||
if err := f(); err != nil {
|
||||
g.mutex.Lock()
|
||||
g.err = Append(g.err, err)
|
||||
g.mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait blocks until all function calls from the Go method have returned, then
|
||||
// returns the multierror.
|
||||
func (g *Group) Wait() *Error {
|
||||
g.wg.Wait()
|
||||
g.mutex.Lock()
|
||||
defer g.mutex.Unlock()
|
||||
return g.err
|
||||
}
|
||||
121
vendor/github.com/hashicorp/go-multierror/multierror.go
generated
vendored
121
vendor/github.com/hashicorp/go-multierror/multierror.go
generated
vendored
@@ -1,121 +0,0 @@
|
||||
package multierror
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Error is an error type to track multiple errors. This is used to
|
||||
// accumulate errors in cases and return them as a single "error".
|
||||
type Error struct {
|
||||
Errors []error
|
||||
ErrorFormat ErrorFormatFunc
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
fn := e.ErrorFormat
|
||||
if fn == nil {
|
||||
fn = ListFormatFunc
|
||||
}
|
||||
|
||||
return fn(e.Errors)
|
||||
}
|
||||
|
||||
// ErrorOrNil returns an error interface if this Error represents
|
||||
// a list of errors, or returns nil if the list of errors is empty. This
|
||||
// function is useful at the end of accumulation to make sure that the value
|
||||
// returned represents the existence of errors.
|
||||
func (e *Error) ErrorOrNil() error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
if len(e.Errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Error) GoString() string {
|
||||
return fmt.Sprintf("*%#v", *e)
|
||||
}
|
||||
|
||||
// WrappedErrors returns the list of errors that this Error is wrapping. It is
|
||||
// an implementation of the errwrap.Wrapper interface so that multierror.Error
|
||||
// can be used with that library.
|
||||
//
|
||||
// This method is not safe to be called concurrently. Unlike accessing the
|
||||
// Errors field directly, this function also checks if the multierror is nil to
|
||||
// prevent a null-pointer panic. It satisfies the errwrap.Wrapper interface.
|
||||
func (e *Error) WrappedErrors() []error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Errors
|
||||
}
|
||||
|
||||
// Unwrap returns an error from Error (or nil if there are no errors).
|
||||
// This error returned will further support Unwrap to get the next error,
|
||||
// etc. The order will match the order of Errors in the multierror.Error
|
||||
// at the time of calling.
|
||||
//
|
||||
// The resulting error supports errors.As/Is/Unwrap so you can continue
|
||||
// to use the stdlib errors package to introspect further.
|
||||
//
|
||||
// This will perform a shallow copy of the errors slice. Any errors appended
|
||||
// to this error after calling Unwrap will not be available until a new
|
||||
// Unwrap is called on the multierror.Error.
|
||||
func (e *Error) Unwrap() error {
|
||||
// If we have no errors then we do nothing
|
||||
if e == nil || len(e.Errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we have exactly one error, we can just return that directly.
|
||||
if len(e.Errors) == 1 {
|
||||
return e.Errors[0]
|
||||
}
|
||||
|
||||
// Shallow copy the slice
|
||||
errs := make([]error, len(e.Errors))
|
||||
copy(errs, e.Errors)
|
||||
return chain(errs)
|
||||
}
|
||||
|
||||
// chain implements the interfaces necessary for errors.Is/As/Unwrap to
|
||||
// work in a deterministic way with multierror. A chain tracks a list of
|
||||
// errors while accounting for the current represented error. This lets
|
||||
// Is/As be meaningful.
|
||||
//
|
||||
// Unwrap returns the next error. In the cleanest form, Unwrap would return
|
||||
// the wrapped error here but we can't do that if we want to properly
|
||||
// get access to all the errors. Instead, users are recommended to use
|
||||
// Is/As to get the correct error type out.
|
||||
//
|
||||
// Precondition: []error is non-empty (len > 0)
|
||||
type chain []error
|
||||
|
||||
// Error implements the error interface
|
||||
func (e chain) Error() string {
|
||||
return e[0].Error()
|
||||
}
|
||||
|
||||
// Unwrap implements errors.Unwrap by returning the next error in the
|
||||
// chain or nil if there are no more errors.
|
||||
func (e chain) Unwrap() error {
|
||||
if len(e) == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e[1:]
|
||||
}
|
||||
|
||||
// As implements errors.As by attempting to map to the current value.
|
||||
func (e chain) As(target interface{}) bool {
|
||||
return errors.As(e[0], target)
|
||||
}
|
||||
|
||||
// Is implements errors.Is by comparing the current value directly.
|
||||
func (e chain) Is(target error) bool {
|
||||
return errors.Is(e[0], target)
|
||||
}
|
||||
37
vendor/github.com/hashicorp/go-multierror/prefix.go
generated
vendored
37
vendor/github.com/hashicorp/go-multierror/prefix.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
package multierror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
)
|
||||
|
||||
// Prefix is a helper function that will prefix some text
|
||||
// to the given error. If the error is a multierror.Error, then
|
||||
// it will be prefixed to each wrapped error.
|
||||
//
|
||||
// This is useful to use when appending multiple multierrors
|
||||
// together in order to give better scoping.
|
||||
func Prefix(err error, prefix string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
format := fmt.Sprintf("%s {{err}}", prefix)
|
||||
switch err := err.(type) {
|
||||
case *Error:
|
||||
// Typed nils can reach here, so initialize if we are nil
|
||||
if err == nil {
|
||||
err = new(Error)
|
||||
}
|
||||
|
||||
// Wrap each of the errors
|
||||
for i, e := range err.Errors {
|
||||
err.Errors[i] = errwrap.Wrapf(format, e)
|
||||
}
|
||||
|
||||
return err
|
||||
default:
|
||||
return errwrap.Wrapf(format, err)
|
||||
}
|
||||
}
|
||||
16
vendor/github.com/hashicorp/go-multierror/sort.go
generated
vendored
16
vendor/github.com/hashicorp/go-multierror/sort.go
generated
vendored
@@ -1,16 +0,0 @@
|
||||
package multierror
|
||||
|
||||
// Len implements sort.Interface function for length
|
||||
func (err Error) Len() int {
|
||||
return len(err.Errors)
|
||||
}
|
||||
|
||||
// Swap implements sort.Interface function for swapping elements
|
||||
func (err Error) Swap(i, j int) {
|
||||
err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
|
||||
}
|
||||
|
||||
// Less implements sort.Interface function for determining order
|
||||
func (err Error) Less(i, j int) bool {
|
||||
return err.Errors[i].Error() < err.Errors[j].Error()
|
||||
}
|
||||
46
vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
generated
vendored
46
vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
generated
vendored
@@ -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 (
|
||||
|
||||
122
vendor/github.com/opencontainers/runtime-tools/error/error.go
generated
vendored
122
vendor/github.com/opencontainers/runtime-tools/error/error.go
generated
vendored
@@ -1,122 +0,0 @@
|
||||
// Package error implements generic tooling for tracking RFC 2119
|
||||
// violations and linking back to the appropriate specification section.
|
||||
package error
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Level represents the RFC 2119 compliance levels
|
||||
type Level int
|
||||
|
||||
const (
|
||||
// MAY-level
|
||||
|
||||
// May represents 'MAY' in RFC 2119.
|
||||
May Level = iota
|
||||
// Optional represents 'OPTIONAL' in RFC 2119.
|
||||
Optional
|
||||
|
||||
// SHOULD-level
|
||||
|
||||
// Should represents 'SHOULD' in RFC 2119.
|
||||
Should
|
||||
// ShouldNot represents 'SHOULD NOT' in RFC 2119.
|
||||
ShouldNot
|
||||
// Recommended represents 'RECOMMENDED' in RFC 2119.
|
||||
Recommended
|
||||
// NotRecommended represents 'NOT RECOMMENDED' in RFC 2119.
|
||||
NotRecommended
|
||||
|
||||
// MUST-level
|
||||
|
||||
// Must represents 'MUST' in RFC 2119
|
||||
Must
|
||||
// MustNot represents 'MUST NOT' in RFC 2119.
|
||||
MustNot
|
||||
// Shall represents 'SHALL' in RFC 2119.
|
||||
Shall
|
||||
// ShallNot represents 'SHALL NOT' in RFC 2119.
|
||||
ShallNot
|
||||
// Required represents 'REQUIRED' in RFC 2119.
|
||||
Required
|
||||
)
|
||||
|
||||
// Error represents an error with compliance level and specification reference.
|
||||
type Error struct {
|
||||
// Level represents the RFC 2119 compliance level.
|
||||
Level Level
|
||||
|
||||
// Reference is a URL for the violated specification requirement.
|
||||
Reference string
|
||||
|
||||
// Err holds additional details about the violation.
|
||||
Err error
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the RFC 2119 compliance level constant.
|
||||
func ParseLevel(level string) (Level, error) {
|
||||
switch strings.ToUpper(level) {
|
||||
case "MAY":
|
||||
fallthrough
|
||||
case "OPTIONAL":
|
||||
return May, nil
|
||||
case "SHOULD":
|
||||
fallthrough
|
||||
case "SHOULDNOT":
|
||||
fallthrough
|
||||
case "RECOMMENDED":
|
||||
fallthrough
|
||||
case "NOTRECOMMENDED":
|
||||
return Should, nil
|
||||
case "MUST":
|
||||
fallthrough
|
||||
case "MUSTNOT":
|
||||
fallthrough
|
||||
case "SHALL":
|
||||
fallthrough
|
||||
case "SHALLNOT":
|
||||
fallthrough
|
||||
case "REQUIRED":
|
||||
return Must, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("%q is not a valid compliance level", level)
|
||||
}
|
||||
|
||||
// String takes a RFC 2119 compliance level constant and returns a string representation.
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case May:
|
||||
return "MAY"
|
||||
case Optional:
|
||||
return "OPTIONAL"
|
||||
case Should:
|
||||
return "SHOULD"
|
||||
case ShouldNot:
|
||||
return "SHOULD NOT"
|
||||
case Recommended:
|
||||
return "RECOMMENDED"
|
||||
case NotRecommended:
|
||||
return "NOT RECOMMENDED"
|
||||
case Must:
|
||||
return "MUST"
|
||||
case MustNot:
|
||||
return "MUST NOT"
|
||||
case Shall:
|
||||
return "SHALL"
|
||||
case ShallNot:
|
||||
return "SHALL NOT"
|
||||
case Required:
|
||||
return "REQUIRED"
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("%d is not a valid compliance level", level))
|
||||
}
|
||||
|
||||
// Error returns the error message with specification reference.
|
||||
func (err *Error) Error() string {
|
||||
return fmt.Sprintf("%s\nRefer to: %s", err.Err.Error(), err.Reference)
|
||||
}
|
||||
48
vendor/github.com/opencontainers/runtime-tools/filepath/abs.go
generated
vendored
48
vendor/github.com/opencontainers/runtime-tools/filepath/abs.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
package filepath
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var windowsAbs = regexp.MustCompile(`^[a-zA-Z]:\\.*$`)
|
||||
|
||||
// Abs is a version of path/filepath's Abs with an explicit operating
|
||||
// system and current working directory.
|
||||
func Abs(os, path, cwd string) (_ string, err error) {
|
||||
if IsAbs(os, path) {
|
||||
return Clean(os, path), nil
|
||||
}
|
||||
return Clean(os, Join(os, cwd, path)), nil
|
||||
}
|
||||
|
||||
// IsAbs is a version of path/filepath's IsAbs with an explicit
|
||||
// operating system.
|
||||
func IsAbs(os, path string) bool {
|
||||
if os == "windows" {
|
||||
// FIXME: copy hideous logic from Go's
|
||||
// src/path/filepath/path_windows.go into somewhere where we can
|
||||
// put 3-clause BSD licensed code.
|
||||
return windowsAbs.MatchString(path)
|
||||
}
|
||||
sep := Separator(os)
|
||||
|
||||
// POSIX has [1]:
|
||||
//
|
||||
// > If a pathname begins with two successive <slash> characters,
|
||||
// > the first component following the leading <slash> characters
|
||||
// > may be interpreted in an implementation-defined manner,
|
||||
// > although more than two leading <slash> characters shall be
|
||||
// > treated as a single <slash> character.
|
||||
//
|
||||
// And Boost treats // as non-absolute [2], but Linux [3,4], Python
|
||||
// [5] and Go [6] all treat // as absolute.
|
||||
//
|
||||
// [1]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
|
||||
// [2]: https://github.com/boostorg/filesystem/blob/boost-1.64.0/test/path_test.cpp#L861
|
||||
// [3]: http://man7.org/linux/man-pages/man7/path_resolution.7.html
|
||||
// [4]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/path-lookup.md?h=v4.12#n41
|
||||
// [5]: https://github.com/python/cpython/blob/v3.6.1/Lib/posixpath.py#L64-L66
|
||||
// [6]: https://go.googlesource.com/go/+/go1.8.3/src/path/path.go#199
|
||||
return strings.HasPrefix(path, string(sep))
|
||||
}
|
||||
32
vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go
generated
vendored
32
vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go
generated
vendored
@@ -1,32 +0,0 @@
|
||||
package filepath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsAncestor returns true when pathB is an strict ancestor of pathA,
|
||||
// and false where the paths are equal or pathB is outside of pathA.
|
||||
// Paths that are not absolute will be made absolute with Abs.
|
||||
func IsAncestor(os, pathA, pathB, cwd string) (_ bool, err error) {
|
||||
if pathA == pathB {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
pathA, err = Abs(os, pathA, cwd)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
pathB, err = Abs(os, pathB, cwd)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
sep := Separator(os)
|
||||
if !strings.HasSuffix(pathA, string(sep)) {
|
||||
pathA = fmt.Sprintf("%s%c", pathA, sep)
|
||||
}
|
||||
if pathA == pathB {
|
||||
return false, nil
|
||||
}
|
||||
return strings.HasPrefix(pathB, pathA), nil
|
||||
}
|
||||
74
vendor/github.com/opencontainers/runtime-tools/filepath/clean.go
generated
vendored
74
vendor/github.com/opencontainers/runtime-tools/filepath/clean.go
generated
vendored
@@ -1,74 +0,0 @@
|
||||
package filepath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Clean is an explicit-OS version of path/filepath's Clean.
|
||||
func Clean(os, path string) string {
|
||||
abs := IsAbs(os, path)
|
||||
sep := Separator(os)
|
||||
elements := strings.Split(path, string(sep))
|
||||
|
||||
// Replace multiple Separator elements with a single one.
|
||||
for i := 0; i < len(elements); i++ {
|
||||
if len(elements[i]) == 0 {
|
||||
elements = append(elements[:i], elements[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminate each . path name element (the current directory).
|
||||
for i := 0; i < len(elements); i++ {
|
||||
if elements[i] == "." && len(elements) > 1 {
|
||||
elements = append(elements[:i], elements[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminate each inner .. path name element (the parent directory)
|
||||
// along with the non-.. element that precedes it.
|
||||
for i := 1; i < len(elements); i++ {
|
||||
if i == 1 && abs && sep == '\\' {
|
||||
continue
|
||||
}
|
||||
if i > 0 && elements[i] == ".." {
|
||||
elements = append(elements[:i-1], elements[i+1:]...)
|
||||
i -= 2
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminate .. elements that begin a rooted path:
|
||||
// that is, replace "/.." by "/" at the beginning of a path,
|
||||
// assuming Separator is '/'.
|
||||
offset := 0
|
||||
if sep == '\\' {
|
||||
offset = 1
|
||||
}
|
||||
if abs {
|
||||
for len(elements) > offset && elements[offset] == ".." {
|
||||
elements = append(elements[:offset], elements[offset+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
cleaned := strings.Join(elements, string(sep))
|
||||
if abs {
|
||||
if sep == '/' {
|
||||
cleaned = fmt.Sprintf("%c%s", sep, cleaned)
|
||||
} else if len(elements) == 1 {
|
||||
cleaned = fmt.Sprintf("%s%c", cleaned, sep)
|
||||
}
|
||||
}
|
||||
|
||||
// If the result of this process is an empty string, Clean returns
|
||||
// the string ".".
|
||||
if len(cleaned) == 0 {
|
||||
cleaned = "."
|
||||
}
|
||||
|
||||
if cleaned == path {
|
||||
return path
|
||||
}
|
||||
return Clean(os, cleaned)
|
||||
}
|
||||
6
vendor/github.com/opencontainers/runtime-tools/filepath/doc.go
generated
vendored
6
vendor/github.com/opencontainers/runtime-tools/filepath/doc.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
// Package filepath implements Go's filepath package with explicit
|
||||
// operating systems (and for some functions and explicit working
|
||||
// directory). This allows tools built for one OS to operate on paths
|
||||
// targeting another OS. For example, a Linux build can determine
|
||||
// whether a path is absolute on Linux or on Windows.
|
||||
package filepath
|
||||
9
vendor/github.com/opencontainers/runtime-tools/filepath/join.go
generated
vendored
9
vendor/github.com/opencontainers/runtime-tools/filepath/join.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
package filepath
|
||||
|
||||
import "strings"
|
||||
|
||||
// Join is an explicit-OS version of path/filepath's Join.
|
||||
func Join(os string, elem ...string) string {
|
||||
sep := Separator(os)
|
||||
return Clean(os, strings.Join(elem, string(sep)))
|
||||
}
|
||||
9
vendor/github.com/opencontainers/runtime-tools/filepath/separator.go
generated
vendored
9
vendor/github.com/opencontainers/runtime-tools/filepath/separator.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
package filepath
|
||||
|
||||
// Separator is an explicit-OS version of path/filepath's Separator.
|
||||
func Separator(os string) rune {
|
||||
if os == "windows" {
|
||||
return '\\'
|
||||
}
|
||||
return '/'
|
||||
}
|
||||
57
vendor/github.com/opencontainers/runtime-tools/generate/generate.go
generated
vendored
57
vendor/github.com/opencontainers/runtime-tools/generate/generate.go
generated
vendored
@@ -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"
|
||||
)
|
||||
|
||||
@@ -42,7 +42,7 @@ type ExportOptions struct {
|
||||
// New creates a configuration Generator with the default
|
||||
// configuration for the target operating system.
|
||||
func New(os string) (generator Generator, err error) {
|
||||
if os != "linux" && os != "solaris" && os != "windows" {
|
||||
if os != "linux" && os != "solaris" && os != "windows" && os != "freebsd" {
|
||||
return generator, fmt.Errorf("no defaults configured for %s", os)
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func New(os string) (generator Generator, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
if os == "linux" || os == "solaris" {
|
||||
if os == "linux" || os == "solaris" || os == "freebsd" {
|
||||
config.Process.User = rspec.User{}
|
||||
config.Process.Env = []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
@@ -237,6 +237,21 @@ func New(os string) (generator Generator, err error) {
|
||||
},
|
||||
Seccomp: seccomp.DefaultProfile(&config),
|
||||
}
|
||||
} else if os == "freebsd" {
|
||||
config.Mounts = []rspec.Mount{
|
||||
{
|
||||
Destination: "/dev",
|
||||
Type: "devfs",
|
||||
Source: "devfs",
|
||||
Options: []string{"ruleset=4"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/fd",
|
||||
Type: "fdescfs",
|
||||
Source: "fdesc",
|
||||
Options: []string{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
envCache := map[string]int{}
|
||||
@@ -249,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 {
|
||||
@@ -1125,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())))
|
||||
@@ -1159,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
|
||||
}
|
||||
|
||||
@@ -1222,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
|
||||
}
|
||||
|
||||
@@ -1246,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
|
||||
}
|
||||
|
||||
@@ -1269,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
|
||||
}
|
||||
|
||||
@@ -1292,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
|
||||
}
|
||||
|
||||
@@ -1315,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
|
||||
}
|
||||
|
||||
@@ -1368,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.
|
||||
@@ -1384,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.
|
||||
@@ -1400,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.
|
||||
@@ -1416,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.
|
||||
@@ -1432,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.
|
||||
@@ -1448,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) {
|
||||
@@ -1606,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()
|
||||
|
||||
18
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
generated
vendored
18
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
generated
vendored
@@ -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",
|
||||
@@ -303,6 +306,7 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp {
|
||||
"stat64",
|
||||
"statfs",
|
||||
"statfs64",
|
||||
"statx",
|
||||
"symlink",
|
||||
"symlinkat",
|
||||
"sync",
|
||||
@@ -353,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,
|
||||
@@ -512,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,
|
||||
},
|
||||
|
||||
15
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go
generated
vendored
15
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go
generated
vendored
@@ -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
|
||||
)
|
||||
|
||||
29
vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go
generated
vendored
29
vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
// define error codes
|
||||
const (
|
||||
// ConfigInRootBundleDir represents "This REQUIRED file MUST reside in the root of the bundle directory"
|
||||
ConfigInRootBundleDir Code = 0xa001 + iota
|
||||
// ConfigConstName represents "This REQUIRED file MUST be named `config.json`."
|
||||
ConfigConstName
|
||||
// ArtifactsInSingleDir represents "When supplied, while these artifacts MUST all be present in a single directory on the local filesystem, that directory itself is not part of the bundle."
|
||||
ArtifactsInSingleDir
|
||||
)
|
||||
|
||||
var (
|
||||
containerFormatRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "bundle.md#container-format"), nil
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(ConfigInRootBundleDir, rfc2119.Must, containerFormatRef)
|
||||
register(ConfigConstName, rfc2119.Must, containerFormatRef)
|
||||
register(ArtifactsInSingleDir, rfc2119.Must, containerFormatRef)
|
||||
}
|
||||
134
vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go
generated
vendored
134
vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go
generated
vendored
@@ -1,134 +0,0 @@
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
// define error codes
|
||||
const (
|
||||
// DefaultFilesystems represents "The following filesystems SHOULD be made available in each container's filesystem:"
|
||||
DefaultFilesystems Code = 0xc001 + iota
|
||||
// NSPathAbs represents "This value MUST be an absolute path in the runtime mount namespace."
|
||||
NSPathAbs
|
||||
// NSProcInPath represents "The runtime MUST place the container process in the namespace associated with that `path`."
|
||||
NSProcInPath
|
||||
// NSPathMatchTypeError represents "The runtime MUST generate an error if `path` is not associated with a namespace of type `type`."
|
||||
NSPathMatchTypeError
|
||||
// NSNewNSWithoutPath represents "If `path` is not specified, the runtime MUST create a new container namespace of type `type`."
|
||||
NSNewNSWithoutPath
|
||||
// NSInheritWithoutType represents "If a namespace type is not specified in the `namespaces` array, the container MUST inherit the runtime namespace of that type."
|
||||
NSInheritWithoutType
|
||||
// NSErrorOnDup represents "If a `namespaces` field contains duplicated namespaces with same `type`, the runtime MUST generate an error."
|
||||
NSErrorOnDup
|
||||
// UserNSMapOwnershipRO represents "The runtime SHOULD NOT modify the ownership of referenced filesystems to realize the mapping."
|
||||
UserNSMapOwnershipRO
|
||||
// DevicesAvailable represents "devices (array of objects, OPTIONAL) lists devices that MUST be available in the container."
|
||||
DevicesAvailable
|
||||
// DevicesFileNotMatch represents "If a file already exists at `path` that does not match the requested device, the runtime MUST generate an error."
|
||||
DevicesFileNotMatch
|
||||
// DevicesMajMinRequired represents "`major, minor` (int64, REQUIRED unless `type` is `p`) - major, minor numbers for the device."
|
||||
DevicesMajMinRequired
|
||||
// DevicesErrorOnDup represents "The same `type`, `major` and `minor` SHOULD NOT be used for multiple devices."
|
||||
DevicesErrorOnDup
|
||||
// DefaultDevices represents "In addition to any devices configured with this setting, the runtime MUST also supply default devices."
|
||||
DefaultDevices
|
||||
// CgroupsPathAbsOrRel represents "The value of `cgroupsPath` MUST be either an absolute path or a relative path."
|
||||
CgroupsPathAbsOrRel
|
||||
// CgroupsAbsPathRelToMount represents "In the case of an absolute path (starting with `/`), the runtime MUST take the path to be relative to the cgroups mount point."
|
||||
CgroupsAbsPathRelToMount
|
||||
// CgroupsPathAttach represents "If the value is specified, the runtime MUST consistently attach to the same place in the cgroups hierarchy given the same value of `cgroupsPath`."
|
||||
CgroupsPathAttach
|
||||
// CgroupsPathError represents "Runtimes MAY consider certain `cgroupsPath` values to be invalid, and MUST generate an error if this is the case."
|
||||
CgroupsPathError
|
||||
// DevicesApplyInOrder represents "The runtime MUST apply entries in the listed order."
|
||||
DevicesApplyInOrder
|
||||
// BlkIOWeightOrLeafWeightExist represents "You MUST specify at least one of `weight` or `leafWeight` in a given entry, and MAY specify both."
|
||||
BlkIOWeightOrLeafWeightExist
|
||||
// IntelRdtPIDWrite represents "If `intelRdt` is set, the runtime MUST write the container process ID to the `<container-id>/tasks` file in a mounted `resctrl` pseudo-filesystem, using the container ID from `start` and creating the `container-id` directory if necessary."
|
||||
IntelRdtPIDWrite
|
||||
// IntelRdtNoMountedResctrlError represents "If no mounted `resctrl` pseudo-filesystem is available in the runtime mount namespace, the runtime MUST generate an error."
|
||||
IntelRdtNoMountedResctrlError
|
||||
// NotManipResctrlWithoutIntelRdt represents "If `intelRdt` is not set, the runtime MUST NOT manipulate any `resctrl` pseudo-filesystems."
|
||||
NotManipResctrlWithoutIntelRdt
|
||||
// IntelRdtL3CacheSchemaWrite represents "If `l3CacheSchema` is set, runtimes MUST write the value to the `schemata` file in the `<container-id>` directory discussed in `intelRdt`."
|
||||
IntelRdtL3CacheSchemaWrite
|
||||
// IntelRdtL3CacheSchemaNotWrite represents "If `l3CacheSchema` is not set, runtimes MUST NOT write to `schemata` files in any `resctrl` pseudo-filesystems."
|
||||
IntelRdtL3CacheSchemaNotWrite
|
||||
// SeccSyscallsNamesRequired represents "`names` MUST contain at least one entry."
|
||||
SeccSyscallsNamesRequired
|
||||
// MaskedPathsAbs represents "maskedPaths (array of strings, OPTIONAL) will mask over the provided paths inside the container so that they cannot be read. The values MUST be absolute paths in the container namespace."
|
||||
MaskedPathsAbs
|
||||
// ReadonlyPathsAbs represents "readonlyPaths (array of strings, OPTIONAL) will set the provided paths as readonly inside the container. The values MUST be absolute paths in the container namespace."
|
||||
ReadonlyPathsAbs
|
||||
)
|
||||
|
||||
var (
|
||||
defaultFilesystemsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil
|
||||
}
|
||||
namespacesRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#namespaces"), nil
|
||||
}
|
||||
userNamespaceMappingsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#user-namespace-mappings"), nil
|
||||
}
|
||||
devicesRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#devices"), nil
|
||||
}
|
||||
defaultDevicesRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-devices"), nil
|
||||
}
|
||||
cgroupsPathRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#cgroups-path"), nil
|
||||
}
|
||||
deviceWhitelistRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#device-whitelist"), nil
|
||||
}
|
||||
blockIoRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#block-io"), nil
|
||||
}
|
||||
intelrdtRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#intelrdt"), nil
|
||||
}
|
||||
seccompRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#seccomp"), nil
|
||||
}
|
||||
maskedPathsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#masked-paths"), nil
|
||||
}
|
||||
readonlyPathsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-linux.md#readonly-paths"), nil
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(DefaultFilesystems, rfc2119.Should, defaultFilesystemsRef)
|
||||
register(NSPathAbs, rfc2119.Must, namespacesRef)
|
||||
register(NSProcInPath, rfc2119.Must, namespacesRef)
|
||||
register(NSPathMatchTypeError, rfc2119.Must, namespacesRef)
|
||||
register(NSNewNSWithoutPath, rfc2119.Must, namespacesRef)
|
||||
register(NSInheritWithoutType, rfc2119.Must, namespacesRef)
|
||||
register(NSErrorOnDup, rfc2119.Must, namespacesRef)
|
||||
register(UserNSMapOwnershipRO, rfc2119.Should, userNamespaceMappingsRef)
|
||||
register(DevicesAvailable, rfc2119.Must, devicesRef)
|
||||
register(DevicesFileNotMatch, rfc2119.Must, devicesRef)
|
||||
register(DevicesMajMinRequired, rfc2119.Required, devicesRef)
|
||||
register(DevicesErrorOnDup, rfc2119.Should, devicesRef)
|
||||
register(DefaultDevices, rfc2119.Must, defaultDevicesRef)
|
||||
register(CgroupsPathAbsOrRel, rfc2119.Must, cgroupsPathRef)
|
||||
register(CgroupsAbsPathRelToMount, rfc2119.Must, cgroupsPathRef)
|
||||
register(CgroupsPathAttach, rfc2119.Must, cgroupsPathRef)
|
||||
register(CgroupsPathError, rfc2119.Must, cgroupsPathRef)
|
||||
register(DevicesApplyInOrder, rfc2119.Must, deviceWhitelistRef)
|
||||
register(BlkIOWeightOrLeafWeightExist, rfc2119.Must, blockIoRef)
|
||||
register(IntelRdtPIDWrite, rfc2119.Must, intelrdtRef)
|
||||
register(IntelRdtNoMountedResctrlError, rfc2119.Must, intelrdtRef)
|
||||
register(NotManipResctrlWithoutIntelRdt, rfc2119.Must, intelrdtRef)
|
||||
register(IntelRdtL3CacheSchemaWrite, rfc2119.Must, intelrdtRef)
|
||||
register(IntelRdtL3CacheSchemaNotWrite, rfc2119.Must, intelrdtRef)
|
||||
register(SeccSyscallsNamesRequired, rfc2119.Must, seccompRef)
|
||||
register(MaskedPathsAbs, rfc2119.Must, maskedPathsRef)
|
||||
register(ReadonlyPathsAbs, rfc2119.Must, readonlyPathsRef)
|
||||
}
|
||||
32
vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go
generated
vendored
32
vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go
generated
vendored
@@ -1,32 +0,0 @@
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
// define error codes
|
||||
const (
|
||||
// WindowsLayerFoldersRequired represents "`layerFolders` MUST contain at least one entry."
|
||||
WindowsLayerFoldersRequired Code = 0xd001 + iota
|
||||
// WindowsHyperVPresent represents "If present, the container MUST be run with Hyper-V isolation."
|
||||
WindowsHyperVPresent
|
||||
// WindowsHyperVOmit represents "If omitted, the container MUST be run as a Windows Server container."
|
||||
WindowsHyperVOmit
|
||||
)
|
||||
|
||||
var (
|
||||
layerfoldersRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-windows.md#layerfolders"), nil
|
||||
}
|
||||
hypervRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config-windows.md#hyperv"), nil
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(WindowsLayerFoldersRequired, rfc2119.Must, layerfoldersRef)
|
||||
register(WindowsHyperVPresent, rfc2119.Must, hypervRef)
|
||||
register(WindowsHyperVOmit, rfc2119.Must, hypervRef)
|
||||
}
|
||||
188
vendor/github.com/opencontainers/runtime-tools/specerror/config.go
generated
vendored
188
vendor/github.com/opencontainers/runtime-tools/specerror/config.go
generated
vendored
@@ -1,188 +0,0 @@
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
// define error codes
|
||||
const (
|
||||
// SpecVersionInSemVer represents "`ociVersion` (string, REQUIRED) MUST be in SemVer v2.0.0 format and specifies the version of the Open Container Initiative Runtime Specification with which the bundle complies."
|
||||
SpecVersionInSemVer Code = 0xb001 + iota
|
||||
// RootOnWindowsRequired represents "On Windows, for Windows Server Containers, this field is REQUIRED."
|
||||
RootOnWindowsRequired
|
||||
// RootOnHyperVNotSet represents "For Hyper-V Containers, this field MUST NOT be set."
|
||||
RootOnHyperVNotSet
|
||||
// RootOnNonWindowsRequired represents "On all other platforms, this field is REQUIRED."
|
||||
RootOnNonWindowsRequired
|
||||
// RootPathOnWindowsGUID represents "On Windows, `path` MUST be a volume GUID path."
|
||||
RootPathOnWindowsGUID
|
||||
// RootPathOnPosixConvention represents "The value SHOULD be the conventional `rootfs`."
|
||||
RootPathOnPosixConvention
|
||||
// RootPathExist represents "A directory MUST exist at the path declared by the field."
|
||||
RootPathExist
|
||||
// RootReadonlyImplement represents "`readonly` (bool, OPTIONAL) If true then the root filesystem MUST be read-only inside the container, defaults to false."
|
||||
RootReadonlyImplement
|
||||
// RootReadonlyOnWindowsFalse represents "* On Windows, this field MUST be omitted or false."
|
||||
RootReadonlyOnWindowsFalse
|
||||
// MountsInOrder represents "The runtime MUST mount entries in the listed order."
|
||||
MountsInOrder
|
||||
// MountsDestAbs represents "Destination of mount point: path inside container. This value MUST be an absolute path."
|
||||
MountsDestAbs
|
||||
// MountsDestOnWindowsNotNested represents "Windows: one mount destination MUST NOT be nested within another mount (e.g., c:\\foo and c:\\foo\\bar)."
|
||||
MountsDestOnWindowsNotNested
|
||||
// MountsOptionsOnWindowsROSupport represents "Windows: runtimes MUST support `ro`, mounting the filesystem read-only when `ro` is given."
|
||||
MountsOptionsOnWindowsROSupport
|
||||
// ProcRequiredAtStart represents "This property is REQUIRED when `start` is called."
|
||||
ProcRequiredAtStart
|
||||
// ProcConsoleSizeIgnore represents "Runtimes MUST ignore `consoleSize` if `terminal` is `false` or unset."
|
||||
ProcConsoleSizeIgnore
|
||||
// ProcCwdAbs represents "cwd (string, REQUIRED) is the working directory that will be set for the executable. This value MUST be an absolute path."
|
||||
ProcCwdAbs
|
||||
// ProcArgsOneEntryRequired represents "This specification extends the IEEE standard in that at least one entry is REQUIRED, and that entry is used with the same semantics as `execvp`'s *file*."
|
||||
ProcArgsOneEntryRequired
|
||||
// PosixProcRlimitsTypeGenError represents "The runtime MUST generate an error for any values which cannot be mapped to a relevant kernel interface."
|
||||
PosixProcRlimitsTypeGenError
|
||||
// PosixProcRlimitsTypeGet represents "For each entry in `rlimits`, a `getrlimit(3)` on `type` MUST succeed."
|
||||
PosixProcRlimitsTypeGet
|
||||
// PosixProcRlimitsTypeValueError represents "valid values are defined in the ... man page"
|
||||
PosixProcRlimitsTypeValueError
|
||||
// PosixProcRlimitsSoftMatchCur represents "`rlim.rlim_cur` MUST match the configured value."
|
||||
PosixProcRlimitsSoftMatchCur
|
||||
// PosixProcRlimitsHardMatchMax represents "`rlim.rlim_max` MUST match the configured value."
|
||||
PosixProcRlimitsHardMatchMax
|
||||
// PosixProcRlimitsErrorOnDup represents "If `rlimits` contains duplicated entries with same `type`, the runtime MUST generate an error."
|
||||
PosixProcRlimitsErrorOnDup
|
||||
// LinuxProcCapError represents "Any value which cannot be mapped to a relevant kernel interface MUST cause an error."
|
||||
LinuxProcCapError
|
||||
// LinuxProcOomScoreAdjSet represents "If `oomScoreAdj` is set, the runtime MUST set `oom_score_adj` to the given value."
|
||||
LinuxProcOomScoreAdjSet
|
||||
// LinuxProcOomScoreAdjNotSet represents "If `oomScoreAdj` is not set, the runtime MUST NOT change the value of `oom_score_adj`."
|
||||
LinuxProcOomScoreAdjNotSet
|
||||
// PlatformSpecConfOnWindowsSet represents "This MUST be set if the target platform of this spec is `windows`."
|
||||
PlatformSpecConfOnWindowsSet
|
||||
// PosixHooksPathAbs represents "This specification extends the IEEE standard in that `path` MUST be absolute."
|
||||
PosixHooksPathAbs
|
||||
// PosixHooksTimeoutPositive represents "If set, `timeout` MUST be greater than zero."
|
||||
PosixHooksTimeoutPositive
|
||||
// PosixHooksCalledInOrder represents "Hooks MUST be called in the listed order."
|
||||
PosixHooksCalledInOrder
|
||||
// PosixHooksStateToStdin represents "The state of the container MUST be passed to hooks over stdin so that they may do work appropriate to the current state of the container."
|
||||
PosixHooksStateToStdin
|
||||
// PrestartTiming represents "The pre-start hooks MUST be called after the `start` operation is called but before the user-specified program command is executed."
|
||||
PrestartTiming
|
||||
// PoststartTiming represents "The post-start hooks MUST be called after the user-specified process is executed but before the `start` operation returns."
|
||||
PoststartTiming
|
||||
// PoststopTiming represents "The post-stop hooks MUST be called after the container is deleted but before the `delete` operation returns."
|
||||
PoststopTiming
|
||||
// AnnotationsKeyValueMap represents "Annotations MUST be a key-value map."
|
||||
AnnotationsKeyValueMap
|
||||
// AnnotationsKeyString represents "Keys MUST be strings."
|
||||
AnnotationsKeyString
|
||||
// AnnotationsKeyRequired represents "Keys MUST NOT be an empty string."
|
||||
AnnotationsKeyRequired
|
||||
// AnnotationsKeyReversedDomain represents "Keys SHOULD be named using a reverse domain notation - e.g. `com.example.myKey`."
|
||||
AnnotationsKeyReversedDomain
|
||||
// AnnotationsKeyReservedNS represents "Keys using the `org.opencontainers` namespace are reserved and MUST NOT be used by subsequent specifications."
|
||||
AnnotationsKeyReservedNS
|
||||
// AnnotationsKeyIgnoreUnknown represents "Implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key."
|
||||
AnnotationsKeyIgnoreUnknown
|
||||
// AnnotationsValueString represents "Values MUST be strings."
|
||||
AnnotationsValueString
|
||||
// ExtensibilityIgnoreUnknownProp represents "Runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property."
|
||||
ExtensibilityIgnoreUnknownProp
|
||||
// ValidValues represents "Runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered."
|
||||
ValidValues
|
||||
)
|
||||
|
||||
var (
|
||||
specificationVersionRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#specification-version"), nil
|
||||
}
|
||||
rootRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil
|
||||
}
|
||||
mountsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#mounts"), nil
|
||||
}
|
||||
processRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#process"), nil
|
||||
}
|
||||
posixProcessRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#posix-process"), nil
|
||||
}
|
||||
linuxProcessRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#linux-process"), nil
|
||||
}
|
||||
platformSpecificConfigurationRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#platform-specific-configuration"), nil
|
||||
}
|
||||
posixPlatformHooksRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#posix-platform-hooks"), nil
|
||||
}
|
||||
prestartRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#prestart"), nil
|
||||
}
|
||||
poststartRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#poststart"), nil
|
||||
}
|
||||
poststopRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#poststop"), nil
|
||||
}
|
||||
annotationsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#annotations"), nil
|
||||
}
|
||||
extensibilityRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#extensibility"), nil
|
||||
}
|
||||
validValuesRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "config.md#valid-values"), nil
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(SpecVersionInSemVer, rfc2119.Must, specificationVersionRef)
|
||||
register(RootOnWindowsRequired, rfc2119.Required, rootRef)
|
||||
register(RootOnHyperVNotSet, rfc2119.Must, rootRef)
|
||||
register(RootOnNonWindowsRequired, rfc2119.Required, rootRef)
|
||||
register(RootPathOnWindowsGUID, rfc2119.Must, rootRef)
|
||||
register(RootPathOnPosixConvention, rfc2119.Should, rootRef)
|
||||
register(RootPathExist, rfc2119.Must, rootRef)
|
||||
register(RootReadonlyImplement, rfc2119.Must, rootRef)
|
||||
register(RootReadonlyOnWindowsFalse, rfc2119.Must, rootRef)
|
||||
register(MountsInOrder, rfc2119.Must, mountsRef)
|
||||
register(MountsDestAbs, rfc2119.Must, mountsRef)
|
||||
register(MountsDestOnWindowsNotNested, rfc2119.Must, mountsRef)
|
||||
register(MountsOptionsOnWindowsROSupport, rfc2119.Must, mountsRef)
|
||||
register(ProcRequiredAtStart, rfc2119.Required, processRef)
|
||||
register(ProcConsoleSizeIgnore, rfc2119.Must, processRef)
|
||||
register(ProcCwdAbs, rfc2119.Must, processRef)
|
||||
register(ProcArgsOneEntryRequired, rfc2119.Required, processRef)
|
||||
register(PosixProcRlimitsTypeGenError, rfc2119.Must, posixProcessRef)
|
||||
register(PosixProcRlimitsTypeGet, rfc2119.Must, posixProcessRef)
|
||||
register(PosixProcRlimitsTypeValueError, rfc2119.Should, posixProcessRef)
|
||||
register(PosixProcRlimitsSoftMatchCur, rfc2119.Must, posixProcessRef)
|
||||
register(PosixProcRlimitsHardMatchMax, rfc2119.Must, posixProcessRef)
|
||||
register(PosixProcRlimitsErrorOnDup, rfc2119.Must, posixProcessRef)
|
||||
register(LinuxProcCapError, rfc2119.Must, linuxProcessRef)
|
||||
register(LinuxProcOomScoreAdjSet, rfc2119.Must, linuxProcessRef)
|
||||
register(LinuxProcOomScoreAdjNotSet, rfc2119.Must, linuxProcessRef)
|
||||
register(PlatformSpecConfOnWindowsSet, rfc2119.Must, platformSpecificConfigurationRef)
|
||||
register(PosixHooksPathAbs, rfc2119.Must, posixPlatformHooksRef)
|
||||
register(PosixHooksTimeoutPositive, rfc2119.Must, posixPlatformHooksRef)
|
||||
register(PosixHooksCalledInOrder, rfc2119.Must, posixPlatformHooksRef)
|
||||
register(PosixHooksStateToStdin, rfc2119.Must, posixPlatformHooksRef)
|
||||
register(PrestartTiming, rfc2119.Must, prestartRef)
|
||||
register(PoststartTiming, rfc2119.Must, poststartRef)
|
||||
register(PoststopTiming, rfc2119.Must, poststopRef)
|
||||
register(AnnotationsKeyValueMap, rfc2119.Must, annotationsRef)
|
||||
register(AnnotationsKeyString, rfc2119.Must, annotationsRef)
|
||||
register(AnnotationsKeyRequired, rfc2119.Must, annotationsRef)
|
||||
register(AnnotationsKeyReversedDomain, rfc2119.Should, annotationsRef)
|
||||
register(AnnotationsKeyReservedNS, rfc2119.Must, annotationsRef)
|
||||
register(AnnotationsKeyIgnoreUnknown, rfc2119.Must, annotationsRef)
|
||||
register(AnnotationsValueString, rfc2119.Must, annotationsRef)
|
||||
register(ExtensibilityIgnoreUnknownProp, rfc2119.Must, extensibilityRef)
|
||||
register(ValidValues, rfc2119.Must, validValuesRef)
|
||||
}
|
||||
152
vendor/github.com/opencontainers/runtime-tools/specerror/error.go
generated
vendored
152
vendor/github.com/opencontainers/runtime-tools/specerror/error.go
generated
vendored
@@ -1,152 +0,0 @@
|
||||
// Package specerror implements runtime-spec-specific tooling for
|
||||
// tracking RFC 2119 violations.
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
const referenceTemplate = "https://github.com/opencontainers/runtime-spec/blob/v%s/%s"
|
||||
|
||||
// Code represents the spec violation, enumerating both
|
||||
// configuration violations and runtime violations.
|
||||
type Code int64
|
||||
|
||||
const (
|
||||
// NonError represents that an input is not an error
|
||||
NonError Code = 0x1a001 + iota
|
||||
// NonRFCError represents that an error is not a rfc2119 error
|
||||
NonRFCError
|
||||
)
|
||||
|
||||
type errorTemplate struct {
|
||||
Level rfc2119.Level
|
||||
Reference func(version string) (reference string, err error)
|
||||
}
|
||||
|
||||
// Error represents a runtime-spec violation.
|
||||
type Error struct {
|
||||
// Err holds the RFC 2119 violation.
|
||||
Err rfc2119.Error
|
||||
|
||||
// Code is a matchable holds a Code
|
||||
Code Code
|
||||
}
|
||||
|
||||
// LevelErrors represents Errors filtered into fatal and warnings.
|
||||
type LevelErrors struct {
|
||||
// Warnings holds Errors that were below a compliance-level threshold.
|
||||
Warnings []*Error
|
||||
|
||||
// Error holds errors that were at or above a compliance-level
|
||||
// threshold, as well as errors that are not Errors.
|
||||
Error *multierror.Error
|
||||
}
|
||||
|
||||
var ociErrors = map[Code]errorTemplate{}
|
||||
|
||||
func register(code Code, level rfc2119.Level, ref func(versiong string) (string, error)) {
|
||||
if _, ok := ociErrors[code]; ok {
|
||||
panic(fmt.Sprintf("should not regist a same code twice: %v", code))
|
||||
}
|
||||
|
||||
ociErrors[code] = errorTemplate{Level: level, Reference: ref}
|
||||
}
|
||||
|
||||
// Error returns the error message with specification reference.
|
||||
func (err *Error) Error() string {
|
||||
return err.Err.Error()
|
||||
}
|
||||
|
||||
// NewRFCError creates an rfc2119.Error referencing a spec violation.
|
||||
//
|
||||
// A version string (for the version of the spec that was violated)
|
||||
// must be set to get a working URL.
|
||||
func NewRFCError(code Code, err error, version string) (*rfc2119.Error, error) {
|
||||
template := ociErrors[code]
|
||||
reference, err2 := template.Reference(version)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
return &rfc2119.Error{
|
||||
Level: template.Level,
|
||||
Reference: reference,
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewRFCErrorOrPanic creates an rfc2119.Error referencing a spec
|
||||
// violation and panics on failure. This is handy for situations
|
||||
// where you can't be bothered to check NewRFCError for failure.
|
||||
func NewRFCErrorOrPanic(code Code, err error, version string) *rfc2119.Error {
|
||||
rfcError, err2 := NewRFCError(code, err, version)
|
||||
if err2 != nil {
|
||||
panic(err2.Error())
|
||||
}
|
||||
return rfcError
|
||||
}
|
||||
|
||||
// NewError creates an Error referencing a spec violation. The error
|
||||
// can be cast to an *Error for extracting structured information
|
||||
// about the level of the violation and a reference to the violated
|
||||
// spec condition.
|
||||
//
|
||||
// A version string (for the version of the spec that was violated)
|
||||
// must be set to get a working URL.
|
||||
func NewError(code Code, err error, version string) error {
|
||||
rfcError, err2 := NewRFCError(code, err, version)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return &Error{
|
||||
Err: *rfcError,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
// FindError finds an error from a source error (multiple error) and
|
||||
// returns the error code if found.
|
||||
// If the source error is nil or empty, return NonError.
|
||||
// If the source error is not a multiple error, return NonRFCError.
|
||||
func FindError(err error, code Code) Code {
|
||||
if err == nil {
|
||||
return NonError
|
||||
}
|
||||
|
||||
if merr, ok := err.(*multierror.Error); ok {
|
||||
if merr.ErrorOrNil() == nil {
|
||||
return NonError
|
||||
}
|
||||
for _, e := range merr.Errors {
|
||||
if rfcErr, ok := e.(*Error); ok {
|
||||
if rfcErr.Code == code {
|
||||
return code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NonRFCError
|
||||
}
|
||||
|
||||
// SplitLevel removes RFC 2119 errors with a level less than 'level'
|
||||
// from the source error. If the source error is not a multierror, it
|
||||
// is returned unchanged.
|
||||
func SplitLevel(errIn error, level rfc2119.Level) (levelErrors LevelErrors, errOut error) {
|
||||
merr, ok := errIn.(*multierror.Error)
|
||||
if !ok {
|
||||
return levelErrors, errIn
|
||||
}
|
||||
for _, err := range merr.Errors {
|
||||
e, ok := err.(*Error)
|
||||
if ok && e.Err.Level < level {
|
||||
fmt.Println(e)
|
||||
levelErrors.Warnings = append(levelErrors.Warnings, e)
|
||||
continue
|
||||
}
|
||||
levelErrors.Error = multierror.Append(levelErrors.Error, err)
|
||||
}
|
||||
return levelErrors, nil
|
||||
}
|
||||
23
vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go
generated
vendored
23
vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
// define error codes
|
||||
const (
|
||||
// DefaultRuntimeLinuxSymlinks represents "While creating the container (step 2 in the lifecycle), runtimes MUST create default symlinks if the source file exists after processing `mounts`."
|
||||
DefaultRuntimeLinuxSymlinks Code = 0xf001 + iota
|
||||
)
|
||||
|
||||
var (
|
||||
devSymbolicLinksRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime-linux.md#dev-symbolic-links"), nil
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(DefaultRuntimeLinuxSymlinks, rfc2119.Must, devSymbolicLinksRef)
|
||||
}
|
||||
179
vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go
generated
vendored
179
vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go
generated
vendored
@@ -1,179 +0,0 @@
|
||||
package specerror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rfc2119 "github.com/opencontainers/runtime-tools/error"
|
||||
)
|
||||
|
||||
// define error codes
|
||||
const (
|
||||
// EntityOperSameContainer represents "The entity using a runtime to create a container MUST be able to use the operations defined in this specification against that same container."
|
||||
EntityOperSameContainer Code = 0xe001 + iota
|
||||
// StateIDUniq represents "`id` (string, REQUIRED) is the container's ID. This MUST be unique across all containers on this host."
|
||||
StateIDUniq
|
||||
// StateNewStatus represents "Additional values MAY be defined by the runtime, however, they MUST be used to represent new runtime states not defined above."
|
||||
StateNewStatus
|
||||
// DefaultStateJSONPattern represents "When serialized in JSON, the format MUST adhere to the default pattern."
|
||||
DefaultStateJSONPattern
|
||||
// EnvCreateImplement represents "The container's runtime environment MUST be created according to the configuration in `config.json`."
|
||||
EnvCreateImplement
|
||||
// EnvCreateError represents "If the runtime is unable to create the environment specified in the `config.json`, it MUST generate an error."
|
||||
EnvCreateError
|
||||
// ProcNotRunAtResRequest represents "While the resources requested in the `config.json` MUST be created, the user-specified program (from `process`) MUST NOT be run at this time."
|
||||
ProcNotRunAtResRequest
|
||||
// ConfigUpdatesWithoutAffect represents "Any updates to `config.json` after this step MUST NOT affect the container."
|
||||
ConfigUpdatesWithoutAffect
|
||||
// PrestartHooksInvoke represents "The prestart hooks MUST be invoked by the runtime."
|
||||
PrestartHooksInvoke
|
||||
// PrestartHookFailGenError represents "If any prestart hook fails, the runtime MUST generate an error, stop the container, and continue the lifecycle at step 9."
|
||||
PrestartHookFailGenError
|
||||
// ProcImplement represents "The runtime MUST run the user-specified program, as specified by `process`."
|
||||
ProcImplement
|
||||
// PoststartHooksInvoke represents "The poststart hooks MUST be invoked by the runtime."
|
||||
PoststartHooksInvoke
|
||||
// PoststartHookFailGenWarn represents "If any poststart hook fails, the runtime MUST log a warning, but the remaining hooks and lifecycle continue as if the hook had succeeded."
|
||||
PoststartHookFailGenWarn
|
||||
// UndoCreateSteps represents "The container MUST be destroyed by undoing the steps performed during create phase (step 2)."
|
||||
UndoCreateSteps
|
||||
// PoststopHooksInvoke represents "The poststop hooks MUST be invoked by the runtime."
|
||||
PoststopHooksInvoke
|
||||
// PoststopHookFailGenWarn represents "If any poststop hook fails, the runtime MUST log a warning, but the remaining hooks and lifecycle continue as if the hook had succeeded."
|
||||
PoststopHookFailGenWarn
|
||||
// ErrorsLeaveStateUnchange represents "Unless otherwise stated, generating an error MUST leave the state of the environment as if the operation were never attempted - modulo any possible trivial ancillary changes such as logging."
|
||||
ErrorsLeaveStateUnchange
|
||||
// WarnsLeaveFlowUnchange represents "Unless otherwise stated, logging a warning does not change the flow of the operation; it MUST continue as if the warning had not been logged."
|
||||
WarnsLeaveFlowUnchange
|
||||
// DefaultOperations represents "Unless otherwise stated, runtimes MUST support the default operations."
|
||||
DefaultOperations
|
||||
// QueryWithoutIDGenError represents "This operation MUST generate an error if it is not provided the ID of a container."
|
||||
QueryWithoutIDGenError
|
||||
// QueryNonExistGenError represents "Attempting to query a container that does not exist MUST generate an error."
|
||||
QueryNonExistGenError
|
||||
// QueryStateImplement represents "This operation MUST return the state of a container as specified in the State section."
|
||||
QueryStateImplement
|
||||
// CreateWithBundlePathAndID represents "This operation MUST generate an error if it is not provided a path to the bundle and the container ID to associate with the container."
|
||||
CreateWithBundlePathAndID
|
||||
// CreateWithUniqueID represents "If the ID provided is not unique across all containers within the scope of the runtime, or is not valid in any other way, the implementation MUST generate an error and a new container MUST NOT be created."
|
||||
CreateWithUniqueID
|
||||
// CreateNewContainer represents "This operation MUST create a new container."
|
||||
CreateNewContainer
|
||||
// PropsApplyExceptProcOnCreate represents "All of the properties configured in `config.json` except for `process` MUST be applied."
|
||||
PropsApplyExceptProcOnCreate
|
||||
// ProcArgsApplyUntilStart represents `process.args` MUST NOT be applied until triggered by the `start` operation."
|
||||
ProcArgsApplyUntilStart
|
||||
// PropApplyFailGenError represents "If the runtime cannot apply a property as specified in the configuration, it MUST generate an error."
|
||||
PropApplyFailGenError
|
||||
// PropApplyFailNotCreate represents "If the runtime cannot apply a property as specified in the configuration, a new container MUST NOT be created."
|
||||
PropApplyFailNotCreate
|
||||
// StartWithoutIDGenError represents "`start` operation MUST generate an error if it is not provided the container ID."
|
||||
StartWithoutIDGenError
|
||||
// StartNotCreatedHaveNoEffect represents "Attempting to `start` a container that is not `created` MUST have no effect on the container."
|
||||
StartNotCreatedHaveNoEffect
|
||||
// StartNotCreatedGenError represents "Attempting to `start` a container that is not `created` MUST generate an error."
|
||||
StartNotCreatedGenError
|
||||
// StartProcImplement represents "`start` operation MUST run the user-specified program as specified by `process`."
|
||||
StartProcImplement
|
||||
// StartWithProcUnsetGenError represents "`start` operation MUST generate an error if `process` was not set."
|
||||
StartWithProcUnsetGenError
|
||||
// KillWithoutIDGenError represents "`kill` operation MUST generate an error if it is not provided the container ID."
|
||||
KillWithoutIDGenError
|
||||
// KillNonCreateRunHaveNoEffect represents "Attempting to send a signal to a container that is neither `created` nor `running` MUST have no effect on the container."
|
||||
KillNonCreateRunHaveNoEffect
|
||||
// KillNonCreateRunGenError represents "Attempting to send a signal to a container that is neither `created` nor `running` MUST generate an error."
|
||||
KillNonCreateRunGenError
|
||||
// KillSignalImplement represents "`kill` operation MUST send the specified signal to the container process."
|
||||
KillSignalImplement
|
||||
// DeleteWithoutIDGenError represents "`delete` operation MUST generate an error if it is not provided the container ID."
|
||||
DeleteWithoutIDGenError
|
||||
// DeleteNonStopHaveNoEffect represents "Attempting to `delete` a container that is not `stopped` MUST have no effect on the container."
|
||||
DeleteNonStopHaveNoEffect
|
||||
// DeleteNonStopGenError represents "Attempting to `delete` a container that is not `stopped` MUST generate an error."
|
||||
DeleteNonStopGenError
|
||||
// DeleteResImplement represents "Deleting a container MUST delete the resources that were created during the `create` step."
|
||||
DeleteResImplement
|
||||
// DeleteOnlyCreatedRes represents "Note that resources associated with the container, but not created by this container, MUST NOT be deleted."
|
||||
DeleteOnlyCreatedRes
|
||||
)
|
||||
|
||||
var (
|
||||
scopeOfAContainerRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#scope-of-a-container"), nil
|
||||
}
|
||||
stateRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#state"), nil
|
||||
}
|
||||
lifecycleRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#lifecycle"), nil
|
||||
}
|
||||
errorsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#errors"), nil
|
||||
}
|
||||
warningsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#warnings"), nil
|
||||
}
|
||||
operationsRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#operations"), nil
|
||||
}
|
||||
queryStateRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#query-state"), nil
|
||||
}
|
||||
createRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#create"), nil
|
||||
}
|
||||
startRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#start"), nil
|
||||
}
|
||||
killRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#kill"), nil
|
||||
}
|
||||
deleteRef = func(version string) (reference string, err error) {
|
||||
return fmt.Sprintf(referenceTemplate, version, "runtime.md#delete"), nil
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(EntityOperSameContainer, rfc2119.Must, scopeOfAContainerRef)
|
||||
register(StateIDUniq, rfc2119.Must, stateRef)
|
||||
register(StateNewStatus, rfc2119.Must, stateRef)
|
||||
register(DefaultStateJSONPattern, rfc2119.Must, stateRef)
|
||||
register(EnvCreateImplement, rfc2119.Must, lifecycleRef)
|
||||
register(EnvCreateError, rfc2119.Must, lifecycleRef)
|
||||
register(ProcNotRunAtResRequest, rfc2119.Must, lifecycleRef)
|
||||
register(ConfigUpdatesWithoutAffect, rfc2119.Must, lifecycleRef)
|
||||
register(PrestartHooksInvoke, rfc2119.Must, lifecycleRef)
|
||||
register(PrestartHookFailGenError, rfc2119.Must, lifecycleRef)
|
||||
register(ProcImplement, rfc2119.Must, lifecycleRef)
|
||||
register(PoststartHooksInvoke, rfc2119.Must, lifecycleRef)
|
||||
register(PoststartHookFailGenWarn, rfc2119.Must, lifecycleRef)
|
||||
register(UndoCreateSteps, rfc2119.Must, lifecycleRef)
|
||||
register(PoststopHooksInvoke, rfc2119.Must, lifecycleRef)
|
||||
register(PoststopHookFailGenWarn, rfc2119.Must, lifecycleRef)
|
||||
register(ErrorsLeaveStateUnchange, rfc2119.Must, errorsRef)
|
||||
register(WarnsLeaveFlowUnchange, rfc2119.Must, warningsRef)
|
||||
register(DefaultOperations, rfc2119.Must, operationsRef)
|
||||
register(QueryWithoutIDGenError, rfc2119.Must, queryStateRef)
|
||||
register(QueryNonExistGenError, rfc2119.Must, queryStateRef)
|
||||
register(QueryStateImplement, rfc2119.Must, queryStateRef)
|
||||
register(CreateWithBundlePathAndID, rfc2119.Must, createRef)
|
||||
register(CreateWithUniqueID, rfc2119.Must, createRef)
|
||||
register(CreateNewContainer, rfc2119.Must, createRef)
|
||||
register(PropsApplyExceptProcOnCreate, rfc2119.Must, createRef)
|
||||
register(ProcArgsApplyUntilStart, rfc2119.Must, createRef)
|
||||
register(PropApplyFailGenError, rfc2119.Must, createRef)
|
||||
register(PropApplyFailNotCreate, rfc2119.Must, createRef)
|
||||
register(StartWithoutIDGenError, rfc2119.Must, startRef)
|
||||
register(StartNotCreatedHaveNoEffect, rfc2119.Must, startRef)
|
||||
register(StartNotCreatedGenError, rfc2119.Must, startRef)
|
||||
register(StartProcImplement, rfc2119.Must, startRef)
|
||||
register(StartWithProcUnsetGenError, rfc2119.Must, startRef)
|
||||
register(KillWithoutIDGenError, rfc2119.Must, killRef)
|
||||
register(KillNonCreateRunHaveNoEffect, rfc2119.Must, killRef)
|
||||
register(KillNonCreateRunGenError, rfc2119.Must, killRef)
|
||||
register(KillSignalImplement, rfc2119.Must, killRef)
|
||||
register(DeleteWithoutIDGenError, rfc2119.Must, deleteRef)
|
||||
register(DeleteNonStopHaveNoEffect, rfc2119.Must, deleteRef)
|
||||
register(DeleteNonStopGenError, rfc2119.Must, deleteRef)
|
||||
register(DeleteResImplement, rfc2119.Must, deleteRef)
|
||||
register(DeleteOnlyCreatedRes, rfc2119.Must, deleteRef)
|
||||
}
|
||||
31
vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go
generated
vendored
Normal file
31
vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
16
vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go
generated
vendored
Normal file
16
vendor/github.com/opencontainers/runtime-tools/validate/capabilities/validate_linux.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package validate
|
||||
package capabilities
|
||||
|
||||
import (
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
@@ -11,8 +11,3 @@ import (
|
||||
func LastCap() capability.Cap {
|
||||
return capability.Cap(-1)
|
||||
}
|
||||
|
||||
// CheckLinux is a noop on this platform
|
||||
func (v *Validator) CheckLinux() (errs error) {
|
||||
return nil
|
||||
}
|
||||
837
vendor/github.com/opencontainers/runtime-tools/validate/validate.go
generated
vendored
837
vendor/github.com/opencontainers/runtime-tools/validate/validate.go
generated
vendored
@@ -1,837 +0,0 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
osFilepath "github.com/opencontainers/runtime-tools/filepath"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
|
||||
"github.com/opencontainers/runtime-tools/specerror"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
)
|
||||
|
||||
const specConfig = "config.json"
|
||||
|
||||
var (
|
||||
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html
|
||||
posixRlimits = []string{
|
||||
"RLIMIT_AS",
|
||||
"RLIMIT_CORE",
|
||||
"RLIMIT_CPU",
|
||||
"RLIMIT_DATA",
|
||||
"RLIMIT_FSIZE",
|
||||
"RLIMIT_NOFILE",
|
||||
"RLIMIT_STACK",
|
||||
}
|
||||
|
||||
// https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man2/getrlimit.2?h=man-pages-4.13
|
||||
linuxRlimits = append(posixRlimits, []string{
|
||||
"RLIMIT_MEMLOCK",
|
||||
"RLIMIT_MSGQUEUE",
|
||||
"RLIMIT_NICE",
|
||||
"RLIMIT_NPROC",
|
||||
"RLIMIT_RSS",
|
||||
"RLIMIT_RTPRIO",
|
||||
"RLIMIT_RTTIME",
|
||||
"RLIMIT_SIGPENDING",
|
||||
}...)
|
||||
|
||||
configSchemaTemplate = "https://raw.githubusercontent.com/opencontainers/runtime-spec/v%s/schema/config-schema.json"
|
||||
)
|
||||
|
||||
// Validator represents a validator for runtime bundle
|
||||
type Validator struct {
|
||||
spec *rspec.Spec
|
||||
bundlePath string
|
||||
HostSpecific bool
|
||||
platform string
|
||||
}
|
||||
|
||||
// NewValidator creates a Validator
|
||||
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool, platform string) (Validator, error) {
|
||||
if hostSpecific && platform != runtime.GOOS {
|
||||
return Validator{}, fmt.Errorf("When hostSpecific is set, platform must be same as the host platform")
|
||||
}
|
||||
return Validator{
|
||||
spec: spec,
|
||||
bundlePath: bundlePath,
|
||||
HostSpecific: hostSpecific,
|
||||
platform: platform,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewValidatorFromPath creates a Validator with specified bundle path
|
||||
func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) (Validator, error) {
|
||||
if bundlePath == "" {
|
||||
return Validator{}, fmt.Errorf("bundle path shouldn't be empty")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(bundlePath); err != nil {
|
||||
return Validator{}, err
|
||||
}
|
||||
|
||||
configPath := filepath.Join(bundlePath, specConfig)
|
||||
content, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return Validator{}, specerror.NewError(specerror.ConfigInRootBundleDir, err, rspec.Version)
|
||||
}
|
||||
if !utf8.Valid(content) {
|
||||
return Validator{}, fmt.Errorf("%q is not encoded in UTF-8", configPath)
|
||||
}
|
||||
var spec rspec.Spec
|
||||
if err = json.Unmarshal(content, &spec); err != nil {
|
||||
return Validator{}, err
|
||||
}
|
||||
|
||||
return NewValidator(&spec, bundlePath, hostSpecific, platform)
|
||||
}
|
||||
|
||||
// CheckAll checks all parts of runtime bundle
|
||||
func (v *Validator) CheckAll() error {
|
||||
var errs *multierror.Error
|
||||
errs = multierror.Append(errs, v.CheckJSONSchema())
|
||||
errs = multierror.Append(errs, v.CheckPlatform())
|
||||
errs = multierror.Append(errs, v.CheckRoot())
|
||||
errs = multierror.Append(errs, v.CheckMandatoryFields())
|
||||
errs = multierror.Append(errs, v.CheckSemVer())
|
||||
errs = multierror.Append(errs, v.CheckMounts())
|
||||
errs = multierror.Append(errs, v.CheckProcess())
|
||||
errs = multierror.Append(errs, v.CheckLinux())
|
||||
errs = multierror.Append(errs, v.CheckAnnotations())
|
||||
if v.platform == "linux" || v.platform == "solaris" {
|
||||
errs = multierror.Append(errs, v.CheckHooks())
|
||||
}
|
||||
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
|
||||
// JSONSchemaURL returns the URL for the JSON Schema specifying the
|
||||
// configuration format. It consumes configSchemaTemplate, but we
|
||||
// provide it as a function to isolate consumers from inconsistent
|
||||
// naming as runtime-spec evolves.
|
||||
func JSONSchemaURL(version string) (url string, err error) {
|
||||
ver, err := semver.Parse(version)
|
||||
if err != nil {
|
||||
return "", specerror.NewError(specerror.SpecVersionInSemVer, err, rspec.Version)
|
||||
}
|
||||
if ver.LT(semver.Version{Major: 1, Minor: 0, Patch: 2}) {
|
||||
return "", errors.New("unsupported configuration version (older than 1.0.2)")
|
||||
}
|
||||
return fmt.Sprintf(configSchemaTemplate, version), nil
|
||||
}
|
||||
|
||||
// CheckJSONSchema validates the configuration against the
|
||||
// runtime-spec JSON Schema, using the version of the schema that
|
||||
// matches the configuration's declared version.
|
||||
func (v *Validator) CheckJSONSchema() (errs error) {
|
||||
logrus.Debugf("check JSON schema")
|
||||
|
||||
url, err := JSONSchemaURL(strings.TrimSuffix(v.spec.Version, "-dev"))
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
return errs
|
||||
}
|
||||
|
||||
schemaLoader := gojsonschema.NewReferenceLoader(url)
|
||||
documentLoader := gojsonschema.NewGoLoader(v.spec)
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
return errs
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
for _, resultError := range result.Errors() {
|
||||
errs = multierror.Append(errs, errors.New(resultError.String()))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// CheckRoot checks status of v.spec.Root
|
||||
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.spec.Root != nil {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootOnHyperVNotSet, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version))
|
||||
}
|
||||
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))
|
||||
return
|
||||
}
|
||||
} else if v.platform != "windows" && v.spec.Root == nil {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootOnNonWindowsRequired, fmt.Errorf("on all other platforms, this field is REQUIRED"), rspec.Version))
|
||||
return
|
||||
}
|
||||
|
||||
if v.platform == "windows" {
|
||||
matched, err := regexp.MatchString(`\\\\[?]\\Volume[{][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}[}]\\`, v.spec.Root.Path)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
} else if !matched {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootPathOnWindowsGUID, fmt.Errorf("root.path is %q, but it MUST be a volume GUID path when target platform is windows", v.spec.Root.Path), rspec.Version))
|
||||
}
|
||||
|
||||
if v.spec.Root.Readonly {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootReadonlyOnWindowsFalse, fmt.Errorf("root.readonly field MUST be omitted or false when target platform is windows"), rspec.Version))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
absBundlePath, err := filepath.Abs(v.bundlePath)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("unable to convert %q to an absolute path", v.bundlePath))
|
||||
return
|
||||
}
|
||||
|
||||
if filepath.Base(v.spec.Root.Path) != "rootfs" {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootPathOnPosixConvention, fmt.Errorf("path name should be the conventional 'rootfs'"), rspec.Version))
|
||||
}
|
||||
|
||||
var rootfsPath string
|
||||
var absRootPath string
|
||||
if filepath.IsAbs(v.spec.Root.Path) {
|
||||
rootfsPath = v.spec.Root.Path
|
||||
absRootPath = filepath.Clean(rootfsPath)
|
||||
} else {
|
||||
var err error
|
||||
rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
|
||||
absRootPath, err = filepath.Abs(rootfsPath)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("unable to convert %q to an absolute path", rootfsPath))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(rootfsPath); err != nil {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootPathExist, fmt.Errorf("cannot find the root path %q", rootfsPath), rspec.Version))
|
||||
} else if !fi.IsDir() {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.RootPathExist, fmt.Errorf("root.path %q is not a directory", rootfsPath), rspec.Version))
|
||||
}
|
||||
|
||||
rootParent := filepath.Dir(absRootPath)
|
||||
if absRootPath == string(filepath.Separator) || rootParent != absBundlePath {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.ArtifactsInSingleDir, fmt.Errorf("root.path is %q, but it MUST be a child of %q", v.spec.Root.Path, absBundlePath), rspec.Version))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckSemVer checks v.spec.Version
|
||||
func (v *Validator) CheckSemVer() (errs error) {
|
||||
logrus.Debugf("check semver")
|
||||
|
||||
version := v.spec.Version
|
||||
_, err := semver.Parse(version)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(specerror.SpecVersionInSemVer, fmt.Errorf("%q is not valid SemVer: %s", version, err.Error()), rspec.Version))
|
||||
}
|
||||
if version != rspec.Version {
|
||||
errs = multierror.Append(errs, fmt.Errorf("validate currently only handles version %s, but the supplied configuration targets %s", rspec.Version, version))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckHooks check v.spec.Hooks
|
||||
func (v *Validator) CheckHooks() (errs error) {
|
||||
logrus.Debugf("check hooks")
|
||||
|
||||
if v.platform != "linux" && v.platform != "solaris" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("For %q platform, the configuration structure does not support hooks", v.platform))
|
||||
return
|
||||
}
|
||||
|
||||
if v.spec.Hooks != nil {
|
||||
errs = multierror.Append(errs, v.checkEventHooks("prestart", v.spec.Hooks.Prestart, v.HostSpecific))
|
||||
errs = multierror.Append(errs, v.checkEventHooks("poststart", v.spec.Hooks.Poststart, v.HostSpecific))
|
||||
errs = multierror.Append(errs, v.checkEventHooks("poststop", v.spec.Hooks.Poststop, v.HostSpecific))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (v *Validator) checkEventHooks(hookType string, hooks []rspec.Hook, hostSpecific bool) (errs error) {
|
||||
for i, hook := range hooks {
|
||||
if !osFilepath.IsAbs(v.platform, hook.Path) {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.PosixHooksPathAbs,
|
||||
fmt.Errorf("hooks.%s[%d].path %v: is not absolute path",
|
||||
hookType, i, hook.Path),
|
||||
rspec.Version))
|
||||
}
|
||||
|
||||
if hostSpecific {
|
||||
fi, err := os.Stat(hook.Path)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("cannot find %s hook: %v", hookType, hook.Path))
|
||||
}
|
||||
if fi.Mode()&0111 == 0 {
|
||||
errs = multierror.Append(errs, fmt.Errorf("the %s hook %v: is not executable", hookType, hook.Path))
|
||||
}
|
||||
}
|
||||
|
||||
for _, env := range hook.Env {
|
||||
if !envValid(env) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("env %q for hook %v is in the invalid form", env, hook.Path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckProcess checks v.spec.Process
|
||||
func (v *Validator) CheckProcess() (errs error) {
|
||||
logrus.Debugf("check process")
|
||||
|
||||
if v.spec.Process == nil {
|
||||
return
|
||||
}
|
||||
|
||||
process := v.spec.Process
|
||||
if !osFilepath.IsAbs(v.platform, process.Cwd) {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.ProcCwdAbs,
|
||||
fmt.Errorf("cwd %q is not an absolute path", process.Cwd),
|
||||
rspec.Version))
|
||||
}
|
||||
|
||||
for _, env := range process.Env {
|
||||
if !envValid(env) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("env %q should be in the form of 'key=value'. The left hand side must consist solely of letters, digits, and underscores '_'", env))
|
||||
}
|
||||
}
|
||||
|
||||
if len(process.Args) == 0 {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.ProcArgsOneEntryRequired,
|
||||
fmt.Errorf("args must not be empty"),
|
||||
rspec.Version))
|
||||
} else {
|
||||
if filepath.IsAbs(process.Args[0]) && v.spec.Root != nil {
|
||||
var rootfsPath string
|
||||
if filepath.IsAbs(v.spec.Root.Path) {
|
||||
rootfsPath = v.spec.Root.Path
|
||||
} else {
|
||||
rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
|
||||
}
|
||||
absPath := filepath.Join(rootfsPath, process.Args[0])
|
||||
fileinfo, err := os.Stat(absPath)
|
||||
if os.IsNotExist(err) {
|
||||
logrus.Warnf("executable %q is not available in rootfs currently", process.Args[0])
|
||||
} else if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
} else {
|
||||
m := fileinfo.Mode()
|
||||
if m.IsDir() || m&0111 == 0 {
|
||||
errs = multierror.Append(errs, fmt.Errorf("arg %q is not executable", process.Args[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v.platform == "linux" || v.platform == "solaris" {
|
||||
errs = multierror.Append(errs, v.CheckRlimits())
|
||||
}
|
||||
|
||||
if v.platform == "linux" {
|
||||
if v.spec.Process.Capabilities != nil {
|
||||
errs = multierror.Append(errs, v.CheckCapabilities())
|
||||
}
|
||||
|
||||
if len(process.ApparmorProfile) > 0 {
|
||||
profilePath := filepath.Join(v.bundlePath, v.spec.Root.Path, "/etc/apparmor.d", process.ApparmorProfile)
|
||||
_, err := os.Stat(profilePath)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckCapabilities checks v.spec.Process.Capabilities
|
||||
func (v *Validator) CheckCapabilities() (errs error) {
|
||||
if v.platform != "linux" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("For %q platform, the configuration structure does not support process.capabilities", v.platform))
|
||||
return
|
||||
}
|
||||
|
||||
process := v.spec.Process
|
||||
var effective, permitted, inheritable, ambient bool
|
||||
caps := make(map[string][]string)
|
||||
|
||||
for _, cap := range process.Capabilities.Bounding {
|
||||
caps[cap] = append(caps[cap], "bounding")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Effective {
|
||||
caps[cap] = append(caps[cap], "effective")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Inheritable {
|
||||
caps[cap] = append(caps[cap], "inheritable")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Permitted {
|
||||
caps[cap] = append(caps[cap], "permitted")
|
||||
}
|
||||
for _, cap := range process.Capabilities.Ambient {
|
||||
caps[cap] = append(caps[cap], "ambient")
|
||||
}
|
||||
|
||||
for capability, owns := range caps {
|
||||
if err := CapValid(capability, v.HostSpecific); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("capability %q is not valid, man capabilities(7)", capability))
|
||||
}
|
||||
|
||||
effective, permitted, ambient, inheritable = false, false, false, false
|
||||
for _, set := range owns {
|
||||
if set == "effective" {
|
||||
effective = true
|
||||
continue
|
||||
}
|
||||
if set == "inheritable" {
|
||||
inheritable = true
|
||||
continue
|
||||
}
|
||||
if set == "permitted" {
|
||||
permitted = true
|
||||
continue
|
||||
}
|
||||
if set == "ambient" {
|
||||
ambient = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
if effective && !permitted {
|
||||
errs = multierror.Append(errs, fmt.Errorf("effective capability %q is not allowed, as it's not permitted", capability))
|
||||
}
|
||||
if ambient && !(permitted && inheritable) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("ambient capability %q is not allowed, as it's not permitted and inheribate", capability))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckRlimits checks v.spec.Process.Rlimits
|
||||
func (v *Validator) CheckRlimits() (errs error) {
|
||||
if v.platform != "linux" && v.platform != "solaris" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("For %q platform, the configuration structure does not support process.rlimits", v.platform))
|
||||
return
|
||||
}
|
||||
|
||||
process := v.spec.Process
|
||||
for index, rlimit := range process.Rlimits {
|
||||
for i := index + 1; i < len(process.Rlimits); i++ {
|
||||
if process.Rlimits[index].Type == process.Rlimits[i].Type {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.PosixProcRlimitsErrorOnDup,
|
||||
fmt.Errorf("rlimit can not contain the same type %q",
|
||||
process.Rlimits[index].Type),
|
||||
rspec.Version))
|
||||
}
|
||||
}
|
||||
errs = multierror.Append(errs, v.rlimitValid(rlimit))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error) {
|
||||
supportedTypes := make(map[string]bool)
|
||||
|
||||
if OS != "linux" && OS != "windows" {
|
||||
logrus.Warnf("%v is not supported to check mount type", OS)
|
||||
return nil, nil
|
||||
} else if OS == "windows" {
|
||||
supportedTypes["ntfs"] = true
|
||||
return supportedTypes, nil
|
||||
}
|
||||
|
||||
if hostSpecific {
|
||||
f, err := os.Open("/proc/filesystems")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
s := bufio.NewScanner(f)
|
||||
for s.Scan() {
|
||||
if err := s.Err(); err != nil {
|
||||
return supportedTypes, err
|
||||
}
|
||||
|
||||
text := s.Text()
|
||||
parts := strings.Split(text, "\t")
|
||||
if len(parts) > 1 {
|
||||
supportedTypes[parts[1]] = true
|
||||
} else {
|
||||
supportedTypes[parts[0]] = true
|
||||
}
|
||||
}
|
||||
|
||||
supportedTypes["bind"] = true
|
||||
|
||||
return supportedTypes, nil
|
||||
}
|
||||
logrus.Warn("Checking linux mount types without --host-specific is not supported yet")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CheckMounts checks v.spec.Mounts
|
||||
func (v *Validator) CheckMounts() (errs error) {
|
||||
logrus.Debugf("check mounts")
|
||||
|
||||
supportedTypes, err := supportedMountTypes(v.platform, v.HostSpecific)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
return
|
||||
}
|
||||
|
||||
for i, mountA := range v.spec.Mounts {
|
||||
if supportedTypes != nil && !supportedTypes[mountA.Type] {
|
||||
errs = multierror.Append(errs, fmt.Errorf("unsupported mount type %q", mountA.Type))
|
||||
}
|
||||
if !osFilepath.IsAbs(v.platform, mountA.Destination) {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.MountsDestAbs,
|
||||
fmt.Errorf("mounts[%d].destination %q is not absolute",
|
||||
i,
|
||||
mountA.Destination),
|
||||
rspec.Version))
|
||||
}
|
||||
for j, mountB := range v.spec.Mounts {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
// whether B.Desination is nested within A.Destination
|
||||
nested, err := osFilepath.IsAncestor(v.platform, mountA.Destination, mountB.Destination, ".")
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
if nested {
|
||||
if v.platform == "windows" && i < j {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.MountsDestOnWindowsNotNested,
|
||||
fmt.Errorf("on Windows, %v nested within %v is forbidden",
|
||||
mountB.Destination, mountA.Destination),
|
||||
rspec.Version))
|
||||
}
|
||||
if i > j {
|
||||
logrus.Warnf("%v will be covered by %v", mountB.Destination, mountA.Destination)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckPlatform checks v.platform
|
||||
func (v *Validator) CheckPlatform() (errs error) {
|
||||
logrus.Debugf("check platform")
|
||||
|
||||
if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("platform %q is not supported", v.platform))
|
||||
return
|
||||
}
|
||||
|
||||
if v.HostSpecific && v.platform != runtime.GOOS {
|
||||
errs = multierror.Append(errs, fmt.Errorf("platform %q differs from the host %q, skipping host-specific checks", v.platform, runtime.GOOS))
|
||||
v.HostSpecific = false
|
||||
}
|
||||
|
||||
if v.platform == "windows" {
|
||||
if v.spec.Windows == nil {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.PlatformSpecConfOnWindowsSet,
|
||||
fmt.Errorf("'windows' MUST be set when platform is `windows`"),
|
||||
rspec.Version))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckLinuxResources checks v.spec.Linux.Resources
|
||||
func (v *Validator) CheckLinuxResources() (errs error) {
|
||||
logrus.Debugf("check linux resources")
|
||||
|
||||
r := v.spec.Linux.Resources
|
||||
if r.Memory != nil {
|
||||
if r.Memory.Limit != nil && r.Memory.Swap != nil && uint64(*r.Memory.Limit) > uint64(*r.Memory.Swap) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("minimum memoryswap should be larger than memory limit"))
|
||||
}
|
||||
if r.Memory.Limit != nil && r.Memory.Reservation != nil && uint64(*r.Memory.Reservation) > uint64(*r.Memory.Limit) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("minimum memory limit should be larger than memory reservation"))
|
||||
}
|
||||
}
|
||||
if r.Network != nil && v.HostSpecific {
|
||||
var exist bool
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
return
|
||||
}
|
||||
for _, prio := range r.Network.Priorities {
|
||||
exist = false
|
||||
for _, ni := range interfaces {
|
||||
if prio.Name == ni.Name {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
errs = multierror.Append(errs, fmt.Errorf("interface %s does not exist currently", prio.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
for index := 0; index < len(r.Devices); index++ {
|
||||
switch r.Devices[index].Type {
|
||||
case "a", "b", "c", "":
|
||||
default:
|
||||
errs = multierror.Append(errs, fmt.Errorf("type of devices %s is invalid", r.Devices[index].Type))
|
||||
}
|
||||
|
||||
access := []byte(r.Devices[index].Access)
|
||||
for i := 0; i < len(access); i++ {
|
||||
switch access[i] {
|
||||
case 'r', 'w', 'm':
|
||||
default:
|
||||
errs = multierror.Append(errs, fmt.Errorf("access %s is invalid", r.Devices[index].Access))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.BlockIO != nil && r.BlockIO.WeightDevice != nil {
|
||||
for i, weightDevice := range r.BlockIO.WeightDevice {
|
||||
if weightDevice.Weight == nil && weightDevice.LeafWeight == nil {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.BlkIOWeightOrLeafWeightExist,
|
||||
fmt.Errorf("linux.resources.blockIO.weightDevice[%d] specifies neither weight nor leafWeight", i),
|
||||
rspec.Version))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CheckAnnotations checks v.spec.Annotations
|
||||
func (v *Validator) CheckAnnotations() (errs error) {
|
||||
logrus.Debugf("check annotations")
|
||||
|
||||
reversedDomain := regexp.MustCompile(`^[A-Za-z]{2,6}(\.[A-Za-z0-9-]{1,63})+$`)
|
||||
for key := range v.spec.Annotations {
|
||||
if strings.HasPrefix(key, "org.opencontainers") {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.AnnotationsKeyReservedNS,
|
||||
fmt.Errorf("key %q is reserved", key),
|
||||
rspec.Version))
|
||||
}
|
||||
|
||||
if !reversedDomain.MatchString(key) {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.AnnotationsKeyReversedDomain,
|
||||
fmt.Errorf("key %q SHOULD be named using a reverse domain notation", key),
|
||||
rspec.Version))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func envValid(env string) bool {
|
||||
items := strings.Split(env, "=")
|
||||
if len(items) < 2 {
|
||||
return false
|
||||
}
|
||||
for i, ch := range strings.TrimSpace(items[0]) {
|
||||
if !unicode.IsDigit(ch) && !unicode.IsLetter(ch) && ch != '_' {
|
||||
return false
|
||||
}
|
||||
if i == 0 && unicode.IsDigit(ch) {
|
||||
logrus.Warnf("Env %v: variable name beginning with digit is not recommended.", env)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (errs error) {
|
||||
if rlimit.Hard < rlimit.Soft {
|
||||
errs = multierror.Append(errs, fmt.Errorf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type))
|
||||
}
|
||||
|
||||
if v.platform == "linux" {
|
||||
for _, val := range linuxRlimits {
|
||||
if val == rlimit.Type {
|
||||
return
|
||||
}
|
||||
}
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.PosixProcRlimitsTypeValueError, fmt.Errorf("rlimit type %q may not be valid", rlimit.Type), v.spec.Version))
|
||||
} else if v.platform == "solaris" {
|
||||
for _, val := range posixRlimits {
|
||||
if val == rlimit.Type {
|
||||
return
|
||||
}
|
||||
}
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.PosixProcRlimitsTypeValueError, fmt.Errorf("rlimit type %q may not be valid", rlimit.Type), v.spec.Version))
|
||||
} else {
|
||||
logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func isStruct(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
func isStructPtr(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
func checkMandatoryUnit(field reflect.Value, tagField reflect.StructField, parent string) (errs error) {
|
||||
mandatory := !strings.Contains(tagField.Tag.Get("json"), "omitempty")
|
||||
switch field.Kind() {
|
||||
case reflect.Ptr:
|
||||
if mandatory && field.IsNil() {
|
||||
errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
|
||||
}
|
||||
case reflect.String:
|
||||
if mandatory && (field.Len() == 0) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
|
||||
}
|
||||
case reflect.Slice:
|
||||
if mandatory && (field.IsNil() || field.Len() == 0) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
|
||||
return
|
||||
}
|
||||
for index := 0; index < field.Len(); index++ {
|
||||
mValue := field.Index(index)
|
||||
if mValue.CanInterface() {
|
||||
errs = multierror.Append(errs, checkMandatory(mValue.Interface()))
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if mandatory && (field.IsNil() || field.Len() == 0) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
|
||||
return
|
||||
}
|
||||
keys := field.MapKeys()
|
||||
for index := 0; index < len(keys); index++ {
|
||||
mValue := field.MapIndex(keys[index])
|
||||
if mValue.CanInterface() {
|
||||
errs = multierror.Append(errs, checkMandatory(mValue.Interface()))
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkMandatory(obj interface{}) (errs error) {
|
||||
objT := reflect.TypeOf(obj)
|
||||
objV := reflect.ValueOf(obj)
|
||||
if isStructPtr(objT) {
|
||||
objT = objT.Elem()
|
||||
objV = objV.Elem()
|
||||
} else if !isStruct(objT) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < objT.NumField(); i++ {
|
||||
t := objT.Field(i).Type
|
||||
if isStructPtr(t) && objV.Field(i).IsNil() {
|
||||
if !strings.Contains(objT.Field(i).Tag.Get("json"), "omitempty") {
|
||||
errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", objT.Name(), objT.Field(i).Name))
|
||||
}
|
||||
} else if (isStruct(t) || isStructPtr(t)) && objV.Field(i).CanInterface() {
|
||||
errs = multierror.Append(errs, checkMandatory(objV.Field(i).Interface()))
|
||||
} else {
|
||||
errs = multierror.Append(errs, checkMandatoryUnit(objV.Field(i), objT.Field(i), objT.Name()))
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CheckMandatoryFields checks mandatory field of container's config file
|
||||
func (v *Validator) CheckMandatoryFields() error {
|
||||
logrus.Debugf("check mandatory fields")
|
||||
|
||||
if v.spec == nil {
|
||||
return fmt.Errorf("Spec can't be nil")
|
||||
}
|
||||
|
||||
return checkMandatory(v.spec)
|
||||
}
|
||||
238
vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go
generated
vendored
238
vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go
generated
vendored
@@ -1,238 +0,0 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"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"
|
||||
"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
|
||||
}
|
||||
|
||||
func deviceValid(d rspec.LinuxDevice) bool {
|
||||
switch d.Type {
|
||||
case "b", "c", "u":
|
||||
if d.Major <= 0 || d.Minor <= 0 {
|
||||
return false
|
||||
}
|
||||
case "p":
|
||||
if d.Major != 0 || d.Minor != 0 {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// CheckLinux checks v.spec.Linux
|
||||
func (v *Validator) CheckLinux() (errs error) {
|
||||
logrus.Debugf("check linux")
|
||||
|
||||
if v.spec.Linux == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var nsTypeList = map[rspec.LinuxNamespaceType]struct {
|
||||
num int
|
||||
newExist bool
|
||||
}{
|
||||
rspec.PIDNamespace: {0, false},
|
||||
rspec.NetworkNamespace: {0, false},
|
||||
rspec.MountNamespace: {0, false},
|
||||
rspec.IPCNamespace: {0, false},
|
||||
rspec.UTSNamespace: {0, false},
|
||||
rspec.UserNamespace: {0, false},
|
||||
rspec.CgroupNamespace: {0, false},
|
||||
}
|
||||
|
||||
for index := 0; index < len(v.spec.Linux.Namespaces); index++ {
|
||||
ns := v.spec.Linux.Namespaces[index]
|
||||
if ns.Path != "" && !osFilepath.IsAbs(v.platform, ns.Path) {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.NSPathAbs, fmt.Errorf("namespace.path %q is not an absolute path", ns.Path), rspec.Version))
|
||||
}
|
||||
|
||||
tmpItem := nsTypeList[ns.Type]
|
||||
tmpItem.num = tmpItem.num + 1
|
||||
if tmpItem.num > 1 {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.NSErrorOnDup, fmt.Errorf("duplicated namespace %q", ns.Type), rspec.Version))
|
||||
}
|
||||
|
||||
if len(ns.Path) == 0 {
|
||||
tmpItem.newExist = true
|
||||
}
|
||||
nsTypeList[ns.Type] = tmpItem
|
||||
}
|
||||
|
||||
if (len(v.spec.Linux.UIDMappings) > 0 || len(v.spec.Linux.GIDMappings) > 0) && !nsTypeList[rspec.UserNamespace].newExist {
|
||||
errs = multierror.Append(errs, errors.New("the UID/GID mappings requires a new User namespace to be specified as well"))
|
||||
}
|
||||
|
||||
for k := range v.spec.Linux.Sysctl {
|
||||
if strings.HasPrefix(k, "net.") && !nsTypeList[rspec.NetworkNamespace].newExist {
|
||||
errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new Network namespace to be specified as well", k))
|
||||
}
|
||||
if strings.HasPrefix(k, "fs.mqueue.") {
|
||||
if !nsTypeList[rspec.MountNamespace].newExist || !nsTypeList[rspec.IPCNamespace].newExist {
|
||||
errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new IPC namespace and Mount namespace to be specified as well", k))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v.platform == "linux" && !nsTypeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
|
||||
errs = multierror.Append(errs, fmt.Errorf("on Linux, hostname requires a new UTS namespace to be specified as well"))
|
||||
}
|
||||
|
||||
// Linux devices validation
|
||||
devList := make(map[string]bool)
|
||||
devTypeList := make(map[string]bool)
|
||||
for index := 0; index < len(v.spec.Linux.Devices); index++ {
|
||||
device := v.spec.Linux.Devices[index]
|
||||
if !deviceValid(device) {
|
||||
errs = multierror.Append(errs, fmt.Errorf("device %v is invalid", device))
|
||||
}
|
||||
|
||||
if _, exists := devList[device.Path]; exists {
|
||||
errs = multierror.Append(errs, fmt.Errorf("device %s is duplicated", device.Path))
|
||||
} else {
|
||||
var rootfsPath string
|
||||
if filepath.IsAbs(v.spec.Root.Path) {
|
||||
rootfsPath = v.spec.Root.Path
|
||||
} else {
|
||||
rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
|
||||
}
|
||||
absPath := filepath.Join(rootfsPath, device.Path)
|
||||
fi, err := os.Stat(absPath)
|
||||
if os.IsNotExist(err) {
|
||||
devList[device.Path] = true
|
||||
} else if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
} else {
|
||||
fStat, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.DevicesAvailable,
|
||||
fmt.Errorf("cannot determine state for device %s", device.Path), rspec.Version))
|
||||
continue
|
||||
}
|
||||
var devType string
|
||||
switch fStat.Mode & syscall.S_IFMT {
|
||||
case syscall.S_IFCHR:
|
||||
devType = "c"
|
||||
case syscall.S_IFBLK:
|
||||
devType = "b"
|
||||
case syscall.S_IFIFO:
|
||||
devType = "p"
|
||||
default:
|
||||
devType = "unmatched"
|
||||
}
|
||||
if devType != device.Type || (devType == "c" && device.Type == "u") {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
|
||||
fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
|
||||
continue
|
||||
}
|
||||
if devType != "p" {
|
||||
dev := fStat.Rdev
|
||||
major := (dev >> 8) & 0xfff
|
||||
minor := (dev & 0xff) | ((dev >> 12) & 0xfff00)
|
||||
if int64(major) != device.Major || int64(minor) != device.Minor {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
|
||||
fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if device.FileMode != nil {
|
||||
expectedPerm := *device.FileMode & os.ModePerm
|
||||
actualPerm := fi.Mode() & os.ModePerm
|
||||
if expectedPerm != actualPerm {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
|
||||
fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if device.UID != nil {
|
||||
if *device.UID != fStat.Uid {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
|
||||
fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if device.GID != nil {
|
||||
if *device.GID != fStat.Gid {
|
||||
errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch,
|
||||
fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unify u->c when comparing, they are synonyms
|
||||
var devID string
|
||||
if device.Type == "u" {
|
||||
devID = fmt.Sprintf("%s:%d:%d", "c", device.Major, device.Minor)
|
||||
} else {
|
||||
devID = fmt.Sprintf("%s:%d:%d", device.Type, device.Major, device.Minor)
|
||||
}
|
||||
|
||||
if _, exists := devTypeList[devID]; exists {
|
||||
logrus.Warnf("%v", specerror.NewError(specerror.DevicesErrorOnDup, fmt.Errorf("type:%s, major:%d and minor:%d for linux devices is duplicated", device.Type, device.Major, device.Minor), rspec.Version))
|
||||
} else {
|
||||
devTypeList[devID] = true
|
||||
}
|
||||
}
|
||||
|
||||
if v.spec.Linux.Resources != nil {
|
||||
errs = multierror.Append(errs, v.CheckLinuxResources())
|
||||
}
|
||||
|
||||
for _, maskedPath := range v.spec.Linux.MaskedPaths {
|
||||
if !strings.HasPrefix(maskedPath, "/") {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.MaskedPathsAbs,
|
||||
fmt.Errorf("maskedPath %v is not an absolute path", maskedPath),
|
||||
rspec.Version))
|
||||
}
|
||||
}
|
||||
|
||||
for _, readonlyPath := range v.spec.Linux.ReadonlyPaths {
|
||||
if !strings.HasPrefix(readonlyPath, "/") {
|
||||
errs = multierror.Append(errs,
|
||||
specerror.NewError(
|
||||
specerror.ReadonlyPathsAbs,
|
||||
fmt.Errorf("readonlyPath %v is not an absolute path", readonlyPath),
|
||||
rspec.Version))
|
||||
}
|
||||
}
|
||||
|
||||
if v.spec.Linux.MountLabel != "" {
|
||||
if err := label.Validate(v.spec.Linux.MountLabel); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("mountLabel %v is invalid", v.spec.Linux.MountLabel))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
201
vendor/github.com/opencontainers/selinux/LICENSE
generated
vendored
201
vendor/github.com/opencontainers/selinux/LICENSE
generated
vendored
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor 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, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
14
vendor/github.com/opencontainers/selinux/go-selinux/doc.go
generated
vendored
14
vendor/github.com/opencontainers/selinux/go-selinux/doc.go
generated
vendored
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
Package selinux provides a high-level interface for interacting with selinux.
|
||||
|
||||
Usage:
|
||||
|
||||
import "github.com/opencontainers/selinux/go-selinux"
|
||||
|
||||
// Ensure that selinux is enforcing mode.
|
||||
if selinux.EnforceMode() != selinux.Enforcing {
|
||||
selinux.SetEnforceMode(selinux.Enforcing)
|
||||
}
|
||||
|
||||
*/
|
||||
package selinux
|
||||
97
vendor/github.com/opencontainers/selinux/go-selinux/label/label.go
generated
vendored
97
vendor/github.com/opencontainers/selinux/go-selinux/label/label.go
generated
vendored
@@ -1,97 +0,0 @@
|
||||
package label
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
// Deprecated: use selinux.ROFileLabel
|
||||
var ROMountLabel = selinux.ROFileLabel
|
||||
|
||||
// SetProcessLabel takes a process label and tells the kernel to assign the
|
||||
// label to the next program executed by the current process.
|
||||
// Deprecated: use selinux.SetExecLabel
|
||||
var SetProcessLabel = selinux.SetExecLabel
|
||||
|
||||
// ProcessLabel returns the process label that the kernel will assign
|
||||
// to the next program executed by the current process. If "" is returned
|
||||
// this indicates that the default labeling will happen for the process.
|
||||
// Deprecated: use selinux.ExecLabel
|
||||
var ProcessLabel = selinux.ExecLabel
|
||||
|
||||
// SetSocketLabel takes a process label and tells the kernel to assign the
|
||||
// label to the next socket that gets created
|
||||
// Deprecated: use selinux.SetSocketLabel
|
||||
var SetSocketLabel = selinux.SetSocketLabel
|
||||
|
||||
// SocketLabel retrieves the current default socket label setting
|
||||
// Deprecated: use selinux.SocketLabel
|
||||
var SocketLabel = selinux.SocketLabel
|
||||
|
||||
// SetKeyLabel takes a process label and tells the kernel to assign the
|
||||
// label to the next kernel keyring that gets created
|
||||
// Deprecated: use selinux.SetKeyLabel
|
||||
var SetKeyLabel = selinux.SetKeyLabel
|
||||
|
||||
// KeyLabel retrieves the current default kernel keyring label setting
|
||||
// Deprecated: use selinux.KeyLabel
|
||||
var KeyLabel = selinux.KeyLabel
|
||||
|
||||
// FileLabel returns the label for specified path
|
||||
// Deprecated: use selinux.FileLabel
|
||||
var FileLabel = selinux.FileLabel
|
||||
|
||||
// PidLabel will return the label of the process running with the specified pid
|
||||
// Deprecated: use selinux.PidLabel
|
||||
var PidLabel = selinux.PidLabel
|
||||
|
||||
// Init initialises the labeling system
|
||||
func Init() {
|
||||
_ = selinux.GetEnabled()
|
||||
}
|
||||
|
||||
// ClearLabels will clear all reserved labels
|
||||
// Deprecated: use selinux.ClearLabels
|
||||
var ClearLabels = selinux.ClearLabels
|
||||
|
||||
// ReserveLabel will record the fact that the MCS label has already been used.
|
||||
// This will prevent InitLabels from using the MCS label in a newly created
|
||||
// container
|
||||
// Deprecated: use selinux.ReserveLabel
|
||||
func ReserveLabel(label string) error {
|
||||
selinux.ReserveLabel(label)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReleaseLabel will remove the reservation of the MCS label.
|
||||
// This will allow InitLabels to use the MCS label in a newly created
|
||||
// containers
|
||||
// Deprecated: use selinux.ReleaseLabel
|
||||
func ReleaseLabel(label string) error {
|
||||
selinux.ReleaseLabel(label)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DupSecOpt takes a process label and returns security options that
|
||||
// can be used to set duplicate labels on future container processes
|
||||
// Deprecated: use selinux.DupSecOpt
|
||||
var DupSecOpt = selinux.DupSecOpt
|
||||
|
||||
// FormatMountLabel returns a string to be used by the mount command.
|
||||
// The format of this string will be used to alter the labeling of the mountpoint.
|
||||
// The string returned is suitable to be used as the options field of the mount command.
|
||||
// If you need to have additional mount point options, you can pass them in as
|
||||
// the first parameter. Second parameter is the label that you wish to apply
|
||||
// to all content in the mount point.
|
||||
func FormatMountLabel(src, mountLabel string) string {
|
||||
if mountLabel != "" {
|
||||
switch src {
|
||||
case "":
|
||||
src = fmt.Sprintf("context=%q", mountLabel)
|
||||
default:
|
||||
src = fmt.Sprintf("%s,context=%q", src, mountLabel)
|
||||
}
|
||||
}
|
||||
return src
|
||||
}
|
||||
196
vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
generated
vendored
196
vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
generated
vendored
@@ -1,196 +0,0 @@
|
||||
package label
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
// Valid Label Options
|
||||
var validOptions = map[string]bool{
|
||||
"disable": true,
|
||||
"type": true,
|
||||
"filetype": true,
|
||||
"user": true,
|
||||
"role": true,
|
||||
"level": true,
|
||||
}
|
||||
|
||||
var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be used together")
|
||||
|
||||
// InitLabels returns the process label and file labels to be used within
|
||||
// the container. A list of options can be passed into this function to alter
|
||||
// the labels. The labels returned will include a random MCS String, that is
|
||||
// guaranteed to be unique.
|
||||
// If the disabled flag is passed in, the process label will not be set, but the mount label will be set
|
||||
// to the container_file label with the maximum category. This label is not usable by any confined label.
|
||||
func InitLabels(options []string) (plabel string, mlabel string, retErr error) {
|
||||
if !selinux.GetEnabled() {
|
||||
return "", "", nil
|
||||
}
|
||||
processLabel, mountLabel := selinux.ContainerLabels()
|
||||
if processLabel != "" {
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
selinux.ReleaseLabel(mountLabel)
|
||||
}
|
||||
}()
|
||||
pcon, err := selinux.NewContext(processLabel)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
mcsLevel := pcon["level"]
|
||||
mcon, err := selinux.NewContext(mountLabel)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
for _, opt := range options {
|
||||
if opt == "disable" {
|
||||
selinux.ReleaseLabel(mountLabel)
|
||||
return "", selinux.PrivContainerMountLabel(), nil
|
||||
}
|
||||
if i := strings.Index(opt, ":"); i == -1 {
|
||||
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
|
||||
}
|
||||
con := strings.SplitN(opt, ":", 2)
|
||||
if !validOptions[con[0]] {
|
||||
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
|
||||
}
|
||||
if con[0] == "filetype" {
|
||||
mcon["type"] = con[1]
|
||||
continue
|
||||
}
|
||||
pcon[con[0]] = con[1]
|
||||
if con[0] == "level" || con[0] == "user" {
|
||||
mcon[con[0]] = con[1]
|
||||
}
|
||||
}
|
||||
if pcon.Get() != processLabel {
|
||||
if pcon["level"] != mcsLevel {
|
||||
selinux.ReleaseLabel(processLabel)
|
||||
}
|
||||
processLabel = pcon.Get()
|
||||
selinux.ReserveLabel(processLabel)
|
||||
}
|
||||
mountLabel = mcon.Get()
|
||||
}
|
||||
return processLabel, mountLabel, nil
|
||||
}
|
||||
|
||||
// Deprecated: The GenLabels function is only to be used during the transition
|
||||
// to the official API. Use InitLabels(strings.Fields(options)) instead.
|
||||
func GenLabels(options string) (string, string, error) {
|
||||
return InitLabels(strings.Fields(options))
|
||||
}
|
||||
|
||||
// SetFileLabel modifies the "path" label to the specified file label
|
||||
func SetFileLabel(path string, fileLabel string) error {
|
||||
if !selinux.GetEnabled() || fileLabel == "" {
|
||||
return nil
|
||||
}
|
||||
return selinux.SetFileLabel(path, fileLabel)
|
||||
}
|
||||
|
||||
// SetFileCreateLabel tells the kernel the label for all files to be created
|
||||
func SetFileCreateLabel(fileLabel string) error {
|
||||
if !selinux.GetEnabled() {
|
||||
return nil
|
||||
}
|
||||
return selinux.SetFSCreateLabel(fileLabel)
|
||||
}
|
||||
|
||||
// Relabel changes the label of path and all the entries beneath the path.
|
||||
// It changes the MCS label to s0 if shared is true.
|
||||
// This will allow all containers to share the content.
|
||||
//
|
||||
// The path itself is guaranteed to be relabeled last.
|
||||
func Relabel(path string, fileLabel string, shared bool) error {
|
||||
if !selinux.GetEnabled() || fileLabel == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
exclude_paths := map[string]bool{
|
||||
"/": true,
|
||||
"/bin": true,
|
||||
"/boot": true,
|
||||
"/dev": true,
|
||||
"/etc": true,
|
||||
"/etc/passwd": true,
|
||||
"/etc/pki": true,
|
||||
"/etc/shadow": true,
|
||||
"/home": true,
|
||||
"/lib": true,
|
||||
"/lib64": true,
|
||||
"/media": true,
|
||||
"/opt": true,
|
||||
"/proc": true,
|
||||
"/root": true,
|
||||
"/run": true,
|
||||
"/sbin": true,
|
||||
"/srv": true,
|
||||
"/sys": true,
|
||||
"/tmp": true,
|
||||
"/usr": true,
|
||||
"/var": true,
|
||||
"/var/lib": true,
|
||||
"/var/log": true,
|
||||
}
|
||||
|
||||
if home := os.Getenv("HOME"); home != "" {
|
||||
exclude_paths[home] = true
|
||||
}
|
||||
|
||||
if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" {
|
||||
if usr, err := user.Lookup(sudoUser); err == nil {
|
||||
exclude_paths[usr.HomeDir] = true
|
||||
}
|
||||
}
|
||||
|
||||
if path != "/" {
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
}
|
||||
if exclude_paths[path] {
|
||||
return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
|
||||
}
|
||||
|
||||
if shared {
|
||||
c, err := selinux.NewContext(fileLabel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c["level"] = "s0"
|
||||
fileLabel = c.Get()
|
||||
}
|
||||
if err := selinux.Chcon(path, fileLabel, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can disable labeling
|
||||
// support for future container processes
|
||||
// Deprecated: use selinux.DisableSecOpt
|
||||
var DisableSecOpt = selinux.DisableSecOpt
|
||||
|
||||
// Validate checks that the label does not include unexpected options
|
||||
func Validate(label string) error {
|
||||
if strings.Contains(label, "z") && strings.Contains(label, "Z") {
|
||||
return ErrIncompatibleLabel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RelabelNeeded checks whether the user requested a relabel
|
||||
func RelabelNeeded(label string) bool {
|
||||
return strings.Contains(label, "z") || strings.Contains(label, "Z")
|
||||
}
|
||||
|
||||
// IsShared checks that the label includes a "shared" mark
|
||||
func IsShared(label string) bool {
|
||||
return strings.Contains(label, "z")
|
||||
}
|
||||
49
vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
generated
vendored
49
vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package label
|
||||
|
||||
// InitLabels returns the process label and file labels to be used within
|
||||
// the container. A list of options can be passed into this function to alter
|
||||
// the labels.
|
||||
func InitLabels(options []string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
// Deprecated: The GenLabels function is only to be used during the transition
|
||||
// to the official API. Use InitLabels(strings.Fields(options)) instead.
|
||||
func GenLabels(options string) (string, string, error) {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func SetFileLabel(path string, fileLabel string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetFileCreateLabel(fileLabel string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Relabel(path string, fileLabel string, shared bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can disable labeling
|
||||
// support for future container processes
|
||||
func DisableSecOpt() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks that the label does not include unexpected options
|
||||
func Validate(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RelabelNeeded checks whether the user requested a relabel
|
||||
func RelabelNeeded(label string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsShared checks that the label includes a "shared" mark
|
||||
func IsShared(label string) bool {
|
||||
return false
|
||||
}
|
||||
22
vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go
generated
vendored
22
vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
// +build linux,go1.16
|
||||
|
||||
package selinux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/opencontainers/selinux/pkg/pwalkdir"
|
||||
)
|
||||
|
||||
func rchcon(fpath, label string) error {
|
||||
return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error {
|
||||
e := lSetFileLabel(p, label)
|
||||
// Walk a file tree can race with removal, so ignore ENOENT.
|
||||
if errors.Is(e, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
return e
|
||||
})
|
||||
}
|
||||
21
vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go
generated
vendored
21
vendor/github.com/opencontainers/selinux/go-selinux/rchcon_go115.go
generated
vendored
@@ -1,21 +0,0 @@
|
||||
// +build linux,!go1.16
|
||||
|
||||
package selinux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/opencontainers/selinux/pkg/pwalk"
|
||||
)
|
||||
|
||||
func rchcon(fpath, label string) error {
|
||||
return pwalk.Walk(fpath, func(p string, _ os.FileInfo, _ error) error {
|
||||
e := lSetFileLabel(p, label)
|
||||
// Walk a file tree can race with removal, so ignore ENOENT.
|
||||
if errors.Is(e, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
return e
|
||||
})
|
||||
}
|
||||
304
vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
generated
vendored
304
vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
generated
vendored
@@ -1,304 +0,0 @@
|
||||
package selinux
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// Enforcing constant indicate SELinux is in enforcing mode
|
||||
Enforcing = 1
|
||||
// Permissive constant to indicate SELinux is in permissive mode
|
||||
Permissive = 0
|
||||
// Disabled constant to indicate SELinux is disabled
|
||||
Disabled = -1
|
||||
// maxCategory is the maximum number of categories used within containers
|
||||
maxCategory = 1024
|
||||
// DefaultCategoryRange is the upper bound on the category range
|
||||
DefaultCategoryRange = uint32(maxCategory)
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
|
||||
ErrMCSAlreadyExists = errors.New("MCS label already exists")
|
||||
// ErrEmptyPath is returned when an empty path has been specified.
|
||||
ErrEmptyPath = errors.New("empty path")
|
||||
|
||||
// InvalidLabel is returned when an invalid label is specified.
|
||||
InvalidLabel = errors.New("Invalid Label")
|
||||
|
||||
// ErrIncomparable is returned two levels are not comparable
|
||||
ErrIncomparable = errors.New("incomparable levels")
|
||||
// ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
|
||||
ErrLevelSyntax = errors.New("invalid level syntax")
|
||||
|
||||
// ErrContextMissing is returned if a requested context is not found in a file.
|
||||
ErrContextMissing = errors.New("context does not have a match")
|
||||
// ErrVerifierNil is returned when a context verifier function is nil.
|
||||
ErrVerifierNil = errors.New("verifier function is nil")
|
||||
|
||||
// CategoryRange allows the upper bound on the category range to be adjusted
|
||||
CategoryRange = DefaultCategoryRange
|
||||
|
||||
privContainerMountLabel string
|
||||
)
|
||||
|
||||
// Context is a representation of the SELinux label broken into 4 parts
|
||||
type Context map[string]string
|
||||
|
||||
// SetDisabled disables SELinux support for the package
|
||||
func SetDisabled() {
|
||||
setDisabled()
|
||||
}
|
||||
|
||||
// GetEnabled returns whether SELinux is currently enabled.
|
||||
func GetEnabled() bool {
|
||||
return getEnabled()
|
||||
}
|
||||
|
||||
// ClassIndex returns the int index for an object class in the loaded policy,
|
||||
// or -1 and an error
|
||||
func ClassIndex(class string) (int, error) {
|
||||
return classIndex(class)
|
||||
}
|
||||
|
||||
// SetFileLabel sets the SELinux label for this path, following symlinks,
|
||||
// or returns an error.
|
||||
func SetFileLabel(fpath string, label string) error {
|
||||
return setFileLabel(fpath, label)
|
||||
}
|
||||
|
||||
// LsetFileLabel sets the SELinux label for this path, not following symlinks,
|
||||
// or returns an error.
|
||||
func LsetFileLabel(fpath string, label string) error {
|
||||
return lSetFileLabel(fpath, label)
|
||||
}
|
||||
|
||||
// FileLabel returns the SELinux label for this path, following symlinks,
|
||||
// or returns an error.
|
||||
func FileLabel(fpath string) (string, error) {
|
||||
return fileLabel(fpath)
|
||||
}
|
||||
|
||||
// LfileLabel returns the SELinux label for this path, not following symlinks,
|
||||
// or returns an error.
|
||||
func LfileLabel(fpath string) (string, error) {
|
||||
return lFileLabel(fpath)
|
||||
}
|
||||
|
||||
// SetFSCreateLabel tells the kernel what label to use for all file system objects
|
||||
// created by this task.
|
||||
// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel
|
||||
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until file system
|
||||
// objects created by this task are finished to guarantee another goroutine does not migrate
|
||||
// to the current thread before execution is complete.
|
||||
func SetFSCreateLabel(label string) error {
|
||||
return setFSCreateLabel(label)
|
||||
}
|
||||
|
||||
// FSCreateLabel returns the default label the kernel which the kernel is using
|
||||
// for file system objects created by this task. "" indicates default.
|
||||
func FSCreateLabel() (string, error) {
|
||||
return fsCreateLabel()
|
||||
}
|
||||
|
||||
// CurrentLabel returns the SELinux label of the current process thread, or an error.
|
||||
func CurrentLabel() (string, error) {
|
||||
return currentLabel()
|
||||
}
|
||||
|
||||
// PidLabel returns the SELinux label of the given pid, or an error.
|
||||
func PidLabel(pid int) (string, error) {
|
||||
return pidLabel(pid)
|
||||
}
|
||||
|
||||
// ExecLabel returns the SELinux label that the kernel will use for any programs
|
||||
// that are executed by the current process thread, or an error.
|
||||
func ExecLabel() (string, error) {
|
||||
return execLabel()
|
||||
}
|
||||
|
||||
// CanonicalizeContext takes a context string and writes it to the kernel
|
||||
// the function then returns the context that the kernel will use. Use this
|
||||
// function to check if two contexts are equivalent
|
||||
func CanonicalizeContext(val string) (string, error) {
|
||||
return canonicalizeContext(val)
|
||||
}
|
||||
|
||||
// ComputeCreateContext requests the type transition from source to target for
|
||||
// class from the kernel.
|
||||
func ComputeCreateContext(source string, target string, class string) (string, error) {
|
||||
return computeCreateContext(source, target, class)
|
||||
}
|
||||
|
||||
// CalculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
|
||||
// of a source and target range.
|
||||
// The glblub is calculated as the greater of the low sensitivities and
|
||||
// the lower of the high sensitivities and the and of each category bitset.
|
||||
func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
|
||||
return calculateGlbLub(sourceRange, targetRange)
|
||||
}
|
||||
|
||||
// SetExecLabel sets the SELinux label that the kernel will use for any programs
|
||||
// that are executed by the current process thread, or an error. Calls to SetExecLabel
|
||||
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until execution
|
||||
// of the program is finished to guarantee another goroutine does not migrate to the current
|
||||
// thread before execution is complete.
|
||||
func SetExecLabel(label string) error {
|
||||
return setExecLabel(label)
|
||||
}
|
||||
|
||||
// SetTaskLabel sets the SELinux label for the current thread, or an error.
|
||||
// This requires the dyntransition permission. Calls to SetTaskLabel should
|
||||
// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee
|
||||
// the current thread does not run in a new mislabeled thread.
|
||||
func SetTaskLabel(label string) error {
|
||||
return setTaskLabel(label)
|
||||
}
|
||||
|
||||
// SetSocketLabel takes a process label and tells the kernel to assign the
|
||||
// label to the next socket that gets created. Calls to SetSocketLabel
|
||||
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
|
||||
// the the socket is created to guarantee another goroutine does not migrate
|
||||
// to the current thread before execution is complete.
|
||||
func SetSocketLabel(label string) error {
|
||||
return setSocketLabel(label)
|
||||
}
|
||||
|
||||
// SocketLabel retrieves the current socket label setting
|
||||
func SocketLabel() (string, error) {
|
||||
return socketLabel()
|
||||
}
|
||||
|
||||
// PeerLabel retrieves the label of the client on the other side of a socket
|
||||
func PeerLabel(fd uintptr) (string, error) {
|
||||
return peerLabel(fd)
|
||||
}
|
||||
|
||||
// SetKeyLabel takes a process label and tells the kernel to assign the
|
||||
// label to the next kernel keyring that gets created. Calls to SetKeyLabel
|
||||
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
|
||||
// the kernel keyring is created to guarantee another goroutine does not migrate
|
||||
// to the current thread before execution is complete.
|
||||
func SetKeyLabel(label string) error {
|
||||
return setKeyLabel(label)
|
||||
}
|
||||
|
||||
// KeyLabel retrieves the current kernel keyring label setting
|
||||
func KeyLabel() (string, error) {
|
||||
return keyLabel()
|
||||
}
|
||||
|
||||
// Get returns the Context as a string
|
||||
func (c Context) Get() string {
|
||||
return c.get()
|
||||
}
|
||||
|
||||
// NewContext creates a new Context struct from the specified label
|
||||
func NewContext(label string) (Context, error) {
|
||||
return newContext(label)
|
||||
}
|
||||
|
||||
// ClearLabels clears all reserved labels
|
||||
func ClearLabels() {
|
||||
clearLabels()
|
||||
}
|
||||
|
||||
// ReserveLabel reserves the MLS/MCS level component of the specified label
|
||||
func ReserveLabel(label string) {
|
||||
reserveLabel(label)
|
||||
}
|
||||
|
||||
// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
|
||||
func EnforceMode() int {
|
||||
return enforceMode()
|
||||
}
|
||||
|
||||
// SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
|
||||
// Disabled is not valid, since this needs to be set at boot time.
|
||||
func SetEnforceMode(mode int) error {
|
||||
return setEnforceMode(mode)
|
||||
}
|
||||
|
||||
// DefaultEnforceMode returns the systems default SELinux mode Enforcing,
|
||||
// Permissive or Disabled. Note this is is just the default at boot time.
|
||||
// EnforceMode tells you the systems current mode.
|
||||
func DefaultEnforceMode() int {
|
||||
return defaultEnforceMode()
|
||||
}
|
||||
|
||||
// ReleaseLabel un-reserves the MLS/MCS Level field of the specified label,
|
||||
// allowing it to be used by another process.
|
||||
func ReleaseLabel(label string) {
|
||||
releaseLabel(label)
|
||||
}
|
||||
|
||||
// ROFileLabel returns the specified SELinux readonly file label
|
||||
func ROFileLabel() string {
|
||||
return roFileLabel()
|
||||
}
|
||||
|
||||
// KVMContainerLabels returns the default processLabel and mountLabel to be used
|
||||
// for kvm containers by the calling process.
|
||||
func KVMContainerLabels() (string, string) {
|
||||
return kvmContainerLabels()
|
||||
}
|
||||
|
||||
// InitContainerLabels returns the default processLabel and file labels to be
|
||||
// used for containers running an init system like systemd by the calling process.
|
||||
func InitContainerLabels() (string, string) {
|
||||
return initContainerLabels()
|
||||
}
|
||||
|
||||
// ContainerLabels returns an allocated processLabel and fileLabel to be used for
|
||||
// container labeling by the calling process.
|
||||
func ContainerLabels() (processLabel string, fileLabel string) {
|
||||
return containerLabels()
|
||||
}
|
||||
|
||||
// SecurityCheckContext validates that the SELinux label is understood by the kernel
|
||||
func SecurityCheckContext(val string) error {
|
||||
return securityCheckContext(val)
|
||||
}
|
||||
|
||||
// CopyLevel returns a label with the MLS/MCS level from src label replaced on
|
||||
// the dest label.
|
||||
func CopyLevel(src, dest string) (string, error) {
|
||||
return copyLevel(src, dest)
|
||||
}
|
||||
|
||||
// Chcon changes the fpath file object to the SELinux label label.
|
||||
// If fpath is a directory and recurse is true, then Chcon walks the
|
||||
// directory tree setting the label.
|
||||
//
|
||||
// The fpath itself is guaranteed to be relabeled last.
|
||||
func Chcon(fpath string, label string, recurse bool) error {
|
||||
return chcon(fpath, label, recurse)
|
||||
}
|
||||
|
||||
// DupSecOpt takes an SELinux process label and returns security options that
|
||||
// can be used to set the SELinux Type and Level for future container processes.
|
||||
func DupSecOpt(src string) ([]string, error) {
|
||||
return dupSecOpt(src)
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can be used to disable SELinux
|
||||
// labeling support for future container processes.
|
||||
func DisableSecOpt() []string {
|
||||
return disableSecOpt()
|
||||
}
|
||||
|
||||
// GetDefaultContextWithLevel gets a single context for the specified SELinux user
|
||||
// identity that is reachable from the specified scon context. The context is based
|
||||
// on the per-user /etc/selinux/{SELINUXTYPE}/contexts/users/<username> if it exists,
|
||||
// and falls back to the global /etc/selinux/{SELINUXTYPE}/contexts/default_contexts
|
||||
// file.
|
||||
func GetDefaultContextWithLevel(user, level, scon string) (string, error) {
|
||||
return getDefaultContextWithLevel(user, level, scon)
|
||||
}
|
||||
|
||||
// PrivContainerMountLabel returns mount label for privileged containers
|
||||
func PrivContainerMountLabel() string {
|
||||
// Make sure label is initialized.
|
||||
_ = label("")
|
||||
return privContainerMountLabel
|
||||
}
|
||||
1262
vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
generated
vendored
1262
vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
generated
vendored
File diff suppressed because it is too large
Load Diff
164
vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
generated
vendored
164
vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
generated
vendored
@@ -1,164 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package selinux
|
||||
|
||||
func setDisabled() {
|
||||
}
|
||||
|
||||
func getEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func classIndex(class string) (int, error) {
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func setFileLabel(fpath string, label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func lSetFileLabel(fpath string, label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func fileLabel(fpath string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func lFileLabel(fpath string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func setFSCreateLabel(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func fsCreateLabel() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func currentLabel() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func pidLabel(pid int) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func execLabel() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func canonicalizeContext(val string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func computeCreateContext(source string, target string, class string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func calculateGlbLub(sourceRange, targetRange string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func setExecLabel(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTaskLabel(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setSocketLabel(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func socketLabel() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func peerLabel(fd uintptr) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func setKeyLabel(label string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyLabel() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c Context) get() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func newContext(label string) (Context, error) {
|
||||
c := make(Context)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func clearLabels() {
|
||||
}
|
||||
|
||||
func reserveLabel(label string) {
|
||||
}
|
||||
|
||||
func enforceMode() int {
|
||||
return Disabled
|
||||
}
|
||||
|
||||
func setEnforceMode(mode int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultEnforceMode() int {
|
||||
return Disabled
|
||||
}
|
||||
|
||||
func releaseLabel(label string) {
|
||||
}
|
||||
|
||||
func roFileLabel() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func kvmContainerLabels() (string, string) {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func initContainerLabels() (string, string) {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func containerLabels() (processLabel string, fileLabel string) {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func securityCheckContext(val string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyLevel(src, dest string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func chcon(fpath string, label string, recurse bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func dupSecOpt(src string) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func disableSecOpt() []string {
|
||||
return []string{"disable"}
|
||||
}
|
||||
|
||||
func getDefaultContextWithLevel(user, level, scon string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func label(_ string) string {
|
||||
return ""
|
||||
}
|
||||
71
vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
generated
vendored
71
vendor/github.com/opencontainers/selinux/go-selinux/xattrs_linux.go
generated
vendored
@@ -1,71 +0,0 @@
|
||||
package selinux
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// lgetxattr returns a []byte slice containing the value of
|
||||
// an extended attribute attr set for path.
|
||||
func lgetxattr(path, attr string) ([]byte, error) {
|
||||
// Start with a 128 length byte array
|
||||
dest := make([]byte, 128)
|
||||
sz, errno := doLgetxattr(path, attr, dest)
|
||||
for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare
|
||||
// Buffer too small, use zero-sized buffer to get the actual size
|
||||
sz, errno = doLgetxattr(path, attr, []byte{})
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
dest = make([]byte, sz)
|
||||
sz, errno = doLgetxattr(path, attr, dest)
|
||||
}
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return dest[:sz], nil
|
||||
}
|
||||
|
||||
// doLgetxattr is a wrapper that retries on EINTR
|
||||
func doLgetxattr(path, attr string, dest []byte) (int, error) {
|
||||
for {
|
||||
sz, err := unix.Lgetxattr(path, attr, dest)
|
||||
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
|
||||
return sz, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getxattr returns a []byte slice containing the value of
|
||||
// an extended attribute attr set for path.
|
||||
func getxattr(path, attr string) ([]byte, error) {
|
||||
// Start with a 128 length byte array
|
||||
dest := make([]byte, 128)
|
||||
sz, errno := dogetxattr(path, attr, dest)
|
||||
for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare
|
||||
// Buffer too small, use zero-sized buffer to get the actual size
|
||||
sz, errno = dogetxattr(path, attr, []byte{})
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
dest = make([]byte, sz)
|
||||
sz, errno = dogetxattr(path, attr, dest)
|
||||
}
|
||||
if errno != nil {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return dest[:sz], nil
|
||||
}
|
||||
|
||||
// dogetxattr is a wrapper that retries on EINTR
|
||||
func dogetxattr(path, attr string, dest []byte) (int, error) {
|
||||
for {
|
||||
sz, err := unix.Getxattr(path, attr, dest)
|
||||
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
|
||||
return sz, err
|
||||
}
|
||||
}
|
||||
}
|
||||
48
vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md
generated
vendored
48
vendor/github.com/opencontainers/selinux/pkg/pwalk/README.md
generated
vendored
@@ -1,48 +0,0 @@
|
||||
## pwalk: parallel implementation of filepath.Walk
|
||||
|
||||
This is a wrapper for [filepath.Walk](https://pkg.go.dev/path/filepath?tab=doc#Walk)
|
||||
which may speed it up by calling multiple callback functions (WalkFunc) in parallel,
|
||||
utilizing goroutines.
|
||||
|
||||
By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks.
|
||||
This can be changed by using WalkN function which has the additional
|
||||
parameter, specifying the number of goroutines (concurrency).
|
||||
|
||||
### pwalk vs pwalkdir
|
||||
|
||||
This package is deprecated in favor of
|
||||
[pwalkdir](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir),
|
||||
which is faster, but requires at least Go 1.16.
|
||||
|
||||
### Caveats
|
||||
|
||||
Please note the following limitations of this code:
|
||||
|
||||
* Unlike filepath.Walk, the order of calls is non-deterministic;
|
||||
|
||||
* Only primitive error handling is supported:
|
||||
|
||||
* filepath.SkipDir is not supported;
|
||||
|
||||
* no errors are ever passed to WalkFunc;
|
||||
|
||||
* once any error is returned from any WalkFunc instance, no more new calls
|
||||
to WalkFunc are made, and the error is returned to the caller of Walk;
|
||||
|
||||
* if more than one walkFunc instance will return an error, only one
|
||||
of such errors will be propagated and returned by Walk, others
|
||||
will be silently discarded.
|
||||
|
||||
### Documentation
|
||||
|
||||
For the official documentation, see
|
||||
https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalk?tab=doc
|
||||
|
||||
### Benchmarks
|
||||
|
||||
For a WalkFunc that consists solely of the return statement, this
|
||||
implementation is about 10% slower than the standard library's
|
||||
filepath.Walk.
|
||||
|
||||
Otherwise (if a WalkFunc is doing something) this is usually faster,
|
||||
except when the WalkN(..., 1) is used.
|
||||
115
vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
generated
vendored
115
vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
generated
vendored
@@ -1,115 +0,0 @@
|
||||
package pwalk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type WalkFunc = filepath.WalkFunc
|
||||
|
||||
// Walk is a wrapper for filepath.Walk which can call multiple walkFn
|
||||
// in parallel, allowing to handle each item concurrently. A maximum of
|
||||
// twice the runtime.NumCPU() walkFn will be called at any one time.
|
||||
// If you want to change the maximum, use WalkN instead.
|
||||
//
|
||||
// The order of calls is non-deterministic.
|
||||
//
|
||||
// Note that this implementation only supports primitive error handling:
|
||||
//
|
||||
// - no errors are ever passed to walkFn;
|
||||
//
|
||||
// - once a walkFn returns any error, all further processing stops
|
||||
// and the error is returned to the caller of Walk;
|
||||
//
|
||||
// - filepath.SkipDir is not supported;
|
||||
//
|
||||
// - if more than one walkFn instance will return an error, only one
|
||||
// of such errors will be propagated and returned by Walk, others
|
||||
// will be silently discarded.
|
||||
func Walk(root string, walkFn WalkFunc) error {
|
||||
return WalkN(root, walkFn, runtime.NumCPU()*2)
|
||||
}
|
||||
|
||||
// WalkN is a wrapper for filepath.Walk which can call multiple walkFn
|
||||
// in parallel, allowing to handle each item concurrently. A maximum of
|
||||
// num walkFn will be called at any one time.
|
||||
//
|
||||
// Please see Walk documentation for caveats of using this function.
|
||||
func WalkN(root string, walkFn WalkFunc, num int) error {
|
||||
// make sure limit is sensible
|
||||
if num < 1 {
|
||||
return fmt.Errorf("walk(%q): num must be > 0", root)
|
||||
}
|
||||
|
||||
files := make(chan *walkArgs, 2*num)
|
||||
errCh := make(chan error, 1) // get the first error, ignore others
|
||||
|
||||
// Start walking a tree asap
|
||||
var (
|
||||
err error
|
||||
wg sync.WaitGroup
|
||||
|
||||
rootLen = len(root)
|
||||
rootEntry *walkArgs
|
||||
)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
close(files)
|
||||
return err
|
||||
}
|
||||
if len(p) == rootLen {
|
||||
// Root entry is processed separately below.
|
||||
rootEntry = &walkArgs{path: p, info: &info}
|
||||
return nil
|
||||
}
|
||||
// add a file to the queue unless a callback sent an error
|
||||
select {
|
||||
case e := <-errCh:
|
||||
close(files)
|
||||
return e
|
||||
default:
|
||||
files <- &walkArgs{path: p, info: &info}
|
||||
return nil
|
||||
}
|
||||
})
|
||||
if err == nil {
|
||||
close(files)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Add(num)
|
||||
for i := 0; i < num; i++ {
|
||||
go func() {
|
||||
for file := range files {
|
||||
if e := walkFn(file.path, *file.info, nil); e != nil {
|
||||
select {
|
||||
case errCh <- e: // sent ok
|
||||
default: // buffer full
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if err == nil {
|
||||
err = walkFn(rootEntry.path, *rootEntry.info, nil)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// walkArgs holds the arguments that were passed to the Walk or WalkN
|
||||
// functions.
|
||||
type walkArgs struct {
|
||||
path string
|
||||
info *os.FileInfo
|
||||
}
|
||||
54
vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md
generated
vendored
54
vendor/github.com/opencontainers/selinux/pkg/pwalkdir/README.md
generated
vendored
@@ -1,54 +0,0 @@
|
||||
## pwalkdir: parallel implementation of filepath.WalkDir
|
||||
|
||||
This is a wrapper for [filepath.WalkDir](https://pkg.go.dev/path/filepath#WalkDir)
|
||||
which may speed it up by calling multiple callback functions (WalkDirFunc)
|
||||
in parallel, utilizing goroutines.
|
||||
|
||||
By default, it utilizes 2\*runtime.NumCPU() goroutines for callbacks.
|
||||
This can be changed by using WalkN function which has the additional
|
||||
parameter, specifying the number of goroutines (concurrency).
|
||||
|
||||
### pwalk vs pwalkdir
|
||||
|
||||
This package is very similar to
|
||||
[pwalk](https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir),
|
||||
but utilizes `filepath.WalkDir` (added to Go 1.16), which does not call stat(2)
|
||||
on every entry and is therefore faster (up to 3x, depending on usage scenario).
|
||||
|
||||
Users who are OK with requiring Go 1.16+ should switch to this
|
||||
implementation.
|
||||
|
||||
### Caveats
|
||||
|
||||
Please note the following limitations of this code:
|
||||
|
||||
* Unlike filepath.WalkDir, the order of calls is non-deterministic;
|
||||
|
||||
* Only primitive error handling is supported:
|
||||
|
||||
* fs.SkipDir is not supported;
|
||||
|
||||
* no errors are ever passed to WalkDirFunc;
|
||||
|
||||
* once any error is returned from any walkDirFunc instance, no more calls
|
||||
to WalkDirFunc are made, and the error is returned to the caller of WalkDir;
|
||||
|
||||
* if more than one WalkDirFunc instance will return an error, only one
|
||||
of such errors will be propagated to and returned by WalkDir, others
|
||||
will be silently discarded.
|
||||
|
||||
### Documentation
|
||||
|
||||
For the official documentation, see
|
||||
https://pkg.go.dev/github.com/opencontainers/selinux/pkg/pwalkdir
|
||||
|
||||
### Benchmarks
|
||||
|
||||
For a WalkDirFunc that consists solely of the return statement, this
|
||||
implementation is about 15% slower than the standard library's
|
||||
filepath.WalkDir.
|
||||
|
||||
Otherwise (if a WalkDirFunc is actually doing something) this is usually
|
||||
faster, except when the WalkDirN(..., 1) is used. Run `go test -bench .`
|
||||
to see how different operations can benefit from it, as well as how the
|
||||
level of paralellism affects the speed.
|
||||
116
vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
generated
vendored
116
vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
generated
vendored
@@ -1,116 +0,0 @@
|
||||
//go:build go1.16
|
||||
// +build go1.16
|
||||
|
||||
package pwalkdir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Walk is a wrapper for filepath.WalkDir which can call multiple walkFn
|
||||
// in parallel, allowing to handle each item concurrently. A maximum of
|
||||
// twice the runtime.NumCPU() walkFn will be called at any one time.
|
||||
// If you want to change the maximum, use WalkN instead.
|
||||
//
|
||||
// The order of calls is non-deterministic.
|
||||
//
|
||||
// Note that this implementation only supports primitive error handling:
|
||||
//
|
||||
// - no errors are ever passed to walkFn;
|
||||
//
|
||||
// - once a walkFn returns any error, all further processing stops
|
||||
// and the error is returned to the caller of Walk;
|
||||
//
|
||||
// - filepath.SkipDir is not supported;
|
||||
//
|
||||
// - if more than one walkFn instance will return an error, only one
|
||||
// of such errors will be propagated and returned by Walk, others
|
||||
// will be silently discarded.
|
||||
func Walk(root string, walkFn fs.WalkDirFunc) error {
|
||||
return WalkN(root, walkFn, runtime.NumCPU()*2)
|
||||
}
|
||||
|
||||
// WalkN is a wrapper for filepath.WalkDir which can call multiple walkFn
|
||||
// in parallel, allowing to handle each item concurrently. A maximum of
|
||||
// num walkFn will be called at any one time.
|
||||
//
|
||||
// Please see Walk documentation for caveats of using this function.
|
||||
func WalkN(root string, walkFn fs.WalkDirFunc, num int) error {
|
||||
// make sure limit is sensible
|
||||
if num < 1 {
|
||||
return fmt.Errorf("walk(%q): num must be > 0", root)
|
||||
}
|
||||
|
||||
files := make(chan *walkArgs, 2*num)
|
||||
errCh := make(chan error, 1) // Get the first error, ignore others.
|
||||
|
||||
// Start walking a tree asap.
|
||||
var (
|
||||
err error
|
||||
wg sync.WaitGroup
|
||||
|
||||
rootLen = len(root)
|
||||
rootEntry *walkArgs
|
||||
)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = filepath.WalkDir(root, func(p string, entry fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
close(files)
|
||||
return err
|
||||
}
|
||||
if len(p) == rootLen {
|
||||
// Root entry is processed separately below.
|
||||
rootEntry = &walkArgs{path: p, entry: entry}
|
||||
return nil
|
||||
}
|
||||
// Add a file to the queue unless a callback sent an error.
|
||||
select {
|
||||
case e := <-errCh:
|
||||
close(files)
|
||||
return e
|
||||
default:
|
||||
files <- &walkArgs{path: p, entry: entry}
|
||||
return nil
|
||||
}
|
||||
})
|
||||
if err == nil {
|
||||
close(files)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Add(num)
|
||||
for i := 0; i < num; i++ {
|
||||
go func() {
|
||||
for file := range files {
|
||||
if e := walkFn(file.path, file.entry, nil); e != nil {
|
||||
select {
|
||||
case errCh <- e: // sent ok
|
||||
default: // buffer full
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if err == nil {
|
||||
err = walkFn(rootEntry.path, rootEntry.entry, nil)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// walkArgs holds the arguments that were passed to the Walk or WalkN
|
||||
// functions.
|
||||
type walkArgs struct {
|
||||
path string
|
||||
entry fs.DirEntry
|
||||
}
|
||||
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
@@ -1,24 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
10
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
10
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
@@ -1,10 +0,0 @@
|
||||
language: go
|
||||
go_import_path: github.com/pkg/errors
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
script:
|
||||
- make check
|
||||
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
@@ -1,23 +0,0 @@
|
||||
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
|
||||
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.
|
||||
|
||||
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 HOLDER 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.
|
||||
44
vendor/github.com/pkg/errors/Makefile
generated
vendored
44
vendor/github.com/pkg/errors/Makefile
generated
vendored
@@ -1,44 +0,0 @@
|
||||
PKGS := github.com/pkg/errors
|
||||
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
|
||||
GO := go
|
||||
|
||||
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
|
||||
|
||||
test:
|
||||
$(GO) test $(PKGS)
|
||||
|
||||
vet: | test
|
||||
$(GO) vet $(PKGS)
|
||||
|
||||
staticcheck:
|
||||
$(GO) get honnef.co/go/tools/cmd/staticcheck
|
||||
staticcheck -checks all $(PKGS)
|
||||
|
||||
misspell:
|
||||
$(GO) get github.com/client9/misspell/cmd/misspell
|
||||
misspell \
|
||||
-locale GB \
|
||||
-error \
|
||||
*.md *.go
|
||||
|
||||
unconvert:
|
||||
$(GO) get github.com/mdempsky/unconvert
|
||||
unconvert -v $(PKGS)
|
||||
|
||||
ineffassign:
|
||||
$(GO) get github.com/gordonklaus/ineffassign
|
||||
find $(SRCDIRS) -name '*.go' | xargs ineffassign
|
||||
|
||||
pedantic: check errcheck
|
||||
|
||||
unparam:
|
||||
$(GO) get mvdan.cc/unparam
|
||||
unparam ./...
|
||||
|
||||
errcheck:
|
||||
$(GO) get github.com/kisielk/errcheck
|
||||
errcheck $(PKGS)
|
||||
|
||||
gofmt:
|
||||
@echo Checking code is gofmted
|
||||
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"
|
||||
59
vendor/github.com/pkg/errors/README.md
generated
vendored
59
vendor/github.com/pkg/errors/README.md
generated
vendored
@@ -1,59 +0,0 @@
|
||||
# errors [](https://travis-ci.org/pkg/errors) [](https://ci.appveyor.com/project/davecheney/errors/branch/master) [](http://godoc.org/github.com/pkg/errors) [](https://goreportcard.com/report/github.com/pkg/errors) [](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||
|
||||
Package errors provides simple error handling primitives.
|
||||
|
||||
`go get github.com/pkg/errors`
|
||||
|
||||
The traditional error handling idiom in Go is roughly akin to
|
||||
```go
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||
|
||||
## Adding context to an error
|
||||
|
||||
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||
```go
|
||||
_, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read failed")
|
||||
}
|
||||
```
|
||||
## Retrieving the cause of an error
|
||||
|
||||
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||
```go
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
```
|
||||
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||
```go
|
||||
switch err := errors.Cause(err).(type) {
|
||||
case *MyError:
|
||||
// handle specifically
|
||||
default:
|
||||
// unknown error
|
||||
}
|
||||
```
|
||||
|
||||
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||
|
||||
## Roadmap
|
||||
|
||||
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
|
||||
|
||||
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
|
||||
- 1.0. Final release.
|
||||
|
||||
## Contributing
|
||||
|
||||
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
|
||||
|
||||
Before sending a PR, please discuss your change by raising an issue.
|
||||
|
||||
## License
|
||||
|
||||
BSD-2-Clause
|
||||
32
vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
32
vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
@@ -1,32 +0,0 @@
|
||||
version: build-{build}.{branch}
|
||||
|
||||
clone_folder: C:\gopath\src\github.com\pkg\errors
|
||||
shallow_clone: true # for startup speed
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
# http://www.appveyor.com/docs/installed-software
|
||||
install:
|
||||
# some helpful output for debugging builds
|
||||
- go version
|
||||
- go env
|
||||
# pre-installed MinGW at C:\MinGW is 32bit only
|
||||
# but MSYS2 at C:\msys64 has mingw64
|
||||
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||
- gcc --version
|
||||
- g++ --version
|
||||
|
||||
build_script:
|
||||
- go install -v ./...
|
||||
|
||||
test_script:
|
||||
- set PATH=C:\gopath\bin;%PATH%
|
||||
- go test -v ./...
|
||||
|
||||
#artifacts:
|
||||
# - path: '%GOPATH%\bin\*.exe'
|
||||
deploy: off
|
||||
288
vendor/github.com/pkg/errors/errors.go
generated
vendored
288
vendor/github.com/pkg/errors/errors.go
generated
vendored
@@ -1,288 +0,0 @@
|
||||
// Package errors provides simple error handling primitives.
|
||||
//
|
||||
// The traditional error handling idiom in Go is roughly akin to
|
||||
//
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// which when applied recursively up the call stack results in error reports
|
||||
// without context or debugging information. The errors package allows
|
||||
// programmers to add context to the failure path in their code in a way
|
||||
// that does not destroy the original value of the error.
|
||||
//
|
||||
// Adding context to an error
|
||||
//
|
||||
// The errors.Wrap function returns a new error that adds context to the
|
||||
// original error by recording a stack trace at the point Wrap is called,
|
||||
// together with the supplied message. For example
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "read failed")
|
||||
// }
|
||||
//
|
||||
// If additional control is required, the errors.WithStack and
|
||||
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||
// operations: annotating an error with a stack trace and with a message,
|
||||
// respectively.
|
||||
//
|
||||
// Retrieving the cause of an error
|
||||
//
|
||||
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||
// preceding error. Depending on the nature of the error it may be necessary
|
||||
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||
// for inspection. Any error value which implements this interface
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||
// the topmost error that does not implement causer, which is assumed to be
|
||||
// the original cause. For example:
|
||||
//
|
||||
// switch err := errors.Cause(err).(type) {
|
||||
// case *MyError:
|
||||
// // handle specifically
|
||||
// default:
|
||||
// // unknown error
|
||||
// }
|
||||
//
|
||||
// Although the causer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// Formatted printing of errors
|
||||
//
|
||||
// All error values returned from this package implement fmt.Formatter and can
|
||||
// be formatted by the fmt package. The following verbs are supported:
|
||||
//
|
||||
// %s print the error. If the error has a Cause it will be
|
||||
// printed recursively.
|
||||
// %v see %s
|
||||
// %+v extended format. Each Frame of the error's StackTrace will
|
||||
// be printed in detail.
|
||||
//
|
||||
// Retrieving the stack trace of an error or wrapper
|
||||
//
|
||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||
// invoked. This information can be retrieved with the following interface:
|
||||
//
|
||||
// type stackTracer interface {
|
||||
// StackTrace() errors.StackTrace
|
||||
// }
|
||||
//
|
||||
// The returned errors.StackTrace type is defined as
|
||||
//
|
||||
// type StackTrace []Frame
|
||||
//
|
||||
// The Frame type represents a call site in the stack trace. Frame supports
|
||||
// the fmt.Formatter interface that can be used for printing information about
|
||||
// the stack trace of this error. For example:
|
||||
//
|
||||
// if err, ok := err.(stackTracer); ok {
|
||||
// for _, f := range err.StackTrace() {
|
||||
// fmt.Printf("%+s:%d\n", f, f)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Although the stackTracer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// See the documentation for Frame.Format for more details.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(message string) error {
|
||||
return &fundamental{
|
||||
msg: message,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withStack) Unwrap() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v", w.Cause())
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withMessage) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||
io.WriteString(s, w.msg)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
return err
|
||||
}
|
||||
38
vendor/github.com/pkg/errors/go113.go
generated
vendored
38
vendor/github.com/pkg/errors/go113.go
generated
vendored
@@ -1,38 +0,0 @@
|
||||
// +build go1.13
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
stderrors "errors"
|
||||
)
|
||||
|
||||
// Is reports whether any error in err's chain matches target.
|
||||
//
|
||||
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||
// repeatedly calling Unwrap.
|
||||
//
|
||||
// An error is considered to match a target if it is equal to that target or if
|
||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
||||
func Is(err, target error) bool { return stderrors.Is(err, target) }
|
||||
|
||||
// As finds the first error in err's chain that matches target, and if so, sets
|
||||
// target to that error value and returns true.
|
||||
//
|
||||
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||
// repeatedly calling Unwrap.
|
||||
//
|
||||
// An error matches target if the error's concrete value is assignable to the value
|
||||
// pointed to by target, or if the error has a method As(interface{}) bool such that
|
||||
// As(target) returns true. In the latter case, the As method is responsible for
|
||||
// setting target.
|
||||
//
|
||||
// As will panic if target is not a non-nil pointer to either a type that implements
|
||||
// error, or to any interface type. As returns false if err is nil.
|
||||
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
|
||||
|
||||
// Unwrap returns the result of calling the Unwrap method on err, if err's
|
||||
// type contains an Unwrap method returning error.
|
||||
// Otherwise, Unwrap returns nil.
|
||||
func Unwrap(err error) error {
|
||||
return stderrors.Unwrap(err)
|
||||
}
|
||||
177
vendor/github.com/pkg/errors/stack.go
generated
vendored
177
vendor/github.com/pkg/errors/stack.go
generated
vendored
@@ -1,177 +0,0 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
// For historical reasons if Frame is interpreted as a uintptr
|
||||
// its value represents the program counter + 1.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// name returns the name of this function, if known.
|
||||
func (f Frame) name() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
return fn.Name()
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
io.WriteString(s, f.name())
|
||||
io.WriteString(s, "\n\t")
|
||||
io.WriteString(s, f.file())
|
||||
default:
|
||||
io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
io.WriteString(s, strconv.Itoa(f.line()))
|
||||
case 'n':
|
||||
io.WriteString(s, funcname(f.name()))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalText formats a stacktrace Frame as a text string. The output is the
|
||||
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
|
||||
func (f Frame) MarshalText() ([]byte, error) {
|
||||
name := f.name()
|
||||
if name == "unknown" {
|
||||
return []byte(name), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
io.WriteString(s, "\n")
|
||||
f.Format(s, verb)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
case 's':
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
}
|
||||
|
||||
// formatSlice will format this StackTrace into the given buffer as a slice of
|
||||
// Frame, only valid when called with '%s' or '%v'.
|
||||
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
|
||||
io.WriteString(s, "[")
|
||||
for i, f := range st {
|
||||
if i > 0 {
|
||||
io.WriteString(s, " ")
|
||||
}
|
||||
f.Format(s, verb)
|
||||
}
|
||||
io.WriteString(s, "]")
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
||||
202
vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt
generated
vendored
202
vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt
generated
vendored
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor 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, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 xeipuuv
|
||||
|
||||
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.
|
||||
41
vendor/github.com/xeipuuv/gojsonpointer/README.md
generated
vendored
41
vendor/github.com/xeipuuv/gojsonpointer/README.md
generated
vendored
@@ -1,41 +0,0 @@
|
||||
# gojsonpointer
|
||||
An implementation of JSON Pointer - Go language
|
||||
|
||||
## Usage
|
||||
jsonText := `{
|
||||
"name": "Bobby B",
|
||||
"occupation": {
|
||||
"title" : "King",
|
||||
"years" : 15,
|
||||
"heir" : "Joffrey B"
|
||||
}
|
||||
}`
|
||||
|
||||
var jsonDocument map[string]interface{}
|
||||
json.Unmarshal([]byte(jsonText), &jsonDocument)
|
||||
|
||||
//create a JSON pointer
|
||||
pointerString := "/occupation/title"
|
||||
pointer, _ := NewJsonPointer(pointerString)
|
||||
|
||||
//SET a new value for the "title" in the document
|
||||
pointer.Set(jsonDocument, "Supreme Leader of Westeros")
|
||||
|
||||
//GET the new "title" from the document
|
||||
title, _, _ := pointer.Get(jsonDocument)
|
||||
fmt.Println(title) //outputs "Supreme Leader of Westeros"
|
||||
|
||||
//DELETE the "heir" from the document
|
||||
deletePointer := NewJsonPointer("/occupation/heir")
|
||||
deletePointer.Delete(jsonDocument)
|
||||
|
||||
b, _ := json.Marshal(jsonDocument)
|
||||
fmt.Println(string(b))
|
||||
//outputs `{"name":"Bobby B","occupation":{"title":"Supreme Leader of Westeros","years":15}}`
|
||||
|
||||
|
||||
## References
|
||||
https://tools.ietf.org/html/rfc6901
|
||||
|
||||
### Note
|
||||
The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented.
|
||||
211
vendor/github.com/xeipuuv/gojsonpointer/pointer.go
generated
vendored
211
vendor/github.com/xeipuuv/gojsonpointer/pointer.go
generated
vendored
@@ -1,211 +0,0 @@
|
||||
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author xeipuuv
|
||||
// author-github https://github.com/xeipuuv
|
||||
// author-mail xeipuuv@gmail.com
|
||||
//
|
||||
// repository-name gojsonpointer
|
||||
// repository-desc An implementation of JSON Pointer - Go language
|
||||
//
|
||||
// description Main and unique file.
|
||||
//
|
||||
// created 25-02-2013
|
||||
|
||||
package gojsonpointer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
const_empty_pointer = ``
|
||||
const_pointer_separator = `/`
|
||||
|
||||
const_invalid_start = `JSON pointer must be empty or start with a "` + const_pointer_separator + `"`
|
||||
)
|
||||
|
||||
type implStruct struct {
|
||||
mode string // "SET" or "GET"
|
||||
|
||||
inDocument interface{}
|
||||
|
||||
setInValue interface{}
|
||||
|
||||
getOutNode interface{}
|
||||
getOutKind reflect.Kind
|
||||
outError error
|
||||
}
|
||||
|
||||
type JsonPointer struct {
|
||||
referenceTokens []string
|
||||
}
|
||||
|
||||
// NewJsonPointer parses the given string JSON pointer and returns an object
|
||||
func NewJsonPointer(jsonPointerString string) (p JsonPointer, err error) {
|
||||
|
||||
// Pointer to the root of the document
|
||||
if len(jsonPointerString) == 0 {
|
||||
// Keep referenceTokens nil
|
||||
return
|
||||
}
|
||||
if jsonPointerString[0] != '/' {
|
||||
return p, errors.New(const_invalid_start)
|
||||
}
|
||||
|
||||
p.referenceTokens = strings.Split(jsonPointerString[1:], const_pointer_separator)
|
||||
return
|
||||
}
|
||||
|
||||
// Uses the pointer to retrieve a value from a JSON document
|
||||
func (p *JsonPointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
|
||||
|
||||
is := &implStruct{mode: "GET", inDocument: document}
|
||||
p.implementation(is)
|
||||
return is.getOutNode, is.getOutKind, is.outError
|
||||
|
||||
}
|
||||
|
||||
// Uses the pointer to update a value from a JSON document
|
||||
func (p *JsonPointer) Set(document interface{}, value interface{}) (interface{}, error) {
|
||||
|
||||
is := &implStruct{mode: "SET", inDocument: document, setInValue: value}
|
||||
p.implementation(is)
|
||||
return document, is.outError
|
||||
|
||||
}
|
||||
|
||||
// Uses the pointer to delete a value from a JSON document
|
||||
func (p *JsonPointer) Delete(document interface{}) (interface{}, error) {
|
||||
is := &implStruct{mode: "DEL", inDocument: document}
|
||||
p.implementation(is)
|
||||
return document, is.outError
|
||||
}
|
||||
|
||||
// Both Get and Set functions use the same implementation to avoid code duplication
|
||||
func (p *JsonPointer) implementation(i *implStruct) {
|
||||
|
||||
kind := reflect.Invalid
|
||||
|
||||
// Full document when empty
|
||||
if len(p.referenceTokens) == 0 {
|
||||
i.getOutNode = i.inDocument
|
||||
i.outError = nil
|
||||
i.getOutKind = kind
|
||||
i.outError = nil
|
||||
return
|
||||
}
|
||||
|
||||
node := i.inDocument
|
||||
|
||||
previousNodes := make([]interface{}, len(p.referenceTokens))
|
||||
previousTokens := make([]string, len(p.referenceTokens))
|
||||
|
||||
for ti, token := range p.referenceTokens {
|
||||
|
||||
isLastToken := ti == len(p.referenceTokens)-1
|
||||
previousNodes[ti] = node
|
||||
previousTokens[ti] = token
|
||||
|
||||
switch v := node.(type) {
|
||||
|
||||
case map[string]interface{}:
|
||||
decodedToken := decodeReferenceToken(token)
|
||||
if _, ok := v[decodedToken]; ok {
|
||||
node = v[decodedToken]
|
||||
if isLastToken && i.mode == "SET" {
|
||||
v[decodedToken] = i.setInValue
|
||||
} else if isLastToken && i.mode == "DEL" {
|
||||
delete(v, decodedToken)
|
||||
}
|
||||
} else if isLastToken && i.mode == "SET" {
|
||||
v[decodedToken] = i.setInValue
|
||||
} else {
|
||||
i.outError = fmt.Errorf("Object has no key '%s'", decodedToken)
|
||||
i.getOutKind = reflect.Map
|
||||
i.getOutNode = nil
|
||||
return
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
tokenIndex, err := strconv.Atoi(token)
|
||||
if err != nil {
|
||||
i.outError = fmt.Errorf("Invalid array index '%s'", token)
|
||||
i.getOutKind = reflect.Slice
|
||||
i.getOutNode = nil
|
||||
return
|
||||
}
|
||||
if tokenIndex < 0 || tokenIndex >= len(v) {
|
||||
i.outError = fmt.Errorf("Out of bound array[0,%d] index '%d'", len(v), tokenIndex)
|
||||
i.getOutKind = reflect.Slice
|
||||
i.getOutNode = nil
|
||||
return
|
||||
}
|
||||
|
||||
node = v[tokenIndex]
|
||||
if isLastToken && i.mode == "SET" {
|
||||
v[tokenIndex] = i.setInValue
|
||||
} else if isLastToken && i.mode == "DEL" {
|
||||
v[tokenIndex] = v[len(v)-1]
|
||||
v[len(v)-1] = nil
|
||||
v = v[:len(v)-1]
|
||||
previousNodes[ti-1].(map[string]interface{})[previousTokens[ti-1]] = v
|
||||
}
|
||||
|
||||
default:
|
||||
i.outError = fmt.Errorf("Invalid token reference '%s'", token)
|
||||
i.getOutKind = reflect.ValueOf(node).Kind()
|
||||
i.getOutNode = nil
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i.getOutNode = node
|
||||
i.getOutKind = reflect.ValueOf(node).Kind()
|
||||
i.outError = nil
|
||||
}
|
||||
|
||||
// Pointer to string representation function
|
||||
func (p *JsonPointer) String() string {
|
||||
|
||||
if len(p.referenceTokens) == 0 {
|
||||
return const_empty_pointer
|
||||
}
|
||||
|
||||
pointerString := const_pointer_separator + strings.Join(p.referenceTokens, const_pointer_separator)
|
||||
|
||||
return pointerString
|
||||
}
|
||||
|
||||
// Specific JSON pointer encoding here
|
||||
// ~0 => ~
|
||||
// ~1 => /
|
||||
// ... and vice versa
|
||||
|
||||
func decodeReferenceToken(token string) string {
|
||||
step1 := strings.Replace(token, `~1`, `/`, -1)
|
||||
step2 := strings.Replace(step1, `~0`, `~`, -1)
|
||||
return step2
|
||||
}
|
||||
|
||||
func encodeReferenceToken(token string) string {
|
||||
step1 := strings.Replace(token, `~`, `~0`, -1)
|
||||
step2 := strings.Replace(step1, `/`, `~1`, -1)
|
||||
return step2
|
||||
}
|
||||
202
vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt
generated
vendored
202
vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt
generated
vendored
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor 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, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 xeipuuv
|
||||
|
||||
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.
|
||||
10
vendor/github.com/xeipuuv/gojsonreference/README.md
generated
vendored
10
vendor/github.com/xeipuuv/gojsonreference/README.md
generated
vendored
@@ -1,10 +0,0 @@
|
||||
# gojsonreference
|
||||
An implementation of JSON Reference - Go language
|
||||
|
||||
## Dependencies
|
||||
https://github.com/xeipuuv/gojsonpointer
|
||||
|
||||
## References
|
||||
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
|
||||
|
||||
http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03
|
||||
147
vendor/github.com/xeipuuv/gojsonreference/reference.go
generated
vendored
147
vendor/github.com/xeipuuv/gojsonreference/reference.go
generated
vendored
@@ -1,147 +0,0 @@
|
||||
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author xeipuuv
|
||||
// author-github https://github.com/xeipuuv
|
||||
// author-mail xeipuuv@gmail.com
|
||||
//
|
||||
// repository-name gojsonreference
|
||||
// repository-desc An implementation of JSON Reference - Go language
|
||||
//
|
||||
// description Main and unique file.
|
||||
//
|
||||
// created 26-02-2013
|
||||
|
||||
package gojsonreference
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/xeipuuv/gojsonpointer"
|
||||
)
|
||||
|
||||
const (
|
||||
const_fragment_char = `#`
|
||||
)
|
||||
|
||||
func NewJsonReference(jsonReferenceString string) (JsonReference, error) {
|
||||
|
||||
var r JsonReference
|
||||
err := r.parse(jsonReferenceString)
|
||||
return r, err
|
||||
|
||||
}
|
||||
|
||||
type JsonReference struct {
|
||||
referenceUrl *url.URL
|
||||
referencePointer gojsonpointer.JsonPointer
|
||||
|
||||
HasFullUrl bool
|
||||
HasUrlPathOnly bool
|
||||
HasFragmentOnly bool
|
||||
HasFileScheme bool
|
||||
HasFullFilePath bool
|
||||
}
|
||||
|
||||
func (r *JsonReference) GetUrl() *url.URL {
|
||||
return r.referenceUrl
|
||||
}
|
||||
|
||||
func (r *JsonReference) GetPointer() *gojsonpointer.JsonPointer {
|
||||
return &r.referencePointer
|
||||
}
|
||||
|
||||
func (r *JsonReference) String() string {
|
||||
|
||||
if r.referenceUrl != nil {
|
||||
return r.referenceUrl.String()
|
||||
}
|
||||
|
||||
if r.HasFragmentOnly {
|
||||
return const_fragment_char + r.referencePointer.String()
|
||||
}
|
||||
|
||||
return r.referencePointer.String()
|
||||
}
|
||||
|
||||
func (r *JsonReference) IsCanonical() bool {
|
||||
return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullUrl)
|
||||
}
|
||||
|
||||
// "Constructor", parses the given string JSON reference
|
||||
func (r *JsonReference) parse(jsonReferenceString string) (err error) {
|
||||
|
||||
r.referenceUrl, err = url.Parse(jsonReferenceString)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
refUrl := r.referenceUrl
|
||||
|
||||
if refUrl.Scheme != "" && refUrl.Host != "" {
|
||||
r.HasFullUrl = true
|
||||
} else {
|
||||
if refUrl.Path != "" {
|
||||
r.HasUrlPathOnly = true
|
||||
} else if refUrl.RawQuery == "" && refUrl.Fragment != "" {
|
||||
r.HasFragmentOnly = true
|
||||
}
|
||||
}
|
||||
|
||||
r.HasFileScheme = refUrl.Scheme == "file"
|
||||
if runtime.GOOS == "windows" {
|
||||
// on Windows, a file URL may have an extra leading slash, and if it
|
||||
// doesn't then its first component will be treated as the host by the
|
||||
// Go runtime
|
||||
if refUrl.Host == "" && strings.HasPrefix(refUrl.Path, "/") {
|
||||
r.HasFullFilePath = filepath.IsAbs(refUrl.Path[1:])
|
||||
} else {
|
||||
r.HasFullFilePath = filepath.IsAbs(refUrl.Host + refUrl.Path)
|
||||
}
|
||||
} else {
|
||||
r.HasFullFilePath = filepath.IsAbs(refUrl.Path)
|
||||
}
|
||||
|
||||
// invalid json-pointer error means url has no json-pointer fragment. simply ignore error
|
||||
r.referencePointer, _ = gojsonpointer.NewJsonPointer(refUrl.Fragment)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Creates a new reference from a parent and a child
|
||||
// If the child cannot inherit from the parent, an error is returned
|
||||
func (r *JsonReference) Inherits(child JsonReference) (*JsonReference, error) {
|
||||
if child.GetUrl() == nil {
|
||||
return nil, errors.New("childUrl is nil!")
|
||||
}
|
||||
|
||||
if r.GetUrl() == nil {
|
||||
return nil, errors.New("parentUrl is nil!")
|
||||
}
|
||||
|
||||
// Get a copy of the parent url to make sure we do not modify the original.
|
||||
// URL reference resolving fails if the fragment of the child is empty, but the parent's is not.
|
||||
// The fragment of the child must be used, so the fragment of the parent is manually removed.
|
||||
parentUrl := *r.GetUrl()
|
||||
parentUrl.Fragment = ""
|
||||
|
||||
ref, err := NewJsonReference(parentUrl.ResolveReference(child.GetUrl()).String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ref, err
|
||||
}
|
||||
3
vendor/github.com/xeipuuv/gojsonschema/.gitignore
generated
vendored
3
vendor/github.com/xeipuuv/gojsonschema/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
*.sw[nop]
|
||||
*.iml
|
||||
.vscode/
|
||||
9
vendor/github.com/xeipuuv/gojsonschema/.travis.yml
generated
vendored
9
vendor/github.com/xeipuuv/gojsonschema/.travis.yml
generated
vendored
@@ -1,9 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- "1.11"
|
||||
- "1.12"
|
||||
- "1.13"
|
||||
before_install:
|
||||
- go get github.com/xeipuuv/gojsonreference
|
||||
- go get github.com/xeipuuv/gojsonpointer
|
||||
- go get github.com/stretchr/testify/assert
|
||||
202
vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt
generated
vendored
202
vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt
generated
vendored
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor 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, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2015 xeipuuv
|
||||
|
||||
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.
|
||||
466
vendor/github.com/xeipuuv/gojsonschema/README.md
generated
vendored
466
vendor/github.com/xeipuuv/gojsonschema/README.md
generated
vendored
@@ -1,466 +0,0 @@
|
||||
[](https://godoc.org/github.com/xeipuuv/gojsonschema)
|
||||
[](https://travis-ci.org/xeipuuv/gojsonschema)
|
||||
[](https://goreportcard.com/report/github.com/xeipuuv/gojsonschema)
|
||||
|
||||
# gojsonschema
|
||||
|
||||
## Description
|
||||
|
||||
An implementation of JSON Schema for the Go programming language. Supports draft-04, draft-06 and draft-07.
|
||||
|
||||
References :
|
||||
|
||||
* http://json-schema.org
|
||||
* http://json-schema.org/latest/json-schema-core.html
|
||||
* http://json-schema.org/latest/json-schema-validation.html
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
go get github.com/xeipuuv/gojsonschema
|
||||
```
|
||||
|
||||
Dependencies :
|
||||
* [github.com/xeipuuv/gojsonpointer](https://github.com/xeipuuv/gojsonpointer)
|
||||
* [github.com/xeipuuv/gojsonreference](https://github.com/xeipuuv/gojsonreference)
|
||||
* [github.com/stretchr/testify/assert](https://github.com/stretchr/testify#assert-package)
|
||||
|
||||
## Usage
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
schemaLoader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
|
||||
documentLoader := gojsonschema.NewReferenceLoader("file:///home/me/document.json")
|
||||
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
if result.Valid() {
|
||||
fmt.Printf("The document is valid\n")
|
||||
} else {
|
||||
fmt.Printf("The document is not valid. see errors :\n")
|
||||
for _, desc := range result.Errors() {
|
||||
fmt.Printf("- %s\n", desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### Loaders
|
||||
|
||||
There are various ways to load your JSON data.
|
||||
In order to load your schemas and documents,
|
||||
first declare an appropriate loader :
|
||||
|
||||
* Web / HTTP, using a reference :
|
||||
|
||||
```go
|
||||
loader := gojsonschema.NewReferenceLoader("http://www.some_host.com/schema.json")
|
||||
```
|
||||
|
||||
* Local file, using a reference :
|
||||
|
||||
```go
|
||||
loader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
|
||||
```
|
||||
|
||||
References use the URI scheme, the prefix (file://) and a full path to the file are required.
|
||||
|
||||
* JSON strings :
|
||||
|
||||
```go
|
||||
loader := gojsonschema.NewStringLoader(`{"type": "string"}`)
|
||||
```
|
||||
|
||||
* Custom Go types :
|
||||
|
||||
```go
|
||||
m := map[string]interface{}{"type": "string"}
|
||||
loader := gojsonschema.NewGoLoader(m)
|
||||
```
|
||||
|
||||
And
|
||||
|
||||
```go
|
||||
type Root struct {
|
||||
Users []User `json:"users"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
data := Root{}
|
||||
data.Users = append(data.Users, User{"John"})
|
||||
data.Users = append(data.Users, User{"Sophia"})
|
||||
data.Users = append(data.Users, User{"Bill"})
|
||||
|
||||
loader := gojsonschema.NewGoLoader(data)
|
||||
```
|
||||
|
||||
#### Validation
|
||||
|
||||
Once the loaders are set, validation is easy :
|
||||
|
||||
```go
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
```
|
||||
|
||||
Alternatively, you might want to load a schema only once and process to multiple validations :
|
||||
|
||||
```go
|
||||
schema, err := gojsonschema.NewSchema(schemaLoader)
|
||||
...
|
||||
result1, err := schema.Validate(documentLoader1)
|
||||
...
|
||||
result2, err := schema.Validate(documentLoader2)
|
||||
...
|
||||
// etc ...
|
||||
```
|
||||
|
||||
To check the result :
|
||||
|
||||
```go
|
||||
if result.Valid() {
|
||||
fmt.Printf("The document is valid\n")
|
||||
} else {
|
||||
fmt.Printf("The document is not valid. see errors :\n")
|
||||
for _, err := range result.Errors() {
|
||||
// Err implements the ResultError interface
|
||||
fmt.Printf("- %s\n", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Loading local schemas
|
||||
|
||||
By default `file` and `http(s)` references to external schemas are loaded automatically via the file system or via http(s). An external schema can also be loaded using a `SchemaLoader`.
|
||||
|
||||
```go
|
||||
sl := gojsonschema.NewSchemaLoader()
|
||||
loader1 := gojsonschema.NewStringLoader(`{ "type" : "string" }`)
|
||||
err := sl.AddSchema("http://some_host.com/string.json", loader1)
|
||||
```
|
||||
|
||||
Alternatively if your schema already has an `$id` you can use the `AddSchemas` function
|
||||
```go
|
||||
loader2 := gojsonschema.NewStringLoader(`{
|
||||
"$id" : "http://some_host.com/maxlength.json",
|
||||
"maxLength" : 5
|
||||
}`)
|
||||
err = sl.AddSchemas(loader2)
|
||||
```
|
||||
|
||||
The main schema should be passed to the `Compile` function. This main schema can then directly reference the added schemas without needing to download them.
|
||||
```go
|
||||
loader3 := gojsonschema.NewStringLoader(`{
|
||||
"$id" : "http://some_host.com/main.json",
|
||||
"allOf" : [
|
||||
{ "$ref" : "http://some_host.com/string.json" },
|
||||
{ "$ref" : "http://some_host.com/maxlength.json" }
|
||||
]
|
||||
}`)
|
||||
|
||||
schema, err := sl.Compile(loader3)
|
||||
|
||||
documentLoader := gojsonschema.NewStringLoader(`"hello world"`)
|
||||
|
||||
result, err := schema.Validate(documentLoader)
|
||||
```
|
||||
|
||||
It's also possible to pass a `ReferenceLoader` to the `Compile` function that references a loaded schema.
|
||||
|
||||
```go
|
||||
err = sl.AddSchemas(loader3)
|
||||
schema, err := sl.Compile(gojsonschema.NewReferenceLoader("http://some_host.com/main.json"))
|
||||
```
|
||||
|
||||
Schemas added by `AddSchema` and `AddSchemas` are only validated when the entire schema is compiled, unless meta-schema validation is used.
|
||||
|
||||
## Using a specific draft
|
||||
By default `gojsonschema` will try to detect the draft of a schema by using the `$schema` keyword and parse it in a strict draft-04, draft-06 or draft-07 mode. If `$schema` is missing, or the draft version is not explicitely set, a hybrid mode is used which merges together functionality of all drafts into one mode.
|
||||
|
||||
Autodectection can be turned off with the `AutoDetect` property. Specific draft versions can be specified with the `Draft` property.
|
||||
|
||||
```go
|
||||
sl := gojsonschema.NewSchemaLoader()
|
||||
sl.Draft = gojsonschema.Draft7
|
||||
sl.AutoDetect = false
|
||||
```
|
||||
|
||||
If autodetection is on (default), a draft-07 schema can savely reference draft-04 schemas and vice-versa, as long as `$schema` is specified in all schemas.
|
||||
|
||||
## Meta-schema validation
|
||||
Schemas that are added using the `AddSchema`, `AddSchemas` and `Compile` can be validated against their meta-schema by setting the `Validate` property.
|
||||
|
||||
The following example will produce an error as `multipleOf` must be a number. If `Validate` is off (default), this error is only returned at the `Compile` step.
|
||||
|
||||
```go
|
||||
sl := gojsonschema.NewSchemaLoader()
|
||||
sl.Validate = true
|
||||
err := sl.AddSchemas(gojsonschema.NewStringLoader(`{
|
||||
$id" : "http://some_host.com/invalid.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"multipleOf" : true
|
||||
}`))
|
||||
```
|
||||
```
|
||||
```
|
||||
|
||||
Errors returned by meta-schema validation are more readable and contain more information, which helps significantly if you are developing a schema.
|
||||
|
||||
Meta-schema validation also works with a custom `$schema`. In case `$schema` is missing, or `AutoDetect` is set to `false`, the meta-schema of the used draft is used.
|
||||
|
||||
|
||||
## Working with Errors
|
||||
|
||||
The library handles string error codes which you can customize by creating your own gojsonschema.locale and setting it
|
||||
```go
|
||||
gojsonschema.Locale = YourCustomLocale{}
|
||||
```
|
||||
|
||||
However, each error contains additional contextual information.
|
||||
|
||||
Newer versions of `gojsonschema` may have new additional errors, so code that uses a custom locale will need to be updated when this happens.
|
||||
|
||||
**err.Type()**: *string* Returns the "type" of error that occurred. Note you can also type check. See below
|
||||
|
||||
Note: An error of RequiredType has an err.Type() return value of "required"
|
||||
|
||||
"required": RequiredError
|
||||
"invalid_type": InvalidTypeError
|
||||
"number_any_of": NumberAnyOfError
|
||||
"number_one_of": NumberOneOfError
|
||||
"number_all_of": NumberAllOfError
|
||||
"number_not": NumberNotError
|
||||
"missing_dependency": MissingDependencyError
|
||||
"internal": InternalError
|
||||
"const": ConstEror
|
||||
"enum": EnumError
|
||||
"array_no_additional_items": ArrayNoAdditionalItemsError
|
||||
"array_min_items": ArrayMinItemsError
|
||||
"array_max_items": ArrayMaxItemsError
|
||||
"unique": ItemsMustBeUniqueError
|
||||
"contains" : ArrayContainsError
|
||||
"array_min_properties": ArrayMinPropertiesError
|
||||
"array_max_properties": ArrayMaxPropertiesError
|
||||
"additional_property_not_allowed": AdditionalPropertyNotAllowedError
|
||||
"invalid_property_pattern": InvalidPropertyPatternError
|
||||
"invalid_property_name": InvalidPropertyNameError
|
||||
"string_gte": StringLengthGTEError
|
||||
"string_lte": StringLengthLTEError
|
||||
"pattern": DoesNotMatchPatternError
|
||||
"multiple_of": MultipleOfError
|
||||
"number_gte": NumberGTEError
|
||||
"number_gt": NumberGTError
|
||||
"number_lte": NumberLTEError
|
||||
"number_lt": NumberLTError
|
||||
"condition_then" : ConditionThenError
|
||||
"condition_else" : ConditionElseError
|
||||
|
||||
**err.Value()**: *interface{}* Returns the value given
|
||||
|
||||
**err.Context()**: *gojsonschema.JsonContext* Returns the context. This has a String() method that will print something like this: (root).firstName
|
||||
|
||||
**err.Field()**: *string* Returns the fieldname in the format firstName, or for embedded properties, person.firstName. This returns the same as the String() method on *err.Context()* but removes the (root). prefix.
|
||||
|
||||
**err.Description()**: *string* The error description. This is based on the locale you are using. See the beginning of this section for overwriting the locale with a custom implementation.
|
||||
|
||||
**err.DescriptionFormat()**: *string* The error description format. This is relevant if you are adding custom validation errors afterwards to the result.
|
||||
|
||||
**err.Details()**: *gojsonschema.ErrorDetails* Returns a map[string]interface{} of additional error details specific to the error. For example, GTE errors will have a "min" value, LTE will have a "max" value. See errors.go for a full description of all the error details. Every error always contains a "field" key that holds the value of *err.Field()*
|
||||
|
||||
Note in most cases, the err.Details() will be used to generate replacement strings in your locales, and not used directly. These strings follow the text/template format i.e.
|
||||
```
|
||||
{{.field}} must be greater than or equal to {{.min}}
|
||||
```
|
||||
|
||||
The library allows you to specify custom template functions, should you require more complex error message handling.
|
||||
```go
|
||||
gojsonschema.ErrorTemplateFuncs = map[string]interface{}{
|
||||
"allcaps": func(s string) string {
|
||||
return strings.ToUpper(s)
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Given the above definition, you can use the custom function `"allcaps"` in your localization templates:
|
||||
```
|
||||
{{allcaps .field}} must be greater than or equal to {{.min}}
|
||||
```
|
||||
|
||||
The above error message would then be rendered with the `field` value in capital letters. For example:
|
||||
```
|
||||
"PASSWORD must be greater than or equal to 8"
|
||||
```
|
||||
|
||||
Learn more about what types of template functions you can use in `ErrorTemplateFuncs` by referring to Go's [text/template FuncMap](https://golang.org/pkg/text/template/#FuncMap) type.
|
||||
|
||||
## Formats
|
||||
JSON Schema allows for optional "format" property to validate instances against well-known formats. gojsonschema ships with all of the formats defined in the spec that you can use like this:
|
||||
|
||||
````json
|
||||
{"type": "string", "format": "email"}
|
||||
````
|
||||
|
||||
Not all formats defined in draft-07 are available. Implemented formats are:
|
||||
|
||||
* `date`
|
||||
* `time`
|
||||
* `date-time`
|
||||
* `hostname`. Subdomains that start with a number are also supported, but this means that it doesn't strictly follow [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5) and has the implication that ipv4 addresses are also recognized as valid hostnames.
|
||||
* `email`. Go's email parser deviates slightly from [RFC5322](https://tools.ietf.org/html/rfc5322). Includes unicode support.
|
||||
* `idn-email`. Same caveat as `email`.
|
||||
* `ipv4`
|
||||
* `ipv6`
|
||||
* `uri`. Includes unicode support.
|
||||
* `uri-reference`. Includes unicode support.
|
||||
* `iri`
|
||||
* `iri-reference`
|
||||
* `uri-template`
|
||||
* `uuid`
|
||||
* `regex`. Go uses the [RE2](https://github.com/google/re2/wiki/Syntax) engine and is not [ECMA262](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf) compatible.
|
||||
* `json-pointer`
|
||||
* `relative-json-pointer`
|
||||
|
||||
`email`, `uri` and `uri-reference` use the same validation code as their unicode counterparts `idn-email`, `iri` and `iri-reference`. If you rely on unicode support you should use the specific
|
||||
unicode enabled formats for the sake of interoperability as other implementations might not support unicode in the regular formats.
|
||||
|
||||
The validation code for `uri`, `idn-email` and their relatives use mostly standard library code.
|
||||
|
||||
For repetitive or more complex formats, you can create custom format checkers and add them to gojsonschema like this:
|
||||
|
||||
```go
|
||||
// Define the format checker
|
||||
type RoleFormatChecker struct {}
|
||||
|
||||
// Ensure it meets the gojsonschema.FormatChecker interface
|
||||
func (f RoleFormatChecker) IsFormat(input interface{}) bool {
|
||||
|
||||
asString, ok := input.(string)
|
||||
if ok == false {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.HasPrefix("ROLE_", asString)
|
||||
}
|
||||
|
||||
// Add it to the library
|
||||
gojsonschema.FormatCheckers.Add("role", RoleFormatChecker{})
|
||||
````
|
||||
|
||||
Now to use in your json schema:
|
||||
````json
|
||||
{"type": "string", "format": "role"}
|
||||
````
|
||||
|
||||
Another example would be to check if the provided integer matches an id on database:
|
||||
|
||||
JSON schema:
|
||||
```json
|
||||
{"type": "integer", "format": "ValidUserId"}
|
||||
```
|
||||
|
||||
```go
|
||||
// Define the format checker
|
||||
type ValidUserIdFormatChecker struct {}
|
||||
|
||||
// Ensure it meets the gojsonschema.FormatChecker interface
|
||||
func (f ValidUserIdFormatChecker) IsFormat(input interface{}) bool {
|
||||
|
||||
asFloat64, ok := input.(float64) // Numbers are always float64 here
|
||||
if ok == false {
|
||||
return false
|
||||
}
|
||||
|
||||
// XXX
|
||||
// do the magic on the database looking for the int(asFloat64)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Add it to the library
|
||||
gojsonschema.FormatCheckers.Add("ValidUserId", ValidUserIdFormatChecker{})
|
||||
````
|
||||
|
||||
Formats can also be removed, for example if you want to override one of the formats that is defined by default.
|
||||
|
||||
```go
|
||||
gojsonschema.FormatCheckers.Remove("hostname")
|
||||
```
|
||||
|
||||
|
||||
## Additional custom validation
|
||||
After the validation has run and you have the results, you may add additional
|
||||
errors using `Result.AddError`. This is useful to maintain the same format within the resultset instead
|
||||
of having to add special exceptions for your own errors. Below is an example.
|
||||
|
||||
```go
|
||||
type AnswerInvalidError struct {
|
||||
gojsonschema.ResultErrorFields
|
||||
}
|
||||
|
||||
func newAnswerInvalidError(context *gojsonschema.JsonContext, value interface{}, details gojsonschema.ErrorDetails) *AnswerInvalidError {
|
||||
err := AnswerInvalidError{}
|
||||
err.SetContext(context)
|
||||
err.SetType("custom_invalid_error")
|
||||
// it is important to use SetDescriptionFormat() as this is used to call SetDescription() after it has been parsed
|
||||
// using the description of err will be overridden by this.
|
||||
err.SetDescriptionFormat("Answer to the Ultimate Question of Life, the Universe, and Everything is {{.answer}}")
|
||||
err.SetValue(value)
|
||||
err.SetDetails(details)
|
||||
|
||||
return &err
|
||||
}
|
||||
|
||||
func main() {
|
||||
// ...
|
||||
schema, err := gojsonschema.NewSchema(schemaLoader)
|
||||
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
|
||||
|
||||
if true { // some validation
|
||||
jsonContext := gojsonschema.NewJsonContext("question", nil)
|
||||
errDetail := gojsonschema.ErrorDetails{
|
||||
"answer": 42,
|
||||
}
|
||||
result.AddError(
|
||||
newAnswerInvalidError(
|
||||
gojsonschema.NewJsonContext("answer", jsonContext),
|
||||
52,
|
||||
errDetail,
|
||||
),
|
||||
errDetail,
|
||||
)
|
||||
}
|
||||
|
||||
return result, err
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This is especially useful if you want to add validation beyond what the
|
||||
json schema drafts can provide such business specific logic.
|
||||
|
||||
## Uses
|
||||
|
||||
gojsonschema uses the following test suite :
|
||||
|
||||
https://github.com/json-schema/JSON-Schema-Test-Suite
|
||||
125
vendor/github.com/xeipuuv/gojsonschema/draft.go
generated
vendored
125
vendor/github.com/xeipuuv/gojsonschema/draft.go
generated
vendored
@@ -1,125 +0,0 @@
|
||||
// Copyright 2018 johandorland ( https://github.com/johandorland )
|
||||
//
|
||||
// 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 gojsonschema
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/xeipuuv/gojsonreference"
|
||||
)
|
||||
|
||||
// Draft is a JSON-schema draft version
|
||||
type Draft int
|
||||
|
||||
// Supported Draft versions
|
||||
const (
|
||||
Draft4 Draft = 4
|
||||
Draft6 Draft = 6
|
||||
Draft7 Draft = 7
|
||||
Hybrid Draft = math.MaxInt32
|
||||
)
|
||||
|
||||
type draftConfig struct {
|
||||
Version Draft
|
||||
MetaSchemaURL string
|
||||
MetaSchema string
|
||||
}
|
||||
type draftConfigs []draftConfig
|
||||
|
||||
var drafts draftConfigs
|
||||
|
||||
func init() {
|
||||
drafts = []draftConfig{
|
||||
{
|
||||
Version: Draft4,
|
||||
MetaSchemaURL: "http://json-schema.org/draft-04/schema",
|
||||
MetaSchema: `{"id":"http://json-schema.org/draft-04/schema#","$schema":"http://json-schema.org/draft-04/schema#","description":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"positiveInteger":{"type":"integer","minimum":0},"positiveIntegerDefault0":{"allOf":[{"$ref":"#/definitions/positiveInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"minItems":1,"uniqueItems":true}},"type":"object","properties":{"id":{"type":"string"},"$schema":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"multipleOf":{"type":"number","minimum":0,"exclusiveMinimum":true},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"boolean","default":false},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"boolean","default":false},"maxLength":{"$ref":"#/definitions/positiveInteger"},"minLength":{"$ref":"#/definitions/positiveIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"anyOf":[{"type":"boolean"},{"$ref":"#"}],"default":{}},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":{}},"maxItems":{"$ref":"#/definitions/positiveInteger"},"minItems":{"$ref":"#/definitions/positiveIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"maxProperties":{"$ref":"#/definitions/positiveInteger"},"minProperties":{"$ref":"#/definitions/positiveIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"anyOf":[{"type":"boolean"},{"$ref":"#"}],"default":{}},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"dependencies":{"exclusiveMaximum":["maximum"],"exclusiveMinimum":["minimum"]},"default":{}}`,
|
||||
},
|
||||
{
|
||||
Version: Draft6,
|
||||
MetaSchemaURL: "http://json-schema.org/draft-06/schema",
|
||||
MetaSchema: `{"$schema":"http://json-schema.org/draft-06/schema#","$id":"http://json-schema.org/draft-06/schema#","title":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"allOf":[{"$ref":"#/definitions/nonNegativeInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}},"type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference"},"$schema":{"type":"string","format":"uri"},"$ref":{"type":"string","format":"uri-reference"},"title":{"type":"string"},"description":{"type":"string"},"default":{},"examples":{"type":"array","items":{}},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/definitions/nonNegativeInteger"},"minLength":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"$ref":"#"},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":{}},"maxItems":{"$ref":"#/definitions/nonNegativeInteger"},"minItems":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"contains":{"$ref":"#"},"maxProperties":{"$ref":"#/definitions/nonNegativeInteger"},"minProperties":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"$ref":"#"},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":{},"enum":{"type":"array","minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":{}}`,
|
||||
},
|
||||
{
|
||||
Version: Draft7,
|
||||
MetaSchemaURL: "http://json-schema.org/draft-07/schema",
|
||||
MetaSchema: `{"$schema":"http://json-schema.org/draft-07/schema#","$id":"http://json-schema.org/draft-07/schema#","title":"Core schema meta-schema","definitions":{"schemaArray":{"type":"array","minItems":1,"items":{"$ref":"#"}},"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"allOf":[{"$ref":"#/definitions/nonNegativeInteger"},{"default":0}]},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}},"type":["object","boolean"],"properties":{"$id":{"type":"string","format":"uri-reference"},"$schema":{"type":"string","format":"uri"},"$ref":{"type":"string","format":"uri-reference"},"$comment":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"default":true,"readOnly":{"type":"boolean","default":false},"examples":{"type":"array","items":true},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/definitions/nonNegativeInteger"},"minLength":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"additionalItems":{"$ref":"#"},"items":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/schemaArray"}],"default":true},"maxItems":{"$ref":"#/definitions/nonNegativeInteger"},"minItems":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"contains":{"$ref":"#"},"maxProperties":{"$ref":"#/definitions/nonNegativeInteger"},"minProperties":{"$ref":"#/definitions/nonNegativeIntegerDefault0"},"required":{"$ref":"#/definitions/stringArray"},"additionalProperties":{"$ref":"#"},"definitions":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"properties":{"type":"object","additionalProperties":{"$ref":"#"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$ref":"#"},"propertyNames":{"format":"regex"},"default":{}},"dependencies":{"type":"object","additionalProperties":{"anyOf":[{"$ref":"#"},{"$ref":"#/definitions/stringArray"}]}},"propertyNames":{"$ref":"#"},"const":true,"enum":{"type":"array","items":true,"minItems":1,"uniqueItems":true},"type":{"anyOf":[{"$ref":"#/definitions/simpleTypes"},{"type":"array","items":{"$ref":"#/definitions/simpleTypes"},"minItems":1,"uniqueItems":true}]},"format":{"type":"string"},"contentMediaType":{"type":"string"},"contentEncoding":{"type":"string"},"if":{"$ref":"#"},"then":{"$ref":"#"},"else":{"$ref":"#"},"allOf":{"$ref":"#/definitions/schemaArray"},"anyOf":{"$ref":"#/definitions/schemaArray"},"oneOf":{"$ref":"#/definitions/schemaArray"},"not":{"$ref":"#"}},"default":true}`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (dc draftConfigs) GetMetaSchema(url string) string {
|
||||
for _, config := range dc {
|
||||
if config.MetaSchemaURL == url {
|
||||
return config.MetaSchema
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (dc draftConfigs) GetDraftVersion(url string) *Draft {
|
||||
for _, config := range dc {
|
||||
if config.MetaSchemaURL == url {
|
||||
return &config.Version
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (dc draftConfigs) GetSchemaURL(draft Draft) string {
|
||||
for _, config := range dc {
|
||||
if config.Version == draft {
|
||||
return config.MetaSchemaURL
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func parseSchemaURL(documentNode interface{}) (string, *Draft, error) {
|
||||
|
||||
if isKind(documentNode, reflect.Bool) {
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
if !isKind(documentNode, reflect.Map) {
|
||||
return "", nil, errors.New("schema is invalid")
|
||||
}
|
||||
|
||||
m := documentNode.(map[string]interface{})
|
||||
|
||||
if existsMapKey(m, KEY_SCHEMA) {
|
||||
if !isKind(m[KEY_SCHEMA], reflect.String) {
|
||||
return "", nil, errors.New(formatErrorDescription(
|
||||
Locale.MustBeOfType(),
|
||||
ErrorDetails{
|
||||
"key": KEY_SCHEMA,
|
||||
"type": TYPE_STRING,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
schemaReference, err := gojsonreference.NewJsonReference(m[KEY_SCHEMA].(string))
|
||||
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
schema := schemaReference.String()
|
||||
|
||||
return schema, drafts.GetDraftVersion(schema), nil
|
||||
}
|
||||
|
||||
return "", nil, nil
|
||||
}
|
||||
364
vendor/github.com/xeipuuv/gojsonschema/errors.go
generated
vendored
364
vendor/github.com/xeipuuv/gojsonschema/errors.go
generated
vendored
@@ -1,364 +0,0 @@
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var errorTemplates = errorTemplate{template.New("errors-new"), sync.RWMutex{}}
|
||||
|
||||
// template.Template is not thread-safe for writing, so some locking is done
|
||||
// sync.RWMutex is used for efficiently locking when new templates are created
|
||||
type errorTemplate struct {
|
||||
*template.Template
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
type (
|
||||
|
||||
// FalseError. ErrorDetails: -
|
||||
FalseError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// RequiredError indicates that a required field is missing
|
||||
// ErrorDetails: property string
|
||||
RequiredError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// InvalidTypeError indicates that a field has the incorrect type
|
||||
// ErrorDetails: expected, given
|
||||
InvalidTypeError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberAnyOfError is produced in case of a failing "anyOf" validation
|
||||
// ErrorDetails: -
|
||||
NumberAnyOfError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberOneOfError is produced in case of a failing "oneOf" validation
|
||||
// ErrorDetails: -
|
||||
NumberOneOfError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberAllOfError is produced in case of a failing "allOf" validation
|
||||
// ErrorDetails: -
|
||||
NumberAllOfError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberNotError is produced if a "not" validation failed
|
||||
// ErrorDetails: -
|
||||
NumberNotError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// MissingDependencyError is produced in case of a "missing dependency" problem
|
||||
// ErrorDetails: dependency
|
||||
MissingDependencyError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// InternalError indicates an internal error
|
||||
// ErrorDetails: error
|
||||
InternalError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ConstError indicates a const error
|
||||
// ErrorDetails: allowed
|
||||
ConstError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// EnumError indicates an enum error
|
||||
// ErrorDetails: allowed
|
||||
EnumError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ArrayNoAdditionalItemsError is produced if additional items were found, but not allowed
|
||||
// ErrorDetails: -
|
||||
ArrayNoAdditionalItemsError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ArrayMinItemsError is produced if an array contains less items than the allowed minimum
|
||||
// ErrorDetails: min
|
||||
ArrayMinItemsError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ArrayMaxItemsError is produced if an array contains more items than the allowed maximum
|
||||
// ErrorDetails: max
|
||||
ArrayMaxItemsError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ItemsMustBeUniqueError is produced if an array requires unique items, but contains non-unique items
|
||||
// ErrorDetails: type, i, j
|
||||
ItemsMustBeUniqueError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ArrayContainsError is produced if an array contains invalid items
|
||||
// ErrorDetails:
|
||||
ArrayContainsError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ArrayMinPropertiesError is produced if an object contains less properties than the allowed minimum
|
||||
// ErrorDetails: min
|
||||
ArrayMinPropertiesError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ArrayMaxPropertiesError is produced if an object contains more properties than the allowed maximum
|
||||
// ErrorDetails: max
|
||||
ArrayMaxPropertiesError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// AdditionalPropertyNotAllowedError is produced if an object has additional properties, but not allowed
|
||||
// ErrorDetails: property
|
||||
AdditionalPropertyNotAllowedError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// InvalidPropertyPatternError is produced if an pattern was found
|
||||
// ErrorDetails: property, pattern
|
||||
InvalidPropertyPatternError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// InvalidPropertyNameError is produced if an invalid-named property was found
|
||||
// ErrorDetails: property
|
||||
InvalidPropertyNameError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// StringLengthGTEError is produced if a string is shorter than the minimum required length
|
||||
// ErrorDetails: min
|
||||
StringLengthGTEError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// StringLengthLTEError is produced if a string is longer than the maximum allowed length
|
||||
// ErrorDetails: max
|
||||
StringLengthLTEError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// DoesNotMatchPatternError is produced if a string does not match the defined pattern
|
||||
// ErrorDetails: pattern
|
||||
DoesNotMatchPatternError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// DoesNotMatchFormatError is produced if a string does not match the defined format
|
||||
// ErrorDetails: format
|
||||
DoesNotMatchFormatError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// MultipleOfError is produced if a number is not a multiple of the defined multipleOf
|
||||
// ErrorDetails: multiple
|
||||
MultipleOfError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberGTEError is produced if a number is lower than the allowed minimum
|
||||
// ErrorDetails: min
|
||||
NumberGTEError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberGTError is produced if a number is lower than, or equal to the specified minimum, and exclusiveMinimum is set
|
||||
// ErrorDetails: min
|
||||
NumberGTError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberLTEError is produced if a number is higher than the allowed maximum
|
||||
// ErrorDetails: max
|
||||
NumberLTEError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// NumberLTError is produced if a number is higher than, or equal to the specified maximum, and exclusiveMaximum is set
|
||||
// ErrorDetails: max
|
||||
NumberLTError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ConditionThenError is produced if a condition's "then" validation is invalid
|
||||
// ErrorDetails: -
|
||||
ConditionThenError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
|
||||
// ConditionElseError is produced if a condition's "else" condition is invalid
|
||||
// ErrorDetails: -
|
||||
ConditionElseError struct {
|
||||
ResultErrorFields
|
||||
}
|
||||
)
|
||||
|
||||
// newError takes a ResultError type and sets the type, context, description, details, value, and field
|
||||
func newError(err ResultError, context *JsonContext, value interface{}, locale locale, details ErrorDetails) {
|
||||
var t string
|
||||
var d string
|
||||
switch err.(type) {
|
||||
case *FalseError:
|
||||
t = "false"
|
||||
d = locale.False()
|
||||
case *RequiredError:
|
||||
t = "required"
|
||||
d = locale.Required()
|
||||
case *InvalidTypeError:
|
||||
t = "invalid_type"
|
||||
d = locale.InvalidType()
|
||||
case *NumberAnyOfError:
|
||||
t = "number_any_of"
|
||||
d = locale.NumberAnyOf()
|
||||
case *NumberOneOfError:
|
||||
t = "number_one_of"
|
||||
d = locale.NumberOneOf()
|
||||
case *NumberAllOfError:
|
||||
t = "number_all_of"
|
||||
d = locale.NumberAllOf()
|
||||
case *NumberNotError:
|
||||
t = "number_not"
|
||||
d = locale.NumberNot()
|
||||
case *MissingDependencyError:
|
||||
t = "missing_dependency"
|
||||
d = locale.MissingDependency()
|
||||
case *InternalError:
|
||||
t = "internal"
|
||||
d = locale.Internal()
|
||||
case *ConstError:
|
||||
t = "const"
|
||||
d = locale.Const()
|
||||
case *EnumError:
|
||||
t = "enum"
|
||||
d = locale.Enum()
|
||||
case *ArrayNoAdditionalItemsError:
|
||||
t = "array_no_additional_items"
|
||||
d = locale.ArrayNoAdditionalItems()
|
||||
case *ArrayMinItemsError:
|
||||
t = "array_min_items"
|
||||
d = locale.ArrayMinItems()
|
||||
case *ArrayMaxItemsError:
|
||||
t = "array_max_items"
|
||||
d = locale.ArrayMaxItems()
|
||||
case *ItemsMustBeUniqueError:
|
||||
t = "unique"
|
||||
d = locale.Unique()
|
||||
case *ArrayContainsError:
|
||||
t = "contains"
|
||||
d = locale.ArrayContains()
|
||||
case *ArrayMinPropertiesError:
|
||||
t = "array_min_properties"
|
||||
d = locale.ArrayMinProperties()
|
||||
case *ArrayMaxPropertiesError:
|
||||
t = "array_max_properties"
|
||||
d = locale.ArrayMaxProperties()
|
||||
case *AdditionalPropertyNotAllowedError:
|
||||
t = "additional_property_not_allowed"
|
||||
d = locale.AdditionalPropertyNotAllowed()
|
||||
case *InvalidPropertyPatternError:
|
||||
t = "invalid_property_pattern"
|
||||
d = locale.InvalidPropertyPattern()
|
||||
case *InvalidPropertyNameError:
|
||||
t = "invalid_property_name"
|
||||
d = locale.InvalidPropertyName()
|
||||
case *StringLengthGTEError:
|
||||
t = "string_gte"
|
||||
d = locale.StringGTE()
|
||||
case *StringLengthLTEError:
|
||||
t = "string_lte"
|
||||
d = locale.StringLTE()
|
||||
case *DoesNotMatchPatternError:
|
||||
t = "pattern"
|
||||
d = locale.DoesNotMatchPattern()
|
||||
case *DoesNotMatchFormatError:
|
||||
t = "format"
|
||||
d = locale.DoesNotMatchFormat()
|
||||
case *MultipleOfError:
|
||||
t = "multiple_of"
|
||||
d = locale.MultipleOf()
|
||||
case *NumberGTEError:
|
||||
t = "number_gte"
|
||||
d = locale.NumberGTE()
|
||||
case *NumberGTError:
|
||||
t = "number_gt"
|
||||
d = locale.NumberGT()
|
||||
case *NumberLTEError:
|
||||
t = "number_lte"
|
||||
d = locale.NumberLTE()
|
||||
case *NumberLTError:
|
||||
t = "number_lt"
|
||||
d = locale.NumberLT()
|
||||
case *ConditionThenError:
|
||||
t = "condition_then"
|
||||
d = locale.ConditionThen()
|
||||
case *ConditionElseError:
|
||||
t = "condition_else"
|
||||
d = locale.ConditionElse()
|
||||
}
|
||||
|
||||
err.SetType(t)
|
||||
err.SetContext(context)
|
||||
err.SetValue(value)
|
||||
err.SetDetails(details)
|
||||
err.SetDescriptionFormat(d)
|
||||
details["field"] = err.Field()
|
||||
|
||||
if _, exists := details["context"]; !exists && context != nil {
|
||||
details["context"] = context.String()
|
||||
}
|
||||
|
||||
err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details))
|
||||
}
|
||||
|
||||
// formatErrorDescription takes a string in the default text/template
|
||||
// format and converts it to a string with replacements. The fields come
|
||||
// from the ErrorDetails struct and vary for each type of error.
|
||||
func formatErrorDescription(s string, details ErrorDetails) string {
|
||||
|
||||
var tpl *template.Template
|
||||
var descrAsBuffer bytes.Buffer
|
||||
var err error
|
||||
|
||||
errorTemplates.RLock()
|
||||
tpl = errorTemplates.Lookup(s)
|
||||
errorTemplates.RUnlock()
|
||||
|
||||
if tpl == nil {
|
||||
errorTemplates.Lock()
|
||||
tpl = errorTemplates.New(s)
|
||||
|
||||
if ErrorTemplateFuncs != nil {
|
||||
tpl.Funcs(ErrorTemplateFuncs)
|
||||
}
|
||||
|
||||
tpl, err = tpl.Parse(s)
|
||||
errorTemplates.Unlock()
|
||||
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
err = tpl.Execute(&descrAsBuffer, details)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return descrAsBuffer.String()
|
||||
}
|
||||
368
vendor/github.com/xeipuuv/gojsonschema/format_checkers.go
generated
vendored
368
vendor/github.com/xeipuuv/gojsonschema/format_checkers.go
generated
vendored
@@ -1,368 +0,0 @@
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
// FormatChecker is the interface all formatters added to FormatCheckerChain must implement
|
||||
FormatChecker interface {
|
||||
// IsFormat checks if input has the correct format and type
|
||||
IsFormat(input interface{}) bool
|
||||
}
|
||||
|
||||
// FormatCheckerChain holds the formatters
|
||||
FormatCheckerChain struct {
|
||||
formatters map[string]FormatChecker
|
||||
}
|
||||
|
||||
// EmailFormatChecker verifies email address formats
|
||||
EmailFormatChecker struct{}
|
||||
|
||||
// IPV4FormatChecker verifies IP addresses in the IPv4 format
|
||||
IPV4FormatChecker struct{}
|
||||
|
||||
// IPV6FormatChecker verifies IP addresses in the IPv6 format
|
||||
IPV6FormatChecker struct{}
|
||||
|
||||
// DateTimeFormatChecker verifies date/time formats per RFC3339 5.6
|
||||
//
|
||||
// Valid formats:
|
||||
// Partial Time: HH:MM:SS
|
||||
// Full Date: YYYY-MM-DD
|
||||
// Full Time: HH:MM:SSZ-07:00
|
||||
// Date Time: YYYY-MM-DDTHH:MM:SSZ-0700
|
||||
//
|
||||
// Where
|
||||
// YYYY = 4DIGIT year
|
||||
// MM = 2DIGIT month ; 01-12
|
||||
// DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
||||
// HH = 2DIGIT hour ; 00-23
|
||||
// MM = 2DIGIT ; 00-59
|
||||
// SS = 2DIGIT ; 00-58, 00-60 based on leap second rules
|
||||
// T = Literal
|
||||
// Z = Literal
|
||||
//
|
||||
// Note: Nanoseconds are also suported in all formats
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc3339#section-5.6
|
||||
DateTimeFormatChecker struct{}
|
||||
|
||||
// DateFormatChecker verifies date formats
|
||||
//
|
||||
// Valid format:
|
||||
// Full Date: YYYY-MM-DD
|
||||
//
|
||||
// Where
|
||||
// YYYY = 4DIGIT year
|
||||
// MM = 2DIGIT month ; 01-12
|
||||
// DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year
|
||||
DateFormatChecker struct{}
|
||||
|
||||
// TimeFormatChecker verifies time formats
|
||||
//
|
||||
// Valid formats:
|
||||
// Partial Time: HH:MM:SS
|
||||
// Full Time: HH:MM:SSZ-07:00
|
||||
//
|
||||
// Where
|
||||
// HH = 2DIGIT hour ; 00-23
|
||||
// MM = 2DIGIT ; 00-59
|
||||
// SS = 2DIGIT ; 00-58, 00-60 based on leap second rules
|
||||
// T = Literal
|
||||
// Z = Literal
|
||||
TimeFormatChecker struct{}
|
||||
|
||||
// URIFormatChecker validates a URI with a valid Scheme per RFC3986
|
||||
URIFormatChecker struct{}
|
||||
|
||||
// URIReferenceFormatChecker validates a URI or relative-reference per RFC3986
|
||||
URIReferenceFormatChecker struct{}
|
||||
|
||||
// URITemplateFormatChecker validates a URI template per RFC6570
|
||||
URITemplateFormatChecker struct{}
|
||||
|
||||
// HostnameFormatChecker validates a hostname is in the correct format
|
||||
HostnameFormatChecker struct{}
|
||||
|
||||
// UUIDFormatChecker validates a UUID is in the correct format
|
||||
UUIDFormatChecker struct{}
|
||||
|
||||
// RegexFormatChecker validates a regex is in the correct format
|
||||
RegexFormatChecker struct{}
|
||||
|
||||
// JSONPointerFormatChecker validates a JSON Pointer per RFC6901
|
||||
JSONPointerFormatChecker struct{}
|
||||
|
||||
// RelativeJSONPointerFormatChecker validates a relative JSON Pointer is in the correct format
|
||||
RelativeJSONPointerFormatChecker struct{}
|
||||
)
|
||||
|
||||
var (
|
||||
// FormatCheckers holds the valid formatters, and is a public variable
|
||||
// so library users can add custom formatters
|
||||
FormatCheckers = FormatCheckerChain{
|
||||
formatters: map[string]FormatChecker{
|
||||
"date": DateFormatChecker{},
|
||||
"time": TimeFormatChecker{},
|
||||
"date-time": DateTimeFormatChecker{},
|
||||
"hostname": HostnameFormatChecker{},
|
||||
"email": EmailFormatChecker{},
|
||||
"idn-email": EmailFormatChecker{},
|
||||
"ipv4": IPV4FormatChecker{},
|
||||
"ipv6": IPV6FormatChecker{},
|
||||
"uri": URIFormatChecker{},
|
||||
"uri-reference": URIReferenceFormatChecker{},
|
||||
"iri": URIFormatChecker{},
|
||||
"iri-reference": URIReferenceFormatChecker{},
|
||||
"uri-template": URITemplateFormatChecker{},
|
||||
"uuid": UUIDFormatChecker{},
|
||||
"regex": RegexFormatChecker{},
|
||||
"json-pointer": JSONPointerFormatChecker{},
|
||||
"relative-json-pointer": RelativeJSONPointerFormatChecker{},
|
||||
},
|
||||
}
|
||||
|
||||
// Regex credit: https://www.socketloop.com/tutorials/golang-validate-hostname
|
||||
rxHostname = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`)
|
||||
|
||||
// Use a regex to make sure curly brackets are balanced properly after validating it as a AURI
|
||||
rxURITemplate = regexp.MustCompile("^([^{]*({[^}]*})?)*$")
|
||||
|
||||
rxUUID = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
|
||||
|
||||
rxJSONPointer = regexp.MustCompile("^(?:/(?:[^~/]|~0|~1)*)*$")
|
||||
|
||||
rxRelJSONPointer = regexp.MustCompile("^(?:0|[1-9][0-9]*)(?:#|(?:/(?:[^~/]|~0|~1)*)*)$")
|
||||
|
||||
lock = new(sync.RWMutex)
|
||||
)
|
||||
|
||||
// Add adds a FormatChecker to the FormatCheckerChain
|
||||
// The name used will be the value used for the format key in your json schema
|
||||
func (c *FormatCheckerChain) Add(name string, f FormatChecker) *FormatCheckerChain {
|
||||
lock.Lock()
|
||||
c.formatters[name] = f
|
||||
lock.Unlock()
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Remove deletes a FormatChecker from the FormatCheckerChain (if it exists)
|
||||
func (c *FormatCheckerChain) Remove(name string) *FormatCheckerChain {
|
||||
lock.Lock()
|
||||
delete(c.formatters, name)
|
||||
lock.Unlock()
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Has checks to see if the FormatCheckerChain holds a FormatChecker with the given name
|
||||
func (c *FormatCheckerChain) Has(name string) bool {
|
||||
lock.RLock()
|
||||
_, ok := c.formatters[name]
|
||||
lock.RUnlock()
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsFormat will check an input against a FormatChecker with the given name
|
||||
// to see if it is the correct format
|
||||
func (c *FormatCheckerChain) IsFormat(name string, input interface{}) bool {
|
||||
lock.RLock()
|
||||
f, ok := c.formatters[name]
|
||||
lock.RUnlock()
|
||||
|
||||
// If a format is unrecognized it should always pass validation
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return f.IsFormat(input)
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted e-mail address
|
||||
func (f EmailFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := mail.ParseAddress(asString)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted IPv4-address
|
||||
func (f IPV4FormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Credit: https://github.com/asaskevich/govalidator
|
||||
ip := net.ParseIP(asString)
|
||||
return ip != nil && strings.Contains(asString, ".")
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted IPv6=address
|
||||
func (f IPV6FormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Credit: https://github.com/asaskevich/govalidator
|
||||
ip := net.ParseIP(asString)
|
||||
return ip != nil && strings.Contains(asString, ":")
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted date/time per RFC3339 5.6
|
||||
func (f DateTimeFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
formats := []string{
|
||||
"15:04:05",
|
||||
"15:04:05Z07:00",
|
||||
"2006-01-02",
|
||||
time.RFC3339,
|
||||
time.RFC3339Nano,
|
||||
}
|
||||
|
||||
for _, format := range formats {
|
||||
if _, err := time.Parse(format, asString); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted date (YYYY-MM-DD)
|
||||
func (f DateFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_, err := time.Parse("2006-01-02", asString)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsFormat checks if input correctly formatted time (HH:MM:SS or HH:MM:SSZ-07:00)
|
||||
func (f TimeFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if _, err := time.Parse("15:04:05Z07:00", asString); err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
_, err := time.Parse("15:04:05", asString)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsFormat checks if input is correctly formatted URI with a valid Scheme per RFC3986
|
||||
func (f URIFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
u, err := url.Parse(asString)
|
||||
|
||||
if err != nil || u.Scheme == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return !strings.Contains(asString, `\`)
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted URI or relative-reference per RFC3986
|
||||
func (f URIReferenceFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := url.Parse(asString)
|
||||
return err == nil && !strings.Contains(asString, `\`)
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted URI template per RFC6570
|
||||
func (f URITemplateFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
u, err := url.Parse(asString)
|
||||
if err != nil || strings.Contains(asString, `\`) {
|
||||
return false
|
||||
}
|
||||
|
||||
return rxURITemplate.MatchString(u.Path)
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted hostname
|
||||
func (f HostnameFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return rxHostname.MatchString(asString) && len(asString) < 256
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted UUID
|
||||
func (f UUIDFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return rxUUID.MatchString(asString)
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted regular expression
|
||||
func (f RegexFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if asString == "" {
|
||||
return true
|
||||
}
|
||||
_, err := regexp.Compile(asString)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted JSON Pointer per RFC6901
|
||||
func (f JSONPointerFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return rxJSONPointer.MatchString(asString)
|
||||
}
|
||||
|
||||
// IsFormat checks if input is a correctly formatted relative JSON Pointer
|
||||
func (f RelativeJSONPointerFormatChecker) IsFormat(input interface{}) bool {
|
||||
asString, ok := input.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return rxRelJSONPointer.MatchString(asString)
|
||||
}
|
||||
13
vendor/github.com/xeipuuv/gojsonschema/glide.yaml
generated
vendored
13
vendor/github.com/xeipuuv/gojsonschema/glide.yaml
generated
vendored
@@ -1,13 +0,0 @@
|
||||
package: github.com/xeipuuv/gojsonschema
|
||||
license: Apache 2.0
|
||||
import:
|
||||
- package: github.com/xeipuuv/gojsonschema
|
||||
|
||||
- package: github.com/xeipuuv/gojsonpointer
|
||||
|
||||
- package: github.com/xeipuuv/gojsonreference
|
||||
|
||||
testImport:
|
||||
- package: github.com/stretchr/testify
|
||||
subpackages:
|
||||
- assert
|
||||
37
vendor/github.com/xeipuuv/gojsonschema/internalLog.go
generated
vendored
37
vendor/github.com/xeipuuv/gojsonschema/internalLog.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author xeipuuv
|
||||
// author-github https://github.com/xeipuuv
|
||||
// author-mail xeipuuv@gmail.com
|
||||
//
|
||||
// repository-name gojsonschema
|
||||
// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
|
||||
//
|
||||
// description Very simple log wrapper.
|
||||
// Used for debugging/testing purposes.
|
||||
//
|
||||
// created 01-01-2015
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
const internalLogEnabled = false
|
||||
|
||||
func internalLog(format string, v ...interface{}) {
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
73
vendor/github.com/xeipuuv/gojsonschema/jsonContext.go
generated
vendored
73
vendor/github.com/xeipuuv/gojsonschema/jsonContext.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
// Copyright 2013 MongoDB, Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author tolsen
|
||||
// author-github https://github.com/tolsen
|
||||
//
|
||||
// repository-name gojsonschema
|
||||
// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
|
||||
//
|
||||
// description Implements a persistent (immutable w/ shared structure) singly-linked list of strings for the purpose of storing a json context
|
||||
//
|
||||
// created 04-09-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import "bytes"
|
||||
|
||||
// JsonContext implements a persistent linked-list of strings
|
||||
type JsonContext struct {
|
||||
head string
|
||||
tail *JsonContext
|
||||
}
|
||||
|
||||
// NewJsonContext creates a new JsonContext
|
||||
func NewJsonContext(head string, tail *JsonContext) *JsonContext {
|
||||
return &JsonContext{head, tail}
|
||||
}
|
||||
|
||||
// String displays the context in reverse.
|
||||
// This plays well with the data structure's persistent nature with
|
||||
// Cons and a json document's tree structure.
|
||||
func (c *JsonContext) String(del ...string) string {
|
||||
byteArr := make([]byte, 0, c.stringLen())
|
||||
buf := bytes.NewBuffer(byteArr)
|
||||
c.writeStringToBuffer(buf, del)
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (c *JsonContext) stringLen() int {
|
||||
length := 0
|
||||
if c.tail != nil {
|
||||
length = c.tail.stringLen() + 1 // add 1 for "."
|
||||
}
|
||||
|
||||
length += len(c.head)
|
||||
return length
|
||||
}
|
||||
|
||||
func (c *JsonContext) writeStringToBuffer(buf *bytes.Buffer, del []string) {
|
||||
if c.tail != nil {
|
||||
c.tail.writeStringToBuffer(buf, del)
|
||||
|
||||
if len(del) > 0 {
|
||||
buf.WriteString(del[0])
|
||||
} else {
|
||||
buf.WriteString(".")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(c.head)
|
||||
}
|
||||
386
vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go
generated
vendored
386
vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go
generated
vendored
@@ -1,386 +0,0 @@
|
||||
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author xeipuuv
|
||||
// author-github https://github.com/xeipuuv
|
||||
// author-mail xeipuuv@gmail.com
|
||||
//
|
||||
// repository-name gojsonschema
|
||||
// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
|
||||
//
|
||||
// description Different strategies to load JSON files.
|
||||
// Includes References (file and HTTP), JSON strings and Go types.
|
||||
//
|
||||
// created 01-02-2015
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/xeipuuv/gojsonreference"
|
||||
)
|
||||
|
||||
var osFS = osFileSystem(os.Open)
|
||||
|
||||
// JSONLoader defines the JSON loader interface
|
||||
type JSONLoader interface {
|
||||
JsonSource() interface{}
|
||||
LoadJSON() (interface{}, error)
|
||||
JsonReference() (gojsonreference.JsonReference, error)
|
||||
LoaderFactory() JSONLoaderFactory
|
||||
}
|
||||
|
||||
// JSONLoaderFactory defines the JSON loader factory interface
|
||||
type JSONLoaderFactory interface {
|
||||
// New creates a new JSON loader for the given source
|
||||
New(source string) JSONLoader
|
||||
}
|
||||
|
||||
// DefaultJSONLoaderFactory is the default JSON loader factory
|
||||
type DefaultJSONLoaderFactory struct {
|
||||
}
|
||||
|
||||
// FileSystemJSONLoaderFactory is a JSON loader factory that uses http.FileSystem
|
||||
type FileSystemJSONLoaderFactory struct {
|
||||
fs http.FileSystem
|
||||
}
|
||||
|
||||
// New creates a new JSON loader for the given source
|
||||
func (d DefaultJSONLoaderFactory) New(source string) JSONLoader {
|
||||
return &jsonReferenceLoader{
|
||||
fs: osFS,
|
||||
source: source,
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a new JSON loader for the given source
|
||||
func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader {
|
||||
return &jsonReferenceLoader{
|
||||
fs: f.fs,
|
||||
source: source,
|
||||
}
|
||||
}
|
||||
|
||||
// osFileSystem is a functional wrapper for os.Open that implements http.FileSystem.
|
||||
type osFileSystem func(string) (*os.File, error)
|
||||
|
||||
// Opens a file with the given name
|
||||
func (o osFileSystem) Open(name string) (http.File, error) {
|
||||
return o(name)
|
||||
}
|
||||
|
||||
// JSON Reference loader
|
||||
// references are used to load JSONs from files and HTTP
|
||||
|
||||
type jsonReferenceLoader struct {
|
||||
fs http.FileSystem
|
||||
source string
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) JsonSource() interface{} {
|
||||
return l.source
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference(l.JsonSource().(string))
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &FileSystemJSONLoaderFactory{
|
||||
fs: l.fs,
|
||||
}
|
||||
}
|
||||
|
||||
// NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system.
|
||||
func NewReferenceLoader(source string) JSONLoader {
|
||||
return &jsonReferenceLoader{
|
||||
fs: osFS,
|
||||
source: source,
|
||||
}
|
||||
}
|
||||
|
||||
// NewReferenceLoaderFileSystem returns a JSON reference loader using the given source and file system.
|
||||
func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) JSONLoader {
|
||||
return &jsonReferenceLoader{
|
||||
fs: fs,
|
||||
source: source,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) {
|
||||
|
||||
var err error
|
||||
|
||||
reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
refToURL := reference
|
||||
refToURL.GetUrl().Fragment = ""
|
||||
|
||||
var document interface{}
|
||||
|
||||
if reference.HasFileScheme {
|
||||
|
||||
filename := strings.TrimPrefix(refToURL.String(), "file://")
|
||||
filename, err = url.QueryUnescape(filename)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
// on Windows, a file URL may have an extra leading slash, use slashes
|
||||
// instead of backslashes, and have spaces escaped
|
||||
filename = strings.TrimPrefix(filename, "/")
|
||||
filename = filepath.FromSlash(filename)
|
||||
}
|
||||
|
||||
document, err = l.loadFromFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
document, err = l.loadFromHTTP(refToURL.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return document, nil
|
||||
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) {
|
||||
|
||||
// returned cached versions for metaschemas for drafts 4, 6 and 7
|
||||
// for performance and allow for easier offline use
|
||||
if metaSchema := drafts.GetMetaSchema(address); metaSchema != "" {
|
||||
return decodeJSONUsingNumber(strings.NewReader(metaSchema))
|
||||
}
|
||||
|
||||
resp, err := http.Get(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// must return HTTP Status 200 OK
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status}))
|
||||
}
|
||||
|
||||
bodyBuff, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decodeJSONUsingNumber(bytes.NewReader(bodyBuff))
|
||||
}
|
||||
|
||||
func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) {
|
||||
f, err := l.fs.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
bodyBuff, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decodeJSONUsingNumber(bytes.NewReader(bodyBuff))
|
||||
|
||||
}
|
||||
|
||||
// JSON string loader
|
||||
|
||||
type jsonStringLoader struct {
|
||||
source string
|
||||
}
|
||||
|
||||
func (l *jsonStringLoader) JsonSource() interface{} {
|
||||
return l.source
|
||||
}
|
||||
|
||||
func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
|
||||
func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
|
||||
// NewStringLoader creates a new JSONLoader, taking a string as source
|
||||
func NewStringLoader(source string) JSONLoader {
|
||||
return &jsonStringLoader{source: source}
|
||||
}
|
||||
|
||||
func (l *jsonStringLoader) LoadJSON() (interface{}, error) {
|
||||
|
||||
return decodeJSONUsingNumber(strings.NewReader(l.JsonSource().(string)))
|
||||
|
||||
}
|
||||
|
||||
// JSON bytes loader
|
||||
|
||||
type jsonBytesLoader struct {
|
||||
source []byte
|
||||
}
|
||||
|
||||
func (l *jsonBytesLoader) JsonSource() interface{} {
|
||||
return l.source
|
||||
}
|
||||
|
||||
func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
|
||||
func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
|
||||
// NewBytesLoader creates a new JSONLoader, taking a `[]byte` as source
|
||||
func NewBytesLoader(source []byte) JSONLoader {
|
||||
return &jsonBytesLoader{source: source}
|
||||
}
|
||||
|
||||
func (l *jsonBytesLoader) LoadJSON() (interface{}, error) {
|
||||
return decodeJSONUsingNumber(bytes.NewReader(l.JsonSource().([]byte)))
|
||||
}
|
||||
|
||||
// JSON Go (types) loader
|
||||
// used to load JSONs from the code as maps, interface{}, structs ...
|
||||
|
||||
type jsonGoLoader struct {
|
||||
source interface{}
|
||||
}
|
||||
|
||||
func (l *jsonGoLoader) JsonSource() interface{} {
|
||||
return l.source
|
||||
}
|
||||
|
||||
func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
|
||||
func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
|
||||
// NewGoLoader creates a new JSONLoader from a given Go struct
|
||||
func NewGoLoader(source interface{}) JSONLoader {
|
||||
return &jsonGoLoader{source: source}
|
||||
}
|
||||
|
||||
func (l *jsonGoLoader) LoadJSON() (interface{}, error) {
|
||||
|
||||
// convert it to a compliant JSON first to avoid types "mismatches"
|
||||
|
||||
jsonBytes, err := json.Marshal(l.JsonSource())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decodeJSONUsingNumber(bytes.NewReader(jsonBytes))
|
||||
|
||||
}
|
||||
|
||||
type jsonIOLoader struct {
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewReaderLoader creates a new JSON loader using the provided io.Reader
|
||||
func NewReaderLoader(source io.Reader) (JSONLoader, io.Reader) {
|
||||
buf := &bytes.Buffer{}
|
||||
return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf)
|
||||
}
|
||||
|
||||
// NewWriterLoader creates a new JSON loader using the provided io.Writer
|
||||
func NewWriterLoader(source io.Writer) (JSONLoader, io.Writer) {
|
||||
buf := &bytes.Buffer{}
|
||||
return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf)
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) JsonSource() interface{} {
|
||||
return l.buf.String()
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) LoadJSON() (interface{}, error) {
|
||||
return decodeJSONUsingNumber(l.buf)
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
|
||||
func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
|
||||
// JSON raw loader
|
||||
// In case the JSON is already marshalled to interface{} use this loader
|
||||
// This is used for testing as otherwise there is no guarantee the JSON is marshalled
|
||||
// "properly" by using https://golang.org/pkg/encoding/json/#Decoder.UseNumber
|
||||
type jsonRawLoader struct {
|
||||
source interface{}
|
||||
}
|
||||
|
||||
// NewRawLoader creates a new JSON raw loader for the given source
|
||||
func NewRawLoader(source interface{}) JSONLoader {
|
||||
return &jsonRawLoader{source: source}
|
||||
}
|
||||
func (l *jsonRawLoader) JsonSource() interface{} {
|
||||
return l.source
|
||||
}
|
||||
func (l *jsonRawLoader) LoadJSON() (interface{}, error) {
|
||||
return l.source, nil
|
||||
}
|
||||
func (l *jsonRawLoader) JsonReference() (gojsonreference.JsonReference, error) {
|
||||
return gojsonreference.NewJsonReference("#")
|
||||
}
|
||||
func (l *jsonRawLoader) LoaderFactory() JSONLoaderFactory {
|
||||
return &DefaultJSONLoaderFactory{}
|
||||
}
|
||||
|
||||
func decodeJSONUsingNumber(r io.Reader) (interface{}, error) {
|
||||
|
||||
var document interface{}
|
||||
|
||||
decoder := json.NewDecoder(r)
|
||||
decoder.UseNumber()
|
||||
|
||||
err := decoder.Decode(&document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return document, nil
|
||||
|
||||
}
|
||||
472
vendor/github.com/xeipuuv/gojsonschema/locales.go
generated
vendored
472
vendor/github.com/xeipuuv/gojsonschema/locales.go
generated
vendored
@@ -1,472 +0,0 @@
|
||||
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author xeipuuv
|
||||
// author-github https://github.com/xeipuuv
|
||||
// author-mail xeipuuv@gmail.com
|
||||
//
|
||||
// repository-name gojsonschema
|
||||
// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
|
||||
//
|
||||
// description Contains const string and messages.
|
||||
//
|
||||
// created 01-01-2015
|
||||
|
||||
package gojsonschema
|
||||
|
||||
type (
|
||||
// locale is an interface for defining custom error strings
|
||||
locale interface {
|
||||
|
||||
// False returns a format-string for "false" schema validation errors
|
||||
False() string
|
||||
|
||||
// Required returns a format-string for "required" schema validation errors
|
||||
Required() string
|
||||
|
||||
// InvalidType returns a format-string for "invalid type" schema validation errors
|
||||
InvalidType() string
|
||||
|
||||
// NumberAnyOf returns a format-string for "anyOf" schema validation errors
|
||||
NumberAnyOf() string
|
||||
|
||||
// NumberOneOf returns a format-string for "oneOf" schema validation errors
|
||||
NumberOneOf() string
|
||||
|
||||
// NumberAllOf returns a format-string for "allOf" schema validation errors
|
||||
NumberAllOf() string
|
||||
|
||||
// NumberNot returns a format-string to format a NumberNotError
|
||||
NumberNot() string
|
||||
|
||||
// MissingDependency returns a format-string for "missing dependency" schema validation errors
|
||||
MissingDependency() string
|
||||
|
||||
// Internal returns a format-string for internal errors
|
||||
Internal() string
|
||||
|
||||
// Const returns a format-string to format a ConstError
|
||||
Const() string
|
||||
|
||||
// Enum returns a format-string to format an EnumError
|
||||
Enum() string
|
||||
|
||||
// ArrayNotEnoughItems returns a format-string to format an error for arrays having not enough items to match positional list of schema
|
||||
ArrayNotEnoughItems() string
|
||||
|
||||
// ArrayNoAdditionalItems returns a format-string to format an ArrayNoAdditionalItemsError
|
||||
ArrayNoAdditionalItems() string
|
||||
|
||||
// ArrayMinItems returns a format-string to format an ArrayMinItemsError
|
||||
ArrayMinItems() string
|
||||
|
||||
// ArrayMaxItems returns a format-string to format an ArrayMaxItemsError
|
||||
ArrayMaxItems() string
|
||||
|
||||
// Unique returns a format-string to format an ItemsMustBeUniqueError
|
||||
Unique() string
|
||||
|
||||
// ArrayContains returns a format-string to format an ArrayContainsError
|
||||
ArrayContains() string
|
||||
|
||||
// ArrayMinProperties returns a format-string to format an ArrayMinPropertiesError
|
||||
ArrayMinProperties() string
|
||||
|
||||
// ArrayMaxProperties returns a format-string to format an ArrayMaxPropertiesError
|
||||
ArrayMaxProperties() string
|
||||
|
||||
// AdditionalPropertyNotAllowed returns a format-string to format an AdditionalPropertyNotAllowedError
|
||||
AdditionalPropertyNotAllowed() string
|
||||
|
||||
// InvalidPropertyPattern returns a format-string to format an InvalidPropertyPatternError
|
||||
InvalidPropertyPattern() string
|
||||
|
||||
// InvalidPropertyName returns a format-string to format an InvalidPropertyNameError
|
||||
InvalidPropertyName() string
|
||||
|
||||
// StringGTE returns a format-string to format an StringLengthGTEError
|
||||
StringGTE() string
|
||||
|
||||
// StringLTE returns a format-string to format an StringLengthLTEError
|
||||
StringLTE() string
|
||||
|
||||
// DoesNotMatchPattern returns a format-string to format an DoesNotMatchPatternError
|
||||
DoesNotMatchPattern() string
|
||||
|
||||
// DoesNotMatchFormat returns a format-string to format an DoesNotMatchFormatError
|
||||
DoesNotMatchFormat() string
|
||||
|
||||
// MultipleOf returns a format-string to format an MultipleOfError
|
||||
MultipleOf() string
|
||||
|
||||
// NumberGTE returns a format-string to format an NumberGTEError
|
||||
NumberGTE() string
|
||||
|
||||
// NumberGT returns a format-string to format an NumberGTError
|
||||
NumberGT() string
|
||||
|
||||
// NumberLTE returns a format-string to format an NumberLTEError
|
||||
NumberLTE() string
|
||||
|
||||
// NumberLT returns a format-string to format an NumberLTError
|
||||
NumberLT() string
|
||||
|
||||
// Schema validations
|
||||
|
||||
// RegexPattern returns a format-string to format a regex-pattern error
|
||||
RegexPattern() string
|
||||
|
||||
// GreaterThanZero returns a format-string to format an error where a number must be greater than zero
|
||||
GreaterThanZero() string
|
||||
|
||||
// MustBeOfA returns a format-string to format an error where a value is of the wrong type
|
||||
MustBeOfA() string
|
||||
|
||||
// MustBeOfAn returns a format-string to format an error where a value is of the wrong type
|
||||
MustBeOfAn() string
|
||||
|
||||
// CannotBeUsedWithout returns a format-string to format a "cannot be used without" error
|
||||
CannotBeUsedWithout() string
|
||||
|
||||
// CannotBeGT returns a format-string to format an error where a value are greater than allowed
|
||||
CannotBeGT() string
|
||||
|
||||
// MustBeOfType returns a format-string to format an error where a value does not match the required type
|
||||
MustBeOfType() string
|
||||
|
||||
// MustBeValidRegex returns a format-string to format an error where a regex is invalid
|
||||
MustBeValidRegex() string
|
||||
|
||||
// MustBeValidFormat returns a format-string to format an error where a value does not match the expected format
|
||||
MustBeValidFormat() string
|
||||
|
||||
// MustBeGTEZero returns a format-string to format an error where a value must be greater or equal than 0
|
||||
MustBeGTEZero() string
|
||||
|
||||
// KeyCannotBeGreaterThan returns a format-string to format an error where a key is greater than the maximum allowed
|
||||
KeyCannotBeGreaterThan() string
|
||||
|
||||
// KeyItemsMustBeOfType returns a format-string to format an error where a key is of the wrong type
|
||||
KeyItemsMustBeOfType() string
|
||||
|
||||
// KeyItemsMustBeUnique returns a format-string to format an error where keys are not unique
|
||||
KeyItemsMustBeUnique() string
|
||||
|
||||
// ReferenceMustBeCanonical returns a format-string to format a "reference must be canonical" error
|
||||
ReferenceMustBeCanonical() string
|
||||
|
||||
// NotAValidType returns a format-string to format an invalid type error
|
||||
NotAValidType() string
|
||||
|
||||
// Duplicated returns a format-string to format an error where types are duplicated
|
||||
Duplicated() string
|
||||
|
||||
// HttpBadStatus returns a format-string for errors when loading a schema using HTTP
|
||||
HttpBadStatus() string
|
||||
|
||||
// ParseError returns a format-string for JSON parsing errors
|
||||
ParseError() string
|
||||
|
||||
// ConditionThen returns a format-string for ConditionThenError errors
|
||||
ConditionThen() string
|
||||
|
||||
// ConditionElse returns a format-string for ConditionElseError errors
|
||||
ConditionElse() string
|
||||
|
||||
// ErrorFormat returns a format string for errors
|
||||
ErrorFormat() string
|
||||
}
|
||||
|
||||
// DefaultLocale is the default locale for this package
|
||||
DefaultLocale struct{}
|
||||
)
|
||||
|
||||
// False returns a format-string for "false" schema validation errors
|
||||
func (l DefaultLocale) False() string {
|
||||
return "False always fails validation"
|
||||
}
|
||||
|
||||
// Required returns a format-string for "required" schema validation errors
|
||||
func (l DefaultLocale) Required() string {
|
||||
return `{{.property}} is required`
|
||||
}
|
||||
|
||||
// InvalidType returns a format-string for "invalid type" schema validation errors
|
||||
func (l DefaultLocale) InvalidType() string {
|
||||
return `Invalid type. Expected: {{.expected}}, given: {{.given}}`
|
||||
}
|
||||
|
||||
// NumberAnyOf returns a format-string for "anyOf" schema validation errors
|
||||
func (l DefaultLocale) NumberAnyOf() string {
|
||||
return `Must validate at least one schema (anyOf)`
|
||||
}
|
||||
|
||||
// NumberOneOf returns a format-string for "oneOf" schema validation errors
|
||||
func (l DefaultLocale) NumberOneOf() string {
|
||||
return `Must validate one and only one schema (oneOf)`
|
||||
}
|
||||
|
||||
// NumberAllOf returns a format-string for "allOf" schema validation errors
|
||||
func (l DefaultLocale) NumberAllOf() string {
|
||||
return `Must validate all the schemas (allOf)`
|
||||
}
|
||||
|
||||
// NumberNot returns a format-string to format a NumberNotError
|
||||
func (l DefaultLocale) NumberNot() string {
|
||||
return `Must not validate the schema (not)`
|
||||
}
|
||||
|
||||
// MissingDependency returns a format-string for "missing dependency" schema validation errors
|
||||
func (l DefaultLocale) MissingDependency() string {
|
||||
return `Has a dependency on {{.dependency}}`
|
||||
}
|
||||
|
||||
// Internal returns a format-string for internal errors
|
||||
func (l DefaultLocale) Internal() string {
|
||||
return `Internal Error {{.error}}`
|
||||
}
|
||||
|
||||
// Const returns a format-string to format a ConstError
|
||||
func (l DefaultLocale) Const() string {
|
||||
return `{{.field}} does not match: {{.allowed}}`
|
||||
}
|
||||
|
||||
// Enum returns a format-string to format an EnumError
|
||||
func (l DefaultLocale) Enum() string {
|
||||
return `{{.field}} must be one of the following: {{.allowed}}`
|
||||
}
|
||||
|
||||
// ArrayNoAdditionalItems returns a format-string to format an ArrayNoAdditionalItemsError
|
||||
func (l DefaultLocale) ArrayNoAdditionalItems() string {
|
||||
return `No additional items allowed on array`
|
||||
}
|
||||
|
||||
// ArrayNotEnoughItems returns a format-string to format an error for arrays having not enough items to match positional list of schema
|
||||
func (l DefaultLocale) ArrayNotEnoughItems() string {
|
||||
return `Not enough items on array to match positional list of schema`
|
||||
}
|
||||
|
||||
// ArrayMinItems returns a format-string to format an ArrayMinItemsError
|
||||
func (l DefaultLocale) ArrayMinItems() string {
|
||||
return `Array must have at least {{.min}} items`
|
||||
}
|
||||
|
||||
// ArrayMaxItems returns a format-string to format an ArrayMaxItemsError
|
||||
func (l DefaultLocale) ArrayMaxItems() string {
|
||||
return `Array must have at most {{.max}} items`
|
||||
}
|
||||
|
||||
// Unique returns a format-string to format an ItemsMustBeUniqueError
|
||||
func (l DefaultLocale) Unique() string {
|
||||
return `{{.type}} items[{{.i}},{{.j}}] must be unique`
|
||||
}
|
||||
|
||||
// ArrayContains returns a format-string to format an ArrayContainsError
|
||||
func (l DefaultLocale) ArrayContains() string {
|
||||
return `At least one of the items must match`
|
||||
}
|
||||
|
||||
// ArrayMinProperties returns a format-string to format an ArrayMinPropertiesError
|
||||
func (l DefaultLocale) ArrayMinProperties() string {
|
||||
return `Must have at least {{.min}} properties`
|
||||
}
|
||||
|
||||
// ArrayMaxProperties returns a format-string to format an ArrayMaxPropertiesError
|
||||
func (l DefaultLocale) ArrayMaxProperties() string {
|
||||
return `Must have at most {{.max}} properties`
|
||||
}
|
||||
|
||||
// AdditionalPropertyNotAllowed returns a format-string to format an AdditionalPropertyNotAllowedError
|
||||
func (l DefaultLocale) AdditionalPropertyNotAllowed() string {
|
||||
return `Additional property {{.property}} is not allowed`
|
||||
}
|
||||
|
||||
// InvalidPropertyPattern returns a format-string to format an InvalidPropertyPatternError
|
||||
func (l DefaultLocale) InvalidPropertyPattern() string {
|
||||
return `Property "{{.property}}" does not match pattern {{.pattern}}`
|
||||
}
|
||||
|
||||
// InvalidPropertyName returns a format-string to format an InvalidPropertyNameError
|
||||
func (l DefaultLocale) InvalidPropertyName() string {
|
||||
return `Property name of "{{.property}}" does not match`
|
||||
}
|
||||
|
||||
// StringGTE returns a format-string to format an StringLengthGTEError
|
||||
func (l DefaultLocale) StringGTE() string {
|
||||
return `String length must be greater than or equal to {{.min}}`
|
||||
}
|
||||
|
||||
// StringLTE returns a format-string to format an StringLengthLTEError
|
||||
func (l DefaultLocale) StringLTE() string {
|
||||
return `String length must be less than or equal to {{.max}}`
|
||||
}
|
||||
|
||||
// DoesNotMatchPattern returns a format-string to format an DoesNotMatchPatternError
|
||||
func (l DefaultLocale) DoesNotMatchPattern() string {
|
||||
return `Does not match pattern '{{.pattern}}'`
|
||||
}
|
||||
|
||||
// DoesNotMatchFormat returns a format-string to format an DoesNotMatchFormatError
|
||||
func (l DefaultLocale) DoesNotMatchFormat() string {
|
||||
return `Does not match format '{{.format}}'`
|
||||
}
|
||||
|
||||
// MultipleOf returns a format-string to format an MultipleOfError
|
||||
func (l DefaultLocale) MultipleOf() string {
|
||||
return `Must be a multiple of {{.multiple}}`
|
||||
}
|
||||
|
||||
// NumberGTE returns the format string to format a NumberGTEError
|
||||
func (l DefaultLocale) NumberGTE() string {
|
||||
return `Must be greater than or equal to {{.min}}`
|
||||
}
|
||||
|
||||
// NumberGT returns the format string to format a NumberGTError
|
||||
func (l DefaultLocale) NumberGT() string {
|
||||
return `Must be greater than {{.min}}`
|
||||
}
|
||||
|
||||
// NumberLTE returns the format string to format a NumberLTEError
|
||||
func (l DefaultLocale) NumberLTE() string {
|
||||
return `Must be less than or equal to {{.max}}`
|
||||
}
|
||||
|
||||
// NumberLT returns the format string to format a NumberLTError
|
||||
func (l DefaultLocale) NumberLT() string {
|
||||
return `Must be less than {{.max}}`
|
||||
}
|
||||
|
||||
// Schema validators
|
||||
|
||||
// RegexPattern returns a format-string to format a regex-pattern error
|
||||
func (l DefaultLocale) RegexPattern() string {
|
||||
return `Invalid regex pattern '{{.pattern}}'`
|
||||
}
|
||||
|
||||
// GreaterThanZero returns a format-string to format an error where a number must be greater than zero
|
||||
func (l DefaultLocale) GreaterThanZero() string {
|
||||
return `{{.number}} must be strictly greater than 0`
|
||||
}
|
||||
|
||||
// MustBeOfA returns a format-string to format an error where a value is of the wrong type
|
||||
func (l DefaultLocale) MustBeOfA() string {
|
||||
return `{{.x}} must be of a {{.y}}`
|
||||
}
|
||||
|
||||
// MustBeOfAn returns a format-string to format an error where a value is of the wrong type
|
||||
func (l DefaultLocale) MustBeOfAn() string {
|
||||
return `{{.x}} must be of an {{.y}}`
|
||||
}
|
||||
|
||||
// CannotBeUsedWithout returns a format-string to format a "cannot be used without" error
|
||||
func (l DefaultLocale) CannotBeUsedWithout() string {
|
||||
return `{{.x}} cannot be used without {{.y}}`
|
||||
}
|
||||
|
||||
// CannotBeGT returns a format-string to format an error where a value are greater than allowed
|
||||
func (l DefaultLocale) CannotBeGT() string {
|
||||
return `{{.x}} cannot be greater than {{.y}}`
|
||||
}
|
||||
|
||||
// MustBeOfType returns a format-string to format an error where a value does not match the required type
|
||||
func (l DefaultLocale) MustBeOfType() string {
|
||||
return `{{.key}} must be of type {{.type}}`
|
||||
}
|
||||
|
||||
// MustBeValidRegex returns a format-string to format an error where a regex is invalid
|
||||
func (l DefaultLocale) MustBeValidRegex() string {
|
||||
return `{{.key}} must be a valid regex`
|
||||
}
|
||||
|
||||
// MustBeValidFormat returns a format-string to format an error where a value does not match the expected format
|
||||
func (l DefaultLocale) MustBeValidFormat() string {
|
||||
return `{{.key}} must be a valid format {{.given}}`
|
||||
}
|
||||
|
||||
// MustBeGTEZero returns a format-string to format an error where a value must be greater or equal than 0
|
||||
func (l DefaultLocale) MustBeGTEZero() string {
|
||||
return `{{.key}} must be greater than or equal to 0`
|
||||
}
|
||||
|
||||
// KeyCannotBeGreaterThan returns a format-string to format an error where a value is greater than the maximum allowed
|
||||
func (l DefaultLocale) KeyCannotBeGreaterThan() string {
|
||||
return `{{.key}} cannot be greater than {{.y}}`
|
||||
}
|
||||
|
||||
// KeyItemsMustBeOfType returns a format-string to format an error where a key is of the wrong type
|
||||
func (l DefaultLocale) KeyItemsMustBeOfType() string {
|
||||
return `{{.key}} items must be {{.type}}`
|
||||
}
|
||||
|
||||
// KeyItemsMustBeUnique returns a format-string to format an error where keys are not unique
|
||||
func (l DefaultLocale) KeyItemsMustBeUnique() string {
|
||||
return `{{.key}} items must be unique`
|
||||
}
|
||||
|
||||
// ReferenceMustBeCanonical returns a format-string to format a "reference must be canonical" error
|
||||
func (l DefaultLocale) ReferenceMustBeCanonical() string {
|
||||
return `Reference {{.reference}} must be canonical`
|
||||
}
|
||||
|
||||
// NotAValidType returns a format-string to format an invalid type error
|
||||
func (l DefaultLocale) NotAValidType() string {
|
||||
return `has a primitive type that is NOT VALID -- given: {{.given}} Expected valid values are:{{.expected}}`
|
||||
}
|
||||
|
||||
// Duplicated returns a format-string to format an error where types are duplicated
|
||||
func (l DefaultLocale) Duplicated() string {
|
||||
return `{{.type}} type is duplicated`
|
||||
}
|
||||
|
||||
// HttpBadStatus returns a format-string for errors when loading a schema using HTTP
|
||||
func (l DefaultLocale) HttpBadStatus() string {
|
||||
return `Could not read schema from HTTP, response status is {{.status}}`
|
||||
}
|
||||
|
||||
// ErrorFormat returns a format string for errors
|
||||
// Replacement options: field, description, context, value
|
||||
func (l DefaultLocale) ErrorFormat() string {
|
||||
return `{{.field}}: {{.description}}`
|
||||
}
|
||||
|
||||
// ParseError returns a format-string for JSON parsing errors
|
||||
func (l DefaultLocale) ParseError() string {
|
||||
return `Expected: {{.expected}}, given: Invalid JSON`
|
||||
}
|
||||
|
||||
// ConditionThen returns a format-string for ConditionThenError errors
|
||||
// If/Else
|
||||
func (l DefaultLocale) ConditionThen() string {
|
||||
return `Must validate "then" as "if" was valid`
|
||||
}
|
||||
|
||||
// ConditionElse returns a format-string for ConditionElseError errors
|
||||
func (l DefaultLocale) ConditionElse() string {
|
||||
return `Must validate "else" as "if" was not valid`
|
||||
}
|
||||
|
||||
// constants
|
||||
const (
|
||||
STRING_NUMBER = "number"
|
||||
STRING_ARRAY_OF_STRINGS = "array of strings"
|
||||
STRING_ARRAY_OF_SCHEMAS = "array of schemas"
|
||||
STRING_SCHEMA = "valid schema"
|
||||
STRING_SCHEMA_OR_ARRAY_OF_STRINGS = "schema or array of strings"
|
||||
STRING_PROPERTIES = "properties"
|
||||
STRING_DEPENDENCY = "dependency"
|
||||
STRING_PROPERTY = "property"
|
||||
STRING_UNDEFINED = "undefined"
|
||||
STRING_CONTEXT_ROOT = "(root)"
|
||||
STRING_ROOT_SCHEMA_PROPERTY = "(root)"
|
||||
)
|
||||
220
vendor/github.com/xeipuuv/gojsonschema/result.go
generated
vendored
220
vendor/github.com/xeipuuv/gojsonschema/result.go
generated
vendored
@@ -1,220 +0,0 @@
|
||||
// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
|
||||
//
|
||||
// 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.
|
||||
|
||||
// author xeipuuv
|
||||
// author-github https://github.com/xeipuuv
|
||||
// author-mail xeipuuv@gmail.com
|
||||
//
|
||||
// repository-name gojsonschema
|
||||
// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language.
|
||||
//
|
||||
// description Result and ResultError implementations.
|
||||
//
|
||||
// created 01-01-2015
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// ErrorDetails is a map of details specific to each error.
|
||||
// While the values will vary, every error will contain a "field" value
|
||||
ErrorDetails map[string]interface{}
|
||||
|
||||
// ResultError is the interface that library errors must implement
|
||||
ResultError interface {
|
||||
// Field returns the field name without the root context
|
||||
// i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
|
||||
Field() string
|
||||
// SetType sets the error-type
|
||||
SetType(string)
|
||||
// Type returns the error-type
|
||||
Type() string
|
||||
// SetContext sets the JSON-context for the error
|
||||
SetContext(*JsonContext)
|
||||
// Context returns the JSON-context of the error
|
||||
Context() *JsonContext
|
||||
// SetDescription sets a description for the error
|
||||
SetDescription(string)
|
||||
// Description returns the description of the error
|
||||
Description() string
|
||||
// SetDescriptionFormat sets the format for the description in the default text/template format
|
||||
SetDescriptionFormat(string)
|
||||
// DescriptionFormat returns the format for the description in the default text/template format
|
||||
DescriptionFormat() string
|
||||
// SetValue sets the value related to the error
|
||||
SetValue(interface{})
|
||||
// Value returns the value related to the error
|
||||
Value() interface{}
|
||||
// SetDetails sets the details specific to the error
|
||||
SetDetails(ErrorDetails)
|
||||
// Details returns details about the error
|
||||
Details() ErrorDetails
|
||||
// String returns a string representation of the error
|
||||
String() string
|
||||
}
|
||||
|
||||
// ResultErrorFields holds the fields for each ResultError implementation.
|
||||
// ResultErrorFields implements the ResultError interface, so custom errors
|
||||
// can be defined by just embedding this type
|
||||
ResultErrorFields struct {
|
||||
errorType string // A string with the type of error (i.e. invalid_type)
|
||||
context *JsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ...
|
||||
description string // A human readable error message
|
||||
descriptionFormat string // A format for human readable error message
|
||||
value interface{} // Value given by the JSON file that is the source of the error
|
||||
details ErrorDetails
|
||||
}
|
||||
|
||||
// Result holds the result of a validation
|
||||
Result struct {
|
||||
errors []ResultError
|
||||
// Scores how well the validation matched. Useful in generating
|
||||
// better error messages for anyOf and oneOf.
|
||||
score int
|
||||
}
|
||||
)
|
||||
|
||||
// Field returns the field name without the root context
|
||||
// i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
|
||||
func (v *ResultErrorFields) Field() string {
|
||||
return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".")
|
||||
}
|
||||
|
||||
// SetType sets the error-type
|
||||
func (v *ResultErrorFields) SetType(errorType string) {
|
||||
v.errorType = errorType
|
||||
}
|
||||
|
||||
// Type returns the error-type
|
||||
func (v *ResultErrorFields) Type() string {
|
||||
return v.errorType
|
||||
}
|
||||
|
||||
// SetContext sets the JSON-context for the error
|
||||
func (v *ResultErrorFields) SetContext(context *JsonContext) {
|
||||
v.context = context
|
||||
}
|
||||
|
||||
// Context returns the JSON-context of the error
|
||||
func (v *ResultErrorFields) Context() *JsonContext {
|
||||
return v.context
|
||||
}
|
||||
|
||||
// SetDescription sets a description for the error
|
||||
func (v *ResultErrorFields) SetDescription(description string) {
|
||||
v.description = description
|
||||
}
|
||||
|
||||
// Description returns the description of the error
|
||||
func (v *ResultErrorFields) Description() string {
|
||||
return v.description
|
||||
}
|
||||
|
||||
// SetDescriptionFormat sets the format for the description in the default text/template format
|
||||
func (v *ResultErrorFields) SetDescriptionFormat(descriptionFormat string) {
|
||||
v.descriptionFormat = descriptionFormat
|
||||
}
|
||||
|
||||
// DescriptionFormat returns the format for the description in the default text/template format
|
||||
func (v *ResultErrorFields) DescriptionFormat() string {
|
||||
return v.descriptionFormat
|
||||
}
|
||||
|
||||
// SetValue sets the value related to the error
|
||||
func (v *ResultErrorFields) SetValue(value interface{}) {
|
||||
v.value = value
|
||||
}
|
||||
|
||||
// Value returns the value related to the error
|
||||
func (v *ResultErrorFields) Value() interface{} {
|
||||
return v.value
|
||||
}
|
||||
|
||||
// SetDetails sets the details specific to the error
|
||||
func (v *ResultErrorFields) SetDetails(details ErrorDetails) {
|
||||
v.details = details
|
||||
}
|
||||
|
||||
// Details returns details about the error
|
||||
func (v *ResultErrorFields) Details() ErrorDetails {
|
||||
return v.details
|
||||
}
|
||||
|
||||
// String returns a string representation of the error
|
||||
func (v ResultErrorFields) String() string {
|
||||
// as a fallback, the value is displayed go style
|
||||
valueString := fmt.Sprintf("%v", v.value)
|
||||
|
||||
// marshal the go value value to json
|
||||
if v.value == nil {
|
||||
valueString = TYPE_NULL
|
||||
} else {
|
||||
if vs, err := marshalToJSONString(v.value); err == nil {
|
||||
if vs == nil {
|
||||
valueString = TYPE_NULL
|
||||
} else {
|
||||
valueString = *vs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{
|
||||
"context": v.context.String(),
|
||||
"description": v.description,
|
||||
"value": valueString,
|
||||
"field": v.Field(),
|
||||
})
|
||||
}
|
||||
|
||||
// Valid indicates if no errors were found
|
||||
func (v *Result) Valid() bool {
|
||||
return len(v.errors) == 0
|
||||
}
|
||||
|
||||
// Errors returns the errors that were found
|
||||
func (v *Result) Errors() []ResultError {
|
||||
return v.errors
|
||||
}
|
||||
|
||||
// AddError appends a fully filled error to the error set
|
||||
// SetDescription() will be called with the result of the parsed err.DescriptionFormat()
|
||||
func (v *Result) AddError(err ResultError, details ErrorDetails) {
|
||||
if _, exists := details["context"]; !exists && err.Context() != nil {
|
||||
details["context"] = err.Context().String()
|
||||
}
|
||||
|
||||
err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details))
|
||||
|
||||
v.errors = append(v.errors, err)
|
||||
}
|
||||
|
||||
func (v *Result) addInternalError(err ResultError, context *JsonContext, value interface{}, details ErrorDetails) {
|
||||
newError(err, context, value, Locale, details)
|
||||
v.errors = append(v.errors, err)
|
||||
v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function
|
||||
}
|
||||
|
||||
// Used to copy errors from a sub-schema to the main one
|
||||
func (v *Result) mergeErrors(otherResult *Result) {
|
||||
v.errors = append(v.errors, otherResult.Errors()...)
|
||||
v.score += otherResult.score
|
||||
}
|
||||
|
||||
func (v *Result) incrementScore() {
|
||||
v.score++
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user