Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,23 @@ linters:
- staticcheck
- whitespace
- wrapcheck
exclusions:
Comment thread
obbardc marked this conversation as resolved.
presets:
- comments
- ineffassign
- unused
- unconvert
- bodyclose
- copyloopvar
- nilerr
- nilnil
- wastedassign
- maintidx
- nakedret
- predeclared
- gocritic
- prealloc
- noctx
- testifylint
- unparam
formatters:
enable:
- gofmt
- gofumpt
- goimports
13 changes: 8 additions & 5 deletions backend.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//go:build linux
// +build linux

// Package fakemachine provides a lightweight virtual machine abstraction for
// running commands in an isolated environment.
package fakemachine

import (
Expand All @@ -15,13 +17,14 @@ func implementedBackends(m *Machine) []backend {
}
}

/* A list of backends which are implemented - sorted in order in which the
* "auto" backend chooses them.
*/
// BackendNames returns the list of implemented backends sorted in order of
// preference for the "auto" selection algorithm, with "auto" prepended.
func BackendNames() []string {
names := []string{"auto"}
backends := implementedBackends(nil)
names := make([]string, 0, 1+len(backends))
names = append(names, "auto")

for _, backend := range implementedBackends(nil) {
for _, backend := range backends {
names = append(names, backend.Name())
}

Expand Down
14 changes: 9 additions & 5 deletions backend_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func (b qemuBackend) ModulePath() (string, error) {
}

func (b qemuBackend) UdevRules() []string {
udevRules := []string{}
udevRules := make([]string, 0, 2*len(b.machine.images))

// create symlink under /dev/disk/by-fakemachine-label/ for each virtual image
for i, img := range b.machine.images {
Expand Down Expand Up @@ -228,14 +228,16 @@ func (b qemuBackend) StartQemu(kvm bool) (bool, error) {
}
memory := fmt.Sprintf("%d", m.memory)
numcpus := fmt.Sprintf("%d", m.numcpus)
qemuargs := []string{qemuMachine.binary,
qemuargs := []string{
qemuMachine.binary,
"-smp", numcpus,
"-m", memory,
"-kernel", kernelPath,
"-initrd", m.initrdpath,
"-display", "none",
"-nic", "user,model=virtio-net-pci",
"-no-reboot"}
"-no-reboot",
}

if kvm {
qemuargs = append(qemuargs,
Expand All @@ -247,9 +249,11 @@ func (b qemuBackend) StartQemu(kvm bool) (bool, error) {

qemuargs = append(qemuargs, "-machine", qemuMachine.machine)
console := fmt.Sprintf("console=%s", qemuMachine.console)
kernelargs := []string{console, "panic=-1",
kernelargs := []string{
console, "panic=-1",
"plymouth.enable=0",
"systemd.unit=fakemachine.service"}
"systemd.unit=fakemachine.service",
}

if m.showBoot {
// Create a character device representing our stdio
Expand Down
21 changes: 13 additions & 8 deletions cmd/fakemachine/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// Package main is the entry point for the fakemachine command-line tool.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rework these comments to better describe the functions.

package main

import (
"al.essio.dev/pkg/shellescape"
"errors"
"fmt"
"github.com/docker/go-units"
"github.com/go-debos/fakemachine"
"github.com/jessevdk/go-flags"
"os"
"runtime/debug"
"strings"

"al.essio.dev/pkg/shellescape"

"github.com/docker/go-units"
"github.com/go-debos/fakemachine"
"github.com/jessevdk/go-flags"
)

var Version string
Expand All @@ -28,8 +31,10 @@ type Options struct {
Version bool `long:"version" description:"Print fakemachine version"`
}

var options Options
var parser = flags.NewParser(&options, flags.Default)
var (
options Options
parser = flags.NewParser(&options, flags.Default)
)

func determineVersionFromBuild() string {
info, ok := debug.ReadBuildInfo()
Expand Down Expand Up @@ -131,7 +136,7 @@ func SetupEnviron(m *fakemachine.Machine, options Options) {
// These are the environment variables that will be detected on the
// host and propagated to fakemachine. These are listed lower case, but
// they are detected and configured in both lower case and upper case.
var environVars = [...]string{
environVars := [...]string{
"http_proxy",
"https_proxy",
"ftp_proxy",
Expand Down Expand Up @@ -166,7 +171,7 @@ func SetupEnviron(m *fakemachine.Machine, options Options) {
}

// Puts in a format that is compatible with output of os.Environ()
EnvironString := []string{}
EnvironString := make([]string, 0, len(EnvironVars))
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is prealloc really a useful linter ?

for k, v := range EnvironVars {
warnLocalhost(k, v)
EnvironString = append(EnvironString, fmt.Sprintf("%s=%s", k, v))
Expand Down
29 changes: 24 additions & 5 deletions cpio/writerhelper.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package writerhelper provides helpers for writing cpio archives.
package writerhelper

import (
Expand All @@ -10,27 +11,33 @@ import (
"path/filepath"
"strings"

"github.com/surma/gocpio"
cpio "github.com/surma/gocpio"
)

// WriterHelper wraps a cpio.Writer and tracks written paths to automatically
// create parent directories as needed.
type WriterHelper struct {
paths map[string]bool
*cpio.Writer
}

// WriteDirectory describes a directory entry to add to the archive.
type WriteDirectory struct {
Directory string
Perm os.FileMode
}

// WriteSymlink describes a symbolic link entry to add to the archive.
type WriteSymlink struct {
Target string
Link string
Perm os.FileMode
}

// Transformer is a function that transforms data from src and writes it to dst.
type Transformer func(dst io.Writer, src io.Reader) error

// NewWriterHelper creates a WriterHelper that writes a cpio archive to f.
func NewWriterHelper(f io.Writer) *WriterHelper {
return &WriterHelper{
paths: map[string]bool{"/": true},
Expand All @@ -54,7 +61,7 @@ func (w *WriterHelper) ensureBaseDirectory(directory string) error {
continue
}

err := w.WriteDirectory(collector, 0755)
err := w.WriteDirectory(collector, 0o755)
if err != nil {
return err
}
Expand All @@ -63,6 +70,7 @@ func (w *WriterHelper) ensureBaseDirectory(directory string) error {
return nil
}

// WriteDirectories writes multiple directory entries to the archive.
func (w *WriterHelper) WriteDirectories(directories []WriteDirectory) error {
for _, d := range directories {
err := w.WriteDirectory(d.Directory, d.Perm)
Expand All @@ -73,6 +81,7 @@ func (w *WriterHelper) WriteDirectories(directories []WriteDirectory) error {
return nil
}

// WriteDirectory writes a single directory entry, creating parent directories as needed.
func (w *WriterHelper) WriteDirectory(directory string, perm os.FileMode) error {
err := w.ensureBaseDirectory(path.Dir(directory))
if err != nil {
Expand All @@ -94,10 +103,12 @@ func (w *WriterHelper) WriteDirectory(directory string, perm os.FileMode) error
return nil
}

// WriteFile writes a regular file with the given string content to the archive.
func (w *WriterHelper) WriteFile(file, content string, perm os.FileMode) error {
return w.WriteFileRaw(file, []byte(content), perm)
}

// WriteFileRaw writes a regular file with the given byte content to the archive.
func (w *WriterHelper) WriteFileRaw(file string, bytes []byte, perm os.FileMode) error {
err := w.ensureBaseDirectory(path.Dir(file))
if err != nil {
Expand All @@ -122,6 +133,7 @@ func (w *WriterHelper) WriteFileRaw(file string, bytes []byte, perm os.FileMode)
return nil
}

// WriteSymlinks writes multiple symbolic link entries to the archive.
func (w *WriterHelper) WriteSymlinks(links []WriteSymlink) error {
for _, l := range links {
err := w.WriteSymlink(l.Target, l.Link, l.Perm)
Expand All @@ -132,6 +144,7 @@ func (w *WriterHelper) WriteSymlinks(links []WriteSymlink) error {
return nil
}

// WriteSymlink writes a single symbolic link entry to the archive.
func (w *WriterHelper) WriteSymlink(target, link string, perm os.FileMode) error {
err := w.ensureBaseDirectory(path.Dir(link))
if err != nil {
Expand Down Expand Up @@ -159,6 +172,7 @@ func (w *WriterHelper) WriteSymlink(target, link string, perm os.FileMode) error
return nil
}

// WriteCharDevice writes a character device entry to the archive.
func (w *WriterHelper) WriteCharDevice(device string, major, minor int64, perm os.FileMode) error {
err := w.ensureBaseDirectory(path.Dir(device))
if err != nil {
Expand All @@ -179,16 +193,18 @@ func (w *WriterHelper) WriteCharDevice(device string, major, minor int64, perm o
return nil
}

// CopyTree recursively copies a host directory tree into the archive.
func (w *WriterHelper) CopyTree(path string) error {
walker := func(p string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error visiting %s: %w", p, err)
}
if info.Mode().IsDir() {
switch {
case info.Mode().IsDir():
err = w.WriteDirectory(p, info.Mode() & ^os.ModeType)
} else if info.Mode().IsRegular() {
case info.Mode().IsRegular():
err = w.CopyFile(p)
} else {
default:
err = fmt.Errorf("file type not handled for %s", p)
}

Expand All @@ -202,6 +218,7 @@ func (w *WriterHelper) CopyTree(path string) error {
return nil
}

// CopyFileTo copies a file from src on the host into the archive at dst.
func (w *WriterHelper) CopyFileTo(src, dst string) (err error) {
if err := w.ensureBaseDirectory(path.Dir(dst)); err != nil {
return err
Expand Down Expand Up @@ -242,6 +259,7 @@ func (w *WriterHelper) CopyFileTo(src, dst string) (err error) {
return nil
}

// TransformFileTo reads src from the host, transforms it with fn, and writes the result into the archive at dst.
func (w *WriterHelper) TransformFileTo(src, dst string, fn Transformer) (err error) {
if err := w.ensureBaseDirectory(path.Dir(dst)); err != nil {
return err
Expand Down Expand Up @@ -287,6 +305,7 @@ func (w *WriterHelper) TransformFileTo(src, dst string, fn Transformer) (err err
return nil
}

// CopyFile copies a file from the host into the archive at the same path.
func (w *WriterHelper) CopyFile(in string) error {
return w.CopyFileTo(in, in)
}
6 changes: 5 additions & 1 deletion decompressors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/ulikunitz/xz"
)

// ZstdDecompressor decompresses zstd-compressed data from src into dst.
func ZstdDecompressor(dst io.Writer, src io.Reader) error {
decompressor, err := zstd.NewReader(src)
if err != nil {
Expand All @@ -24,13 +25,14 @@ func ZstdDecompressor(dst io.Writer, src io.Reader) error {
return nil
}

// XzDecompressor decompresses xz-compressed data from src into dst.
func XzDecompressor(dst io.Writer, src io.Reader) error {
decompressor, err := xz.NewReader(src)
if err != nil {
return fmt.Errorf("failed to create xz decompressor: %w", err)
}
// There is no Close() API. See: https://github.com/ulikunitz/xz/issues/45
//defer decompressor.Close()
// defer decompressor.Close()

_, err = io.Copy(dst, decompressor)
if err != nil {
Expand All @@ -39,6 +41,7 @@ func XzDecompressor(dst io.Writer, src io.Reader) error {
return nil
}

// GzipDecompressor decompresses gzip-compressed data from src into dst.
func GzipDecompressor(dst io.Writer, src io.Reader) (err error) {
decompressor, err := gzip.NewReader(src)
if err != nil {
Expand All @@ -57,6 +60,7 @@ func GzipDecompressor(dst io.Writer, src io.Reader) (err error) {
return nil
}

// NullDecompressor copies uncompressed data from src into dst unchanged.
func NullDecompressor(dst io.Writer, src io.Reader) error {
_, err := io.Copy(dst, src)
if err != nil {
Expand Down
16 changes: 8 additions & 8 deletions decompressors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"path"
"testing"

"github.com/go-debos/fakemachine/cpio"
writerhelper "github.com/go-debos/fakemachine/cpio"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -50,8 +50,8 @@ func checkStreamsMatch(output, check io.Reader) error {
}
}

func decompressorTest(file, suffix string, d writerhelper.Transformer) (err error) {
testFilePath := path.Join("testdata", file+suffix)
func decompressorTest(suffix string, d writerhelper.Transformer) (err error) {
testFilePath := path.Join("testdata", "test"+suffix)
f, err := os.Open(testFilePath)
if err != nil {
return fmt.Errorf("open test file %s: %w", testFilePath, err)
Expand All @@ -67,7 +67,7 @@ func decompressorTest(file, suffix string, d writerhelper.Transformer) (err erro
return fmt.Errorf("decompress test file %s: %w", testFilePath, err)
}

checkFilePath := path.Join("testdata", file)
checkFilePath := path.Join("testdata", "test")
checkFile, err := os.Open(checkFilePath)
if err != nil {
return fmt.Errorf("open check file %s: %w", checkFilePath, err)
Expand All @@ -86,21 +86,21 @@ func decompressorTest(file, suffix string, d writerhelper.Transformer) (err erro
}

func TestZstd(t *testing.T) {
err := decompressorTest("test", ".zst", ZstdDecompressor)
err := decompressorTest(".zst", ZstdDecompressor)
require.NoError(t, err)
}

func TestXz(t *testing.T) {
err := decompressorTest("test", ".xz", XzDecompressor)
err := decompressorTest(".xz", XzDecompressor)
require.NoError(t, err)
}

func TestGzip(t *testing.T) {
err := decompressorTest("test", ".gz", GzipDecompressor)
err := decompressorTest(".gz", GzipDecompressor)
require.NoError(t, err)
}

func TestNull(t *testing.T) {
err := decompressorTest("test", "", NullDecompressor)
err := decompressorTest("", NullDecompressor)
require.NoError(t, err)
}
Loading