github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/mdbd/loadFleetManager.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "sync" 7 "time" 8 9 "github.com/Cloud-Foundations/Dominator/lib/constants" 10 "github.com/Cloud-Foundations/Dominator/lib/log" 11 "github.com/Cloud-Foundations/Dominator/lib/mdb" 12 "github.com/Cloud-Foundations/Dominator/lib/srpc" 13 fm_proto "github.com/Cloud-Foundations/Dominator/proto/fleetmanager" 14 hyper_proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 15 ) 16 17 type fleetManagerGeneratorType struct { 18 eventChannel chan<- struct{} 19 fleetManager string 20 location string 21 logger log.DebugLogger 22 mutex sync.Mutex 23 machines map[string]*fm_proto.Machine // Key: Hostname 24 vmToHypervisor map[string]string // Key: VM IP, Value: Hostname 25 vms map[string]*hyper_proto.VmInfo 26 } 27 28 func newFleetManagerGenerator(params makeGeneratorParams) (generator, error) { 29 g := &fleetManagerGeneratorType{ 30 eventChannel: params.eventChannel, 31 fleetManager: fmt.Sprintf("%s:%d", 32 params.args[0], constants.FleetManagerPortNumber), 33 logger: params.logger, 34 machines: make(map[string]*fm_proto.Machine), 35 vmToHypervisor: make(map[string]string), 36 vms: make(map[string]*hyper_proto.VmInfo), 37 } 38 if len(params.args) > 1 { 39 g.location = params.args[1] 40 } 41 params.waitGroup.Add(1) 42 go g.daemon(params.waitGroup) 43 return g, nil 44 } 45 46 func (g *fleetManagerGeneratorType) daemon(waitGroup *sync.WaitGroup) { 47 for { 48 if err := g.getUpdates(g.fleetManager, waitGroup); err != nil { 49 g.logger.Println(err) 50 time.Sleep(time.Second) 51 } 52 waitGroup = nil 53 } 54 } 55 56 func (g *fleetManagerGeneratorType) getUpdates(fleetManager string, 57 waitGroup *sync.WaitGroup) error { 58 client, err := srpc.DialHTTP("tcp", g.fleetManager, 0) 59 if err != nil { 60 return err 61 } 62 defer client.Close() 63 conn, err := client.Call("FleetManager.GetUpdates") 64 if err != nil { 65 return err 66 } 67 defer conn.Close() 68 request := fm_proto.GetUpdatesRequest{Location: g.location} 69 if err := conn.Encode(request); err != nil { 70 return err 71 } 72 if err := conn.Flush(); err != nil { 73 return err 74 } 75 initialUpdate := true 76 for { 77 var update fm_proto.Update 78 if err := conn.Decode(&update); err != nil { 79 return err 80 } 81 g.update(update, initialUpdate) 82 initialUpdate = false 83 if waitGroup != nil { 84 waitGroup.Done() 85 waitGroup = nil 86 } 87 select { 88 case g.eventChannel <- struct{}{}: 89 default: 90 } 91 } 92 } 93 94 func (g *fleetManagerGeneratorType) Generate(unused_datacentre string, 95 logger log.DebugLogger) (*mdb.Mdb, error) { 96 var newMdb mdb.Mdb 97 g.mutex.Lock() 98 defer g.mutex.Unlock() 99 for _, machine := range g.machines { 100 var ipAddr string 101 if len(machine.HostIpAddress) > 0 { 102 ipAddr = machine.HostIpAddress.String() 103 } 104 tags := machine.Tags 105 if tags == nil { 106 tags = emptyTags 107 } 108 _, disableUpdates := tags["DisableUpdates"] 109 newMdb.Machines = append(newMdb.Machines, mdb.Machine{ 110 Hostname: machine.Hostname, 111 IpAddress: ipAddr, 112 Location: machine.Location, 113 OwnerGroups: machine.OwnerGroups, 114 OwnerUsers: machine.OwnerUsers, 115 RequiredImage: tags["RequiredImage"], 116 PlannedImage: tags["PlannedImage"], 117 DisableUpdates: disableUpdates, 118 Tags: machine.Tags, 119 }) 120 } 121 for ipAddr, vm := range g.vms { 122 if vm.State == hyper_proto.StateRunning { 123 tags := vm.Tags 124 if tags == nil { 125 tags = emptyTags 126 } 127 _, disableUpdates := tags["DisableUpdates"] 128 var ownerGroup string 129 if len(vm.OwnerGroups) > 0 { 130 ownerGroup = vm.OwnerGroups[0] 131 } 132 machine := mdb.Machine{ 133 Hostname: ipAddr, 134 IpAddress: ipAddr, 135 RequiredImage: tags["RequiredImage"], 136 PlannedImage: tags["PlannedImage"], 137 DisableUpdates: disableUpdates, 138 OwnerGroup: ownerGroup, 139 Tags: vm.Tags, 140 } 141 if h := g.machines[g.vmToHypervisor[ipAddr]]; h != nil { 142 machine.Location = filepath.Join(h.Location, h.Hostname) 143 } 144 newMdb.Machines = append(newMdb.Machines, machine) 145 } 146 } 147 return &newMdb, nil 148 } 149 150 func (g *fleetManagerGeneratorType) update(update fm_proto.Update, 151 initialUpdate bool) { 152 machinesToDelete := make(map[string]struct{}, len(g.machines)) 153 vmsToDelete := make(map[string]struct{}, len(g.vms)) 154 if initialUpdate { 155 for hostname := range g.machines { 156 machinesToDelete[hostname] = struct{}{} 157 } 158 for ipAddr := range g.vms { 159 vmsToDelete[ipAddr] = struct{}{} 160 } 161 } 162 g.mutex.Lock() 163 defer g.mutex.Unlock() 164 for _, machine := range update.ChangedMachines { 165 g.machines[machine.Hostname] = machine 166 delete(machinesToDelete, machine.Hostname) 167 } 168 for _, hostname := range update.DeletedMachines { 169 delete(g.machines, hostname) 170 } 171 for hostname := range machinesToDelete { 172 delete(g.machines, hostname) 173 } 174 for ipAddr, vm := range update.ChangedVMs { 175 g.vmToHypervisor[ipAddr] = update.VmToHypervisor[ipAddr] 176 g.vms[ipAddr] = vm 177 delete(vmsToDelete, ipAddr) 178 } 179 for _, ipAddr := range update.DeletedVMs { 180 delete(g.vms, ipAddr) 181 } 182 for ipAddr := range vmsToDelete { 183 delete(g.vmToHypervisor, ipAddr) 184 delete(g.vms, ipAddr) 185 } 186 }