// InitSpec creates an OCI spec from the plugin's config. func (p *Plugin) InitSpec(s specs.Spec, libRoot string) (*specs.Spec, error) { rootfs := filepath.Join(libRoot, p.PluginObj.ID, "rootfs") s.Root = specs.Root{ Path: rootfs, Readonly: false, // TODO: all plugins should be readonly? settable in manifest? } mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{ Source: &p.RuntimeSourcePath, Destination: defaultPluginRuntimeDestination, Type: "bind", Options: []string{"rbind", "rshared"}, }) for _, mount := range mounts { m := specs.Mount{ Destination: mount.Destination, Type: mount.Type, Options: mount.Options, } // TODO: if nil, then it's required and user didn't set it if mount.Source != nil { m.Source = *mount.Source } if m.Source != "" && m.Type == "bind" { fi, err := os.Lstat(filepath.Join(rootfs, m.Destination)) // TODO: followsymlinks if err != nil { return nil, err } if fi.IsDir() { if err := os.MkdirAll(m.Source, 0700); err != nil { return nil, err } } } s.Mounts = append(s.Mounts, m) } envs := make([]string, 1, len(p.PluginObj.Config.Env)+1) envs[0] = "PATH=" + system.DefaultPathEnv envs = append(envs, p.PluginObj.Config.Env...) args := append(p.PluginObj.Manifest.Entrypoint, p.PluginObj.Config.Args...) cwd := p.PluginObj.Manifest.Workdir if len(cwd) == 0 { cwd = "/" } s.Process = specs.Process{ Terminal: false, Args: args, Cwd: cwd, Env: envs, } return &s, nil }