diff --git a/blueprints/README.md b/blueprints/README.md index 0745ac620..3615284d3 100644 --- a/blueprints/README.md +++ b/blueprints/README.md @@ -33,7 +33,7 @@ $ linuxkit build -name docker-for-mac base.yml docker-ce.yml To run the VM with a 4G disk: ``` -linuxkit run hyperkit -networking=vpnkit -vsock-ports=2376 -disk size=4096M -data ./metadata.json docker-for-mac +linuxkit run hyperkit -networking=vpnkit -vsock-ports=2376 -disk size=4096M -data-file ./metadata.json docker-for-mac ``` In another terminal you should now be able to access docker via the socket `guest.00000947` in the state directory (`docker-for-mac-state/` by default): diff --git a/docs/metadata.md b/docs/metadata.md index d3efcea41..738d48a5b 100644 --- a/docs/metadata.md +++ b/docs/metadata.md @@ -55,19 +55,22 @@ The JSON file consists of a map from `name` to an entry object. Each entry objec - `entries`: if present then the entry is a directory. The value is a map from `name` to entry objects. - `perm`: the permissions to create the file with. -The `content` and `entries` fields are mutually exclusive, it is an error to include both, -one or the other _must_ be present. +The `content` and `entries` fields are mutually exclusive, it is an error to include both, +one or the other _must_ be present. The file or directory's name in each case is the same as the key which referred to that entry. - + This hierarchy can then be used by individual containers, who can bind mount the config sub-directory into their namespace where it is needed. # Metadata image creation -Run `linuxkit run` backends accept a `-data=STRING` option which will -cause the given string to be passed to the VM in a platform specific -manner to be picked up by the `pkg/metadata` component. +`linuxkit run` backends accept two options to pass metadata to the VM in a platform specific +manner to be picked up by the `pkg/metadata` component: + +* `-data=STRING` will cause the given `STRING` to be passed to the VM +* `-data-file=PATH` will cause the contents of the file at `PATH` to be passed to the VM + Alternatively `linuxkit metadata create meta.iso STRING` will produce a correctly formatted ISO image which can be passed to a VM as a CDROM diff --git a/docs/platform-hyperkit.md b/docs/platform-hyperkit.md index 3e8535441..81b169805 100644 --- a/docs/platform-hyperkit.md +++ b/docs/platform-hyperkit.md @@ -166,7 +166,7 @@ there are a number of packages, such as `vsudd`, which enable tighter integration of the VM with the host (see below). The HyperKit backend also allows passing custom userdata into the -[metadata package](./metadata.md) using the `-data` command-line +[metadata package](./metadata.md) using either the `-data` or `-data-file` command-line option. This attaches a CD device with the data on. diff --git a/src/cmd/linuxkit/run_hyperkit.go b/src/cmd/linuxkit/run_hyperkit.go index 1db165686..df4376b49 100644 --- a/src/cmd/linuxkit/run_hyperkit.go +++ b/src/cmd/linuxkit/run_hyperkit.go @@ -42,7 +42,13 @@ func runHyperKit(args []string) { mem := flags.Int("mem", 1024, "Amount of memory in MB") var disks Disks flags.Var(&disks, "disk", "Disk config. [file=]path[,size=1G]") - data := flags.String("data", "", "Metadata to pass to VM (either a path to a file or a string)") + data := flags.String("data", "", "String of metadata to pass to VM; error to specify both -data and -data-file") + dataPath := flags.String("data-file", "", "Path to file containing metadata to pass to VM; error to specify both -data and -data-file") + + if *data != "" && *dataPath != "" { + log.Fatal("Cannot specify both -data and -data-file") + } + ipStr := flags.String("ip", "", "Preferred IPv4 address for the VM.") state := flags.String("state", "", "Path to directory to keep VM state in") vsockports := flags.String("vsock-ports", "", "List of vsock ports to forward from the guest on startup (comma separated). A unix domain socket for each port will be created in the state directory") @@ -142,7 +148,7 @@ func runHyperKit(args []string) { log.Fatalf("Could not create state directory: %v", err) } - metadataPaths, err := CreateMetadataISO(*state, *data) + metadataPaths, err := CreateMetadataISO(*state, *data, *dataPath) if err != nil { log.Fatalf("%v", err) } diff --git a/src/cmd/linuxkit/run_qemu.go b/src/cmd/linuxkit/run_qemu.go index bb081e7e0..1bb83326b 100644 --- a/src/cmd/linuxkit/run_qemu.go +++ b/src/cmd/linuxkit/run_qemu.go @@ -148,7 +148,12 @@ func runQemu(args []string) { // Paths and settings for disks var disks Disks flags.Var(&disks, "disk", "Disk config, may be repeated. [file=]path[,size=1G][,format=qcow2]") - data := flags.String("data", "", "Metadata to pass to VM (either a path to a file or a string)") + data := flags.String("data", "", "String of metadata to pass to VM; error to specify both -data and -data-file") + dataPath := flags.String("data-file", "", "Path to file containing metadata to pass to VM; error to specify both -data and -data-file") + + if *data != "" && *dataPath != "" { + log.Fatal("Cannot specify both -data and -data-file") + } // Paths and settings for UEFI firware // Note, we do not use defaultFWPath here as we have a special case for containerised execution @@ -223,7 +228,7 @@ func runQemu(args []string) { isoPaths = append(isoPaths, path) } - metadataPaths, err := CreateMetadataISO(*state, *data) + metadataPaths, err := CreateMetadataISO(*state, *data, *dataPath) if err != nil { log.Fatalf("%v", err) } diff --git a/src/cmd/linuxkit/util.go b/src/cmd/linuxkit/util.go index f0147af28..70fb047d5 100644 --- a/src/cmd/linuxkit/util.go +++ b/src/cmd/linuxkit/util.go @@ -256,22 +256,25 @@ func NewPublishedPort(publish string) (PublishedPort, error) { } // CreateMetadataISO writes the provided meta data to an iso file in the given state directory -func CreateMetadataISO(state, data string) ([]string, error) { - if data == "" { - return []string{}, nil - } - +func CreateMetadataISO(state, data string, dataPath string) ([]string, error) { var d []byte - if st, err := os.Stat(data); os.IsNotExist(err) { - d = []byte(data) - } else if st.Size() == 0 { + + // if we have neither data nor dataPath, nothing to return + switch { + case data != "" && dataPath != "": + return nil, fmt.Errorf("Cannot specify options for both data and dataPath") + case data == "" && dataPath == "": return []string{}, nil - } else { - d, err = ioutil.ReadFile(data) + case data != "": + d = []byte(data) + case dataPath != "": + var err error + d, err = ioutil.ReadFile(dataPath) if err != nil { - return nil, fmt.Errorf("Cannot read user data: %v", err) + return nil, fmt.Errorf("Cannot read user data from path %s: %v", dataPath, err) } } + isoPath := filepath.Join(state, "data.iso") if err := WriteMetadataISO(isoPath, d); err != nil { return nil, fmt.Errorf("Cannot write user data ISO: %v", err)