From df8fe4cdda7efce30f7fca16d15c04ad0798e48d Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 2 Dec 2024 21:18:16 +0400 Subject: [PATCH] feat: support vlan/bond in v1, vlan in v2 for nocloud Fixes #9753 Signed-off-by: Andrey Smirnov (cherry picked from commit 852baf819d453a3d8d58ae9f029e280ae75e0cb1) --- .../platform/internal/netutils/netutils.go | 43 -- .../v1alpha1/platform/nocloud/metadata.go | 437 +++++++++++++----- .../v1alpha1/platform/nocloud/nocloud.go | 70 ++- .../v1alpha1/platform/nocloud/nocloud_test.go | 86 +++- .../nocloud/testdata/expected-v1-pnap.yaml | 105 +++++ .../testdata/expected-v2-serverscom.yaml | 158 +++++++ .../nocloud/testdata/expected-v2.yaml | 18 +- .../nocloud/testdata/metadata-v1-pnap.yaml | 53 +++ .../testdata/metadata-v2-cloud-init.yaml | 8 + .../nocloud/testdata/metadata-v2-nocloud.yaml | 8 + .../testdata/metadata-v2-serverscom.yaml | 49 ++ .../nocloud/testdata/metadata-v2.yaml | 49 -- .../nocloud/testdata/metadata-v3.yaml | 49 -- 13 files changed, 834 insertions(+), 299 deletions(-) create mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v1-pnap.yaml create mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-serverscom.yaml create mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v1-pnap.yaml create mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-serverscom.yaml delete mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2.yaml delete mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v3.yaml diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils/netutils.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils/netutils.go index c358e99aee..90f3a9653e 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils/netutils.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils/netutils.go @@ -7,12 +7,9 @@ package netutils import ( "context" - "fmt" "log" "time" - "github.com/cenkalti/backoff/v4" - "github.com/cosi-project/runtime/pkg/safe" "github.com/cosi-project/runtime/pkg/state" "github.com/siderolabs/go-retry/retry" @@ -28,46 +25,6 @@ func Wait(ctx context.Context, r state.State) error { return network.NewReadyCondition(r, network.AddressReady).Wait(ctx) } -// WaitInterfaces for the interfaces to be up to interact with platform metadata services. -func WaitInterfaces(ctx context.Context, r state.State) error { - backoff := backoff.NewExponentialBackOff() - backoff.MaxInterval = 2 * time.Second - backoff.MaxElapsedTime = 30 * time.Second - - for ctx.Err() == nil { - hostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, r) - if err != nil { - return fmt.Errorf("error listing host interfaces: %w", err) - } - - numPhysical := 0 - - for iter := hostInterfaces.Iterator(); iter.Next(); { - iface := iter.Value() - - if iface.TypedSpec().Physical() { - numPhysical++ - } - } - - if numPhysical > 0 { - return nil - } - - log.Printf("waiting for physical network interfaces to appear...") - - interval := backoff.NextBackOff() - - select { - case <-ctx.Done(): - return nil - case <-time.After(interval): - } - } - - return nil -} - // WaitForDevicesReady waits for devices to be ready. func WaitForDevicesReady(ctx context.Context, r state.State) error { log.Printf("waiting for devices to be ready...") diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go index 34eb3f77e0..50b3b12bbc 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go @@ -14,6 +14,7 @@ import ( "net/url" "os" "path/filepath" + "slices" "sort" "strings" @@ -50,22 +51,30 @@ type NetworkCloudInitConfig struct { // NetworkConfig holds network-config info. type NetworkConfig struct { - Version int `yaml:"version"` - Config []struct { - Mac string `yaml:"mac_address,omitempty"` - Interfaces string `yaml:"name,omitempty"` - MTU uint32 `yaml:"mtu,omitempty"` - Subnets []struct { - Address string `yaml:"address,omitempty"` - Netmask string `yaml:"netmask,omitempty"` - Gateway string `yaml:"gateway,omitempty"` - Type string `yaml:"type"` - } `yaml:"subnets,omitempty"` - Address []string `yaml:"address,omitempty"` - Type string `yaml:"type"` - } `yaml:"config,omitempty"` + Version int `yaml:"version"` + Config []ConfigV1 `yaml:"config,omitempty"` Ethernets map[string]Ethernet `yaml:"ethernets,omitempty"` - Bonds map[string]Bonds `yaml:"bonds,omitempty"` + Bonds map[string]Bond `yaml:"bonds,omitempty"` + VLANs map[string]VLAN `yaml:"vlans,omitempty"` +} + +// ConfigV1 holds nocloud v1 config. +type ConfigV1 struct { + Mac string `yaml:"mac_address,omitempty"` + Interfaces string `yaml:"name,omitempty"` + MTU uint32 `yaml:"mtu,omitempty"` + Subnets []struct { + Address string `yaml:"address,omitempty"` + Netmask string `yaml:"netmask,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + Type string `yaml:"type"` + } `yaml:"subnets,omitempty"` + Address []string `yaml:"address,omitempty"` + Type string `yaml:"type"` + BondInterfaces []string `yaml:"bond_interfaces,omitempty"` + VlanID uint16 `yaml:"vlan_id,omitempty"` + VlanLink string `yaml:"vlan_link,omitempty"` + Params NetworkParams `yaml:"params,omitempty"` } // Ethernet holds network interface info. @@ -97,8 +106,8 @@ type Ethernet struct { } `yaml:"routing-policy,omitempty"` } -// Bonds holds bonding interface info. -type Bonds struct { +// Bond holds bonding interface info. +type Bond struct { Ethernet `yaml:",inline"` Interfaces []string `yaml:"interfaces,omitempty"` Params struct { @@ -111,6 +120,13 @@ type Bonds struct { } `yaml:"parameters,omitempty"` } +// VLAN holds vlan interface info. +type VLAN struct { + Ethernet `yaml:",inline"` + ID uint16 `yaml:"id,omitempty"` + Link string `yaml:"link,omitempty"` +} + // MetadataConfig holds meta info. type MetadataConfig struct { Hostname string `yaml:"hostname,omitempty"` @@ -123,6 +139,16 @@ type MetadataConfig struct { Zone string `yaml:"zone,omitempty"` } +// NetworkParams holds network parameters (mostly bond for v1 network-config). +type NetworkParams struct { + BondLACPRate string `yaml:"bond-lacp-rate,omitempty"` + BondMiimon uint32 `yaml:"bond-miimon,omitempty"` + BondMode string `yaml:"bond-mode,omitempty"` + BondXmitHashPolicy string `yaml:"bond-xmit-hash-policy,omitempty"` + UpDelay uint32 `yaml:"up-delay,omitempty"` + DownDelay uint32 `yaml:"down-delay,omitempty"` +} + func (n *Nocloud) configFromNetwork(ctx context.Context, metaBaseURL string, r state.State) (metaConfig []byte, networkConfig []byte, machineConfig []byte, err error) { log.Printf("fetching meta config from: %q", metaBaseURL+configMetaDataPath) @@ -284,18 +310,112 @@ func (n *Nocloud) acquireConfig(ctx context.Context, r state.State) (metadataNet } //nolint:gocyclo,cyclop -func (n *Nocloud) applyNetworkConfigV1(config *NetworkConfig, st state.State, networkConfig *runtime.PlatformNetworkConfig) error { - ctx := context.TODO() +func (n *Nocloud) applyNetworkConfigV1(ctx context.Context, config *NetworkConfig, st state.State, networkConfig *runtime.PlatformNetworkConfig) (bool, error) { + hostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st) + if err != nil { + return false, fmt.Errorf("error listing host interfaces: %w", err) + } + + var needsReconcile bool + + parseSubnets := func(ntwrk ConfigV1, name string) error { + for _, subnet := range ntwrk.Subnets { + switch subnet.Type { + case "dhcp", "dhcp4": + networkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{ + Operator: network.OperatorDHCP4, + LinkName: name, + RequireUp: true, + DHCP4: network.DHCP4OperatorSpec{ + RouteMetric: network.DefaultRouteMetric, + }, + ConfigLayer: network.ConfigPlatform, + }) + case "static", "static6": + family := nethelpers.FamilyInet4 + + if subnet.Type == "static6" { + family = nethelpers.FamilyInet6 + } + + ipPrefix, err := netip.ParsePrefix(subnet.Address) + if err != nil { + ip, err := netip.ParseAddr(subnet.Address) + if err != nil { + return err + } + + netmask, err := netip.ParseAddr(subnet.Netmask) + if err != nil { + return err + } - if err := netutils.WaitInterfaces(ctx, st); err != nil { - return err + mask, _ := netmask.MarshalBinary() //nolint:errcheck // never fails + ones, _ := net.IPMask(mask).Size() + ipPrefix = netip.PrefixFrom(ip, ones) + } + + networkConfig.Addresses = append(networkConfig.Addresses, + network.AddressSpecSpec{ + ConfigLayer: network.ConfigPlatform, + LinkName: name, + Address: ipPrefix, + Scope: nethelpers.ScopeGlobal, + Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent), + Family: family, + }, + ) + + if subnet.Gateway != "" { + gw, err := netip.ParseAddr(subnet.Gateway) + if err != nil { + return err + } + + route := network.RouteSpecSpec{ + ConfigLayer: network.ConfigPlatform, + Gateway: gw, + OutLinkName: name, + Table: nethelpers.TableMain, + Protocol: nethelpers.ProtocolStatic, + Type: nethelpers.TypeUnicast, + Family: family, + Priority: network.DefaultRouteMetric, + } + + if family == nethelpers.FamilyInet6 { + route.Priority = 2 * network.DefaultRouteMetric + } + + route.Normalize() + + networkConfig.Routes = append(networkConfig.Routes, route) + } + case "ipv6_dhcpv6-stateful": + networkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{ + Operator: network.OperatorDHCP6, + LinkName: name, + RequireUp: true, + DHCP6: network.DHCP6OperatorSpec{ + RouteMetric: 2 * network.DefaultRouteMetric, + }, + ConfigLayer: network.ConfigPlatform, + }) + } + } + + return nil } - hostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st) - if err != nil { - return fmt.Errorf("error listing host interfaces: %w", err) + physicalNameMap := map[string]string{} + + type enslavedLink struct { + bondName string + slaveIndex int } + enslavedLinks := map[string]enslavedLink{} + for _, ntwrk := range config.Config { switch ntwrk.Type { case "nameserver": @@ -305,7 +425,7 @@ func (n *Nocloud) applyNetworkConfigV1(config *NetworkConfig, st state.State, ne if ip, err := netip.ParseAddr(ntwrk.Address[i]); err == nil { dnsIPs = append(dnsIPs, ip) } else { - return err + return false, err } } @@ -313,6 +433,89 @@ func (n *Nocloud) applyNetworkConfigV1(config *NetworkConfig, st state.State, ne DNSServers: dnsIPs, ConfigLayer: network.ConfigPlatform, }) + case "bond": + name := ntwrk.Interfaces + + mode, err := nethelpers.BondModeByName(ntwrk.Params.BondMode) + if err != nil { + return false, fmt.Errorf("invalid mode: %w", err) + } + + hashPolicy, err := nethelpers.BondXmitHashPolicyByName(ntwrk.Params.BondXmitHashPolicy) + if err != nil { + return false, fmt.Errorf("invalid transmit-hash-policy: %w", err) + } + + lacpRate, err := nethelpers.LACPRateByName(ntwrk.Params.BondLACPRate) + if err != nil { + return false, fmt.Errorf("invalid lacp-rate: %w", err) + } + + bondLink := network.LinkSpecSpec{ + ConfigLayer: network.ConfigPlatform, + Name: name, + Logical: true, + Up: true, + Kind: network.LinkKindBond, + Type: nethelpers.LinkEther, + BondMaster: network.BondMasterSpec{ + Mode: mode, + HashPolicy: hashPolicy, + MIIMon: ntwrk.Params.BondMiimon, + UpDelay: ntwrk.Params.UpDelay, + DownDelay: ntwrk.Params.DownDelay, + LACPRate: lacpRate, + }, + } + + if ntwrk.MTU != 0 { + bondLink.MTU = ntwrk.MTU + } + + networkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults() + networkConfig.Links = append(networkConfig.Links, bondLink) + + for idx, slave := range ntwrk.BondInterfaces { + enslavedLinks[slave] = enslavedLink{ + bondName: name, + slaveIndex: idx, + } + } + + if err = parseSubnets(ntwrk, name); err != nil { + return false, err + } + case "vlan": + name := ntwrk.Interfaces + + parentName, ok := physicalNameMap[ntwrk.VlanLink] + if !ok { + parentName = ntwrk.VlanLink + } + + linkSpec := network.LinkSpecSpec{ + ConfigLayer: network.ConfigPlatform, + Name: name, + Logical: true, + Up: true, + Kind: network.LinkKindVLAN, + Type: nethelpers.LinkEther, + ParentName: parentName, + VLAN: network.VLANSpec{ + VID: ntwrk.VlanID, + Protocol: nethelpers.VLANProtocol8021Q, + }, + } + + if ntwrk.MTU != 0 { + linkSpec.MTU = ntwrk.MTU + } + + networkConfig.Links = append(networkConfig.Links, linkSpec) + + if err = parseSubnets(ntwrk, name); err != nil { + return false, err + } case "physical": name := ntwrk.Interfaces @@ -342,103 +545,50 @@ func (n *Nocloud) applyNetworkConfigV1(config *NetworkConfig, st state.State, ne if !macAddressMatched { log.Printf("nocloud: no link with matching MAC address %q, defaulted to use name %s instead", ntwrk.Mac, name) + + needsReconcile = true } } - networkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{ + physicalNameMap[ntwrk.Interfaces] = name + + linkSpec := network.LinkSpecSpec{ Name: name, Up: true, ConfigLayer: network.ConfigPlatform, - }) + } - for _, subnet := range ntwrk.Subnets { - switch subnet.Type { - case "dhcp", "dhcp4": - networkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{ - Operator: network.OperatorDHCP4, - LinkName: name, - RequireUp: true, - DHCP4: network.DHCP4OperatorSpec{ - RouteMetric: network.DefaultRouteMetric, - }, - ConfigLayer: network.ConfigPlatform, - }) - case "static", "static6": - family := nethelpers.FamilyInet4 + if ntwrk.MTU != 0 { + linkSpec.MTU = ntwrk.MTU + } - if subnet.Type == "static6" { - family = nethelpers.FamilyInet6 - } + networkConfig.Links = append(networkConfig.Links, linkSpec) - ipPrefix, err := netip.ParsePrefix(subnet.Address) - if err != nil { - ip, err := netip.ParseAddr(subnet.Address) - if err != nil { - return err - } - - netmask, err := netip.ParseAddr(subnet.Netmask) - if err != nil { - return err - } - - mask, _ := netmask.MarshalBinary() //nolint:errcheck // never fails - ones, _ := net.IPMask(mask).Size() - ipPrefix = netip.PrefixFrom(ip, ones) - } + if err = parseSubnets(ntwrk, name); err != nil { + return false, err + } + } + } - networkConfig.Addresses = append(networkConfig.Addresses, - network.AddressSpecSpec{ - ConfigLayer: network.ConfigPlatform, - LinkName: name, - Address: ipPrefix, - Scope: nethelpers.ScopeGlobal, - Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent), - Family: family, - }, - ) - - if subnet.Gateway != "" { - gw, err := netip.ParseAddr(subnet.Gateway) - if err != nil { - return err - } - - route := network.RouteSpecSpec{ - ConfigLayer: network.ConfigPlatform, - Gateway: gw, - OutLinkName: name, - Table: nethelpers.TableMain, - Protocol: nethelpers.ProtocolStatic, - Type: nethelpers.TypeUnicast, - Family: family, - Priority: network.DefaultRouteMetric, - } - - if family == nethelpers.FamilyInet6 { - route.Priority = 2 * network.DefaultRouteMetric - } - - route.Normalize() - - networkConfig.Routes = append(networkConfig.Routes, route) - } - case "ipv6_dhcpv6-stateful": - networkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{ - Operator: network.OperatorDHCP6, - LinkName: name, - RequireUp: true, - DHCP6: network.DHCP6OperatorSpec{ - RouteMetric: 2 * network.DefaultRouteMetric, - }, - ConfigLayer: network.ConfigPlatform, - }) - } + for slaveName, enslavedLink := range enslavedLinks { + physicalName, ok := physicalNameMap[slaveName] + if !ok { + physicalName = slaveName + } + + for idx := range networkConfig.Links { + if networkConfig.Links[idx].Name != physicalName { + continue + } + + networkConfig.Links[idx].BondSlave = network.BondSlave{ + MasterName: enslavedLink.bondName, + SlaveIndex: enslavedLink.slaveIndex, } } } - return nil + return needsReconcile, nil } //nolint:gocyclo @@ -605,13 +755,16 @@ func applyNetworkConfigV2Ethernet(name string, eth Ethernet, networkConfig *runt return nil } -//nolint:gocyclo -func (n *Nocloud) applyNetworkConfigV2(config *NetworkConfig, st state.State, networkConfig *runtime.PlatformNetworkConfig) error { - var dnsIPs []netip.Addr +//nolint:gocyclo,cyclop +func (n *Nocloud) applyNetworkConfigV2(ctx context.Context, config *NetworkConfig, st state.State, networkConfig *runtime.PlatformNetworkConfig) (bool, error) { + var ( + dnsIPs []netip.Addr + needsReconcile bool + ) - hostInterfaces, err := safe.StateListAll[*network.LinkStatus](context.TODO(), st) + hostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st) if err != nil { - return fmt.Errorf("error listing host interfaces: %w", err) + return false, fmt.Errorf("error listing host interfaces: %w", err) } ethernetNames := maps.Keys(config.Ethernets) @@ -623,10 +776,10 @@ func (n *Nocloud) applyNetworkConfigV2(config *NetworkConfig, st state.State, ne var bondSlave network.BondSlave for bondName, bond := range config.Bonds { - for _, iface := range bond.Interfaces { + for idx, iface := range bond.Interfaces { if iface == name { bondSlave.MasterName = bondName - bondSlave.SlaveIndex = 1 + bondSlave.SlaveIndex = idx } } } @@ -661,6 +814,8 @@ func (n *Nocloud) applyNetworkConfigV2(config *NetworkConfig, st state.State, ne if !macAddressMatched { log.Printf("nocloud: no link with matching MAC address %q (available %v), defaulted to use name %s instead", eth.Match.HWAddr, availableMACAddresses, name) + + needsReconcile = true } } @@ -674,29 +829,34 @@ func (n *Nocloud) applyNetworkConfigV2(config *NetworkConfig, st state.State, ne err := applyNetworkConfigV2Ethernet(name, eth, networkConfig, &dnsIPs) if err != nil { - return err + return false, err } } - for name, bond := range config.Bonds { + bondNames := maps.Keys(config.Bonds) + slices.Sort(bondNames) + + for _, bondName := range bondNames { + bond := config.Bonds[bondName] + mode, err := nethelpers.BondModeByName(bond.Params.Mode) if err != nil { - return fmt.Errorf("invalid mode: %w", err) + return false, fmt.Errorf("invalid mode: %w", err) } hashPolicy, err := nethelpers.BondXmitHashPolicyByName(bond.Params.HashPolicy) if err != nil { - return fmt.Errorf("invalid transmit-hash-policy: %w", err) + return false, fmt.Errorf("invalid transmit-hash-policy: %w", err) } lacpRate, err := nethelpers.LACPRateByName(bond.Params.LACPRate) if err != nil { - return fmt.Errorf("invalid lacp-rate: %w", err) + return false, fmt.Errorf("invalid lacp-rate: %w", err) } bondLink := network.LinkSpecSpec{ ConfigLayer: network.ConfigPlatform, - Name: name, + Name: bondName, Logical: true, Up: true, MTU: bond.Ethernet.MTU, @@ -715,9 +875,38 @@ func (n *Nocloud) applyNetworkConfigV2(config *NetworkConfig, st state.State, ne networkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults() networkConfig.Links = append(networkConfig.Links, bondLink) - err = applyNetworkConfigV2Ethernet(name, bond.Ethernet, networkConfig, &dnsIPs) + err = applyNetworkConfigV2Ethernet(bondName, bond.Ethernet, networkConfig, &dnsIPs) if err != nil { - return err + return false, err + } + } + + vlanNames := maps.Keys(config.VLANs) + slices.Sort(vlanNames) + + for _, vlanName := range vlanNames { + vlan := config.VLANs[vlanName] + + vlanLink := network.LinkSpecSpec{ + ConfigLayer: network.ConfigPlatform, + Name: vlanName, + Logical: true, + Up: true, + MTU: vlan.Ethernet.MTU, + Kind: network.LinkKindVLAN, + Type: nethelpers.LinkEther, + ParentName: vlan.Link, + VLAN: network.VLANSpec{ + VID: vlan.ID, + Protocol: nethelpers.VLANProtocol8021Q, + }, + } + + networkConfig.Links = append(networkConfig.Links, vlanLink) + + err = applyNetworkConfigV2Ethernet(vlanName, vlan.Ethernet, networkConfig, &dnsIPs) + if err != nil { + return false, err } } @@ -728,7 +917,7 @@ func (n *Nocloud) applyNetworkConfigV2(config *NetworkConfig, st state.State, ne }) } - return nil + return needsReconcile, nil } func withDefault[T comparable](v T, defaultValue T) T { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go index e05519174d..21947f44b9 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go @@ -9,14 +9,18 @@ import ( "context" stderrors "errors" "fmt" + "time" + "github.com/cenkalti/backoff/v4" "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/gen/channel" "github.com/siderolabs/gen/maps" "github.com/siderolabs/go-procfs/procfs" yaml "gopkg.in/yaml.v3" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors" + "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/resources/network" runtimeres "github.com/siderolabs/talos/pkg/machinery/resources/runtime" @@ -31,7 +35,7 @@ func (n *Nocloud) Name() string { } // ParseMetadata converts nocloud metadata to platform network config. -func (n *Nocloud) ParseMetadata(unmarshalledNetworkConfig *NetworkConfig, st state.State, metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) { +func (n *Nocloud) ParseMetadata(ctx context.Context, unmarshalledNetworkConfig *NetworkConfig, st state.State, metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, bool, error) { networkConfig := &runtime.PlatformNetworkConfig{} hostname := metadata.Hostname @@ -45,23 +49,28 @@ func (n *Nocloud) ParseMetadata(unmarshalledNetworkConfig *NetworkConfig, st sta } if err := hostnameSpec.ParseFQDN(hostname); err != nil { - return nil, err + return nil, false, err } networkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec) } + var ( + needsReconcile bool + err error + ) + switch unmarshalledNetworkConfig.Version { case 1: - if err := n.applyNetworkConfigV1(unmarshalledNetworkConfig, st, networkConfig); err != nil { - return nil, err + if needsReconcile, err = n.applyNetworkConfigV1(ctx, unmarshalledNetworkConfig, st, networkConfig); err != nil { + return nil, false, err } case 2: - if err := n.applyNetworkConfigV2(unmarshalledNetworkConfig, st, networkConfig); err != nil { - return nil, err + if needsReconcile, err = n.applyNetworkConfigV2(ctx, unmarshalledNetworkConfig, st, networkConfig); err != nil { + return nil, false, err } default: - return nil, fmt.Errorf("network-config metadata version=%d is not supported", unmarshalledNetworkConfig.Version) + return nil, false, fmt.Errorf("network-config metadata version=%d is not supported", unmarshalledNetworkConfig.Version) } networkConfig.Metadata = &runtimeres.PlatformMetadataSpec{ @@ -76,7 +85,7 @@ func (n *Nocloud) ParseMetadata(unmarshalledNetworkConfig *NetworkConfig, st sta ExternalDNS: metadata.ExternalDNS, } - return networkConfig, nil + return networkConfig, needsReconcile, nil } // Configuration implements the runtime.Platform interface. @@ -107,7 +116,14 @@ func (n *Nocloud) KernelArgs(string) procfs.Parameters { } // NetworkConfiguration implements the runtime.Platform interface. +// +//nolint:gocyclo func (n *Nocloud) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error { + // wait for devices to be ready before proceeding + if err := netutils.WaitForDevicesReady(ctx, st); err != nil { + return fmt.Errorf("error waiting for devices to be ready: %w", err) + } + metadataNetworkConfigDl, _, metadata, err := n.acquireConfig(ctx, st) if stderrors.Is(err, errors.ErrNoConfigSource) { err = nil @@ -127,18 +143,36 @@ func (n *Nocloud) NetworkConfiguration(ctx context.Context, st state.State, ch c return err } - networkConfig, err := n.ParseMetadata(unmarshalledNetworkConfig, st, metadata) - if err != nil { - return err - } + // do a loop to retry network config remap in case of missing links + // on each try, export the configuration as it is, and if the network is reconciled next time, export the reconciled configuration + for { + bckoff := backoff.NewExponentialBackOff() - select { - case ch <- networkConfig: - case <-ctx.Done(): - return ctx.Err() - } + networkConfig, needsReconcile, err := n.ParseMetadata(ctx, unmarshalledNetworkConfig, st, metadata) + if err != nil { + return err + } + + if !channel.SendWithContext(ctx, ch, networkConfig) { + return ctx.Err() + } + + if !needsReconcile { + return nil + } + + // wait for for backoff to retry network config remap + nextBackoff := bckoff.NextBackOff() + if nextBackoff == backoff.Stop { + return nil + } - return nil + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(nextBackoff): + } + } } // DecodeNetworkConfig decodes the network configuration guessing the format from the content. diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go index f96735d6a6..b6aea9f28e 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go @@ -7,11 +7,14 @@ package nocloud_test import ( "context" _ "embed" + "net" "testing" + "time" "github.com/cosi-project/runtime/pkg/state" "github.com/cosi-project/runtime/pkg/state/impl/inmem" "github.com/cosi-project/runtime/pkg/state/impl/namespaced" + "github.com/siderolabs/gen/xtesting/must" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -19,28 +22,45 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud" "github.com/siderolabs/talos/pkg/machinery/nethelpers" "github.com/siderolabs/talos/pkg/machinery/resources/network" + "github.com/siderolabs/talos/pkg/machinery/resources/runtime" ) //go:embed testdata/metadata-v1.yaml var rawMetadataV1 []byte +//go:embed testdata/metadata-v1-pnap.yaml +var rawMetadataV1Pnap []byte + //go:embed testdata/metadata-v2-nocloud.yaml var rawMetadataV2Nocloud []byte //go:embed testdata/metadata-v2-cloud-init.yaml var rawMetadataV2CloudInit []byte +//go:embed testdata/metadata-v2-serverscom.yaml +var rawMetadataV2Serverscom []byte + //go:embed testdata/expected-v1.yaml var expectedNetworkConfigV1 string +//go:embed testdata/expected-v1-pnap.yaml +var expectedNetworkConfigV1Pnap string + //go:embed testdata/expected-v2.yaml var expectedNetworkConfigV2 string +//go:embed testdata/expected-v2-serverscom.yaml +var expectedNetworkConfigV2Serverscom string + func TestParseMetadata(t *testing.T) { + t.Parallel() + for _, tt := range []struct { - name string - raw []byte - expected string + name string + raw []byte + + expected string + expectedNeedsRecocile bool }{ { name: "V1", @@ -48,45 +68,78 @@ func TestParseMetadata(t *testing.T) { expected: expectedNetworkConfigV1, }, { - name: "V2-nocloud", - raw: rawMetadataV2Nocloud, - expected: expectedNetworkConfigV2, + name: "V1-pnap", + raw: rawMetadataV1Pnap, + expected: expectedNetworkConfigV1Pnap, + }, + { + name: "V2-nocloud", + raw: rawMetadataV2Nocloud, + expected: expectedNetworkConfigV2, + expectedNeedsRecocile: true, }, { - name: "V2-cloud-init", - raw: rawMetadataV2CloudInit, - expected: expectedNetworkConfigV2, + name: "V2-cloud-init", + raw: rawMetadataV2CloudInit, + expected: expectedNetworkConfigV2, + expectedNeedsRecocile: true, + }, + { + name: "V2-servers.com", + raw: rawMetadataV2Serverscom, + expected: expectedNetworkConfigV2Serverscom, }, } { t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + t.Cleanup(cancel) + n := &nocloud.Nocloud{} st := state.WrapCore(namespaced.NewState(inmem.Build)) + devicesReady := runtime.NewDevicesStatus(runtime.NamespaceName, runtime.DevicesID) + devicesReady.TypedSpec().Ready = true + require.NoError(t, st.Create(ctx, devicesReady)) + bond0 := network.NewLinkStatus(network.NamespaceName, "bond0") bond0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf7} // this link is not a physical one, so it should be ignored bond0.TypedSpec().Type = nethelpers.LinkEther bond0.TypedSpec().Kind = "bond" - require.NoError(t, st.Create(context.TODO(), bond0)) + require.NoError(t, st.Create(ctx, bond0)) eth0 := network.NewLinkStatus(network.NamespaceName, "eth0") eth0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf7} eth0.TypedSpec().Type = nethelpers.LinkEther eth0.TypedSpec().Kind = "" - require.NoError(t, st.Create(context.TODO(), eth0)) + require.NoError(t, st.Create(ctx, eth0)) eth1 := network.NewLinkStatus(network.NamespaceName, "eth1") eth1.TypedSpec().HardwareAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf9} // this link has a permanent address, so hardware addr should be ignored eth1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf8} eth1.TypedSpec().Type = nethelpers.LinkEther eth1.TypedSpec().Kind = "" - require.NoError(t, st.Create(context.TODO(), eth1)) + require.NoError(t, st.Create(ctx, eth1)) eth2 := network.NewLinkStatus(network.NamespaceName, "eth2") eth2.TypedSpec().HardwareAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf9} // this link doesn't have a permanent address, but only a hardware address eth2.TypedSpec().Type = nethelpers.LinkEther eth2.TypedSpec().Kind = "" - require.NoError(t, st.Create(context.TODO(), eth2)) + require.NoError(t, st.Create(ctx, eth2)) + + eno1np0 := network.NewLinkStatus(network.NamespaceName, "eno1np0") + eno1np0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr(must.Value(net.ParseMAC("3c:ec:ef:e0:45:28"))(t)) + eno1np0.TypedSpec().Type = nethelpers.LinkEther + eno1np0.TypedSpec().Kind = "" + require.NoError(t, st.Create(ctx, eno1np0)) + + eno2np1 := network.NewLinkStatus(network.NamespaceName, "eno2np1") + eno2np1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr(must.Value(net.ParseMAC("3c:ec:ef:e0:45:29"))(t)) + eno2np1.TypedSpec().Type = nethelpers.LinkEther + eno2np1.TypedSpec().Kind = "" + require.NoError(t, st.Create(ctx, eno2np1)) m, err := nocloud.DecodeNetworkConfig(tt.raw) require.NoError(t, err) @@ -101,11 +154,14 @@ func TestParseMetadata(t *testing.T) { InstanceID: "0", } - networkConfig, err := n.ParseMetadata(m, st, &mc) + networkConfig, needsReconcile, err := n.ParseMetadata(ctx, m, st, &mc) require.NoError(t, err) - networkConfig2, err := n.ParseMetadata(m, st, &mc2) + networkConfig2, needsReconcile2, err := n.ParseMetadata(ctx, m, st, &mc2) require.NoError(t, err) + assert.Equal(t, needsReconcile, needsReconcile2) + assert.Equal(t, tt.expectedNeedsRecocile, needsReconcile) + marshaled, err := yaml.Marshal(networkConfig) require.NoError(t, err) marshaled2, err := yaml.Marshal(networkConfig2) diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v1-pnap.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v1-pnap.yaml new file mode 100644 index 0000000000..e8aee81a87 --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v1-pnap.yaml @@ -0,0 +1,105 @@ +addresses: + - address: 1.2.3.4/29 + linkName: bond0.2 + family: inet4 + scope: global + flags: permanent + layer: platform + - address: 10.0.0.11/24 + linkName: bond0.4 + family: inet4 + scope: global + flags: permanent + layer: platform +links: + - name: eno1np0 + logical: false + up: true + mtu: 9000 + kind: "" + type: netrom + masterName: bond0 + layer: platform + - name: eno2np1 + logical: false + up: true + mtu: 9000 + kind: "" + type: netrom + masterName: bond0 + slaveIndex: 1 + layer: platform + - name: bond0 + logical: true + up: true + mtu: 9000 + kind: bond + type: ether + bondMaster: + mode: 802.3ad + xmitHashPolicy: layer3+4 + lacpRate: fast + arpValidate: none + arpAllTargets: any + primaryReselect: always + failOverMac: 0 + miimon: 100 + resendIgmp: 1 + lpInterval: 1 + packetsPerSlave: 1 + numPeerNotif: 1 + tlbLogicalLb: 1 + adActorSysPrio: 65535 + layer: platform + - name: bond0.2 + logical: true + up: true + mtu: 9000 + kind: vlan + type: ether + parentName: bond0 + vlan: + vlanID: 2 + vlanProtocol: 802.1q + layer: platform + - name: bond0.4 + logical: true + up: true + mtu: 9000 + kind: vlan + type: ether + parentName: bond0 + vlan: + vlanID: 4 + vlanProtocol: 802.1q + layer: platform +routes: + - family: inet4 + dst: "" + src: "" + gateway: 1.2.3.5 + outLinkName: bond0.2 + table: main + priority: 1024 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform +hostnames: + - hostname: talos + domainname: fqdn + layer: platform +resolvers: + - dnsServers: + - 8.8.8.8 + - 8.8.4.4 + layer: platform +timeServers: [] +operators: [] +externalIPs: [] +metadata: + platform: nocloud + hostname: talos.fqdn + instanceId: "0" + internalDNS: talos.fqdn diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-serverscom.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-serverscom.yaml new file mode 100644 index 0000000000..c8a4e19ddb --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-serverscom.yaml @@ -0,0 +1,158 @@ +addresses: + - address: 188.42.48.188/29 + linkName: agge + family: inet4 + scope: global + flags: permanent + layer: platform + - address: 10.26.98.92/29 + linkName: aggi + family: inet4 + scope: global + flags: permanent + layer: platform +links: + - name: eno1np0 + logical: false + up: true + mtu: 0 + kind: "" + type: netrom + masterName: agge + layer: platform + - name: eno2np1 + logical: false + up: true + mtu: 0 + kind: "" + type: netrom + masterName: agge + slaveIndex: 1 + layer: platform + - name: eth1 + logical: false + up: true + mtu: 0 + kind: "" + type: netrom + masterName: aggi + layer: platform + - name: eth2 + logical: false + up: true + mtu: 0 + kind: "" + type: netrom + masterName: aggi + slaveIndex: 1 + layer: platform + - name: agge + logical: true + up: true + mtu: 0 + kind: bond + type: ether + bondMaster: + mode: 802.3ad + xmitHashPolicy: layer3+4 + lacpRate: slow + arpValidate: none + arpAllTargets: any + primaryReselect: always + failOverMac: 0 + miimon: 100 + updelay: 200 + downdelay: 200 + resendIgmp: 1 + lpInterval: 1 + packetsPerSlave: 1 + numPeerNotif: 1 + tlbLogicalLb: 1 + adActorSysPrio: 65535 + layer: platform + - name: aggi + logical: true + up: true + mtu: 0 + kind: bond + type: ether + bondMaster: + mode: 802.3ad + xmitHashPolicy: layer3+4 + lacpRate: slow + arpValidate: none + arpAllTargets: any + primaryReselect: always + failOverMac: 0 + miimon: 100 + updelay: 200 + downdelay: 200 + resendIgmp: 1 + lpInterval: 1 + packetsPerSlave: 1 + numPeerNotif: 1 + tlbLogicalLb: 1 + adActorSysPrio: 65535 + layer: platform +routes: + - family: inet4 + dst: "" + src: "" + gateway: 188.42.48.187 + outLinkName: agge + table: main + priority: 1024 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform + - family: inet4 + dst: 10.0.0.0/8 + src: "" + gateway: 10.26.98.91 + outLinkName: aggi + table: main + priority: 1024 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform + - family: inet4 + dst: 192.168.0.0/16 + src: "" + gateway: 10.26.98.91 + outLinkName: aggi + table: main + priority: 1024 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform + - family: inet4 + dst: 188.42.208.0/21 + src: "" + gateway: 10.26.98.91 + outLinkName: aggi + table: main + priority: 1024 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform +hostnames: + - hostname: talos + domainname: fqdn + layer: platform +resolvers: [] +timeServers: [] +operators: [] +externalIPs: [] +metadata: + platform: nocloud + hostname: talos.fqdn + instanceId: "0" + internalDNS: talos.fqdn diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml index afd24fa23e..3a90656333 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml @@ -23,6 +23,12 @@ addresses: scope: global flags: permanent layer: platform + - address: 192.34.34.34/32 + linkName: bond0.4 + family: inet4 + scope: global + flags: permanent + layer: platform links: - name: eth0 logical: false @@ -45,7 +51,6 @@ links: kind: "" type: netrom masterName: bond0 - slaveIndex: 1 layer: platform - name: eth2 logical: false @@ -80,6 +85,17 @@ links: tlbLogicalLb: 1 adActorSysPrio: 65535 layer: platform + - name: bond0.4 + logical: true + up: true + mtu: 1500 + kind: vlan + type: ether + parentName: bond0 + vlan: + vlanID: 4 + vlanProtocol: 802.1q + layer: platform routes: - family: inet4 dst: "" diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v1-pnap.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v1-pnap.yaml new file mode 100644 index 0000000000..bafdf6f7e2 --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v1-pnap.yaml @@ -0,0 +1,53 @@ +version: 1 +config: + +- type: physical + name: eno1np0 + mac_address: "3c:ec:ef:e0:45:28" + mtu: 9000 + +- type: physical + name: eno2np1 + mac_address: "3c:ec:ef:e0:45:29" + mtu: 9000 + +- type: bond + name: bond0 + mac_address: "3c:ec:ef:e0:45:28" + mtu: 9000 + bond_interfaces: + - eno1np0 + - eno2np1 + params: + bond-lacp-rate: fast + bond-miimon: 100 + bond-mode: 802.3ad + bond-xmit-hash-policy: layer3+4 + up-delay: 0 + down-delay: 0 + +# public frontend MERGED_FRONTEND vlan 2 +- type: vlan + name: bond0.2 + mtu: 9000 + vlan_id: 2 + vlan_link: bond0 + subnets: + - address: 1.2.3.4/29 + gateway: 1.2.3.5 + type: static + +# private backend vlan 4 +- type: vlan + mtu: 9000 + name: bond0.4 + vlan_id: 4 + vlan_link: bond0 + subnets: + - type: static + address: 10.0.0.11/24 + +- type: nameserver + address: + - 8.8.8.8 + - 8.8.4.4 diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-cloud-init.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-cloud-init.yaml index f01cee2d11..1e1735a1a1 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-cloud-init.yaml +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-cloud-init.yaml @@ -60,3 +60,11 @@ network: via: 10.10.4.147 - to: 188.42.208.0/21 via: 10.10.4.147 + + vlans: + bond0.4: + id: 4 + link: bond0 + mtu: 1500 + addresses: + - 192.34.34.34/32 diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-nocloud.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-nocloud.yaml index 43739eb089..51f5659b2d 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-nocloud.yaml +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-nocloud.yaml @@ -59,3 +59,11 @@ bonds: via: 10.10.4.147 - to: 188.42.208.0/21 via: 10.10.4.147 + +vlans: + bond0.4: + id: 4 + link: bond0 + mtu: 1500 + addresses: + - 192.34.34.34/32 diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-serverscom.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-serverscom.yaml new file mode 100644 index 0000000000..52846ce94e --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-serverscom.yaml @@ -0,0 +1,49 @@ +version: 2 +bonds: + aggi: + interfaces: + - int0 + - int1 + addresses: + - 10.26.98.92/29 + parameters: + mode: 802.3ad + lacp-rate: slow + mii-monitor-interval: 100 + up-delay: 200 + down-delay: 200 + transmit-hash-policy: layer3+4 + routes: + - to: 10.0.0.0/8 + via: 10.26.98.91 + - to: 192.168.0.0/16 + via: 10.26.98.91 + - to: 188.42.208.0/21 + via: 10.26.98.91 + agge: + interfaces: + - ext0 + - ext1 + addresses: + - 188.42.48.188/29 + parameters: + mode: 802.3ad + lacp-rate: slow + mii-monitor-interval: 100 + up-delay: 200 + down-delay: 200 + transmit-hash-policy: layer3+4 + gateway4: 188.42.48.187 +ethernets: + int0: + match: + macaddress: 68:05:ca:b8:f1:f8 + int1: + match: + macaddress: 68:05:ca:b8:f1:f9 + ext0: + match: + macaddress: 3c:ec:ef:e0:45:28 + ext1: + match: + macaddress: 3c:ec:ef:e0:45:29 diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2.yaml deleted file mode 100644 index 5d7b0d0435..0000000000 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2.yaml +++ /dev/null @@ -1,49 +0,0 @@ -version: 2 -ethernets: - eth0: - match: - macaddress: '00:20:6e:1f:f9:a8' - dhcp4: true - addresses: - - 192.168.14.2/24 - - 2001:1::1/64 - gateway4: 192.168.14.1 - gateway6: 2001:1::2 - nameservers: - search: [foo.local, bar.local] - addresses: [8.8.8.8] - - ext1: - match: - macaddress: 68:05:ca:b8:f1:f8 - ext2: - match: - macaddress: 68:05:ca:b8:f1:f9 - -bonds: - bond0: - interfaces: - - ext1 - - ext2 - macaddress: e4:3d:1a:4d:6a:28 - mtu: 1500 - parameters: - mode: 802.3ad - mii-monitor-interval: 100 - down-delay: 200 - up-delay: 200 - lacp-rate: fast - transmit-hash-policy: layer3+4 - addresses: - - 10.10.4.140/29 - nameservers: - addresses: - - 1.1.1.1 - - 2.2.2.2 - routes: - - to: 10.0.0.0/8 - via: 10.10.4.147 - - to: 192.168.0.0/16 - via: 10.10.4.147 - - to: 188.42.208.0/21 - via: 10.10.4.147 diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v3.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v3.yaml deleted file mode 100644 index b6fe782617..0000000000 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v3.yaml +++ /dev/null @@ -1,49 +0,0 @@ -version: 2 -ethernets: - eth0: - match: - macaddress: '00:20:6e:1f:f9:a8' - dhcp4: true - addresses: - - 192.168.14.2/24 - - 2001:1::1/64 - gateway4: 192.168.14.1 - gateway6: 2001:1::2 - nameservers: - search: [foo.local, bar.local] - addresses: [8.8.8.8] - - ext1: - match: - macaddress: f4:33:01:16:3d:90 - ext2: - match: - macaddress: 50:a5:1b:e8:7b:db - -bonds: - bond0: - interfaces: - - ext1 - - ext2 - macaddress: e4:3d:1a:4d:6a:28 - mtu: 1500 - parameters: - mode: 802.3ad - mii-monitor-interval: 100 - down-delay: 200 - up-delay: 200 - lacp-rate: fast - transmit-hash-policy: layer3+4 - addresses: - - 10.10.4.140/29 - nameservers: - addresses: - - 1.1.1.1 - - 2.2.2.2 - routes: - - to: 10.0.0.0/8 - via: 10.10.4.147 - - to: 192.168.0.0/16 - via: 10.10.4.147 - - to: 188.42.208.0/21 - via: 10.10.4.147