Skip to content

Commit

Permalink
Add down functionality to stop VMs
Browse files Browse the repository at this point in the history
  • Loading branch information
bensallen committed Aug 14, 2019
1 parent b0763fa commit 7c685c6
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 20 deletions.
3 changes: 3 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ cmd: ifconfig bridge1 192.168.99.1 netmask 0xffffff00
- Generate UUID if not specified, store in run dir
- Generate MAC for tap interfaces if not specified, store in run dir
- Add CI, CircleCI, clean code, etc.
- Reorganize internal/config to move VM action logic outside of config

## Down

## Destroy

## Status

- Add pid in status output

## SSH

## Console
Expand Down
87 changes: 77 additions & 10 deletions internal/config/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os/exec"
"strconv"
"strings"
"syscall"

"github.com/mitchellh/go-ps"
)
Expand Down Expand Up @@ -88,18 +89,19 @@ func (v *VMConfig) Up() error {
return nil
}

// Status attempts to find the pid file in the run dir of a VM and checks to see if its running or not.
func (v *VMConfig) Status() Status {
pidFile := v.RunDir + "/pid"
if _, err := os.Stat(pidFile); os.IsNotExist(err) {
return NotFound
}
pidTxt, err := ioutil.ReadFile(pidFile)
if err != nil {
return NotFound
// Down stops a VM if its running.
func (v *VMConfig) Down(signal string) error {
if v.Status() != Running {
return fmt.Errorf("not running")
}

pid, err := strconv.Atoi(string(pidTxt))
return v.Kill(signal)
}

// Status attempts to find the pid file in the run dir of a VM and checks to see if its running or not.
func (v *VMConfig) Status() Status {
pidFilePath := v.RunDir + "/pid"
pid, err := pidFile(pidFilePath)
if err != nil {
return NotFound
}
Expand All @@ -114,6 +116,71 @@ func (v *VMConfig) Status() Status {
return Running
}

// Kill attempts to kill a VM via the pid file with the specified signal.
func (v *VMConfig) Kill(signal string) error {
var sysSig syscall.Signal
if signal == "" {
sysSig = syscall.SIGTERM
} else {
var err error
if sysSig, err = sigLookup(signal); err != nil {
return err
}
}

pidFilePath := v.RunDir + "/pid"
pid, err := pidFile(pidFilePath)
if err != nil {
return err
}

proc, err := os.FindProcess(pid)
if err != nil {
return err
}

return proc.Signal(sysSig)
}

func sigLookup(s string) (syscall.Signal, error) {
sigmap := map[string]syscall.Signal{
"SIGINT": syscall.Signal(2),
"SIGKILL": syscall.Signal(9),
"SIGUSR1": syscall.Signal(10),
"SIGUSR2": syscall.Signal(12),
"SIGTERM": syscall.Signal(15),
"2": syscall.Signal(2),
"9": syscall.Signal(9),
"10": syscall.Signal(10),
"12": syscall.Signal(12),
"15": syscall.Signal(15),
}

sig, ok := sigmap[s]
if !ok {
return 0, fmt.Errorf("%s is not a supported signal", s)
}

return sig, nil
}

func pidFile(path string) (int, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return 0, fmt.Errorf("pid file not found")
}
pidTxt, err := ioutil.ReadFile(path)
if err != nil {
return 0, fmt.Errorf("pid file cannot be read")
}

pid, err := strconv.Atoi(string(pidTxt))
if err != nil {
return 0, fmt.Errorf("pid file does not contain an integer")
}

return pid, nil
}

func (v *VMConfig) Cli() []string {

var args []string
Expand Down
24 changes: 19 additions & 5 deletions internal/down/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,26 @@ import (
"fmt"

"github.com/bensallen/hkmgr/internal/config"
"github.com/kr/pretty"
)

func Run(cfg *config.Config) error {
fmt.Printf("%# v\n", pretty.Formatter(cfg))

// Run stops all VMs or the specific VMs passed as "name".
func Run(cfg *config.Config, name string, signal string) error {
if name != "" {
if vm, ok := cfg.VM[name]; ok {
err := vm.Down(signal)
if err != nil {
fmt.Printf("Stopping VM failed, %v\n", err)
}
} else {
return fmt.Errorf("%s not found in the configuration", name)
}
} else {
for name, vm := range cfg.VM {
err := vm.Down(signal)
if err != nil {
fmt.Printf("Stopping VM %s failed, %v\n", name, err)
}
}
}
return nil

}
12 changes: 7 additions & 5 deletions internal/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func Run() error {

downSubcommand = flaggy.NewSubcommand("down")
downSubcommand.Description = "Stop VMs"
var downSignal string
downSubcommand.String(&downSignal, "s", "signal", "Signal to send to VM")
downSubcommand.AddPositionalValue(&vmName, "name", 1, false, "Specify a VM, otherwise all VMs will be stopped")

destroySubcommand = flaggy.NewSubcommand("destroy")
Expand All @@ -71,11 +73,11 @@ func Run() error {

flaggy.AttachSubcommand(upSubcommand, 1)
flaggy.AttachSubcommand(downSubcommand, 1)
flaggy.AttachSubcommand(destroySubcommand, 1)
flaggy.AttachSubcommand(validateSubcommand, 1)
//flaggy.AttachSubcommand(destroySubcommand, 1)
//flaggy.AttachSubcommand(validateSubcommand, 1)
flaggy.AttachSubcommand(statusSubcommand, 1)
flaggy.AttachSubcommand(sshSubcommand, 1)
flaggy.AttachSubcommand(consoleSubcommand, 1)
//flaggy.AttachSubcommand(sshSubcommand, 1)
//flaggy.AttachSubcommand(consoleSubcommand, 1)

flaggy.SetVersion(version)
flaggy.Parse()
Expand Down Expand Up @@ -108,7 +110,7 @@ func Run() error {
return err
}
case downSubcommand.Used:
if err := down.Run(&config); err != nil {
if err := down.Run(&config, vmName, downSignal); err != nil {
return err
}
case destroySubcommand.Used:
Expand Down

0 comments on commit 7c685c6

Please sign in to comment.