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