mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-05-06 19:08:13 +00:00
Merge pull request #1141 from balena-io/contract-l4t
Compare Linux4Tegra versions in contracts
This commit is contained in:
commit
05f4239cc6
147
package-lock.json
generated
147
package-lock.json
generated
@ -1195,8 +1195,7 @@
|
|||||||
"array-flatten": {
|
"array-flatten": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||||
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
|
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"array-from": {
|
"array-from": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@ -1573,7 +1572,7 @@
|
|||||||
"fetch-ponyfill": "^4.0.0",
|
"fetch-ponyfill": "^4.0.0",
|
||||||
"fetch-readablestream": "^0.2.0",
|
"fetch-readablestream": "^0.2.0",
|
||||||
"lodash": "^4.6.1",
|
"lodash": "^4.6.1",
|
||||||
"node-web-streams": "github:resin-io-modules/node-web-streams#46f98300b69090bde3f6b4983877ccfe283a892c",
|
"node-web-streams": "github:resin-io-modules/node-web-streams#emit-errors",
|
||||||
"progress-stream": "^2.0.0",
|
"progress-stream": "^2.0.0",
|
||||||
"qs": "^6.3.0",
|
"qs": "^6.3.0",
|
||||||
"rindle": "^1.3.1"
|
"rindle": "^1.3.1"
|
||||||
@ -1594,6 +1593,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fetch-readablestream/-/fetch-readablestream-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/fetch-readablestream/-/fetch-readablestream-0.2.0.tgz",
|
||||||
"integrity": "sha512-qu4mXWf4wus4idBIN/kVH+XSer8IZ9CwHP+Pd7DL7TuKNC1hP7ykon4kkBjwJF3EMX2WsFp4hH7gU7CyL7ucXw==",
|
"integrity": "sha512-qu4mXWf4wus4idBIN/kVH+XSer8IZ9CwHP+Pd7DL7TuKNC1hP7ykon4kkBjwJF3EMX2WsFp4hH7gU7CyL7ucXw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"node-web-streams": {
|
||||||
|
"version": "github:resin-io-modules/node-web-streams#46f98300b69090bde3f6b4983877ccfe283a892c",
|
||||||
|
"from": "github:resin-io-modules/node-web-streams#emit-errors",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"is-stream": "^1.1.0",
|
||||||
|
"web-streams-polyfill": "^1.3.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1709,7 +1717,7 @@
|
|||||||
"lodash": "^4.13.1",
|
"lodash": "^4.13.1",
|
||||||
"resin-cli-form": "^1.4.1",
|
"resin-cli-form": "^1.4.1",
|
||||||
"resin-cli-visuals": "^1.2.8",
|
"resin-cli-visuals": "^1.2.8",
|
||||||
"resin-discoverable-services": "git+https://github.com/resin-io-modules/resin-discoverable-services.git#afca9e4700ec5ef82aa897f14bd5a46f06518061",
|
"resin-discoverable-services": "git+https://github.com/resin-io-modules/resin-discoverable-services.git#find-on-all-interfaces",
|
||||||
"resin-semver": "^1.4.0",
|
"resin-semver": "^1.4.0",
|
||||||
"revalidator": "^0.3.1",
|
"revalidator": "^0.3.1",
|
||||||
"rindle": "^1.3.0",
|
"rindle": "^1.3.0",
|
||||||
@ -1727,6 +1735,18 @@
|
|||||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"bonjour": {
|
||||||
|
"version": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
|
||||||
|
"from": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
|
||||||
|
"requires": {
|
||||||
|
"array-flatten": "^2.1.0",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"dns-equal": "^1.0.0",
|
||||||
|
"dns-txt": "^2.0.2",
|
||||||
|
"multicast-dns": "git+https://github.com/resin-io-modules/multicast-dns.git#listen-on-all-interfaces",
|
||||||
|
"multicast-dns-service-types": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||||
@ -1765,6 +1785,32 @@
|
|||||||
"tar-stream": "^1.5.2"
|
"tar-stream": "^1.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"resin-discoverable-services": {
|
||||||
|
"version": "git+https://github.com/resin-io-modules/resin-discoverable-services.git#afca9e4700ec5ef82aa897f14bd5a46f06518061",
|
||||||
|
"from": "git+https://github.com/resin-io-modules/resin-discoverable-services.git#find-on-all-interfaces",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"bluebird": "^3.0.0",
|
||||||
|
"bonjour": "git+https://github.com/resin-io/bonjour.git#fixed-mdns",
|
||||||
|
"ip": "^1.1.4",
|
||||||
|
"lodash": "^4.17.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bonjour": {
|
||||||
|
"version": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
|
||||||
|
"from": "git+https://github.com/resin-io/bonjour.git#fixed-mdns",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-flatten": "^2.1.0",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"dns-equal": "^1.0.0",
|
||||||
|
"dns-txt": "^2.0.2",
|
||||||
|
"multicast-dns": "git+https://github.com/resin-io-modules/multicast-dns.git#listen-on-all-interfaces",
|
||||||
|
"multicast-dns-service-types": "^1.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||||
@ -1951,19 +1997,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bonjour": {
|
|
||||||
"version": "git+https://github.com/resin-io/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
|
|
||||||
"from": "git+https://github.com/resin-io/bonjour.git#fixed-mdns",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"array-flatten": "^2.1.0",
|
|
||||||
"deep-equal": "^1.0.1",
|
|
||||||
"dns-equal": "^1.0.0",
|
|
||||||
"dns-txt": "^2.0.2",
|
|
||||||
"multicast-dns": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
|
|
||||||
"multicast-dns-service-types": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
@ -2133,8 +2166,7 @@
|
|||||||
"buffer-indexof": {
|
"buffer-indexof": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
|
||||||
"integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
|
"integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"buffer-xor": {
|
"buffer-xor": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
@ -3010,10 +3042,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"deep-equal": {
|
"deep-equal": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
|
||||||
"integrity": "sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw==",
|
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-arguments": "^1.0.4",
|
"is-arguments": "^1.0.4",
|
||||||
"is-date-object": "^1.0.1",
|
"is-date-object": "^1.0.1",
|
||||||
@ -3070,7 +3101,6 @@
|
|||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
|
||||||
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
|
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"object-keys": "^1.0.12"
|
"object-keys": "^1.0.12"
|
||||||
}
|
}
|
||||||
@ -3268,14 +3298,12 @@
|
|||||||
"dns-equal": {
|
"dns-equal": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||||
"integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
|
"integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"dns-packet": {
|
"dns-packet": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
|
||||||
"integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
|
"integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ip": "^1.1.0",
|
"ip": "^1.1.0",
|
||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
@ -3285,7 +3313,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
|
||||||
"integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
|
"integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"buffer-indexof": "^1.0.0"
|
"buffer-indexof": "^1.0.0"
|
||||||
}
|
}
|
||||||
@ -5185,8 +5212,7 @@
|
|||||||
"function-bind": {
|
"function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"g-status": {
|
"g-status": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
@ -5565,7 +5591,6 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"function-bind": "^1.1.1"
|
"function-bind": "^1.1.1"
|
||||||
}
|
}
|
||||||
@ -6231,8 +6256,7 @@
|
|||||||
"ip": {
|
"ip": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||||
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
|
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"ipaddr.js": {
|
"ipaddr.js": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
@ -6273,8 +6297,7 @@
|
|||||||
"is-arguments": {
|
"is-arguments": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
|
||||||
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
|
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"is-arrayish": {
|
"is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
@ -6337,8 +6360,7 @@
|
|||||||
"is-date-object": {
|
"is-date-object": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
||||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"is-descriptor": {
|
"is-descriptor": {
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
@ -6487,7 +6509,6 @@
|
|||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
||||||
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
|
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"has": "^1.0.1"
|
"has": "^1.0.1"
|
||||||
}
|
}
|
||||||
@ -6847,7 +6868,7 @@
|
|||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
|
"resolved": "http://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
|
||||||
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
|
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
@ -8227,8 +8248,7 @@
|
|||||||
},
|
},
|
||||||
"multicast-dns": {
|
"multicast-dns": {
|
||||||
"version": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
|
"version": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
|
||||||
"from": "git+https://github.com/resin-io-modules/multicast-dns.git#a15c63464eb43e8925b187ed5cb9de6892e8aacc",
|
"from": "git+https://github.com/resin-io-modules/multicast-dns.git#listen-on-all-interfaces",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"dns-packet": "^1.0.1",
|
"dns-packet": "^1.0.1",
|
||||||
"thunky": "^0.1.0"
|
"thunky": "^0.1.0"
|
||||||
@ -8237,8 +8257,7 @@
|
|||||||
"multicast-dns-service-types": {
|
"multicast-dns-service-types": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
|
||||||
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
|
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"mute-stream": {
|
"mute-stream": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.5",
|
||||||
@ -8481,15 +8500,6 @@
|
|||||||
"integrity": "sha512-W0SgGKaB9qSCfFfNj2uQZ/5BlVumaNHjVCAPdEoXrkEJ3ynSf/806LEz1rbDFbJ4+PL9G8IxRkJJTvZndd5D9g==",
|
"integrity": "sha512-W0SgGKaB9qSCfFfNj2uQZ/5BlVumaNHjVCAPdEoXrkEJ3ynSf/806LEz1rbDFbJ4+PL9G8IxRkJJTvZndd5D9g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node-web-streams": {
|
|
||||||
"version": "github:resin-io-modules/node-web-streams#46f98300b69090bde3f6b4983877ccfe283a892c",
|
|
||||||
"from": "github:resin-io-modules/node-web-streams#46f98300b69090bde3f6b4983877ccfe283a892c",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"is-stream": "^1.1.0",
|
|
||||||
"web-streams-polyfill": "^1.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"noop-logger": {
|
"noop-logger": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
|
||||||
@ -8632,14 +8642,12 @@
|
|||||||
"object-is": {
|
"object-is": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz",
|
||||||
"integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=",
|
"integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"object-keys": {
|
"object-keys": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"object-visit": {
|
"object-visit": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -9540,7 +9548,6 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz",
|
||||||
"integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==",
|
"integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"define-properties": "^1.1.2"
|
"define-properties": "^1.1.2"
|
||||||
}
|
}
|
||||||
@ -9734,17 +9741,6 @@
|
|||||||
"lodash": "^4.0.0"
|
"lodash": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resin-discoverable-services": {
|
|
||||||
"version": "git+https://github.com/resin-io-modules/resin-discoverable-services.git#afca9e4700ec5ef82aa897f14bd5a46f06518061",
|
|
||||||
"from": "git+https://github.com/resin-io-modules/resin-discoverable-services.git#afca9e4700ec5ef82aa897f14bd5a46f06518061",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"bluebird": "^3.0.0",
|
|
||||||
"bonjour": "git+https://github.com/resin-io/bonjour.git#fixed-mdns",
|
|
||||||
"ip": "^1.1.4",
|
|
||||||
"lodash": "^4.17.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"resin-lint": {
|
"resin-lint": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/resin-lint/-/resin-lint-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/resin-lint/-/resin-lint-3.1.1.tgz",
|
||||||
@ -9773,9 +9769,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/bluebird": {
|
"@types/bluebird": {
|
||||||
"version": "3.5.28",
|
"version": "3.5.29",
|
||||||
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.28.tgz",
|
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.29.tgz",
|
||||||
"integrity": "sha512-0Vk/kqkukxPKSzP9c8WJgisgGDx5oZDbsLLWIP5t70yThO/YleE+GEm2S1GlRALTaack3O7U5OS5qEm7q2kciA==",
|
"integrity": "sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
@ -9795,6 +9791,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
|
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
|
||||||
"integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==",
|
"integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "1.19.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
|
||||||
|
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -11078,8 +11080,7 @@
|
|||||||
"thunky": {
|
"thunky": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz",
|
||||||
"integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=",
|
"integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"tildify": {
|
"tildify": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
"build:debug": "npm run typescript:release && npm run coffeescript:release && npm run migrations:copy && npm run packagejson:copy",
|
"build:debug": "npm run typescript:release && npm run coffeescript:release && npm run migrations:copy && npm run packagejson:copy",
|
||||||
"lint": "npm run lint:coffee && npm run lint:typescript",
|
"lint": "npm run lint:coffee && npm run lint:typescript",
|
||||||
"test": "npm run lint && npm run test:build && JUNIT_REPORT_PATH=report.xml istanbul cover _mocha && npm run coverage",
|
"test": "npm run lint && npm run test:build && TEST=1 JUNIT_REPORT_PATH=report.xml istanbul cover _mocha && npm run coverage",
|
||||||
"test:build": "npm run typescript:test-build && npm run coffeescript:test && npm run testitems:copy && npm run migrations:copy-test && npm run packagejson:copy",
|
"test:build": "npm run typescript:test-build && npm run coffeescript:test && npm run testitems:copy && npm run migrations:copy-test && npm run packagejson:copy",
|
||||||
"coverage": "istanbul report text && istanbul report html",
|
"coverage": "istanbul report text && istanbul report html",
|
||||||
"test:fast": "mocha --opts test/fast-mocha.opts",
|
"test:fast": "TEST=1 mocha --opts test/fast-mocha.opts",
|
||||||
"test:debug": "npm run test:build && mocha --inspect-brk",
|
"test:debug": "npm run test:build && TEST=1 mocha --inspect-brk",
|
||||||
"prettify": "prettier --config ./node_modules/resin-lint/config/.prettierrc --write \"{src,test,typings}/**/*.ts\"",
|
"prettify": "prettier --config ./node_modules/resin-lint/config/.prettierrc --write \"{src,test,typings}/**/*.ts\"",
|
||||||
"typescript:test-build": "tsc --project tsconfig.json",
|
"typescript:test-build": "tsc --project tsconfig.json",
|
||||||
"typescript:release": "tsc --project tsconfig.release.json && cp -r build/src/* build && rm -rf build/src",
|
"typescript:release": "tsc --project tsconfig.release.json && cp -r build/src/* build && rm -rf build/src",
|
||||||
|
@ -9,12 +9,12 @@ path = require 'path'
|
|||||||
constants = require './lib/constants'
|
constants = require './lib/constants'
|
||||||
{ log } = require './lib/supervisor-console'
|
{ log } = require './lib/supervisor-console'
|
||||||
|
|
||||||
{ containerContractsFulfilled, validateContract } = require './lib/contracts'
|
{ validateTargetContracts } = require './lib/contracts'
|
||||||
{ DockerUtils: Docker } = require './lib/docker-utils'
|
{ DockerUtils: Docker } = require './lib/docker-utils'
|
||||||
{ LocalModeManager } = require './local-mode'
|
{ LocalModeManager } = require './local-mode'
|
||||||
updateLock = require './lib/update-lock'
|
updateLock = require './lib/update-lock'
|
||||||
{ checkTruthy, checkInt, checkString } = require './lib/validation'
|
{ checkTruthy, checkInt, checkString } = require './lib/validation'
|
||||||
{ ContractViolationError, ContractValidationError, NotFoundError } = require './lib/errors'
|
{ ContractViolationError, NotFoundError } = require './lib/errors'
|
||||||
{ pathExistsOnHost } = require './lib/fs-utils'
|
{ pathExistsOnHost } = require './lib/fs-utils'
|
||||||
|
|
||||||
{ TargetStateAccessor } = require './target-state'
|
{ TargetStateAccessor } = require './target-state'
|
||||||
@ -683,34 +683,7 @@ module.exports = class ApplicationManager extends EventEmitter
|
|||||||
return outApp
|
return outApp
|
||||||
)
|
)
|
||||||
|
|
||||||
setTarget: (apps, dependent , source, trx) =>
|
setTarget: (apps, dependent , source, trx) ->
|
||||||
# We look at the container contracts here, as if we
|
|
||||||
# cannot run the release, we don't want it to be added
|
|
||||||
# to the database, overwriting the current release. This
|
|
||||||
# is because if we just reject the release, but leave it
|
|
||||||
# in the db, if for any reason the current state stops
|
|
||||||
# running, we won't restart it, leaving the device
|
|
||||||
# useless
|
|
||||||
contractsFulfilled = _.mapValues apps, (app) ->
|
|
||||||
serviceContracts = {}
|
|
||||||
_.each app.services, (s) ->
|
|
||||||
if s.contract?
|
|
||||||
try
|
|
||||||
validateContract(s.contract)
|
|
||||||
catch e
|
|
||||||
throw new ContractValidationError(s.serviceName, e.message)
|
|
||||||
serviceContracts[s.serviceName] =
|
|
||||||
contract: s.contract,
|
|
||||||
optional: checkTruthy(s.labels['io.balena.features.optional']) ? false
|
|
||||||
else
|
|
||||||
serviceContracts[s.serviceName] = { contract: null, optional: false }
|
|
||||||
|
|
||||||
if !_.isEmpty(serviceContracts)
|
|
||||||
containerContractsFulfilled(serviceContracts)
|
|
||||||
else
|
|
||||||
{ valid: true, fulfilledServices: _.map(app.services, 'serviceName') }
|
|
||||||
|
|
||||||
|
|
||||||
setInTransaction = (filteredApps, trx) =>
|
setInTransaction = (filteredApps, trx) =>
|
||||||
Promise.try =>
|
Promise.try =>
|
||||||
appsArray = _.map filteredApps, (app, appId) ->
|
appsArray = _.map filteredApps, (app, appId) ->
|
||||||
@ -734,8 +707,18 @@ module.exports = class ApplicationManager extends EventEmitter
|
|||||||
.then =>
|
.then =>
|
||||||
@proxyvisor.setTargetInTransaction(dependent, trx)
|
@proxyvisor.setTargetInTransaction(dependent, trx)
|
||||||
|
|
||||||
|
# We look at the container contracts here, as if we
|
||||||
|
# cannot run the release, we don't want it to be added
|
||||||
|
# to the database, overwriting the current release. This
|
||||||
|
# is because if we just reject the release, but leave it
|
||||||
|
# in the db, if for any reason the current state stops
|
||||||
|
# running, we won't restart it, leaving the device
|
||||||
|
# useless - The exception to this rule is when the only
|
||||||
|
# failing services are marked as optional, then we
|
||||||
|
# filter those out and add the target state to the database
|
||||||
contractViolators = {}
|
contractViolators = {}
|
||||||
Promise.props(contractsFulfilled).then (fulfilledContracts) =>
|
Promise.resolve(validateTargetContracts(apps))
|
||||||
|
.then (fulfilledContracts) =>
|
||||||
filteredApps = _.cloneDeep(apps)
|
filteredApps = _.cloneDeep(apps)
|
||||||
_.each(
|
_.each(
|
||||||
fulfilledContracts,
|
fulfilledContracts,
|
||||||
|
@ -5,48 +5,84 @@ import * as _ from 'lodash';
|
|||||||
|
|
||||||
import { Blueprint, Contract, ContractObject } from '@balena/contrato';
|
import { Blueprint, Contract, ContractObject } from '@balena/contrato';
|
||||||
|
|
||||||
import constants = require('./constants');
|
import { ContractValidationError, InternalInconsistencyError } from './errors';
|
||||||
import { InternalInconsistencyError } from './errors';
|
|
||||||
import * as osRelease from './os-release';
|
import * as osRelease from './os-release';
|
||||||
import supervisorVersion = require('./supervisor-version');
|
import supervisorVersion = require('./supervisor-version');
|
||||||
|
import { checkTruthy } from './validation';
|
||||||
|
|
||||||
export { ContractObject };
|
export { ContractObject };
|
||||||
|
|
||||||
|
// TODO{type}: When target and current state are correctly
|
||||||
|
// defined, replace this
|
||||||
|
interface AppWithContracts {
|
||||||
|
services: {
|
||||||
|
[key: string]: {
|
||||||
|
serviceName: string;
|
||||||
|
contract?: ContractObject;
|
||||||
|
labels?: Dictionary<string>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicationContractResult {
|
||||||
|
valid: boolean;
|
||||||
|
unmetServices: string[];
|
||||||
|
fulfilledServices: string[];
|
||||||
|
unmetAndOptional: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ServiceContracts {
|
export interface ServiceContracts {
|
||||||
[serviceName: string]: { contract?: ContractObject; optional: boolean };
|
[serviceName: string]: { contract?: ContractObject; optional: boolean };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PotentialContractRequirements = 'sw.supervisor' | 'sw.l4t';
|
||||||
|
type ContractRequirementVersions = {
|
||||||
|
[key in PotentialContractRequirements]?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
let contractRequirementVersions = async () => {
|
||||||
|
const versions: ContractRequirementVersions = {
|
||||||
|
'sw.supervisor': supervisorVersion,
|
||||||
|
};
|
||||||
|
const l4tVersion = await osRelease.getL4tVersion();
|
||||||
|
if (l4tVersion != null) {
|
||||||
|
versions['sw.l4t'] = l4tVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
return versions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// When running in tests, we need this function to be
|
||||||
|
// repeatedly executed, but on-device, this should only be
|
||||||
|
// executed once per run
|
||||||
|
if (process.env.TEST !== '1') {
|
||||||
|
contractRequirementVersions = _.once(contractRequirementVersions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidRequirementType(
|
||||||
|
requirementVersions: ContractRequirementVersions,
|
||||||
|
requirement: string,
|
||||||
|
) {
|
||||||
|
return requirement in requirementVersions;
|
||||||
|
}
|
||||||
|
|
||||||
export async function containerContractsFulfilled(
|
export async function containerContractsFulfilled(
|
||||||
serviceContracts: ServiceContracts,
|
serviceContracts: ServiceContracts,
|
||||||
): Promise<{
|
): Promise<ApplicationContractResult> {
|
||||||
valid: boolean;
|
|
||||||
unmetServices: string[];
|
|
||||||
fulfilledServices: string[];
|
|
||||||
unmetAndOptional: string[];
|
|
||||||
}> {
|
|
||||||
const containers = _(serviceContracts)
|
const containers = _(serviceContracts)
|
||||||
.map('contract')
|
.map('contract')
|
||||||
.compact()
|
.compact()
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
const osContract = new Contract({
|
const versions = await contractRequirementVersions();
|
||||||
slug: 'balenaOS',
|
|
||||||
type: 'sw.os',
|
|
||||||
name: 'balenaOS',
|
|
||||||
version: await osRelease.getOSSemver(constants.hostOSVersionPath),
|
|
||||||
});
|
|
||||||
|
|
||||||
const supervisorContract = new Contract({
|
|
||||||
slug: 'balena-supervisor',
|
|
||||||
type: 'sw.supervisor',
|
|
||||||
name: 'balena-supervisor',
|
|
||||||
version: supervisorVersion,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const blueprintMembership: Dictionary<number> = {};
|
||||||
|
for (const component of _.keys(versions)) {
|
||||||
|
blueprintMembership[component] = 1;
|
||||||
|
}
|
||||||
const blueprint = new Blueprint(
|
const blueprint = new Blueprint(
|
||||||
{
|
{
|
||||||
'sw.os': 1,
|
...blueprintMembership,
|
||||||
'sw.supervisor': 1,
|
|
||||||
'sw.container': '1+',
|
'sw.container': '1+',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -59,11 +95,11 @@ export async function containerContractsFulfilled(
|
|||||||
type: 'meta.universe',
|
type: 'meta.universe',
|
||||||
});
|
});
|
||||||
|
|
||||||
universe.addChildren([
|
universe.addChildren(
|
||||||
osContract,
|
[...getContractsFromVersions(versions), ...containers].map(
|
||||||
supervisorContract,
|
c => new Contract(c),
|
||||||
...containers.map(c => new Contract(c)),
|
),
|
||||||
]);
|
);
|
||||||
|
|
||||||
const solution = blueprint.reproduce(universe);
|
const solution = blueprint.reproduce(universe);
|
||||||
|
|
||||||
@ -145,14 +181,76 @@ const contractObjectValidator = t.type({
|
|||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function validateContract(
|
function getContractsFromVersions(versions: ContractRequirementVersions) {
|
||||||
contract: unknown,
|
return _.map(versions, (version, component) => ({
|
||||||
): contract is ContractObject {
|
type: component,
|
||||||
|
slug: component,
|
||||||
|
name: component,
|
||||||
|
version,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function validateContract(contract: unknown): Promise<boolean> {
|
||||||
const result = contractObjectValidator.decode(contract);
|
const result = contractObjectValidator.decode(contract);
|
||||||
|
|
||||||
if (isLeft(result)) {
|
if (isLeft(result)) {
|
||||||
throw new Error(reporter(result).join('\n'));
|
throw new Error(reporter(result).join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const requirementVersions = await contractRequirementVersions();
|
||||||
|
|
||||||
|
for (const { type } of result.right.requires || []) {
|
||||||
|
if (!isValidRequirementType(requirementVersions, type)) {
|
||||||
|
throw new Error(`${type} is not a valid contract requirement type`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
export async function validateTargetContracts(
|
||||||
|
apps: Dictionary<AppWithContracts>,
|
||||||
|
): Promise<Dictionary<ApplicationContractResult>> {
|
||||||
|
const appsFulfilled: Dictionary<ApplicationContractResult> = {};
|
||||||
|
|
||||||
|
for (const appId of _.keys(apps)) {
|
||||||
|
const app = apps[appId];
|
||||||
|
const serviceContracts: ServiceContracts = {};
|
||||||
|
|
||||||
|
for (const svcId of _.keys(app.services)) {
|
||||||
|
const svc = app.services[svcId];
|
||||||
|
|
||||||
|
if (svc.contract) {
|
||||||
|
try {
|
||||||
|
await validateContract(svc.contract);
|
||||||
|
|
||||||
|
serviceContracts[svc.serviceName] = {
|
||||||
|
contract: svc.contract,
|
||||||
|
optional:
|
||||||
|
checkTruthy(svc.labels?.['io.balena.features.optional']) || false,
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
throw new ContractValidationError(svc.serviceName, e.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
serviceContracts[svc.serviceName] = {
|
||||||
|
contract: undefined,
|
||||||
|
optional: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.isEmpty(serviceContracts)) {
|
||||||
|
appsFulfilled[appId] = await containerContractsFulfilled(
|
||||||
|
serviceContracts,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
appsFulfilled[appId] = {
|
||||||
|
valid: true,
|
||||||
|
fulfilledServices: _.map(app.services, 'serviceName'),
|
||||||
|
unmetAndOptional: [],
|
||||||
|
unmetServices: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return appsFulfilled;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import fs = require('mz/fs');
|
import { child_process, fs } from 'mz';
|
||||||
|
|
||||||
import { InternalInconsistencyError } from './errors';
|
import { InternalInconsistencyError } from './errors';
|
||||||
import log from './supervisor-console';
|
import log from './supervisor-console';
|
||||||
@ -58,3 +58,20 @@ export function getOSVariant(path: string): Promise<string | undefined> {
|
|||||||
export function getOSSemver(path: string): Promise<string | undefined> {
|
export function getOSSemver(path: string): Promise<string | undefined> {
|
||||||
return getOSReleaseField(path, 'VERSION');
|
return getOSReleaseField(path, 'VERSION');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const L4T_REGEX = /^.*-l4t-r(\d+\.\d+).*$/;
|
||||||
|
export async function getL4tVersion(): Promise<string | undefined> {
|
||||||
|
// We call `uname -r` on the host, and look for l4t
|
||||||
|
try {
|
||||||
|
const [stdout] = await child_process.exec('uname -r');
|
||||||
|
const match = L4T_REGEX.exec(stdout.toString().trim());
|
||||||
|
if (match == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match[1];
|
||||||
|
} catch (e) {
|
||||||
|
log.error('Could not detect l4t version! Error: ', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { assert, expect } from 'chai';
|
import { assert, expect } from 'chai';
|
||||||
|
import { SinonStub, stub } from 'sinon';
|
||||||
|
|
||||||
|
import { child_process } from 'mz';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
|
||||||
import * as constants from '../src/lib/constants';
|
import * as constants from '../src/lib/constants';
|
||||||
@ -11,56 +13,63 @@ import * as osRelease from '../src/lib/os-release';
|
|||||||
import supervisorVersion = require('../src/lib/supervisor-version');
|
import supervisorVersion = require('../src/lib/supervisor-version');
|
||||||
|
|
||||||
describe('Container contracts', () => {
|
describe('Container contracts', () => {
|
||||||
describe('Contract validation', () => {
|
let execStub: SinonStub;
|
||||||
it('should correctly validate a contract with no requirements', () => {
|
before(() => {
|
||||||
assert(
|
execStub = stub(child_process, 'exec').returns(
|
||||||
validateContract({
|
Promise.resolve([
|
||||||
slug: 'user-container',
|
Buffer.from('4.9.140-l4t-r32.2+g3dcbed5'),
|
||||||
}),
|
Buffer.from(''),
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly validate a contract with extra fields', () => {
|
after(() => {
|
||||||
assert(
|
execStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Contract validation', () => {
|
||||||
|
it('should correctly validate a contract with no requirements', () =>
|
||||||
|
expect(
|
||||||
|
validateContract({
|
||||||
|
slug: 'user-container',
|
||||||
|
}),
|
||||||
|
).to.be.fulfilled);
|
||||||
|
|
||||||
|
it('should correctly validate a contract with extra fields', () =>
|
||||||
|
expect(
|
||||||
validateContract({
|
validateContract({
|
||||||
slug: 'user-container',
|
slug: 'user-container',
|
||||||
name: 'user-container',
|
name: 'user-container',
|
||||||
version: '3.0.0',
|
version: '3.0.0',
|
||||||
}),
|
}),
|
||||||
);
|
).to.be.fulfilled);
|
||||||
});
|
|
||||||
|
|
||||||
it('should not validate a contract without the minimum required fields', () => {
|
it('should not validate a contract without the minimum required fields', () => {
|
||||||
expect(() => {
|
return Promise.all([
|
||||||
validateContract({});
|
expect(validateContract({})).to.be.rejected,
|
||||||
}).to.throw();
|
expect(validateContract({ name: 'test' })).to.be.rejected,
|
||||||
expect(() => {
|
expect(validateContract({ requires: [] })).to.be.rejected,
|
||||||
validateContract({ name: 'test' });
|
]);
|
||||||
}).to.throw();
|
|
||||||
expect(() => {
|
|
||||||
validateContract({ requires: [] });
|
|
||||||
}).to.throw();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly validate a contract with requirements', () => {
|
it('should correctly validate a contract with requirements', () =>
|
||||||
assert(
|
expect(
|
||||||
validateContract({
|
validateContract({
|
||||||
slug: 'user-container',
|
slug: 'user-container',
|
||||||
requires: [
|
requires: [
|
||||||
{
|
{
|
||||||
type: 'sw.os',
|
type: 'sw.l4t',
|
||||||
version: '>3.0.0',
|
version: '32.2',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'sw.supervisor',
|
type: 'sw.supervisor',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
);
|
).to.be.fulfilled);
|
||||||
});
|
|
||||||
|
|
||||||
it('should not validate a contract with requirements without the minimum required fields', () => {
|
it('should not validate a contract with requirements without the minimum required fields', () => {
|
||||||
expect(() =>
|
return expect(
|
||||||
validateContract({
|
validateContract({
|
||||||
slug: 'user-container',
|
slug: 'user-container',
|
||||||
requires: [
|
requires: [
|
||||||
@ -69,7 +78,7 @@ describe('Container contracts', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
).to.throw();
|
).to.be.rejected;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -140,8 +149,8 @@ describe('Container contracts', () => {
|
|||||||
slug: 'user-container',
|
slug: 'user-container',
|
||||||
requires: [
|
requires: [
|
||||||
{
|
{
|
||||||
type: 'sw.os',
|
type: 'sw.supervisor',
|
||||||
version: '>2.0.0',
|
version: `>${supervisorVersionLesser}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -207,8 +216,8 @@ describe('Container contracts', () => {
|
|||||||
version: `>${supervisorVersionLesser}`,
|
version: `>${supervisorVersionLesser}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'sw.os',
|
type: 'sw.l4t',
|
||||||
version: '<3.0.0',
|
version: '32.2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -263,8 +272,8 @@ describe('Container contracts', () => {
|
|||||||
slug: 'user-container',
|
slug: 'user-container',
|
||||||
requires: [
|
requires: [
|
||||||
{
|
{
|
||||||
type: 'sw.os',
|
type: 'sw.supervisor',
|
||||||
version: '>=3.0.0',
|
version: `>=${supervisorVersionGreater}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -286,12 +295,8 @@ describe('Container contracts', () => {
|
|||||||
slug: 'user-container2',
|
slug: 'user-container2',
|
||||||
requires: [
|
requires: [
|
||||||
{
|
{
|
||||||
type: 'sw.supervisor',
|
type: 'sw.l4t',
|
||||||
version: `>=${supervisorVersionLesser}`,
|
version: '28.2',
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'sw.os',
|
|
||||||
version: '>3.0.0',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -356,7 +361,7 @@ describe('Container contracts', () => {
|
|||||||
slug: 'service1',
|
slug: 'service1',
|
||||||
requires: [
|
requires: [
|
||||||
{
|
{
|
||||||
type: 'sw.os',
|
type: 'sw.supervisor',
|
||||||
version: `<${supervisorVersionGreater}`,
|
version: `<${supervisorVersionGreater}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -381,7 +386,7 @@ describe('Container contracts', () => {
|
|||||||
slug: 'service1',
|
slug: 'service1',
|
||||||
requires: [
|
requires: [
|
||||||
{
|
{
|
||||||
type: 'sw.os',
|
type: 'sw.supervisor',
|
||||||
version: `>${supervisorVersionGreater}`,
|
version: `>${supervisorVersionGreater}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -403,3 +408,38 @@ describe('Container contracts', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('L4T version detection', () => {
|
||||||
|
it('should correctly parse L4T version strings', async () => {
|
||||||
|
let execStub = stub(child_process, 'exec').returns(
|
||||||
|
Promise.resolve([
|
||||||
|
Buffer.from('4.9.140-l4t-r32.2+g3dcbed5'),
|
||||||
|
Buffer.from(''),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await osRelease.getL4tVersion()).to.equal('32.2');
|
||||||
|
expect(execStub.callCount).to.equal(1);
|
||||||
|
|
||||||
|
execStub.restore();
|
||||||
|
|
||||||
|
execStub = stub(child_process, 'exec').returns(
|
||||||
|
Promise.resolve([
|
||||||
|
Buffer.from('4.4.38-l4t-r28.2+g174510d'),
|
||||||
|
Buffer.from(''),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
expect(await osRelease.getL4tVersion()).to.equal('28.2');
|
||||||
|
expect(execStub.callCount).to.equal(1);
|
||||||
|
execStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when there is no l4t string in uname', async () => {
|
||||||
|
const execStub = stub(child_process, 'exec').returns(
|
||||||
|
Promise.resolve([Buffer.from('4.18.14-yocto-standard'), Buffer.from('')]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(await osRelease.getL4tVersion()).to.be.undefined;
|
||||||
|
execStub.restore();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user