diff --git a/bundle/bundle.go b/bundle/bundle.go new file mode 100644 index 0000000..68da885 --- /dev/null +++ b/bundle/bundle.go @@ -0,0 +1,62 @@ +package bundle + +import ( + "encoding/json" + "os" + "path/filepath" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +const configName = "config.json" + +func New(path string, s *specs.Spec) (*Bundle, error) { + if err := os.Mkdir(path, 0700); err != nil { + return nil, err + } + b := &Bundle{ + Path: path, + } + if err := os.Mkdir(filepath.Join(path, "rootfs"), 0700); err != nil { + b.Delete() + return nil, err + } + f, err := os.Create(filepath.Join(path, configName)) + if err != nil { + b.Delete() + return nil, err + } + err = json.NewEncoder(f).Encode(s) + f.Close() + if err != nil { + b.Delete() + return nil, err + } + return b, nil +} + +func Load(path string) (*Bundle, error) { + // TODO: do validation + return &Bundle{ + Path: path, + }, nil +} + +type Bundle struct { + Path string +} + +func (b *Bundle) Config() (*specs.Spec, error) { + var s specs.Spec + f, err := os.Open(filepath.Join(b.Path, configName)) + if err != nil { + return nil, err + } + err = json.NewDecoder(f).Decode(&s) + f.Close() + return &s, err +} + +func (b *Bundle) Delete() error { + return os.RemoveAll(b.Path) +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..77af6d4 --- /dev/null +++ b/config.go @@ -0,0 +1,18 @@ +package containerd + +type Process struct { + Args []string + Env []string + Cwd string + Uid int + Gid int + TTY bool +} + +type Config struct { + Process Process + Hostname string + Domain string + Labels map[string]string + StopSignal int +} diff --git a/specification/spec.go b/specification/spec.go new file mode 100644 index 0000000..f1dc0a1 --- /dev/null +++ b/specification/spec.go @@ -0,0 +1,70 @@ +package specification + +import ( + "runtime" + + "github.com/docker/containerd" + "github.com/opencontainers/runtime-spec/specs-go" +) + +var rwm = "rwm" + +func Default(config containerd.Config, mounts []containerd.Mount) *specs.Spec { + s := &specs.Spec{ + Version: specs.Version, + Platform: specs.Platform{ + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }, + Root: specs.Root{ + Path: "rootfs", + Readonly: false, + }, + Process: specs.Process{ + Args: config.Process.Args, + Env: config.Process.Env, + Terminal: config.Process.TTY, + Cwd: config.Process.Cwd, + NoNewPrivileges: true, + }, + Hostname: config.Hostname, + Linux: &specs.Linux{ + Resources: &specs.LinuxResources{ + Devices: []specs.LinuxDeviceCgroup{ + { + Allow: false, + Access: &rwm, + }, + }, + }, + Namespaces: []specs.LinuxNamespace{ + { + Type: "pid", + }, + { + Type: "ipc", + }, + { + Type: "uts", + }, + { + Type: "mount", + }, + { + Type: "network", + }, + }, + }, + Annotations: config.Labels, + } + // apply snapshot mounts + for _, m := range mounts { + s.Mounts = append(s.Mounts, specs.Mount{ + Source: m.Source, + Destination: "/", + Type: m.Type, + Options: m.Options, + }) + } + return s +}