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

     1  package fsstorer
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  	"strconv"
    12  	"syscall"
    13  
    14  	"github.com/Cloud-Foundations/Dominator/lib/fsutil"
    15  	"github.com/Cloud-Foundations/Dominator/lib/tags"
    16  )
    17  
    18  const (
    19  	dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP |
    20  		syscall.S_IROTH | syscall.S_IXOTH
    21  	filePerms = syscall.S_IRUSR | syscall.S_IWUSR | syscall.S_IRGRP |
    22  		syscall.S_IROTH
    23  )
    24  
    25  func (s *Storer) addIPsForHypervisor(hypervisor net.IP,
    26  	netAddrs []net.IP) error {
    27  	hypervisorIP, err := netIpToIp(hypervisor)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	addrs := make([]IP, 0, len(netAddrs))
    32  	for _, addr := range netAddrs {
    33  		if ip, err := netIpToIp(addr); err != nil {
    34  			return err
    35  		} else {
    36  			addrs = append(addrs, ip)
    37  		}
    38  	}
    39  	newAddrs := make([]IP, 0, len(addrs))
    40  	s.mutex.Lock()
    41  	defer s.mutex.Unlock()
    42  	for _, addr := range addrs {
    43  		if hIP, ok := s.ipToHypervisor[addr]; !ok {
    44  			s.ipToHypervisor[addr] = hypervisorIP
    45  			newAddrs = append(newAddrs, addr)
    46  		} else {
    47  			if hIP != hypervisorIP {
    48  				return fmt.Errorf("cannot move IP: %s from: %s", addr, hIP)
    49  			}
    50  		}
    51  	}
    52  	if len(newAddrs) < 1 {
    53  		return nil // No changes.
    54  	}
    55  	err = s.writeIPsForHypervisor(hypervisorIP, addrs, os.O_APPEND)
    56  	if err != nil {
    57  		for _, addr := range newAddrs {
    58  			delete(s.ipToHypervisor, addr)
    59  		}
    60  		return err
    61  	}
    62  	s.hypervisorToIPs[hypervisorIP] = append(s.hypervisorToIPs[hypervisorIP],
    63  		newAddrs...)
    64  	return nil
    65  }
    66  
    67  func (s *Storer) getHypervisorDirectory(hypervisor IP) string {
    68  	return filepath.Join(s.topDir,
    69  		strconv.FormatUint(uint64(hypervisor[0]), 10),
    70  		strconv.FormatUint(uint64(hypervisor[1]), 10),
    71  		strconv.FormatUint(uint64(hypervisor[2]), 10),
    72  		strconv.FormatUint(uint64(hypervisor[3]), 10))
    73  }
    74  
    75  func (s *Storer) setIPsForHypervisor(hypervisor net.IP,
    76  	netAddrs []net.IP) error {
    77  	hypervisorIP, err := netIpToIp(hypervisor)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	addrs := make([]IP, 0, len(netAddrs))
    82  	for _, addr := range netAddrs {
    83  		if ip, err := netIpToIp(addr); err != nil {
    84  			return err
    85  		} else {
    86  			addrs = append(addrs, ip)
    87  		}
    88  	}
    89  	addrsToForget := make(map[IP]struct{})
    90  	s.mutex.Lock()
    91  	defer s.mutex.Unlock()
    92  	for _, addr := range s.hypervisorToIPs[hypervisorIP] {
    93  		addrsToForget[addr] = struct{}{}
    94  	}
    95  	addedSome := false
    96  	for _, addr := range addrs {
    97  		delete(addrsToForget, addr)
    98  		if hIP, ok := s.ipToHypervisor[addr]; !ok {
    99  			s.ipToHypervisor[addr] = hypervisorIP
   100  			addedSome = true
   101  		} else {
   102  			if hIP != hypervisorIP {
   103  				return fmt.Errorf("cannot move IP: %s from: %s", addr, hIP)
   104  			}
   105  		}
   106  	}
   107  	if !addedSome && len(addrsToForget) < 1 {
   108  		return nil // No changes.
   109  	}
   110  	err = s.writeIPsForHypervisor(hypervisorIP, addrs, os.O_TRUNC)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	for addr := range addrsToForget {
   115  		delete(s.ipToHypervisor, addr)
   116  	}
   117  	s.hypervisorToIPs[hypervisorIP] = addrs
   118  	return nil
   119  }
   120  
   121  func (s *Storer) unregisterHypervisor(hypervisor net.IP) error {
   122  	hypervisorIP, err := netIpToIp(hypervisor)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	dirname := s.getHypervisorDirectory(hypervisorIP)
   127  	s.mutex.Lock()
   128  	defer s.mutex.Unlock()
   129  	if err := os.RemoveAll(dirname); err != nil {
   130  		return err
   131  	}
   132  	for _, ip := range s.hypervisorToIPs[hypervisorIP] {
   133  		delete(s.ipToHypervisor, ip)
   134  	}
   135  	delete(s.hypervisorToIPs, hypervisorIP)
   136  	return nil
   137  }
   138  
   139  func (s *Storer) writeIPsForHypervisor(hypervisor IP, ipList []IP,
   140  	flags int) error {
   141  	dirname := s.getHypervisorDirectory(hypervisor)
   142  	if dirfile, err := os.Open(dirname); err != nil {
   143  		if err := os.MkdirAll(dirname, dirPerms); err != nil {
   144  			return err
   145  		}
   146  	} else {
   147  		dirfile.Close()
   148  	}
   149  	return writeIpList(filepath.Join(dirname, "ip-list.raw"), ipList, flags)
   150  }
   151  
   152  func (s *Storer) writeMachineSerialNumber(hypervisor net.IP,
   153  	serialNumber string) error {
   154  	hypervisorIP, err := netIpToIp(hypervisor)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	dirname := s.getHypervisorDirectory(hypervisorIP)
   159  	filename := filepath.Join(dirname, "serial-number")
   160  	if len(serialNumber) < 1 {
   161  		if err := os.Remove(filename); err != nil && !os.IsNotExist(err) {
   162  			return err
   163  		}
   164  		return nil
   165  	}
   166  	file, err := fsutil.CreateRenamingWriter(filename, filePerms)
   167  	if err != nil {
   168  		if !os.IsNotExist(err) {
   169  			return err
   170  		}
   171  		return nil
   172  	}
   173  	defer file.Close()
   174  	if _, err := fmt.Fprintln(file, serialNumber); err != nil {
   175  		return err
   176  	}
   177  	return nil
   178  }
   179  
   180  func (s *Storer) writeMachineTags(hypervisor net.IP, tgs tags.Tags) error {
   181  	hypervisorIP, err := netIpToIp(hypervisor)
   182  	if err != nil {
   183  		return err
   184  	}
   185  	dirname := s.getHypervisorDirectory(hypervisorIP)
   186  	filename := filepath.Join(dirname, "tags.raw")
   187  	if len(tgs) < 1 {
   188  		if err := os.Remove(filename); err != nil && !os.IsNotExist(err) {
   189  			return err
   190  		}
   191  		return nil
   192  	}
   193  	keys := make([]string, 0, len(tgs))
   194  	for key := range tgs {
   195  		keys = append(keys, key)
   196  	}
   197  	sort.Strings(keys)
   198  	file, err := fsutil.CreateRenamingWriter(filename, filePerms)
   199  	if err != nil {
   200  		if !os.IsNotExist(err) {
   201  			return err
   202  		}
   203  		return nil
   204  	}
   205  	defer file.Close()
   206  	writer := bufio.NewWriter(file)
   207  	for _, key := range keys {
   208  		if _, err := writer.WriteString(key + "\n"); err != nil {
   209  			return err
   210  		}
   211  		if _, err := writer.WriteString(tgs[key] + "\n"); err != nil {
   212  			return err
   213  		}
   214  	}
   215  	return writer.Flush()
   216  }
   217  
   218  func writeIpList(filename string, ipList []IP, flags int) error {
   219  	file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|flags, filePerms)
   220  	if err != nil {
   221  		return err
   222  	}
   223  	defer file.Close()
   224  	writer := bufio.NewWriter(file)
   225  	defer writer.Flush()
   226  	for _, ip := range ipList {
   227  		if nWritten, err := writer.Write(ip[:]); err != nil {
   228  			return err
   229  		} else if nWritten != len(ip) {
   230  			return errors.New("short write")
   231  		}
   232  	}
   233  	if err := writer.Flush(); err != nil {
   234  		return err
   235  	}
   236  	return file.Close()
   237  }