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  }