This commit introduces two new commands to the `borg` CLI: - `borg compile`: Compiles a `Borgfile` into a "Terminal Isolation Matrix" (`.matrix` file). The `Borgfile` format is a simple text file with `ADD <src> <dest>` instructions. - `borg run`: Executes a `.matrix` file using `runc`. The command unpacks the matrix into a temporary directory and then executes `runc run`. Tests have been added for both commands, mocking the `runc` execution to avoid environment dependencies.
126 lines
2.3 KiB
Go
126 lines
2.3 KiB
Go
package matrix
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"encoding/json"
|
|
"io/fs"
|
|
|
|
"github.com/Snider/Borg/pkg/datanode"
|
|
)
|
|
|
|
// TerminalIsolationMatrix represents a runc bundle.
|
|
type TerminalIsolationMatrix struct {
|
|
Config []byte
|
|
RootFS *datanode.DataNode
|
|
}
|
|
|
|
// New creates a new, empty TerminalIsolationMatrix.
|
|
func New() (*TerminalIsolationMatrix, error) {
|
|
// Use the default runc spec as a starting point.
|
|
// This can be customized later.
|
|
spec, err := defaultConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
specBytes, err := json.Marshal(spec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &TerminalIsolationMatrix{
|
|
Config: specBytes,
|
|
RootFS: datanode.New(),
|
|
}, nil
|
|
}
|
|
|
|
// FromDataNode creates a new TerminalIsolationMatrix from a DataNode.
|
|
func FromDataNode(dn *datanode.DataNode) (*TerminalIsolationMatrix, error) {
|
|
m, err := New()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
m.RootFS = dn
|
|
return m, nil
|
|
}
|
|
|
|
// ToTar serializes the TerminalIsolationMatrix to a tarball.
|
|
func (m *TerminalIsolationMatrix) ToTar() ([]byte, error) {
|
|
buf := new(bytes.Buffer)
|
|
tw := tar.NewWriter(buf)
|
|
|
|
// Add the config.json file.
|
|
hdr := &tar.Header{
|
|
Name: "config.json",
|
|
Mode: 0600,
|
|
Size: int64(len(m.Config)),
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := tw.Write(m.Config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Add the rootfs directory.
|
|
hdr = &tar.Header{
|
|
Name: "rootfs/",
|
|
Mode: 0755,
|
|
Typeflag: tar.TypeDir,
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Add the rootfs files.
|
|
err := m.RootFS.Walk(".", func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if d.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
file, err := m.RootFS.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
info, err := file.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hdr := &tar.Header{
|
|
Name: "rootfs/" + path,
|
|
Mode: 0600,
|
|
Size: info.Size(),
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
return err
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
if _, err := buf.ReadFrom(file); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := tw.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := tw.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|