Skip to content

Commit

Permalink
add ptp based network (#227)
Browse files Browse the repository at this point in the history
* build: add vmnet script

* chore: minor refactors and fixes

* net: begin ptp network

* net: embed vmnet

* chore: remove obsolete dry-run command

* net: vmnet support checkpoint

* net: vmnet works

* net: add ip address to colima list

* net: make network instance dynamic

* net: fix embedded archives

* net: ptp network works

* net: route fixed, general refactor

* misc: minor refactor

* cli: enable force stop

* cli: add json to colima list

* k8s: bind to VM ip address

* fix lint
  • Loading branch information
abiosoft authored Mar 19, 2022
1 parent 5a4a704 commit f944599
Show file tree
Hide file tree
Showing 30 changed files with 856 additions and 143 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea/
.vscode/
_output/
_build/
bin/
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GOARCH ?= $(shell echo "$(GOARCH_$(ARCH))")
all: build

clean:
rm -rf _output
rm -rf _output _build

gopath:
go get -v ./cmd/colima
Expand All @@ -22,6 +22,9 @@ fmt:
build:
GOOS=$(GOOS) GOARCH=$(GOARCH) OS=$(OS) ARCH=$(ARCH) sh scripts/build.sh

vmnet:
sh scripts/build_vmnet.sh

install:
cp _output/binaries/colima-$(OS)-$(ARCH) /usr/local/bin/colima
chmod +x /usr/local/bin/colima
Expand Down
10 changes: 5 additions & 5 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
type App interface {
Active() bool
Start(config.Config) error
Stop() error
Stop(force bool) error
Delete() error
SSH(...string) error
Status() error
Expand Down Expand Up @@ -93,14 +93,14 @@ func (c colimaApp) Start(conf config.Config) error {
return nil
}

func (c colimaApp) Stop() error {
func (c colimaApp) Stop(force bool) error {
log.Println("stopping", config.Profile().DisplayName)

// the order for stop is:
// container stop -> vm stop

// stop container runtimes
if c.guest.Running() {
// stop container runtimes if not a forceful shutdown
if c.guest.Running() && !force {
containers, err := c.currentContainerEnvironments()
if err != nil {
log.Warnln(fmt.Errorf("error retrieving runtimes: %w", err))
Expand All @@ -120,7 +120,7 @@ func (c colimaApp) Stop() error {

// stop vm
// no need to check running status, it may be in a state that requires stopping.
if err := c.guest.Stop(); err != nil {
if err := c.guest.Stop(force); err != nil {
return fmt.Errorf("error stopping vm: %w", err)
}

Expand Down
4 changes: 3 additions & 1 deletion cli/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ func (a *ActiveCommandChain) Retry(stage string, interval time.Duration, count i
a.Add(func() (err error) {
var i int
for err = f(); i < count && err != nil; i, err = i+1, f() {
if stage != "" {
a.log.Println(stage, "...")
}
time.Sleep(interval)
a.log.Println(stage, "...")
}
return err
})
Expand Down
34 changes: 0 additions & 34 deletions cli/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"
)

var runner commandRunner = &defaultCommandRunner{}
Expand All @@ -16,16 +14,6 @@ var Settings = struct {
Verbose bool
}{}

// DryRun toggles the state of the command runner. If true, commands are only printed to the console
// without execution.
func DryRun(d bool) {
if d {
runner = dryRunCommandRunner{}
return
}
runner = &defaultCommandRunner{}
}

// Command creates a new command.
func Command(command string, args ...string) *exec.Cmd { return runner.Command(command, args...) }

Expand Down Expand Up @@ -58,28 +46,6 @@ func (d defaultCommandRunner) CommandInteractive(command string, args ...string)
return cmd
}

var _ commandRunner = (*dryRunCommandRunner)(nil)

type dryRunCommandRunner struct{}

func (d dryRunCommandRunner) Command(command string, args ...string) *exec.Cmd {
d.printArgs("run:", command, args...)
return exec.Command("echo")
}

func (d dryRunCommandRunner) CommandInteractive(command string, args ...string) *exec.Cmd {
d.printArgs("interactive run:", command, args...)
return exec.Command("echo")
}
func (d dryRunCommandRunner) printArgs(prefix, command string, args ...string) {
var str []string
str = append(str, prefix, strconv.Quote(command))
for _, arg := range args {
str = append(str, strconv.Quote(arg))
}
fmt.Println(strings.Join(str, " "))
}

// Prompt prompts for input with a question. It returns true only if answer is y or Y.
func Prompt(question string) bool {
fmt.Print(question)
Expand Down
16 changes: 14 additions & 2 deletions cmd/colima/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
package main

import (
_ "github.com/abiosoft/colima/cmd" // for other commands
"os"
"path/filepath"

_ "github.com/abiosoft/colima/cmd" // for other commands
_ "github.com/abiosoft/colima/embedded" // for embedded assets

"github.com/abiosoft/colima/cmd/root"
"github.com/abiosoft/colima/cmd/vmnet"
)

func main() {
root.Execute()
_, cmd := filepath.Split(os.Args[0])
switch cmd {
case "colima-vmnet":
vmnet.Execute()
default:
root.Execute()
}
}
23 changes: 21 additions & 2 deletions cmd/list.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"encoding/json"
"fmt"
"text/tabwriter"

Expand All @@ -11,6 +12,10 @@ import (
"github.com/spf13/cobra"
)

var listCmdArgs struct {
json bool
}

// listCmd represents the version command
var listCmd = &cobra.Command{
Use: "list",
Expand All @@ -26,21 +31,33 @@ A new instance can be created during 'colima start' by specifying the '--profile
return err
}

if listCmdArgs.json {
encoder := json.NewEncoder(cmd.OutOrStdout())
// print instance per line to conform with Lima's output
for _, instance := range instances {
if err := encoder.Encode(instance); err != nil {
return err
}
}
return nil
}

w := tabwriter.NewWriter(cmd.OutOrStdout(), 4, 8, 4, ' ', 0)
fmt.Fprintln(w, "PROFILE\tSTATUS\tARCH\tCPUS\tMEMORY\tDISK")
fmt.Fprintln(w, "PROFILE\tSTATUS\tARCH\tCPUS\tMEMORY\tDISK\tADDRESS")

if len(instances) == 0 {
logrus.Warn("No instance found. Run `colima start` to create an instance.")
}

for _, inst := range instances {
fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%s\n",
fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%s\t%s\t%s\n",
inst.Name,
inst.Status,
inst.Arch,
inst.CPU,
units.BytesSize(float64(inst.Memory)),
units.BytesSize(float64(inst.Disk)),
inst.IPAddress,
)
}

Expand All @@ -50,4 +67,6 @@ A new instance can be created during 'colima start' by specifying the '--profile

func init() {
root.Cmd().AddCommand(listCmd)

listCmd.Flags().BoolVarP(&listCmdArgs.json, "json", "j", false, "print json output")
}
2 changes: 1 addition & 1 deletion cmd/nerdctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ var nerdctlLinkFunc = func() *cobra.Command {
Use: "install",
Short: "install nerdctl alias script on the host",
Long: `Install nerdctl alias script on the host. The script will be installed at ` + nerdctlDefaultInstallPath + `.`,
Args: cobra.NoArgs,
Args: cobra.NoArgs,
PreRun: func(cmd *cobra.Command, args []string) {
// check if /usr/local/bin is writeable and no need for sudo

Expand Down
10 changes: 0 additions & 10 deletions cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ func Cmd() *cobra.Command {

// rootCmdArgs holds all flags configured in root Cmd
var rootCmdArgs struct {
DryRun bool
Profile string
Verbose bool
}
Expand All @@ -60,24 +59,15 @@ func Execute() {
}

func init() {
rootCmd.PersistentFlags().BoolVar(&rootCmdArgs.DryRun, "dry-run", rootCmdArgs.DryRun, "perform a dry run instead")
rootCmd.PersistentFlags().BoolVar(&rootCmdArgs.Verbose, "verbose", rootCmdArgs.Verbose, "enable verbose log")
rootCmd.PersistentFlags().StringVarP(&rootCmdArgs.Profile, "profile", "p", "default", "profile name, for multiple instances")

// decide if these should be public
// implementations are currently half-baked, only for test during development
_ = rootCmd.PersistentFlags().MarkHidden("dry-run")

}

func initLog() error {
// general log output
log.SetOutput(logrus.New().Writer())
log.SetFlags(0)

if rootCmdArgs.DryRun {
cli.DryRun(rootCmdArgs.DryRun)
}
if rootCmdArgs.Verbose {
cli.Settings.Verbose = rootCmdArgs.Verbose
}
Expand Down
8 changes: 7 additions & 1 deletion cmd/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
"github.com/spf13/cobra"
)

var stopCmdArgs struct {
force bool
}

// stopCmd represents the stop command
var stopCmd = &cobra.Command{
Use: "stop [profile]",
Expand All @@ -15,10 +19,12 @@ The state of the VM is persisted at stop. A start afterwards
should return it back to its previous state.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return newApp().Stop()
return newApp().Stop(stopCmdArgs.force)
},
}

func init() {
root.Cmd().AddCommand(stopCmd)

stopCmd.Flags().BoolVarP(&stopCmdArgs.force, "force", "f", false, "stop without graceful shutdown")
}
74 changes: 74 additions & 0 deletions cmd/vmnet/vmnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package vmnet

import (
"os"
"strings"

"github.com/abiosoft/colima/cli"
"github.com/abiosoft/colima/config"
"github.com/abiosoft/colima/environment/vm/lima/network"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := vmnetCmd.Execute(); err != nil {
logrus.Fatal(err)
}
}

// vmnetCmd represents the base command when called without any subcommands
var vmnetCmd = &cobra.Command{
Use: "vmnet",
Short: "vde_vmnet runner",
Long: `vde_vmnet runner for vde_vmnet daemons.`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cmd.SilenceUsage = true
cmd.SilenceErrors = true
},
}

// startCmd represents the kubernetes start command
var startCmd = &cobra.Command{
Use: "start",
Short: "start daemon",
Long: `start the daemon`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
config.SetProfile(args[0])

ptp, err := network.PTPFile()
if err != nil {
logrus.Warnln("ptp file error: %w", err) // this should never happen
}
pid := strings.TrimSuffix(ptp, ".ptp") + ".pid"

// delete existing sockets if exist
// errors ignored on purpose
_ = forceDeleteFileIfExists(ptp)
_ = forceDeleteFileIfExists(ptp + "+") // created by running qemu instance

command := cli.CommandInteractive(network.VmnetBinary,
"--vmnet-mode", "shared",
"--vmnet-gateway", "192.168.106.1",
"--vmnet-dhcp-end", "192.168.106.254",
"--pidfile", pid,
ptp+"[]",
)

return command.Run()
},
}

func forceDeleteFileIfExists(name string) error {
if stat, err := os.Stat(name); err == nil && !stat.IsDir() {
return os.Remove(name)
}
return nil
}

func init() {
vmnetCmd.AddCommand(startCmd)
}
4 changes: 3 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

const AppName = "colima"

var profile = ProfileInfo{ID: AppName, DisplayName: AppName}
var profile = ProfileInfo{ID: AppName, DisplayName: AppName, ShortName: AppName}

// SetProfile sets the profile name for the application.
// This is an avenue to test Colima without breaking an existing stable setup.
Expand All @@ -29,6 +29,7 @@ func SetProfile(profileName string) {
// use a prefix to prevent possible name clashes
profile.ID = "colima-" + profileName
profile.DisplayName = "colima [profile=" + profileName + "]"
profile.ShortName = profileName
}

// Profile returns the current application profile.
Expand All @@ -38,6 +39,7 @@ func Profile() ProfileInfo { return profile }
type ProfileInfo struct {
ID string
DisplayName string
ShortName string
}

// VersionInfo is the application version info.
Expand Down
Loading

0 comments on commit f944599

Please sign in to comment.