Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Candidate cherry picks (v1-edge) #577

Merged
merged 12 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions microcloud/cmd/microcloud/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type cmdAdd struct {

flagAutoSetup bool
flagWipe bool
flagPreseed string
flagPreseed bool
}

func (c *cmdAdd) Command() *cobra.Command {
Expand All @@ -29,7 +29,7 @@ func (c *cmdAdd) Command() *cobra.Command {

cmd.Flags().BoolVar(&c.flagAutoSetup, "auto", false, "Automatic setup with default configuration")
cmd.Flags().BoolVar(&c.flagWipe, "wipe", false, "Wipe disks to add to MicroCeph")
cmd.Flags().StringVar(&c.flagPreseed, "preseed", "", "Preseed YAML for configuring MicroCloud")
cmd.Flags().BoolVar(&c.flagPreseed, "preseed", false, "Expect Preseed YAML for configuring MicroCloud in stdin")

return cmd
}
Expand All @@ -39,8 +39,8 @@ func (c *cmdAdd) Run(cmd *cobra.Command, args []string) error {
return cmd.Help()
}

if c.flagPreseed != "" {
return c.common.RunPreseed(cmd, c.flagPreseed, false)
if c.flagPreseed {
return c.common.RunPreseed(cmd, false)
}

cloudApp, err := microcluster.App(context.Background(), microcluster.Args{StateDir: c.common.FlagMicroCloudDir})
Expand All @@ -57,7 +57,7 @@ func (c *cmdAdd) Run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("MicroCloud is uninitialized, run 'microcloud init' first")
}

addr, subnet, err := c.common.askAddress(c.flagAutoSetup, status.Address.Addr().String())
addr, iface, subnet, err := c.common.askAddress(c.flagAutoSetup, status.Address.Addr().String())
if err != nil {
return err
}
Expand All @@ -79,7 +79,7 @@ func (c *cmdAdd) Run(cmd *cobra.Command, args []string) error {
}

systems := map[string]InitSystem{}
err = lookupPeers(s, c.flagAutoSetup, subnet, nil, systems)
err = lookupPeers(s, c.flagAutoSetup, iface, subnet, nil, systems)
if err != nil {
return err
}
Expand Down
18 changes: 9 additions & 9 deletions microcloud/cmd/microcloud/ask.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,22 @@ func (c *CmdControl) askMissingServices(services []types.ServiceType, stateDirs
return services, nil
}

func (c *CmdControl) askAddress(autoSetup bool, listenAddr string) (string, *net.IPNet, error) {
func (c *CmdControl) askAddress(autoSetup bool, listenAddr string) (string, *net.Interface, *net.IPNet, error) {
info, err := mdns.GetNetworkInfo()
if err != nil {
return "", nil, fmt.Errorf("Failed to find network interfaces: %w", err)
return "", nil, nil, fmt.Errorf("Failed to find network interfaces: %w", err)
}

if listenAddr == "" {
if len(info) == 0 {
return "", nil, fmt.Errorf("Found no valid network interfaces")
return "", nil, nil, fmt.Errorf("Found no valid network interfaces")
}

listenAddr = info[0].Address
if !autoSetup && len(info) > 1 {
data := make([][]string, 0, len(info))
for _, net := range info {
data = append(data, []string{net.Address, net.Interface})
data = append(data, []string{net.Address, net.Interface.Name})
}

table := NewSelectableTable([]string{"ADDRESS", "IFACE"}, data)
Expand Down Expand Up @@ -119,31 +119,31 @@ func (c *CmdControl) askAddress(autoSetup bool, listenAddr string) (string, *net
}

var subnet *net.IPNet

var iface *net.Interface
for _, network := range info {
if network.Subnet.Contains(net.ParseIP(listenAddr)) {
subnet = network.Subnet

iface = &network.Interface
break
}
}

if subnet == nil {
return "", nil, fmt.Errorf("Cloud not find valid subnet for address %q", listenAddr)
return "", nil, nil, fmt.Errorf("Cloud not find valid subnet for address %q", listenAddr)
}

if !autoSetup {
filter, err := c.asker.AskBool(fmt.Sprintf("Limit search for other MicroCloud servers to %s? (yes/no) [default=yes]: ", subnet.String()), "yes")
if err != nil {
return "", nil, err
return "", nil, nil, err
}

if !filter {
subnet = nil
}
}

return listenAddr, subnet, nil
return listenAddr, iface, subnet, nil
}

func (c *CmdControl) askDisks(sh *service.Handler, systems map[string]InitSystem, autoSetup bool, wipeAllDisks bool) error {
Expand Down
16 changes: 8 additions & 8 deletions microcloud/cmd/microcloud/main_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type cmdInit struct {
flagAutoSetup bool
flagWipeAllDisks bool
flagAddress string
flagPreseed string
flagPreseed bool
}

func (c *cmdInit) Command() *cobra.Command {
Expand All @@ -62,7 +62,7 @@ func (c *cmdInit) Command() *cobra.Command {
cmd.Flags().BoolVar(&c.flagAutoSetup, "auto", false, "Automatic setup with default configuration")
cmd.Flags().BoolVar(&c.flagWipeAllDisks, "wipe", false, "Wipe disks to add to MicroCeph")
cmd.Flags().StringVar(&c.flagAddress, "address", "", "Address to use for MicroCloud")
cmd.Flags().StringVar(&c.flagPreseed, "preseed", "", "Preseed YAML for configuring MicroCloud")
cmd.Flags().BoolVar(&c.flagPreseed, "preseed", false, "Expect Preseed YAML for configuring MicroCloud in stdin")

return cmd
}
Expand All @@ -72,8 +72,8 @@ func (c *cmdInit) Run(cmd *cobra.Command, args []string) error {
return cmd.Help()
}

if c.flagPreseed != "" {
return c.common.RunPreseed(cmd, c.flagPreseed, true)
if c.flagPreseed {
return c.common.RunPreseed(cmd, true)
}

return c.RunInteractive(cmd, args)
Expand All @@ -94,7 +94,7 @@ func (c *cmdInit) RunInteractive(cmd *cobra.Command, args []string) error {

systems := map[string]InitSystem{}

addr, subnet, err := c.common.askAddress(c.flagAutoSetup, c.flagAddress)
addr, iface, subnet, err := c.common.askAddress(c.flagAutoSetup, c.flagAddress)
if err != nil {
return err
}
Expand Down Expand Up @@ -127,7 +127,7 @@ func (c *cmdInit) RunInteractive(cmd *cobra.Command, args []string) error {
return err
}

err = lookupPeers(s, c.flagAutoSetup, subnet, nil, systems)
err = lookupPeers(s, c.flagAutoSetup, iface, subnet, nil, systems)
if err != nil {
return err
}
Expand Down Expand Up @@ -156,7 +156,7 @@ func (c *cmdInit) RunInteractive(cmd *cobra.Command, args []string) error {
// - If `autoSetup` is true, all systems found in the first 5s will be recorded, and no other input is required.
// - `expectedSystems` is a list of expected hostnames. If given, the behaviour is similar to `autoSetup`,
// except it will wait up to a minute for exclusively these systems to be recorded.
func lookupPeers(s *service.Handler, autoSetup bool, subnet *net.IPNet, expectedSystems []string, systems map[string]InitSystem) error {
func lookupPeers(s *service.Handler, autoSetup bool, iface *net.Interface, subnet *net.IPNet, expectedSystems []string, systems map[string]InitSystem) error {
header := []string{"NAME", "IFACE", "ADDR"}
var table *SelectableTable
var answers []string
Expand Down Expand Up @@ -215,7 +215,7 @@ func lookupPeers(s *service.Handler, autoSetup bool, subnet *net.IPNet, expected
break
}

peers, err := mdns.LookupPeers(context.Background(), mdns.Version, s.Name)
peers, err := mdns.LookupPeers(context.Background(), iface, mdns.Version, s.Name)
if err != nil {
return err
}
Expand Down
32 changes: 23 additions & 9 deletions microcloud/cmd/microcloud/main_init_preseed.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"io"
"net"
"os"
"strconv"
Expand All @@ -23,10 +24,11 @@ import (

// Preseed represents the structure of the supported preseed yaml.
type Preseed struct {
LookupSubnet string `yaml:"lookup_subnet"`
Systems []System `yaml:"systems"`
OVN InitNetwork `yaml:"ovn"`
Storage StorageFilter `yaml:"storage"`
LookupSubnet string `yaml:"lookup_subnet"`
LookupInterface string `yaml:"lookup_interface"`
Systems []System `yaml:"systems"`
OVN InitNetwork `yaml:"ovn"`
Storage StorageFilter `yaml:"storage"`
}

// System represents the structure of the systems we expect to find in the preseed yaml.
Expand Down Expand Up @@ -87,14 +89,14 @@ func DiskOperatorSet() filter.OperatorSet {
}

// RunPreseed initializes MicroCloud from a preseed yaml filepath input.
func (c *CmdControl) RunPreseed(cmd *cobra.Command, preseed string, init bool) error {
fileBytes, err := os.ReadFile(preseed)
func (c *CmdControl) RunPreseed(cmd *cobra.Command, init bool) error {
bytes, err := io.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("Failed to read preseed file %q: %w", preseed, err)
return fmt.Errorf("Failed to read from stdin: %w", err)
}

config := Preseed{}
err = yaml.Unmarshal(fileBytes, &config)
err = yaml.Unmarshal(bytes, &config)
if err != nil {
return fmt.Errorf("Failed to parse the preseed yaml: %w", err)
}
Expand Down Expand Up @@ -361,7 +363,19 @@ func (p *Preseed) Parse(s *service.Handler, bootstrap bool) (map[string]InitSyst
return nil, err
}

err = lookupPeers(s, true, lookupSubnet, expectedSystems, systems)
ifaces, err := net.Interfaces()
if err != nil {
return nil, fmt.Errorf("Failed to get network interfaces: %w", err)
}

var lookupIface *net.Interface
for _, iface := range ifaces {
if iface.Name == p.LookupInterface {
lookupIface = &iface
}
}

err = lookupPeers(s, true, lookupIface, lookupSubnet, expectedSystems, systems)
if err != nil {
return nil, err
}
Expand Down
11 changes: 6 additions & 5 deletions microcloud/mdns/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type ServerInfo struct {

// NetworkInfo represents information about a network interface broadcast by a MicroCloud peer.
type NetworkInfo struct {
Interface string
Interface net.Interface
Address string
Subnet *net.IPNet
}
Expand Down Expand Up @@ -58,10 +58,10 @@ func (f forwardingWriter) Write(p []byte) (int, error) {
}

// LookupPeers finds any broadcasting peers and returns a list of their names.
func LookupPeers(ctx context.Context, version string, localPeer string) (map[string]ServerInfo, error) {
func LookupPeers(ctx context.Context, iface *net.Interface, version string, localPeer string) (map[string]ServerInfo, error) {
entries := []*mdns.ServiceEntry{}
for i := 0; i < ServiceSize; i++ {
nextEntries, err := Lookup(ctx, fmt.Sprintf("%s_%d", ClusterService, i), clusterSize)
nextEntries, err := Lookup(ctx, iface, fmt.Sprintf("%s_%d", ClusterService, i), clusterSize)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -125,7 +125,7 @@ func LookupPeers(ctx context.Context, version string, localPeer string) (map[str
}

// Lookup searches for the given service name over mdns.
func Lookup(ctx context.Context, service string, size int) ([]*mdns.ServiceEntry, error) {
func Lookup(ctx context.Context, iface *net.Interface, service string, size int) ([]*mdns.ServiceEntry, error) {
log.SetOutput(forwardingWriter{})
ctx, cancel := context.WithCancel(ctx)
defer cancel()
Expand All @@ -145,6 +145,7 @@ func Lookup(ctx context.Context, service string, size int) ([]*mdns.ServiceEntry
}()

params := mdns.DefaultParams(service)
params.Interface = iface
params.Entries = entriesCh
params.Timeout = 100 * time.Millisecond
err := mdns.Query(params)
Expand Down Expand Up @@ -185,7 +186,7 @@ func GetNetworkInfo() ([]NetworkInfo, error) {
continue
}

networks = append(networks, NetworkInfo{Interface: iface.Name, Address: ipNet.IP.String(), Subnet: ipNet})
networks = append(networks, NetworkInfo{Interface: iface, Address: ipNet.IP.String(), Subnet: ipNet})
}
}

Expand Down
4 changes: 2 additions & 2 deletions microcloud/mdns/mdns.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ServiceSize = 10
const clusterSize = 1000

// NewBroadcast returns a running mdns.Server which broadcasts the service at the given name and address.
func NewBroadcast(name string, addr string, port int64, service string, txt []byte) (*mdns.Server, error) {
func NewBroadcast(name string, iface *net.Interface, addr string, port int64, service string, txt []byte) (*mdns.Server, error) {
var sendTXT []string
if txt != nil {
sendTXT = dnsTXTSlice(txt)
Expand All @@ -28,7 +28,7 @@ func NewBroadcast(name string, addr string, port int64, service string, txt []by
return nil, fmt.Errorf("Failed to create configuration for broadcast: %w", err)
}

server, err := mdns.NewServer(&mdns.Config{Zone: config})
server, err := mdns.NewServer(&mdns.Config{Zone: config, Iface: iface})
if err != nil {
return nil, fmt.Errorf("Failed to begin broadcast: %w", err)
}
Expand Down
8 changes: 7 additions & 1 deletion microcloud/service/lxd_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,13 @@ func (s LXDService) DefaultPendingZFSStoragePool(wipe bool, path string) api.Sto
// DefaultZFSStoragePool returns the default local storage configuration when
// creating the finalized pool.
func (s LXDService) DefaultZFSStoragePool() api.StoragePoolsPost {
return api.StoragePoolsPost{Name: "local", Driver: "zfs"}
return api.StoragePoolsPost{
Name: "local",
Driver: "zfs",
StoragePoolPut: api.StoragePoolPut{
Description: "Local storage on ZFS",
},
}
}

// DefaultZFSStoragePoolJoinConfig returns the default local storage configuration when
Expand Down
10 changes: 8 additions & 2 deletions microcloud/service/service_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"sync"
Expand Down Expand Up @@ -120,7 +121,7 @@ func (s *Handler) Broadcast() error {
broadcasts := make([][]cloudMDNS.ServerInfo, cloudMDNS.ServiceSize)
for i, net := range networks {
info.Address = net.Address
info.Interface = net.Interface
info.Interface = net.Interface.Name

services := broadcasts[i%cloudMDNS.ServiceSize]
if services == nil {
Expand All @@ -142,7 +143,12 @@ func (s *Handler) Broadcast() error {
return fmt.Errorf("Failed to marshal server info: %w", err)
}

server, err := cloudMDNS.NewBroadcast(info.LookupKey(), info.Address, s.Port, service, bytes)
iface, err := net.InterfaceByName(info.Interface)
if err != nil {
return err
}

server, err := cloudMDNS.NewBroadcast(info.LookupKey(), iface, info.Address, s.Port, service, bytes)
if err != nil {
return err
}
Expand Down
18 changes: 12 additions & 6 deletions microcloud/test/includes/microcloud.sh
Original file line number Diff line number Diff line change
Expand Up @@ -552,13 +552,19 @@ cluster_reset() {
fi

lxc exec "${name}" -- sh -c "
for m in \$(lxc ls -f csv -c n) ; do
lxc rm \$m -f
done
if lxc ls -f csv -c n > /dev/null
then
for m in \$(lxc ls -f csv -c n) ; do
lxc rm \$m -f
done
fi

for f in \$(lxc image ls -f csv -c f) ; do
lxc image rm \$f
done
if lxc image ls -f csv -c f > /dev/null
then
for f in \$(lxc image ls -f csv -c f) ; do
lxc image rm \$f
done
fi

echo 'config: {}' | lxc profile edit default || true
"
Expand Down
Loading
Loading