github.com/Cloud-Foundations/Dominator@v0.3.4/hypervisor/manager/subnets.go (about) 1 package manager 2 3 import ( 4 "flag" 5 "fmt" 6 "net" 7 "os" 8 "path" 9 "sort" 10 11 "github.com/Cloud-Foundations/Dominator/lib/fsutil" 12 "github.com/Cloud-Foundations/Dominator/lib/json" 13 "github.com/Cloud-Foundations/Dominator/lib/net/util" 14 "github.com/Cloud-Foundations/Dominator/lib/srpc" 15 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 16 ) 17 18 var ( 19 addHypervisorSubnet = flag.Bool("addHypervisorSubnet", false, 20 "If true, automatically add the subnet for the default gateway (deprecated)") 21 ) 22 23 func checkSubnetAccess(subnet proto.Subnet, 24 authInfo *srpc.AuthInformation) bool { 25 if authInfo.HaveMethodAccess { 26 return true 27 } 28 if len(subnet.AllowedUsers) < 1 && len(subnet.AllowedGroups) < 1 { 29 return true 30 } 31 for _, allowedUser := range subnet.AllowedUsers { 32 if authInfo.Username == allowedUser { 33 return true 34 } 35 } 36 for _, allowedGroup := range subnet.AllowedGroups { 37 if _, ok := authInfo.GroupList[allowedGroup]; ok { 38 return true 39 } 40 } 41 return false 42 } 43 44 func getHypervisorSubnet() (proto.Subnet, error) { 45 defaultRoute, err := util.GetDefaultRoute() 46 if err != nil { 47 return proto.Subnet{}, err 48 } 49 resolverConfig, err := util.GetResolverConfiguration() 50 if err != nil { 51 return proto.Subnet{}, err 52 } 53 myIP, err := util.GetMyIP() 54 if err != nil { 55 return proto.Subnet{}, err 56 } 57 nameservers := make([]net.IP, 0, len(resolverConfig.Nameservers)) 58 for _, nameserver := range resolverConfig.Nameservers { 59 if nameserver[0] == 127 { 60 nameservers = append(nameservers, myIP) 61 } else { 62 nameservers = append(nameservers, nameserver) 63 } 64 } 65 return proto.Subnet{ 66 Id: "hypervisor", 67 IpGateway: defaultRoute.Address, 68 IpMask: net.IP(defaultRoute.Mask), 69 DomainNameServers: nameservers, 70 }, nil 71 } 72 73 func (m *Manager) getBridgeForSubnet(subnet proto.Subnet) ( 74 string, string, error) { 75 mapName := fmt.Sprintf("br@%s", subnet.Id) 76 if _, ok := m.BridgeMap[mapName]; ok { 77 return mapName, "", nil 78 } else if bridge, ok := m.VlanIdToBridge[subnet.VlanId]; ok { 79 return bridge, "", nil 80 } else if bridge, ok = m.VlanIdToBridge[0]; ok { 81 return bridge, fmt.Sprintf(",vlan=%d", subnet.VlanId), nil 82 } else { 83 return "", "", fmt.Errorf("no usable bridge") 84 } 85 } 86 87 // This must be called with the lock held. 88 func (m *Manager) getMatchingSubnet(ipAddr net.IP) string { 89 if len(ipAddr) > 0 { 90 for id, subnet := range m.subnets { 91 subnetMask := net.IPMask(subnet.IpMask) 92 subnetAddr := subnet.IpGateway.Mask(subnetMask) 93 if ipAddr.Mask(subnetMask).Equal(subnetAddr) { 94 return id 95 } 96 } 97 } 98 return "" 99 } 100 101 // This must be called with the lock held. 102 func (m *Manager) getSubnetAndAuth(subnetId string, 103 authInfo *srpc.AuthInformation) (proto.Subnet, error) { 104 if len(m.subnets) < 1 { 105 return proto.Subnet{}, fmt.Errorf("no subnets exist") 106 } 107 if subnetId != "" { 108 if subnet, ok := m.subnets[subnetId]; !ok { 109 return proto.Subnet{}, fmt.Errorf("subnet: %s does not exist", 110 subnetId) 111 } else if !checkSubnetAccess(subnet, authInfo) { 112 return proto.Subnet{}, fmt.Errorf("no access to subnet: %s", 113 subnetId) 114 } else { 115 return subnet, nil 116 } 117 } 118 // Unspecified subnet: try to find one. 119 if len(m.subnets) == 1 { 120 if subnet, ok := m.subnets["hypervisor"]; !ok { 121 return proto.Subnet{}, fmt.Errorf( 122 "hypervisor subnet does not exist") 123 } else { 124 return subnet, nil 125 } 126 } 127 subnetsPermitted := make([]string, 0, 1) 128 for _, subnet := range m.subnets { 129 if subnet.Id == "hypervisor" { 130 continue 131 } 132 if !checkSubnetAccess(subnet, authInfo) { 133 continue 134 } 135 if len(subnetsPermitted) > 0 { 136 return proto.Subnet{}, fmt.Errorf( 137 "multiple available subnets: pick one") 138 } 139 subnetsPermitted = append(subnetsPermitted, subnet.Id) 140 } 141 if len(subnetsPermitted) < 1 { 142 return proto.Subnet{}, fmt.Errorf("no subnets permitted") 143 } 144 return m.subnets[subnetsPermitted[0]], nil 145 } 146 147 func (m *Manager) listSubnets(doSort bool) []proto.Subnet { 148 m.mutex.Lock() 149 defer m.mutex.Unlock() 150 subnets := make([]proto.Subnet, 0, len(m.subnets)) 151 if !doSort { 152 for _, subnet := range m.subnets { 153 subnets = append(subnets, subnet) 154 } 155 return subnets 156 } 157 subnetIDs := make([]string, 0, len(m.subnets)) 158 for subnetID := range m.subnets { 159 subnetIDs = append(subnetIDs, subnetID) 160 } 161 sort.Strings(subnetIDs) 162 for _, subnetID := range subnetIDs { 163 subnets = append(subnets, m.subnets[subnetID]) 164 } 165 return subnets 166 } 167 168 // This returns with the Manager locked, waiting for existing subnets to be 169 // drained from the channel by the caller before unlocking. 170 func (m *Manager) makeSubnetChannel() <-chan proto.Subnet { 171 ch := make(chan proto.Subnet, 1) 172 m.mutex.Lock() 173 m.subnetChannels = append(m.subnetChannels, ch) 174 go func() { 175 defer m.mutex.Unlock() 176 for _, subnet := range m.subnets { 177 ch <- subnet 178 } 179 }() 180 return ch 181 } 182 183 func (m *Manager) loadSubnets() error { 184 var subnets []proto.Subnet 185 err := json.ReadFromFile(path.Join(m.StateDir, "subnets.json"), &subnets) 186 if err != nil && !os.IsNotExist(err) { 187 return err 188 } 189 for index := range subnets { 190 subnets[index].Shrink() 191 } 192 m.subnets = make(map[string]proto.Subnet, len(subnets)+1) 193 for _, subnet := range subnets { 194 m.subnets[subnet.Id] = subnet 195 } 196 if *addHypervisorSubnet { 197 if subnet, err := getHypervisorSubnet(); err != nil { 198 return err 199 } else { 200 m.subnets["hypervisor"] = subnet 201 } 202 } 203 for _, subnet := range m.subnets { 204 m.DhcpServer.AddSubnet(subnet) 205 } 206 return nil 207 } 208 209 func (m *Manager) updateSubnets(request proto.UpdateSubnetsRequest) error { 210 for index, subnet := range request.Add { 211 if subnet.Id == "hypervisor" { 212 return fmt.Errorf("cannot add hypervisor subnet") 213 } 214 request.Add[index].Shrink() 215 } 216 for index, subnet := range request.Change { 217 if subnet.Id == "hypervisor" { 218 return fmt.Errorf("cannot change hypervisor subnet") 219 } 220 request.Change[index].Shrink() 221 } 222 for _, subnetId := range request.Delete { 223 if subnetId == "hypervisor" { 224 return fmt.Errorf("cannot delete hypervisor subnet") 225 } 226 } 227 if err := m.updateSubnetsLocked(request); err != nil { 228 return err 229 } 230 for _, subnet := range request.Add { 231 m.DhcpServer.AddSubnet(subnet) 232 for _, ch := range m.subnetChannels { 233 ch <- subnet 234 } 235 } 236 for _, subnet := range request.Change { 237 m.DhcpServer.RemoveSubnet(subnet.Id) 238 m.DhcpServer.AddSubnet(subnet) 239 // TOOO(rgooch): Design a clean way to send updates to the channels. 240 } 241 for _, subnetId := range request.Delete { 242 m.DhcpServer.RemoveSubnet(subnetId) 243 // TOOO(rgooch): Design a clean way to send deletes to the channels. 244 } 245 return nil 246 } 247 248 func (m *Manager) updateSubnetsLocked( 249 request proto.UpdateSubnetsRequest) error { 250 m.mutex.Lock() 251 defer m.mutex.Unlock() 252 for _, subnet := range request.Add { 253 if _, ok := m.subnets[subnet.Id]; ok { 254 return fmt.Errorf("subnet: %s already exists", subnet.Id) 255 } 256 } 257 for _, subnet := range request.Change { 258 if _, ok := m.subnets[subnet.Id]; !ok { 259 return fmt.Errorf("subnet: %s does not exist", subnet.Id) 260 } 261 } 262 for _, subnetId := range request.Delete { 263 if _, ok := m.subnets[subnetId]; !ok { 264 return fmt.Errorf("subnet: %s does not exist", subnetId) 265 } 266 } 267 for _, subnet := range request.Add { 268 m.subnets[subnet.Id] = subnet 269 } 270 for _, subnet := range request.Change { 271 m.subnets[subnet.Id] = subnet 272 } 273 for _, subnetId := range request.Delete { 274 delete(m.subnets, subnetId) 275 } 276 subnetsToWrite := make([]proto.Subnet, 0, len(m.subnets)-1) 277 for _, subnet := range m.subnets { 278 if subnet.Id != "hypervisor" { 279 subnetsToWrite = append(subnetsToWrite, subnet) 280 } 281 } 282 // TODO(rgooch): Should precompute the numFreeAddresses map. 283 numFreeAddresses, err := m.computeNumFreeAddressesMap(m.addressPool) 284 if err != nil { 285 return err 286 } 287 err = json.WriteToFile(path.Join(m.StateDir, "subnets.json"), 288 fsutil.PublicFilePerms, " ", subnetsToWrite) 289 if err != nil { 290 return err 291 } 292 // Make a copy, since these will be sent over a channel. 293 registered := make([]proto.Address, 0, len(m.addressPool.Registered)) 294 for _, addr := range m.addressPool.Registered { 295 registered = append(registered, addr) 296 } 297 m.sendUpdate( 298 proto.Update{ 299 HaveAddressPool: true, 300 AddressPool: registered, 301 NumFreeAddresses: numFreeAddresses, 302 HaveSubnets: true, 303 Subnets: subnetsToWrite, 304 }) 305 return nil 306 }