CDI: update go.mod and vendor deps
Signed-off-by: Ed Bartosh <eduard.bartosh@intel.com>
This commit is contained in:
parent
ff5c55847a
commit
825c1c58a9
8
go.mod
8
go.mod
@ -6,6 +6,7 @@ require (
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8
|
||||
github.com/Microsoft/go-winio v0.5.1
|
||||
github.com/Microsoft/hcsshim v0.9.2
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1
|
||||
github.com/containerd/aufs v1.0.0
|
||||
github.com/containerd/btrfs v1.0.0
|
||||
github.com/containerd/cgroups v1.0.3
|
||||
@ -101,6 +102,7 @@ require (
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
@ -110,7 +112,11 @@ require (
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 // indirect
|
||||
@ -128,7 +134,7 @@ require (
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
// When updating replace rules, make sure to also update the rules in integration/client/go.mod and api/go.mod
|
||||
|
11
go.sum
11
go.sum
@ -160,6 +160,8 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1 h1:AvASKHHm6w3qMU49iPYyp8GhwbacvqjfGHUZEgvA/mQ=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1/go.mod h1:E1zcucIkq9P3eyNmY+68dBQsTcsXJh9cgRo2IVNScKQ=
|
||||
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
|
||||
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
|
||||
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
|
||||
@ -709,6 +711,8 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.m
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e h1:2Tg49TNXSTIsX8AAtmo1aQ1IbfnoUFzkOp7p2iWygtc=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
@ -834,6 +838,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
|
||||
@ -857,9 +862,12 @@ github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvV
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
@ -1435,5 +1443,6 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
@ -21,7 +21,9 @@ require (
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cilium/ebpf v0.7.0 // indirect
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1 // indirect
|
||||
github.com/containerd/console v1.0.3 // indirect
|
||||
github.com/containerd/continuity v0.2.2 // indirect
|
||||
github.com/containerd/fifo v1.0.0 // indirect
|
||||
@ -34,16 +36,23 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/klauspost/compress v1.11.13 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/opencontainers/runc v1.1.1 // indirect
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e // indirect
|
||||
github.com/opencontainers/selinux v1.10.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
@ -51,7 +60,9 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.43.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
|
@ -90,6 +90,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
@ -122,6 +124,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1 h1:AvASKHHm6w3qMU49iPYyp8GhwbacvqjfGHUZEgvA/mQ=
|
||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1/go.mod h1:E1zcucIkq9P3eyNmY+68dBQsTcsXJh9cgRo2IVNScKQ=
|
||||
github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
|
||||
github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
|
||||
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
|
||||
@ -359,11 +363,13 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
@ -410,6 +416,7 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
@ -423,6 +430,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@ -446,6 +454,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
@ -495,6 +504,7 @@ github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1 h1:9iFHD5Kt9hkOfeawBNiEeEaV7bmC4/Z5wJp8E9BptMs=
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1/go.mod h1:K/JAU0m27RFhDRX4PcFdIKntROP6y5Ed6O91aZYDQfs=
|
||||
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runc v1.1.1 h1:PJ9DSs2sVwE0iVr++pAHE6QkS9tzcVWozlPifdwMgrU=
|
||||
github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
|
||||
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
@ -503,7 +513,10 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.m
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e h1:2Tg49TNXSTIsX8AAtmo1aQ1IbfnoUFzkOp7p2iWygtc=
|
||||
github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU=
|
||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
@ -516,6 +529,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
@ -575,17 +589,22 @@ github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -599,6 +618,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@ -612,8 +632,11 @@ github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:tw
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
@ -676,6 +699,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@ -778,6 +802,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -987,6 +1012,7 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@ -1045,6 +1071,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
@ -1105,3 +1132,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
201
vendor/github.com/container-orchestrated-devices/container-device-interface/LICENSE
generated
vendored
Normal file
201
vendor/github.com/container-orchestrated-devices/container-device-interface/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
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.
|
139
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/annotations.go
generated
vendored
Normal file
139
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/annotations.go
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright © 2021-2022 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// AnnotationPrefix is the prefix for CDI container annotation keys.
|
||||
AnnotationPrefix = "cdi.k8s.io/"
|
||||
)
|
||||
|
||||
// UpdateAnnotations updates annotations with a plugin-specific CDI device
|
||||
// injection request for the given devices. Upon any error a non-nil error
|
||||
// is returned and annotations are left intact. By convention plugin should
|
||||
// be in the format of "vendor.device-type".
|
||||
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")
|
||||
}
|
||||
if _, ok := annotations[key]; ok {
|
||||
return annotations, errors.Errorf("CDI annotation failed, key %q used", key)
|
||||
}
|
||||
value, err := AnnotationValue(devices)
|
||||
if err != nil {
|
||||
return annotations, errors.Wrap(err, "CDI annotation failed")
|
||||
}
|
||||
|
||||
if annotations == nil {
|
||||
annotations = make(map[string]string)
|
||||
}
|
||||
annotations[key] = value
|
||||
|
||||
return annotations, nil
|
||||
}
|
||||
|
||||
// ParseAnnotations parses annotations for CDI device injection requests.
|
||||
// The keys and devices from all such requests are collected into slices
|
||||
// which are returned as the result. All devices are expected to be fully
|
||||
// qualified CDI device names. If any device fails this check empty slices
|
||||
// are returned along with a non-nil error. The annotations are expected
|
||||
// to be formatted by, or in a compatible fashion to UpdateAnnotations().
|
||||
func ParseAnnotations(annotations map[string]string) ([]string, []string, error) {
|
||||
var (
|
||||
keys []string
|
||||
devices []string
|
||||
)
|
||||
|
||||
for key, value := range annotations {
|
||||
if !strings.HasPrefix(key, AnnotationPrefix) {
|
||||
continue
|
||||
}
|
||||
for _, d := range strings.Split(value, ",") {
|
||||
if !IsQualifiedName(d) {
|
||||
return nil, nil, errors.Errorf("invalid CDI device name %q", d)
|
||||
}
|
||||
devices = append(devices, d)
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
return keys, devices, nil
|
||||
}
|
||||
|
||||
// AnnotationKey returns a unique annotation key for an device allocation
|
||||
// by a K8s device plugin. pluginName should be in the format of
|
||||
// "vendor.device-type". deviceID is the ID of the device the plugin is
|
||||
// allocating. It is used to make sure that the generated key is unique
|
||||
// even if multiple allocations by a single plugin needs to be annotated.
|
||||
func AnnotationKey(pluginName, deviceID string) (string, error) {
|
||||
const maxNameLen = 63
|
||||
|
||||
if pluginName == "" {
|
||||
return "", errors.New("invalid plugin name, empty")
|
||||
}
|
||||
if deviceID == "" {
|
||||
return "", errors.New("invalid deviceID, empty")
|
||||
}
|
||||
|
||||
name := pluginName + "_" + strings.ReplaceAll(deviceID, "/", "_")
|
||||
|
||||
if len(name) > maxNameLen {
|
||||
return "", errors.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",
|
||||
name, c)
|
||||
}
|
||||
if len(name) > 2 {
|
||||
for _, c := range name[1 : len(name)-1] {
|
||||
switch {
|
||||
case isAlphaNumeric(c):
|
||||
case c == '_' || c == '-' || c == '.':
|
||||
default:
|
||||
return "", errors.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",
|
||||
name, c)
|
||||
}
|
||||
|
||||
return AnnotationPrefix + name, nil
|
||||
}
|
||||
|
||||
// AnnotationValue returns an annotation value for the given devices.
|
||||
func AnnotationValue(devices []string) (string, error) {
|
||||
value, sep := "", ""
|
||||
for _, d := range devices {
|
||||
if _, _, _, err := ParseQualifiedName(d); err != nil {
|
||||
return "", err
|
||||
}
|
||||
value += sep + d
|
||||
sep = ","
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
279
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go
generated
vendored
Normal file
279
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/cache.go
generated
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"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.
|
||||
type Option func(*Cache) error
|
||||
|
||||
// Cache stores CDI Specs loaded from Spec directories.
|
||||
type Cache struct {
|
||||
sync.Mutex
|
||||
specDirs []string
|
||||
specs map[string][]*Spec
|
||||
devices map[string]*Device
|
||||
errors map[string][]error
|
||||
}
|
||||
|
||||
// NewCache creates a new CDI Cache. The cache is populated from a set
|
||||
// of CDI Spec directories. These can be specified using a WithSpecDirs
|
||||
// option. The default set of directories is exposed in DefaultSpecDirs.
|
||||
func NewCache(options ...Option) (*Cache, error) {
|
||||
c := &Cache{}
|
||||
|
||||
if err := c.Configure(options...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(c.specDirs) == 0 {
|
||||
c.Configure(WithSpecDirs(DefaultSpecDirs...))
|
||||
}
|
||||
|
||||
return c, c.Refresh()
|
||||
}
|
||||
|
||||
// Configure applies options to the cache. Updates the cache if options have
|
||||
// changed.
|
||||
func (c *Cache) Configure(options ...Option) error {
|
||||
if len(options) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
for _, o := range options {
|
||||
if err := o(c); err != nil {
|
||||
return errors.Wrapf(err, "failed to apply cache options")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Refresh rescans the CDI Spec directories and refreshes the Cache.
|
||||
func (c *Cache) Refresh() error {
|
||||
var (
|
||||
specs = map[string][]*Spec{}
|
||||
devices = map[string]*Device{}
|
||||
conflicts = map[string]struct{}{}
|
||||
specErrors = map[string][]error{}
|
||||
result []error
|
||||
)
|
||||
|
||||
// collect errors per spec file path and once globally
|
||||
collectError := func(err error, paths ...string) {
|
||||
result = append(result, err)
|
||||
for _, path := range paths {
|
||||
specErrors[path] = append(specErrors[path], err)
|
||||
}
|
||||
}
|
||||
// resolve conflicts based on device Spec priority (order of precedence)
|
||||
resolveConflict := func(name string, dev *Device, old *Device) bool {
|
||||
devSpec, oldSpec := dev.GetSpec(), old.GetSpec()
|
||||
devPrio, oldPrio := devSpec.GetPriority(), oldSpec.GetPriority()
|
||||
switch {
|
||||
case devPrio > oldPrio:
|
||||
return false
|
||||
case devPrio == oldPrio:
|
||||
devPath, oldPath := devSpec.GetPath(), oldSpec.GetPath()
|
||||
collectError(errors.Errorf("conflicting device %q (specs %q, %q)",
|
||||
name, devPath, oldPath), devPath, oldPath)
|
||||
conflicts[name] = struct{}{}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
_ = 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)
|
||||
return nil
|
||||
}
|
||||
|
||||
vendor := spec.GetVendor()
|
||||
specs[vendor] = append(specs[vendor], spec)
|
||||
|
||||
for _, dev := range spec.devices {
|
||||
qualified := dev.GetQualifiedName()
|
||||
other, ok := devices[qualified]
|
||||
if ok {
|
||||
if resolveConflict(qualified, dev, other) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
devices[qualified] = dev
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
for conflict := range conflicts {
|
||||
delete(devices, conflict)
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.specs = specs
|
||||
c.devices = devices
|
||||
c.errors = specErrors
|
||||
|
||||
if len(result) > 0 {
|
||||
return multierror.Append(nil, result...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InjectDevices injects the given qualified devices to an OCI Spec. It
|
||||
// returns any unresolvable devices and an error if injection fails for
|
||||
// any of the devices.
|
||||
func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, error) {
|
||||
var unresolved []string
|
||||
|
||||
if ociSpec == nil {
|
||||
return devices, errors.Errorf("can't inject devices, nil OCI Spec")
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
edits := &ContainerEdits{}
|
||||
specs := map[*Spec]struct{}{}
|
||||
|
||||
for _, device := range devices {
|
||||
d := c.devices[device]
|
||||
if d == nil {
|
||||
unresolved = append(unresolved, device)
|
||||
continue
|
||||
}
|
||||
if _, ok := specs[d.GetSpec()]; !ok {
|
||||
specs[d.GetSpec()] = struct{}{}
|
||||
edits.Append(d.GetSpec().edits())
|
||||
}
|
||||
edits.Append(d.edits())
|
||||
}
|
||||
|
||||
if unresolved != nil {
|
||||
return unresolved, errors.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, nil
|
||||
}
|
||||
|
||||
// GetDevice returns the cached device for the given qualified name.
|
||||
func (c *Cache) GetDevice(device string) *Device {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
return c.devices[device]
|
||||
}
|
||||
|
||||
// ListDevices lists all cached devices by qualified name.
|
||||
func (c *Cache) ListDevices() []string {
|
||||
var devices []string
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
for name := range c.devices {
|
||||
devices = append(devices, name)
|
||||
}
|
||||
sort.Strings(devices)
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
// ListVendors lists all vendors known to the cache.
|
||||
func (c *Cache) ListVendors() []string {
|
||||
var vendors []string
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
for vendor := range c.specs {
|
||||
vendors = append(vendors, vendor)
|
||||
}
|
||||
sort.Strings(vendors)
|
||||
|
||||
return vendors
|
||||
}
|
||||
|
||||
// ListClasses lists all device classes known to the cache.
|
||||
func (c *Cache) ListClasses() []string {
|
||||
var (
|
||||
cmap = map[string]struct{}{}
|
||||
classes []string
|
||||
)
|
||||
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
for _, specs := range c.specs {
|
||||
for _, spec := range specs {
|
||||
cmap[spec.GetClass()] = struct{}{}
|
||||
}
|
||||
}
|
||||
for class := range cmap {
|
||||
classes = append(classes, class)
|
||||
}
|
||||
sort.Strings(classes)
|
||||
|
||||
return classes
|
||||
}
|
||||
|
||||
// GetVendorSpecs returns all specs for the given vendor.
|
||||
func (c *Cache) GetVendorSpecs(vendor string) []*Spec {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
return c.specs[vendor]
|
||||
}
|
||||
|
||||
// GetSpecErrors returns all errors encountered for the spec during the
|
||||
// last cache refresh.
|
||||
func (c *Cache) GetSpecErrors(spec *Spec) []error {
|
||||
return c.errors[spec.GetPath()]
|
||||
}
|
||||
|
||||
// GetErrors returns all errors encountered during the last
|
||||
// cache refresh.
|
||||
func (c *Cache) GetErrors() map[string][]error {
|
||||
return c.errors
|
||||
}
|
||||
|
||||
// GetSpecDirectories returns the CDI Spec directories currently in use.
|
||||
func (c *Cache) GetSpecDirectories() []string {
|
||||
dirs := make([]string, len(c.specDirs))
|
||||
copy(dirs, c.specDirs)
|
||||
return dirs
|
||||
}
|
357
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits.go
generated
vendored
Normal file
357
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/container-edits.go
generated
vendored
Normal file
@ -0,0 +1,357 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
ocigen "github.com/opencontainers/runtime-tools/generate"
|
||||
|
||||
runc "github.com/opencontainers/runc/libcontainer/devices"
|
||||
)
|
||||
|
||||
const (
|
||||
// PrestartHook is the name of the OCI "prestart" hook.
|
||||
PrestartHook = "prestart"
|
||||
// CreateRuntimeHook is the name of the OCI "createRuntime" hook.
|
||||
CreateRuntimeHook = "createRuntime"
|
||||
// CreateContainerHook is the name of the OCI "createContainer" hook.
|
||||
CreateContainerHook = "createContainer"
|
||||
// StartContainerHook is the name of the OCI "startContainer" hook.
|
||||
StartContainerHook = "startContainer"
|
||||
// PoststartHook is the name of the OCI "poststart" hook.
|
||||
PoststartHook = "poststart"
|
||||
// PoststopHook is the name of the OCI "poststop" hook.
|
||||
PoststopHook = "poststop"
|
||||
)
|
||||
|
||||
var (
|
||||
// Names of recognized hooks.
|
||||
validHookNames = map[string]struct{}{
|
||||
PrestartHook: {},
|
||||
CreateRuntimeHook: {},
|
||||
CreateContainerHook: {},
|
||||
StartContainerHook: {},
|
||||
PoststartHook: {},
|
||||
PoststopHook: {},
|
||||
}
|
||||
)
|
||||
|
||||
// ContainerEdits represent updates to be applied to an OCI Spec.
|
||||
// These updates can be specific to a CDI device, or they can be
|
||||
// specific to a CDI Spec. In the former case these edits should
|
||||
// be applied to all OCI Specs where the corresponding CDI device
|
||||
// is injected. In the latter case, these edits should be applied
|
||||
// to all OCI Specs where at least one devices from the CDI Spec
|
||||
// is injected.
|
||||
type ContainerEdits struct {
|
||||
*specs.ContainerEdits
|
||||
}
|
||||
|
||||
// Apply edits to the given OCI Spec. Updates the OCI Spec in place.
|
||||
// Returns an error if the update fails.
|
||||
func (e *ContainerEdits) Apply(spec *oci.Spec) error {
|
||||
if spec == nil {
|
||||
return errors.New("can't edit nil OCI Spec")
|
||||
}
|
||||
if e == nil || e.ContainerEdits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
specgen := ocigen.NewFromSpec(spec)
|
||||
if len(e.Env) > 0 {
|
||||
specgen.AddMultipleProcessEnv(e.Env)
|
||||
}
|
||||
|
||||
for _, d := range e.DeviceNodes {
|
||||
dev := d.ToOCI()
|
||||
if err := fillMissingInfo(&dev); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dev.UID == nil && spec.Process != nil {
|
||||
if uid := spec.Process.User.UID; uid > 0 {
|
||||
dev.UID = &uid
|
||||
}
|
||||
}
|
||||
if dev.GID == nil && spec.Process != nil {
|
||||
if gid := spec.Process.User.GID; gid > 0 {
|
||||
dev.GID = &gid
|
||||
}
|
||||
}
|
||||
|
||||
specgen.RemoveDevice(dev.Path)
|
||||
specgen.AddDevice(dev)
|
||||
|
||||
if dev.Type == "b" || dev.Type == "c" {
|
||||
access := d.Permissions
|
||||
if access == "" {
|
||||
access = "rwm"
|
||||
}
|
||||
specgen.AddLinuxResourcesDevice(true, dev.Type, &dev.Major, &dev.Minor, access)
|
||||
}
|
||||
}
|
||||
|
||||
if len(e.Mounts) > 0 {
|
||||
for _, m := range e.Mounts {
|
||||
specgen.RemoveMount(m.ContainerPath)
|
||||
specgen.AddMount(m.ToOCI())
|
||||
}
|
||||
sortMounts(&specgen)
|
||||
}
|
||||
|
||||
for _, h := range e.Hooks {
|
||||
switch h.HookName {
|
||||
case PrestartHook:
|
||||
specgen.AddPreStartHook(h.ToOCI())
|
||||
case PoststartHook:
|
||||
specgen.AddPostStartHook(h.ToOCI())
|
||||
case PoststopHook:
|
||||
specgen.AddPostStopHook(h.ToOCI())
|
||||
// TODO: Maybe runtime-tools/generate should be updated with these...
|
||||
case CreateRuntimeHook:
|
||||
ensureOCIHooks(spec)
|
||||
spec.Hooks.CreateRuntime = append(spec.Hooks.CreateRuntime, h.ToOCI())
|
||||
case CreateContainerHook:
|
||||
ensureOCIHooks(spec)
|
||||
spec.Hooks.CreateContainer = append(spec.Hooks.CreateContainer, h.ToOCI())
|
||||
case StartContainerHook:
|
||||
ensureOCIHooks(spec)
|
||||
spec.Hooks.StartContainer = append(spec.Hooks.StartContainer, h.ToOCI())
|
||||
default:
|
||||
return errors.Errorf("unknown hook name %q", h.HookName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate container edits.
|
||||
func (e *ContainerEdits) Validate() error {
|
||||
if e == nil || e.ContainerEdits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := ValidateEnv(e.Env); err != nil {
|
||||
return errors.Wrap(err, "invalid container edits")
|
||||
}
|
||||
for _, d := range e.DeviceNodes {
|
||||
if err := (&DeviceNode{d}).Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, h := range e.Hooks {
|
||||
if err := (&Hook{h}).Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, m := range e.Mounts {
|
||||
if err := (&Mount{m}).Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append other edits into this one. If called with a nil receiver,
|
||||
// allocates and returns newly allocated edits.
|
||||
func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
|
||||
if o == nil || o.ContainerEdits == nil {
|
||||
return e
|
||||
}
|
||||
if e == nil {
|
||||
e = &ContainerEdits{}
|
||||
}
|
||||
if e.ContainerEdits == nil {
|
||||
e.ContainerEdits = &specs.ContainerEdits{}
|
||||
}
|
||||
|
||||
e.Env = append(e.Env, o.Env...)
|
||||
e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...)
|
||||
e.Hooks = append(e.Hooks, o.Hooks...)
|
||||
e.Mounts = append(e.Mounts, o.Mounts...)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// isEmpty returns true if these edits are empty. This is valid in a
|
||||
// global Spec context but invalid in a Device context.
|
||||
func (e *ContainerEdits) isEmpty() bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
return len(e.Env)+len(e.DeviceNodes)+len(e.Hooks)+len(e.Mounts) == 0
|
||||
}
|
||||
|
||||
// ValidateEnv validates the given environment variables.
|
||||
func ValidateEnv(env []string) error {
|
||||
for _, v := range env {
|
||||
if strings.IndexByte(v, byte('=')) <= 0 {
|
||||
return errors.Errorf("invalid environment variable %q", v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes.
|
||||
type DeviceNode struct {
|
||||
*specs.DeviceNode
|
||||
}
|
||||
|
||||
// Validate a CDI Spec DeviceNode.
|
||||
func (d *DeviceNode) Validate() error {
|
||||
validTypes := map[string]struct{}{
|
||||
"": {},
|
||||
"b": {},
|
||||
"c": {},
|
||||
"u": {},
|
||||
"p": {},
|
||||
}
|
||||
|
||||
if d.Path == "" {
|
||||
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)
|
||||
}
|
||||
for _, bit := range d.Permissions {
|
||||
if bit != 'r' && bit != 'w' && bit != 'm' {
|
||||
return errors.Errorf("device %q: invalid persmissions %q",
|
||||
d.Path, d.Permissions)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hook is a CDI Spec Hook wrapper, used for validating hooks.
|
||||
type Hook struct {
|
||||
*specs.Hook
|
||||
}
|
||||
|
||||
// Validate a hook.
|
||||
func (h *Hook) Validate() error {
|
||||
if _, ok := validHookNames[h.HookName]; !ok {
|
||||
return errors.Errorf("invalid hook name %q", h.HookName)
|
||||
}
|
||||
if h.Path == "" {
|
||||
return errors.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 nil
|
||||
}
|
||||
|
||||
// Mount is a CDI Mount wrapper, used for validating mounts.
|
||||
type Mount struct {
|
||||
*specs.Mount
|
||||
}
|
||||
|
||||
// Validate a mount.
|
||||
func (m *Mount) Validate() error {
|
||||
if m.HostPath == "" {
|
||||
return errors.New("invalid mount, empty host path")
|
||||
}
|
||||
if m.ContainerPath == "" {
|
||||
return errors.New("invalid mount, empty container path")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ensure OCI Spec hooks are not nil so we can add hooks.
|
||||
func ensureOCIHooks(spec *oci.Spec) {
|
||||
if spec.Hooks == nil {
|
||||
spec.Hooks = &oci.Hooks{}
|
||||
}
|
||||
}
|
||||
|
||||
// fillMissingInfo fills in missing mandatory attributes from the host device.
|
||||
func fillMissingInfo(dev *oci.LinuxDevice) error {
|
||||
if dev.Type != "" && (dev.Major != 0 || dev.Type == "p") {
|
||||
return nil
|
||||
}
|
||||
hostDev, err := runc.DeviceFromPath(dev.Path, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to stat CDI host device %q", dev.Path)
|
||||
}
|
||||
|
||||
if dev.Type == "" {
|
||||
dev.Type = string(hostDev.Type)
|
||||
} else {
|
||||
if dev.Type != string(hostDev.Type) {
|
||||
return errors.Errorf("CDI device %q, host type mismatch (%s, %s)",
|
||||
dev.Path, dev.Type, string(hostDev.Type))
|
||||
}
|
||||
}
|
||||
if dev.Major == 0 && dev.Type != "p" {
|
||||
dev.Major = hostDev.Major
|
||||
dev.Minor = hostDev.Minor
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sortMounts sorts the mounts in the given OCI Spec.
|
||||
func sortMounts(specgen *ocigen.Generator) {
|
||||
mounts := specgen.Mounts()
|
||||
specgen.ClearMounts()
|
||||
sort.Sort(orderedMounts(mounts))
|
||||
specgen.Config.Mounts = mounts
|
||||
}
|
||||
|
||||
// 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
|
||||
type orderedMounts []oci.Mount
|
||||
|
||||
// Len returns the number of mounts. Used in sorting.
|
||||
func (m orderedMounts) Len() int {
|
||||
return len(m)
|
||||
}
|
||||
|
||||
// Less returns true if the number of parts (a/b/c would be 3 parts) in the
|
||||
// mount indexed by parameter 1 is less than that of the mount indexed by
|
||||
// parameter 2. Used in sorting.
|
||||
func (m orderedMounts) Less(i, j int) bool {
|
||||
ip, jp := m.parts(i), m.parts(j)
|
||||
if ip < jp {
|
||||
return true
|
||||
}
|
||||
if jp < ip {
|
||||
return false
|
||||
}
|
||||
return m[i].Destination < m[j].Destination
|
||||
}
|
||||
|
||||
// Swap swaps two items in an array of mounts. Used in sorting
|
||||
func (m orderedMounts) Swap(i, j int) {
|
||||
m[i], m[j] = m[j], m[i]
|
||||
}
|
||||
|
||||
// parts returns the number of parts in the destination of a mount. Used in sorting.
|
||||
func (m orderedMounts) parts(i int) int {
|
||||
return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator))
|
||||
}
|
78
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/device.go
generated
vendored
Normal file
78
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/device.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
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.
|
||||
type Device struct {
|
||||
*cdi.Device
|
||||
spec *Spec
|
||||
}
|
||||
|
||||
// Create a new Device, associate it with the given Spec.
|
||||
func newDevice(spec *Spec, d cdi.Device) (*Device, error) {
|
||||
dev := &Device{
|
||||
Device: &d,
|
||||
spec: spec,
|
||||
}
|
||||
|
||||
if err := dev.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
// GetSpec returns the Spec this device is defined in.
|
||||
func (d *Device) GetSpec() *Spec {
|
||||
return d.spec
|
||||
}
|
||||
|
||||
// GetQualifiedName returns the qualified name for this device.
|
||||
func (d *Device) GetQualifiedName() string {
|
||||
return QualifiedName(d.spec.GetVendor(), d.spec.GetClass(), d.Name)
|
||||
}
|
||||
|
||||
// ApplyEdits applies the device-speific container edits to an OCI Spec.
|
||||
func (d *Device) ApplyEdits(ociSpec *oci.Spec) error {
|
||||
return d.edits().Apply(ociSpec)
|
||||
}
|
||||
|
||||
// edits returns the applicable container edits for this spec.
|
||||
func (d *Device) edits() *ContainerEdits {
|
||||
return &ContainerEdits{&d.ContainerEdits}
|
||||
}
|
||||
|
||||
// Validate the device.
|
||||
func (d *Device) validate() error {
|
||||
if err := ValidateDeviceName(d.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
edits := d.edits()
|
||||
if edits.isEmpty() {
|
||||
return errors.Errorf("invalid device, empty device edits")
|
||||
}
|
||||
if err := edits.Validate(); err != nil {
|
||||
return errors.Wrapf(err, "invalid device %q", d.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
150
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go
generated
vendored
Normal file
150
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/doc.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
// Package cdi has the primary purpose of providing an API for
|
||||
// interacting with CDI and consuming CDI devices.
|
||||
//
|
||||
// For more information about Container Device Interface, please refer to
|
||||
// https://github.com/container-orchestrated-devices/container-device-interface
|
||||
//
|
||||
// Container Device Interface
|
||||
//
|
||||
// Container Device Interface, or CDI for short, provides comprehensive
|
||||
// third party device support for container runtimes. CDI uses vendor
|
||||
// provided specification files, CDI Specs for short, to describe how a
|
||||
// container's runtime environment should be modified when one or more
|
||||
// of the vendor-specific devices is injected into the container. Beyond
|
||||
// describing the low level platform-specific details of how to gain
|
||||
// basic access to a device, CDI Specs allow more fine-grained device
|
||||
// initialization, and the automatic injection of any necessary vendor-
|
||||
// or device-specific software that might be required for a container
|
||||
// to use a device or take full advantage of it.
|
||||
//
|
||||
// In the CDI device model containers request access to a device using
|
||||
// fully qualified device names, qualified names for short, consisting of
|
||||
// a vendor identifier, a device class and a device name or identifier.
|
||||
// These pieces of information together uniquely identify a device among
|
||||
// all device vendors, classes and device instances.
|
||||
//
|
||||
// This package implements an API for easy consumption of CDI. The API
|
||||
// implements discovery, loading and caching of CDI Specs and injection
|
||||
// of CDI devices into containers. This is the most common functionality
|
||||
// the vast majority of CDI consumers need. The API should be usable both
|
||||
// by OCI runtime clients and runtime implementations.
|
||||
//
|
||||
// CDI Registry
|
||||
//
|
||||
// The primary interface to interact with CDI devices is the Registry. It
|
||||
// is essentially a cache of all Specs and devices discovered in standard
|
||||
// CDI directories on the host. The registry has two main functionality,
|
||||
// injecting devices into an OCI Spec and refreshing the cache of CDI
|
||||
// Specs and devices.
|
||||
//
|
||||
// Device Injection
|
||||
//
|
||||
// Using the Registry one can inject CDI devices into a container with code
|
||||
// similar to the following snippet:
|
||||
//
|
||||
// import (
|
||||
// "fmt"
|
||||
// "strings"
|
||||
//
|
||||
// "github.com/pkg/errors"
|
||||
// log "github.com/sirupsen/logrus"
|
||||
//
|
||||
// "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
// oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
// )
|
||||
//
|
||||
// func injectCDIDevices(spec *oci.Spec, devices []string) error {
|
||||
// log.Debug("pristine OCI Spec: %s", dumpSpec(spec))
|
||||
//
|
||||
// unresolved, err := cdi.GetRegistry().InjectDevices(spec, devices)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "CDI device injection failed")
|
||||
// }
|
||||
//
|
||||
// log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec))
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// Cache Refresh
|
||||
//
|
||||
// In a runtime implementation one typically wants to make sure the
|
||||
// CDI Spec cache is up to date before performing device injection.
|
||||
// A code snippet similar to the following accmplishes that:
|
||||
//
|
||||
// import (
|
||||
// "fmt"
|
||||
// "strings"
|
||||
//
|
||||
// "github.com/pkg/errors"
|
||||
// log "github.com/sirupsen/logrus"
|
||||
//
|
||||
// "github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
||||
// oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
// )
|
||||
//
|
||||
// func injectCDIDevices(spec *oci.Spec, devices []string) error {
|
||||
// registry := cdi.GetRegistry()
|
||||
//
|
||||
// if err := registry.Refresh(); err != nil {
|
||||
// // Note:
|
||||
// // It is up to the implementation to decide whether
|
||||
// // to abort injection on errors. A failed Refresh()
|
||||
// // does not necessarily render the registry unusable.
|
||||
// // For instance, a parse error in a Spec file for
|
||||
// // vendor A does not have any effect on devices of
|
||||
// // vendor B...
|
||||
// log.Warnf("pre-injection Refresh() failed: %v", err)
|
||||
// }
|
||||
//
|
||||
// log.Debug("pristine OCI Spec: %s", dumpSpec(spec))
|
||||
//
|
||||
// unresolved, err := registry.InjectDevices(spec, devices)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "CDI device injection failed")
|
||||
// }
|
||||
//
|
||||
// log.Debug("CDI-updated OCI Spec: %s", dumpSpec(spec))
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// CDI can collect Spec files from multiple directories. Spec files are
|
||||
// automatically assigned priorities according to which directory they
|
||||
// were loaded from. The later a directory occurs in the list of CDI
|
||||
// directories to scan, the higher priority Spec files loaded from that
|
||||
// directory are assigned to. When two or more Spec files define the
|
||||
// same device, conflict is resolved by chosing the definition from the
|
||||
// Spec file with the highest priority.
|
||||
//
|
||||
// The default CDI directory configuration is chosen to encourage
|
||||
// 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'.
|
||||
//
|
||||
// CDI Spec Validation
|
||||
//
|
||||
// This package performs both syntactic and semantic validation of CDI
|
||||
// Spec file data when a Spec file is loaded via the registry or using
|
||||
// the ReadSpec API function. As part of the semantic verification, the
|
||||
// Spec file is verified against the CDI Spec JSON validation schema.
|
||||
//
|
||||
// If a valid externally provided JSON validation schema is found in
|
||||
// the filesystem at /etc/cdi/schema/schema.json it is loaded and used
|
||||
// as the default validation schema. If such a file is not found or
|
||||
// fails to load, an embedded no-op schema is used.
|
||||
//
|
||||
// The used validation schema can also be changed programmatically using
|
||||
// the SetSchema API convenience function. This function also accepts
|
||||
// the special "builtin" (BuiltinSchemaName) and "none" (NoneSchemaName)
|
||||
// schema names which switch the used schema to the in-repo validation
|
||||
// schema embedded into the binary or the now default no-op schema
|
||||
// correspondingly. Other names are interpreted as the path to the actual
|
||||
/// validation schema to load and use.
|
||||
package cdi
|
203
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/qualified-device.go
generated
vendored
Normal file
203
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/qualified-device.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// QualifiedName returns the qualified name for a device.
|
||||
// The syntax for a qualified device names is
|
||||
// "<vendor>/<class>=<name>".
|
||||
// A valid vendor name may contain the following runes:
|
||||
// 'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
|
||||
// A valid class name may contain the following runes:
|
||||
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_'.
|
||||
// A valid device name may containe the following runes:
|
||||
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
|
||||
func QualifiedName(vendor, class, name string) string {
|
||||
return vendor + "/" + class + "=" + name
|
||||
}
|
||||
|
||||
// IsQualifiedName tests if a device name is qualified.
|
||||
func IsQualifiedName(device string) bool {
|
||||
_, _, _, err := ParseQualifiedName(device)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// ParseQualifiedName splits a qualified name into device vendor, class,
|
||||
// and name. If the device fails to parse as a qualified name, or if any
|
||||
// of the split components fail to pass syntax validation, vendor and
|
||||
// class are returned as empty, together with the verbatim input as the
|
||||
// name and an error describing the reason for failure.
|
||||
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)
|
||||
}
|
||||
if class == "" {
|
||||
return "", "", device, errors.Errorf("unqualified device %q, missing class", device)
|
||||
}
|
||||
if name == "" {
|
||||
return "", "", device, errors.Errorf("unqualified device %q, missing device name", device)
|
||||
}
|
||||
|
||||
if err := ValidateVendorName(vendor); err != nil {
|
||||
return "", "", device, errors.Wrapf(err, "invalid device %q", device)
|
||||
}
|
||||
if err := ValidateClassName(class); err != nil {
|
||||
return "", "", device, errors.Wrapf(err, "invalid device %q", device)
|
||||
}
|
||||
if err := ValidateDeviceName(name); err != nil {
|
||||
return "", "", device, errors.Wrapf(err, "invalid device %q", device)
|
||||
}
|
||||
|
||||
return vendor, class, name, nil
|
||||
}
|
||||
|
||||
// ParseDevice tries to split a device name into vendor, class, and name.
|
||||
// If this fails, for instance in the case of unqualified device names,
|
||||
// ParseDevice returns an empty vendor and class together with name set
|
||||
// to the verbatim input.
|
||||
func ParseDevice(device string) (string, string, string) {
|
||||
if device == "" || device[0] == '/' {
|
||||
return "", "", device
|
||||
}
|
||||
|
||||
parts := strings.SplitN(device, "=", 2)
|
||||
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
|
||||
return "", "", device
|
||||
}
|
||||
|
||||
name := parts[1]
|
||||
vendor, class := ParseQualifier(parts[0])
|
||||
if vendor == "" {
|
||||
return "", "", device
|
||||
}
|
||||
|
||||
return vendor, class, name
|
||||
}
|
||||
|
||||
// ParseQualifier splits a device qualifier into vendor and class.
|
||||
// The syntax for a device qualifier is
|
||||
// "<vendor>/<class>"
|
||||
// If parsing fails, an empty vendor and the class set to the
|
||||
// verbatim input is returned.
|
||||
func ParseQualifier(kind string) (string, string) {
|
||||
parts := strings.SplitN(kind, "/", 2)
|
||||
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
|
||||
return "", kind
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
// ValidateVendorName checks the validity of a vendor name.
|
||||
// A vendor name may contain the following ASCII characters:
|
||||
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
|
||||
// - digits ('0'-'9')
|
||||
// - underscore, dash, and dot ('_', '-', and '.')
|
||||
func ValidateVendorName(vendor string) error {
|
||||
if vendor == "" {
|
||||
return errors.Errorf("invalid (empty) vendor name")
|
||||
}
|
||||
if !isLetter(rune(vendor[0])) {
|
||||
return errors.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",
|
||||
c, vendor)
|
||||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(vendor[len(vendor)-1])) {
|
||||
return errors.Errorf("invalid vendor %q, should end with letter", vendor)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateClassName checks the validity of class name.
|
||||
// A class name may contain the following ASCII characters:
|
||||
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
|
||||
// - digits ('0'-'9')
|
||||
// - underscore and dash ('_', '-')
|
||||
func ValidateClassName(class string) error {
|
||||
if class == "" {
|
||||
return errors.Errorf("invalid (empty) device class")
|
||||
}
|
||||
if !isLetter(rune(class[0])) {
|
||||
return errors.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",
|
||||
c, class)
|
||||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(class[len(class)-1])) {
|
||||
return errors.Errorf("invalid class %q, should end with letter", class)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateDeviceName checks the validity of a device name.
|
||||
// A device name may contain the following ASCII characters:
|
||||
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
|
||||
// - digits ('0'-'9')
|
||||
// - underscore, dash, dot, colon ('_', '-', '.', ':')
|
||||
func ValidateDeviceName(name string) error {
|
||||
if name == "" {
|
||||
return errors.Errorf("invalid (empty) device name")
|
||||
}
|
||||
if !isLetter(rune(name[0])) {
|
||||
return errors.Errorf("invalid name %q, should start with letter", name)
|
||||
}
|
||||
for _, c := range string(name[1 : len(name)-1]) {
|
||||
switch {
|
||||
case isAlphaNumeric(c):
|
||||
case c == '_' || c == '-' || c == '.' || c == ':':
|
||||
default:
|
||||
return errors.Errorf("invalid character '%c' in device name %q",
|
||||
c, name)
|
||||
}
|
||||
}
|
||||
if !isAlphaNumeric(rune(name[len(name)-1])) {
|
||||
return errors.Errorf("invalid name %q, should start with letter", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isLetter(c rune) bool {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')
|
||||
}
|
||||
|
||||
func isDigit(c rune) bool {
|
||||
return '0' <= c && c <= '9'
|
||||
}
|
||||
|
||||
func isAlphaNumeric(c rune) bool {
|
||||
return isLetter(c) || isDigit(c)
|
||||
}
|
139
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/registry.go
generated
vendored
Normal file
139
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/registry.go
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
oci "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
//
|
||||
// Registry keeps a cache of all CDI Specs installed or generated on
|
||||
// the host. Registry is the primary interface clients should use to
|
||||
// interact with CDI.
|
||||
//
|
||||
// The most commonly used Registry functions are for refreshing the
|
||||
// registry and injecting CDI devices into an OCI Spec.
|
||||
//
|
||||
type Registry interface {
|
||||
RegistryResolver
|
||||
RegistryRefresher
|
||||
DeviceDB() RegistryDeviceDB
|
||||
SpecDB() RegistrySpecDB
|
||||
}
|
||||
|
||||
// RegistryRefresher is the registry interface for refreshing the
|
||||
// cache of CDI Specs and devices.
|
||||
//
|
||||
// Refresh rescans all CDI Spec directories and updates the
|
||||
// state of the cache to reflect any changes. It returns any
|
||||
// errors encountered during the refresh.
|
||||
//
|
||||
// GetErrors returns all errors encountered for any of the scanned
|
||||
// Spec files during the last cache refresh.
|
||||
//
|
||||
// GetSpecDirectories returns the set up CDI Spec directories
|
||||
// currently in use. The directories are returned in the scan
|
||||
// order of Refresh().
|
||||
type RegistryRefresher interface {
|
||||
Refresh() error
|
||||
GetErrors() map[string][]error
|
||||
GetSpecDirectories() []string
|
||||
}
|
||||
|
||||
// RegistryResolver is the registry interface for injecting CDI
|
||||
// devices into an OCI Spec.
|
||||
//
|
||||
// InjectDevices takes an OCI Spec and injects into it a set of
|
||||
// CDI devices given by qualified name. It returns the names of
|
||||
// any unresolved devices and an error if injection fails.
|
||||
type RegistryResolver interface {
|
||||
InjectDevices(spec *oci.Spec, device ...string) (unresolved []string, err error)
|
||||
}
|
||||
|
||||
// RegistryDeviceDB is the registry interface for querying devices.
|
||||
//
|
||||
// GetDevice returns the CDI device for the given qualified name. If
|
||||
// the device is not GetDevice returns nil.
|
||||
//
|
||||
// ListDevices returns a slice with the names of qualified device
|
||||
// known. The returned slice is sorted.
|
||||
type RegistryDeviceDB interface {
|
||||
GetDevice(device string) *Device
|
||||
ListDevices() []string
|
||||
}
|
||||
|
||||
// RegistrySpecDB is the registry interface for querying CDI Specs.
|
||||
//
|
||||
// ListVendors returns a slice with all vendors known. The returned
|
||||
// slice is sorted.
|
||||
//
|
||||
// ListClasses returns a slice with all classes known. The returned
|
||||
// slice is sorted.
|
||||
//
|
||||
// GetVendorSpecs returns a slice of all Specs for the vendor.
|
||||
//
|
||||
// GetSpecErrors returns any errors for the Spec encountered during
|
||||
// the last cache refresh.
|
||||
type RegistrySpecDB interface {
|
||||
ListVendors() []string
|
||||
ListClasses() []string
|
||||
GetVendorSpecs(vendor string) []*Spec
|
||||
GetSpecErrors(*Spec) []error
|
||||
}
|
||||
|
||||
type registry struct {
|
||||
*Cache
|
||||
}
|
||||
|
||||
var _ Registry = ®istry{}
|
||||
|
||||
var (
|
||||
reg *registry
|
||||
initOnce sync.Once
|
||||
)
|
||||
|
||||
// GetRegistry returns the CDI registry. If any options are given, those
|
||||
// are applied to the registry.
|
||||
func GetRegistry(options ...Option) Registry {
|
||||
var new bool
|
||||
initOnce.Do(func() {
|
||||
reg, _ = getRegistry(options...)
|
||||
new = true
|
||||
})
|
||||
if !new && len(options) > 0 {
|
||||
reg.Configure(options...)
|
||||
reg.Refresh()
|
||||
}
|
||||
return reg
|
||||
}
|
||||
|
||||
// DeviceDB returns the registry interface for querying devices.
|
||||
func (r *registry) DeviceDB() RegistryDeviceDB {
|
||||
return r
|
||||
}
|
||||
|
||||
// SpecDB returns the registry interface for querying Specs.
|
||||
func (r *registry) SpecDB() RegistrySpecDB {
|
||||
return r
|
||||
}
|
||||
|
||||
func getRegistry(options ...Option) (*registry, error) {
|
||||
c, err := NewCache(options...)
|
||||
return ®istry{c}, err
|
||||
}
|
46
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/schema.go
generated
vendored
Normal file
46
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/schema.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright © 2022 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"github.com/container-orchestrated-devices/container-device-interface/schema"
|
||||
cdi "github.com/container-orchestrated-devices/container-device-interface/specs-go"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultExternalSchema is the JSON schema to load if found.
|
||||
DefaultExternalSchema = "/etc/cdi/schema/schema.json"
|
||||
)
|
||||
|
||||
// SetSchema sets the Spec JSON validation schema to use.
|
||||
func SetSchema(name string) error {
|
||||
s, err := schema.Load(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
schema.Set(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate CDI Spec against JSON Schema.
|
||||
func validateWithSchema(raw *cdi.Spec) error {
|
||||
return schema.ValidateType(raw)
|
||||
}
|
||||
|
||||
func init() {
|
||||
SetSchema(DefaultExternalSchema)
|
||||
}
|
110
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec-dirs.go
generated
vendored
Normal file
110
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec-dirs.go
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultStaticDir is the default directory for static CDI Specs.
|
||||
DefaultStaticDir = "/etc/cdi"
|
||||
// DefaultDynamicDir is the default directory for generated CDI Specs
|
||||
DefaultDynamicDir = "/var/run/cdi"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultSpecDirs is the default Spec directory configuration.
|
||||
// While altering this variable changes the package defaults,
|
||||
// the preferred way of overriding the default directories is
|
||||
// to use a WithSpecDirs options. Otherwise the change is only
|
||||
// effective if it takes place before creating the Registry or
|
||||
// other Cache instances.
|
||||
DefaultSpecDirs = []string{DefaultStaticDir, DefaultDynamicDir}
|
||||
// ErrStopScan can be returned from a ScanSpecFunc to stop the scan.
|
||||
ErrStopScan = errors.New("stop Spec scan")
|
||||
)
|
||||
|
||||
// WithSpecDirs returns an option to override the CDI Spec directories.
|
||||
func WithSpecDirs(dirs ...string) Option {
|
||||
return func(c *Cache) error {
|
||||
c.specDirs = make([]string, len(dirs))
|
||||
for i, dir := range dirs {
|
||||
c.specDirs[i] = filepath.Clean(dir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// scanSpecFunc is a function for processing CDI Spec files.
|
||||
type scanSpecFunc func(string, int, *Spec, error) error
|
||||
|
||||
// ScanSpecDirs scans the given directories looking for CDI Spec files,
|
||||
// which are all files with a '.json' or '.yaml' suffix. For every Spec
|
||||
// file discovered, ScanSpecDirs loads a Spec from the file then calls
|
||||
// the scan function passing it the path to the file, the priority (the
|
||||
// index of the directory in the slice of directories given), the Spec
|
||||
// itself, and any error encountered while loading the Spec.
|
||||
//
|
||||
// Scanning stops once all files have been processed or when the scan
|
||||
// function returns an error. The result of ScanSpecDirs is the error
|
||||
// returned by the scan function, if any. The special error ErrStopScan
|
||||
// can be used to terminate the scan gracefully without ScanSpecDirs
|
||||
// returning an error. ScanSpecDirs silently skips any subdirectories.
|
||||
func scanSpecDirs(dirs []string, scanFn scanSpecFunc) error {
|
||||
var (
|
||||
spec *Spec
|
||||
err error
|
||||
)
|
||||
|
||||
for priority, dir := range dirs {
|
||||
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
// for initial stat failure Walk calls us with nil info
|
||||
if info == nil {
|
||||
return err
|
||||
}
|
||||
// first call from Walk is for dir itself, others we skip
|
||||
if info.IsDir() {
|
||||
if path == dir {
|
||||
return nil
|
||||
}
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
// ignore obviously non-Spec files
|
||||
if ext := filepath.Ext(path); ext != ".json" && ext != ".yaml" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return scanFn(path, priority, nil, err)
|
||||
}
|
||||
|
||||
spec, err = ReadSpec(path, priority)
|
||||
return scanFn(path, priority, spec, err)
|
||||
})
|
||||
|
||||
if err != nil && err != ErrStopScan {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
190
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go
generated
vendored
Normal file
190
vendor/github.com/container-orchestrated-devices/container-device-interface/pkg/cdi/spec.go
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
Copyright © 2021 The CDI Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cdi
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
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": {},
|
||||
}
|
||||
)
|
||||
|
||||
// Spec represents a single CDI Spec. It is usually loaded from a
|
||||
// file and stored in a cache. The Spec has an associated priority.
|
||||
// This priority is inherited from the associated priority of the
|
||||
// CDI Spec directory that contains the CDI Spec file and is used
|
||||
// to resolve conflicts if multiple CDI Spec files contain entries
|
||||
// for the same fully qualified device.
|
||||
type Spec struct {
|
||||
*cdi.Spec
|
||||
vendor string
|
||||
class string
|
||||
path string
|
||||
priority int
|
||||
devices map[string]*Device
|
||||
}
|
||||
|
||||
// ReadSpec reads the given CDI Spec file. The resulting Spec is
|
||||
// assigned the given priority. If reading or parsing the Spec
|
||||
// data fails ReadSpec returns a nil Spec and an error.
|
||||
func ReadSpec(path string, priority int) (*Spec, error) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
return nil, err
|
||||
case err != nil:
|
||||
return nil, errors.Wrapf(err, "failed to read CDI Spec %q", path)
|
||||
}
|
||||
|
||||
raw, err := parseSpec(data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse CDI Spec %q", path)
|
||||
}
|
||||
if raw == nil {
|
||||
return nil, errors.Errorf("failed to parse CDI Spec %q, no Spec data", path)
|
||||
}
|
||||
|
||||
spec, err := NewSpec(raw, path, priority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// Spec and an error.
|
||||
func NewSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) {
|
||||
err := validateWithSchema(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spec := &Spec{
|
||||
Spec: raw,
|
||||
path: filepath.Clean(path),
|
||||
priority: priority,
|
||||
}
|
||||
|
||||
spec.vendor, spec.class = ParseQualifier(spec.Kind)
|
||||
|
||||
if spec.devices, err = spec.validate(); err != nil {
|
||||
return nil, errors.Wrap(err, "invalid CDI Spec")
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
// GetVendor returns the vendor of this Spec.
|
||||
func (s *Spec) GetVendor() string {
|
||||
return s.vendor
|
||||
}
|
||||
|
||||
// GetClass returns the device class of this Spec.
|
||||
func (s *Spec) GetClass() string {
|
||||
return s.class
|
||||
}
|
||||
|
||||
// GetDevice returns the device for the given unqualified name.
|
||||
func (s *Spec) GetDevice(name string) *Device {
|
||||
return s.devices[name]
|
||||
}
|
||||
|
||||
// GetPath returns the filesystem path of this Spec.
|
||||
func (s *Spec) GetPath() string {
|
||||
return s.path
|
||||
}
|
||||
|
||||
// GetPriority returns the priority of this Spec.
|
||||
func (s *Spec) GetPriority() int {
|
||||
return s.priority
|
||||
}
|
||||
|
||||
// ApplyEdits applies the Spec's global-scope container edits to an OCI Spec.
|
||||
func (s *Spec) ApplyEdits(ociSpec *oci.Spec) error {
|
||||
return s.edits().Apply(ociSpec)
|
||||
}
|
||||
|
||||
// edits returns the applicable global container edits for this spec.
|
||||
func (s *Spec) edits() *ContainerEdits {
|
||||
return &ContainerEdits{&s.ContainerEdits}
|
||||
}
|
||||
|
||||
// Validate the Spec.
|
||||
func (s *Spec) validate() (map[string]*Device, error) {
|
||||
if err := validateVersion(s.Version); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ValidateVendorName(s.vendor); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ValidateClassName(s.class); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.edits().Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
devices := make(map[string]*Device)
|
||||
for _, d := range s.Devices {
|
||||
dev, err := newDevice(s, d)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed add device %q", d.Name)
|
||||
}
|
||||
if _, conflict := devices[d.Name]; conflict {
|
||||
return nil, errors.Errorf("invalid spec, multiple device %q", d.Name)
|
||||
}
|
||||
devices[d.Name] = dev
|
||||
}
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse raw CDI Spec file data.
|
||||
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 raw, nil
|
||||
}
|
27
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/Makefile
generated
vendored
Normal file
27
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/Makefile
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
VALIDATE ?= ../bin/validate
|
||||
SCHEMA ?= schema.json
|
||||
|
||||
test:
|
||||
@FMT_RED=$$(tput setaf 1); \
|
||||
FMT_BLUE=$$(tput setaf 12); \
|
||||
FMT_CLEAR=$$(tput sgr0); \
|
||||
echo "Running Good Tests"; \
|
||||
for FILE in $$(ls "testdata/good"); do \
|
||||
FILE_PATH="testdata/good/$${FILE}"; \
|
||||
if $(VALIDATE) --schema "$(SCHEMA)" "$${FILE_PATH}" > /dev/null ; then \
|
||||
printf '%s[OK]%s %s\n' "$${FMT_BLUE}" "$${FMT_CLEAR}" "$${FILE_PATH}"; \
|
||||
else \
|
||||
printf '%s[KO]%s %s\n' "$${FMT_RED}" "$${FMT_CLEAR}" "$${FILE_PATH}"; \
|
||||
exit 1; \
|
||||
fi \
|
||||
done; \
|
||||
echo "Running Bad Tests"; \
|
||||
for FILE in $$(ls "testdata/bad"); do \
|
||||
FILE_PATH="testdata/bad/$${FILE}"; \
|
||||
if $(VALIDATE) --schema "$(SCHEMA)" "$${FILE_PATH}" > /dev/null ; then \
|
||||
printf '%s[KO]%s %s\n' "$${FMT_RED}" "$${FMT_CLEAR}" "$${FILE_PATH}"; \
|
||||
exit 1; \
|
||||
else \
|
||||
printf '%s[OK]%s %s\n' "$${FMT_BLUE}" "$${FMT_CLEAR}" "$${FILE_PATH}"; \
|
||||
fi \
|
||||
done
|
127
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/defs.json
generated
vendored
Normal file
127
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/defs.json
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
{
|
||||
"description": "Definitions used throughout the Container Device Interface Specification",
|
||||
"definitions": {
|
||||
"uint32": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 4294967295
|
||||
},
|
||||
"int64": {
|
||||
"type": "integer",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807
|
||||
},
|
||||
"ArrayOfStrings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"FilePath": {
|
||||
"type": "string"
|
||||
},
|
||||
"Env": {
|
||||
"$ref": "#/definitions/ArrayOfStrings"
|
||||
},
|
||||
"DeviceNode": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
"$ref": "#/definitions/FilePath"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"major": {
|
||||
"$ref": "#/definitions/int64"
|
||||
},
|
||||
"minor": {
|
||||
"$ref": "#/definitions/int64"
|
||||
},
|
||||
"uid": {
|
||||
"$ref": "#/definitions/uint32"
|
||||
},
|
||||
"gid": {
|
||||
"$ref": "#/definitions/uint32"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
]
|
||||
},
|
||||
"Mount": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hostPath": {
|
||||
"$ref": "#/definitions/FilePath"
|
||||
},
|
||||
"containerPath": {
|
||||
"$ref": "#/definitions/FilePath"
|
||||
},
|
||||
"options": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hostPath",
|
||||
"containerPath"
|
||||
]
|
||||
},
|
||||
"Hook": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hookName": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"$ref": "#/definitions/FilePath"
|
||||
},
|
||||
"args": {
|
||||
"$ref": "#/definitions/ArrayOfStrings"
|
||||
},
|
||||
"env": {
|
||||
"$ref": "#/definitions/ArrayOfStrings"
|
||||
},
|
||||
"timeout": {
|
||||
"$ref": "#/definitions/uint32"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hookName",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
"containerEdits": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"env": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"ref": "#definitions/Env"
|
||||
}
|
||||
},
|
||||
"deviceNodes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/DeviceNode"
|
||||
}
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Mount"
|
||||
}
|
||||
},
|
||||
"hooks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Hook"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
253
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/schema.go
generated
vendored
Normal file
253
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/schema.go
generated
vendored
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
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 schema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
schema "github.com/xeipuuv/gojsonschema"
|
||||
)
|
||||
|
||||
const (
|
||||
// BuiltinSchemaName references the builtin schema for Load()/Set().
|
||||
BuiltinSchemaName = "builtin"
|
||||
// NoneSchemaName references a disabled/NOP schema for Load()/Set().
|
||||
NoneSchemaName = "none"
|
||||
// DefaultSchemaName is the none schema.
|
||||
DefaultSchemaName = NoneSchemaName
|
||||
|
||||
// builtinSchemaFile is the builtin schema URI in our embedded FS.
|
||||
builtinSchemaFile = "file:///schema.json"
|
||||
)
|
||||
|
||||
// Schema is a JSON validation schema.
|
||||
type Schema struct {
|
||||
schema *schema.Schema
|
||||
}
|
||||
|
||||
// Error wraps a JSON validation result.
|
||||
type Error struct {
|
||||
Result *schema.Result
|
||||
}
|
||||
|
||||
// Set sets the default validating JSON schema.
|
||||
func Set(s *Schema) {
|
||||
current = s
|
||||
}
|
||||
|
||||
// Get returns the active validating JSON schema.
|
||||
func Get() *Schema {
|
||||
return current
|
||||
}
|
||||
|
||||
// BuiltinSchema returns the builtin validating JSON Schema.
|
||||
func BuiltinSchema() *Schema {
|
||||
return builtin
|
||||
}
|
||||
|
||||
// NopSchema returns an validating JSON Schema that does no real validation.
|
||||
func NopSchema() *Schema {
|
||||
return &Schema{}
|
||||
}
|
||||
|
||||
// ReadAndValidate all data from the given reader, using the active schema for validation.
|
||||
func ReadAndValidate(r io.Reader) ([]byte, error) {
|
||||
return current.ReadAndValidate(r)
|
||||
}
|
||||
|
||||
// Validate validates the data read from an io.Reader against the active schema.
|
||||
func Validate(r io.Reader) error {
|
||||
return current.Validate(r)
|
||||
}
|
||||
|
||||
// ValidateData validates the given JSON document against the active schema.
|
||||
func ValidateData(data []byte) error {
|
||||
return current.ValidateData(data)
|
||||
}
|
||||
|
||||
// ValidateFile validates the given JSON file against the active schema.
|
||||
func ValidateFile(path string) error {
|
||||
return current.ValidateFile(path)
|
||||
}
|
||||
|
||||
// ValidateType validates a go object against the schema.
|
||||
func ValidateType(obj interface{}) error {
|
||||
return current.ValidateType(obj)
|
||||
}
|
||||
|
||||
// Load the given JSON Schema.
|
||||
func Load(source string) (*Schema, error) {
|
||||
var (
|
||||
loader schema.JSONLoader
|
||||
err error
|
||||
s *schema.Schema
|
||||
)
|
||||
|
||||
source = strings.TrimSpace(source)
|
||||
|
||||
switch {
|
||||
case source == BuiltinSchemaName:
|
||||
return BuiltinSchema(), nil
|
||||
case source == NoneSchemaName, source == "":
|
||||
return NopSchema(), nil
|
||||
case strings.HasPrefix(source, "file://"):
|
||||
case strings.HasPrefix(source, "http://"):
|
||||
case strings.HasPrefix(source, "https://"):
|
||||
default:
|
||||
if strings.Index(source, "://") < 0 {
|
||||
source, err = filepath.Abs(source)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err,
|
||||
"failed to get JSON schema absolute path for %s", source)
|
||||
}
|
||||
source = "file://" + source
|
||||
}
|
||||
}
|
||||
|
||||
loader = schema.NewReferenceLoader(source)
|
||||
|
||||
s, err = schema.NewSchema(loader)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load JSON schema")
|
||||
}
|
||||
|
||||
return &Schema{schema: s}, nil
|
||||
}
|
||||
|
||||
// ReadAndValidate all data from the given reader, using the schema for validation.
|
||||
func (s *Schema) ReadAndValidate(r io.Reader) ([]byte, error) {
|
||||
loader, reader := schema.NewReaderLoader(r)
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read data for validation")
|
||||
}
|
||||
return data, s.validate(loader)
|
||||
}
|
||||
|
||||
// Validate validates the data read from an io.Reader against the schema.
|
||||
func (s *Schema) Validate(r io.Reader) error {
|
||||
_, err := s.ReadAndValidate(r)
|
||||
return err
|
||||
}
|
||||
|
||||
// ValidateData validates the given JSON data against the schema.
|
||||
func (s *Schema) ValidateData(data []byte) error {
|
||||
var (
|
||||
any interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
if !bytes.HasPrefix(bytes.TrimSpace(data), []byte{'{'}) {
|
||||
err = yaml.Unmarshal(data, &any)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to YAML unmarshal data for validation")
|
||||
}
|
||||
data, err = json.Marshal(any)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to JSON remarshal data for validation")
|
||||
}
|
||||
}
|
||||
|
||||
return s.validate(schema.NewBytesLoader(data))
|
||||
}
|
||||
|
||||
// ValidateFile validates the given JSON file against the schema.
|
||||
func (s *Schema) ValidateFile(path string) error {
|
||||
if filepath.Ext(path) == ".json" {
|
||||
return s.validate(schema.NewReferenceLoader("file://" + path))
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.ValidateData(data)
|
||||
}
|
||||
|
||||
// ValidateType validates a go object against the schema.
|
||||
func (s *Schema) ValidateType(obj interface{}) error {
|
||||
l := schema.NewGoLoader(obj)
|
||||
return s.validate(l)
|
||||
}
|
||||
|
||||
// Validate the (to be) loaded doc against the schema.
|
||||
func (s *Schema) validate(doc schema.JSONLoader) error {
|
||||
if s == nil || s.schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
docErr, jsonErr := s.schema.Validate(doc)
|
||||
if jsonErr != nil {
|
||||
return errors.Wrap(jsonErr, "failed to load JSON data for validation")
|
||||
}
|
||||
if docErr.Valid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Error{Result: docErr}
|
||||
}
|
||||
|
||||
// Error returns the given Result's error as a multierror(.Error()).
|
||||
func (e *Error) Error() string {
|
||||
if e == nil || e.Result == nil || e.Result.Valid() {
|
||||
return ""
|
||||
}
|
||||
|
||||
var multi error
|
||||
for _, err := range e.Result.Errors() {
|
||||
multi = multierror.Append(multi, errors.Errorf("%v", err))
|
||||
}
|
||||
return strings.TrimRight(multi.Error(), "\n")
|
||||
}
|
||||
|
||||
var (
|
||||
// our builtin schema
|
||||
builtin *Schema
|
||||
// currently loaded schema, builtin by default
|
||||
current *Schema
|
||||
)
|
||||
|
||||
//go:embed *.json
|
||||
var builtinFS embed.FS
|
||||
|
||||
func init() {
|
||||
s, err := schema.NewSchema(
|
||||
schema.NewReferenceLoaderFileSystem(
|
||||
builtinSchemaFile,
|
||||
http.FS(builtinFS),
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
builtin = NopSchema()
|
||||
} else {
|
||||
builtin = &Schema{schema: s}
|
||||
}
|
||||
|
||||
current = builtin
|
||||
}
|
39
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/schema.json
generated
vendored
Normal file
39
vendor/github.com/container-orchestrated-devices/container-device-interface/schema/schema.json
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"description": "Configuration Schema for the Container Device Interface",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cdiVersion": {
|
||||
"description": "The version of the Container Device Interface Specification that the document complies with",
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"description": "The kind of the device usually of the form 'vendor.com/device'",
|
||||
"type": "string"
|
||||
},
|
||||
"devices": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "The name of the device",
|
||||
"type": "string"
|
||||
},
|
||||
"containerEdits": {
|
||||
"$ref": "defs.json#/definitions/containerEdits"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"containerEdits"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cdiVersion",
|
||||
"kind",
|
||||
"devices"
|
||||
]
|
||||
}
|
57
vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/config.go
generated
vendored
Normal file
57
vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/config.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package specs
|
||||
|
||||
import "os"
|
||||
|
||||
// CurrentVersion is the current version of the Spec.
|
||||
const CurrentVersion = "0.3.0"
|
||||
|
||||
// Spec is the base configuration for CDI
|
||||
type Spec struct {
|
||||
Version string `json:"cdiVersion"`
|
||||
Kind string `json:"kind"`
|
||||
|
||||
Devices []Device `json:"devices"`
|
||||
ContainerEdits ContainerEdits `json:"containerEdits,omitempty"`
|
||||
}
|
||||
|
||||
// Device is a "Device" a container runtime can add to a container
|
||||
type Device struct {
|
||||
Name string `json:"name"`
|
||||
ContainerEdits ContainerEdits `json:"containerEdits"`
|
||||
}
|
||||
|
||||
// ContainerEdits are edits a container runtime must make to the OCI spec to expose the device.
|
||||
type ContainerEdits struct {
|
||||
Env []string `json:"env,omitempty"`
|
||||
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty"`
|
||||
Hooks []*Hook `json:"hooks,omitempty"`
|
||||
Mounts []*Mount `json:"mounts,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceNode represents a device node that needs to be added to the OCI spec.
|
||||
type DeviceNode struct {
|
||||
Path string `json:"path"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Major int64 `json:"major,omitempty"`
|
||||
Minor int64 `json:"minor,omitempty"`
|
||||
FileMode *os.FileMode `json:"fileMode,omitempty"`
|
||||
Permissions string `json:"permissions,omitempty"`
|
||||
UID *uint32 `json:"uid,omitempty"`
|
||||
GID *uint32 `json:"gid,omitempty"`
|
||||
}
|
||||
|
||||
// Mount represents a mount that needs to be added to the OCI spec.
|
||||
type Mount struct {
|
||||
HostPath string `json:"hostPath"`
|
||||
ContainerPath string `json:"containerPath"`
|
||||
Options []string `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
// Hook represents a hook that needs to be added to the OCI spec.
|
||||
type Hook struct {
|
||||
HookName string `json:"hookName"`
|
||||
Path string `json:"path"`
|
||||
Args []string `json:"args,omitempty"`
|
||||
Env []string `json:"env,omitempty"`
|
||||
Timeout *int `json:"timeout,omitempty"`
|
||||
}
|
112
vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/oci.go
generated
vendored
Normal file
112
vendor/github.com/container-orchestrated-devices/container-device-interface/specs-go/oci.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
package specs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// ApplyOCIEditsForDevice applies devices OCI edits, in other words
|
||||
// it finds the device in the CDI spec and applies the OCI patches that device
|
||||
// requires to the OCI specification.
|
||||
func ApplyOCIEditsForDevice(config *spec.Spec, cdi *Spec, dev string) error {
|
||||
for _, d := range cdi.Devices {
|
||||
if d.Name != dev {
|
||||
continue
|
||||
}
|
||||
|
||||
return ApplyEditsToOCISpec(config, &d.ContainerEdits)
|
||||
}
|
||||
|
||||
return fmt.Errorf("CDI: device %q not found for spec %q", dev, cdi.Kind)
|
||||
}
|
||||
|
||||
// ApplyOCIEdits applies the OCI edits the CDI spec declares globablly
|
||||
func ApplyOCIEdits(config *spec.Spec, cdi *Spec) error {
|
||||
return ApplyEditsToOCISpec(config, &cdi.ContainerEdits)
|
||||
}
|
||||
|
||||
// ApplyEditsToOCISpec applies the specified edits to the OCI spec.
|
||||
func ApplyEditsToOCISpec(config *spec.Spec, edits *ContainerEdits) error {
|
||||
if config == nil {
|
||||
return errors.New("spec is nil")
|
||||
}
|
||||
if edits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(edits.Env) > 0 {
|
||||
if config.Process == nil {
|
||||
config.Process = &spec.Process{}
|
||||
}
|
||||
config.Process.Env = append(config.Process.Env, edits.Env...)
|
||||
}
|
||||
|
||||
for _, d := range edits.DeviceNodes {
|
||||
if config.Linux == nil {
|
||||
config.Linux = &spec.Linux{}
|
||||
}
|
||||
config.Linux.Devices = append(config.Linux.Devices, d.ToOCI())
|
||||
}
|
||||
|
||||
for _, m := range edits.Mounts {
|
||||
config.Mounts = append(config.Mounts, m.ToOCI())
|
||||
}
|
||||
|
||||
for _, h := range edits.Hooks {
|
||||
if config.Hooks == nil {
|
||||
config.Hooks = &spec.Hooks{}
|
||||
}
|
||||
switch h.HookName {
|
||||
case "prestart":
|
||||
config.Hooks.Prestart = append(config.Hooks.Prestart, h.ToOCI())
|
||||
case "createRuntime":
|
||||
config.Hooks.CreateRuntime = append(config.Hooks.CreateRuntime, h.ToOCI())
|
||||
case "createContainer":
|
||||
config.Hooks.CreateContainer = append(config.Hooks.CreateContainer, h.ToOCI())
|
||||
case "startContainer":
|
||||
config.Hooks.StartContainer = append(config.Hooks.StartContainer, h.ToOCI())
|
||||
case "poststart":
|
||||
config.Hooks.Poststart = append(config.Hooks.Poststart, h.ToOCI())
|
||||
case "poststop":
|
||||
config.Hooks.Poststop = append(config.Hooks.Poststop, h.ToOCI())
|
||||
default:
|
||||
fmt.Printf("CDI: Unknown hook %q\n", h.HookName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToOCI returns the opencontainers runtime Spec Hook for this Hook.
|
||||
func (h *Hook) ToOCI() spec.Hook {
|
||||
return spec.Hook{
|
||||
Path: h.Path,
|
||||
Args: h.Args,
|
||||
Env: h.Env,
|
||||
Timeout: h.Timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// ToOCI returns the opencontainers runtime Spec Mount for this Mount.
|
||||
func (m *Mount) ToOCI() spec.Mount {
|
||||
return spec.Mount{
|
||||
Source: m.HostPath,
|
||||
Destination: m.ContainerPath,
|
||||
Options: m.Options,
|
||||
}
|
||||
}
|
||||
|
||||
// ToOCI returns the opencontainers runtime Spec LinuxDevice for this DeviceNode.
|
||||
func (d *DeviceNode) ToOCI() spec.LinuxDevice {
|
||||
return spec.LinuxDevice{
|
||||
Path: d.Path,
|
||||
Type: d.Type,
|
||||
Major: d.Major,
|
||||
Minor: d.Minor,
|
||||
FileMode: d.FileMode,
|
||||
UID: d.UID,
|
||||
GID: d.GID,
|
||||
}
|
||||
}
|
174
vendor/github.com/opencontainers/runc/libcontainer/devices/device.go
generated
vendored
Normal file
174
vendor/github.com/opencontainers/runc/libcontainer/devices/device.go
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
package devices
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
Wildcard = -1
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
Rule
|
||||
|
||||
// Path to the device.
|
||||
Path string `json:"path"`
|
||||
|
||||
// FileMode permission bits for the device.
|
||||
FileMode os.FileMode `json:"file_mode"`
|
||||
|
||||
// Uid of the device.
|
||||
Uid uint32 `json:"uid"`
|
||||
|
||||
// Gid of the device.
|
||||
Gid uint32 `json:"gid"`
|
||||
}
|
||||
|
||||
// Permissions is a cgroupv1-style string to represent device access. It
|
||||
// has to be a string for backward compatibility reasons, hence why it has
|
||||
// methods to do set operations.
|
||||
type Permissions string
|
||||
|
||||
const (
|
||||
deviceRead uint = (1 << iota)
|
||||
deviceWrite
|
||||
deviceMknod
|
||||
)
|
||||
|
||||
func (p Permissions) toSet() uint {
|
||||
var set uint
|
||||
for _, perm := range p {
|
||||
switch perm {
|
||||
case 'r':
|
||||
set |= deviceRead
|
||||
case 'w':
|
||||
set |= deviceWrite
|
||||
case 'm':
|
||||
set |= deviceMknod
|
||||
}
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func fromSet(set uint) Permissions {
|
||||
var perm string
|
||||
if set&deviceRead == deviceRead {
|
||||
perm += "r"
|
||||
}
|
||||
if set&deviceWrite == deviceWrite {
|
||||
perm += "w"
|
||||
}
|
||||
if set&deviceMknod == deviceMknod {
|
||||
perm += "m"
|
||||
}
|
||||
return Permissions(perm)
|
||||
}
|
||||
|
||||
// Union returns the union of the two sets of Permissions.
|
||||
func (p Permissions) Union(o Permissions) Permissions {
|
||||
lhs := p.toSet()
|
||||
rhs := o.toSet()
|
||||
return fromSet(lhs | rhs)
|
||||
}
|
||||
|
||||
// Difference returns the set difference of the two sets of Permissions.
|
||||
// In set notation, A.Difference(B) gives you A\B.
|
||||
func (p Permissions) Difference(o Permissions) Permissions {
|
||||
lhs := p.toSet()
|
||||
rhs := o.toSet()
|
||||
return fromSet(lhs &^ rhs)
|
||||
}
|
||||
|
||||
// Intersection computes the intersection of the two sets of Permissions.
|
||||
func (p Permissions) Intersection(o Permissions) Permissions {
|
||||
lhs := p.toSet()
|
||||
rhs := o.toSet()
|
||||
return fromSet(lhs & rhs)
|
||||
}
|
||||
|
||||
// IsEmpty returns whether the set of permissions in a Permissions is
|
||||
// empty.
|
||||
func (p Permissions) IsEmpty() bool {
|
||||
return p == Permissions("")
|
||||
}
|
||||
|
||||
// IsValid returns whether the set of permissions is a subset of valid
|
||||
// permissions (namely, {r,w,m}).
|
||||
func (p Permissions) IsValid() bool {
|
||||
return p == fromSet(p.toSet())
|
||||
}
|
||||
|
||||
type Type rune
|
||||
|
||||
const (
|
||||
WildcardDevice Type = 'a'
|
||||
BlockDevice Type = 'b'
|
||||
CharDevice Type = 'c' // or 'u'
|
||||
FifoDevice Type = 'p'
|
||||
)
|
||||
|
||||
func (t Type) IsValid() bool {
|
||||
switch t {
|
||||
case WildcardDevice, BlockDevice, CharDevice, FifoDevice:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (t Type) CanMknod() bool {
|
||||
switch t {
|
||||
case BlockDevice, CharDevice, FifoDevice:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (t Type) CanCgroup() bool {
|
||||
switch t {
|
||||
case WildcardDevice, BlockDevice, CharDevice:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
// Type of device ('c' for char, 'b' for block). If set to 'a', this rule
|
||||
// acts as a wildcard and all fields other than Allow are ignored.
|
||||
Type Type `json:"type"`
|
||||
|
||||
// Major is the device's major number.
|
||||
Major int64 `json:"major"`
|
||||
|
||||
// Minor is the device's minor number.
|
||||
Minor int64 `json:"minor"`
|
||||
|
||||
// Permissions is the set of permissions that this rule applies to (in the
|
||||
// cgroupv1 format -- any combination of "rwm").
|
||||
Permissions Permissions `json:"permissions"`
|
||||
|
||||
// Allow specifies whether this rule is allowed.
|
||||
Allow bool `json:"allow"`
|
||||
}
|
||||
|
||||
func (d *Rule) CgroupString() string {
|
||||
var (
|
||||
major = strconv.FormatInt(d.Major, 10)
|
||||
minor = strconv.FormatInt(d.Minor, 10)
|
||||
)
|
||||
if d.Major == Wildcard {
|
||||
major = "*"
|
||||
}
|
||||
if d.Minor == Wildcard {
|
||||
minor = "*"
|
||||
}
|
||||
return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions)
|
||||
}
|
||||
|
||||
func (d *Rule) Mkdev() (uint64, error) {
|
||||
return mkDev(d)
|
||||
}
|
120
vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go
generated
vendored
Normal file
120
vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package devices
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ErrNotADevice denotes that a file is not a valid linux device.
|
||||
var ErrNotADevice = errors.New("not a device node")
|
||||
|
||||
// Testing dependencies
|
||||
var (
|
||||
unixLstat = unix.Lstat
|
||||
osReadDir = os.ReadDir
|
||||
)
|
||||
|
||||
func mkDev(d *Rule) (uint64, error) {
|
||||
if d.Major == Wildcard || d.Minor == Wildcard {
|
||||
return 0, errors.New("cannot mkdev() device with wildcards")
|
||||
}
|
||||
return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil
|
||||
}
|
||||
|
||||
// DeviceFromPath takes the path to a device and its cgroup_permissions (which
|
||||
// cannot be easily queried) to look up the information about a linux device
|
||||
// and returns that information as a Device struct.
|
||||
func DeviceFromPath(path, permissions string) (*Device, error) {
|
||||
var stat unix.Stat_t
|
||||
err := unixLstat(path, &stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
devType Type
|
||||
mode = stat.Mode
|
||||
devNumber = uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS.
|
||||
major = unix.Major(devNumber)
|
||||
minor = unix.Minor(devNumber)
|
||||
)
|
||||
switch mode & unix.S_IFMT {
|
||||
case unix.S_IFBLK:
|
||||
devType = BlockDevice
|
||||
case unix.S_IFCHR:
|
||||
devType = CharDevice
|
||||
case unix.S_IFIFO:
|
||||
devType = FifoDevice
|
||||
default:
|
||||
return nil, ErrNotADevice
|
||||
}
|
||||
return &Device{
|
||||
Rule: Rule{
|
||||
Type: devType,
|
||||
Major: int64(major),
|
||||
Minor: int64(minor),
|
||||
Permissions: Permissions(permissions),
|
||||
},
|
||||
Path: path,
|
||||
FileMode: os.FileMode(mode &^ unix.S_IFMT),
|
||||
Uid: stat.Uid,
|
||||
Gid: stat.Gid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HostDevices returns all devices that can be found under /dev directory.
|
||||
func HostDevices() ([]*Device, error) {
|
||||
return GetDevices("/dev")
|
||||
}
|
||||
|
||||
// GetDevices recursively traverses a directory specified by path
|
||||
// and returns all devices found there.
|
||||
func GetDevices(path string) ([]*Device, error) {
|
||||
files, err := osReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var out []*Device
|
||||
for _, f := range files {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
|
||||
// ".udev" added to address https://github.com/opencontainers/runc/issues/2093
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
|
||||
continue
|
||||
default:
|
||||
sub, err := GetDevices(filepath.Join(path, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, sub...)
|
||||
continue
|
||||
}
|
||||
case f.Name() == "console":
|
||||
continue
|
||||
}
|
||||
device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNotADevice) {
|
||||
continue
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if device.Type == FifoDevice {
|
||||
continue
|
||||
}
|
||||
out = append(out, device)
|
||||
}
|
||||
return out, nil
|
||||
}
|
191
vendor/github.com/opencontainers/runtime-tools/LICENSE
generated
vendored
Normal file
191
vendor/github.com/opencontainers/runtime-tools/LICENSE
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
|
||||
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
|
||||
|
||||
Copyright 2015 The Linux Foundation.
|
||||
|
||||
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.
|
122
vendor/github.com/opencontainers/runtime-tools/error/error.go
generated
vendored
Normal file
122
vendor/github.com/opencontainers/runtime-tools/error/error.go
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
// 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
Normal file
48
vendor/github.com/opencontainers/runtime-tools/filepath/abs.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
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
Normal file
32
vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
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
Normal file
74
vendor/github.com/opencontainers/runtime-tools/filepath/clean.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
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
Normal file
6
vendor/github.com/opencontainers/runtime-tools/filepath/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// 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
Normal file
9
vendor/github.com/opencontainers/runtime-tools/filepath/join.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
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
Normal file
9
vendor/github.com/opencontainers/runtime-tools/filepath/separator.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package filepath
|
||||
|
||||
// Separator is an explicit-OS version of path/filepath's Separator.
|
||||
func Separator(os string) rune {
|
||||
if os == "windows" {
|
||||
return '\\'
|
||||
}
|
||||
return '/'
|
||||
}
|
208
vendor/github.com/opencontainers/runtime-tools/generate/config.go
generated
vendored
Normal file
208
vendor/github.com/opencontainers/runtime-tools/generate/config.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func (g *Generator) initConfig() {
|
||||
if g.Config == nil {
|
||||
g.Config = &rspec.Spec{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigProcess() {
|
||||
g.initConfig()
|
||||
if g.Config.Process == nil {
|
||||
g.Config.Process = &rspec.Process{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigProcessConsoleSize() {
|
||||
g.initConfigProcess()
|
||||
if g.Config.Process.ConsoleSize == nil {
|
||||
g.Config.Process.ConsoleSize = &rspec.Box{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigProcessCapabilities() {
|
||||
g.initConfigProcess()
|
||||
if g.Config.Process.Capabilities == nil {
|
||||
g.Config.Process.Capabilities = &rspec.LinuxCapabilities{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigRoot() {
|
||||
g.initConfig()
|
||||
if g.Config.Root == nil {
|
||||
g.Config.Root = &rspec.Root{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigAnnotations() {
|
||||
g.initConfig()
|
||||
if g.Config.Annotations == nil {
|
||||
g.Config.Annotations = make(map[string]string)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigHooks() {
|
||||
g.initConfig()
|
||||
if g.Config.Hooks == nil {
|
||||
g.Config.Hooks = &rspec.Hooks{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinux() {
|
||||
g.initConfig()
|
||||
if g.Config.Linux == nil {
|
||||
g.Config.Linux = &rspec.Linux{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxIntelRdt() {
|
||||
g.initConfigLinux()
|
||||
if g.Config.Linux.IntelRdt == nil {
|
||||
g.Config.Linux.IntelRdt = &rspec.LinuxIntelRdt{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxSysctl() {
|
||||
g.initConfigLinux()
|
||||
if g.Config.Linux.Sysctl == nil {
|
||||
g.Config.Linux.Sysctl = make(map[string]string)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxSeccomp() {
|
||||
g.initConfigLinux()
|
||||
if g.Config.Linux.Seccomp == nil {
|
||||
g.Config.Linux.Seccomp = &rspec.LinuxSeccomp{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxResources() {
|
||||
g.initConfigLinux()
|
||||
if g.Config.Linux.Resources == nil {
|
||||
g.Config.Linux.Resources = &rspec.LinuxResources{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxResourcesBlockIO() {
|
||||
g.initConfigLinuxResources()
|
||||
if g.Config.Linux.Resources.BlockIO == nil {
|
||||
g.Config.Linux.Resources.BlockIO = &rspec.LinuxBlockIO{}
|
||||
}
|
||||
}
|
||||
|
||||
// InitConfigLinuxResourcesCPU initializes CPU of Linux resources
|
||||
func (g *Generator) InitConfigLinuxResourcesCPU() {
|
||||
g.initConfigLinuxResources()
|
||||
if g.Config.Linux.Resources.CPU == nil {
|
||||
g.Config.Linux.Resources.CPU = &rspec.LinuxCPU{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxResourcesMemory() {
|
||||
g.initConfigLinuxResources()
|
||||
if g.Config.Linux.Resources.Memory == nil {
|
||||
g.Config.Linux.Resources.Memory = &rspec.LinuxMemory{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxResourcesNetwork() {
|
||||
g.initConfigLinuxResources()
|
||||
if g.Config.Linux.Resources.Network == nil {
|
||||
g.Config.Linux.Resources.Network = &rspec.LinuxNetwork{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigLinuxResourcesPids() {
|
||||
g.initConfigLinuxResources()
|
||||
if g.Config.Linux.Resources.Pids == nil {
|
||||
g.Config.Linux.Resources.Pids = &rspec.LinuxPids{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigSolaris() {
|
||||
g.initConfig()
|
||||
if g.Config.Solaris == nil {
|
||||
g.Config.Solaris = &rspec.Solaris{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigSolarisCappedCPU() {
|
||||
g.initConfigSolaris()
|
||||
if g.Config.Solaris.CappedCPU == nil {
|
||||
g.Config.Solaris.CappedCPU = &rspec.SolarisCappedCPU{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigSolarisCappedMemory() {
|
||||
g.initConfigSolaris()
|
||||
if g.Config.Solaris.CappedMemory == nil {
|
||||
g.Config.Solaris.CappedMemory = &rspec.SolarisCappedMemory{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigWindows() {
|
||||
g.initConfig()
|
||||
if g.Config.Windows == nil {
|
||||
g.Config.Windows = &rspec.Windows{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigWindowsNetwork() {
|
||||
g.initConfigWindows()
|
||||
if g.Config.Windows.Network == nil {
|
||||
g.Config.Windows.Network = &rspec.WindowsNetwork{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigWindowsHyperV() {
|
||||
g.initConfigWindows()
|
||||
if g.Config.Windows.HyperV == nil {
|
||||
g.Config.Windows.HyperV = &rspec.WindowsHyperV{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigWindowsResources() {
|
||||
g.initConfigWindows()
|
||||
if g.Config.Windows.Resources == nil {
|
||||
g.Config.Windows.Resources = &rspec.WindowsResources{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigWindowsResourcesMemory() {
|
||||
g.initConfigWindowsResources()
|
||||
if g.Config.Windows.Resources.Memory == nil {
|
||||
g.Config.Windows.Resources.Memory = &rspec.WindowsMemoryResources{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigVM() {
|
||||
g.initConfig()
|
||||
if g.Config.VM == nil {
|
||||
g.Config.VM = &rspec.VM{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigVMHypervisor() {
|
||||
g.initConfigVM()
|
||||
if &g.Config.VM.Hypervisor == nil {
|
||||
g.Config.VM.Hypervisor = rspec.VMHypervisor{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigVMKernel() {
|
||||
g.initConfigVM()
|
||||
if &g.Config.VM.Kernel == nil {
|
||||
g.Config.VM.Kernel = rspec.VMKernel{}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initConfigVMImage() {
|
||||
g.initConfigVM()
|
||||
if &g.Config.VM.Image == nil {
|
||||
g.Config.VM.Image = rspec.VMImage{}
|
||||
}
|
||||
}
|
1832
vendor/github.com/opencontainers/runtime-tools/generate/generate.go
generated
vendored
Normal file
1832
vendor/github.com/opencontainers/runtime-tools/generate/generate.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go
generated
vendored
Normal file
12
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package seccomp
|
||||
|
||||
const (
|
||||
seccompOverwrite = "overwrite"
|
||||
seccompAppend = "append"
|
||||
nothing = "nothing"
|
||||
kill = "kill"
|
||||
trap = "trap"
|
||||
trace = "trace"
|
||||
allow = "allow"
|
||||
errno = "errno"
|
||||
)
|
135
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go
generated
vendored
Normal file
135
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// SyscallOpts contain options for parsing syscall rules
|
||||
type SyscallOpts struct {
|
||||
Action string
|
||||
Syscall string
|
||||
Index string
|
||||
Value string
|
||||
ValueTwo string
|
||||
Operator string
|
||||
}
|
||||
|
||||
// ParseSyscallFlag takes a SyscallOpts struct and the seccomp configuration
|
||||
// and sets the new syscall rule accordingly
|
||||
func ParseSyscallFlag(args SyscallOpts, config *rspec.LinuxSeccomp) error {
|
||||
var arguments []string
|
||||
if args.Index != "" && args.Value != "" && args.ValueTwo != "" && args.Operator != "" {
|
||||
arguments = []string{args.Action, args.Syscall, args.Index, args.Value,
|
||||
args.ValueTwo, args.Operator}
|
||||
} else {
|
||||
arguments = []string{args.Action, args.Syscall}
|
||||
}
|
||||
|
||||
action, _ := parseAction(arguments[0])
|
||||
if action == config.DefaultAction && args.argsAreEmpty() {
|
||||
// default already set, no need to make changes
|
||||
return nil
|
||||
}
|
||||
|
||||
var newSyscall rspec.LinuxSyscall
|
||||
numOfArgs := len(arguments)
|
||||
if numOfArgs == 6 || numOfArgs == 2 {
|
||||
argStruct, err := parseArguments(arguments[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newSyscall = newSyscallStruct(arguments[1], action, argStruct)
|
||||
} else {
|
||||
return fmt.Errorf("incorrect number of arguments to ParseSyscall: %d", numOfArgs)
|
||||
}
|
||||
|
||||
descison, err := decideCourseOfAction(&newSyscall, config.Syscalls)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delimDescison := strings.Split(descison, ":")
|
||||
|
||||
if delimDescison[0] == seccompAppend {
|
||||
config.Syscalls = append(config.Syscalls, newSyscall)
|
||||
}
|
||||
|
||||
if delimDescison[0] == seccompOverwrite {
|
||||
indexForOverwrite, err := strconv.ParseInt(delimDescison[1], 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.Syscalls[indexForOverwrite] = newSyscall
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var actions = map[string]rspec.LinuxSeccompAction{
|
||||
"allow": rspec.ActAllow,
|
||||
"errno": rspec.ActErrno,
|
||||
"kill": rspec.ActKill,
|
||||
"trace": rspec.ActTrace,
|
||||
"trap": rspec.ActTrap,
|
||||
}
|
||||
|
||||
// Take passed action, return the SCMP_ACT_<ACTION> version of it
|
||||
func parseAction(action string) (rspec.LinuxSeccompAction, error) {
|
||||
a, ok := actions[action]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unrecognized action: %s", action)
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// ParseDefaultAction sets the default action of the seccomp configuration
|
||||
// and then removes any rules that were already specified with this action
|
||||
func ParseDefaultAction(action string, config *rspec.LinuxSeccomp) error {
|
||||
if action == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultAction, err := parseAction(action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.DefaultAction = defaultAction
|
||||
err = RemoveAllMatchingRules(config, defaultAction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseDefaultActionForce simply sets the default action of the seccomp configuration
|
||||
func ParseDefaultActionForce(action string, config *rspec.LinuxSeccomp) error {
|
||||
if action == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultAction, err := parseAction(action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.DefaultAction = defaultAction
|
||||
return nil
|
||||
}
|
||||
|
||||
func newSyscallStruct(name string, action rspec.LinuxSeccompAction, args []rspec.LinuxSeccompArg) rspec.LinuxSyscall {
|
||||
syscallStruct := rspec.LinuxSyscall{
|
||||
Names: []string{name},
|
||||
Action: action,
|
||||
Args: args,
|
||||
}
|
||||
return syscallStruct
|
||||
}
|
||||
|
||||
func (s SyscallOpts) argsAreEmpty() bool {
|
||||
return (s.Index == "" &&
|
||||
s.Value == "" &&
|
||||
s.ValueTwo == "" &&
|
||||
s.Operator == "")
|
||||
}
|
55
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go
generated
vendored
Normal file
55
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// ParseArchitectureFlag takes the raw string passed with the --arch flag, parses it
|
||||
// and updates the Seccomp config accordingly
|
||||
func ParseArchitectureFlag(architectureArg string, config *rspec.LinuxSeccomp) error {
|
||||
correctedArch, err := parseArch(architectureArg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
shouldAppend := true
|
||||
for _, alreadySpecified := range config.Architectures {
|
||||
if correctedArch == alreadySpecified {
|
||||
shouldAppend = false
|
||||
}
|
||||
}
|
||||
if shouldAppend {
|
||||
config.Architectures = append(config.Architectures, correctedArch)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseArch(arch string) (rspec.Arch, error) {
|
||||
arches := map[string]rspec.Arch{
|
||||
"x86": rspec.ArchX86,
|
||||
"amd64": rspec.ArchX86_64,
|
||||
"x32": rspec.ArchX32,
|
||||
"arm": rspec.ArchARM,
|
||||
"arm64": rspec.ArchAARCH64,
|
||||
"mips": rspec.ArchMIPS,
|
||||
"mips64": rspec.ArchMIPS64,
|
||||
"mips64n32": rspec.ArchMIPS64N32,
|
||||
"mipsel": rspec.ArchMIPSEL,
|
||||
"mipsel64": rspec.ArchMIPSEL64,
|
||||
"mipsel64n32": rspec.ArchMIPSEL64N32,
|
||||
"parisc": rspec.ArchPARISC,
|
||||
"parisc64": rspec.ArchPARISC64,
|
||||
"ppc": rspec.ArchPPC,
|
||||
"ppc64": rspec.ArchPPC64,
|
||||
"ppc64le": rspec.ArchPPC64LE,
|
||||
"s390": rspec.ArchS390,
|
||||
"s390x": rspec.ArchS390X,
|
||||
}
|
||||
a, ok := arches[arch]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unrecognized architecture: %s", arch)
|
||||
}
|
||||
return a, nil
|
||||
}
|
73
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go
generated
vendored
Normal file
73
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// parseArguments takes a list of arguments (delimArgs). It parses and fills out
|
||||
// the argument information and returns a slice of arg structs
|
||||
func parseArguments(delimArgs []string) ([]rspec.LinuxSeccompArg, error) {
|
||||
nilArgSlice := []rspec.LinuxSeccompArg{}
|
||||
numberOfArgs := len(delimArgs)
|
||||
|
||||
// No parameters passed with syscall
|
||||
if numberOfArgs == 1 {
|
||||
return nilArgSlice, nil
|
||||
}
|
||||
|
||||
// Correct number of parameters passed with syscall
|
||||
if numberOfArgs == 5 {
|
||||
syscallIndex, err := strconv.ParseUint(delimArgs[1], 10, 0)
|
||||
if err != nil {
|
||||
return nilArgSlice, err
|
||||
}
|
||||
|
||||
syscallValue, err := strconv.ParseUint(delimArgs[2], 10, 64)
|
||||
if err != nil {
|
||||
return nilArgSlice, err
|
||||
}
|
||||
|
||||
syscallValueTwo, err := strconv.ParseUint(delimArgs[3], 10, 64)
|
||||
if err != nil {
|
||||
return nilArgSlice, err
|
||||
}
|
||||
|
||||
syscallOp, err := parseOperator(delimArgs[4])
|
||||
if err != nil {
|
||||
return nilArgSlice, err
|
||||
}
|
||||
|
||||
argStruct := rspec.LinuxSeccompArg{
|
||||
Index: uint(syscallIndex),
|
||||
Value: syscallValue,
|
||||
ValueTwo: syscallValueTwo,
|
||||
Op: syscallOp,
|
||||
}
|
||||
|
||||
argSlice := []rspec.LinuxSeccompArg{}
|
||||
argSlice = append(argSlice, argStruct)
|
||||
return argSlice, nil
|
||||
}
|
||||
|
||||
return nilArgSlice, fmt.Errorf("incorrect number of arguments passed with syscall: %d", numberOfArgs)
|
||||
}
|
||||
|
||||
func parseOperator(operator string) (rspec.LinuxSeccompOperator, error) {
|
||||
operators := map[string]rspec.LinuxSeccompOperator{
|
||||
"NE": rspec.OpNotEqual,
|
||||
"LT": rspec.OpLessThan,
|
||||
"LE": rspec.OpLessEqual,
|
||||
"EQ": rspec.OpEqualTo,
|
||||
"GE": rspec.OpGreaterEqual,
|
||||
"GT": rspec.OpGreaterThan,
|
||||
"ME": rspec.OpMaskedEqual,
|
||||
}
|
||||
o, ok := operators[operator]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unrecognized operator: %s", operator)
|
||||
}
|
||||
return o, nil
|
||||
}
|
52
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go
generated
vendored
Normal file
52
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// RemoveAction takes the argument string that was passed with the --remove flag,
|
||||
// parses it, and updates the Seccomp config accordingly
|
||||
func RemoveAction(arguments string, config *rspec.LinuxSeccomp) error {
|
||||
if config == nil {
|
||||
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
|
||||
}
|
||||
|
||||
syscallsToRemove := strings.Split(arguments, ",")
|
||||
|
||||
for counter, syscallStruct := range config.Syscalls {
|
||||
if reflect.DeepEqual(syscallsToRemove, syscallStruct.Names) {
|
||||
config.Syscalls = append(config.Syscalls[:counter], config.Syscalls[counter+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveAllSeccompRules removes all seccomp syscall rules
|
||||
func RemoveAllSeccompRules(config *rspec.LinuxSeccomp) error {
|
||||
if config == nil {
|
||||
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
|
||||
}
|
||||
newSyscallSlice := []rspec.LinuxSyscall{}
|
||||
config.Syscalls = newSyscallSlice
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveAllMatchingRules will remove any syscall rules that match the specified action
|
||||
func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, seccompAction rspec.LinuxSeccompAction) error {
|
||||
if config == nil {
|
||||
return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
|
||||
}
|
||||
|
||||
for _, syscall := range config.Syscalls {
|
||||
if reflect.DeepEqual(syscall.Action, seccompAction) {
|
||||
RemoveAction(strings.Join(syscall.Names, ","), config)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
576
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
generated
vendored
Normal file
576
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
generated
vendored
Normal file
@ -0,0 +1,576 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func arches() []rspec.Arch {
|
||||
native := runtime.GOARCH
|
||||
|
||||
switch native {
|
||||
case "amd64":
|
||||
return []rspec.Arch{rspec.ArchX86_64, rspec.ArchX86, rspec.ArchX32}
|
||||
case "arm64":
|
||||
return []rspec.Arch{rspec.ArchARM, rspec.ArchAARCH64}
|
||||
case "mips64":
|
||||
return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32}
|
||||
case "mips64n32":
|
||||
return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32}
|
||||
case "mipsel64":
|
||||
return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32}
|
||||
case "mipsel64n32":
|
||||
return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32}
|
||||
case "s390x":
|
||||
return []rspec.Arch{rspec.ArchS390, rspec.ArchS390X}
|
||||
default:
|
||||
return []rspec.Arch{}
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultProfile defines the whitelist for the default seccomp profile.
|
||||
func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp {
|
||||
|
||||
syscalls := []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"accept",
|
||||
"accept4",
|
||||
"access",
|
||||
"alarm",
|
||||
"bind",
|
||||
"brk",
|
||||
"capget",
|
||||
"capset",
|
||||
"chdir",
|
||||
"chmod",
|
||||
"chown",
|
||||
"chown32",
|
||||
"clock_getres",
|
||||
"clock_gettime",
|
||||
"clock_nanosleep",
|
||||
"close",
|
||||
"connect",
|
||||
"copy_file_range",
|
||||
"creat",
|
||||
"dup",
|
||||
"dup2",
|
||||
"dup3",
|
||||
"epoll_create",
|
||||
"epoll_create1",
|
||||
"epoll_ctl",
|
||||
"epoll_ctl_old",
|
||||
"epoll_pwait",
|
||||
"epoll_wait",
|
||||
"epoll_wait_old",
|
||||
"eventfd",
|
||||
"eventfd2",
|
||||
"execve",
|
||||
"execveat",
|
||||
"exit",
|
||||
"exit_group",
|
||||
"faccessat",
|
||||
"fadvise64",
|
||||
"fadvise64_64",
|
||||
"fallocate",
|
||||
"fanotify_mark",
|
||||
"fchdir",
|
||||
"fchmod",
|
||||
"fchmodat",
|
||||
"fchown",
|
||||
"fchown32",
|
||||
"fchownat",
|
||||
"fcntl",
|
||||
"fcntl64",
|
||||
"fdatasync",
|
||||
"fgetxattr",
|
||||
"flistxattr",
|
||||
"flock",
|
||||
"fork",
|
||||
"fremovexattr",
|
||||
"fsetxattr",
|
||||
"fstat",
|
||||
"fstat64",
|
||||
"fstatat64",
|
||||
"fstatfs",
|
||||
"fstatfs64",
|
||||
"fsync",
|
||||
"ftruncate",
|
||||
"ftruncate64",
|
||||
"futex",
|
||||
"futimesat",
|
||||
"getcpu",
|
||||
"getcwd",
|
||||
"getdents",
|
||||
"getdents64",
|
||||
"getegid",
|
||||
"getegid32",
|
||||
"geteuid",
|
||||
"geteuid32",
|
||||
"getgid",
|
||||
"getgid32",
|
||||
"getgroups",
|
||||
"getgroups32",
|
||||
"getitimer",
|
||||
"getpeername",
|
||||
"getpgid",
|
||||
"getpgrp",
|
||||
"getpid",
|
||||
"getppid",
|
||||
"getpriority",
|
||||
"getrandom",
|
||||
"getresgid",
|
||||
"getresgid32",
|
||||
"getresuid",
|
||||
"getresuid32",
|
||||
"getrlimit",
|
||||
"get_robust_list",
|
||||
"getrusage",
|
||||
"getsid",
|
||||
"getsockname",
|
||||
"getsockopt",
|
||||
"get_thread_area",
|
||||
"gettid",
|
||||
"gettimeofday",
|
||||
"getuid",
|
||||
"getuid32",
|
||||
"getxattr",
|
||||
"inotify_add_watch",
|
||||
"inotify_init",
|
||||
"inotify_init1",
|
||||
"inotify_rm_watch",
|
||||
"io_cancel",
|
||||
"ioctl",
|
||||
"io_destroy",
|
||||
"io_getevents",
|
||||
"ioprio_get",
|
||||
"ioprio_set",
|
||||
"io_setup",
|
||||
"io_submit",
|
||||
"ipc",
|
||||
"kill",
|
||||
"lchown",
|
||||
"lchown32",
|
||||
"lgetxattr",
|
||||
"link",
|
||||
"linkat",
|
||||
"listen",
|
||||
"listxattr",
|
||||
"llistxattr",
|
||||
"_llseek",
|
||||
"lremovexattr",
|
||||
"lseek",
|
||||
"lsetxattr",
|
||||
"lstat",
|
||||
"lstat64",
|
||||
"madvise",
|
||||
"memfd_create",
|
||||
"mincore",
|
||||
"mkdir",
|
||||
"mkdirat",
|
||||
"mknod",
|
||||
"mknodat",
|
||||
"mlock",
|
||||
"mlock2",
|
||||
"mlockall",
|
||||
"mmap",
|
||||
"mmap2",
|
||||
"mprotect",
|
||||
"mq_getsetattr",
|
||||
"mq_notify",
|
||||
"mq_open",
|
||||
"mq_timedreceive",
|
||||
"mq_timedsend",
|
||||
"mq_unlink",
|
||||
"mremap",
|
||||
"msgctl",
|
||||
"msgget",
|
||||
"msgrcv",
|
||||
"msgsnd",
|
||||
"msync",
|
||||
"munlock",
|
||||
"munlockall",
|
||||
"munmap",
|
||||
"nanosleep",
|
||||
"newfstatat",
|
||||
"_newselect",
|
||||
"open",
|
||||
"openat",
|
||||
"pause",
|
||||
"pipe",
|
||||
"pipe2",
|
||||
"poll",
|
||||
"ppoll",
|
||||
"prctl",
|
||||
"pread64",
|
||||
"preadv",
|
||||
"prlimit64",
|
||||
"pselect6",
|
||||
"pwrite64",
|
||||
"pwritev",
|
||||
"read",
|
||||
"readahead",
|
||||
"readlink",
|
||||
"readlinkat",
|
||||
"readv",
|
||||
"recv",
|
||||
"recvfrom",
|
||||
"recvmmsg",
|
||||
"recvmsg",
|
||||
"remap_file_pages",
|
||||
"removexattr",
|
||||
"rename",
|
||||
"renameat",
|
||||
"renameat2",
|
||||
"restart_syscall",
|
||||
"rmdir",
|
||||
"rt_sigaction",
|
||||
"rt_sigpending",
|
||||
"rt_sigprocmask",
|
||||
"rt_sigqueueinfo",
|
||||
"rt_sigreturn",
|
||||
"rt_sigsuspend",
|
||||
"rt_sigtimedwait",
|
||||
"rt_tgsigqueueinfo",
|
||||
"sched_getaffinity",
|
||||
"sched_getattr",
|
||||
"sched_getparam",
|
||||
"sched_get_priority_max",
|
||||
"sched_get_priority_min",
|
||||
"sched_getscheduler",
|
||||
"sched_rr_get_interval",
|
||||
"sched_setaffinity",
|
||||
"sched_setattr",
|
||||
"sched_setparam",
|
||||
"sched_setscheduler",
|
||||
"sched_yield",
|
||||
"seccomp",
|
||||
"select",
|
||||
"semctl",
|
||||
"semget",
|
||||
"semop",
|
||||
"semtimedop",
|
||||
"send",
|
||||
"sendfile",
|
||||
"sendfile64",
|
||||
"sendmmsg",
|
||||
"sendmsg",
|
||||
"sendto",
|
||||
"setfsgid",
|
||||
"setfsgid32",
|
||||
"setfsuid",
|
||||
"setfsuid32",
|
||||
"setgid",
|
||||
"setgid32",
|
||||
"setgroups",
|
||||
"setgroups32",
|
||||
"setitimer",
|
||||
"setpgid",
|
||||
"setpriority",
|
||||
"setregid",
|
||||
"setregid32",
|
||||
"setresgid",
|
||||
"setresgid32",
|
||||
"setresuid",
|
||||
"setresuid32",
|
||||
"setreuid",
|
||||
"setreuid32",
|
||||
"setrlimit",
|
||||
"set_robust_list",
|
||||
"setsid",
|
||||
"setsockopt",
|
||||
"set_thread_area",
|
||||
"set_tid_address",
|
||||
"setuid",
|
||||
"setuid32",
|
||||
"setxattr",
|
||||
"shmat",
|
||||
"shmctl",
|
||||
"shmdt",
|
||||
"shmget",
|
||||
"shutdown",
|
||||
"sigaltstack",
|
||||
"signalfd",
|
||||
"signalfd4",
|
||||
"sigreturn",
|
||||
"socket",
|
||||
"socketcall",
|
||||
"socketpair",
|
||||
"splice",
|
||||
"stat",
|
||||
"stat64",
|
||||
"statfs",
|
||||
"statfs64",
|
||||
"symlink",
|
||||
"symlinkat",
|
||||
"sync",
|
||||
"sync_file_range",
|
||||
"syncfs",
|
||||
"sysinfo",
|
||||
"syslog",
|
||||
"tee",
|
||||
"tgkill",
|
||||
"time",
|
||||
"timer_create",
|
||||
"timer_delete",
|
||||
"timerfd_create",
|
||||
"timerfd_gettime",
|
||||
"timerfd_settime",
|
||||
"timer_getoverrun",
|
||||
"timer_gettime",
|
||||
"timer_settime",
|
||||
"times",
|
||||
"tkill",
|
||||
"truncate",
|
||||
"truncate64",
|
||||
"ugetrlimit",
|
||||
"umask",
|
||||
"uname",
|
||||
"unlink",
|
||||
"unlinkat",
|
||||
"utime",
|
||||
"utimensat",
|
||||
"utimes",
|
||||
"vfork",
|
||||
"vmsplice",
|
||||
"wait4",
|
||||
"waitid",
|
||||
"waitpid",
|
||||
"write",
|
||||
"writev",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
{
|
||||
Names: []string{"personality"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{
|
||||
{
|
||||
Index: 0,
|
||||
Value: 0x0,
|
||||
Op: rspec.OpEqualTo,
|
||||
},
|
||||
{
|
||||
Index: 0,
|
||||
Value: 0x0008,
|
||||
Op: rspec.OpEqualTo,
|
||||
},
|
||||
{
|
||||
Index: 0,
|
||||
Value: 0xffffffff,
|
||||
Op: rspec.OpEqualTo,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
var sysCloneFlagsIndex uint
|
||||
|
||||
capSysAdmin := false
|
||||
caps := make(map[string]bool)
|
||||
|
||||
for _, cap := range rs.Process.Capabilities.Bounding {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap := range rs.Process.Capabilities.Effective {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap := range rs.Process.Capabilities.Inheritable {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap := range rs.Process.Capabilities.Permitted {
|
||||
caps[cap] = true
|
||||
}
|
||||
for _, cap := range rs.Process.Capabilities.Ambient {
|
||||
caps[cap] = true
|
||||
}
|
||||
|
||||
for cap := range caps {
|
||||
switch cap {
|
||||
case "CAP_DAC_READ_SEARCH":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"open_by_handle_at"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_ADMIN":
|
||||
capSysAdmin = true
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"bpf",
|
||||
"clone",
|
||||
"fanotify_init",
|
||||
"lookup_dcookie",
|
||||
"mount",
|
||||
"name_to_handle_at",
|
||||
"perf_event_open",
|
||||
"setdomainname",
|
||||
"sethostname",
|
||||
"setns",
|
||||
"umount",
|
||||
"umount2",
|
||||
"unshare",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_BOOT":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"reboot"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_CHROOT":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"chroot"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_MODULE":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"delete_module",
|
||||
"init_module",
|
||||
"finit_module",
|
||||
"query_module",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_PACCT":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"acct"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_PTRACE":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"kcmp",
|
||||
"process_vm_readv",
|
||||
"process_vm_writev",
|
||||
"ptrace",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_RAWIO":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"iopl",
|
||||
"ioperm",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_TIME":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"settimeofday",
|
||||
"stime",
|
||||
"adjtimex",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "CAP_SYS_TTY_CONFIG":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"vhangup"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
}
|
||||
}
|
||||
|
||||
if !capSysAdmin {
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"clone"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{
|
||||
{
|
||||
Index: sysCloneFlagsIndex,
|
||||
Value: CloneNewNS | CloneNewUTS | CloneNewIPC | CloneNewUser | CloneNewPID | CloneNewNet,
|
||||
ValueTwo: 0,
|
||||
Op: rspec.OpMaskedEqual,
|
||||
},
|
||||
},
|
||||
},
|
||||
}...)
|
||||
|
||||
}
|
||||
|
||||
arch := runtime.GOARCH
|
||||
switch arch {
|
||||
case "arm", "arm64":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"breakpoint",
|
||||
"cacheflush",
|
||||
"set_tls",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "amd64", "x32":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"arch_prctl"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
fallthrough
|
||||
case "x86":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{"modify_ldt"},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
case "s390", "s390x":
|
||||
syscalls = append(syscalls, []rspec.LinuxSyscall{
|
||||
{
|
||||
Names: []string{
|
||||
"s390_pci_mmio_read",
|
||||
"s390_pci_mmio_write",
|
||||
"s390_runtime_instr",
|
||||
},
|
||||
Action: rspec.ActAllow,
|
||||
Args: []rspec.LinuxSeccompArg{},
|
||||
},
|
||||
}...)
|
||||
/* Flags parameter of the clone syscall is the 2nd on s390 */
|
||||
}
|
||||
|
||||
return &rspec.LinuxSeccomp{
|
||||
DefaultAction: rspec.ActErrno,
|
||||
Architectures: arches(),
|
||||
Syscalls: syscalls,
|
||||
}
|
||||
}
|
15
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go
generated
vendored
Normal file
15
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// +build linux
|
||||
|
||||
package seccomp
|
||||
|
||||
import "syscall"
|
||||
|
||||
// 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
|
||||
)
|
15
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go
generated
vendored
Normal file
15
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// +build !linux
|
||||
|
||||
package seccomp
|
||||
|
||||
// These are copied from linux/amd64 syscall values, as a reference for other
|
||||
// platforms to have access to
|
||||
const (
|
||||
CloneNewIPC = 0x8000000
|
||||
CloneNewNet = 0x40000000
|
||||
CloneNewNS = 0x20000
|
||||
CloneNewPID = 0x20000000
|
||||
CloneNewUser = 0x10000000
|
||||
CloneNewUTS = 0x4000000
|
||||
CloneNewCgroup = 0x02000000
|
||||
)
|
140
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go
generated
vendored
Normal file
140
vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// Determine if a new syscall rule should be appended, overwrite an existing rule
|
||||
// or if no action should be taken at all
|
||||
func decideCourseOfAction(newSyscall *rspec.LinuxSyscall, syscalls []rspec.LinuxSyscall) (string, error) {
|
||||
ruleForSyscallAlreadyExists := false
|
||||
|
||||
var sliceOfDeterminedActions []string
|
||||
for i, syscall := range syscalls {
|
||||
if sameName(&syscall, newSyscall) {
|
||||
ruleForSyscallAlreadyExists = true
|
||||
|
||||
if identical(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing)
|
||||
}
|
||||
|
||||
if sameAction(newSyscall, &syscall) {
|
||||
if bothHaveArgs(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
|
||||
}
|
||||
if onlyOneHasArgs(newSyscall, &syscall) {
|
||||
if firstParamOnlyHasArgs(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i))
|
||||
} else {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !sameAction(newSyscall, &syscall) {
|
||||
if bothHaveArgs(newSyscall, &syscall) {
|
||||
if sameArgs(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i))
|
||||
}
|
||||
if !sameArgs(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
|
||||
}
|
||||
}
|
||||
if onlyOneHasArgs(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
|
||||
}
|
||||
if neitherHasArgs(newSyscall, &syscall) {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ruleForSyscallAlreadyExists {
|
||||
sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
|
||||
}
|
||||
|
||||
// Nothing has highest priority
|
||||
for _, determinedAction := range sliceOfDeterminedActions {
|
||||
if determinedAction == nothing {
|
||||
return determinedAction, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite has second highest priority
|
||||
for _, determinedAction := range sliceOfDeterminedActions {
|
||||
if strings.Contains(determinedAction, seccompOverwrite) {
|
||||
return determinedAction, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Append has the lowest priority
|
||||
for _, determinedAction := range sliceOfDeterminedActions {
|
||||
if determinedAction == seccompAppend {
|
||||
return determinedAction, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Trouble determining action: %s", sliceOfDeterminedActions)
|
||||
}
|
||||
|
||||
func hasArguments(config *rspec.LinuxSyscall) bool {
|
||||
nilSyscall := new(rspec.LinuxSyscall)
|
||||
return !sameArgs(nilSyscall, config)
|
||||
}
|
||||
|
||||
func identical(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return reflect.DeepEqual(config1, config2)
|
||||
}
|
||||
|
||||
func identicalExceptAction(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
samename := sameName(config1, config2)
|
||||
sameAction := sameAction(config1, config2)
|
||||
sameArgs := sameArgs(config1, config2)
|
||||
|
||||
return samename && !sameAction && sameArgs
|
||||
}
|
||||
|
||||
func identicalExceptArgs(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
samename := sameName(config1, config2)
|
||||
sameAction := sameAction(config1, config2)
|
||||
sameArgs := sameArgs(config1, config2)
|
||||
|
||||
return samename && sameAction && !sameArgs
|
||||
}
|
||||
|
||||
func sameName(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return reflect.DeepEqual(config1.Names, config2.Names)
|
||||
}
|
||||
|
||||
func sameAction(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return config1.Action == config2.Action
|
||||
}
|
||||
|
||||
func sameArgs(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return reflect.DeepEqual(config1.Args, config2.Args)
|
||||
}
|
||||
|
||||
func bothHaveArgs(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return hasArguments(config1) && hasArguments(config2)
|
||||
}
|
||||
|
||||
func onlyOneHasArgs(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
conf1 := hasArguments(config1)
|
||||
conf2 := hasArguments(config2)
|
||||
|
||||
return (conf1 && !conf2) || (!conf1 && conf2)
|
||||
}
|
||||
|
||||
func neitherHasArgs(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return !hasArguments(config1) && !hasArguments(config2)
|
||||
}
|
||||
|
||||
func firstParamOnlyHasArgs(config1, config2 *rspec.LinuxSyscall) bool {
|
||||
return !hasArguments(config1) && hasArguments(config2)
|
||||
}
|
29
vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go
generated
vendored
Normal file
29
vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
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
Normal file
134
vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
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
Normal file
32
vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
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
Normal file
188
vendor/github.com/opencontainers/runtime-tools/specerror/config.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
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
Normal file
152
vendor/github.com/opencontainers/runtime-tools/specerror/error.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// 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
Normal file
23
vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
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
Normal file
179
vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go
generated
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
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)
|
||||
}
|
838
vendor/github.com/opencontainers/runtime-tools/validate/validate.go
generated
vendored
Normal file
838
vendor/github.com/opencontainers/runtime-tools/validate/validate.go
generated
vendored
Normal file
@ -0,0 +1,838 @@
|
||||
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)
|
||||
}
|
||||
configRenamedToConfigSchemaVersion, err := semver.Parse("1.0.0-rc2") // config.json became config-schema.json in 1.0.0-rc2
|
||||
if ver.Compare(configRenamedToConfigSchemaVersion) == -1 {
|
||||
return "", fmt.Errorf("unsupported configuration version (older than %s)", configRenamedToConfigSchemaVersion)
|
||||
}
|
||||
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(v.spec.Version)
|
||||
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)
|
||||
}
|
237
vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go
generated
vendored
Normal file
237
vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
// +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
|
||||
}
|
17
vendor/github.com/opencontainers/runtime-tools/validate/validate_unsupported.go
generated
vendored
Normal file
17
vendor/github.com/opencontainers/runtime-tools/validate/validate_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// +build !linux
|
||||
|
||||
package validate
|
||||
|
||||
import (
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
// LastCap return last cap of system
|
||||
func LastCap() capability.Cap {
|
||||
return capability.Cap(-1)
|
||||
}
|
||||
|
||||
// CheckLinux is a noop on this platform
|
||||
func (v *Validator) CheckLinux() (errs error) {
|
||||
return nil
|
||||
}
|
24
vendor/github.com/syndtr/gocapability/LICENSE
generated
vendored
Normal file
24
vendor/github.com/syndtr/gocapability/LICENSE
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||
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.
|
133
vendor/github.com/syndtr/gocapability/capability/capability.go
generated
vendored
Normal file
133
vendor/github.com/syndtr/gocapability/capability/capability.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Package capability provides utilities for manipulating POSIX capabilities.
|
||||
package capability
|
||||
|
||||
type Capabilities interface {
|
||||
// Get check whether a capability present in the given
|
||||
// capabilities set. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Get(which CapType, what Cap) bool
|
||||
|
||||
// Empty check whether all capability bits of the given capabilities
|
||||
// set are zero. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Empty(which CapType) bool
|
||||
|
||||
// Full check whether all capability bits of the given capabilities
|
||||
// set are one. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Full(which CapType) bool
|
||||
|
||||
// Set sets capabilities of the given capabilities sets. The
|
||||
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Set(which CapType, caps ...Cap)
|
||||
|
||||
// Unset unsets capabilities of the given capabilities sets. The
|
||||
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Unset(which CapType, caps ...Cap)
|
||||
|
||||
// Fill sets all bits of the given capabilities kind to one. The
|
||||
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
||||
// BOUNDS or AMBS.
|
||||
Fill(kind CapType)
|
||||
|
||||
// Clear sets all bits of the given capabilities kind to zero. The
|
||||
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
||||
// BOUNDS or AMBS.
|
||||
Clear(kind CapType)
|
||||
|
||||
// String return current capabilities state of the given capabilities
|
||||
// set as string. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE BOUNDING or AMBIENT
|
||||
StringCap(which CapType) string
|
||||
|
||||
// String return current capabilities state as string.
|
||||
String() string
|
||||
|
||||
// Load load actual capabilities value. This will overwrite all
|
||||
// outstanding changes.
|
||||
Load() error
|
||||
|
||||
// Apply apply the capabilities settings, so all changes will take
|
||||
// effect.
|
||||
Apply(kind CapType) error
|
||||
}
|
||||
|
||||
// NewPid initializes a new Capabilities object for given pid when
|
||||
// it is nonzero, or for the current process if pid is 0.
|
||||
//
|
||||
// Deprecated: Replace with NewPid2. For example, replace:
|
||||
//
|
||||
// c, err := NewPid(0)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// with:
|
||||
//
|
||||
// c, err := NewPid2(0)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = c.Load()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
func NewPid(pid int) (Capabilities, error) {
|
||||
c, err := newPid(pid)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
err = c.Load()
|
||||
return c, err
|
||||
}
|
||||
|
||||
// NewPid2 initializes a new Capabilities object for given pid when
|
||||
// it is nonzero, or for the current process if pid is 0. This
|
||||
// does not load the process's current capabilities; to do that you
|
||||
// must call Load explicitly.
|
||||
func NewPid2(pid int) (Capabilities, error) {
|
||||
return newPid(pid)
|
||||
}
|
||||
|
||||
// NewFile initializes a new Capabilities object for given file path.
|
||||
//
|
||||
// Deprecated: Replace with NewFile2. For example, replace:
|
||||
//
|
||||
// c, err := NewFile(path)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// with:
|
||||
//
|
||||
// c, err := NewFile2(path)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = c.Load()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
func NewFile(path string) (Capabilities, error) {
|
||||
c, err := newFile(path)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
err = c.Load()
|
||||
return c, err
|
||||
}
|
||||
|
||||
// NewFile2 creates a new initialized Capabilities object for given
|
||||
// file path. This does not load the process's current capabilities;
|
||||
// to do that you must call Load explicitly.
|
||||
func NewFile2(path string) (Capabilities, error) {
|
||||
return newFile(path)
|
||||
}
|
642
vendor/github.com/syndtr/gocapability/capability/capability_linux.go
generated
vendored
Normal file
642
vendor/github.com/syndtr/gocapability/capability/capability_linux.go
generated
vendored
Normal file
@ -0,0 +1,642 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package capability
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var errUnknownVers = errors.New("unknown capability version")
|
||||
|
||||
const (
|
||||
linuxCapVer1 = 0x19980330
|
||||
linuxCapVer2 = 0x20071026
|
||||
linuxCapVer3 = 0x20080522
|
||||
)
|
||||
|
||||
var (
|
||||
capVers uint32
|
||||
capLastCap Cap
|
||||
)
|
||||
|
||||
func init() {
|
||||
var hdr capHeader
|
||||
capget(&hdr, nil)
|
||||
capVers = hdr.version
|
||||
|
||||
if initLastCap() == nil {
|
||||
CAP_LAST_CAP = capLastCap
|
||||
if capLastCap > 31 {
|
||||
capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1
|
||||
} else {
|
||||
capUpperMask = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initLastCap() error {
|
||||
if capLastCap != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Open("/proc/sys/kernel/cap_last_cap")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var b []byte = make([]byte, 11)
|
||||
_, err = f.Read(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Sscanf(string(b), "%d", &capLastCap)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mkStringCap(c Capabilities, which CapType) (ret string) {
|
||||
for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ {
|
||||
if !c.Get(which, i) {
|
||||
continue
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
ret += ", "
|
||||
}
|
||||
ret += i.String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mkString(c Capabilities, max CapType) (ret string) {
|
||||
ret = "{"
|
||||
for i := CapType(1); i <= max; i <<= 1 {
|
||||
ret += " " + i.String() + "=\""
|
||||
if c.Empty(i) {
|
||||
ret += "empty"
|
||||
} else if c.Full(i) {
|
||||
ret += "full"
|
||||
} else {
|
||||
ret += c.StringCap(i)
|
||||
}
|
||||
ret += "\""
|
||||
}
|
||||
ret += " }"
|
||||
return
|
||||
}
|
||||
|
||||
func newPid(pid int) (c Capabilities, err error) {
|
||||
switch capVers {
|
||||
case linuxCapVer1:
|
||||
p := new(capsV1)
|
||||
p.hdr.version = capVers
|
||||
p.hdr.pid = int32(pid)
|
||||
c = p
|
||||
case linuxCapVer2, linuxCapVer3:
|
||||
p := new(capsV3)
|
||||
p.hdr.version = capVers
|
||||
p.hdr.pid = int32(pid)
|
||||
c = p
|
||||
default:
|
||||
err = errUnknownVers
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type capsV1 struct {
|
||||
hdr capHeader
|
||||
data capData
|
||||
}
|
||||
|
||||
func (c *capsV1) Get(which CapType, what Cap) bool {
|
||||
if what > 32 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
return (1<<uint(what))&c.data.effective != 0
|
||||
case PERMITTED:
|
||||
return (1<<uint(what))&c.data.permitted != 0
|
||||
case INHERITABLE:
|
||||
return (1<<uint(what))&c.data.inheritable != 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *capsV1) getData(which CapType) (ret uint32) {
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
ret = c.data.effective
|
||||
case PERMITTED:
|
||||
ret = c.data.permitted
|
||||
case INHERITABLE:
|
||||
ret = c.data.inheritable
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *capsV1) Empty(which CapType) bool {
|
||||
return c.getData(which) == 0
|
||||
}
|
||||
|
||||
func (c *capsV1) Full(which CapType) bool {
|
||||
return (c.getData(which) & 0x7fffffff) == 0x7fffffff
|
||||
}
|
||||
|
||||
func (c *capsV1) Set(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
if what > 32 {
|
||||
continue
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data.effective |= 1 << uint(what)
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data.permitted |= 1 << uint(what)
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data.inheritable |= 1 << uint(what)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV1) Unset(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
if what > 32 {
|
||||
continue
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data.effective &= ^(1 << uint(what))
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data.permitted &= ^(1 << uint(what))
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data.inheritable &= ^(1 << uint(what))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV1) Fill(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data.effective = 0x7fffffff
|
||||
c.data.permitted = 0x7fffffff
|
||||
c.data.inheritable = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV1) Clear(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data.effective = 0
|
||||
c.data.permitted = 0
|
||||
c.data.inheritable = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV1) StringCap(which CapType) (ret string) {
|
||||
return mkStringCap(c, which)
|
||||
}
|
||||
|
||||
func (c *capsV1) String() (ret string) {
|
||||
return mkString(c, BOUNDING)
|
||||
}
|
||||
|
||||
func (c *capsV1) Load() (err error) {
|
||||
return capget(&c.hdr, &c.data)
|
||||
}
|
||||
|
||||
func (c *capsV1) Apply(kind CapType) error {
|
||||
if kind&CAPS == CAPS {
|
||||
return capset(&c.hdr, &c.data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type capsV3 struct {
|
||||
hdr capHeader
|
||||
data [2]capData
|
||||
bounds [2]uint32
|
||||
ambient [2]uint32
|
||||
}
|
||||
|
||||
func (c *capsV3) Get(which CapType, what Cap) bool {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
return (1<<uint(what))&c.data[i].effective != 0
|
||||
case PERMITTED:
|
||||
return (1<<uint(what))&c.data[i].permitted != 0
|
||||
case INHERITABLE:
|
||||
return (1<<uint(what))&c.data[i].inheritable != 0
|
||||
case BOUNDING:
|
||||
return (1<<uint(what))&c.bounds[i] != 0
|
||||
case AMBIENT:
|
||||
return (1<<uint(what))&c.ambient[i] != 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *capsV3) getData(which CapType, dest []uint32) {
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
dest[0] = c.data[0].effective
|
||||
dest[1] = c.data[1].effective
|
||||
case PERMITTED:
|
||||
dest[0] = c.data[0].permitted
|
||||
dest[1] = c.data[1].permitted
|
||||
case INHERITABLE:
|
||||
dest[0] = c.data[0].inheritable
|
||||
dest[1] = c.data[1].inheritable
|
||||
case BOUNDING:
|
||||
dest[0] = c.bounds[0]
|
||||
dest[1] = c.bounds[1]
|
||||
case AMBIENT:
|
||||
dest[0] = c.ambient[0]
|
||||
dest[1] = c.ambient[1]
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Empty(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
return data[0] == 0 && data[1] == 0
|
||||
}
|
||||
|
||||
func (c *capsV3) Full(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
if (data[0] & 0xffffffff) != 0xffffffff {
|
||||
return false
|
||||
}
|
||||
return (data[1] & capUpperMask) == capUpperMask
|
||||
}
|
||||
|
||||
func (c *capsV3) Set(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data[i].effective |= 1 << uint(what)
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data[i].permitted |= 1 << uint(what)
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data[i].inheritable |= 1 << uint(what)
|
||||
}
|
||||
if which&BOUNDING != 0 {
|
||||
c.bounds[i] |= 1 << uint(what)
|
||||
}
|
||||
if which&AMBIENT != 0 {
|
||||
c.ambient[i] |= 1 << uint(what)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Unset(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data[i].effective &= ^(1 << uint(what))
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data[i].permitted &= ^(1 << uint(what))
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data[i].inheritable &= ^(1 << uint(what))
|
||||
}
|
||||
if which&BOUNDING != 0 {
|
||||
c.bounds[i] &= ^(1 << uint(what))
|
||||
}
|
||||
if which&AMBIENT != 0 {
|
||||
c.ambient[i] &= ^(1 << uint(what))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Fill(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data[0].effective = 0xffffffff
|
||||
c.data[0].permitted = 0xffffffff
|
||||
c.data[0].inheritable = 0
|
||||
c.data[1].effective = 0xffffffff
|
||||
c.data[1].permitted = 0xffffffff
|
||||
c.data[1].inheritable = 0
|
||||
}
|
||||
|
||||
if kind&BOUNDS == BOUNDS {
|
||||
c.bounds[0] = 0xffffffff
|
||||
c.bounds[1] = 0xffffffff
|
||||
}
|
||||
if kind&AMBS == AMBS {
|
||||
c.ambient[0] = 0xffffffff
|
||||
c.ambient[1] = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Clear(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data[0].effective = 0
|
||||
c.data[0].permitted = 0
|
||||
c.data[0].inheritable = 0
|
||||
c.data[1].effective = 0
|
||||
c.data[1].permitted = 0
|
||||
c.data[1].inheritable = 0
|
||||
}
|
||||
|
||||
if kind&BOUNDS == BOUNDS {
|
||||
c.bounds[0] = 0
|
||||
c.bounds[1] = 0
|
||||
}
|
||||
if kind&AMBS == AMBS {
|
||||
c.ambient[0] = 0
|
||||
c.ambient[1] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) StringCap(which CapType) (ret string) {
|
||||
return mkStringCap(c, which)
|
||||
}
|
||||
|
||||
func (c *capsV3) String() (ret string) {
|
||||
return mkString(c, BOUNDING)
|
||||
}
|
||||
|
||||
func (c *capsV3) Load() (err error) {
|
||||
err = capget(&c.hdr, &c.data[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var status_path string
|
||||
|
||||
if c.hdr.pid == 0 {
|
||||
status_path = fmt.Sprintf("/proc/self/status")
|
||||
} else {
|
||||
status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid)
|
||||
}
|
||||
|
||||
f, err := os.Open(status_path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b := bufio.NewReader(f)
|
||||
for {
|
||||
line, e := b.ReadString('\n')
|
||||
if e != nil {
|
||||
if e != io.EOF {
|
||||
err = e
|
||||
}
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(line, "CapB") {
|
||||
fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0])
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "CapA") {
|
||||
fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0])
|
||||
continue
|
||||
}
|
||||
}
|
||||
f.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *capsV3) Apply(kind CapType) (err error) {
|
||||
if kind&BOUNDS == BOUNDS {
|
||||
var data [2]capData
|
||||
err = capget(&c.hdr, &data[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 {
|
||||
for i := Cap(0); i <= CAP_LAST_CAP; i++ {
|
||||
if c.Get(BOUNDING, i) {
|
||||
continue
|
||||
}
|
||||
err = prctl(syscall.PR_CAPBSET_DROP, uintptr(i), 0, 0, 0)
|
||||
if err != nil {
|
||||
// Ignore EINVAL since the capability may not be supported in this system.
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if kind&CAPS == CAPS {
|
||||
err = capset(&c.hdr, &c.data[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if kind&AMBS == AMBS {
|
||||
for i := Cap(0); i <= CAP_LAST_CAP; i++ {
|
||||
action := pr_CAP_AMBIENT_LOWER
|
||||
if c.Get(AMBIENT, i) {
|
||||
action = pr_CAP_AMBIENT_RAISE
|
||||
}
|
||||
err := prctl(pr_CAP_AMBIENT, action, uintptr(i), 0, 0)
|
||||
// Ignore EINVAL as not supported on kernels before 4.3
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func newFile(path string) (c Capabilities, err error) {
|
||||
c = &capsFile{path: path}
|
||||
return
|
||||
}
|
||||
|
||||
type capsFile struct {
|
||||
path string
|
||||
data vfscapData
|
||||
}
|
||||
|
||||
func (c *capsFile) Get(which CapType, what Cap) bool {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
if c.data.version == 1 {
|
||||
return false
|
||||
}
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
return (1<<uint(what))&c.data.effective[i] != 0
|
||||
case PERMITTED:
|
||||
return (1<<uint(what))&c.data.data[i].permitted != 0
|
||||
case INHERITABLE:
|
||||
return (1<<uint(what))&c.data.data[i].inheritable != 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *capsFile) getData(which CapType, dest []uint32) {
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
dest[0] = c.data.effective[0]
|
||||
dest[1] = c.data.effective[1]
|
||||
case PERMITTED:
|
||||
dest[0] = c.data.data[0].permitted
|
||||
dest[1] = c.data.data[1].permitted
|
||||
case INHERITABLE:
|
||||
dest[0] = c.data.data[0].inheritable
|
||||
dest[1] = c.data.data[1].inheritable
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Empty(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
return data[0] == 0 && data[1] == 0
|
||||
}
|
||||
|
||||
func (c *capsFile) Full(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
if c.data.version == 0 {
|
||||
return (data[0] & 0x7fffffff) == 0x7fffffff
|
||||
}
|
||||
if (data[0] & 0xffffffff) != 0xffffffff {
|
||||
return false
|
||||
}
|
||||
return (data[1] & capUpperMask) == capUpperMask
|
||||
}
|
||||
|
||||
func (c *capsFile) Set(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
if c.data.version == 1 {
|
||||
continue
|
||||
}
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data.effective[i] |= 1 << uint(what)
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data.data[i].permitted |= 1 << uint(what)
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data.data[i].inheritable |= 1 << uint(what)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Unset(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
if c.data.version == 1 {
|
||||
continue
|
||||
}
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data.effective[i] &= ^(1 << uint(what))
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data.data[i].permitted &= ^(1 << uint(what))
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data.data[i].inheritable &= ^(1 << uint(what))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Fill(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data.effective[0] = 0xffffffff
|
||||
c.data.data[0].permitted = 0xffffffff
|
||||
c.data.data[0].inheritable = 0
|
||||
if c.data.version == 2 {
|
||||
c.data.effective[1] = 0xffffffff
|
||||
c.data.data[1].permitted = 0xffffffff
|
||||
c.data.data[1].inheritable = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Clear(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data.effective[0] = 0
|
||||
c.data.data[0].permitted = 0
|
||||
c.data.data[0].inheritable = 0
|
||||
if c.data.version == 2 {
|
||||
c.data.effective[1] = 0
|
||||
c.data.data[1].permitted = 0
|
||||
c.data.data[1].inheritable = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) StringCap(which CapType) (ret string) {
|
||||
return mkStringCap(c, which)
|
||||
}
|
||||
|
||||
func (c *capsFile) String() (ret string) {
|
||||
return mkString(c, INHERITABLE)
|
||||
}
|
||||
|
||||
func (c *capsFile) Load() (err error) {
|
||||
return getVfsCap(c.path, &c.data)
|
||||
}
|
||||
|
||||
func (c *capsFile) Apply(kind CapType) (err error) {
|
||||
if kind&CAPS == CAPS {
|
||||
return setVfsCap(c.path, &c.data)
|
||||
}
|
||||
return
|
||||
}
|
19
vendor/github.com/syndtr/gocapability/capability/capability_noop.go
generated
vendored
Normal file
19
vendor/github.com/syndtr/gocapability/capability/capability_noop.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package capability
|
||||
|
||||
import "errors"
|
||||
|
||||
func newPid(pid int) (Capabilities, error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
||||
func newFile(path string) (Capabilities, error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
309
vendor/github.com/syndtr/gocapability/capability/enum.go
generated
vendored
Normal file
309
vendor/github.com/syndtr/gocapability/capability/enum.go
generated
vendored
Normal file
@ -0,0 +1,309 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package capability
|
||||
|
||||
type CapType uint
|
||||
|
||||
func (c CapType) String() string {
|
||||
switch c {
|
||||
case EFFECTIVE:
|
||||
return "effective"
|
||||
case PERMITTED:
|
||||
return "permitted"
|
||||
case INHERITABLE:
|
||||
return "inheritable"
|
||||
case BOUNDING:
|
||||
return "bounding"
|
||||
case CAPS:
|
||||
return "caps"
|
||||
case AMBIENT:
|
||||
return "ambient"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
const (
|
||||
EFFECTIVE CapType = 1 << iota
|
||||
PERMITTED
|
||||
INHERITABLE
|
||||
BOUNDING
|
||||
AMBIENT
|
||||
|
||||
CAPS = EFFECTIVE | PERMITTED | INHERITABLE
|
||||
BOUNDS = BOUNDING
|
||||
AMBS = AMBIENT
|
||||
)
|
||||
|
||||
//go:generate go run enumgen/gen.go
|
||||
type Cap int
|
||||
|
||||
// POSIX-draft defined capabilities and Linux extensions.
|
||||
//
|
||||
// Defined in https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h
|
||||
const (
|
||||
// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
|
||||
// overrides the restriction of changing file ownership and group
|
||||
// ownership.
|
||||
CAP_CHOWN = Cap(0)
|
||||
|
||||
// Override all DAC access, including ACL execute access if
|
||||
// [_POSIX_ACL] is defined. Excluding DAC access covered by
|
||||
// CAP_LINUX_IMMUTABLE.
|
||||
CAP_DAC_OVERRIDE = Cap(1)
|
||||
|
||||
// Overrides all DAC restrictions regarding read and search on files
|
||||
// and directories, including ACL restrictions if [_POSIX_ACL] is
|
||||
// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
|
||||
CAP_DAC_READ_SEARCH = Cap(2)
|
||||
|
||||
// Overrides all restrictions about allowed operations on files, where
|
||||
// file owner ID must be equal to the user ID, except where CAP_FSETID
|
||||
// is applicable. It doesn't override MAC and DAC restrictions.
|
||||
CAP_FOWNER = Cap(3)
|
||||
|
||||
// Overrides the following restrictions that the effective user ID
|
||||
// shall match the file owner ID when setting the S_ISUID and S_ISGID
|
||||
// bits on that file; that the effective group ID (or one of the
|
||||
// supplementary group IDs) shall match the file owner ID when setting
|
||||
// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
|
||||
// cleared on successful return from chown(2) (not implemented).
|
||||
CAP_FSETID = Cap(4)
|
||||
|
||||
// Overrides the restriction that the real or effective user ID of a
|
||||
// process sending a signal must match the real or effective user ID
|
||||
// of the process receiving the signal.
|
||||
CAP_KILL = Cap(5)
|
||||
|
||||
// Allows setgid(2) manipulation
|
||||
// Allows setgroups(2)
|
||||
// Allows forged gids on socket credentials passing.
|
||||
CAP_SETGID = Cap(6)
|
||||
|
||||
// Allows set*uid(2) manipulation (including fsuid).
|
||||
// Allows forged pids on socket credentials passing.
|
||||
CAP_SETUID = Cap(7)
|
||||
|
||||
// Linux-specific capabilities
|
||||
|
||||
// Without VFS support for capabilities:
|
||||
// Transfer any capability in your permitted set to any pid,
|
||||
// remove any capability in your permitted set from any pid
|
||||
// With VFS support for capabilities (neither of above, but)
|
||||
// Add any capability from current's capability bounding set
|
||||
// to the current process' inheritable set
|
||||
// Allow taking bits out of capability bounding set
|
||||
// Allow modification of the securebits for a process
|
||||
CAP_SETPCAP = Cap(8)
|
||||
|
||||
// Allow modification of S_IMMUTABLE and S_APPEND file attributes
|
||||
CAP_LINUX_IMMUTABLE = Cap(9)
|
||||
|
||||
// Allows binding to TCP/UDP sockets below 1024
|
||||
// Allows binding to ATM VCIs below 32
|
||||
CAP_NET_BIND_SERVICE = Cap(10)
|
||||
|
||||
// Allow broadcasting, listen to multicast
|
||||
CAP_NET_BROADCAST = Cap(11)
|
||||
|
||||
// Allow interface configuration
|
||||
// Allow administration of IP firewall, masquerading and accounting
|
||||
// Allow setting debug option on sockets
|
||||
// Allow modification of routing tables
|
||||
// Allow setting arbitrary process / process group ownership on
|
||||
// sockets
|
||||
// Allow binding to any address for transparent proxying (also via NET_RAW)
|
||||
// Allow setting TOS (type of service)
|
||||
// Allow setting promiscuous mode
|
||||
// Allow clearing driver statistics
|
||||
// Allow multicasting
|
||||
// Allow read/write of device-specific registers
|
||||
// Allow activation of ATM control sockets
|
||||
CAP_NET_ADMIN = Cap(12)
|
||||
|
||||
// Allow use of RAW sockets
|
||||
// Allow use of PACKET sockets
|
||||
// Allow binding to any address for transparent proxying (also via NET_ADMIN)
|
||||
CAP_NET_RAW = Cap(13)
|
||||
|
||||
// Allow locking of shared memory segments
|
||||
// Allow mlock and mlockall (which doesn't really have anything to do
|
||||
// with IPC)
|
||||
CAP_IPC_LOCK = Cap(14)
|
||||
|
||||
// Override IPC ownership checks
|
||||
CAP_IPC_OWNER = Cap(15)
|
||||
|
||||
// Insert and remove kernel modules - modify kernel without limit
|
||||
CAP_SYS_MODULE = Cap(16)
|
||||
|
||||
// Allow ioperm/iopl access
|
||||
// Allow sending USB messages to any device via /proc/bus/usb
|
||||
CAP_SYS_RAWIO = Cap(17)
|
||||
|
||||
// Allow use of chroot()
|
||||
CAP_SYS_CHROOT = Cap(18)
|
||||
|
||||
// Allow ptrace() of any process
|
||||
CAP_SYS_PTRACE = Cap(19)
|
||||
|
||||
// Allow configuration of process accounting
|
||||
CAP_SYS_PACCT = Cap(20)
|
||||
|
||||
// Allow configuration of the secure attention key
|
||||
// Allow administration of the random device
|
||||
// Allow examination and configuration of disk quotas
|
||||
// Allow setting the domainname
|
||||
// Allow setting the hostname
|
||||
// Allow calling bdflush()
|
||||
// Allow mount() and umount(), setting up new smb connection
|
||||
// Allow some autofs root ioctls
|
||||
// Allow nfsservctl
|
||||
// Allow VM86_REQUEST_IRQ
|
||||
// Allow to read/write pci config on alpha
|
||||
// Allow irix_prctl on mips (setstacksize)
|
||||
// Allow flushing all cache on m68k (sys_cacheflush)
|
||||
// Allow removing semaphores
|
||||
// Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores
|
||||
// and shared memory
|
||||
// Allow locking/unlocking of shared memory segment
|
||||
// Allow turning swap on/off
|
||||
// Allow forged pids on socket credentials passing
|
||||
// Allow setting readahead and flushing buffers on block devices
|
||||
// Allow setting geometry in floppy driver
|
||||
// Allow turning DMA on/off in xd driver
|
||||
// Allow administration of md devices (mostly the above, but some
|
||||
// extra ioctls)
|
||||
// Allow tuning the ide driver
|
||||
// Allow access to the nvram device
|
||||
// Allow administration of apm_bios, serial and bttv (TV) device
|
||||
// Allow manufacturer commands in isdn CAPI support driver
|
||||
// Allow reading non-standardized portions of pci configuration space
|
||||
// Allow DDI debug ioctl on sbpcd driver
|
||||
// Allow setting up serial ports
|
||||
// Allow sending raw qic-117 commands
|
||||
// Allow enabling/disabling tagged queuing on SCSI controllers and sending
|
||||
// arbitrary SCSI commands
|
||||
// Allow setting encryption key on loopback filesystem
|
||||
// Allow setting zone reclaim policy
|
||||
// Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility
|
||||
CAP_SYS_ADMIN = Cap(21)
|
||||
|
||||
// Allow use of reboot()
|
||||
CAP_SYS_BOOT = Cap(22)
|
||||
|
||||
// Allow raising priority and setting priority on other (different
|
||||
// UID) processes
|
||||
// Allow use of FIFO and round-robin (realtime) scheduling on own
|
||||
// processes and setting the scheduling algorithm used by another
|
||||
// process.
|
||||
// Allow setting cpu affinity on other processes
|
||||
CAP_SYS_NICE = Cap(23)
|
||||
|
||||
// Override resource limits. Set resource limits.
|
||||
// Override quota limits.
|
||||
// Override reserved space on ext2 filesystem
|
||||
// Modify data journaling mode on ext3 filesystem (uses journaling
|
||||
// resources)
|
||||
// NOTE: ext2 honors fsuid when checking for resource overrides, so
|
||||
// you can override using fsuid too
|
||||
// Override size restrictions on IPC message queues
|
||||
// Allow more than 64hz interrupts from the real-time clock
|
||||
// Override max number of consoles on console allocation
|
||||
// Override max number of keymaps
|
||||
// Control memory reclaim behavior
|
||||
CAP_SYS_RESOURCE = Cap(24)
|
||||
|
||||
// Allow manipulation of system clock
|
||||
// Allow irix_stime on mips
|
||||
// Allow setting the real-time clock
|
||||
CAP_SYS_TIME = Cap(25)
|
||||
|
||||
// Allow configuration of tty devices
|
||||
// Allow vhangup() of tty
|
||||
CAP_SYS_TTY_CONFIG = Cap(26)
|
||||
|
||||
// Allow the privileged aspects of mknod()
|
||||
CAP_MKNOD = Cap(27)
|
||||
|
||||
// Allow taking of leases on files
|
||||
CAP_LEASE = Cap(28)
|
||||
|
||||
CAP_AUDIT_WRITE = Cap(29)
|
||||
CAP_AUDIT_CONTROL = Cap(30)
|
||||
CAP_SETFCAP = Cap(31)
|
||||
|
||||
// Override MAC access.
|
||||
// The base kernel enforces no MAC policy.
|
||||
// An LSM may enforce a MAC policy, and if it does and it chooses
|
||||
// to implement capability based overrides of that policy, this is
|
||||
// the capability it should use to do so.
|
||||
CAP_MAC_OVERRIDE = Cap(32)
|
||||
|
||||
// Allow MAC configuration or state changes.
|
||||
// The base kernel requires no MAC configuration.
|
||||
// An LSM may enforce a MAC policy, and if it does and it chooses
|
||||
// to implement capability based checks on modifications to that
|
||||
// policy or the data required to maintain it, this is the
|
||||
// capability it should use to do so.
|
||||
CAP_MAC_ADMIN = Cap(33)
|
||||
|
||||
// Allow configuring the kernel's syslog (printk behaviour)
|
||||
CAP_SYSLOG = Cap(34)
|
||||
|
||||
// Allow triggering something that will wake the system
|
||||
CAP_WAKE_ALARM = Cap(35)
|
||||
|
||||
// Allow preventing system suspends
|
||||
CAP_BLOCK_SUSPEND = Cap(36)
|
||||
|
||||
// Allow reading the audit log via multicast netlink socket
|
||||
CAP_AUDIT_READ = Cap(37)
|
||||
|
||||
// Allow system performance and observability privileged operations
|
||||
// using perf_events, i915_perf and other kernel subsystems
|
||||
CAP_PERFMON = Cap(38)
|
||||
|
||||
// CAP_BPF allows the following BPF operations:
|
||||
// - Creating all types of BPF maps
|
||||
// - Advanced verifier features
|
||||
// - Indirect variable access
|
||||
// - Bounded loops
|
||||
// - BPF to BPF function calls
|
||||
// - Scalar precision tracking
|
||||
// - Larger complexity limits
|
||||
// - Dead code elimination
|
||||
// - And potentially other features
|
||||
// - Loading BPF Type Format (BTF) data
|
||||
// - Retrieve xlated and JITed code of BPF programs
|
||||
// - Use bpf_spin_lock() helper
|
||||
//
|
||||
// CAP_PERFMON relaxes the verifier checks further:
|
||||
// - BPF progs can use of pointer-to-integer conversions
|
||||
// - speculation attack hardening measures are bypassed
|
||||
// - bpf_probe_read to read arbitrary kernel memory is allowed
|
||||
// - bpf_trace_printk to print kernel memory is allowed
|
||||
//
|
||||
// CAP_SYS_ADMIN is required to use bpf_probe_write_user.
|
||||
//
|
||||
// CAP_SYS_ADMIN is required to iterate system wide loaded
|
||||
// programs, maps, links, BTFs and convert their IDs to file descriptors.
|
||||
//
|
||||
// CAP_PERFMON and CAP_BPF are required to load tracing programs.
|
||||
// CAP_NET_ADMIN and CAP_BPF are required to load networking programs.
|
||||
CAP_BPF = Cap(39)
|
||||
|
||||
// Allow checkpoint/restore related operations.
|
||||
// Introduced in kernel 5.9
|
||||
CAP_CHECKPOINT_RESTORE = Cap(40)
|
||||
)
|
||||
|
||||
var (
|
||||
// Highest valid capability of the running kernel.
|
||||
CAP_LAST_CAP = Cap(63)
|
||||
|
||||
capUpperMask = ^uint32(0)
|
||||
)
|
138
vendor/github.com/syndtr/gocapability/capability/enum_gen.go
generated
vendored
Normal file
138
vendor/github.com/syndtr/gocapability/capability/enum_gen.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// generated file; DO NOT EDIT - use go generate in directory with source
|
||||
|
||||
package capability
|
||||
|
||||
func (c Cap) String() string {
|
||||
switch c {
|
||||
case CAP_CHOWN:
|
||||
return "chown"
|
||||
case CAP_DAC_OVERRIDE:
|
||||
return "dac_override"
|
||||
case CAP_DAC_READ_SEARCH:
|
||||
return "dac_read_search"
|
||||
case CAP_FOWNER:
|
||||
return "fowner"
|
||||
case CAP_FSETID:
|
||||
return "fsetid"
|
||||
case CAP_KILL:
|
||||
return "kill"
|
||||
case CAP_SETGID:
|
||||
return "setgid"
|
||||
case CAP_SETUID:
|
||||
return "setuid"
|
||||
case CAP_SETPCAP:
|
||||
return "setpcap"
|
||||
case CAP_LINUX_IMMUTABLE:
|
||||
return "linux_immutable"
|
||||
case CAP_NET_BIND_SERVICE:
|
||||
return "net_bind_service"
|
||||
case CAP_NET_BROADCAST:
|
||||
return "net_broadcast"
|
||||
case CAP_NET_ADMIN:
|
||||
return "net_admin"
|
||||
case CAP_NET_RAW:
|
||||
return "net_raw"
|
||||
case CAP_IPC_LOCK:
|
||||
return "ipc_lock"
|
||||
case CAP_IPC_OWNER:
|
||||
return "ipc_owner"
|
||||
case CAP_SYS_MODULE:
|
||||
return "sys_module"
|
||||
case CAP_SYS_RAWIO:
|
||||
return "sys_rawio"
|
||||
case CAP_SYS_CHROOT:
|
||||
return "sys_chroot"
|
||||
case CAP_SYS_PTRACE:
|
||||
return "sys_ptrace"
|
||||
case CAP_SYS_PACCT:
|
||||
return "sys_pacct"
|
||||
case CAP_SYS_ADMIN:
|
||||
return "sys_admin"
|
||||
case CAP_SYS_BOOT:
|
||||
return "sys_boot"
|
||||
case CAP_SYS_NICE:
|
||||
return "sys_nice"
|
||||
case CAP_SYS_RESOURCE:
|
||||
return "sys_resource"
|
||||
case CAP_SYS_TIME:
|
||||
return "sys_time"
|
||||
case CAP_SYS_TTY_CONFIG:
|
||||
return "sys_tty_config"
|
||||
case CAP_MKNOD:
|
||||
return "mknod"
|
||||
case CAP_LEASE:
|
||||
return "lease"
|
||||
case CAP_AUDIT_WRITE:
|
||||
return "audit_write"
|
||||
case CAP_AUDIT_CONTROL:
|
||||
return "audit_control"
|
||||
case CAP_SETFCAP:
|
||||
return "setfcap"
|
||||
case CAP_MAC_OVERRIDE:
|
||||
return "mac_override"
|
||||
case CAP_MAC_ADMIN:
|
||||
return "mac_admin"
|
||||
case CAP_SYSLOG:
|
||||
return "syslog"
|
||||
case CAP_WAKE_ALARM:
|
||||
return "wake_alarm"
|
||||
case CAP_BLOCK_SUSPEND:
|
||||
return "block_suspend"
|
||||
case CAP_AUDIT_READ:
|
||||
return "audit_read"
|
||||
case CAP_PERFMON:
|
||||
return "perfmon"
|
||||
case CAP_BPF:
|
||||
return "bpf"
|
||||
case CAP_CHECKPOINT_RESTORE:
|
||||
return "checkpoint_restore"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// List returns list of all supported capabilities
|
||||
func List() []Cap {
|
||||
return []Cap{
|
||||
CAP_CHOWN,
|
||||
CAP_DAC_OVERRIDE,
|
||||
CAP_DAC_READ_SEARCH,
|
||||
CAP_FOWNER,
|
||||
CAP_FSETID,
|
||||
CAP_KILL,
|
||||
CAP_SETGID,
|
||||
CAP_SETUID,
|
||||
CAP_SETPCAP,
|
||||
CAP_LINUX_IMMUTABLE,
|
||||
CAP_NET_BIND_SERVICE,
|
||||
CAP_NET_BROADCAST,
|
||||
CAP_NET_ADMIN,
|
||||
CAP_NET_RAW,
|
||||
CAP_IPC_LOCK,
|
||||
CAP_IPC_OWNER,
|
||||
CAP_SYS_MODULE,
|
||||
CAP_SYS_RAWIO,
|
||||
CAP_SYS_CHROOT,
|
||||
CAP_SYS_PTRACE,
|
||||
CAP_SYS_PACCT,
|
||||
CAP_SYS_ADMIN,
|
||||
CAP_SYS_BOOT,
|
||||
CAP_SYS_NICE,
|
||||
CAP_SYS_RESOURCE,
|
||||
CAP_SYS_TIME,
|
||||
CAP_SYS_TTY_CONFIG,
|
||||
CAP_MKNOD,
|
||||
CAP_LEASE,
|
||||
CAP_AUDIT_WRITE,
|
||||
CAP_AUDIT_CONTROL,
|
||||
CAP_SETFCAP,
|
||||
CAP_MAC_OVERRIDE,
|
||||
CAP_MAC_ADMIN,
|
||||
CAP_SYSLOG,
|
||||
CAP_WAKE_ALARM,
|
||||
CAP_BLOCK_SUSPEND,
|
||||
CAP_AUDIT_READ,
|
||||
CAP_PERFMON,
|
||||
CAP_BPF,
|
||||
CAP_CHECKPOINT_RESTORE,
|
||||
}
|
||||
}
|
154
vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
generated
vendored
Normal file
154
vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package capability
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type capHeader struct {
|
||||
version uint32
|
||||
pid int32
|
||||
}
|
||||
|
||||
type capData struct {
|
||||
effective uint32
|
||||
permitted uint32
|
||||
inheritable uint32
|
||||
}
|
||||
|
||||
func capget(hdr *capHeader, data *capData) (err error) {
|
||||
_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func capset(hdr *capHeader, data *capData) (err error) {
|
||||
_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// not yet in syscall
|
||||
const (
|
||||
pr_CAP_AMBIENT = 47
|
||||
pr_CAP_AMBIENT_IS_SET = uintptr(1)
|
||||
pr_CAP_AMBIENT_RAISE = uintptr(2)
|
||||
pr_CAP_AMBIENT_LOWER = uintptr(3)
|
||||
pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
|
||||
)
|
||||
|
||||
func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
|
||||
_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
vfsXattrName = "security.capability"
|
||||
|
||||
vfsCapVerMask = 0xff000000
|
||||
vfsCapVer1 = 0x01000000
|
||||
vfsCapVer2 = 0x02000000
|
||||
|
||||
vfsCapFlagMask = ^vfsCapVerMask
|
||||
vfsCapFlageffective = 0x000001
|
||||
|
||||
vfscapDataSizeV1 = 4 * (1 + 2*1)
|
||||
vfscapDataSizeV2 = 4 * (1 + 2*2)
|
||||
)
|
||||
|
||||
type vfscapData struct {
|
||||
magic uint32
|
||||
data [2]struct {
|
||||
permitted uint32
|
||||
inheritable uint32
|
||||
}
|
||||
effective [2]uint32
|
||||
version int8
|
||||
}
|
||||
|
||||
var (
|
||||
_vfsXattrName *byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
|
||||
}
|
||||
|
||||
func getVfsCap(path string, dest *vfscapData) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
|
||||
if e1 != 0 {
|
||||
if e1 == syscall.ENODATA {
|
||||
dest.version = 2
|
||||
return
|
||||
}
|
||||
err = e1
|
||||
}
|
||||
switch dest.magic & vfsCapVerMask {
|
||||
case vfsCapVer1:
|
||||
dest.version = 1
|
||||
if r0 != vfscapDataSizeV1 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
dest.data[1].permitted = 0
|
||||
dest.data[1].inheritable = 0
|
||||
case vfsCapVer2:
|
||||
dest.version = 2
|
||||
if r0 != vfscapDataSizeV2 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if dest.magic&vfsCapFlageffective != 0 {
|
||||
dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable
|
||||
dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable
|
||||
} else {
|
||||
dest.effective[0] = 0
|
||||
dest.effective[1] = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setVfsCap(path string, data *vfscapData) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var size uintptr
|
||||
if data.version == 1 {
|
||||
data.magic = vfsCapVer1
|
||||
size = vfscapDataSizeV1
|
||||
} else if data.version == 2 {
|
||||
data.magic = vfsCapVer2
|
||||
if data.effective[0] != 0 || data.effective[1] != 0 {
|
||||
data.magic |= vfsCapFlageffective
|
||||
}
|
||||
size = vfscapDataSizeV2
|
||||
} else {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
202
vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt
generated
vendored
Normal file
202
vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
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
Normal file
41
vendor/github.com/xeipuuv/gojsonpointer/README.md
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# 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
|
||||
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
|
||||
|
||||
### 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
Normal file
211
vendor/github.com/xeipuuv/gojsonpointer/pointer.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
// 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
Normal file
202
vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
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
Normal file
10
vendor/github.com/xeipuuv/gojsonreference/README.md
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# 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
Normal file
147
vendor/github.com/xeipuuv/gojsonreference/reference.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// 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
Normal file
3
vendor/github.com/xeipuuv/gojsonschema/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.sw[nop]
|
||||
*.iml
|
||||
.vscode/
|
9
vendor/github.com/xeipuuv/gojsonschema/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/xeipuuv/gojsonschema/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
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
Normal file
202
vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
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
Normal file
466
vendor/github.com/xeipuuv/gojsonschema/README.md
generated
vendored
Normal file
@ -0,0 +1,466 @@
|
||||
[](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
Normal file
125
vendor/github.com/xeipuuv/gojsonschema/draft.go
generated
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
// 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
Normal file
364
vendor/github.com/xeipuuv/gojsonschema/errors.go
generated
vendored
Normal file
@ -0,0 +1,364 @@
|
||||
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
Normal file
368
vendor/github.com/xeipuuv/gojsonschema/format_checkers.go
generated
vendored
Normal file
@ -0,0 +1,368 @@
|
||||
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
Normal file
13
vendor/github.com/xeipuuv/gojsonschema/glide.yaml
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
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
Normal file
37
vendor/github.com/xeipuuv/gojsonschema/internalLog.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// 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
Normal file
73
vendor/github.com/xeipuuv/gojsonschema/jsonContext.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
// 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
Normal file
386
vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go
generated
vendored
Normal file
@ -0,0 +1,386 @@
|
||||
// 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
Normal file
472
vendor/github.com/xeipuuv/gojsonschema/locales.go
generated
vendored
Normal file
@ -0,0 +1,472 @@
|
||||
// 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
Normal file
220
vendor/github.com/xeipuuv/gojsonschema/result.go
generated
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
// 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++
|
||||
}
|
1087
vendor/github.com/xeipuuv/gojsonschema/schema.go
generated
vendored
Normal file
1087
vendor/github.com/xeipuuv/gojsonschema/schema.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
206
vendor/github.com/xeipuuv/gojsonschema/schemaLoader.go
generated
vendored
Normal file
206
vendor/github.com/xeipuuv/gojsonschema/schemaLoader.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/xeipuuv/gojsonreference"
|
||||
)
|
||||
|
||||
// SchemaLoader is used to load schemas
|
||||
type SchemaLoader struct {
|
||||
pool *schemaPool
|
||||
AutoDetect bool
|
||||
Validate bool
|
||||
Draft Draft
|
||||
}
|
||||
|
||||
// NewSchemaLoader creates a new NewSchemaLoader
|
||||
func NewSchemaLoader() *SchemaLoader {
|
||||
|
||||
ps := &SchemaLoader{
|
||||
pool: &schemaPool{
|
||||
schemaPoolDocuments: make(map[string]*schemaPoolDocument),
|
||||
},
|
||||
AutoDetect: true,
|
||||
Validate: false,
|
||||
Draft: Hybrid,
|
||||
}
|
||||
ps.pool.autoDetect = &ps.AutoDetect
|
||||
|
||||
return ps
|
||||
}
|
||||
|
||||
func (sl *SchemaLoader) validateMetaschema(documentNode interface{}) error {
|
||||
|
||||
var (
|
||||
schema string
|
||||
err error
|
||||
)
|
||||
if sl.AutoDetect {
|
||||
schema, _, err = parseSchemaURL(documentNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If no explicit "$schema" is used, use the default metaschema associated with the draft used
|
||||
if schema == "" {
|
||||
if sl.Draft == Hybrid {
|
||||
return nil
|
||||
}
|
||||
schema = drafts.GetSchemaURL(sl.Draft)
|
||||
}
|
||||
|
||||
//Disable validation when loading the metaschema to prevent an infinite recursive loop
|
||||
sl.Validate = false
|
||||
|
||||
metaSchema, err := sl.Compile(NewReferenceLoader(schema))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sl.Validate = true
|
||||
|
||||
result := metaSchema.validateDocument(documentNode)
|
||||
|
||||
if !result.Valid() {
|
||||
var res bytes.Buffer
|
||||
for _, err := range result.Errors() {
|
||||
res.WriteString(err.String())
|
||||
res.WriteString("\n")
|
||||
}
|
||||
return errors.New(res.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddSchemas adds an arbritrary amount of schemas to the schema cache. As this function does not require
|
||||
// an explicit URL, every schema should contain an $id, so that it can be referenced by the main schema
|
||||
func (sl *SchemaLoader) AddSchemas(loaders ...JSONLoader) error {
|
||||
emptyRef, _ := gojsonreference.NewJsonReference("")
|
||||
|
||||
for _, loader := range loaders {
|
||||
doc, err := loader.LoadJSON()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sl.Validate {
|
||||
if err := sl.validateMetaschema(doc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Directly use the Recursive function, so that it get only added to the schema pool by $id
|
||||
// and not by the ref of the document as it's empty
|
||||
if err = sl.pool.parseReferences(doc, emptyRef, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//AddSchema adds a schema under the provided URL to the schema cache
|
||||
func (sl *SchemaLoader) AddSchema(url string, loader JSONLoader) error {
|
||||
|
||||
ref, err := gojsonreference.NewJsonReference(url)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
doc, err := loader.LoadJSON()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sl.Validate {
|
||||
if err := sl.validateMetaschema(doc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sl.pool.parseReferences(doc, ref, true)
|
||||
}
|
||||
|
||||
// Compile loads and compiles a schema
|
||||
func (sl *SchemaLoader) Compile(rootSchema JSONLoader) (*Schema, error) {
|
||||
|
||||
ref, err := rootSchema.JsonReference()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := Schema{}
|
||||
d.pool = sl.pool
|
||||
d.pool.jsonLoaderFactory = rootSchema.LoaderFactory()
|
||||
d.documentReference = ref
|
||||
d.referencePool = newSchemaReferencePool()
|
||||
|
||||
var doc interface{}
|
||||
if ref.String() != "" {
|
||||
// Get document from schema pool
|
||||
spd, err := d.pool.GetDocument(d.documentReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
doc = spd.Document
|
||||
} else {
|
||||
// Load JSON directly
|
||||
doc, err = rootSchema.LoadJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// References need only be parsed if loading JSON directly
|
||||
// as pool.GetDocument already does this for us if loading by reference
|
||||
err = sl.pool.parseReferences(doc, ref, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if sl.Validate {
|
||||
if err := sl.validateMetaschema(doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
draft := sl.Draft
|
||||
if sl.AutoDetect {
|
||||
_, detectedDraft, err := parseSchemaURL(doc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if detectedDraft != nil {
|
||||
draft = *detectedDraft
|
||||
}
|
||||
}
|
||||
|
||||
err = d.parse(doc, draft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
}
|
215
vendor/github.com/xeipuuv/gojsonschema/schemaPool.go
generated
vendored
Normal file
215
vendor/github.com/xeipuuv/gojsonschema/schemaPool.go
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
// 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 Defines resources pooling.
|
||||
// Eases referencing and avoids downloading the same resource twice.
|
||||
//
|
||||
// created 26-02-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/xeipuuv/gojsonreference"
|
||||
)
|
||||
|
||||
type schemaPoolDocument struct {
|
||||
Document interface{}
|
||||
Draft *Draft
|
||||
}
|
||||
|
||||
type schemaPool struct {
|
||||
schemaPoolDocuments map[string]*schemaPoolDocument
|
||||
jsonLoaderFactory JSONLoaderFactory
|
||||
autoDetect *bool
|
||||
}
|
||||
|
||||
func (p *schemaPool) parseReferences(document interface{}, ref gojsonreference.JsonReference, pooled bool) error {
|
||||
|
||||
var (
|
||||
draft *Draft
|
||||
err error
|
||||
reference = ref.String()
|
||||
)
|
||||
// Only the root document should be added to the schema pool if pooled is true
|
||||
if _, ok := p.schemaPoolDocuments[reference]; pooled && ok {
|
||||
return fmt.Errorf("Reference already exists: \"%s\"", reference)
|
||||
}
|
||||
|
||||
if *p.autoDetect {
|
||||
_, draft, err = parseSchemaURL(document)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = p.parseReferencesRecursive(document, ref, draft)
|
||||
|
||||
if pooled {
|
||||
p.schemaPoolDocuments[reference] = &schemaPoolDocument{Document: document, Draft: draft}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *schemaPool) parseReferencesRecursive(document interface{}, ref gojsonreference.JsonReference, draft *Draft) error {
|
||||
// parseReferencesRecursive parses a JSON document and resolves all $id and $ref references.
|
||||
// For $ref references it takes into account the $id scope it is in and replaces
|
||||
// the reference by the absolute resolved reference
|
||||
|
||||
// When encountering errors it fails silently. Error handling is done when the schema
|
||||
// is syntactically parsed and any error encountered here should also come up there.
|
||||
switch m := document.(type) {
|
||||
case []interface{}:
|
||||
for _, v := range m {
|
||||
p.parseReferencesRecursive(v, ref, draft)
|
||||
}
|
||||
case map[string]interface{}:
|
||||
localRef := &ref
|
||||
|
||||
keyID := KEY_ID_NEW
|
||||
if existsMapKey(m, KEY_ID) {
|
||||
keyID = KEY_ID
|
||||
}
|
||||
if existsMapKey(m, keyID) && isKind(m[keyID], reflect.String) {
|
||||
jsonReference, err := gojsonreference.NewJsonReference(m[keyID].(string))
|
||||
if err == nil {
|
||||
localRef, err = ref.Inherits(jsonReference)
|
||||
if err == nil {
|
||||
if _, ok := p.schemaPoolDocuments[localRef.String()]; ok {
|
||||
return fmt.Errorf("Reference already exists: \"%s\"", localRef.String())
|
||||
}
|
||||
p.schemaPoolDocuments[localRef.String()] = &schemaPoolDocument{Document: document, Draft: draft}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if existsMapKey(m, KEY_REF) && isKind(m[KEY_REF], reflect.String) {
|
||||
jsonReference, err := gojsonreference.NewJsonReference(m[KEY_REF].(string))
|
||||
if err == nil {
|
||||
absoluteRef, err := localRef.Inherits(jsonReference)
|
||||
if err == nil {
|
||||
m[KEY_REF] = absoluteRef.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range m {
|
||||
// const and enums should be interpreted literally, so ignore them
|
||||
if k == KEY_CONST || k == KEY_ENUM {
|
||||
continue
|
||||
}
|
||||
// Something like a property or a dependency is not a valid schema, as it might describe properties named "$ref", "$id" or "const", etc
|
||||
// Therefore don't treat it like a schema.
|
||||
if k == KEY_PROPERTIES || k == KEY_DEPENDENCIES || k == KEY_PATTERN_PROPERTIES {
|
||||
if child, ok := v.(map[string]interface{}); ok {
|
||||
for _, v := range child {
|
||||
p.parseReferencesRecursive(v, *localRef, draft)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.parseReferencesRecursive(v, *localRef, draft)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*schemaPoolDocument, error) {
|
||||
|
||||
var (
|
||||
spd *schemaPoolDocument
|
||||
draft *Draft
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("Get Document ( %s )", reference.String())
|
||||
}
|
||||
|
||||
// Create a deep copy, so we can remove the fragment part later on without altering the original
|
||||
refToURL, _ := gojsonreference.NewJsonReference(reference.String())
|
||||
|
||||
// First check if the given fragment is a location independent identifier
|
||||
// http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3
|
||||
|
||||
if spd, ok = p.schemaPoolDocuments[refToURL.String()]; ok {
|
||||
if internalLogEnabled {
|
||||
internalLog(" From pool")
|
||||
}
|
||||
return spd, nil
|
||||
}
|
||||
|
||||
// If the given reference is not a location independent identifier,
|
||||
// strip the fragment and look for a document with it's base URI
|
||||
|
||||
refToURL.GetUrl().Fragment = ""
|
||||
|
||||
if cachedSpd, ok := p.schemaPoolDocuments[refToURL.String()]; ok {
|
||||
document, _, err := reference.GetPointer().Get(cachedSpd.Document)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog(" From pool")
|
||||
}
|
||||
|
||||
spd = &schemaPoolDocument{Document: document, Draft: cachedSpd.Draft}
|
||||
p.schemaPoolDocuments[reference.String()] = spd
|
||||
|
||||
return spd, nil
|
||||
}
|
||||
|
||||
// It is not possible to load anything remotely that is not canonical...
|
||||
if !reference.IsCanonical() {
|
||||
return nil, errors.New(formatErrorDescription(
|
||||
Locale.ReferenceMustBeCanonical(),
|
||||
ErrorDetails{"reference": reference.String()},
|
||||
))
|
||||
}
|
||||
|
||||
jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String())
|
||||
document, err := jsonReferenceLoader.LoadJSON()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add the whole document to the pool for potential re-use
|
||||
p.parseReferences(document, refToURL, true)
|
||||
|
||||
_, draft, _ = parseSchemaURL(document)
|
||||
|
||||
// resolve the potential fragment and also cache it
|
||||
document, _, err = reference.GetPointer().Get(document)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &schemaPoolDocument{Document: document, Draft: draft}, nil
|
||||
}
|
68
vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go
generated
vendored
Normal file
68
vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// 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 Pool of referenced schemas.
|
||||
//
|
||||
// created 25-06-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type schemaReferencePool struct {
|
||||
documents map[string]*subSchema
|
||||
}
|
||||
|
||||
func newSchemaReferencePool() *schemaReferencePool {
|
||||
|
||||
p := &schemaReferencePool{}
|
||||
p.documents = make(map[string]*subSchema)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *schemaReferencePool) Get(ref string) (r *subSchema, o bool) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog(fmt.Sprintf("Schema Reference ( %s )", ref))
|
||||
}
|
||||
|
||||
if sch, ok := p.documents[ref]; ok {
|
||||
if internalLogEnabled {
|
||||
internalLog(fmt.Sprintf(" From pool"))
|
||||
}
|
||||
return sch, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *schemaReferencePool) Add(ref string, sch *subSchema) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog(fmt.Sprintf("Add Schema Reference %s to pool", ref))
|
||||
}
|
||||
if _, ok := p.documents[ref]; !ok {
|
||||
p.documents[ref] = sch
|
||||
}
|
||||
}
|
83
vendor/github.com/xeipuuv/gojsonschema/schemaType.go
generated
vendored
Normal file
83
vendor/github.com/xeipuuv/gojsonschema/schemaType.go
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
// 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 Helper structure to handle schema types, and the combination of them.
|
||||
//
|
||||
// created 28-02-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type jsonSchemaType struct {
|
||||
types []string
|
||||
}
|
||||
|
||||
// Is the schema typed ? that is containing at least one type
|
||||
// When not typed, the schema does not need any type validation
|
||||
func (t *jsonSchemaType) IsTyped() bool {
|
||||
return len(t.types) > 0
|
||||
}
|
||||
|
||||
func (t *jsonSchemaType) Add(etype string) error {
|
||||
|
||||
if !isStringInSlice(JSON_TYPES, etype) {
|
||||
return errors.New(formatErrorDescription(Locale.NotAValidType(), ErrorDetails{"given": "/" + etype + "/", "expected": JSON_TYPES}))
|
||||
}
|
||||
|
||||
if t.Contains(etype) {
|
||||
return errors.New(formatErrorDescription(Locale.Duplicated(), ErrorDetails{"type": etype}))
|
||||
}
|
||||
|
||||
t.types = append(t.types, etype)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *jsonSchemaType) Contains(etype string) bool {
|
||||
|
||||
for _, v := range t.types {
|
||||
if v == etype {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *jsonSchemaType) String() string {
|
||||
|
||||
if len(t.types) == 0 {
|
||||
return STRING_UNDEFINED // should never happen
|
||||
}
|
||||
|
||||
// Displayed as a list [type1,type2,...]
|
||||
if len(t.types) > 1 {
|
||||
return fmt.Sprintf("[%s]", strings.Join(t.types, ","))
|
||||
}
|
||||
|
||||
// Only one type: name only
|
||||
return t.types[0]
|
||||
}
|
149
vendor/github.com/xeipuuv/gojsonschema/subSchema.go
generated
vendored
Normal file
149
vendor/github.com/xeipuuv/gojsonschema/subSchema.go
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
// 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 Defines the structure of a sub-subSchema.
|
||||
// A sub-subSchema can contain other sub-schemas.
|
||||
//
|
||||
// created 27-02-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"github.com/xeipuuv/gojsonreference"
|
||||
"math/big"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Constants
|
||||
const (
|
||||
KEY_SCHEMA = "$schema"
|
||||
KEY_ID = "id"
|
||||
KEY_ID_NEW = "$id"
|
||||
KEY_REF = "$ref"
|
||||
KEY_TITLE = "title"
|
||||
KEY_DESCRIPTION = "description"
|
||||
KEY_TYPE = "type"
|
||||
KEY_ITEMS = "items"
|
||||
KEY_ADDITIONAL_ITEMS = "additionalItems"
|
||||
KEY_PROPERTIES = "properties"
|
||||
KEY_PATTERN_PROPERTIES = "patternProperties"
|
||||
KEY_ADDITIONAL_PROPERTIES = "additionalProperties"
|
||||
KEY_PROPERTY_NAMES = "propertyNames"
|
||||
KEY_DEFINITIONS = "definitions"
|
||||
KEY_MULTIPLE_OF = "multipleOf"
|
||||
KEY_MINIMUM = "minimum"
|
||||
KEY_MAXIMUM = "maximum"
|
||||
KEY_EXCLUSIVE_MINIMUM = "exclusiveMinimum"
|
||||
KEY_EXCLUSIVE_MAXIMUM = "exclusiveMaximum"
|
||||
KEY_MIN_LENGTH = "minLength"
|
||||
KEY_MAX_LENGTH = "maxLength"
|
||||
KEY_PATTERN = "pattern"
|
||||
KEY_FORMAT = "format"
|
||||
KEY_MIN_PROPERTIES = "minProperties"
|
||||
KEY_MAX_PROPERTIES = "maxProperties"
|
||||
KEY_DEPENDENCIES = "dependencies"
|
||||
KEY_REQUIRED = "required"
|
||||
KEY_MIN_ITEMS = "minItems"
|
||||
KEY_MAX_ITEMS = "maxItems"
|
||||
KEY_UNIQUE_ITEMS = "uniqueItems"
|
||||
KEY_CONTAINS = "contains"
|
||||
KEY_CONST = "const"
|
||||
KEY_ENUM = "enum"
|
||||
KEY_ONE_OF = "oneOf"
|
||||
KEY_ANY_OF = "anyOf"
|
||||
KEY_ALL_OF = "allOf"
|
||||
KEY_NOT = "not"
|
||||
KEY_IF = "if"
|
||||
KEY_THEN = "then"
|
||||
KEY_ELSE = "else"
|
||||
)
|
||||
|
||||
type subSchema struct {
|
||||
draft *Draft
|
||||
|
||||
// basic subSchema meta properties
|
||||
id *gojsonreference.JsonReference
|
||||
title *string
|
||||
description *string
|
||||
|
||||
property string
|
||||
|
||||
// Quick pass/fail for boolean schemas
|
||||
pass *bool
|
||||
|
||||
// Types associated with the subSchema
|
||||
types jsonSchemaType
|
||||
|
||||
// Reference url
|
||||
ref *gojsonreference.JsonReference
|
||||
// Schema referenced
|
||||
refSchema *subSchema
|
||||
|
||||
// hierarchy
|
||||
parent *subSchema
|
||||
itemsChildren []*subSchema
|
||||
itemsChildrenIsSingleSchema bool
|
||||
propertiesChildren []*subSchema
|
||||
|
||||
// validation : number / integer
|
||||
multipleOf *big.Rat
|
||||
maximum *big.Rat
|
||||
exclusiveMaximum *big.Rat
|
||||
minimum *big.Rat
|
||||
exclusiveMinimum *big.Rat
|
||||
|
||||
// validation : string
|
||||
minLength *int
|
||||
maxLength *int
|
||||
pattern *regexp.Regexp
|
||||
format string
|
||||
|
||||
// validation : object
|
||||
minProperties *int
|
||||
maxProperties *int
|
||||
required []string
|
||||
|
||||
dependencies map[string]interface{}
|
||||
additionalProperties interface{}
|
||||
patternProperties map[string]*subSchema
|
||||
propertyNames *subSchema
|
||||
|
||||
// validation : array
|
||||
minItems *int
|
||||
maxItems *int
|
||||
uniqueItems bool
|
||||
contains *subSchema
|
||||
|
||||
additionalItems interface{}
|
||||
|
||||
// validation : all
|
||||
_const *string //const is a golang keyword
|
||||
enum []string
|
||||
|
||||
// validation : subSchema
|
||||
oneOf []*subSchema
|
||||
anyOf []*subSchema
|
||||
allOf []*subSchema
|
||||
not *subSchema
|
||||
_if *subSchema // if/else are golang keywords
|
||||
_then *subSchema
|
||||
_else *subSchema
|
||||
}
|
62
vendor/github.com/xeipuuv/gojsonschema/types.go
generated
vendored
Normal file
62
vendor/github.com/xeipuuv/gojsonschema/types.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
// 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 types for schema and JSON.
|
||||
//
|
||||
// created 28-02-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
// Type constants
|
||||
const (
|
||||
TYPE_ARRAY = `array`
|
||||
TYPE_BOOLEAN = `boolean`
|
||||
TYPE_INTEGER = `integer`
|
||||
TYPE_NUMBER = `number`
|
||||
TYPE_NULL = `null`
|
||||
TYPE_OBJECT = `object`
|
||||
TYPE_STRING = `string`
|
||||
)
|
||||
|
||||
// JSON_TYPES hosts the list of type that are supported in JSON
|
||||
var JSON_TYPES []string
|
||||
|
||||
// SCHEMA_TYPES hosts the list of type that are supported in schemas
|
||||
var SCHEMA_TYPES []string
|
||||
|
||||
func init() {
|
||||
JSON_TYPES = []string{
|
||||
TYPE_ARRAY,
|
||||
TYPE_BOOLEAN,
|
||||
TYPE_INTEGER,
|
||||
TYPE_NUMBER,
|
||||
TYPE_NULL,
|
||||
TYPE_OBJECT,
|
||||
TYPE_STRING}
|
||||
|
||||
SCHEMA_TYPES = []string{
|
||||
TYPE_ARRAY,
|
||||
TYPE_BOOLEAN,
|
||||
TYPE_INTEGER,
|
||||
TYPE_NUMBER,
|
||||
TYPE_OBJECT,
|
||||
TYPE_STRING}
|
||||
}
|
197
vendor/github.com/xeipuuv/gojsonschema/utils.go
generated
vendored
Normal file
197
vendor/github.com/xeipuuv/gojsonschema/utils.go
generated
vendored
Normal file
@ -0,0 +1,197 @@
|
||||
// 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 Various utility functions.
|
||||
//
|
||||
// created 26-02-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func isKind(what interface{}, kinds ...reflect.Kind) bool {
|
||||
target := what
|
||||
if isJSONNumber(what) {
|
||||
// JSON Numbers are strings!
|
||||
target = *mustBeNumber(what)
|
||||
}
|
||||
targetKind := reflect.ValueOf(target).Kind()
|
||||
for _, kind := range kinds {
|
||||
if targetKind == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func existsMapKey(m map[string]interface{}, k string) bool {
|
||||
_, ok := m[k]
|
||||
return ok
|
||||
}
|
||||
|
||||
func isStringInSlice(s []string, what string) bool {
|
||||
for i := range s {
|
||||
if s[i] == what {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// indexStringInSlice returns the index of the first instance of 'what' in s or -1 if it is not found in s.
|
||||
func indexStringInSlice(s []string, what string) int {
|
||||
for i := range s {
|
||||
if s[i] == what {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func marshalToJSONString(value interface{}) (*string, error) {
|
||||
|
||||
mBytes, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sBytes := string(mBytes)
|
||||
return &sBytes, nil
|
||||
}
|
||||
|
||||
func marshalWithoutNumber(value interface{}) (*string, error) {
|
||||
|
||||
// The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber
|
||||
// This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1
|
||||
// One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber
|
||||
// so that these differences in representation are removed
|
||||
|
||||
jsonString, err := marshalToJSONString(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var document interface{}
|
||||
|
||||
err = json.Unmarshal([]byte(*jsonString), &document)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return marshalToJSONString(document)
|
||||
}
|
||||
|
||||
func isJSONNumber(what interface{}) bool {
|
||||
|
||||
switch what.(type) {
|
||||
|
||||
case json.Number:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkJSONInteger(what interface{}) (isInt bool) {
|
||||
|
||||
jsonNumber := what.(json.Number)
|
||||
|
||||
bigFloat, isValidNumber := new(big.Rat).SetString(string(jsonNumber))
|
||||
|
||||
return isValidNumber && bigFloat.IsInt()
|
||||
|
||||
}
|
||||
|
||||
// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
|
||||
const (
|
||||
maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
|
||||
minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
|
||||
)
|
||||
|
||||
func mustBeInteger(what interface{}) *int {
|
||||
|
||||
if isJSONNumber(what) {
|
||||
|
||||
number := what.(json.Number)
|
||||
|
||||
isInt := checkJSONInteger(number)
|
||||
|
||||
if isInt {
|
||||
|
||||
int64Value, err := number.Int64()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
int32Value := int(int64Value)
|
||||
return &int32Value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mustBeNumber(what interface{}) *big.Rat {
|
||||
|
||||
if isJSONNumber(what) {
|
||||
number := what.(json.Number)
|
||||
float64Value, success := new(big.Rat).SetString(string(number))
|
||||
if success {
|
||||
return float64Value
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func convertDocumentNode(val interface{}) interface{} {
|
||||
|
||||
if lval, ok := val.([]interface{}); ok {
|
||||
|
||||
res := []interface{}{}
|
||||
for _, v := range lval {
|
||||
res = append(res, convertDocumentNode(v))
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
}
|
||||
|
||||
if mval, ok := val.(map[interface{}]interface{}); ok {
|
||||
|
||||
res := map[string]interface{}{}
|
||||
|
||||
for k, v := range mval {
|
||||
res[k.(string)] = convertDocumentNode(v)
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
858
vendor/github.com/xeipuuv/gojsonschema/validation.go
generated
vendored
Normal file
858
vendor/github.com/xeipuuv/gojsonschema/validation.go
generated
vendored
Normal file
@ -0,0 +1,858 @@
|
||||
// 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 Extends Schema and subSchema, implements the validation phase.
|
||||
//
|
||||
// created 28-02-2013
|
||||
|
||||
package gojsonschema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Validate loads and validates a JSON schema
|
||||
func Validate(ls JSONLoader, ld JSONLoader) (*Result, error) {
|
||||
// load schema
|
||||
schema, err := NewSchema(ls)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return schema.Validate(ld)
|
||||
}
|
||||
|
||||
// Validate loads and validates a JSON document
|
||||
func (v *Schema) Validate(l JSONLoader) (*Result, error) {
|
||||
root, err := l.LoadJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.validateDocument(root), nil
|
||||
}
|
||||
|
||||
func (v *Schema) validateDocument(root interface{}) *Result {
|
||||
result := &Result{}
|
||||
context := NewJsonContext(STRING_CONTEXT_ROOT, nil)
|
||||
v.rootSchema.validateRecursive(v.rootSchema, root, result, context)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *subSchema) subValidateWithContext(document interface{}, context *JsonContext) *Result {
|
||||
result := &Result{}
|
||||
v.validateRecursive(v, document, result, context)
|
||||
return result
|
||||
}
|
||||
|
||||
// Walker function to validate the json recursively against the subSchema
|
||||
func (v *subSchema) validateRecursive(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateRecursive %s", context.String())
|
||||
internalLog(" %v", currentNode)
|
||||
}
|
||||
|
||||
// Handle true/false schema as early as possible as all other fields will be nil
|
||||
if currentSubSchema.pass != nil {
|
||||
if !*currentSubSchema.pass {
|
||||
result.addInternalError(
|
||||
new(FalseError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{},
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Handle referenced schemas, returns directly when a $ref is found
|
||||
if currentSubSchema.refSchema != nil {
|
||||
v.validateRecursive(currentSubSchema.refSchema, currentNode, result, context)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for null value
|
||||
if currentNode == nil {
|
||||
if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_NULL) {
|
||||
result.addInternalError(
|
||||
new(InvalidTypeError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{
|
||||
"expected": currentSubSchema.types.String(),
|
||||
"given": TYPE_NULL,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
currentSubSchema.validateSchema(currentSubSchema, currentNode, result, context)
|
||||
v.validateCommon(currentSubSchema, currentNode, result, context)
|
||||
|
||||
} else { // Not a null value
|
||||
|
||||
if isJSONNumber(currentNode) {
|
||||
|
||||
value := currentNode.(json.Number)
|
||||
|
||||
isInt := checkJSONInteger(value)
|
||||
|
||||
validType := currentSubSchema.types.Contains(TYPE_NUMBER) || (isInt && currentSubSchema.types.Contains(TYPE_INTEGER))
|
||||
|
||||
if currentSubSchema.types.IsTyped() && !validType {
|
||||
|
||||
givenType := TYPE_INTEGER
|
||||
if !isInt {
|
||||
givenType = TYPE_NUMBER
|
||||
}
|
||||
|
||||
result.addInternalError(
|
||||
new(InvalidTypeError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{
|
||||
"expected": currentSubSchema.types.String(),
|
||||
"given": givenType,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
currentSubSchema.validateSchema(currentSubSchema, value, result, context)
|
||||
v.validateNumber(currentSubSchema, value, result, context)
|
||||
v.validateCommon(currentSubSchema, value, result, context)
|
||||
v.validateString(currentSubSchema, value, result, context)
|
||||
|
||||
} else {
|
||||
|
||||
rValue := reflect.ValueOf(currentNode)
|
||||
rKind := rValue.Kind()
|
||||
|
||||
switch rKind {
|
||||
|
||||
// Slice => JSON array
|
||||
|
||||
case reflect.Slice:
|
||||
|
||||
if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_ARRAY) {
|
||||
result.addInternalError(
|
||||
new(InvalidTypeError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{
|
||||
"expected": currentSubSchema.types.String(),
|
||||
"given": TYPE_ARRAY,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
castCurrentNode := currentNode.([]interface{})
|
||||
|
||||
currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context)
|
||||
|
||||
v.validateArray(currentSubSchema, castCurrentNode, result, context)
|
||||
v.validateCommon(currentSubSchema, castCurrentNode, result, context)
|
||||
|
||||
// Map => JSON object
|
||||
|
||||
case reflect.Map:
|
||||
if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_OBJECT) {
|
||||
result.addInternalError(
|
||||
new(InvalidTypeError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{
|
||||
"expected": currentSubSchema.types.String(),
|
||||
"given": TYPE_OBJECT,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
castCurrentNode, ok := currentNode.(map[string]interface{})
|
||||
if !ok {
|
||||
castCurrentNode = convertDocumentNode(currentNode).(map[string]interface{})
|
||||
}
|
||||
|
||||
currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context)
|
||||
|
||||
v.validateObject(currentSubSchema, castCurrentNode, result, context)
|
||||
v.validateCommon(currentSubSchema, castCurrentNode, result, context)
|
||||
|
||||
for _, pSchema := range currentSubSchema.propertiesChildren {
|
||||
nextNode, ok := castCurrentNode[pSchema.property]
|
||||
if ok {
|
||||
subContext := NewJsonContext(pSchema.property, context)
|
||||
v.validateRecursive(pSchema, nextNode, result, subContext)
|
||||
}
|
||||
}
|
||||
|
||||
// Simple JSON values : string, number, boolean
|
||||
|
||||
case reflect.Bool:
|
||||
|
||||
if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_BOOLEAN) {
|
||||
result.addInternalError(
|
||||
new(InvalidTypeError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{
|
||||
"expected": currentSubSchema.types.String(),
|
||||
"given": TYPE_BOOLEAN,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
value := currentNode.(bool)
|
||||
|
||||
currentSubSchema.validateSchema(currentSubSchema, value, result, context)
|
||||
v.validateNumber(currentSubSchema, value, result, context)
|
||||
v.validateCommon(currentSubSchema, value, result, context)
|
||||
v.validateString(currentSubSchema, value, result, context)
|
||||
|
||||
case reflect.String:
|
||||
|
||||
if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_STRING) {
|
||||
result.addInternalError(
|
||||
new(InvalidTypeError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{
|
||||
"expected": currentSubSchema.types.String(),
|
||||
"given": TYPE_STRING,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
value := currentNode.(string)
|
||||
|
||||
currentSubSchema.validateSchema(currentSubSchema, value, result, context)
|
||||
v.validateNumber(currentSubSchema, value, result, context)
|
||||
v.validateCommon(currentSubSchema, value, result, context)
|
||||
v.validateString(currentSubSchema, value, result, context)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
||||
|
||||
// Different kinds of validation there, subSchema / common / array / object / string...
|
||||
func (v *subSchema) validateSchema(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateSchema %s", context.String())
|
||||
internalLog(" %v", currentNode)
|
||||
}
|
||||
|
||||
if len(currentSubSchema.anyOf) > 0 {
|
||||
|
||||
validatedAnyOf := false
|
||||
var bestValidationResult *Result
|
||||
|
||||
for _, anyOfSchema := range currentSubSchema.anyOf {
|
||||
if !validatedAnyOf {
|
||||
validationResult := anyOfSchema.subValidateWithContext(currentNode, context)
|
||||
validatedAnyOf = validationResult.Valid()
|
||||
|
||||
if !validatedAnyOf && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) {
|
||||
bestValidationResult = validationResult
|
||||
}
|
||||
}
|
||||
}
|
||||
if !validatedAnyOf {
|
||||
|
||||
result.addInternalError(new(NumberAnyOfError), context, currentNode, ErrorDetails{})
|
||||
|
||||
if bestValidationResult != nil {
|
||||
// add error messages of closest matching subSchema as
|
||||
// that's probably the one the user was trying to match
|
||||
result.mergeErrors(bestValidationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(currentSubSchema.oneOf) > 0 {
|
||||
|
||||
nbValidated := 0
|
||||
var bestValidationResult *Result
|
||||
|
||||
for _, oneOfSchema := range currentSubSchema.oneOf {
|
||||
validationResult := oneOfSchema.subValidateWithContext(currentNode, context)
|
||||
if validationResult.Valid() {
|
||||
nbValidated++
|
||||
} else if nbValidated == 0 && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) {
|
||||
bestValidationResult = validationResult
|
||||
}
|
||||
}
|
||||
|
||||
if nbValidated != 1 {
|
||||
|
||||
result.addInternalError(new(NumberOneOfError), context, currentNode, ErrorDetails{})
|
||||
|
||||
if nbValidated == 0 {
|
||||
// add error messages of closest matching subSchema as
|
||||
// that's probably the one the user was trying to match
|
||||
result.mergeErrors(bestValidationResult)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(currentSubSchema.allOf) > 0 {
|
||||
nbValidated := 0
|
||||
|
||||
for _, allOfSchema := range currentSubSchema.allOf {
|
||||
validationResult := allOfSchema.subValidateWithContext(currentNode, context)
|
||||
if validationResult.Valid() {
|
||||
nbValidated++
|
||||
}
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
|
||||
if nbValidated != len(currentSubSchema.allOf) {
|
||||
result.addInternalError(new(NumberAllOfError), context, currentNode, ErrorDetails{})
|
||||
}
|
||||
}
|
||||
|
||||
if currentSubSchema.not != nil {
|
||||
validationResult := currentSubSchema.not.subValidateWithContext(currentNode, context)
|
||||
if validationResult.Valid() {
|
||||
result.addInternalError(new(NumberNotError), context, currentNode, ErrorDetails{})
|
||||
}
|
||||
}
|
||||
|
||||
if currentSubSchema.dependencies != nil && len(currentSubSchema.dependencies) > 0 {
|
||||
if isKind(currentNode, reflect.Map) {
|
||||
for elementKey := range currentNode.(map[string]interface{}) {
|
||||
if dependency, ok := currentSubSchema.dependencies[elementKey]; ok {
|
||||
switch dependency := dependency.(type) {
|
||||
|
||||
case []string:
|
||||
for _, dependOnKey := range dependency {
|
||||
if _, dependencyResolved := currentNode.(map[string]interface{})[dependOnKey]; !dependencyResolved {
|
||||
result.addInternalError(
|
||||
new(MissingDependencyError),
|
||||
context,
|
||||
currentNode,
|
||||
ErrorDetails{"dependency": dependOnKey},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
case *subSchema:
|
||||
dependency.validateRecursive(dependency, currentNode, result, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentSubSchema._if != nil {
|
||||
validationResultIf := currentSubSchema._if.subValidateWithContext(currentNode, context)
|
||||
if currentSubSchema._then != nil && validationResultIf.Valid() {
|
||||
validationResultThen := currentSubSchema._then.subValidateWithContext(currentNode, context)
|
||||
if !validationResultThen.Valid() {
|
||||
result.addInternalError(new(ConditionThenError), context, currentNode, ErrorDetails{})
|
||||
result.mergeErrors(validationResultThen)
|
||||
}
|
||||
}
|
||||
if currentSubSchema._else != nil && !validationResultIf.Valid() {
|
||||
validationResultElse := currentSubSchema._else.subValidateWithContext(currentNode, context)
|
||||
if !validationResultElse.Valid() {
|
||||
result.addInternalError(new(ConditionElseError), context, currentNode, ErrorDetails{})
|
||||
result.mergeErrors(validationResultElse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
||||
|
||||
func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateCommon %s", context.String())
|
||||
internalLog(" %v", value)
|
||||
}
|
||||
|
||||
// const:
|
||||
if currentSubSchema._const != nil {
|
||||
vString, err := marshalWithoutNumber(value)
|
||||
if err != nil {
|
||||
result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err})
|
||||
}
|
||||
if *vString != *currentSubSchema._const {
|
||||
result.addInternalError(new(ConstError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{
|
||||
"allowed": *currentSubSchema._const,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// enum:
|
||||
if len(currentSubSchema.enum) > 0 {
|
||||
vString, err := marshalWithoutNumber(value)
|
||||
if err != nil {
|
||||
result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err})
|
||||
}
|
||||
if !isStringInSlice(currentSubSchema.enum, *vString) {
|
||||
result.addInternalError(
|
||||
new(EnumError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{
|
||||
"allowed": strings.Join(currentSubSchema.enum, ", "),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
||||
|
||||
func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateArray %s", context.String())
|
||||
internalLog(" %v", value)
|
||||
}
|
||||
|
||||
nbValues := len(value)
|
||||
|
||||
// TODO explain
|
||||
if currentSubSchema.itemsChildrenIsSingleSchema {
|
||||
for i := range value {
|
||||
subContext := NewJsonContext(strconv.Itoa(i), context)
|
||||
validationResult := currentSubSchema.itemsChildren[0].subValidateWithContext(value[i], subContext)
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
} else {
|
||||
if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 {
|
||||
|
||||
nbItems := len(currentSubSchema.itemsChildren)
|
||||
|
||||
// while we have both schemas and values, check them against each other
|
||||
for i := 0; i != nbItems && i != nbValues; i++ {
|
||||
subContext := NewJsonContext(strconv.Itoa(i), context)
|
||||
validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext)
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
|
||||
if nbItems < nbValues {
|
||||
// we have less schemas than elements in the instance array,
|
||||
// but that might be ok if "additionalItems" is specified.
|
||||
|
||||
switch currentSubSchema.additionalItems.(type) {
|
||||
case bool:
|
||||
if !currentSubSchema.additionalItems.(bool) {
|
||||
result.addInternalError(new(ArrayNoAdditionalItemsError), context, value, ErrorDetails{})
|
||||
}
|
||||
case *subSchema:
|
||||
additionalItemSchema := currentSubSchema.additionalItems.(*subSchema)
|
||||
for i := nbItems; i != nbValues; i++ {
|
||||
subContext := NewJsonContext(strconv.Itoa(i), context)
|
||||
validationResult := additionalItemSchema.subValidateWithContext(value[i], subContext)
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// minItems & maxItems
|
||||
if currentSubSchema.minItems != nil {
|
||||
if nbValues < int(*currentSubSchema.minItems) {
|
||||
result.addInternalError(
|
||||
new(ArrayMinItemsError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"min": *currentSubSchema.minItems},
|
||||
)
|
||||
}
|
||||
}
|
||||
if currentSubSchema.maxItems != nil {
|
||||
if nbValues > int(*currentSubSchema.maxItems) {
|
||||
result.addInternalError(
|
||||
new(ArrayMaxItemsError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"max": *currentSubSchema.maxItems},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// uniqueItems:
|
||||
if currentSubSchema.uniqueItems {
|
||||
var stringifiedItems = make(map[string]int)
|
||||
for j, v := range value {
|
||||
vString, err := marshalWithoutNumber(v)
|
||||
if err != nil {
|
||||
result.addInternalError(new(InternalError), context, value, ErrorDetails{"err": err})
|
||||
}
|
||||
if i, ok := stringifiedItems[*vString]; ok {
|
||||
result.addInternalError(
|
||||
new(ItemsMustBeUniqueError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"type": TYPE_ARRAY, "i": i, "j": j},
|
||||
)
|
||||
}
|
||||
stringifiedItems[*vString] = j
|
||||
}
|
||||
}
|
||||
|
||||
// contains:
|
||||
|
||||
if currentSubSchema.contains != nil {
|
||||
validatedOne := false
|
||||
var bestValidationResult *Result
|
||||
|
||||
for i, v := range value {
|
||||
subContext := NewJsonContext(strconv.Itoa(i), context)
|
||||
|
||||
validationResult := currentSubSchema.contains.subValidateWithContext(v, subContext)
|
||||
if validationResult.Valid() {
|
||||
validatedOne = true
|
||||
break
|
||||
} else {
|
||||
if bestValidationResult == nil || validationResult.score > bestValidationResult.score {
|
||||
bestValidationResult = validationResult
|
||||
}
|
||||
}
|
||||
}
|
||||
if !validatedOne {
|
||||
result.addInternalError(
|
||||
new(ArrayContainsError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{},
|
||||
)
|
||||
if bestValidationResult != nil {
|
||||
result.mergeErrors(bestValidationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
||||
|
||||
func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string]interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateObject %s", context.String())
|
||||
internalLog(" %v", value)
|
||||
}
|
||||
|
||||
// minProperties & maxProperties:
|
||||
if currentSubSchema.minProperties != nil {
|
||||
if len(value) < int(*currentSubSchema.minProperties) {
|
||||
result.addInternalError(
|
||||
new(ArrayMinPropertiesError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"min": *currentSubSchema.minProperties},
|
||||
)
|
||||
}
|
||||
}
|
||||
if currentSubSchema.maxProperties != nil {
|
||||
if len(value) > int(*currentSubSchema.maxProperties) {
|
||||
result.addInternalError(
|
||||
new(ArrayMaxPropertiesError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"max": *currentSubSchema.maxProperties},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// required:
|
||||
for _, requiredProperty := range currentSubSchema.required {
|
||||
_, ok := value[requiredProperty]
|
||||
if ok {
|
||||
result.incrementScore()
|
||||
} else {
|
||||
result.addInternalError(
|
||||
new(RequiredError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"property": requiredProperty},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// additionalProperty & patternProperty:
|
||||
for pk := range value {
|
||||
|
||||
// Check whether this property is described by "properties"
|
||||
found := false
|
||||
for _, spValue := range currentSubSchema.propertiesChildren {
|
||||
if pk == spValue.property {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether this property is described by "patternProperties"
|
||||
ppMatch := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context)
|
||||
|
||||
// If it is not described by neither "properties" nor "patternProperties" it must pass "additionalProperties"
|
||||
if !found && !ppMatch {
|
||||
switch ap := currentSubSchema.additionalProperties.(type) {
|
||||
case bool:
|
||||
// Handle the boolean case separately as it's cleaner to return a specific error than failing to pass the false schema
|
||||
if !ap {
|
||||
result.addInternalError(
|
||||
new(AdditionalPropertyNotAllowedError),
|
||||
context,
|
||||
value[pk],
|
||||
ErrorDetails{"property": pk},
|
||||
)
|
||||
|
||||
}
|
||||
case *subSchema:
|
||||
validationResult := ap.subValidateWithContext(value[pk], NewJsonContext(pk, context))
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// propertyNames:
|
||||
if currentSubSchema.propertyNames != nil {
|
||||
for pk := range value {
|
||||
validationResult := currentSubSchema.propertyNames.subValidateWithContext(pk, context)
|
||||
if !validationResult.Valid() {
|
||||
result.addInternalError(new(InvalidPropertyNameError),
|
||||
context,
|
||||
value, ErrorDetails{
|
||||
"property": pk,
|
||||
})
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
||||
|
||||
func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *JsonContext) bool {
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validatePatternProperty %s", context.String())
|
||||
internalLog(" %s %v", key, value)
|
||||
}
|
||||
|
||||
validated := false
|
||||
|
||||
for pk, pv := range currentSubSchema.patternProperties {
|
||||
if matches, _ := regexp.MatchString(pk, key); matches {
|
||||
validated = true
|
||||
subContext := NewJsonContext(key, context)
|
||||
validationResult := pv.subValidateWithContext(value, subContext)
|
||||
result.mergeErrors(validationResult)
|
||||
}
|
||||
}
|
||||
|
||||
if !validated {
|
||||
return false
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
return true
|
||||
}
|
||||
|
||||
func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
// Ignore JSON numbers
|
||||
if isJSONNumber(value) {
|
||||
return
|
||||
}
|
||||
|
||||
// Ignore non strings
|
||||
if !isKind(value, reflect.String) {
|
||||
return
|
||||
}
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateString %s", context.String())
|
||||
internalLog(" %v", value)
|
||||
}
|
||||
|
||||
stringValue := value.(string)
|
||||
|
||||
// minLength & maxLength:
|
||||
if currentSubSchema.minLength != nil {
|
||||
if utf8.RuneCount([]byte(stringValue)) < int(*currentSubSchema.minLength) {
|
||||
result.addInternalError(
|
||||
new(StringLengthGTEError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"min": *currentSubSchema.minLength},
|
||||
)
|
||||
}
|
||||
}
|
||||
if currentSubSchema.maxLength != nil {
|
||||
if utf8.RuneCount([]byte(stringValue)) > int(*currentSubSchema.maxLength) {
|
||||
result.addInternalError(
|
||||
new(StringLengthLTEError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"max": *currentSubSchema.maxLength},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// pattern:
|
||||
if currentSubSchema.pattern != nil {
|
||||
if !currentSubSchema.pattern.MatchString(stringValue) {
|
||||
result.addInternalError(
|
||||
new(DoesNotMatchPatternError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"pattern": currentSubSchema.pattern},
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// format
|
||||
if currentSubSchema.format != "" {
|
||||
if !FormatCheckers.IsFormat(currentSubSchema.format, stringValue) {
|
||||
result.addInternalError(
|
||||
new(DoesNotMatchFormatError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"format": currentSubSchema.format},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
||||
|
||||
func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) {
|
||||
|
||||
// Ignore non numbers
|
||||
if !isJSONNumber(value) {
|
||||
return
|
||||
}
|
||||
|
||||
if internalLogEnabled {
|
||||
internalLog("validateNumber %s", context.String())
|
||||
internalLog(" %v", value)
|
||||
}
|
||||
|
||||
number := value.(json.Number)
|
||||
float64Value, _ := new(big.Rat).SetString(string(number))
|
||||
|
||||
// multipleOf:
|
||||
if currentSubSchema.multipleOf != nil {
|
||||
if q := new(big.Rat).Quo(float64Value, currentSubSchema.multipleOf); !q.IsInt() {
|
||||
result.addInternalError(
|
||||
new(MultipleOfError),
|
||||
context,
|
||||
number,
|
||||
ErrorDetails{
|
||||
"multiple": new(big.Float).SetRat(currentSubSchema.multipleOf),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//maximum & exclusiveMaximum:
|
||||
if currentSubSchema.maximum != nil {
|
||||
if float64Value.Cmp(currentSubSchema.maximum) == 1 {
|
||||
result.addInternalError(
|
||||
new(NumberLTEError),
|
||||
context,
|
||||
number,
|
||||
ErrorDetails{
|
||||
"max": new(big.Float).SetRat(currentSubSchema.maximum),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
if currentSubSchema.exclusiveMaximum != nil {
|
||||
if float64Value.Cmp(currentSubSchema.exclusiveMaximum) >= 0 {
|
||||
result.addInternalError(
|
||||
new(NumberLTError),
|
||||
context,
|
||||
number,
|
||||
ErrorDetails{
|
||||
"max": new(big.Float).SetRat(currentSubSchema.exclusiveMaximum),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//minimum & exclusiveMinimum:
|
||||
if currentSubSchema.minimum != nil {
|
||||
if float64Value.Cmp(currentSubSchema.minimum) == -1 {
|
||||
result.addInternalError(
|
||||
new(NumberGTEError),
|
||||
context,
|
||||
number,
|
||||
ErrorDetails{
|
||||
"min": new(big.Float).SetRat(currentSubSchema.minimum),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
if currentSubSchema.exclusiveMinimum != nil {
|
||||
if float64Value.Cmp(currentSubSchema.exclusiveMinimum) <= 0 {
|
||||
result.addInternalError(
|
||||
new(NumberGTError),
|
||||
context,
|
||||
number,
|
||||
ErrorDetails{
|
||||
"min": new(big.Float).SetRat(currentSubSchema.exclusiveMinimum),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// format
|
||||
if currentSubSchema.format != "" {
|
||||
if !FormatCheckers.IsFormat(currentSubSchema.format, float64Value) {
|
||||
result.addInternalError(
|
||||
new(DoesNotMatchFormatError),
|
||||
context,
|
||||
value,
|
||||
ErrorDetails{"format": currentSubSchema.format},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
result.incrementScore()
|
||||
}
|
28
vendor/modules.txt
vendored
28
vendor/modules.txt
vendored
@ -67,6 +67,11 @@ github.com/cilium/ebpf/internal
|
||||
github.com/cilium/ebpf/internal/btf
|
||||
github.com/cilium/ebpf/internal/unix
|
||||
github.com/cilium/ebpf/link
|
||||
# github.com/container-orchestrated-devices/container-device-interface v0.3.1
|
||||
## explicit; go 1.17
|
||||
github.com/container-orchestrated-devices/container-device-interface/pkg/cdi
|
||||
github.com/container-orchestrated-devices/container-device-interface/schema
|
||||
github.com/container-orchestrated-devices/container-device-interface/specs-go
|
||||
# github.com/containerd/aufs v1.0.0
|
||||
## explicit; go 1.13
|
||||
github.com/containerd/aufs
|
||||
@ -332,10 +337,19 @@ github.com/opencontainers/image-spec/specs-go
|
||||
github.com/opencontainers/image-spec/specs-go/v1
|
||||
# github.com/opencontainers/runc v1.1.1
|
||||
## explicit; go 1.16
|
||||
github.com/opencontainers/runc/libcontainer/devices
|
||||
github.com/opencontainers/runc/libcontainer/user
|
||||
# github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||
## explicit
|
||||
github.com/opencontainers/runtime-spec/specs-go
|
||||
# github.com/opencontainers/runtime-tools v0.0.0-20190417131837-cd1349b7c47e
|
||||
## explicit
|
||||
github.com/opencontainers/runtime-tools/error
|
||||
github.com/opencontainers/runtime-tools/filepath
|
||||
github.com/opencontainers/runtime-tools/generate
|
||||
github.com/opencontainers/runtime-tools/generate/seccomp
|
||||
github.com/opencontainers/runtime-tools/specerror
|
||||
github.com/opencontainers/runtime-tools/validate
|
||||
# github.com/opencontainers/selinux v1.10.0
|
||||
## explicit; go 1.13
|
||||
github.com/opencontainers/selinux/go-selinux
|
||||
@ -388,6 +402,9 @@ github.com/stefanberger/go-pkcs11uri
|
||||
## explicit; go 1.13
|
||||
github.com/stretchr/testify/assert
|
||||
github.com/stretchr/testify/require
|
||||
# github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
|
||||
## explicit
|
||||
github.com/syndtr/gocapability/capability
|
||||
# github.com/tchap/go-patricia/v2 v2.3.1
|
||||
## explicit; go 1.16
|
||||
github.com/tchap/go-patricia/v2/patricia
|
||||
@ -401,6 +418,15 @@ github.com/vishvananda/netlink/nl
|
||||
# github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
|
||||
## explicit; go 1.12
|
||||
github.com/vishvananda/netns
|
||||
# github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f
|
||||
## explicit
|
||||
github.com/xeipuuv/gojsonpointer
|
||||
# github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415
|
||||
## explicit
|
||||
github.com/xeipuuv/gojsonreference
|
||||
# github.com/xeipuuv/gojsonschema v1.2.0
|
||||
## explicit
|
||||
github.com/xeipuuv/gojsonschema
|
||||
# go.etcd.io/bbolt v1.3.6
|
||||
## explicit; go 1.12
|
||||
go.etcd.io/bbolt
|
||||
@ -738,7 +764,7 @@ k8s.io/utils/integer
|
||||
# sigs.k8s.io/structured-merge-diff/v4 v4.1.2
|
||||
## explicit; go 1.13
|
||||
sigs.k8s.io/structured-merge-diff/v4/value
|
||||
# sigs.k8s.io/yaml v1.2.0
|
||||
# sigs.k8s.io/yaml v1.3.0
|
||||
## explicit; go 1.12
|
||||
sigs.k8s.io/yaml
|
||||
# github.com/urfave/cli => github.com/urfave/cli v1.22.1
|
||||
|
4
vendor/sigs.k8s.io/yaml/.gitignore
generated
vendored
4
vendor/sigs.k8s.io/yaml/.gitignore
generated
vendored
@ -6,6 +6,10 @@
|
||||
.project
|
||||
.settings/**
|
||||
|
||||
# Idea files
|
||||
.idea/**
|
||||
.idea/
|
||||
|
||||
# Emacs save files
|
||||
*~
|
||||
|
||||
|
7
vendor/sigs.k8s.io/yaml/.travis.yml
generated
vendored
7
vendor/sigs.k8s.io/yaml/.travis.yml
generated
vendored
@ -1,8 +1,7 @@
|
||||
language: go
|
||||
dist: xenial
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
arch: arm64
|
||||
dist: focal
|
||||
go: 1.15.x
|
||||
script:
|
||||
- diff -u <(echo -n) <(gofmt -d *.go)
|
||||
- diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON)
|
||||
|
2
vendor/sigs.k8s.io/yaml/README.md
generated
vendored
2
vendor/sigs.k8s.io/yaml/README.md
generated
vendored
@ -107,8 +107,8 @@ func main() {
|
||||
}
|
||||
fmt.Println(string(y))
|
||||
/* Output:
|
||||
name: John
|
||||
age: 30
|
||||
name: John
|
||||
*/
|
||||
j2, err := yaml.YAMLToJSON(y)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user