Skip to content

Commit

Permalink
Add IP and state to vm list
Browse files Browse the repository at this point in the history
  • Loading branch information
dvob committed Dec 25, 2020
1 parent 0ed96b5 commit 00e5867
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 10 deletions.
80 changes: 74 additions & 6 deletions internal/vm/libvirt/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package libvirt

import (
"fmt"
"strconv"

"github.com/digitalocean/go-libvirt"
"github.com/dvob/vu/internal/vm"
libvirtxml "github.com/libvirt/libvirt-go-xml"
)

const (
UnusedFlag uint32 = 0
)

var _ vm.Manager = &Manager{}

type Manager struct {
Expand Down Expand Up @@ -60,13 +65,13 @@ func (m *Manager) ListDetail() error {
return nil
}

func (m *Manager) List() ([]vm.State, error) {
func (m *Manager) List() ([]vm.VM, error) {
// TODO: not sure why first paramater has to be 1
domains, _, err := m.ConnectListAllDomains(1, 0)
if err != nil {
return nil, err
}
vms := []vm.State{}
vms := []vm.VM{}
for _, dom := range domains {
vm, err := m.get(dom)
if err != nil {
Expand All @@ -77,19 +82,20 @@ func (m *Manager) List() ([]vm.State, error) {
return vms, nil
}

func (m *Manager) Get(name string) (*vm.State, error) {
func (m *Manager) Get(name string) (*vm.VM, error) {
dom, err := m.DomainLookupByName(name)
if err != nil {
return nil, err
}
return m.get(dom)
}

func (m *Manager) get(dom libvirt.Domain) (*vm.State, error) {
state := &vm.State{
func (m *Manager) get(dom libvirt.Domain) (*vm.VM, error) {
state := &vm.VM{
Name: dom.Name,
}

// get disks
xml, err := m.DomainGetXMLDesc(dom, 0)
if err != nil {
return nil, err
Expand All @@ -100,9 +106,71 @@ func (m *Manager) get(dom libvirt.Domain) (*vm.State, error) {
return nil, err
}
state.Images = getDisksFromDomain(vmDef)

// get IP
state.IPAddress = m.getIP(dom)

// state
domState, _, err := m.DomainGetState(dom, UnusedFlag)
if err != nil {
return nil, err
}
state.State = stateToString(libvirt.DomainState(domState))
return state, nil
}

func stateToString(state libvirt.DomainState) string {
switch state {
case libvirt.DomainRunning:
return "running"
case libvirt.DomainBlocked:
return "blocked"
case libvirt.DomainPaused:
return "paused"
case libvirt.DomainShutdown:
return "shutdown"
case libvirt.DomainShutoff:
return "shutoff"
case libvirt.DomainCrashed:
return "crashed"
case libvirt.DomainPmsuspended:
return "pmsuspended"
default:
return strconv.Itoa(int(state))
}
}

func (m *Manager) getIP(dom libvirt.Domain) string {
// dhcp leases
ifs, err := m.DomainInterfaceAddresses(dom, 0, UnusedFlag)
if err == nil && len(ifs) > 0 {
ip := getFirstIP(ifs)
if ip != "" {
return ip
}
}

// arp cache
ifs, err = m.DomainInterfaceAddresses(dom, 2, UnusedFlag)
if err == nil && len(ifs) > 0 {
ip := getFirstIP(ifs)
if ip != "" {
return ip
}
}

return "n/a"
}

func getFirstIP(ifaces []libvirt.DomainInterface) string {
for _, iface := range ifaces {
if len(iface.Addrs) > 0 {
return iface.Addrs[0].Addr
}
}
return ""
}

func getDisksFromDomain(dom *libvirtxml.Domain) []string {
disks := []string{}
if dom.Devices == nil {
Expand Down Expand Up @@ -218,7 +286,7 @@ func (m *Manager) Remove(name string) error {
return err
}

stateInt, _, err := m.DomainGetState(dom, 0)
stateInt, _, err := m.DomainGetState(dom, UnusedFlag)
state := libvirt.DomainState(stateInt)
if err != nil {
return err
Expand Down
54 changes: 54 additions & 0 deletions internal/vm/libvirt/vm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// +build integration

package libvirt

import (
"fmt"
"net"
"testing"
"time"

"github.com/digitalocean/go-libvirt"
"github.com/matryer/is"
)

func conn() (*libvirt.Libvirt, error) {
c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
if err != nil {
return nil, fmt.Errorf("failed to connect to libvirtd: %s", err)
}

l := libvirt.New(c)
if err := l.Connect(); err != nil {
return nil, fmt.Errorf("failed to connect: %v", err)
}
return l, nil
}

func Test_CreateVolume(t *testing.T) {
is := is.New(t)
t.Log("foo")
conn, err := conn()
if err != nil {
t.Fatal(err)
}

dom, err := conn.DomainLookupByName("net2-dhcp")
is.NoErr(err)

for _, i := range []uint32{0, 1, 2, 3} {
t.Log("source", i)
ifs, err := conn.DomainInterfaceAddresses(dom, i, 0)
if err != nil {
t.Log(err)
} else {
printIFs(t, ifs)
}
}
}

func printIFs(t *testing.T, ifs []libvirt.DomainInterface) {
for _, i := range ifs {
t.Log(i)
}
}
6 changes: 3 additions & 3 deletions internal/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ type Manager interface {
Start(name string) error
Shutdown(name string, force bool) error
Remove(name string) error
List() ([]State, error)
Get(name string) (*State, error)
List() ([]VM, error)
Get(name string) (*VM, error)
}

type Config struct {
Expand All @@ -18,7 +18,7 @@ type Config struct {
DiskSize uint64
}

type State struct {
type VM struct {
Name string
State string
IPAddress string
Expand Down
8 changes: 7 additions & 1 deletion vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"fmt"
"os"
"text/tabwriter"

vu "github.com/dvob/vu/internal"
"github.com/dvob/vu/internal/cloudinit"
Expand Down Expand Up @@ -127,9 +129,13 @@ func newListCmd(mgr *vu.Manager) *cobra.Command {
if err != nil {
return err
}

w := &tabwriter.Writer{}
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
for _, vm := range vms {
fmt.Println(vm.Name)
fmt.Fprintf(w, "%s\t%s\t%s\n", vm.Name, vm.State, vm.IPAddress)
}
w.Flush()
return nil
},
}
Expand Down

0 comments on commit 00e5867

Please sign in to comment.