mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-10-31 11:13:22 +00:00 
			
		
		
		
	support merge yaml flags
Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
		| @@ -144,7 +144,9 @@ options. Default values may be specified using the `org.mobyproject.config` imag | |||||||
| For more details see the [OCI specification](https://github.com/opencontainers/runtime-spec/blob/master/spec.md). | For more details see the [OCI specification](https://github.com/opencontainers/runtime-spec/blob/master/spec.md). | ||||||
|  |  | ||||||
| If the `org.mobylinux.config` label is set in the image, that specifies default values for these fields if they | If the `org.mobylinux.config` label is set in the image, that specifies default values for these fields if they | ||||||
| are not set in the yaml file. You can override the label by setting the value, or setting it to be empty to remove | are not set in the yaml file. While most fields are _replaced_ if they are specified in the yaml file, | ||||||
|  | some support _add_ via the format `<field>.add`; see below. | ||||||
|  | You can override the label entirely by setting the value, or setting it to be empty to remove | ||||||
| the specification for that value in the label. | the specification for that value in the label. | ||||||
|  |  | ||||||
| If you need an OCI option that is not specified here please open an issue or pull request as the list is not yet | If you need an OCI option that is not specified here please open an issue or pull request as the list is not yet | ||||||
| @@ -159,6 +161,7 @@ bind mounted into a container. | |||||||
|   extracted from this so they need not be filled in. |   extracted from this so they need not be filled in. | ||||||
| - `capabilities` the Linux capabilities required, for example `CAP_SYS_ADMIN`. If there is a single | - `capabilities` the Linux capabilities required, for example `CAP_SYS_ADMIN`. If there is a single | ||||||
|   capability `all` then all capabilities are added. |   capability `all` then all capabilities are added. | ||||||
|  | - `capabilities.add` the Linux capabilities required, but these are added to the defaults, rather than overriding them. | ||||||
| - `ambient` the Linux ambient capabilities (capabilities passed to non root users) that are required. | - `ambient` the Linux ambient capabilities (capabilities passed to non root users) that are required. | ||||||
| - `mounts` is the full form for specifying a mount, which requires `type`, `source`, `destination` | - `mounts` is the full form for specifying a mount, which requires `type`, `source`, `destination` | ||||||
|   and a list of `options`. If any fields are omitted, sensible defaults are used if possible, for example |   and a list of `options`. If any fields are omitted, sensible defaults are used if possible, for example | ||||||
| @@ -166,6 +169,7 @@ bind mounted into a container. | |||||||
|   can be replaced by specifying a mount with new options here at the same mount point. |   can be replaced by specifying a mount with new options here at the same mount point. | ||||||
| - `binds` is a simpler interface to specify bind mounts, accepting a string like `/src:/dest:opt1,opt2` | - `binds` is a simpler interface to specify bind mounts, accepting a string like `/src:/dest:opt1,opt2` | ||||||
|   similar to the `-v` option for bind mounts in Docker. |   similar to the `-v` option for bind mounts in Docker. | ||||||
|  | - `binds.add` is a simpler interface to specify bind mounts, but these are added to the defaults, rather than overriding them. | ||||||
| - `tmpfs` is a simpler interface to mount a `tmpfs`, like `--tmpfs` in Docker, taking `/dest:opt1,opt2`. | - `tmpfs` is a simpler interface to mount a `tmpfs`, like `--tmpfs` in Docker, taking `/dest:opt1,opt2`. | ||||||
| - `command` will override the command and entrypoint in the image with a new list of commands. | - `command` will override the command and entrypoint in the image with a new list of commands. | ||||||
| - `env` will override the environment in the image with a new environment list. Specify variables as `VAR=value`. | - `env` will override the environment in the image with a new environment list. Specify variables as `VAR=value`. | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								examples/addbinds.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/addbinds.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | kernel: | ||||||
|  |   image: linuxkit/kernel:5.4.30 | ||||||
|  |   cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0" | ||||||
|  | init: | ||||||
|  |   - linuxkit/init:7195dc244cd92af01fd0895fd204249a6114c5e2 | ||||||
|  |   - linuxkit/runc:f79954950022fea76b8b6f10de58cb48e4fb3878 | ||||||
|  |   - linuxkit/containerd:8ee7a0d636fff9df7e13076f5492d06274e5f644 | ||||||
|  |   - linuxkit/ca-certificates:abfc6701b9ca17e34ac9439ce5946a247e720ff5 | ||||||
|  | onboot: | ||||||
|  |   - name: sysctl | ||||||
|  |     image: linuxkit/sysctl:541f60fe3676611328e89e8bac251fc636b1a6aa | ||||||
|  |   - name: dhcpcd | ||||||
|  |     image: linuxkit/dhcpcd:2f8a9b670aa6e96a09db56ec45c9f07ef2a811ee | ||||||
|  |     command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] | ||||||
|  | services: | ||||||
|  |   - name: getty | ||||||
|  |     image: linuxkit/getty:48f66df198981e692084bf70ab72b9fe2be0f880 | ||||||
|  |     binds.add: | ||||||
|  |       # this will keep all of the existing ones as well | ||||||
|  |       - /var/tmp:/var/tmp | ||||||
|  |   - name: rngd | ||||||
|  |     image: linuxkit/rngd:7fab61cca793113280397dcee8159f35dc37adcb | ||||||
|  | files: | ||||||
|  |   - path: etc/getty.shadow | ||||||
|  |     # sample sets password for root to "abcdefgh" (without quotes) | ||||||
|  |     contents: 'root:$6$6tPd2uhHrecCEKug$8mKfcgfwguP7f.BLdZsT1Wz7WIIJOBY1oUFHzIv9/O71M2J0EPdtFqFGTxB1UK5ejqQxRFQ.ZSG9YXR0SNsc11:17322:0:::::' | ||||||
|  | trust: | ||||||
|  |   org: | ||||||
|  |     - linuxkit | ||||||
| @@ -71,9 +71,11 @@ type Image struct { | |||||||
| // Everything except Runtime and ref is used to build the OCI spec | // Everything except Runtime and ref is used to build the OCI spec | ||||||
| type ImageConfig struct { | type ImageConfig struct { | ||||||
| 	Capabilities      *[]string               `yaml:"capabilities,omitempty" json:"capabilities,omitempty"` | 	Capabilities      *[]string               `yaml:"capabilities,omitempty" json:"capabilities,omitempty"` | ||||||
|  | 	CapabilitiesAdd   *[]string               `yaml:"capabilities.add,omitempty" json:"capabilities.add,omitempty"` | ||||||
| 	Ambient           *[]string               `yaml:"ambient,omitempty" json:"ambient,omitempty"` | 	Ambient           *[]string               `yaml:"ambient,omitempty" json:"ambient,omitempty"` | ||||||
| 	Mounts            *[]specs.Mount          `yaml:"mounts,omitempty" json:"mounts,omitempty"` | 	Mounts            *[]specs.Mount          `yaml:"mounts,omitempty" json:"mounts,omitempty"` | ||||||
| 	Binds             *[]string               `yaml:"binds,omitempty" json:"binds,omitempty"` | 	Binds             *[]string               `yaml:"binds,omitempty" json:"binds,omitempty"` | ||||||
|  | 	BindsAdd          *[]string               `yaml:"binds.add,omitempty" json:"binds.add,omitempty"` | ||||||
| 	Tmpfs             *[]string               `yaml:"tmpfs,omitempty" json:"tmpfs,omitempty"` | 	Tmpfs             *[]string               `yaml:"tmpfs,omitempty" json:"tmpfs,omitempty"` | ||||||
| 	Command           *[]string               `yaml:"command,omitempty" json:"command,omitempty"` | 	Command           *[]string               `yaml:"command,omitempty" json:"command,omitempty"` | ||||||
| 	Env               *[]string               `yaml:"env,omitempty" json:"env,omitempty"` | 	Env               *[]string               `yaml:"env,omitempty" json:"env,omitempty"` | ||||||
| @@ -505,6 +507,34 @@ func assignStrings3(v1 []string, v2, v3 *[]string) []string { | |||||||
| 	return v1 | 	return v1 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // mergeStrings does ordered unique merge between JSON string array pointers | ||||||
|  | func mergeStrings(v1, v2 *[]string) *[]string { | ||||||
|  | 	switch { | ||||||
|  | 	case v2 == nil && v1 == nil: | ||||||
|  | 		return &[]string{} | ||||||
|  | 	case v2 == nil: | ||||||
|  | 		return v1 | ||||||
|  | 	case v1 == nil: | ||||||
|  | 		return v2 | ||||||
|  | 	} | ||||||
|  | 	// merge the two uniquely | ||||||
|  | 	ret := []string{} | ||||||
|  | 	m := make(map[string]bool) | ||||||
|  | 	for _, s := range *v1 { | ||||||
|  | 		if m[s] { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		ret = append(ret, s) | ||||||
|  | 	} | ||||||
|  | 	for _, s := range *v2 { | ||||||
|  | 		if m[s] { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		ret = append(ret, s) | ||||||
|  | 	} | ||||||
|  | 	return &ret | ||||||
|  | } | ||||||
|  |  | ||||||
| // assignMaps does ordered overrides from JSON string map pointers | // assignMaps does ordered overrides from JSON string map pointers | ||||||
| func assignMaps(v1, v2 *map[string]string) map[string]string { | func assignMaps(v1, v2 *map[string]string) map[string]string { | ||||||
| 	if v2 != nil { | 	if v2 != nil { | ||||||
| @@ -770,7 +800,7 @@ func ConfigInspectToOCI(yaml *Image, inspect types.ImageInspect, idMap map[strin | |||||||
| 		} | 		} | ||||||
| 		mounts[dest] = specs.Mount{Destination: dest, Type: "tmpfs", Source: "tmpfs", Options: opts} | 		mounts[dest] = specs.Mount{Destination: dest, Type: "tmpfs", Source: "tmpfs", Options: opts} | ||||||
| 	} | 	} | ||||||
| 	for _, b := range assignStrings(label.Binds, yaml.Binds) { | 	for _, b := range assignStrings(mergeStrings(label.Binds, yaml.BindsAdd), yaml.Binds) { | ||||||
| 		parts := strings.Split(b, ":") | 		parts := strings.Split(b, ":") | ||||||
| 		if len(parts) < 2 { | 		if len(parts) < 2 { | ||||||
| 			return oci, runtime, fmt.Errorf("Cannot parse bind, missing ':': %s", b) | 			return oci, runtime, fmt.Errorf("Cannot parse bind, missing ':': %s", b) | ||||||
| @@ -880,7 +910,7 @@ func ConfigInspectToOCI(yaml *Image, inspect types.ImageInspect, idMap map[strin | |||||||
| 		capCheck[capability] = true | 		capCheck[capability] = true | ||||||
| 	} | 	} | ||||||
| 	boundingSet := map[string]bool{} | 	boundingSet := map[string]bool{} | ||||||
| 	caps := assignStrings(label.Capabilities, yaml.Capabilities) | 	caps := assignStrings(mergeStrings(label.Capabilities, yaml.CapabilitiesAdd), yaml.Capabilities) | ||||||
| 	if len(caps) == 1 { | 	if len(caps) == 1 { | ||||||
| 		switch cap := strings.ToLower(caps[0]); cap { | 		switch cap := strings.ToLower(caps[0]); cap { | ||||||
| 		case "none": | 		case "none": | ||||||
|   | |||||||
| @@ -260,9 +260,11 @@ var schema = string(` | |||||||
|         "name": {"type": "string"}, |         "name": {"type": "string"}, | ||||||
|         "image": {"type": "string"}, |         "image": {"type": "string"}, | ||||||
|         "capabilities": { "$ref": "#/definitions/strings" }, |         "capabilities": { "$ref": "#/definitions/strings" }, | ||||||
|  |         "capabilities.add": { "$ref": "#/definitions/strings" }, | ||||||
|         "ambient": { "$ref": "#/definitions/strings" }, |         "ambient": { "$ref": "#/definitions/strings" }, | ||||||
|         "mounts": { "$ref": "#/definitions/mounts" }, |         "mounts": { "$ref": "#/definitions/mounts" }, | ||||||
|         "binds": { "$ref": "#/definitions/strings" }, |         "binds": { "$ref": "#/definitions/strings" }, | ||||||
|  |         "binds.add": { "$ref": "#/definitions/strings" }, | ||||||
|         "tmpfs": { "$ref": "#/definitions/strings" }, |         "tmpfs": { "$ref": "#/definitions/strings" }, | ||||||
|         "command": { "$ref": "#/definitions/strings" }, |         "command": { "$ref": "#/definitions/strings" }, | ||||||
|         "env": { "$ref": "#/definitions/strings" }, |         "env": { "$ref": "#/definitions/strings" }, | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								test/cases/000_build/020_binds/check.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								test/cases/000_build/020_binds/check.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | #!/bin/sh | ||||||
|  |  | ||||||
|  | set -x | ||||||
|  |  | ||||||
|  | function failed { | ||||||
|  | 	printf "bindmerge test suite FAILED\n" >&1 | ||||||
|  | 	exit 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # the very fact that this is running means that the bind worked, so just need to check that the defaults also | ||||||
|  | # are there | ||||||
|  |  | ||||||
|  | [ -d /dev/mapper ] || failed | ||||||
|  | [ -d /hostroot ] || failed | ||||||
|  | printf "bindmerge test suite PASSED\n" >&1 | ||||||
							
								
								
									
										27
									
								
								test/cases/000_build/020_binds/test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								test/cases/000_build/020_binds/test.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | # SUMMARY: Check that the userdata is found and read when on a cidata partition | ||||||
|  | # LABELS: | ||||||
|  | # REPEAT: | ||||||
|  |  | ||||||
|  | set -ex | ||||||
|  |  | ||||||
|  | # Source libraries. Uncomment if needed/defined | ||||||
|  | #. "${RT_LIB}" | ||||||
|  | . "${RT_PROJECT_ROOT}/_lib/lib.sh" | ||||||
|  |  | ||||||
|  | NAME=bindtest | ||||||
|  | DISK=disk.img | ||||||
|  |  | ||||||
|  | clean_up() { | ||||||
|  | 	rm -rf ${NAME}-* ${DISK} | ||||||
|  | } | ||||||
|  | trap clean_up EXIT | ||||||
|  |  | ||||||
|  | # Test code goes here | ||||||
|  |  | ||||||
|  | linuxkit build -format kernel+initrd -name ${NAME} test.yml | ||||||
|  | RESULT="$(linuxkit run -disk file=${DISK},size=32M ${NAME})" | ||||||
|  | echo "${RESULT}" | ||||||
|  | echo "${RESULT}" | grep -q "suite PASSED" | ||||||
|  |  | ||||||
|  | exit 0 | ||||||
							
								
								
									
										28
									
								
								test/cases/000_build/020_binds/test.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								test/cases/000_build/020_binds/test.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | kernel: | ||||||
|  |   image: linuxkit/kernel:5.4.30 | ||||||
|  |   cmdline: "console=ttyS0 console=ttyAMA0" | ||||||
|  | init: | ||||||
|  |   - linuxkit/init:7195dc244cd92af01fd0895fd204249a6114c5e2 | ||||||
|  |   - linuxkit/runc:f79954950022fea76b8b6f10de58cb48e4fb3878 | ||||||
|  | onboot: | ||||||
|  |   - name: mount | ||||||
|  |     image: linuxkit/mount:19fa297189166206ac97261679c3e31fb140d48f | ||||||
|  |     binds.add: | ||||||
|  |       - /check.sh:/check.sh | ||||||
|  |       - /var/tmp:/var/tmp | ||||||
|  |     # default binds from linuxkit/mount | ||||||
|  |     # - /dev:/dev | ||||||
|  |     # - /var:/var:rshared,rbind | ||||||
|  |     # - /:/hostroot | ||||||
|  |     command: ["sh", "-c", "/check.sh"] | ||||||
|  |   - name: poweroff | ||||||
|  |     image: linuxkit/poweroff:06dd4e46c62fbe79123a028835c921f80e4855d3 | ||||||
|  |     command: ["/bin/sh", "/poweroff.sh", "10"] | ||||||
|  | files: | ||||||
|  |   - path: check.sh | ||||||
|  |     source: ./check.sh | ||||||
|  |     mode: "0700" | ||||||
|  | trust: | ||||||
|  |   org: | ||||||
|  |     - linuxkit | ||||||
|  |     - library | ||||||
		Reference in New Issue
	
	Block a user