Skip to content

Commit

Permalink
chore: add tests and such
Browse files Browse the repository at this point in the history
  • Loading branch information
nixpig committed Sep 14, 2024
1 parent e66682a commit 2e474a0
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 157 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: build

on:
push:
branches:
- main

workflow_dispatch:
inputs:
reason:
description: "Reason for manual trigger"
required: true

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup
uses: actions/setup-go@v5
with:
go-version: "1.22.5"

- name: Audit
run: make audit

- name: Install
run: make install

- name: Build
run: make build

- name: Test
run: |
git clone --depth=1 https://github.com/opencontainers/runtime-tools.git \
&& npm install tap \
&& make runtimetest validation-executables \
&& make RUNTIME=tmp/bin/brownie localvalidation
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ go.work.sum

# env file
.env

# temp
tmp/
testdata/
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ audit:

.PHONY: build
build:
go build -o tmp/bin/brownie ./...
go build -o tmp/bin/brownie main.go

.PHONY: test
test:


.PHONY: run
run:
Expand All @@ -32,3 +36,7 @@ watch:
clean:
rm -rf tmp
go clean

.PHONY: install
install:
go mod download
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# brownie
🍪 An experimental Linux container runtime; working towards OCI Runtime Spec compliance.

🍪 An experimental Linux container runtime; working towards OCI Runtime Spec compliance.
100 changes: 66 additions & 34 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cmd

import (
"os"

"github.com/nixpig/brownie/internal/commands"
"github.com/spf13/cobra"
)
Expand All @@ -12,6 +14,49 @@ var Root = &cobra.Command{
Example: "",
}

func createCmd() *cobra.Command {
var create = &cobra.Command{
Use: "create [flags] CONTAINER_ID",
Short: "Create a container",
Args: cobra.ExactArgs(1),
Example: " brownie create busybox",
RunE: func(cmd *cobra.Command, args []string) error {
containerID := args[0]

bundle, err := cmd.Flags().GetString("bundle")
if err != nil {
return err
}

consoleSocket, err := cmd.Flags().GetString("console-socket")
if err != nil {
return err
}

pidFile, err := cmd.Flags().GetString("pid-file")
if err != nil {
return err
}

opts := &commands.CreateOpts{
ID: containerID,
Bundle: bundle,
ConsoleSocket: consoleSocket,
PIDFile: pidFile,
}

return commands.Create(opts)
},
}

cwd, _ := os.Getwd()
create.Flags().StringP("bundle", "b", cwd, "Path to bundle directory")
create.Flags().StringP("console-socket", "s", "", "Console socket")
create.Flags().StringP("pid-file", "p", "", "File to write container PID to")

return create
}

var Start = &cobra.Command{
Use: "start [flags] CONTAINER_ID",
Short: "Start a container",
Expand All @@ -24,28 +69,16 @@ var Start = &cobra.Command{
},
}

var Create = &cobra.Command{
Use: "create [flags] CONTAINER_ID PATH_TO_BUNDLE",
Short: "Create a container",
var Kill = &cobra.Command{
Use: "kill [flags] CONTAINER_ID SIGNAL",
Short: "Kill a container",
Args: cobra.ExactArgs(2),
Example: " brownie create busybox ./busybox",
RunE: func(cmd *cobra.Command, args []string) error {
containerID := args[0]
bundlePath := args[1]

return commands.Create(containerID, bundlePath)
},
}

var QueryState = &cobra.Command{
Use: "state [flags] CONTAINER_ID",
Short: "Query a container state",
Args: cobra.ExactArgs(1),
Example: " brownie state busybox",
Example: " brownie delete busybox 9",
RunE: func(cmd *cobra.Command, args []string) error {
containerID := args[0]
signal := args[1]

return commands.QueryState(containerID)
return commands.Kill(containerID, signal)
},
}

Expand All @@ -61,37 +94,36 @@ var Delete = &cobra.Command{
},
}

var Kill = &cobra.Command{
Use: "kill [flags] CONTAINER_ID SIGNAL",
Short: "Kill a container",
Args: cobra.ExactArgs(2),
Example: " brownie delete busybox 9",
RunE: func(cmd *cobra.Command, args []string) error {
containerID := args[0]
signal := args[1]

return commands.Kill(containerID, signal)
},
}

var Fork = &cobra.Command{
Use: "fork [flags] CONTAINER_ID INIT_SOCK_ADDR CONTAINER_SOCK_ADDR",
Short: "Fork container process\n\n \033[31m ⚠ FOR INTERNAL USE ONLY - DO NOT RUN DIRECTLY ⚠ \033[0m",
Args: cobra.ExactArgs(3),
Example: "\n -- FOR INTERNAL USE ONLY --",
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
Run: func(cmd *cobra.Command, args []string) {
containerID := args[0]
initSockAddr := args[1]
containerSockAddr := args[2]

return commands.Fork(containerID, initSockAddr, containerSockAddr)
commands.Fork(containerID, initSockAddr, containerSockAddr)
},
}

var QueryState = &cobra.Command{
Use: "state [flags] CONTAINER_ID",
Short: "Query a container state",
Args: cobra.ExactArgs(1),
Example: " brownie state busybox",
RunE: func(cmd *cobra.Command, args []string) error {
containerID := args[0]

return commands.QueryState(containerID)
},
}

func init() {
Root.AddCommand(
Create,
createCmd(),
Start,
QueryState,
Delete,
Expand Down
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ module github.com/nixpig/brownie
go 1.23.0

require (
github.com/google/uuid v1.6.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0
github.com/otiai10/copy v1.14.0
github.com/spf13/cobra v1.8.1
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
github.com/otiai10/copy v1.14.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
Expand Down
46 changes: 26 additions & 20 deletions internal/commands/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package commands

import (
"encoding/json"
"errors"
"fmt"
"net"
"os"
Expand All @@ -15,35 +16,42 @@ import (
cp "github.com/otiai10/copy"
)

func Create(containerID, bundlePath string) error {
containerPath := filepath.Join(pkg.BrownieRootDir, "containers", containerID)
type CreateOpts struct {
ID string
Bundle string
ConsoleSocket string
PIDFile string
}

if err := os.MkdirAll(containerPath, os.ModeDir); err != nil {
if err == os.ErrExist {
return pkg.ErrContainerExists
}
func Create(opts *CreateOpts) error {
containerPath := filepath.Join(pkg.BrownieRootDir, "containers", opts.ID)

if stat, _ := os.Stat(containerPath); stat != nil {
return pkg.ErrContainerExists
}

if err := os.MkdirAll(containerPath, os.ModeDir); err != nil {
return fmt.Errorf("make brownie container directory: %w", err)
}

absBundlePath, err := filepath.Abs(bundlePath)
absBundlePath, err := filepath.Abs(opts.Bundle)
if err != nil {
return fmt.Errorf("get absolute path to bundle: %w", err)
}

configJson, err := os.ReadFile(filepath.Join(absBundlePath, "config.json"))
configJSON, err := os.ReadFile(filepath.Join(absBundlePath, "config.json"))
if err != nil {
return fmt.Errorf("read spec: %w", err)
}

var spec specs.Spec
if err := json.Unmarshal(configJson, &spec); err != nil {
if err := json.Unmarshal(configJSON, &spec); err != nil {
return fmt.Errorf("parse config: %w", err)
}

state := &specs.State{
Version: spec.Version,
ID: containerID,
ID: opts.ID,
Status: specs.StateCreating,
Bundle: absBundlePath,
Annotations: spec.Annotations,
Expand All @@ -65,13 +73,11 @@ func Create(containerID, bundlePath string) error {
return fmt.Errorf("copy container spec: %w", err)
}

// 4. Invoke 'createRuntime' hooks.
// TODO: If error, destroy container and created resources then call 'poststop' hooks.
if err := internal.ExecHooks(spec.Hooks.CreateRuntime); err != nil {
return fmt.Errorf("run createRuntime hooks: %w", err)
}

// 5. Invoke 'createContainer' hooks.
// TODO: If error, destroy container and created resources then call 'poststop' hooks.
if err := internal.ExecHooks(spec.Hooks.CreateContainer); err != nil {
return fmt.Errorf("run createContainer hooks: %w", err)
Expand All @@ -84,20 +90,23 @@ func Create(containerID, bundlePath string) error {
"/proc/self/exe",
[]string{
"fork",
containerID,
opts.ID,
initSockAddr,
containerSockAddr,
}...)

if spec.Linux == nil {
return errors.New("not a linux container")
}
var cloneFlags uintptr
for _, ns := range spec.Linux.Namespaces {
lns := internal.LinuxNamespace(ns)
f, err := lns.ToFlag()
ns := internal.LinuxNamespace(ns)
flag, err := ns.ToFlag()
if err != nil {
return err
}

cloneFlags = cloneFlags | f
cloneFlags = cloneFlags | flag
}

// apply configuration, e.g. devices, proc, etc...
Expand All @@ -120,10 +129,7 @@ func Create(containerID, bundlePath string) error {
},
}

if err := forkCmd.Start(); err != nil {
return fmt.Errorf("fork create command: %w", err)
}

forkCmd.Start()
pid := forkCmd.Process.Pid
if err := forkCmd.Process.Release(); err != nil {
return fmt.Errorf("detach from process: %w", err)
Expand Down
4 changes: 2 additions & 2 deletions internal/commands/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ func Delete(containerID string) error {
return fmt.Errorf("remove container path: %s", err)
}

configJson, err := os.ReadFile(filepath.Join(state.Bundle, "config.json"))
configJSON, err := os.ReadFile(filepath.Join(state.Bundle, "config.json"))
if err != nil {
return fmt.Errorf("read config file: %w", err)
}

var spec specs.Spec
if err := json.Unmarshal(configJson, &spec); err != nil {
if err := json.Unmarshal(configJSON, &spec); err != nil {
return fmt.Errorf("unmarshal config.json: %w", err)
}

Expand Down
Loading

0 comments on commit 2e474a0

Please sign in to comment.