feat: add support for CI Network config in nocloud

Fixes #9351

Signed-off-by: ekarlso <endre.karlson@gmail.com>
Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
(cherry picked from commit aa846cc186c1c6125f8f39ea084fa2023512656f)
This commit is contained in:
ekarlso 2024-09-21 22:48:45 +02:00 committed by Andrey Smirnov
parent 01e580bddb
commit d29f660799
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
5 changed files with 163 additions and 15 deletions

View File

@ -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"`

View File

@ -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))
}

View File

@ -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))
})

View File

@ -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

View File

@ -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