226 lines
8.4 KiB
Go
226 lines
8.4 KiB
Go
/*
|
|
Copyright © 2022 - 2025 SUSE LLC
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package network
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/rancher/elemental-operator/api/v1beta1"
|
|
utilmocks "github.com/rancher/elemental-operator/pkg/util/mocks"
|
|
"github.com/rancher/yip/pkg/schema"
|
|
"go.uber.org/mock/gomock"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"github.com/twpayne/go-vfs"
|
|
"github.com/twpayne/go-vfs/vfst"
|
|
)
|
|
|
|
func TestNetwork(t *testing.T) {
|
|
RegisterFailHandler(Fail)
|
|
RunSpecs(t, "Network Suite")
|
|
}
|
|
|
|
var _ = Describe("configurator", Label("network", "configurator"), func() {
|
|
var fs *vfst.TestFS
|
|
var err error
|
|
var fsCleanup func()
|
|
var runner *utilmocks.MockCommandRunner
|
|
var networkConfigurator Configurator
|
|
BeforeEach(func() {
|
|
fs, fsCleanup, err = vfst.NewTestFS(map[string]interface{}{"/tmp/init": ""})
|
|
Expect(err).ToNot(HaveOccurred())
|
|
mockCtrl := gomock.NewController(GinkgoT())
|
|
runner = utilmocks.NewMockCommandRunner(mockCtrl)
|
|
networkConfigurator = &configurator{
|
|
fs: fs,
|
|
runner: runner,
|
|
}
|
|
DeferCleanup(fsCleanup)
|
|
})
|
|
It("should return error on uknown configurator", func() {
|
|
_, err := networkConfigurator.GetNetworkConfigApplicator(v1beta1.NetworkConfig{Configurator: "does not exist"})
|
|
Expect(errors.Is(err, ErrUnknownConfigurator)).Should(BeTrue(), "Uknown configurator must return ErrUnknownConfigurator")
|
|
})
|
|
It("should return nmconnections yip config applicator", func() {
|
|
wantNetworkConfig := v1beta1.NetworkConfig{
|
|
Configurator: "nmconnections",
|
|
IPAddresses: map[string]string{
|
|
"my-ip-1": "192.168.122.10",
|
|
"my-ip-2": "192.168.122.11",
|
|
},
|
|
Config: map[string]runtime.RawExtension{
|
|
"eth0": {
|
|
Raw: []byte(`"[connection]\nid=Wired connection 1\n[ipv4]\naddress1={my-ip-1}"`),
|
|
},
|
|
"eth1": {
|
|
Raw: []byte(`"[connection]\nid=Wired connection 2\n[ipv4]\naddress1={my-ip-2}"`),
|
|
},
|
|
},
|
|
}
|
|
wantFiles := []schema.File{
|
|
{
|
|
Content: "[connection]\nid=Wired connection 1\n[ipv4]\naddress1=192.168.122.10",
|
|
Path: filepath.Join(systemConnectionsDir, "eth0.nmconnection"),
|
|
Permissions: 0600,
|
|
},
|
|
{
|
|
Content: "[connection]\nid=Wired connection 2\n[ipv4]\naddress1=192.168.122.11",
|
|
Path: filepath.Join(systemConnectionsDir, "eth1.nmconnection"),
|
|
Permissions: 0600,
|
|
},
|
|
}
|
|
|
|
applicator, err := networkConfigurator.GetNetworkConfigApplicator(wantNetworkConfig)
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
|
|
stage, found := applicator.Stages["initramfs"]
|
|
Expect(found).To(BeTrue(), "Config should be applied at initramfs stage")
|
|
|
|
Expect(len(stage[0].Files)).To(Equal(2), "Two nmconnection files must have been copied")
|
|
Expect(stage[0].Files).To(ContainElements(wantFiles))
|
|
})
|
|
It("should return nmstate yip config applicator", func() {
|
|
wantNetworkConfig := v1beta1.NetworkConfig{
|
|
Configurator: "nmstate",
|
|
IPAddresses: map[string]string{
|
|
"foo": "192.168.122.10",
|
|
"bar": "192.168.122.11",
|
|
},
|
|
Config: map[string]runtime.RawExtension{
|
|
"foo": {
|
|
Raw: []byte(`"{foo}"`),
|
|
},
|
|
"bar": {
|
|
Raw: []byte(`"{bar}"`),
|
|
},
|
|
},
|
|
}
|
|
|
|
wantFiles := []schema.File{
|
|
{
|
|
Content: "[connection]\nid=Wired connection 1\n",
|
|
Path: filepath.Join(systemConnectionsDir, "wired1.nmconnection"),
|
|
Permissions: 0600,
|
|
},
|
|
{
|
|
Content: "[connection]\nid=Wired connection 2\n",
|
|
Path: filepath.Join(systemConnectionsDir, "wired2.nmconnection"),
|
|
Permissions: 0600,
|
|
},
|
|
}
|
|
|
|
runner.EXPECT().Run("nmstatectl", "apply", nmstateTempPath).Return(nil)
|
|
//prepare some dummy nmconnection files to simulate `nmstatectl apply` result
|
|
Expect(vfs.MkdirAll(fs, systemConnectionsDir, 0700)).Should(Succeed())
|
|
Expect(fs.WriteFile(filepath.Join(systemConnectionsDir, "wired1.nmconnection"), []byte("[connection]\nid=Wired connection 1\n"), 0600)).Should(Succeed())
|
|
Expect(fs.WriteFile(filepath.Join(systemConnectionsDir, "wired2.nmconnection"), []byte("[connection]\nid=Wired connection 2\n"), 0600)).Should(Succeed())
|
|
|
|
applicator, err := networkConfigurator.GetNetworkConfigApplicator(wantNetworkConfig)
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
|
|
// Test the variable substitution took place when generating the nmstate config from the template
|
|
compareFiles(fs, nmstateTempPath, "_testdata/digested-intermediate.yaml")
|
|
|
|
stage, found := applicator.Stages["initramfs"]
|
|
Expect(found).To(BeTrue(), "Config should be applied at initramfs stage")
|
|
|
|
Expect(len(stage[0].Files)).To(Equal(2), "Two nmconnection files must have been copied")
|
|
Expect(stage[0].Files).To(ContainElements(wantFiles))
|
|
})
|
|
It("should return nmc yip config applicator", func() {
|
|
wantNetworkConfig := v1beta1.NetworkConfig{
|
|
Configurator: "nmc",
|
|
IPAddresses: map[string]string{
|
|
"foo": "192.168.122.10",
|
|
"bar": "192.168.122.11",
|
|
},
|
|
Config: map[string]runtime.RawExtension{
|
|
"foo": {
|
|
Raw: []byte(`"{foo}"`),
|
|
},
|
|
"bar": {
|
|
Raw: []byte(`"{bar}"`),
|
|
},
|
|
},
|
|
}
|
|
wantFiles := []schema.File{
|
|
{
|
|
Content: "[connection]\nid=Wired connection 1\n",
|
|
Path: filepath.Join(systemConnectionsDir, "wired1.nmconnection"),
|
|
Permissions: 0600,
|
|
},
|
|
{
|
|
Content: "[connection]\nid=Wired connection 2\n",
|
|
Path: filepath.Join(systemConnectionsDir, "wired2.nmconnection"),
|
|
Permissions: 0600,
|
|
},
|
|
}
|
|
|
|
runner.EXPECT().Run("nmc", "generate", "--config-dir", nmcDesiredStatesDir, "--output-dir", nmcNewtorkConfigDir).Return(nil)
|
|
runner.EXPECT().Run("nmc", "apply", "--config-dir", nmcNewtorkConfigDir).Return(nil)
|
|
//prepare some dummy nmconnection files to simulate `nmc apply` result
|
|
Expect(vfs.MkdirAll(fs, systemConnectionsDir, 0700)).Should(Succeed())
|
|
Expect(fs.WriteFile(filepath.Join(systemConnectionsDir, "wired1.nmconnection"), []byte("[connection]\nid=Wired connection 1\n"), 0600)).Should(Succeed())
|
|
Expect(fs.WriteFile(filepath.Join(systemConnectionsDir, "wired2.nmconnection"), []byte("[connection]\nid=Wired connection 2\n"), 0600)).Should(Succeed())
|
|
|
|
applicator, err := networkConfigurator.GetNetworkConfigApplicator(wantNetworkConfig)
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
|
|
// Test the variable substitution took place when generating the nmc config from the template
|
|
compareFiles(fs, filepath.Join(nmcDesiredStatesDir, nmcAllConfigName), "_testdata/digested-intermediate.yaml")
|
|
|
|
stage, found := applicator.Stages["initramfs"]
|
|
Expect(found).To(BeTrue(), "Config should be applied at initramfs stage")
|
|
|
|
Expect(len(stage[0].Files)).To(Equal(2), "Two nmconnection files must have been copied")
|
|
Expect(stage[0].Files).To(ContainElements(wantFiles))
|
|
})
|
|
It("should reset network", func() {
|
|
//prepare a dummy nmconnection file to highlight the need to reset network
|
|
Expect(vfs.MkdirAll(fs, systemConnectionsDir, 0700)).Should(Succeed())
|
|
Expect(fs.WriteFile(filepath.Join(systemConnectionsDir, "wired1.nmconnection"), []byte("[connection]\nid=Wired connection 1\n"), 0600)).Should(Succeed())
|
|
|
|
gomock.InOrder(
|
|
runner.EXPECT().Run("find", systemConnectionsDir, "-name", "*.nmconnection", "-type", "f", "-delete").Return(nil),
|
|
runner.EXPECT().Run("nmcli", "connection", "reload").Return(nil),
|
|
runner.EXPECT().Run("systemctl", "restart", "NetworkManager.service").Return(nil),
|
|
runner.EXPECT().Run("systemctl", "start", "NetworkManager-wait-online.service").Return(nil),
|
|
runner.EXPECT().Run("systemctl", "restart", "elemental-system-agent.service").Return(nil),
|
|
)
|
|
|
|
Expect(networkConfigurator.ResetNetworkConfig()).Should(Succeed())
|
|
})
|
|
It("should consider reset network done if no nmconnection files", func() {
|
|
Expect(vfs.MkdirAll(fs, systemConnectionsDir, 0700)).Should(Succeed())
|
|
|
|
Expect(networkConfigurator.ResetNetworkConfig()).Should(Succeed())
|
|
})
|
|
})
|
|
|
|
func compareFiles(fs vfs.FS, got string, want string) {
|
|
gotFile, err := fs.ReadFile(got)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
wantFile, err := os.ReadFile(want)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(string(gotFile)).To(Equal(string(wantFile)))
|
|
}
|