github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/mdbd/loadHypervisor.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/Cloud-Foundations/Dominator/lib/constants"
     9  	"github.com/Cloud-Foundations/Dominator/lib/log"
    10  	"github.com/Cloud-Foundations/Dominator/lib/mdb"
    11  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    12  	proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor"
    13  )
    14  
    15  var emptyTags = make(map[string]string)
    16  
    17  type hypervisorGeneratorType struct {
    18  	logger       log.DebugLogger
    19  	eventChannel chan<- struct{}
    20  	mutex        sync.Mutex
    21  	vms          map[string]*proto.VmInfo
    22  }
    23  
    24  func newHypervisorGenerator(args []string,
    25  	logger log.DebugLogger) (generator, error) {
    26  	g := &hypervisorGeneratorType{
    27  		logger: logger,
    28  		vms:    make(map[string]*proto.VmInfo),
    29  	}
    30  	go g.daemon()
    31  	return g, nil
    32  }
    33  
    34  func (g *hypervisorGeneratorType) daemon() {
    35  	address := fmt.Sprintf(":%d", constants.HypervisorPortNumber)
    36  	for {
    37  		if err := g.getUpdates(address); err != nil {
    38  			g.logger.Println(err)
    39  			time.Sleep(time.Second)
    40  		}
    41  	}
    42  }
    43  
    44  func (g *hypervisorGeneratorType) getUpdates(hypervisor string) error {
    45  	client, err := srpc.DialHTTP("tcp", hypervisor, 0)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	defer client.Close()
    50  	conn, err := client.Call("Hypervisor.GetUpdates")
    51  	if err != nil {
    52  		return err
    53  	}
    54  	defer conn.Close()
    55  	initialUpdate := true
    56  	for {
    57  		var update proto.Update
    58  		if err := conn.Decode(&update); err != nil {
    59  			return err
    60  		}
    61  		g.updateVMs(update.VMs, initialUpdate)
    62  		initialUpdate = false
    63  		select {
    64  		case g.eventChannel <- struct{}{}:
    65  		default:
    66  		}
    67  	}
    68  }
    69  
    70  func (g *hypervisorGeneratorType) Generate(unused_datacentre string,
    71  	logger log.Logger) (*mdb.Mdb, error) {
    72  	var newMdb mdb.Mdb
    73  	g.mutex.Lock()
    74  	defer g.mutex.Unlock()
    75  	for ipAddr, vm := range g.vms {
    76  		if vm.State == proto.StateRunning {
    77  			tags := vm.Tags
    78  			if tags == nil {
    79  				tags = emptyTags
    80  			}
    81  			_, disableUpdates := tags["DisableUpdates"]
    82  			var ownerGroup string
    83  			if len(vm.OwnerGroups) > 0 {
    84  				ownerGroup = vm.OwnerGroups[0]
    85  			}
    86  			newMdb.Machines = append(newMdb.Machines, mdb.Machine{
    87  				Hostname:       ipAddr,
    88  				IpAddress:      ipAddr,
    89  				RequiredImage:  tags["RequiredImage"],
    90  				PlannedImage:   tags["PlannedImage"],
    91  				DisableUpdates: disableUpdates,
    92  				OwnerGroup:     ownerGroup,
    93  				Tags:           vm.Tags,
    94  			})
    95  		}
    96  	}
    97  	return &newMdb, nil
    98  }
    99  
   100  func (g *hypervisorGeneratorType) RegisterEventChannel(events chan<- struct{}) {
   101  	g.eventChannel = events
   102  }
   103  
   104  func (g *hypervisorGeneratorType) updateVMs(vms map[string]*proto.VmInfo,
   105  	initialUpdate bool) {
   106  	vmsToDelete := make(map[string]struct{}, len(g.vms))
   107  	if initialUpdate {
   108  		for ipAddr := range g.vms {
   109  			vmsToDelete[ipAddr] = struct{}{}
   110  		}
   111  	}
   112  	g.mutex.Lock()
   113  	defer g.mutex.Unlock()
   114  	for ipAddr, vm := range vms {
   115  		if vm == nil || len(vm.Volumes) < 1 {
   116  			delete(g.vms, ipAddr)
   117  		} else {
   118  			g.vms[ipAddr] = vm
   119  			delete(vmsToDelete, ipAddr)
   120  		}
   121  	}
   122  	for ipAddr := range vmsToDelete {
   123  		delete(g.vms, ipAddr)
   124  	}
   125  }