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 4756f939ba..f98d2949ef 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go @@ -43,6 +43,11 @@ const ( mnt = "/mnt" ) +// NetworkCloudInitConfig wraps nocloud network config to match cloud-init format. +type NetworkCloudInitConfig struct { + Config NetworkConfig `yaml:"network"` +} + // NetworkConfig holds network-config info. type NetworkConfig struct { Version int `yaml:"version"` 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 152acd3687..617281b4c8 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go @@ -11,6 +11,7 @@ import ( "fmt" "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/gen/maps" "github.com/siderolabs/go-procfs/procfs" yaml "gopkg.in/yaml.v3" @@ -121,14 +122,18 @@ func (n *Nocloud) NetworkConfiguration(ctx context.Context, st state.State, ch c return nil } - var unmarshalledNetworkConfig NetworkConfig + var unmarshalledNetworkConfig *NetworkConfig + if metadataNetworkConfigDl != nil { - if err = yaml.Unmarshal(metadataNetworkConfigDl, &unmarshalledNetworkConfig); err != nil { + nc, err := DecodeNetworkConfig(metadataNetworkConfigDl) + if err != nil { return err } + + unmarshalledNetworkConfig = nc } - networkConfig, err := n.ParseMetadata(&unmarshalledNetworkConfig, st, metadata) + networkConfig, err := n.ParseMetadata(unmarshalledNetworkConfig, st, metadata) if err != nil { return err } @@ -141,3 +146,38 @@ func (n *Nocloud) NetworkConfiguration(ctx context.Context, st state.State, ch c return nil } + +// DecodeNetworkConfig decodes the network configuration guessing the format from the content. +func DecodeNetworkConfig(content []byte) (*NetworkConfig, error) { + var decoded map[string]any + + err := yaml.Unmarshal(content, &decoded) + if err != nil { + return nil, err + } + + if _, ok := decoded["network"]; ok { + var ciNetworkConfig NetworkCloudInitConfig + + err = yaml.Unmarshal(content, &ciNetworkConfig) + if err != nil { + return nil, err + } + + return &ciNetworkConfig.Config, nil + } + + // If it is not plain *v2 cloud-init* config then we attempt to decode *nocloud* + if _, ok := decoded["version"]; ok { + var nc NetworkConfig + + err = yaml.Unmarshal(content, &nc) + if err != nil { + return nil, err + } + + return &nc, nil + } + + return nil, fmt.Errorf("failed to decode network configuration, keys: %v", maps.Keys(decoded)) +} 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 560275fb71..9c4bb18df2 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,7 +7,6 @@ package nocloud_test import ( "context" _ "embed" - "fmt" "testing" "github.com/cosi-project/runtime/pkg/state" @@ -25,8 +24,11 @@ import ( //go:embed testdata/metadata-v1.yaml var rawMetadataV1 []byte -//go:embed testdata/metadata-v2.yaml -var rawMetadataV2 []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/expected-v1.yaml var expectedNetworkConfigV1 string @@ -46,8 +48,13 @@ func TestParseMetadata(t *testing.T) { expected: expectedNetworkConfigV1, }, { - name: "V2", - raw: rawMetadataV2, + name: "V2-nocloud", + raw: rawMetadataV2Nocloud, + expected: expectedNetworkConfigV2, + }, + { + name: "V2-cloud-init", + raw: rawMetadataV2CloudInit, expected: expectedNetworkConfigV2, }, } { @@ -74,9 +81,8 @@ func TestParseMetadata(t *testing.T) { eth2.TypedSpec().Kind = "" require.NoError(t, st.Create(context.TODO(), eth2)) - var m nocloud.NetworkConfig - - require.NoError(t, yaml.Unmarshal(tt.raw, &m)) + m, err := nocloud.DecodeNetworkConfig(tt.raw) + require.NoError(t, err) mc := nocloud.MetadataConfig{ Hostname: "talos.fqdn", @@ -88,9 +94,9 @@ func TestParseMetadata(t *testing.T) { InstanceID: "0", } - networkConfig, err := n.ParseMetadata(&m, st, &mc) + networkConfig, err := n.ParseMetadata(m, st, &mc) require.NoError(t, err) - networkConfig2, err := n.ParseMetadata(&m, st, &mc2) + networkConfig2, err := n.ParseMetadata(m, st, &mc2) require.NoError(t, err) marshaled, err := yaml.Marshal(networkConfig) @@ -98,8 +104,6 @@ func TestParseMetadata(t *testing.T) { marshaled2, err := yaml.Marshal(networkConfig2) require.NoError(t, err) - fmt.Print(string(marshaled)) - assert.Equal(t, tt.expected, string(marshaled)) assert.Equal(t, tt.expected, string(marshaled2)) }) 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 new file mode 100644 index 0000000000..d01fba0c19 --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-cloud-init.yaml @@ -0,0 +1,50 @@ +network: + 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-v2-nocloud.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-nocloud.yaml new file mode 100644 index 0000000000..be1720a43c --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-v2-nocloud.yaml @@ -0,0 +1,49 @@ +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