Skip to content

Commit

Permalink
contd: parse startup.toml and update container data
Browse files Browse the repository at this point in the history
fixes #319

we extract 3 things from statup.toml:
- entrypoint
- working dir
- enviroment variable
  • Loading branch information
zaibon committed Oct 15, 2019
1 parent 8cc88ec commit 3c555e6
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 143 deletions.
2 changes: 2 additions & 0 deletions pkg/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Container struct {
RootFS string
// Env env variables to container in format {'KEY=VALUE', 'KEY2=VALUE2'}
Env []string
// WorkingDir of the entrypoint command
WorkingDir string
// Network network info for container
Network NetworkInfo
// Mounts extra mounts for container
Expand Down
122 changes: 73 additions & 49 deletions pkg/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ package container
import (
"context"

"github.com/BurntSushi/toml"
"github.com/pkg/errors"

"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"syscall"
"time"

"github.com/BurntSushi/toml"

"github.com/rs/zerolog/log"

"github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -65,12 +63,7 @@ func New(root string, containerd string) pkg.ContainerModule {
}

// Run creates and starts a container
// THIS IS A WIP Create action and it's not fully implemented atm
func (c *containerModule) Run(ns string, data pkg.Container) (id pkg.ContainerID, err error) {
log.Info().
Str("namesapce", ns).
Str("data", fmt.Sprintf("%+v", data)).
Msgf("create new container")
// create a new client connected to the default socket path for containerd
client, err := containerd.New(c.containerd)
if err != nil {
Expand All @@ -92,6 +85,10 @@ func (c *containerModule) Run(ns string, data pkg.Container) (id pkg.ContainerID
return id, errors.Wrap(err, "failed to set resolv.conf")
}

if err := applyStartup(&data, filepath.Join(data.RootFS, ".startup.toml")); err != nil {
errors.Wrap(err, "error updating environment variable from startup file")
}

if data.Interactive {
if err := os.MkdirAll(filepath.Join(data.RootFS, "sandbox"), 0770); err != nil {
return id, err
Expand All @@ -118,6 +115,11 @@ func (c *containerModule) Run(ns string, data pkg.Container) (id pkg.ContainerID
oci.WithEnv(data.Env),
removeRunMount(),
}

if data.WorkingDir != "" {
opts = append(opts, oci.WithProcessCwd(data.WorkingDir))
}

if data.Interactive {
opts = append(
opts,
Expand Down Expand Up @@ -155,6 +157,11 @@ func (c *containerModule) Run(ns string, data pkg.Container) (id pkg.ContainerID
)
}

log.Info().
Str("namespace", ns).
Str("data", fmt.Sprintf("%+v", data)).
Msgf("create new container")

container, err := client.NewContainer(
ctx,
data.Name,
Expand Down Expand Up @@ -303,54 +310,71 @@ func (c *containerModule) Delete(ns string, id pkg.ContainerID) error {
return container.Delete(ctx)
}

// readEnvs reads the environment variable from the statup.toml file
func readEnvs(r io.Reader) ([]string, error) {
env := struct {
Startup struct {
Entry struct {
Name string `json:"name"`
Args struct {
Name string `json:"name"`
Dir string `json:"dir"`
Env map[string]string `json:"env"`
} `json:"args"`
} `json:"entry"`
} `json:"startup"`
}{}
if _, err := toml.DecodeReader(r, &env); err != nil {
return nil, err
}

result := make([]string, 0, len(env.Startup.Entry.Args.Env))
for k, v := range env.Startup.Entry.Args.Env {
result = append(result, fmt.Sprintf("%s=%s", k, v))
}
return result, nil
func (c *containerModule) ensureNamespace(ctx context.Context, client *containerd.Client, namespace string) error {
service := client.NamespaceService()
namespaces, err := service.List(ctx)
if err != nil {
return err
}

for _, ns := range namespaces {
if ns == namespace {
return nil
}
}

return service.Create(ctx, namespace, nil)
}

// mergeEnvs merge a into b
// all the key from a will endup in b
// if a key is present in both, key from a are kept
func mergeEnvs(a, b []string) []string {
ma := make(map[string]string, len(a))
mb := make(map[string]string, len(b))
func setResolvConf(root string) error {
const tmp = "nameserver 1.1.1.1\nnameserver 1.0.0.1\n2606:4700:4700::1111\nnameserver 2606:4700:4700::1001\n"

for _, s := range a {
ss := strings.SplitN(s, "=", 2)
ma[ss[0]] = ss[1]
path := filepath.Join(root, "etc/resolv.conf")
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 644)
if err != nil && !os.IsNotExist(err) {
return err
}
for _, s := range b {
ss := strings.SplitN(s, "=", 2)
mb[ss[0]] = ss[1]

defer f.Close()

if os.IsNotExist(err) {
_, err = f.WriteString(tmp)
return err
}

for ka, va := range ma {
mb[ka] = va
info, err := f.Stat()
if err != nil {
return err
}
if info.Size() == 0 {
_, err = f.WriteString(tmp)
}
return err
}

result := make([]string, 0, len(mb))
for k, v := range mb {
result = append(result, fmt.Sprintf("%s=%s", k, v))
func applyStartup(data *pkg.Container, path string) error {
f, err := os.Open(path)
if err == nil {
defer f.Close()
log.Info().Msg("startup file found")

startup := startup{}
if _, err := toml.DecodeReader(f, &startup); err != nil {
return err
}

entry, ok := startup.Entries["entry"]
if !ok {
return nil
}

data.Env = mergeEnvs(entry.Envs(), data.Env)
if data.Entrypoint == "" && entry.Entrypoint() != "" {
data.Entrypoint = entry.Entrypoint()
}
if data.WorkingDir == "" && entry.WorkingDir() != "" {
data.WorkingDir = entry.WorkingDir()
}
}
return result
return nil
}
48 changes: 0 additions & 48 deletions pkg/container/container_test.go

This file was deleted.

49 changes: 3 additions & 46 deletions pkg/container/spec_opts.go → pkg/container/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ package container

import (
"context"
"os"

"path"
"path/filepath"

"github.com/containerd/containerd"
"github.com/opencontainers/runtime-spec/specs-go"

"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/oci"
"github.com/opencontainers/runtime-spec/specs-go"
)

// withNetworkNamespace set the named network namespace to use for the container
Expand Down Expand Up @@ -57,22 +56,6 @@ func withAddedCapabilities(caps []string) oci.SpecOpts {
}
}

func (c *containerModule) ensureNamespace(ctx context.Context, client *containerd.Client, namespace string) error {
service := client.NamespaceService()
namespaces, err := service.List(ctx)
if err != nil {
return err
}

for _, ns := range namespaces {
if ns == namespace {
return nil
}
}

return service.Create(ctx, namespace, nil)
}

func removeRunMount() oci.SpecOpts {
return func(_ context.Context, _ oci.Client, _ *containers.Container, s *oci.Spec) error {
for i, mount := range s.Mounts {
Expand All @@ -84,29 +67,3 @@ func removeRunMount() oci.SpecOpts {
return nil
}
}

func setResolvConf(root string) error {
const tmp = "nameserver 1.1.1.1\nnameserver 1.0.0.1\n2606:4700:4700::1111\nnameserver 2606:4700:4700::1001\n"

path := filepath.Join(root, "etc/resolv.conf")
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 644)
if err != nil && !os.IsNotExist(err) {
return err
}

defer f.Close()

if os.IsNotExist(err) {
_, err = f.WriteString(tmp)
return err
}

info, err := f.Stat()
if err != nil {
return err
}
if info.Size() == 0 {
_, err = f.WriteString(tmp)
}
return err
}
68 changes: 68 additions & 0 deletions pkg/container/startup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package container

import (
"fmt"
"strings"
)

type startup struct {
Entries map[string]entry `toml:"startup"`
}

type entry struct {
Name string
Args args
}

type args struct {
Name string
Dir string
Env map[string]string
}

func (e entry) Entrypoint() string {
if e.Name == "core.system" ||
e.Name == "core.base" && e.Args.Name != "" {
return e.Args.Name
}
return ""
}

func (e entry) WorkingDir() string {
return e.Args.Dir
}

func (e entry) Envs() []string {
envs := make([]string, 0, len(e.Args.Env))
for k, v := range e.Args.Env {
envs = append(envs, fmt.Sprintf("%s=%s", k, v))
}
return envs
}

// mergeEnvs merge a into b
// all the key from a will endup in b
// if a key is present in both, key from a are kept
func mergeEnvs(a, b []string) []string {
ma := make(map[string]string, len(a))
mb := make(map[string]string, len(b))

for _, s := range a {
ss := strings.SplitN(s, "=", 2)
ma[ss[0]] = ss[1]
}
for _, s := range b {
ss := strings.SplitN(s, "=", 2)
mb[ss[0]] = ss[1]
}

for ka, va := range ma {
mb[ka] = va
}

result := make([]string, 0, len(mb))
for k, v := range mb {
result = append(result, fmt.Sprintf("%s=%s", k, v))
}
return result
}
Loading

0 comments on commit 3c555e6

Please sign in to comment.