diff --git a/microcloud/cmd/microcloud/ask.go b/microcloud/cmd/microcloud/ask.go index ec12a228f..bf51a6fb8 100644 --- a/microcloud/cmd/microcloud/ask.go +++ b/microcloud/cmd/microcloud/ask.go @@ -599,7 +599,7 @@ func (c *CmdControl) askNetwork(sh *service.Handler, systems map[string]InitSyst infos = append(infos, system.ServerInfo) } - allNetworks, err := sh.Services[types.LXD].(*service.LXDService).GetInterfaces(context.Background(), bootstrap, infos, service.UplinkInterface) + allNetworks, err := sh.Services[types.LXD].(*service.LXDService).GetInterfaces(context.Background(), bootstrap, infos, service.UnderlayInterface|service.UplinkInterface) if err != nil { return err } @@ -607,11 +607,13 @@ func (c *CmdControl) askNetwork(sh *service.Handler, systems map[string]InitSyst uplinkNetworks := make(map[string][]api.Network) for peer, networks := range allNetworks { for _, net := range networks { - _, ok := uplinkNetworks[peer] - if !ok { - uplinkNetworks[peer] = []api.Network{net.Network} - } else { - uplinkNetworks[peer] = append(uplinkNetworks[peer], net.Network) + if len(net.Addresses) == 0 { + _, ok := uplinkNetworks[peer] + if !ok { + uplinkNetworks[peer] = []api.Network{net.Network} + } else { + uplinkNetworks[peer] = append(uplinkNetworks[peer], net.Network) + } } } } @@ -832,5 +834,110 @@ func (c *CmdControl) askNetwork(sh *service.Handler, systems map[string]InitSyst systems[sh.Name] = bootstrapSystem } + // Underlay network selection table. + // Ask the user if they want an underlay network. + if bootstrap { + wantsDedicatedUnderlay, err := c.asker.AskBool("Configure dedicated underlay networking? (yes/no) [default=no]: ", "no") + if err != nil { + return err + } + + if !wantsDedicatedUnderlay { + return nil + } + } else { + // If the bootstrapped node has an underlay network, then we don't need to ask. Else, return. + customUnderlayEnabled := false + for _, system := range systems { + if system.OVNGeneveAddr != "" { + customUnderlayEnabled = true + break + } + } + + if !customUnderlayEnabled { + return nil + } + } + + underlayNetworks := make(map[string][]service.NetworkWithAllocatedIPs) + for peer, networks := range allNetworks { + for _, net := range networks { + if len(net.Addresses) != 0 { + _, ok := underlayNetworks[peer] + if !ok { + underlayNetworks[peer] = []service.NetworkWithAllocatedIPs{net} + } else { + underlayNetworks[peer] = append(underlayNetworks[peer], net) + } + } + } + } + + if len(underlayNetworks) != len(systems) { + fmt.Println("Not enough interfaces available to create an underlay network, skipping") + return nil + } + + for peer, nets := range underlayNetworks { + if len(nets) == 0 { + fmt.Printf("Not enough interfaces available on %q to configure the underlay network, skipping\n", peer) + return nil + } + } + + header = []string{"LOCATION", "IFACE", "TYPE", "IP ADDRESS (CIDR)"} + fmt.Println("Select exactly one network interface from each cluster member:") + data = [][]string{} + for peer, nets := range underlayNetworks { + for _, net := range nets { + for _, addr := range net.Addresses { + data = append(data, []string{peer, net.Network.Name, net.Network.Type, addr}) + } + } + } + + table = NewSelectableTable(header, data) + selected = map[string]string{} + c.askRetry("Retry selecting underlay network interfaces?", autoSetup, func() error { + err = table.Render(table.rows) + if err != nil { + return err + } + + answers, err := table.GetSelections() + if err != nil { + return err + } + + selected = map[string]string{} + for _, answer := range answers { + target := table.SelectionValue(answer, "LOCATION") + ipAddr := table.SelectionValue(answer, "IP ADDRESS (CIDR)") + + if selected[target] != "" { + return fmt.Errorf("Failed to configure OVN underlay traffic: Selected more than one interface for target %q", target) + } + + selected[target] = ipAddr + } + + if len(selected) != len(underlayNetworks) { + return fmt.Errorf("Failed to configure OVN underlay traffic: Some peers don't have a selected interface") + } + + return nil + }) + + for peer, ipAddr := range selected { + system := systems[peer] + ip, _, err := net.ParseCIDR(ipAddr) + if err != nil { + return err + } + + system.OVNGeneveAddr = ip.String() + } + return nil }