├── tools └── host │ ├── client.py │ └── goserial.go ├── LICENSE ├── plugins ├── error.go ├── cpu.go ├── ether.go ├── mem.go ├── host.go └── disk.go ├── termios ├── term_windows.go ├── term_bsd.go ├── term_linux.go └── term.go ├── Makefile ├── websocket └── websocket.go ├── README.md └── main.go /tools/host/client.py: -------------------------------------------------------------------------------- 1 | import websocket 2 | 3 | GUEST_IP = "192.168.100.193" 4 | GUEST_PORT = "8080" 5 | 6 | if __name__ == "__main__": 7 | websocket.enableTrace(True) 8 | ws = websocket.create_connection("ws://{0}:{1}/".format(GUEST_IP, GUEST_PORT)) 9 | opts = ('cpu', 'mem', 'iface', 'disk', 'uptime') 10 | 11 | for opt in opts: 12 | ws.send(opt) 13 | result = ws.recv() 14 | print("Received: {}".format(result)) 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | -------------------------------------------------------------------------------- /plugins/error.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package plugins 30 | 31 | func CheckErr(err error) { 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /plugins/cpu.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package plugins 30 | 31 | import ( 32 | "github.com/shirou/gopsutil/cpu" 33 | ) 34 | 35 | // Returns information about CPU usage. 36 | func CpuInfo() []cpu.TimesStat { 37 | vcpu, err := cpu.Times(false) 38 | CheckErr(err) 39 | 40 | return vcpu 41 | } 42 | -------------------------------------------------------------------------------- /plugins/ether.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package plugins 30 | 31 | import ( 32 | "github.com/shirou/gopsutil/net" 33 | ) 34 | 35 | // Returns information about IFACE settings. 36 | func NetInfo() []net.InterfaceStat { 37 | vnet, err := net.Interfaces() 38 | CheckErr(err) 39 | 40 | return vnet 41 | } 42 | -------------------------------------------------------------------------------- /plugins/mem.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package plugins 30 | 31 | import ( 32 | "github.com/shirou/gopsutil/mem" 33 | ) 34 | 35 | // Returns information about memory usage. 36 | func Memory() *mem.VirtualMemoryStat { 37 | vm, err := mem.VirtualMemory() 38 | CheckErr(err) 39 | 40 | return vm 41 | } 42 | -------------------------------------------------------------------------------- /termios/term_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | // +build 386 amd64 3 | 4 | /*- 5 | * Copyright 2018 iXsystems, Inc. 6 | * Copyright 2018 by Marcelo Araujo . 7 | * All rights reserved 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted providing that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | package termios 33 | 34 | func SetTerm(fd *int) { 35 | } 36 | 37 | func CloseConnection(fd int) { 38 | } 39 | 40 | func Read(fd int) []byte { 41 | return []byte("not implemented") 42 | } 43 | 44 | func Write(fd int, guestInfo []byte) { 45 | } 46 | 47 | func NewConnection(vconsole string) int { 48 | return 0 49 | } 50 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GO ?= go 2 | TARGET := bhyve-vm-goagent 3 | OS := freebsd netbsd linux windows 4 | ARCH := 386 amd64 5 | VERSION := `grep \"VERSION\" main.go | cut -d '"' -f 2 | head -1` 6 | HOSTOS := `go env | grep GOHOSTOS | cut -d '"' -f 2 | head -1` 7 | 8 | all: build 9 | 10 | deps: 11 | @echo "===> Downloading crossbuild dependencies." 12 | go get github.com/gorilla/websocket 13 | go get github.com/shirou/w32 14 | go get github.com/araujobsd/bhyve-vm-goagent/plugins 15 | go get github.com/araujobsd/bhyve-vm-goagent/termios 16 | go get github.com/araujobsd/bhyve-vm-goagent/websocket 17 | go get github.com/go-ole/go-ole 18 | go get github.com/go-ole/go-ole/oleutil 19 | 20 | deps_windows: 21 | go get github.com/StackExchange/wmi 22 | 23 | tools: 24 | go build -o goserial ./tools/host/goserial.go 25 | 26 | build: 27 | @for arch in $(ARCH); do \ 28 | echo "===> building: $(TARGET)-$(HOSTOS)-$$arch-$(VERSION)"; \ 29 | if [ $$arch == "386" ] ; then \ 30 | GOOS=$$os GOARCH=$$arch go build -o $(TARGET)-$(HOSTOS)-"i386"-"$(VERSION)" $^ ;\ 31 | else \ 32 | GOOS=$$os GOARCH=$$arch go build -o $(TARGET)-$(HOSTOS)-$$arch-"$(VERSION)" $^ ;\ 33 | fi \ 34 | done \ 35 | 36 | release: 37 | @for os in $(OS); do \ 38 | for arch in $(ARCH); do \ 39 | echo "===> building: $(TARGET)-$$os-$$arch-$(VERSION)"; \ 40 | if [ $$arch == "386" ] ; then \ 41 | GOOS=$$os GOARCH=$$arch go build -o $(TARGET)-$$os-"i386"-"$(VERSION)" $^ ;\ 42 | else \ 43 | GOOS=$$os GOARCH=$$arch go build -o $(TARGET)-$$os-$$arch-"$(VERSION)" $^ ;\ 44 | fi \ 45 | done \ 46 | done \ 47 | 48 | clean: 49 | @$(GO) clean 50 | @for os in $(OS); do \ 51 | for arch in $(ARCH); do \ 52 | echo "===> Removing: $(TARGET)-$$os-$$arch-$(VERSION)"; \ 53 | rm -f $(TARGET)-$$os-$$arch-"$(VERSION)" $^ ;\ 54 | done \ 55 | done \ 56 | 57 | 58 | .PHONY: all release deps deps_windows tools build clean 59 | -------------------------------------------------------------------------------- /termios/term_bsd.go: -------------------------------------------------------------------------------- 1 | // +build freebsd netbsd openbsd,amd64 2 | 3 | /*- 4 | * Copyright 2018 iXsystems, Inc. 5 | * Copyright 2018 by Marcelo Araujo . 6 | * All rights reserved 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted providing that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package termios 32 | 33 | import ( 34 | "syscall" 35 | "unsafe" 36 | ) 37 | 38 | func SetTerm(fd *int) { 39 | termios := syscall.Termios{} 40 | termios.Cflag |= syscall.CS8 | syscall.CREAD | syscall.CLOCAL | syscall.B115200 41 | termios.Cflag &^= syscall.CSIZE | syscall.PARENB 42 | termios.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON 43 | termios.Oflag &^= syscall.OPOST 44 | termios.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG 45 | termios.Cc[syscall.VMIN] = 1 46 | termios.Cc[syscall.VTIME] = 0 47 | termios.Ispeed = syscall.B115200 48 | termios.Ospeed = syscall.B115200 49 | 50 | syscall.Syscall6(syscall.SYS_IOCTL, uintptr(*fd), 51 | uintptr(syscall.TIOCSETA), uintptr(unsafe.Pointer(&termios)), 52 | 0, 0, 0) 53 | } 54 | -------------------------------------------------------------------------------- /termios/term_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | // +build 386 amd64 3 | 4 | /*- 5 | * Copyright 2018 iXsystems, Inc. 6 | * Copyright 2018 by Marcelo Araujo . 7 | * All rights reserved 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted providing that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | */ 31 | 32 | package termios 33 | 34 | import ( 35 | "syscall" 36 | "unsafe" 37 | ) 38 | 39 | func SetTerm(fd *int) { 40 | termios := syscall.Termios{} 41 | termios.Cflag |= syscall.CS8 | syscall.CREAD | syscall.CLOCAL | syscall.B115200 42 | termios.Cflag &^= syscall.CSIZE | syscall.PARENB 43 | termios.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON 44 | termios.Oflag &^= syscall.OPOST 45 | termios.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG 46 | termios.Cc[syscall.VMIN] = 1 47 | termios.Cc[syscall.VTIME] = 0 48 | termios.Ispeed = syscall.B115200 49 | termios.Ospeed = syscall.B115200 50 | 51 | syscall.Syscall6(syscall.SYS_IOCTL, uintptr(*fd), 52 | uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&termios)), 53 | 0, 0, 0) 54 | } 55 | -------------------------------------------------------------------------------- /plugins/host.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package plugins 30 | 31 | import ( 32 | "encoding/json" 33 | 34 | "github.com/shirou/gopsutil/host" 35 | ) 36 | 37 | type HostInfo struct { 38 | Seconds uint64 `json:"seconds"` 39 | Days uint64 `json:"days"` 40 | Hours uint64 `json:"hours"` 41 | Minutes uint64 `json:"minutes"` 42 | } 43 | 44 | func Uptime() []byte { 45 | hostinfo := HostInfo{} 46 | for i := 0; i < 3; i++ { 47 | seconds, err := host.Uptime() 48 | CheckErr(err) 49 | hostinfo.Seconds = seconds 50 | hostinfo.Days = hostinfo.Seconds / (60 * 60 * 24) 51 | hostinfo.Hours = (hostinfo.Seconds - (hostinfo.Days * 60 * 60 * 24)) / (60 * 60) 52 | hostinfo.Minutes = ((hostinfo.Seconds - (hostinfo.Days * 60 * 60 * 24)) - (hostinfo.Hours * 60 * 60)) / 60 53 | } 54 | convjson, err := json.Marshal(hostinfo) 55 | CheckErr(err) 56 | 57 | return convjson 58 | } 59 | 60 | // Return pong. 61 | func Ping() string { 62 | return "pong" 63 | } 64 | -------------------------------------------------------------------------------- /termios/term.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | /*- 4 | * Copyright 2018 iXsystems, Inc. 5 | * Copyright 2018 by Marcelo Araujo . 6 | * All rights reserved 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted providing that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | package termios 32 | 33 | import ( 34 | "log" 35 | "syscall" 36 | ) 37 | 38 | const DEBUG int = 1 39 | 40 | func NewConnection(vconsole string) int { 41 | fd, err := syscall.Open(vconsole, syscall.O_RDWR, 0666) 42 | if err != nil { 43 | panic(err.Error()) 44 | } 45 | 46 | SetTerm(&fd) 47 | return fd 48 | } 49 | 50 | func CloseConnection(fd int) { 51 | syscall.Close(fd) 52 | } 53 | 54 | func Read(fd int) []byte { 55 | var MaxRead int = 1024 56 | var numread int 57 | var err error 58 | var guestInfo []byte 59 | 60 | buffer := make([]byte, MaxRead) 61 | numread, err = syscall.Read(fd, buffer) 62 | if err != nil { 63 | panic(err.Error()) 64 | } 65 | 66 | if numread < MaxRead { 67 | MaxRead = numread 68 | } 69 | guestInfo = append(buffer[:MaxRead]) 70 | 71 | if DEBUG == 1 { 72 | log.Println("===> READ COMMAND: ", string(guestInfo[:MaxRead])) 73 | } 74 | 75 | return guestInfo 76 | } 77 | 78 | func Write(fd int, guestInfo []byte) { 79 | _, err := syscall.Write(fd, guestInfo) 80 | if err != nil { 81 | panic(err.Error()) 82 | } 83 | if DEBUG == 1 { 84 | log.Println("===> Writting: ", string(guestInfo)) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /plugins/disk.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package plugins 30 | 31 | import ( 32 | "encoding/json" 33 | 34 | "github.com/shirou/gopsutil/disk" 35 | ) 36 | 37 | var FSTYPE = map[string]bool{ 38 | "ext3": true, 39 | "ext4": true, 40 | "zfs": true, 41 | "ufs": true, 42 | } 43 | 44 | type DiskUsage struct { 45 | Mountpoint string `json:"mountpoint"` 46 | Fstype string `json:"fstype"` 47 | Total uint64 `json:"total"` 48 | Free uint64 `json:"free"` 49 | Used uint64 `json:"used"` 50 | } 51 | 52 | var DiskInformation []DiskUsage 53 | 54 | func UsageInfo(path string) DiskUsage { 55 | usage, err := disk.Usage(path) 56 | CheckErr(err) 57 | 58 | diskusage := DiskUsage{} 59 | diskusage.Mountpoint = usage.Path 60 | diskusage.Fstype = usage.Fstype 61 | diskusage.Total = usage.Total 62 | diskusage.Free = usage.Free 63 | diskusage.Used = usage.Used 64 | 65 | return diskusage 66 | } 67 | 68 | // Returns information about root slice. 69 | func DiskInfo() []byte { 70 | vdisk, err := disk.Partitions(true) 71 | DiskInformation := []DiskUsage{} 72 | CheckErr(err) 73 | for _, disk := range vdisk { 74 | if FSTYPE[disk.Fstype] { 75 | info := UsageInfo("/") 76 | DiskInformation = append(DiskInformation, info) 77 | break 78 | } 79 | } 80 | convjson, err := json.Marshal([]DiskUsage(DiskInformation)) 81 | CheckErr(err) 82 | 83 | return convjson 84 | } 85 | -------------------------------------------------------------------------------- /websocket/websocket.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package websocket 30 | 31 | import ( 32 | "fmt" 33 | "log" 34 | "net" 35 | "net/http" 36 | "strconv" 37 | 38 | "github.com/araujobsd/bhyve-vm-goagent/plugins" 39 | "github.com/gorilla/websocket" 40 | ) 41 | 42 | var upgrader = websocket.Upgrader{} 43 | 44 | func testIPAddr(ipadd string) bool { 45 | ipType := net.ParseIP(ipadd) 46 | if ipType.To4() == nil || ipType.To16() == nil { 47 | return false 48 | } 49 | return true 50 | } 51 | 52 | func home(w http.ResponseWriter, r *http.Request) { 53 | var dump []byte 54 | c, err := upgrader.Upgrade(w, r, nil) 55 | 56 | if err != nil { 57 | log.Print("Upgrade: ", err) 58 | return 59 | } 60 | 61 | for { 62 | mt, message, err := c.ReadMessage() 63 | if err != nil { 64 | break 65 | } 66 | 67 | switch opt := string(message); opt { 68 | case "mem": 69 | memoryinfo := plugins.Memory() 70 | dump = append([]byte(fmt.Sprintf("%v", memoryinfo))) 71 | case "cpu": 72 | cpuinfo := plugins.CpuInfo() 73 | dump = append([]byte(fmt.Sprintf("%v", cpuinfo))) 74 | case "iface": 75 | ifaceinfo := plugins.NetInfo() 76 | dump = append([]byte(fmt.Sprintf("%v", ifaceinfo))) 77 | case "disk": 78 | diskinfo := plugins.DiskInfo() 79 | dump = append(diskinfo) 80 | case "uptime": 81 | uptimeinfo := plugins.Uptime() 82 | dump = append(uptimeinfo) 83 | case "ping": 84 | pinginfo := plugins.Ping() 85 | dump = append([]byte(fmt.Sprintf("%v", pinginfo))) 86 | default: 87 | dump = append([]byte("bang! bang!")) 88 | } 89 | err = c.WriteMessage(mt, dump) 90 | plugins.CheckErr(err) 91 | } 92 | defer c.Close() 93 | } 94 | 95 | func RunServer(ipaddr *string, port *int) { 96 | var bindto string 97 | http.HandleFunc("/", home) 98 | 99 | if testIPAddr(*ipaddr) { 100 | bindto = *ipaddr + ":" + strconv.Itoa(*port) 101 | } else { 102 | bindto = "127.0.0.1:" + strconv.Itoa(*port) 103 | } 104 | 105 | log.Printf("==> Running server at: %s:%d\n", *ipaddr, *port) 106 | log.Fatal(http.ListenAndServe(bindto, nil)) 107 | } 108 | -------------------------------------------------------------------------------- /tools/host/goserial.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | // Example of usage: 30 | // ./host -socket="/tmp/FreeBSD12.sock" -disk -uptime 31 | // Result: [{"mountpoint":"/","fstype":"zfs","total":48978477056,"free":48396845056,"used":581632000}] 32 | // Result: {"seconds":3822,"days":0,"hours":1,"minutes":3} 33 | 34 | package main 35 | 36 | import ( 37 | "flag" 38 | "fmt" 39 | "log" 40 | "net" 41 | ) 42 | 43 | var socketPath = flag.String("socket", "", "Canonical path for the socket file.") 44 | var memoryinfo = flag.Bool("mem", false, "Get memory information from guest.") 45 | var cpuinfo = flag.Bool("cpu", false, "Get CPU information from guest.") 46 | var diskinfo = flag.Bool("disk", false, "Get DISK information from guest.") 47 | var etherinfo = flag.Bool("ether", false, "Get Ethernet information from guest.") 48 | var uptimeinfo = flag.Bool("uptime", false, "Get guest's UPTIME.") 49 | var ping = flag.Bool("ping", false, "Check if guest is alive.") 50 | 51 | func connect(opt string, path string) { 52 | var buf [2048]byte 53 | 54 | c, err := net.Dial("unix", path) 55 | if err != nil { 56 | panic(err) 57 | } 58 | 59 | _, err = c.Write([]byte(opt)) 60 | if err != nil { 61 | log.Println("Erro to write: ", err) 62 | panic(err) 63 | } 64 | 65 | n, err := c.Read(buf[:]) 66 | if err != nil { 67 | log.Println("Erro to read: ", err) 68 | panic(err) 69 | } 70 | fmt.Println("Result: ", string(buf[:n])) 71 | 72 | c.Close() 73 | } 74 | 75 | func main() { 76 | var arg string 77 | flag.Parse() 78 | 79 | if len(*socketPath) > 0 { 80 | if *memoryinfo { 81 | arg = "mem" 82 | connect(arg, *socketPath) 83 | } 84 | if *cpuinfo { 85 | arg = "cpu" 86 | connect(arg, *socketPath) 87 | } 88 | if *diskinfo { 89 | arg = "disk" 90 | connect(arg, *socketPath) 91 | } 92 | if *etherinfo { 93 | arg = "iface" 94 | connect(arg, *socketPath) 95 | } 96 | if *uptimeinfo { 97 | arg = "uptime" 98 | connect(arg, *socketPath) 99 | } 100 | if *ping { 101 | arg = "ping" 102 | connect(arg, *socketPath) 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GoDoc](https://godoc.org/github.com/araujobsd/bhyve-vm-goagent/plugins?status.svg)](https://godoc.org/github.com/araujobsd/bhyve-vm-goagent/) 2 | [![GitHub issues](https://img.shields.io/github/issues/araujobsd/bhyve-vm-goagent.svg)](https://github.com/araujobsd/bhyve-vm-goagent/issues) 3 | [![GitHub forks](https://img.shields.io/github/forks/araujobsd/bhyve-vm-goagent.svg)](https://github.com/araujobsd/bhyve-vm-goagent/network) 4 | 5 | bhyve-vm-goagent 6 | ================ 7 | It is an agent developed using [Go](http://golang.org/) that runs inside guest virtual machines and allows host hypervisor to obtain information from guest such like memory usage, cpu, disk and ethernet configuration. 8 | 9 | It supports [virtio-console](https://fedoraproject.org/wiki/Features/VirtioSerial) as well as [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. 10 | 11 | ## Build instructions 12 | 1) `make deps` 13 | 2) `make` 14 | 15 | It will try to detect your OS and build the binaries for it. 16 | 17 | ## Build release 18 | 1) `make deps` 19 | 2) `make deps_windows` 20 | 3) `make release` 21 | 22 | It will cross compile binaries for the following platforms: FreeBSD, NetBSD, Linux and Windows. 23 | 24 | NOTE: When it runs `make deps_windows` a 'build constraints' will appears, just ignore it. 25 | 26 | ## Usage instructions (Host VM) 27 | Start bhyve(8). 28 | ``` 29 | Usage of -virtio:bhyve -A -H -w -c 2 -m 2048 -s 0:0,hostbridge \ 30 | -s 31,lpc -l com1,/dev/nmdm132A -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \ 31 | -s 3,e1000,tap0,mac=00:a0:98:1e:c0:08 -s 9,fbuf,vncserver,tcp=192.168.100.111:6032,w=800,h=600,, \ 32 | -s 30,xhci,tablet -s 4,ahci-hd,/dev/zvol/tank/freebsd12 \ 33 | -s 2,virtio-console,org.freenas.bhyve-agent=/tmp/FreeBSD12.sock FreeBSD12 34 | ``` 35 | 36 | Note for the parameter -s 2,virtio-console,org.freenas.bhyve-agent=/tmp/FreeBSD12.sock 37 | 38 | ## Usage instructions (Guest VM) 39 | `root@guest:/tmp # ./bhyve-vm-goagent-freebsd-386` 40 | ``` 41 | Usage of -virtio: 42 | -virtio 43 | It uses the virtio-console for communication. 44 | 45 | Usage of -websocket: 46 | -websocket 47 | It uses the websocket for communication. 48 | -ipaddr string 49 | IPv4/IPv6 to bind the service. (default "127.0.0.1") 50 | -port int 51 | TCP port to bind the websocket. (default 8080) 52 | ``` 53 | 54 | Start in websocket mode 55 | ``` 56 | root@guest:/tmp # ./bhyve-vm-goagent-freebsd-386 -websocket -ipaddr="192.168.100.193" -port=9191 57 | 018/01/22 11:30:12 ==> Running server at: 192.168.100.193:9191 58 | ``` 59 | Start in virtio mode 60 | ``` 61 | root@guest:/tmp # ./bhyve-vm-goagent-freebsd-386 -virtio 62 | 2018/01/22 11:41:50 ==> /dev/vtcon/org.freenas.bhyve-agent 63 | ``` 64 | 65 | ## How to use host [tools](https://github.com/araujobsd/bhyve-vm-goagent/tree/master/tools/host)? 66 | Build goserial: 67 | 68 | ```make tools``` 69 | 70 | goserial.go: 71 | ``` 72 | root@freenas:/tmp # ./goserial -socket="/tmp/FreeBSD12.sock" -ether -uptime 73 | Result: [{"mtu":1500,"name":"em0","hardwareaddr":"00:a0:98:1e:c0:08","flags":["up","broadcast","multicast"],"addrs":[{"addr":"192.168.100.193/24"}]} {"mtu":16384,"name":"lo0","hardwareaddr":"","flags":["up","loopback","multicast"],"addrs":[{"addr":"::1/128"},{"addr":"fe80::1/64"},{"addr":"127.0.0.1/8"}]}] 74 | Result: {"seconds":5742,"days":0,"hours":1,"minutes":35} 75 | ``` 76 | 77 | client.py: 78 | ``` 79 | [araujo@pipoca] /z/go/bhyve-vm-goagent/tools/host# python3 client.py 80 | ``` 81 | 82 | You need to edit client.py and change GUEST_IP and GUEST_PORT according with your guest vm settings. 83 | 84 | 85 | ## Copyright and licensing 86 | Distributed under [2-Clause BSD License](https://github.com/araujobsd/bhyve-vm-goagent/blob/master/LICENSE). 87 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2018 iXsystems, Inc. 3 | * Copyright 2018 by Marcelo Araujo . 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | package main 30 | 31 | import ( 32 | "flag" 33 | "fmt" 34 | "log" 35 | "os" 36 | 37 | "github.com/araujobsd/bhyve-vm-goagent/plugins" 38 | "github.com/araujobsd/bhyve-vm-goagent/termios" 39 | "github.com/araujobsd/bhyve-vm-goagent/websocket" 40 | ) 41 | 42 | const ( 43 | DEBUG int = 0 44 | VERSION string = "1.0-RELEASE" 45 | ) 46 | 47 | var ( 48 | guestInfo []byte 49 | vconsolePath = [...]string{ 50 | "/dev/virtio-ports/org.freenas.bhyve-agent", 51 | "/dev/vtcon/org.freenas.bhyve-agent", 52 | "/dev/ttyV0.0", 53 | } 54 | ) 55 | 56 | func checkConsole() string { 57 | for _, device := range vconsolePath { 58 | _, err := os.Stat(device) 59 | if os.IsNotExist(err) { 60 | continue 61 | } else { 62 | if DEBUG == 1 { 63 | log.Println("==> Device: ", device) 64 | } 65 | return device 66 | } 67 | } 68 | return "" 69 | } 70 | 71 | func Run(fd int) { 72 | var dump []byte 73 | callback := termios.Read(fd) 74 | if len(callback) > 0 { 75 | switch opt := string(callback); opt { 76 | case "mem": 77 | memoryinfo := plugins.Memory() 78 | dump = append([]byte(fmt.Sprintf("%v", memoryinfo))) 79 | case "cpu": 80 | cpuinfo := plugins.CpuInfo() 81 | dump = append([]byte(fmt.Sprintf("%v", cpuinfo))) 82 | case "iface": 83 | ifaceinfo := plugins.NetInfo() 84 | dump = append([]byte(fmt.Sprintf("%v", ifaceinfo))) 85 | case "disk": 86 | diskinfo := plugins.DiskInfo() 87 | dump = append(diskinfo) 88 | case "uptime": 89 | uptimeinfo := plugins.Uptime() 90 | dump = append(uptimeinfo) 91 | case "ping": 92 | pinginfo := plugins.Ping() 93 | dump = append([]byte(fmt.Sprintf("%v", pinginfo))) 94 | default: 95 | dump = append([]byte("bang! bang!")) 96 | } 97 | termios.Write(fd, dump) 98 | } 99 | } 100 | 101 | func usage() { 102 | fmt.Println("Usage of -virtio:") 103 | fmt.Printf(" -virtio\n") 104 | fmt.Printf("\tIt uses the virtio-console for communication.\n") 105 | fmt.Println("") 106 | fmt.Println("Usage of -websocket:") 107 | fmt.Printf(" -websocket\n") 108 | fmt.Printf("\tIt uses the websocket for communication.\n") 109 | fmt.Printf(" -ipaddr string\n") 110 | fmt.Printf("\tIPv4/IPv6 to bind the service. (default '127.0.0.1')\n") 111 | fmt.Printf(" -port int\n") 112 | fmt.Printf("\tTCP port to bind the websocket. (default 8080)\n") 113 | fmt.Println("") 114 | fmt.Println("Usage of -version:") 115 | fmt.Printf(" -version\n") 116 | fmt.Printf("\tPrint out software version.\n") 117 | fmt.Println("") 118 | 119 | os.Exit(2) 120 | } 121 | 122 | func main() { 123 | vconsoleCmd := flag.NewFlagSet("-virtio", flag.ExitOnError) 124 | websocketCmd := flag.NewFlagSet("-websocket", flag.ExitOnError) 125 | websocketIp := websocketCmd.String("ipaddr", "127.0.0.1", "IPv4/IPv6 to bind the service.") 126 | websocketPort := websocketCmd.Int("port", 8080, "TCP port to bind the websocket.") 127 | 128 | if len(os.Args) < 2 { 129 | usage() 130 | } 131 | 132 | switch os.Args[1] { 133 | case "-version", "-v": 134 | fmt.Printf("==> bhyve-vm-goagent version %s.\n", VERSION) 135 | case "-virtio": 136 | vconsoleCmd.Parse(os.Args[2:]) 137 | case "-websocket": 138 | websocketCmd.Parse(os.Args[2:]) 139 | default: 140 | usage() 141 | } 142 | 143 | if vconsoleCmd.Parsed() { 144 | vconsole := checkConsole() 145 | if len(vconsole) > 0 { 146 | fd := termios.NewConnection(vconsole) 147 | for { 148 | Run(fd) 149 | } 150 | defer termios.CloseConnection(fd) 151 | } else { 152 | fmt.Println("Error: Guest without support of virtio-console.") 153 | os.Exit(2) 154 | } 155 | } else if websocketCmd.Parsed() { 156 | websocket.RunServer(websocketIp, websocketPort) 157 | } 158 | } 159 | --------------------------------------------------------------------------------