Skip to content

Commit

Permalink
Add runtime.envFromFiles
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya Dmitrichenko <errordeveloper@gmail.com>
  • Loading branch information
errordeveloper committed Jan 2, 2019
1 parent 1616b18 commit 7ea1129
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 29 deletions.
1 change: 1 addition & 0 deletions docs/yaml.md
Expand Up @@ -208,6 +208,7 @@ which specifies some actions to take place when the container is being started.
- `bindNS` specifies a namespace type and a path where the namespace from the container being created will be bound. This allows a namespace to be set up in an `onboot` container, and then
using `net: path` for a `service` container to use that network namespace later.
- `namespace` overrides the LinuxKit default containerd namespace to put the container in; only applicable to services.
- `envFromFiles` specifies environment variables that need to be set based on content of files, e.g. for use when metadata needs to be used to set environment variables.

An example of using the `runtime` config to configure a network namespace with `wireguard` and then run `nginx` in that namespace is shown below:
```
Expand Down
7 changes: 4 additions & 3 deletions pkg/init/cmd/service/cmd.go
Expand Up @@ -156,7 +156,7 @@ func start(ctx context.Context, service, sock, basePath, dumpSpec string) (strin

rootfs := filepath.Join(path, "rootfs")

if err := prepareFilesystem(path, runtimeConfig); err != nil {
if err := prepareFilesystem(rootfs, runtimeConfig); err != nil {
return "", 0, "preparing filesystem", err
}

Expand All @@ -174,7 +174,9 @@ func start(ctx context.Context, service, sock, basePath, dumpSpec string) (strin
return "", 0, "failed to parse service spec", err
}

spec.Root.Path = rootfs
if err := prepareSpec(rootfs, runtimeConfig, spec); err != nil {
return "", 0, "preparing environment variables", err
}

if dumpSpec != "" {
d, err := os.Create(dumpSpec)
Expand All @@ -186,7 +188,6 @@ func start(ctx context.Context, service, sock, basePath, dumpSpec string) (strin
if err := enc.Encode(&spec); err != nil {
return "", 0, "failed to write spec dump", err
}

}

if runtimeConfig.Namespace != "" {
Expand Down
59 changes: 41 additions & 18 deletions pkg/init/cmd/service/prepare.go
Expand Up @@ -8,7 +8,7 @@ import (
"path/filepath"
"strings"

"github.com/opencontainers/runtime-spec/specs-go"
specs "github.com/opencontainers/runtime-spec/specs-go"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
Expand All @@ -18,12 +18,13 @@ import (

// Runtime is the type of config processed at runtime, not used to build the OCI spec
type Runtime struct {
Cgroups []string `yaml:"cgroups" json:"cgroups,omitempty"`
Mounts []specs.Mount `yaml:"mounts" json:"mounts,omitempty"`
Mkdir []string `yaml:"mkdir" json:"mkdir,omitempty"`
Interfaces []Interface `yaml:"interfaces" json:"interfaces,omitempty"`
BindNS Namespaces `yaml:"bindNS" json:"bindNS,omitempty"`
Namespace string `yaml:"namespace,omitempty" json:"namespace,omitempty"`
Cgroups []string `yaml:"cgroups" json:"cgroups,omitempty"`
Mounts []specs.Mount `yaml:"mounts" json:"mounts,omitempty"`
Mkdir []string `yaml:"mkdir" json:"mkdir,omitempty"`
Interfaces []Interface `yaml:"interfaces" json:"interfaces,omitempty"`
BindNS Namespaces `yaml:"bindNS" json:"bindNS,omitempty"`
Namespace string `yaml:"namespace,omitempty" json:"namespace,omitempty"`
EnvFromFiles map[string]string `yaml:"envFromFiles,omitempty" json:"envFromFiles,omitempty"`
}

// Namespaces is the type for configuring paths to bind namespaces
Expand Down Expand Up @@ -139,23 +140,23 @@ func newCgroup(cgroup string) error {
return nil
}

func makeAbsolute(rootfs, dir string) string {
if filepath.IsAbs(dir) {
return dir
}
// relative paths are relative to rootfs of container
return filepath.Join(rootfs, dir)
}

// prepareFilesystem sets up the mounts and cgroups, before the container is created
func prepareFilesystem(path string, runtime Runtime) error {
func prepareFilesystem(rootfs string, runtime Runtime) error {
// execute the runtime config that should be done up front
// we execute Mounts before Mkdir so you can make a directory under a mount
// but we do mkdir of the destination path in case missing
rootfs := filepath.Join(path, "rootfs")
makeAbsolute := func(dir string) string {
if filepath.IsAbs(dir) {
return dir
}
// relative paths are relative to rootfs of container
return filepath.Join(rootfs, dir)
}

for _, mount := range runtime.Mounts {
const mode os.FileMode = 0755
dir := makeAbsolute(mount.Destination)
dir := makeAbsolute(rootfs, mount.Destination)
err := os.MkdirAll(dir, mode)
if err != nil {
return fmt.Errorf("Cannot create directory for mount destination %s: %v", dir, err)
Expand All @@ -178,7 +179,7 @@ func prepareFilesystem(path string, runtime Runtime) error {
for _, dir := range runtime.Mkdir {
// in future we may need to change the structure to set mode, ownership
const mode os.FileMode = 0755
dir = makeAbsolute(dir)
dir = makeAbsolute(rootfs, dir)
err := os.MkdirAll(dir, mode)
if err != nil {
return fmt.Errorf("Cannot create directory %s: %v", dir, err)
Expand All @@ -195,6 +196,28 @@ func prepareFilesystem(path string, runtime Runtime) error {
return nil
}

// prepareSpec appends spec based on runtime config;
// NOTE these changes are runtime-only, we don't update config.json after this
func prepareSpec(rootfs string, runtime Runtime, spec *specs.Spec) error {
spec.Root.Path = rootfs

if spec.Process == nil {
spec.Process = &specs.Process{}
}

for envKey, filePath := range runtime.EnvFromFiles {
filePath = makeAbsolute(rootfs, filePath)
data, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("Cannot read file %s: %v", filePath, err)
}
envVar := fmt.Sprintf("%s=%s", envKey, string(data))
spec.Process.Env = append(spec.Process.Env, envVar)
}

return nil
}

// bind mount a namespace file
func bindNS(ns string, path string, pid int) error {
if path == "" {
Expand Down
17 changes: 10 additions & 7 deletions src/cmd/linuxkit/moby/config.go
Expand Up @@ -110,12 +110,13 @@ type ImageConfig struct {

// Runtime is the type of config processed at runtime, not used to build the OCI spec
type Runtime struct {
Cgroups *[]string `yaml:"cgroups,omitempty" json:"cgroups,omitempty"`
Mounts *[]specs.Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
Mkdir *[]string `yaml:"mkdir,omitempty" json:"mkdir,omitempty"`
Interfaces *[]Interface `yaml:"interfaces,omitempty,omitempty" json:"interfaces,omitempty"`
BindNS Namespaces `yaml:"bindNS,omitempty" json:"bindNS,omitempty"`
Namespace *string `yaml:"namespace,omitempty" json:"namespace,omitempty"`
Cgroups *[]string `yaml:"cgroups,omitempty" json:"cgroups,omitempty"`
Mounts *[]specs.Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
Mkdir *[]string `yaml:"mkdir,omitempty" json:"mkdir,omitempty"`
Interfaces *[]Interface `yaml:"interfaces,omitempty,omitempty" json:"interfaces,omitempty"`
BindNS Namespaces `yaml:"bindNS,omitempty" json:"bindNS,omitempty"`
Namespace *string `yaml:"namespace,omitempty" json:"namespace,omitempty"`
EnvFromFiles *map[string]string `yaml:"envFromFiles,omitempty" json:"envFromFiles,omitempty"`
}

// Namespaces is the type for configuring paths to bind namespaces
Expand Down Expand Up @@ -590,6 +591,7 @@ func assignRuntime(v1, v2 *Runtime) Runtime {
runtimeMkdir := assignStrings(v1.Mkdir, v2.Mkdir)
runtimeInterfaces := assignRuntimeInterfaceArray(v1.Interfaces, v2.Interfaces)
runtimeNamespace := assignString(v1.Namespace, v2.Namespace)
runtimeEnvFromFiles := assignMaps(v1.EnvFromFiles, v2.EnvFromFiles)
runtime := Runtime{
Cgroups: &runtimeCgroups,
Mounts: &runtimeMounts,
Expand All @@ -604,7 +606,8 @@ func assignRuntime(v1, v2 *Runtime) Runtime {
User: assignStringPtr(v1.BindNS.User, v2.BindNS.User),
Uts: assignStringPtr(v1.BindNS.Uts, v2.BindNS.Uts),
},
Namespace: &runtimeNamespace,
Namespace: &runtimeNamespace,
EnvFromFiles: &runtimeEnvFromFiles,
}
return runtime
}
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/linuxkit/moby/schema.go
Expand Up @@ -249,7 +249,8 @@ var schema = string(`
"mkdir": {"$ref": "#/definitions/strings"},
"interfaces": {"$ref": "#/definitions/interfaces"},
"bindNS": {"$ref": "#/definitions/namespaces"},
"namespace": {"type": "string"}
"namespace": {"type": "string"},
"envFromFiles": {"$ref": "#/definitions/mapstring"}
}
},
"image": {
Expand Down

0 comments on commit 7ea1129

Please sign in to comment.