mirror of
https://github.com/abiosoft/colima.git
synced 2026-05-17 12:10:34 +00:00
+4
-3
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/abiosoft/colima/environment/container/ubuntu"
|
||||
"github.com/abiosoft/colima/environment/host"
|
||||
"github.com/abiosoft/colima/environment/vm/lima"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -208,7 +209,7 @@ func (c colimaApp) SSH(layer bool, args ...string) error {
|
||||
return c.guest.RunInteractive(args...)
|
||||
}
|
||||
|
||||
conf, err := lima.InstanceConfig()
|
||||
conf, err := limautil.InstanceConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -216,7 +217,7 @@ func (c colimaApp) SSH(layer bool, args ...string) error {
|
||||
return c.guest.RunInteractive(args...)
|
||||
}
|
||||
|
||||
resp, err := lima.ShowSSH(config.CurrentProfile().ID, layer, "args")
|
||||
resp, err := limautil.ShowSSH(config.CurrentProfile().ID, layer, "args")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting ssh config: %w", err)
|
||||
}
|
||||
@@ -256,7 +257,7 @@ func (c colimaApp) Status() error {
|
||||
log.Println(config.CurrentProfile().DisplayName, "is running")
|
||||
log.Println("arch:", c.guest.Arch())
|
||||
log.Println("runtime:", currentRuntime)
|
||||
if conf, err := lima.InstanceConfig(); err == nil {
|
||||
if conf, err := limautil.InstanceConfig(); err == nil {
|
||||
log.Println("mountType:", conf.MountType)
|
||||
}
|
||||
if currentRuntime == docker.Name {
|
||||
|
||||
+11
-4
@@ -10,12 +10,12 @@ import (
|
||||
_ "github.com/abiosoft/colima/cmd" // for other commands
|
||||
_ "github.com/abiosoft/colima/cmd/daemon" // for vmnet daemon
|
||||
_ "github.com/abiosoft/colima/embedded" // for embedded assets
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/gvproxy"
|
||||
"github.com/abiosoft/colima/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/abiosoft/colima/cmd/root"
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/daemon/process/gvproxy"
|
||||
"github.com/abiosoft/colima/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -27,6 +27,7 @@ func main() {
|
||||
root.Execute()
|
||||
}
|
||||
}
|
||||
|
||||
func qemuWrapper(qemu string) {
|
||||
if profile := os.Getenv(config.SubprocessProfileEnvVar); profile != "" {
|
||||
config.SetProfile(profile)
|
||||
@@ -79,6 +80,12 @@ func qemuWrapper(qemu string) {
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, fd)
|
||||
}
|
||||
|
||||
_ = cmd.Run()
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
os.Exit(err.ExitCode())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-11
@@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/gvproxy"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/vmnet"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
"github.com/abiosoft/colima/daemon/process/gvproxy"
|
||||
"github.com/abiosoft/colima/daemon/process/vmnet"
|
||||
|
||||
"github.com/abiosoft/colima/cmd/root"
|
||||
"github.com/abiosoft/colima/config"
|
||||
@@ -18,10 +18,6 @@ var daemonCmd = &cobra.Command{
|
||||
Short: "daemon",
|
||||
Long: `runner for background daemons.`,
|
||||
Hidden: true,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
cmd.SilenceUsage = true
|
||||
cmd.SilenceErrors = true
|
||||
},
|
||||
}
|
||||
|
||||
var startCmd = &cobra.Command{
|
||||
@@ -31,8 +27,9 @@ var startCmd = &cobra.Command{
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
config.SetProfile(args[0])
|
||||
ctx := cmd.Context()
|
||||
|
||||
var processes []daemon.Process
|
||||
var processes []process.Process
|
||||
if daemonArgs.vmnet {
|
||||
processes = append(processes, vmnet.New())
|
||||
}
|
||||
@@ -40,7 +37,7 @@ var startCmd = &cobra.Command{
|
||||
processes = append(processes, gvproxy.New())
|
||||
}
|
||||
|
||||
return start(cmd.Context(), processes)
|
||||
return start(ctx, processes)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -74,8 +71,11 @@ var statusCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
var daemonArgs struct {
|
||||
vmnet bool
|
||||
gvproxy bool
|
||||
vmnet bool
|
||||
gvproxy bool
|
||||
fsnotify bool
|
||||
|
||||
verbose bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -87,4 +87,5 @@ func init() {
|
||||
|
||||
startCmd.Flags().BoolVar(&daemonArgs.vmnet, "vmnet", false, "start vmnet")
|
||||
startCmd.Flags().BoolVar(&daemonArgs.gvproxy, "gvproxy", false, "start gvproxy")
|
||||
startCmd.Flags().BoolVar(&daemonArgs.fsnotify, "fsnotify", false, "start fsnotify")
|
||||
}
|
||||
|
||||
+34
-4
@@ -7,16 +7,17 @@ import (
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/abiosoft/colima/cli"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
godaemon "github.com/sevlyar/go-daemon"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var dir = daemon.Dir
|
||||
var dir = process.Dir
|
||||
|
||||
// daemonize creates the daemon and returns if this is a child process
|
||||
func daemonize() (ctx *godaemon.Context, child bool, err error) {
|
||||
@@ -49,7 +50,7 @@ func daemonize() (ctx *godaemon.Context, child bool, err error) {
|
||||
return ctx, true, nil
|
||||
}
|
||||
|
||||
func start(ctx context.Context, processes []daemon.Process) error {
|
||||
func start(ctx context.Context, processes []process.Process) error {
|
||||
if status() == nil {
|
||||
logrus.Info("daemon already running, startup ignored")
|
||||
return nil
|
||||
@@ -75,7 +76,7 @@ func start(ctx context.Context, processes []daemon.Process) error {
|
||||
ctx, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
return daemon.Run(ctx, processes...)
|
||||
return RunProcesses(ctx, processes...)
|
||||
}
|
||||
|
||||
func stop(ctx context.Context) error {
|
||||
@@ -153,3 +154,32 @@ func Info() struct {
|
||||
LogFile: filepath.Join(dir, logFileName),
|
||||
}
|
||||
}
|
||||
|
||||
// Run runs the daemon with background processes.
|
||||
// NOTE: this must be called from the program entrypoint with minimal intermediary logic
|
||||
// due to the creation of the daemon.
|
||||
func RunProcesses(ctx context.Context, processes ...process.Process) error {
|
||||
ctx, stop := context.WithCancel(ctx)
|
||||
defer stop()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(processes))
|
||||
|
||||
for _, bg := range processes {
|
||||
go func(bg process.Process) {
|
||||
err := bg.Start(ctx)
|
||||
if err != nil {
|
||||
logrus.Error(fmt.Errorf("error starting %s: %w", bg.Name(), err))
|
||||
stop()
|
||||
}
|
||||
wg.Done()
|
||||
}(bg)
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
logrus.Info("terminate signal received")
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
+43
-10
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
)
|
||||
|
||||
var testDir string
|
||||
@@ -19,22 +19,28 @@ func setDir(t *testing.T) {
|
||||
dir = func() string { return testDir }
|
||||
}
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
setDir(t)
|
||||
info := Info()
|
||||
|
||||
func getProcesses() []process.Process {
|
||||
var addresses = []string{
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
}
|
||||
|
||||
t.Log("pidfile", info.PidFile)
|
||||
|
||||
var processes []daemon.Process
|
||||
var processes []process.Process
|
||||
for _, add := range addresses {
|
||||
processes = append(processes, &pinger{address: add})
|
||||
}
|
||||
|
||||
return processes
|
||||
}
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
setDir(t)
|
||||
info := Info()
|
||||
|
||||
processes := getProcesses()
|
||||
|
||||
t.Log("pidfile", info.PidFile)
|
||||
|
||||
timeout := time.Second * 5
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
@@ -54,6 +60,8 @@ func TestStart(t *testing.T) {
|
||||
default:
|
||||
if p, err := os.ReadFile(info.PidFile); err == nil && len(p) > 0 {
|
||||
break loop
|
||||
} else if err != nil {
|
||||
t.Logf("encountered err: %v", err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
@@ -79,7 +87,32 @@ func TestStart(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
var _ daemon.Process = (*pinger)(nil)
|
||||
func TestRunProcesses(t *testing.T) {
|
||||
processes := getProcesses()
|
||||
|
||||
timeout := time.Second * 5
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
|
||||
// start the processes
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- RunProcesses(ctx, processes...)
|
||||
}()
|
||||
|
||||
cancel()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if err := ctx.Err(); err != context.Canceled {
|
||||
t.Error(err)
|
||||
}
|
||||
case err := <-done:
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _ process.Process = (*pinger)(nil)
|
||||
|
||||
type pinger struct {
|
||||
address string
|
||||
@@ -98,7 +131,7 @@ func (p *pinger) Start(ctx context.Context) error {
|
||||
}
|
||||
|
||||
// Start implements BgProcess
|
||||
func (p *pinger) Dependencies() ([]daemon.Dependency, bool) { return nil, false }
|
||||
func (p *pinger) Dependencies() ([]process.Dependency, bool) { return nil, false }
|
||||
|
||||
func (p *pinger) run(ctx context.Context, command string, args ...string) error {
|
||||
cmd := exec.CommandContext(ctx, command, args...)
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import (
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/abiosoft/colima/cmd/root"
|
||||
"github.com/abiosoft/colima/environment/vm/lima"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -26,7 +26,7 @@ var listCmd = &cobra.Command{
|
||||
A new instance can be created during 'colima start' by specifying the '--profile' flag.`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
instances, err := lima.Instances()
|
||||
instances, err := limautil.Instances()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/abiosoft/colima/cmd/root"
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/environment/vm/lima"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ var sshConfigCmd = &cobra.Command{
|
||||
Long: `Show configuration of the SSH connection to the VM.`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
resp, err := lima.ShowSSH(config.CurrentProfile().ID, sshConfigCmdArgs.layer, sshConfigCmdArgs.format)
|
||||
resp, err := limautil.ShowSSH(config.CurrentProfile().ID, sshConfigCmdArgs.layer, sshConfigCmdArgs.format)
|
||||
if err == nil {
|
||||
fmt.Println(resp.Output)
|
||||
}
|
||||
|
||||
@@ -132,6 +132,17 @@ func (m Mount) CleanPath() (string, error) {
|
||||
return strings.TrimSuffix(str, "/") + "/", nil
|
||||
}
|
||||
|
||||
func (c Config) MountsOrDefault() []Mount {
|
||||
if len(c.Mounts) > 0 {
|
||||
return c.Mounts
|
||||
}
|
||||
|
||||
return []Mount{
|
||||
{Location: util.HomeDir(), Writable: true},
|
||||
{Location: filepath.Join("/tmp", CurrentProfile().ID), Writable: true},
|
||||
}
|
||||
}
|
||||
|
||||
// Empty checks if the configuration is empty.
|
||||
func (c Config) Empty() bool { return c.Runtime == "" } // this may be better but not really needed.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package network
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -6,18 +6,18 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
"github.com/abiosoft/colima/daemon/process/gvproxy"
|
||||
"github.com/abiosoft/colima/daemon/process/vmnet"
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/gvproxy"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/vmnet"
|
||||
)
|
||||
|
||||
// Manager handles networking between the host and the vm.
|
||||
// Manager handles running background processes.
|
||||
type Manager interface {
|
||||
Start(context.Context) error
|
||||
Stop(context.Context) error
|
||||
Running(ctx context.Context) (Status, error)
|
||||
Dependencies(ctx context.Context) (deps daemon.Dependency, root bool)
|
||||
Dependencies(ctx context.Context) (deps process.Dependency, root bool)
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
@@ -32,35 +32,35 @@ type processStatus struct {
|
||||
Error error
|
||||
}
|
||||
|
||||
// NewManager creates a new network manager.
|
||||
// NewManager creates a new process manager.
|
||||
func NewManager(host environment.HostActions) Manager {
|
||||
return &limaNetworkManager{
|
||||
return &processManager{
|
||||
host: host,
|
||||
}
|
||||
}
|
||||
|
||||
func CtxKey(s string) any { return struct{ key string }{key: s} }
|
||||
|
||||
var _ Manager = (*limaNetworkManager)(nil)
|
||||
var _ Manager = (*processManager)(nil)
|
||||
|
||||
type limaNetworkManager struct {
|
||||
type processManager struct {
|
||||
host environment.HostActions
|
||||
}
|
||||
|
||||
func (l limaNetworkManager) Dependencies(ctx context.Context) (deps daemon.Dependency, root bool) {
|
||||
func (l processManager) Dependencies(ctx context.Context) (deps process.Dependency, root bool) {
|
||||
processes := processesFromCtx(ctx)
|
||||
return daemon.Dependencies(processes...)
|
||||
return process.Dependencies(processes...)
|
||||
}
|
||||
|
||||
func (l limaNetworkManager) init() error {
|
||||
func (l processManager) init() error {
|
||||
// dependencies for network
|
||||
if err := os.MkdirAll(daemon.Dir(), 0755); err != nil {
|
||||
if err := os.MkdirAll(process.Dir(), 0755); err != nil {
|
||||
return fmt.Errorf("error preparing vmnet: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l limaNetworkManager) Running(ctx context.Context) (s Status, err error) {
|
||||
func (l processManager) Running(ctx context.Context) (s Status, err error) {
|
||||
err = l.host.RunQuiet(os.Args[0], "daemon", "status", config.CurrentProfile().ShortName)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -78,7 +78,7 @@ func (l limaNetworkManager) Running(ctx context.Context) (s Status, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (l limaNetworkManager) Start(ctx context.Context) error {
|
||||
func (l processManager) Start(ctx context.Context) error {
|
||||
_ = l.Stop(ctx) // this is safe, nothing is done when not running
|
||||
|
||||
if err := l.init(); err != nil {
|
||||
@@ -93,10 +93,13 @@ func (l limaNetworkManager) Start(ctx context.Context) error {
|
||||
if opts.GVProxy {
|
||||
args = append(args, "--gvproxy")
|
||||
}
|
||||
if opts.FSNotify {
|
||||
args = append(args, "--fsnotify")
|
||||
}
|
||||
|
||||
return l.host.RunQuiet(args...)
|
||||
}
|
||||
func (l limaNetworkManager) Stop(ctx context.Context) error {
|
||||
func (l processManager) Stop(ctx context.Context) error {
|
||||
if s, err := l.Running(ctx); err != nil || !s.Running {
|
||||
return nil
|
||||
}
|
||||
@@ -104,12 +107,14 @@ func (l limaNetworkManager) Stop(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func optsFromCtx(ctx context.Context) struct {
|
||||
Vmnet bool
|
||||
GVProxy bool
|
||||
Vmnet bool
|
||||
GVProxy bool
|
||||
FSNotify bool
|
||||
} {
|
||||
var opts = struct {
|
||||
Vmnet bool
|
||||
GVProxy bool
|
||||
Vmnet bool
|
||||
GVProxy bool
|
||||
FSNotify bool
|
||||
}{}
|
||||
opts.Vmnet, _ = ctx.Value(CtxKey(vmnet.Name())).(bool)
|
||||
opts.GVProxy, _ = ctx.Value(CtxKey(gvproxy.Name())).(bool)
|
||||
@@ -117,8 +122,8 @@ func optsFromCtx(ctx context.Context) struct {
|
||||
return opts
|
||||
}
|
||||
|
||||
func processesFromCtx(ctx context.Context) []daemon.Process {
|
||||
var processes []daemon.Process
|
||||
func processesFromCtx(ctx context.Context) []process.Process {
|
||||
var processes []process.Process
|
||||
|
||||
opts := optsFromCtx(ctx)
|
||||
if opts.Vmnet {
|
||||
@@ -8,11 +8,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
)
|
||||
|
||||
var _ daemon.Dependency = qemuBinsSymlinks{}
|
||||
var _ process.Dependency = qemuBinsSymlinks{}
|
||||
|
||||
// only these two are required for Lima
|
||||
var qemuBins = []string{"qemu-system-aarch64", "qemu-system-x86_64"}
|
||||
@@ -52,7 +52,7 @@ func (q qemuBinsSymlinks) Install(host environment.HostActions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ daemon.Dependency = qemuShareDirSymlink{}
|
||||
var _ process.Dependency = qemuShareDirSymlink{}
|
||||
|
||||
type qemuShareDirSymlink struct{}
|
||||
|
||||
+9
-9
@@ -11,7 +11,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
"github.com/abiosoft/colima/util"
|
||||
"github.com/containers/gvisor-tap-vsock/pkg/transport"
|
||||
"github.com/containers/gvisor-tap-vsock/pkg/types"
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
// New creates a new Process for gvproxy.
|
||||
func New() daemon.Process {
|
||||
func New() process.Process {
|
||||
return &gvproxyProcess{}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ func Info() struct {
|
||||
Socket Socket
|
||||
MacAddress string
|
||||
}{
|
||||
Socket: Socket(filepath.Join(daemon.Dir(), socketFileName)),
|
||||
Socket: Socket(filepath.Join(process.Dir(), socketFileName)),
|
||||
MacAddress: MacAddress(),
|
||||
}
|
||||
}
|
||||
|
||||
var _ daemon.Process = (*gvproxyProcess)(nil)
|
||||
var _ process.Process = (*gvproxyProcess)(nil)
|
||||
|
||||
type gvproxyProcess struct{}
|
||||
|
||||
@@ -56,10 +56,10 @@ func (*gvproxyProcess) Alive(context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name implements daemon.BgProcess
|
||||
// Name implements daemon.Process
|
||||
func (*gvproxyProcess) Name() string { return Name() }
|
||||
|
||||
// Start implements daemon.BgProcess
|
||||
// Start implements daemon.Process
|
||||
func (*gvproxyProcess) Start(ctx context.Context) error {
|
||||
info := Info()
|
||||
return run(ctx, info.Socket)
|
||||
@@ -87,7 +87,7 @@ func MacAddress() string {
|
||||
// there is not much concern about the precision of the uniqueness.
|
||||
// this can be revisited
|
||||
if macAddress == nil {
|
||||
sum := util.SHA256Hash(daemon.Dir())
|
||||
sum := util.SHA256Hash(process.Dir())
|
||||
macAddress = append(macAddress, baseHWAddr...)
|
||||
macAddress = append(macAddress, sum[0:3]...)
|
||||
}
|
||||
@@ -207,8 +207,8 @@ func searchDomains() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gvproxyProcess) Dependencies() (deps []daemon.Dependency, root bool) {
|
||||
return []daemon.Dependency{
|
||||
func (gvproxyProcess) Dependencies() (deps []process.Dependency, root bool) {
|
||||
return []process.Dependency{
|
||||
qemuBinsSymlinks{},
|
||||
qemuShareDirSymlink{},
|
||||
}, false
|
||||
@@ -1,15 +1,13 @@
|
||||
package daemon
|
||||
package process
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/abiosoft/colima/config"
|
||||
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Process is a background process managed by the daemon.
|
||||
@@ -27,8 +25,8 @@ type Process interface {
|
||||
Dependencies() (deps []Dependency, root bool)
|
||||
}
|
||||
|
||||
// Dir is the directory for network related files.
|
||||
func Dir() string { return filepath.Join(config.Dir(), "network") }
|
||||
// Dir is the directory for daemon files.
|
||||
func Dir() string { return filepath.Join(config.Dir(), "daemon") }
|
||||
|
||||
// Dependency is a requirement to be fulfilled before a process can be started.
|
||||
type Dependency interface {
|
||||
@@ -83,32 +81,3 @@ func (p processDeps) Install(host environment.HostActions) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs the daemon with background processes.
|
||||
// NOTE: this must be called from the program entrypoint with minimal intermediary logic
|
||||
// due to the creation of the daemon.
|
||||
func Run(ctx context.Context, processes ...Process) error {
|
||||
ctx, stop := context.WithCancel(ctx)
|
||||
defer stop()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(processes))
|
||||
|
||||
for _, bg := range processes {
|
||||
go func(bg Process) {
|
||||
err := bg.Start(ctx)
|
||||
if err != nil {
|
||||
logrus.Error(fmt.Errorf("error starting %s: %w", bg.Name(), err))
|
||||
stop()
|
||||
}
|
||||
wg.Done()
|
||||
}(bg)
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
logrus.Info("terminate signal received")
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return ctx.Err()
|
||||
}
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
"github.com/abiosoft/colima/embedded"
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
)
|
||||
|
||||
var _ daemon.Dependency = sudoerFile{}
|
||||
var _ process.Dependency = sudoerFile{}
|
||||
|
||||
type sudoerFile struct{}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (s sudoerFile) Install(host environment.HostActions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ daemon.Dependency = vmnetFile{}
|
||||
var _ process.Dependency = vmnetFile{}
|
||||
|
||||
const BinaryPath = "/opt/colima/bin/vde_vmnet"
|
||||
const LibraryPath = "/opt/colima/lib/libvdeplug.3.dylib"
|
||||
@@ -113,7 +113,7 @@ func (v vmnetFile) Install(host environment.HostActions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ daemon.Dependency = vmnetRunDir{}
|
||||
var _ process.Dependency = vmnetRunDir{}
|
||||
|
||||
type vmnetRunDir struct{}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/abiosoft/colima/cli"
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon"
|
||||
"github.com/abiosoft/colima/daemon/process"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,10 +18,10 @@ const (
|
||||
NetInterface = "col0"
|
||||
)
|
||||
|
||||
var _ daemon.Process = (*vmnetProcess)(nil)
|
||||
var _ process.Process = (*vmnetProcess)(nil)
|
||||
|
||||
func New() daemon.Process { return &vmnetProcess{} }
|
||||
func Name() string { return "vmnet" }
|
||||
func New() process.Process { return &vmnetProcess{} }
|
||||
func Name() string { return "vmnet" }
|
||||
|
||||
type vmnetProcess struct{}
|
||||
|
||||
@@ -44,10 +44,10 @@ func (*vmnetProcess) Alive(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name implements daemon.BgProcess
|
||||
// Name implements process.BgProcess
|
||||
func (*vmnetProcess) Name() string { return Name() }
|
||||
|
||||
// Start implements daemon.BgProcess
|
||||
// Start implements process.BgProcess
|
||||
func (*vmnetProcess) Start(ctx context.Context) error {
|
||||
info := Info()
|
||||
ptp := info.PTPFile
|
||||
@@ -88,8 +88,8 @@ func (*vmnetProcess) Start(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vmnetProcess) Dependencies() (deps []daemon.Dependency, root bool) {
|
||||
return []daemon.Dependency{
|
||||
func (vmnetProcess) Dependencies() (deps []process.Dependency, root bool) {
|
||||
return []process.Dependency{
|
||||
sudoerFile{},
|
||||
vmnetFile{},
|
||||
vmnetRunDir{},
|
||||
@@ -124,6 +124,6 @@ func Info() struct {
|
||||
PTPFile string
|
||||
}{
|
||||
PidFile: filepath.Join(runDir(), "vmnet-"+config.CurrentProfile().ShortName+".pid"),
|
||||
PTPFile: filepath.Join(daemon.Dir(), "vmnet.ptp"),
|
||||
PTPFile: filepath.Join(process.Dir(), "vmnet.ptp"),
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/abiosoft/colima/environment/container/containerd"
|
||||
"github.com/abiosoft/colima/environment/container/docker"
|
||||
"github.com/abiosoft/colima/environment/vm/lima"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
"github.com/abiosoft/colima/util/downloader"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -128,7 +128,7 @@ func installK3sCluster(
|
||||
}
|
||||
|
||||
// replace ip address if networking is enabled
|
||||
ipAddress := lima.IPAddress(config.CurrentProfile().ID)
|
||||
ipAddress := limautil.IPAddress(config.CurrentProfile().ID)
|
||||
if ipAddress == "127.0.0.1" {
|
||||
args = append(args, "--flannel-iface", "eth0")
|
||||
} else {
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
"github.com/abiosoft/colima/cli"
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/environment/vm/lima"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
)
|
||||
|
||||
const masterAddressKey = "master_address"
|
||||
|
||||
func (c kubernetesRuntime) provisionKubeconfig(ctx context.Context) error {
|
||||
ip := lima.IPAddress(config.CurrentProfile().ID)
|
||||
ip := limautil.IPAddress(config.CurrentProfile().ID)
|
||||
if ip == c.guest.Get(masterAddressKey) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/util"
|
||||
)
|
||||
|
||||
type buildArgs struct {
|
||||
@@ -158,12 +157,7 @@ func (u ubuntuRuntime) createContainer(conf config.Config) error {
|
||||
"--volume", "/:/host",
|
||||
)
|
||||
|
||||
mounts := conf.Mounts
|
||||
if len(mounts) == 0 {
|
||||
// TODO: should be not be repeated here but rather populated externally
|
||||
mounts = append(mounts, config.Mount{Location: util.HomeDir()})
|
||||
mounts = append(mounts, config.Mount{Location: filepath.Join("/tmp", config.CurrentProfile().ID)})
|
||||
}
|
||||
mounts := conf.MountsOrDefault()
|
||||
for _, m := range mounts {
|
||||
args = append(args, "--volume", m.Location+":"+m.Location)
|
||||
}
|
||||
|
||||
+23
-23
@@ -11,13 +11,14 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/gvproxy"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/vmnet"
|
||||
"github.com/abiosoft/colima/daemon"
|
||||
"github.com/abiosoft/colima/daemon/process/gvproxy"
|
||||
"github.com/abiosoft/colima/daemon/process/vmnet"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
|
||||
"github.com/abiosoft/colima/cli"
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network"
|
||||
"github.com/abiosoft/colima/util"
|
||||
"github.com/abiosoft/colima/util/yamlutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -46,7 +47,7 @@ func New(host environment.HostActions) environment.VM {
|
||||
host: host.WithEnv(envs...),
|
||||
home: home,
|
||||
CommandChain: cli.New("vm"),
|
||||
network: network.NewManager(host),
|
||||
daemon: daemon.NewManager(host),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +55,6 @@ const (
|
||||
limaInstanceEnvVar = "LIMA_INSTANCE"
|
||||
lima = "lima"
|
||||
limactl = "limactl"
|
||||
layerEnvVar = "COLIMA_LAYER_SSH_PORT"
|
||||
)
|
||||
|
||||
func limaHome() (string, error) {
|
||||
@@ -96,7 +96,7 @@ type limaVM struct {
|
||||
home string
|
||||
|
||||
// network between host and the vm
|
||||
network network.Manager
|
||||
daemon daemon.Manager
|
||||
}
|
||||
|
||||
func (l limaVM) Dependencies() []string {
|
||||
@@ -105,14 +105,14 @@ func (l limaVM) Dependencies() []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *limaVM) prepareNetwork(ctx context.Context, conf config.Network) (context.Context, error) {
|
||||
func (l *limaVM) startDaemon(ctx context.Context, conf config.Config) (context.Context, error) {
|
||||
// limited to macOS for now
|
||||
if !util.MacOS() {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
ctxKeyVmnet := network.CtxKey(vmnet.Name())
|
||||
ctxKeyGVProxy := network.CtxKey(gvproxy.Name())
|
||||
ctxKeyVmnet := daemon.CtxKey(vmnet.Name())
|
||||
ctxKeyGVProxy := daemon.CtxKey(gvproxy.Name())
|
||||
|
||||
// use a nested chain for convenience
|
||||
a := l.Init(ctx)
|
||||
@@ -121,10 +121,10 @@ func (l *limaVM) prepareNetwork(ctx context.Context, conf config.Network) (conte
|
||||
a.Stage("preparing network")
|
||||
a.Add(func() error {
|
||||
ctx = context.WithValue(ctx, ctxKeyGVProxy, true)
|
||||
if conf.Address {
|
||||
if conf.Network.Address {
|
||||
ctx = context.WithValue(ctx, ctxKeyVmnet, true)
|
||||
}
|
||||
deps, root := l.network.Dependencies(ctx)
|
||||
deps, root := l.daemon.Dependencies(ctx)
|
||||
if deps.Installed() {
|
||||
return nil
|
||||
}
|
||||
@@ -139,14 +139,14 @@ func (l *limaVM) prepareNetwork(ctx context.Context, conf config.Network) (conte
|
||||
})
|
||||
|
||||
a.Add(func() error {
|
||||
return l.network.Start(ctx)
|
||||
return l.daemon.Start(ctx)
|
||||
})
|
||||
|
||||
// delay to ensure that the vmnet is running
|
||||
statusKey := "networkStatus"
|
||||
if conf.Address {
|
||||
statusKey := struct{ key string }{key: "networkStatus"}
|
||||
if conf.Network.Address {
|
||||
a.Retry("", time.Second*3, 5, func(i int) error {
|
||||
s, err := l.network.Running(ctx)
|
||||
s, err := l.daemon.Running(ctx)
|
||||
ctx = context.WithValue(ctx, statusKey, s)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -166,7 +166,7 @@ func (l *limaVM) prepareNetwork(ctx context.Context, conf config.Network) (conte
|
||||
// network failure is not fatal
|
||||
if err := a.Exec(); err != nil {
|
||||
func() {
|
||||
status, ok := ctx.Value(statusKey).(network.Status)
|
||||
status, ok := ctx.Value(statusKey).(daemon.Status)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -177,7 +177,7 @@ func (l *limaVM) prepareNetwork(ctx context.Context, conf config.Network) (conte
|
||||
|
||||
for _, p := range status.Processes {
|
||||
if !p.Running {
|
||||
ctx = context.WithValue(ctx, network.CtxKey(p.Name), false)
|
||||
ctx = context.WithValue(ctx, daemon.CtxKey(p.Name), false)
|
||||
log.Warnln(fmt.Errorf("error starting %s: %w", p.Name, err))
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func (l *limaVM) prepareNetwork(ctx context.Context, conf config.Network) (conte
|
||||
}
|
||||
|
||||
// preserve gvproxy context
|
||||
if gvproxyEnabled, _ := ctx.Value(network.CtxKey(gvproxy.Name())).(bool); gvproxyEnabled {
|
||||
if gvproxyEnabled, _ := ctx.Value(daemon.CtxKey(gvproxy.Name())).(bool); gvproxyEnabled {
|
||||
l.host = l.host.WithEnv(gvproxy.SubProcessEnvVar + "=1")
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ func (l *limaVM) Start(ctx context.Context, conf config.Config) error {
|
||||
}
|
||||
|
||||
a.Add(func() (err error) {
|
||||
ctx, err = l.prepareNetwork(ctx, conf.Network)
|
||||
ctx, err = l.startDaemon(ctx, conf)
|
||||
return err
|
||||
})
|
||||
|
||||
@@ -255,7 +255,7 @@ func (l limaVM) resume(ctx context.Context, conf config.Config) error {
|
||||
}
|
||||
|
||||
a.Add(func() (err error) {
|
||||
ctx, err = l.prepareNetwork(ctx, conf.Network)
|
||||
ctx, err = l.startDaemon(ctx, conf)
|
||||
return err
|
||||
})
|
||||
|
||||
@@ -281,7 +281,7 @@ func (l limaVM) resume(ctx context.Context, conf config.Config) error {
|
||||
}
|
||||
|
||||
func (l limaVM) Running(ctx context.Context) bool {
|
||||
i, err := Instance()
|
||||
i, err := limautil.Instance()
|
||||
if err != nil {
|
||||
logrus.Trace(fmt.Errorf("error retrieving running instance: %w", err))
|
||||
return false
|
||||
@@ -301,7 +301,7 @@ func (l limaVM) Stop(ctx context.Context, force bool) error {
|
||||
|
||||
if util.MacOS() {
|
||||
a.Retry("", time.Second*1, 10, func(retryCount int) error {
|
||||
return l.network.Stop(ctx)
|
||||
return l.daemon.Stop(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ func (l limaVM) Teardown(ctx context.Context) error {
|
||||
|
||||
if util.MacOS() {
|
||||
a.Retry("", time.Second*1, 10, func(retryCount int) error {
|
||||
return l.network.Stop(ctx)
|
||||
return l.daemon.Stop(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package lima
|
||||
package limautil
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -16,6 +16,44 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
LayerEnvVar = "COLIMA_LAYER_SSH_PORT"
|
||||
)
|
||||
|
||||
// Instance returns current instance.
|
||||
func Instance() (InstanceInfo, error) {
|
||||
return getInstance(config.CurrentProfile().ID)
|
||||
}
|
||||
|
||||
// InstanceConfig returns the current instance config.
|
||||
func InstanceConfig() (config.Config, error) {
|
||||
i, err := Instance()
|
||||
if err != nil {
|
||||
return config.Config{}, err
|
||||
}
|
||||
return i.Config()
|
||||
}
|
||||
|
||||
// IPAddress returns the ip address for profile.
|
||||
// It returns the PTP address if networking is enabled or falls back to 127.0.0.1.
|
||||
// It is guaranteed to return a value.
|
||||
// TODO: unnecessary round-trip is done to get instance details from Lima.
|
||||
func IPAddress(profileID string) string {
|
||||
// profile = toUserFriendlyName(profile)
|
||||
|
||||
const fallback = "127.0.0.1"
|
||||
instance, err := getInstance(profileID)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
|
||||
if len(instance.Network) > 0 {
|
||||
return getIPAddress(profileID, instance.Network[0].Interface)
|
||||
}
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
// InstanceInfo is the information about a Lima instance
|
||||
type InstanceInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
@@ -61,154 +99,6 @@ func (i InstanceInfo) Config() (config.Config, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Lima statuses
|
||||
const (
|
||||
limaStatusRunning = "Running"
|
||||
)
|
||||
|
||||
// Instance returns current instance.
|
||||
func Instance() (InstanceInfo, error) {
|
||||
return getInstance(config.CurrentProfile().ID)
|
||||
}
|
||||
|
||||
// InstanceConfig returns the current instance config.
|
||||
func InstanceConfig() (config.Config, error) {
|
||||
i, err := Instance()
|
||||
if err != nil {
|
||||
return config.Config{}, err
|
||||
}
|
||||
return i.Config()
|
||||
}
|
||||
|
||||
func getInstance(profileID string) (InstanceInfo, error) {
|
||||
var i InstanceInfo
|
||||
var buf bytes.Buffer
|
||||
cmd := cli.Command("limactl", "list", profileID, "--json")
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = &buf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return i, fmt.Errorf("error retrieving instance: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(buf.Bytes(), &i); err != nil {
|
||||
return i, fmt.Errorf("error retrieving instance: %w", err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Instances returns Lima instances created by colima.
|
||||
func Instances() ([]InstanceInfo, error) {
|
||||
var buf bytes.Buffer
|
||||
cmd := cli.Command("limactl", "list", "--json")
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = &buf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("error retrieving instances: %w", err)
|
||||
}
|
||||
|
||||
var instances []InstanceInfo
|
||||
scanner := bufio.NewScanner(&buf)
|
||||
for scanner.Scan() {
|
||||
var i InstanceInfo
|
||||
line := scanner.Bytes()
|
||||
if err := json.Unmarshal(line, &i); err != nil {
|
||||
return nil, fmt.Errorf("error retrieving instances: %w", err)
|
||||
}
|
||||
|
||||
// limit to colima instances
|
||||
if !strings.HasPrefix(i.Name, "colima") {
|
||||
continue
|
||||
}
|
||||
|
||||
if i.Running() {
|
||||
if len(i.Network) > 0 && i.Network[0].Interface != "" {
|
||||
i.IPAddress = getIPAddress(i.Name, i.Network[0].Interface)
|
||||
}
|
||||
conf, _ := i.Config()
|
||||
i.Runtime = getRuntime(conf)
|
||||
}
|
||||
|
||||
// rename to local friendly names
|
||||
i.Name = config.Profile(i.Name).ShortName
|
||||
|
||||
// network is low level, remove
|
||||
i.Network = nil
|
||||
|
||||
instances = append(instances, i)
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
func getIPAddress(profileID, interfaceName string) string {
|
||||
var buf bytes.Buffer
|
||||
// TODO: this should be less hacky
|
||||
cmd := cli.Command("limactl", "shell", profileID, "sh", "-c",
|
||||
`ifconfig `+interfaceName+` | grep "inet addr:" | awk -F' ' '{print $2}' | awk -F':' '{print $2}'`)
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = &buf
|
||||
|
||||
_ = cmd.Run()
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func ubuntuSSHPort(profileID string) (int, error) {
|
||||
var buf bytes.Buffer
|
||||
cmd := cli.Command("limactl", "shell", profileID, "--", "sh", "-c", "echo $"+layerEnvVar)
|
||||
cmd.Stdout = &buf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return 0, fmt.Errorf("cannot retrieve ubuntu layer SSH port: %w", err)
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(strings.TrimSpace(buf.String()))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid ubuntu layer SSH port '%d': %w", port, err)
|
||||
}
|
||||
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func getRuntime(conf config.Config) string {
|
||||
var runtime string
|
||||
|
||||
switch conf.Runtime {
|
||||
case "docker":
|
||||
runtime = "docker"
|
||||
case "containerd":
|
||||
runtime = "containerd"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
if conf.Kubernetes.Enabled {
|
||||
runtime += "+k3s"
|
||||
}
|
||||
return runtime
|
||||
}
|
||||
|
||||
// IPAddress returns the ip address for profile.
|
||||
// It returns the PTP address if networking is enabled or falls back to 127.0.0.1.
|
||||
// It is guaranteed to return a value.
|
||||
// TODO: unnecessary round-trip is done to get instance details from Lima.
|
||||
func IPAddress(profileID string) string {
|
||||
// profile = toUserFriendlyName(profile)
|
||||
|
||||
const fallback = "127.0.0.1"
|
||||
instance, err := getInstance(profileID)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
|
||||
if len(instance.Network) > 0 {
|
||||
return getIPAddress(profileID, instance.Network[0].Interface)
|
||||
}
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
// ShowSSH runs the show-ssh command in Lima.
|
||||
// returns the ssh output, if in layer, and an error if any
|
||||
func ShowSSH(profileID string, layer bool, format string) (resp struct {
|
||||
@@ -314,3 +204,114 @@ func replaceSSHConfig(conf string, name string, ip string, port int) string {
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// Lima statuses
|
||||
const (
|
||||
limaStatusRunning = "Running"
|
||||
)
|
||||
|
||||
func getInstance(profileID string) (InstanceInfo, error) {
|
||||
var i InstanceInfo
|
||||
var buf bytes.Buffer
|
||||
cmd := cli.Command("limactl", "list", profileID, "--json")
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = &buf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return i, fmt.Errorf("error retrieving instance: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(buf.Bytes(), &i); err != nil {
|
||||
return i, fmt.Errorf("error retrieving instance: %w", err)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Instances returns Lima instances created by colima.
|
||||
func Instances() ([]InstanceInfo, error) {
|
||||
var buf bytes.Buffer
|
||||
cmd := cli.Command("limactl", "list", "--json")
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = &buf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("error retrieving instances: %w", err)
|
||||
}
|
||||
|
||||
var instances []InstanceInfo
|
||||
scanner := bufio.NewScanner(&buf)
|
||||
for scanner.Scan() {
|
||||
var i InstanceInfo
|
||||
line := scanner.Bytes()
|
||||
if err := json.Unmarshal(line, &i); err != nil {
|
||||
return nil, fmt.Errorf("error retrieving instances: %w", err)
|
||||
}
|
||||
|
||||
// limit to colima instances
|
||||
if !strings.HasPrefix(i.Name, "colima") {
|
||||
continue
|
||||
}
|
||||
|
||||
if i.Running() {
|
||||
if len(i.Network) > 0 && i.Network[0].Interface != "" {
|
||||
i.IPAddress = getIPAddress(i.Name, i.Network[0].Interface)
|
||||
}
|
||||
conf, _ := i.Config()
|
||||
i.Runtime = getRuntime(conf)
|
||||
}
|
||||
|
||||
// rename to local friendly names
|
||||
i.Name = config.Profile(i.Name).ShortName
|
||||
|
||||
// network is low level, remove
|
||||
i.Network = nil
|
||||
|
||||
instances = append(instances, i)
|
||||
}
|
||||
|
||||
return instances, nil
|
||||
}
|
||||
func getIPAddress(profileID, interfaceName string) string {
|
||||
var buf bytes.Buffer
|
||||
// TODO: this should be less hacky
|
||||
cmd := cli.Command("limactl", "shell", profileID, "sh", "-c",
|
||||
`ifconfig `+interfaceName+` | grep "inet addr:" | awk -F' ' '{print $2}' | awk -F':' '{print $2}'`)
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = &buf
|
||||
|
||||
_ = cmd.Run()
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func ubuntuSSHPort(profileID string) (int, error) {
|
||||
var buf bytes.Buffer
|
||||
cmd := cli.Command("limactl", "shell", profileID, "--", "sh", "-c", "echo $"+LayerEnvVar)
|
||||
cmd.Stdout = &buf
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return 0, fmt.Errorf("cannot retrieve ubuntu layer SSH port: %w", err)
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(strings.TrimSpace(buf.String()))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid ubuntu layer SSH port '%d': %w", port, err)
|
||||
}
|
||||
|
||||
return port, nil
|
||||
}
|
||||
|
||||
func getRuntime(conf config.Config) string {
|
||||
var runtime string
|
||||
|
||||
switch conf.Runtime {
|
||||
case "docker", "containerd":
|
||||
runtime = conf.Runtime
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
if conf.Kubernetes.Enabled {
|
||||
runtime += "+k3s"
|
||||
}
|
||||
return runtime
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
var addresses = []string{
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
}
|
||||
|
||||
var processes []Process
|
||||
for _, add := range addresses {
|
||||
processes = append(processes, &pinger{address: add})
|
||||
}
|
||||
|
||||
timeout := time.Second * 30
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
|
||||
// start the processes
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- Run(ctx, processes...)
|
||||
}()
|
||||
|
||||
cancel()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if err := ctx.Err(); err != context.Canceled {
|
||||
t.Error(err)
|
||||
}
|
||||
case err := <-done:
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _ Process = (*pinger)(nil)
|
||||
|
||||
type pinger struct {
|
||||
address string
|
||||
}
|
||||
|
||||
func (p pinger) Alive(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name implements BgProcess
|
||||
func (pinger) Name() string { return "pinger" }
|
||||
|
||||
// Start implements BgProcess
|
||||
func (p *pinger) Start(ctx context.Context) error {
|
||||
return p.run(ctx, "ping", "-c10", p.address)
|
||||
}
|
||||
|
||||
// Start implements BgProcess
|
||||
func (p *pinger) Dependencies() ([]Dependency, bool) { return nil, false }
|
||||
|
||||
func (p *pinger) run(ctx context.Context, command string, args ...string) error {
|
||||
cmd := exec.CommandContext(ctx, command, args...)
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
@@ -10,15 +10,16 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/gvproxy"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/network/daemon/vmnet"
|
||||
"github.com/abiosoft/colima/daemon"
|
||||
"github.com/abiosoft/colima/daemon/process/gvproxy"
|
||||
"github.com/abiosoft/colima/daemon/process/vmnet"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/abiosoft/colima/config"
|
||||
"github.com/abiosoft/colima/embedded"
|
||||
"github.com/abiosoft/colima/environment"
|
||||
"github.com/abiosoft/colima/environment/container/docker"
|
||||
"github.com/abiosoft/colima/environment/vm/lima/limautil"
|
||||
"github.com/abiosoft/colima/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -60,11 +61,11 @@ func newConf(ctx context.Context, conf config.Config) (l Config, err error) {
|
||||
|
||||
l.DNS = conf.Network.DNS
|
||||
if len(l.DNS) == 0 {
|
||||
gvProxyEnabled, _ := ctx.Value(network.CtxKey(gvproxy.Name())).(bool)
|
||||
gvProxyEnabled, _ := ctx.Value(daemon.CtxKey(gvproxy.Name())).(bool)
|
||||
if gvProxyEnabled {
|
||||
l.DNS = append(l.DNS, net.ParseIP(gvproxy.GatewayIP))
|
||||
}
|
||||
reachableIPAddress, _ := ctx.Value(network.CtxKey(vmnet.Name())).(bool)
|
||||
reachableIPAddress, _ := ctx.Value(daemon.CtxKey(vmnet.Name())).(bool)
|
||||
if reachableIPAddress {
|
||||
l.DNS = append(l.DNS, net.ParseIP(vmnet.NetGateway))
|
||||
}
|
||||
@@ -84,7 +85,7 @@ func newConf(ctx context.Context, conf config.Config) (l Config, err error) {
|
||||
|
||||
// network setup
|
||||
{
|
||||
reachableIPAddress, _ := ctx.Value(network.CtxKey(vmnet.Name())).(bool)
|
||||
reachableIPAddress, _ := ctx.Value(daemon.CtxKey(vmnet.Name())).(bool)
|
||||
|
||||
// network is currently limited to macOS.
|
||||
// gvproxy is cross platform but not needed on Linux as slirp is only erratic on macOS.
|
||||
@@ -128,7 +129,7 @@ func newConf(ctx context.Context, conf config.Config) (l Config, err error) {
|
||||
values.Vmnet.Interface = vmnet.NetInterface
|
||||
}
|
||||
|
||||
gvProxyEnabled, _ := ctx.Value(network.CtxKey(gvproxy.Name())).(bool)
|
||||
gvProxyEnabled, _ := ctx.Value(daemon.CtxKey(gvproxy.Name())).(bool)
|
||||
if gvProxyEnabled {
|
||||
values.GVProxy.Enabled = true
|
||||
values.GVProxy.MacAddress = strings.ToUpper(gvproxy.MacAddress())
|
||||
@@ -185,7 +186,7 @@ func newConf(ctx context.Context, conf config.Config) (l Config, err error) {
|
||||
if conf.Layer {
|
||||
port := util.RandomAvailablePort()
|
||||
// set port for future retrieval
|
||||
l.Env[layerEnvVar] = strconv.Itoa(port)
|
||||
l.Env[limautil.LayerEnvVar] = strconv.Itoa(port)
|
||||
// forward port
|
||||
l.PortForwards = append(l.PortForwards,
|
||||
PortForward{
|
||||
|
||||
@@ -35,9 +35,10 @@ require (
|
||||
require (
|
||||
github.com/containers/gvisor-tap-vsock v0.3.0
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/fsnotify/fsnotify v1.5.4
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
|
||||
)
|
||||
|
||||
@@ -219,6 +219,8 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -890,8 +892,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
||||
+4
-2
@@ -16,10 +16,12 @@ go build \
|
||||
-o "$OUTPUT_DIR/$OUTPUT_BIN" \
|
||||
./cmd/colima
|
||||
|
||||
# sha256sum is not on macOS by default, use shasum
|
||||
# sha256sum is not on macOS by default, use shasum if missing
|
||||
SHA256SUM=sha256sum
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
SHA256SUM="shasum -a 256"
|
||||
if ! command -v "${SHA256SUM}" &>/dev/null; then
|
||||
SHA256SUM="shasum -a 256"
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "${OUTPUT_DIR}" && ${SHA256SUM} "${OUTPUT_BIN}" >"${OUTPUT_BIN}.sha256sum"
|
||||
|
||||
Reference in New Issue
Block a user