github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/httpd/showVM.go (about) 1 package httpd 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "net" 8 "net/http" 9 "sort" 10 "strings" 11 12 "github.com/Cloud-Foundations/Dominator/lib/format" 13 "github.com/Cloud-Foundations/Dominator/lib/html" 14 "github.com/Cloud-Foundations/Dominator/lib/json" 15 "github.com/Cloud-Foundations/Dominator/lib/url" 16 ) 17 18 func (s state) showVMHandler(w http.ResponseWriter, req *http.Request) { 19 parsedQuery := url.ParseQuery(req.URL) 20 if len(parsedQuery.Flags) != 1 { 21 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 22 w.WriteHeader(http.StatusBadRequest) 23 return 24 } 25 var ipAddr string 26 for name := range parsedQuery.Flags { 27 ipAddr = name 28 } 29 netIpAddr := net.ParseIP(ipAddr) 30 vm, err := s.manager.GetVmInfo(netIpAddr) 31 if err != nil { 32 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 33 w.WriteHeader(http.StatusNotFound) 34 return 35 } 36 writer := bufio.NewWriter(w) 37 defer writer.Flush() 38 if parsedQuery.OutputType() == url.OutputTypeJson { 39 json.WriteWithIndent(writer, " ", vm) 40 } else { 41 var storage uint64 42 volumeSizes := make([]string, 0, len(vm.Volumes)) 43 for _, volume := range vm.Volumes { 44 storage += volume.Size 45 volumeSizes = append(volumeSizes, format.FormatBytes(volume.Size)) 46 } 47 var tagNames []string 48 for name := range vm.Tags { 49 tagNames = append(tagNames, name) 50 } 51 sort.Strings(tagNames) 52 fmt.Fprintf(writer, "<title>Information for VM %s</title>\n", ipAddr) 53 fmt.Fprintln(writer, `<style> 54 table, th, td { 55 border-collapse: collapse; 56 } 57 </style>`) 58 fmt.Fprintln(writer, "<body>") 59 fmt.Fprintln(writer, `<table border="0">`) 60 if len(vm.Address.IpAddress) < 1 { 61 writeString(writer, "IP Address", ipAddr+" (externally allocated)") 62 } else if vm.Uncommitted { 63 writeString(writer, "IP Address", ipAddr+" (uncommitted)") 64 } else { 65 writeString(writer, "IP Address", ipAddr) 66 } 67 if vm.Hostname != "" { 68 writeString(writer, "Hostname", vm.Hostname) 69 } 70 writeString(writer, "MAC Address", vm.Address.MacAddress) 71 if vm.ImageName != "" { 72 image := fmt.Sprintf("<a href=\"http://%s/showImage?%s\">%s</a>", 73 s.manager.GetImageServerAddress(), vm.ImageName, vm.ImageName) 74 writeString(writer, "Boot image", image) 75 } else if vm.ImageURL != "" { 76 writeString(writer, "Boot image URL", vm.ImageURL) 77 } else { 78 writeString(writer, "Boot image", "was streamed in") 79 } 80 writeString(writer, "State", vm.State.String()) 81 writeString(writer, "RAM", format.FormatBytes(vm.MemoryInMiB<<20)) 82 writeFloat(writer, "CPU", float64(vm.MilliCPUs)*1e-3) 83 writeStrings(writer, "Volume sizes", volumeSizes) 84 writeString(writer, "Total storage", format.FormatBytes(storage)) 85 writeStrings(writer, "Owner users", vm.OwnerGroups) 86 writeStrings(writer, "Owner users", vm.OwnerUsers) 87 writeBool(writer, "Spread volumes", vm.SpreadVolumes) 88 writeString(writer, "Latest boot", 89 fmt.Sprintf("<a href=\"showVmBootLog?%s\">log</a>", ipAddr)) 90 if ok, _ := s.manager.CheckVmHasHealthAgent(netIpAddr); ok { 91 writeString(writer, "Health Agent", 92 fmt.Sprintf("<a href=\"http://%s:6910/\">detected</a>", 93 ipAddr)) 94 } 95 fmt.Fprintln(writer, "</table>") 96 fmt.Fprintln(writer, "Tags:<br>") 97 fmt.Fprintln(writer, `<table border="1">`) 98 tw, _ := html.NewTableWriter(writer, true, "Name", "Value") 99 for _, name := range tagNames { 100 tw.WriteRow("", "", name, vm.Tags[name]) 101 } 102 fmt.Fprintln(writer, "</table><br>") 103 fmt.Fprintf(writer, 104 "<a href=\"showVM?%s&output=json\">VM info:</a><br>\n", 105 vm.Address.IpAddress) 106 fmt.Fprintln(writer, `<pre style="background-color: #eee; border: 1px solid #999; display: block; float: left;">`) 107 json.WriteWithIndent(writer, " ", vm) 108 fmt.Fprintln(writer, `</pre><p style="clear: both;">`) 109 fmt.Fprintln(writer, "</body>") 110 } 111 } 112 113 func writeBool(writer io.Writer, name string, value bool) { 114 fmt.Fprintf(writer, " <tr><td>%s</td><td>%t</td></tr>\n", name, value) 115 } 116 117 func writeInt(writer io.Writer, name string, value int) { 118 fmt.Fprintf(writer, " <tr><td>%s</td><td>%d</td></tr>\n", name, value) 119 } 120 121 func writeFloat(writer io.Writer, name string, value float64) { 122 fmt.Fprintf(writer, " <tr><td>%s</td><td>%g</td></tr>\n", name, value) 123 } 124 125 func writeString(writer io.Writer, name, value string) { 126 fmt.Fprintf(writer, " <tr><td>%s</td><td>%s</td></tr>\n", name, value) 127 } 128 129 func writeStrings(writer io.Writer, name string, value []string) { 130 if len(value) < 1 { 131 return 132 } 133 fmt.Fprintf(writer, " <tr><td>%s</td><td>%s</td></tr>\n", 134 name, strings.Join(value, ", ")) 135 } 136 137 func writeUint64(writer io.Writer, name string, value uint64) { 138 fmt.Fprintf(writer, " <tr><td>%s</td><td>%d</td></tr>\n", name, value) 139 }