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  }