github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/fleetmanager/hypervisors/listVMs.go (about)

     1  package hypervisors
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"sort"
     9  
    10  	"github.com/Cloud-Foundations/Dominator/lib/constants"
    11  	"github.com/Cloud-Foundations/Dominator/lib/format"
    12  	"github.com/Cloud-Foundations/Dominator/lib/html"
    13  	"github.com/Cloud-Foundations/Dominator/lib/json"
    14  	"github.com/Cloud-Foundations/Dominator/lib/url"
    15  	"github.com/Cloud-Foundations/Dominator/lib/verstr"
    16  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    17  )
    18  
    19  const commonStyleSheet string = `<style>
    20  table, th, td {
    21  border-collapse: collapse;
    22  }
    23  </style>
    24  `
    25  
    26  func getVmListFromMap(vmMap map[string]*vmInfoType, doSort bool) []*vmInfoType {
    27  	vms := make([]*vmInfoType, 0, len(vmMap))
    28  	if doSort {
    29  		ipAddrs := make([]string, 0, len(vmMap))
    30  		for ipAddr := range vmMap {
    31  			ipAddrs = append(ipAddrs, ipAddr)
    32  		}
    33  		verstr.Sort(ipAddrs)
    34  		for _, ipAddr := range ipAddrs {
    35  			vms = append(vms, vmMap[ipAddr])
    36  		}
    37  	} else {
    38  		for _, vm := range vmMap {
    39  			vms = append(vms, vm)
    40  		}
    41  	}
    42  	return vms
    43  }
    44  
    45  func (m *Manager) listVMs(writer *bufio.Writer, vms []*vmInfoType,
    46  	primaryOwnerFilter string, outputType uint) (map[string]struct{}, error) {
    47  	topology, err := m.getTopology()
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	var tw *html.TableWriter
    52  	if outputType == url.OutputTypeHtml {
    53  		fmt.Fprintf(writer, "<title>List of VMs</title>\n")
    54  		writer.WriteString(commonStyleSheet)
    55  		fmt.Fprintln(writer, `<table border="1" style="width:100%">`)
    56  		tw, _ = html.NewTableWriter(writer, true, "IP Addr", "Name(tag)",
    57  			"State", "RAM", "CPU", "Num Volumes", "Storage", "Primary Owner",
    58  			"Hypervisor", "Location")
    59  	}
    60  	primaryOwnersMap := make(map[string]struct{})
    61  	for _, vm := range vms {
    62  		if primaryOwnerFilter != "" {
    63  			if vm.OwnerUsers[0] != primaryOwnerFilter {
    64  				primaryOwnersMap[vm.OwnerUsers[0]] = struct{}{}
    65  				continue
    66  			}
    67  		} else {
    68  			primaryOwnersMap[vm.OwnerUsers[0]] = struct{}{}
    69  		}
    70  		switch outputType {
    71  		case url.OutputTypeText:
    72  			fmt.Fprintln(writer, vm.ipAddr)
    73  		case url.OutputTypeHtml:
    74  			var background, foreground string
    75  			if vm.hypervisor.probeStatus == probeStatusOff {
    76  				foreground = "#ff8080"
    77  			} else if vm.hypervisor.probeStatus != probeStatusConnected {
    78  				foreground = "red"
    79  			} else if vm.hypervisor.healthStatus == "at risk" {
    80  				foreground = "#c00000"
    81  			} else if vm.hypervisor.healthStatus == "marginal" {
    82  				foreground = "#800000"
    83  			}
    84  			if vm.Uncommitted {
    85  				background = "yellow"
    86  			} else if topology.CheckIfIpIsReserved(vm.ipAddr) {
    87  				background = "orange"
    88  			}
    89  			tw.WriteRow(foreground, background,
    90  				fmt.Sprintf("<a href=\"http://%s:%d/showVM?%s\">%s</a>",
    91  					vm.hypervisor.machine.Hostname,
    92  					constants.HypervisorPortNumber, vm.ipAddr, vm.ipAddr),
    93  				vm.Tags["Name"],
    94  				vm.State.String(),
    95  				format.FormatBytes(vm.MemoryInMiB<<20),
    96  				fmt.Sprintf("%g", float64(vm.MilliCPUs)*1e-3),
    97  				vm.numVolumesTableEntry(),
    98  				vm.storageTotalTableEntry(),
    99  				vm.OwnerUsers[0],
   100  				fmt.Sprintf("<a href=\"http://%s:%d/\">%s</a>",
   101  					vm.hypervisor.machine.Hostname,
   102  					constants.HypervisorPortNumber,
   103  					vm.hypervisor.machine.Hostname),
   104  				vm.hypervisor.location,
   105  			)
   106  		}
   107  	}
   108  	switch outputType {
   109  	case url.OutputTypeHtml:
   110  		fmt.Fprintln(writer, "</table>")
   111  	}
   112  	return primaryOwnersMap, nil
   113  }
   114  
   115  func (m *Manager) getVMs(doSort bool) []*vmInfoType {
   116  	m.mutex.RLock()
   117  	defer m.mutex.RUnlock()
   118  	return getVmListFromMap(m.vms, doSort)
   119  }
   120  
   121  func (m *Manager) listVMsHandler(w http.ResponseWriter,
   122  	req *http.Request) {
   123  	writer := bufio.NewWriter(w)
   124  	defer writer.Flush()
   125  	parsedQuery := url.ParseQuery(req.URL)
   126  	vms := m.getVMs(true)
   127  	if parsedQuery.OutputType() == url.OutputTypeJson {
   128  		json.WriteWithIndent(writer, "   ", vms)
   129  	}
   130  	primaryOwnerFilter := parsedQuery.Table["primaryOwner"]
   131  	primaryOwnersMap, err := m.listVMs(writer, vms, primaryOwnerFilter,
   132  		parsedQuery.OutputType())
   133  	if err != nil {
   134  		fmt.Fprintln(writer, err)
   135  		return
   136  	}
   137  	switch parsedQuery.OutputType() {
   138  	case url.OutputTypeHtml:
   139  		fmt.Fprintln(writer, "</body>")
   140  		primaryOwners := make([]string, 0, len(primaryOwnersMap))
   141  		for primaryOwner := range primaryOwnersMap {
   142  			primaryOwners = append(primaryOwners, primaryOwner)
   143  		}
   144  		sort.Strings(primaryOwners)
   145  		fmt.Fprintln(writer, "Filter by primary owner:<br>")
   146  		for _, primaryOwner := range primaryOwners {
   147  			fmt.Fprintf(writer,
   148  				"<a href=\"listVMs?primaryOwner=%s\">%s</a><br>\n",
   149  				primaryOwner, primaryOwner)
   150  		}
   151  	}
   152  }
   153  
   154  func (m *Manager) listVMsInLocation(dirname string) ([]net.IP, error) {
   155  	hypervisors, err := m.listHypervisors(dirname, showAll, "")
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	addresses := make([]net.IP, 0)
   160  	for _, hypervisor := range hypervisors {
   161  		hypervisor.mutex.RLock()
   162  		for _, vm := range hypervisor.vms {
   163  			addresses = append(addresses, vm.Address.IpAddress)
   164  		}
   165  		hypervisor.mutex.RUnlock()
   166  	}
   167  	return addresses, nil
   168  }
   169  
   170  func (vm *vmInfoType) numVolumesTableEntry() string {
   171  	var comment string
   172  	for _, volume := range vm.Volumes {
   173  		if comment == "" && volume.Format != proto.VolumeFormatRaw {
   174  			comment = `<font style="color:grey;font-size:12px"> (!RAW)</font>`
   175  		}
   176  	}
   177  	return fmt.Sprintf("%d%s", len(vm.Volumes), comment)
   178  }
   179  
   180  func (vm *vmInfoType) storageTotalTableEntry() string {
   181  	var storage uint64
   182  	for _, volume := range vm.Volumes {
   183  		storage += volume.Size
   184  	}
   185  	return format.FormatBytes(storage)
   186  }