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 }