diff --git a/config.md b/config.md index 049614ad..ffba65ac 100644 --- a/config.md +++ b/config.md @@ -110,6 +110,24 @@ Note: Any OPTIONAL field MAY also be set to null, which is equivalent to being a The name of the operating system which the image is built to run on. Configurations SHOULD use, and implementations SHOULD understand, values listed in the Go Language document for [`GOOS`][go-environment]. +- **os.version** *string*, OPTIONAL + + This OPTIONAL property specifies the version of the operating system targeted by the referenced blob. + Implementations MAY refuse to use manifests where `os.version` is not known to work with the host OS version. + Valid values are implementation-defined. e.g. `10.0.14393.1066` on `windows`. + +- **os.features** *array of strings*, OPTIONAL + + This OPTIONAL property specifies an array of strings, each specifying a mandatory OS feature. + When `os` is `windows`, image indexes SHOULD use, and implementations SHOULD understand the following values: + + - `win32k`: image requires `win32k.sys` on the host (Note: `win32k.sys` is missing on Nano Server) + +- **variant** *string*, OPTIONAL + + The variant of the specified CPU architecture. + Configurations SHOULD use, and implementations SHOULD understand, `variant` values listed in the [Platform Variants](image-index.md#platform-variants) table. + - **config** *object*, OPTIONAL The execution parameters which SHOULD be used as a base when running a container using the image. diff --git a/conversion.md b/conversion.md index 5420dbe4..d406baed 100644 --- a/conversion.md +++ b/conversion.md @@ -46,17 +46,23 @@ These fields all affect the `annotations` of the runtime configuration, and are | ------------------- | --------------- | ----- | | `os` | `annotations` | 1,2 | | `architecture` | `annotations` | 1,3 | -| `author` | `annotations` | 1,4 | -| `created` | `annotations` | 1,5 | +| `variant` | `annotations` | 1,4 | +| `os.version` | `annotations` | 1,5 | +| `os.features` | `annotations` | 1,6 | +| `author` | `annotations` | 1,7 | +| `created` | `annotations` | 1,8 | | `Config.Labels` | `annotations` | | -| `Config.StopSignal` | `annotations` | 1,6 | +| `Config.StopSignal` | `annotations` | 1,9 | 1. If a user has explicitly specified this annotation with `Config.Labels`, then the value specified in this field takes lower [precedence](#annotations) and the converter MUST instead use the value from `Config.Labels`. 2. The value of this field MUST be set as the value of `org.opencontainers.image.os` in `annotations`. 3. The value of this field MUST be set as the value of `org.opencontainers.image.architecture` in `annotations`. -4. The value of this field MUST be set as the value of `org.opencontainers.image.author` in `annotations`. -5. The value of this field MUST be set as the value of `org.opencontainers.image.created` in `annotations`. -6. The value of this field MUST be set as the value of `org.opencontainers.image.stopSignal` in `annotations`. +4. The value of this field MUST be set as the value of `org.opencontainers.image.variant` in `annotations`. +5. The value of this field MUST be set as the value of `org.opencontainers.image.os.version` in `annotations`. +6. The value of this field MUST be set as the value of `org.opencontainers.image.os.features` in `annotations`. +7. The value of this field MUST be set as the value of `org.opencontainers.image.author` in `annotations`. +8. The value of this field MUST be set as the value of `org.opencontainers.image.created` in `annotations`. +9. The value of this field MUST be set as the value of `org.opencontainers.image.stopSignal` in `annotations`. ## Parsed Fields diff --git a/image-index.md b/image-index.md index 27c30531..6acb0120 100644 --- a/image-index.md +++ b/image-index.md @@ -76,15 +76,7 @@ For the media type(s) that this document is compatible with, see the [matrix][ma - **`variant`** *string* This OPTIONAL property specifies the variant of the CPU. - Image indexes SHOULD use, and implementations SHOULD understand, values listed in the following table. - When the variant of the CPU is not listed in the table, values are implementation-defined and SHOULD be submitted to this specification for standardization. - - | ISA/ABI | `architecture` | `variant` | - |-----------------|----------------|-------------| - | ARM 32-bit, v6 | `arm` | `v6` | - | ARM 32-bit, v7 | `arm` | `v7` | - | ARM 32-bit, v8 | `arm` | `v8` | - | ARM 64-bit, v8 | `arm64` | `v8` | + Image indexes SHOULD use, and implementations SHOULD understand, `variant` values listed in the [Platform Variants](#platform-variants) table. - **`features`** *array of strings* @@ -97,6 +89,17 @@ For the media type(s) that this document is compatible with, see the [matrix][ma See [Pre-Defined Annotation Keys](annotations.md#pre-defined-annotation-keys). +## Platform Variants + +When the variant of the CPU is not listed in the table, values are implementation-defined and SHOULD be submitted to this specification for standardization. + +| ISA/ABI | `architecture` | `variant` | +|-----------------|----------------|-------------| +| ARM 32-bit, v6 | `arm` | `v6` | +| ARM 32-bit, v7 | `arm` | `v7` | +| ARM 32-bit, v8 | `arm` | `v8` | +| ARM 64-bit, v8 | `arm64` | `v8` | + ## Example Image Index *Example showing a simple image index pointing to image manifests for two platforms:* diff --git a/schema/config-schema.json b/schema/config-schema.json index 15bccd04..9b3be97c 100644 --- a/schema/config-schema.json +++ b/schema/config-schema.json @@ -14,9 +14,21 @@ "architecture": { "type": "string" }, + "variant": { + "type": "string" + }, "os": { "type": "string" }, + "os.version": { + "type": "string" + }, + "os.features": { + "type": "array", + "items": { + "type": "string" + } + }, "config": { "type": "object", "properties": { diff --git a/schema/config_test.go b/schema/config_test.go index 28b87287..9daa41e5 100644 --- a/schema/config_test.go +++ b/schema/config_test.go @@ -39,6 +39,23 @@ func TestConfig(t *testing.T) { "type": "layers" } } +`, + fail: true, + }, + // expected failure: field "variant" has numeric value, must be string + { + config: ` +{ + "architecture": "arm64", + "variant": 123, + "os": "linux", + "rootfs": { + "diff_ids": [ + "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" + ], + "type": "layers" + } +} `, fail: true, }, @@ -140,7 +157,8 @@ func TestConfig(t *testing.T) { { "created": "2015-10-31T22:22:56.015925234Z", "author": "Alyssa P. Hacker ", - "architecture": "amd64", + "architecture": "arm64", + "variant": "v8", "os": "linux", "config": { "User": "1:1", diff --git a/schema/fs.go b/schema/fs.go index ca5bbe95..9c6b2941 100644 --- a/schema/fs.go +++ b/schema/fs.go @@ -226,19 +226,19 @@ var _escData = map[string]*_escFile{ "/config-schema.json": { name: "config-schema.json", local: "config-schema.json", - size: 2771, - modtime: 1619819526, + size: 2969, + modtime: 1625865937, compressed: ` -H4sIAAAAAAAC/+RWQY/TPBC951dE2T22m+/wnXot3JCKVAGHFarcZNLOEnvMeIKIUP87itNCkjpp6apc -OEUaz7z35nns+EcUx0kOLmO0gmSSRZysLJglGVFogOMlmQJ38dpChgVmymfNmrJHl+1Bq6ZkL2IXafri -yMzb6BPxLs1ZFTL/7/+0jT20dZifStwiTcmCyU5szpe12SlqtYM08/xtpdQWmlravkAmbcwyWWBBcMki -btqJ4yRjUAL5r0Cn1AmjaeF8vCDWSpqVXAnMBTUkfu3QpiSqkj3xBFQ/m7M9CmRSMVxbQ+7azKMXgeyO -Iz4ecMXHPzjgXmSEscPqc95+t+Qgf08sblj/yFB4A6FwT80IPKQ5FGiwGRWXamXXHnnVagzjm29jshSz -qpNZdwkF9FDGRCNxfBghFa4toZEhNxlYNT099wj6dJMSJ2RekNqXO5A8qcJUZdlH6uJ8Dlqw1Pk/2/tH -KisN7sb+b536e3f1ifgLmt0bvOmcv1NbKO9tyTqw8fe0ZC1k17gzqrzakqj7PV2/TCSFe831m2NRbDB3 -f/+uO+ZPdd+jBVPpsx1PSlUDuyTseDRgTRi+Vsj+P/wc8GCoLuoinjzfoxPiOmR636yAUWPbM75BwbfD -Zbem3hGB8T5/U1ze1FlA42ZbvwKDtIazP98fAIC2Um/8RIyDbIlKUGZkPvunLDoynM9N/1n1+9nUP5dR -MzuH6GcAAAD//0pj2wvTCgAA +H4sIAAAAAAAC/+RWsW7bQAzd9RWCkjGJOnTymnYrkAJG2yEojLNE2Ux1xyuPMioU/vdCJzvx2SfZteEu +XSnyvcdHSuLvJE2zElzBaAXJZJM0e7JgHsmIQgOcPpKpcJFOLRRYYaF81l1XduuKJWjVlSxF7CTPXxyZ ++z76QLzIS1aV3L97n/exm74Oy22Jm+Q5WTDFls35sj47R60WkBeev6+U1kJXS/MXKKSPWSYLLAgum6Rd +O2maFQxKoHwN7JQ6YTQ9nI9XxFpJ96RUAveCGjL/bN2nZKqRJfEIVJjNxRIFCmkYTq1ZKUZl5NR0cqdn +PqyAXT/WUysqUJ34KIliVu2bdyigd/MGwNN0HZBsJhrB35mrj0dm6+NfHHAQGWR+ZfU5H39ZclB+Jha3 +X3/LUPk1gMo9dIt8k5dQocFu4V2ulZ165KdeYxzfrIZkhdYN2DfayNbGQ1Lh1hIGG9RP08BT19NzQBDS +jUockXlEaih3T/KoCtPUdYi0i/M9asGjLv/b3r9S3WhwZ/Z/7tZfu6tvxD/QLD7gWe/5JzWH+tqWTCOD +v6YlUyE7xYVR9cmWRD+/TCSVu+TzW2JVzbB0//5bt8kf6z6gBdPog4lntWqBXRZ3PNljzRh+Nsj+mniO +eLCvLtlF3Hq+RCfE7WX/1L3xDA8oegEdd2vsGoqs9+FldHyodxGNs3l7AQZpDQd/vr8AAG2lnfmNGAaZ +E9WgzMB+hm9ZsmE43JvwOHy75sL3Mul2Z538CQAA//9C38scmQsAAA== `, }, @@ -246,7 +246,7 @@ MzuH6GcAAAD//0pj2wvTCgAA name: "content-descriptor.json", local: "content-descriptor.json", size: 1079, - modtime: 1619819526, + modtime: 1625865919, compressed: ` H4sIAAAAAAAC/5yTsW7cMAyGdz8F4QTIkos6BB2MIEu7d2i3ooNOok5Mz5JK8RBci7x7QcvX2G2RILfZ xP+Rn2zqVwfQe6yOqQjl1A/QfyqYPuQklhIy6BMmgY9zKDN8LugokLMTca0tLquLOFrFo0gZjHmoOW1a @@ -262,7 +262,7 @@ dIbaEm+G3WzZM/44EKMqff37riz3dL0uHcC37qn7HQAA//9DKIMKNwQAAA== name: "defs-descriptor.json", local: "defs-descriptor.json", size: 844, - modtime: 1619819526, + modtime: 1625865919, compressed: ` H4sIAAAAAAAC/5SST2/TTBDG7/kU826jt0DiOHBAqlWKKnrnUE6t0mi6O7aneP9od6IqVPnuaG03SYtA cLC1+2jmefwbz9MEQBlKOnIQ9k5VoK6oZsf5liBgFNabDiOIh6+B3BfvBNlRhKuxzUe4DqS5Zo29x3ww @@ -279,7 +279,7 @@ TAMAAA== name: "defs.json", local: "defs.json", size: 1670, - modtime: 1619819526, + modtime: 1625865903, compressed: ` H4sIAAAAAAAC/7STza6bMBCF9zzFyO2S9oJtbGDb7hMpy6oLSiaJq2AjY6RWEe9e8RNChFuJKneRgGc8 3zmeMbcAgByxKa2qnTKa5EC+4klp1a8aaBs8grtY054vpnXgLgi7GvUXo12hNFo41FiqkyqLoTwceTOA @@ -295,7 +295,7 @@ fIvD7in0ryMEy+fK1G6UfmdTE+tvpoL+1wV/AgAA//96IpqyhgYAAA== name: "image-index-schema.json", local: "image-index-schema.json", size: 2993, - modtime: 1619819526, + modtime: 1625865919, compressed: ` H4sIAAAAAAAC/6yWz0/jOhDH7/0rRgGJC5CnJ/QOFeLy9sJpD4v2suJg7EkybGNnx1Ogu+r/vrJN2qRJ C4Te2rHnO5/vxL/+zAAyg14zNULOZnPIvjZo/3dWFFlkuK1ViXBrDb7AtwY1FaRVnHoeck+9rrBWIa8S @@ -316,7 +316,7 @@ VmZjL8HOE24GcD9bz/4GAAD//yCnv52xCwAA name: "image-layout-schema.json", local: "image-layout-schema.json", size: 439, - modtime: 1619819526, + modtime: 1625865903, compressed: ` H4sIAAAAAAAC/2yPQUvEMBCF7/0VQ/Sg4DYVPOW6pwVhD4IX8VDTaTvLNonJVFik/12SaRXRU5g38+W9 91kBqA6TjRSYvFMG1DGg23vHLTmMcJjaAeGxvfiZ4cmOOLXqLlPXSQYDamQORutT8m4nau3joLvY9rxr @@ -330,7 +330,7 @@ HrRoV8JRtyHJaO0DOruZpYLJtaZsrM/FWEi+BMysfzuhXbUQfcDIhEkZyG2yQyYl8TPGJLVk97fth1yA name: "image-manifest-schema.json", local: "image-manifest-schema.json", size: 921, - modtime: 1619819526, + modtime: 1625865903, compressed: ` H4sIAAAAAAAC/5ySMW8iMRCF+/0VI0MJ+O501bZXUZxSJEoTpXB2x7uDWNsZmygo4r9HtnHAkCKifTvv zTdv/dEAiB59x+QCWSNaEHcOzT9rgiKDDOtJDQj/lSGNPsC9w440dSpNL6J97rsRJxWtYwiulXLjrVlm diff --git a/schema/validator.go b/schema/validator.go index 545ade22..8cd9ecfc 100644 --- a/schema/validator.go +++ b/schema/validator.go @@ -23,7 +23,7 @@ import ( "regexp" digest "github.com/opencontainers/go-digest" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/xeipuuv/gojsonschema" ) @@ -168,6 +168,7 @@ func validateIndex(r io.Reader) error { } if manifest.Platform != nil { checkPlatform(manifest.Platform.OS, manifest.Platform.Architecture) + checkArchitecture(manifest.Platform.Architecture, manifest.Platform.Variant) } } @@ -189,6 +190,7 @@ func validateConfig(r io.Reader) error { } checkPlatform(header.OS, header.Architecture) + checkArchitecture(header.Architecture, header.Variant) envRegexp := regexp.MustCompile(`^[^=]+=.*$`) for _, e := range header.Config.Env { @@ -200,6 +202,31 @@ func validateConfig(r io.Reader) error { return nil } +func checkArchitecture(Architecture string, Variant string) { + validCombins := map[string][]string{ + "arm": {"", "v6", "v7", "v8"}, + "arm64": {"", "v8"}, + "386": {""}, + "amd64": {""}, + "ppc64": {""}, + "ppc64le": {""}, + "mips64": {""}, + "mips64le": {""}, + "s390x": {""}, + } + for arch, variants := range validCombins { + if arch == Architecture { + for _, variant := range variants { + if variant == Variant { + return + } + } + fmt.Printf("warning: combination of architecture %q and variant %q is not valid.\n", Architecture, Variant) + } + } + fmt.Printf("warning: architecture %q is not supported yet.\n", Architecture) +} + func checkPlatform(OS string, Architecture string) { validCombins := map[string][]string{ "android": {"arm"}, @@ -219,7 +246,7 @@ func checkPlatform(OS string, Architecture string) { return } } - fmt.Printf("warning: combination of %q and %q is invalid.\n", OS, Architecture) + fmt.Printf("warning: combination of os %q and architecture %q is invalid.\n", OS, Architecture) } } fmt.Printf("warning: operating system %q of the bundle is not supported yet.\n", OS) diff --git a/specs-go/v1/config.go b/specs-go/v1/config.go index fe799bd6..ffff4b6d 100644 --- a/specs-go/v1/config.go +++ b/specs-go/v1/config.go @@ -89,9 +89,20 @@ type Image struct { // Architecture is the CPU architecture which the binaries in this image are built to run on. Architecture string `json:"architecture"` + // Variant is the variant of the specified CPU architecture which image binaries are intended to run on. + Variant string `json:"variant,omitempty"` + // OS is the name of the operating system which the image is built to run on. OS string `json:"os"` + // OSVersion is an optional field specifying the operating system + // version, for example on Windows `10.0.14393.1066`. + OSVersion string `json:"os.version,omitempty"` + + // OSFeatures is an optional field specifying an array of strings, + // each listing a required OS feature (for example on Windows `win32k`). + OSFeatures []string `json:"os.features,omitempty"` + // Config defines the execution parameters which should be used as a base when running a container using the image. Config ImageConfig `json:"config,omitempty"`