From b580f1bddd31e646a10ebef1836480051bbd060f Mon Sep 17 00:00:00 2001 From: Yaacov Zamir Date: Wed, 28 Aug 2024 13:15:31 +0300 Subject: [PATCH] [MTV-595] [2.6.5] Add customize disk image step to virt-v2v pod (#995) Backport of https://github.com/kubev2v/forklift/pull/985 - sen mac <=> ip mappings for linux https://github.com/kubev2v/forklift/pull/983 - customize script for linux https://github.com/kubev2v/forklift/pull/997 - refactor bash script https://github.com/kubev2v/forklift/pull/998 - run customize script on any linux Ref: https://issues.redhat.com/browse/MTV-595 Issue: When migrating a simple RHEL8 VM from VMware 7 to OCPv 4.13 the name of the network interfaces changes and the static IP configuration for the VM no longer works --------- Signed-off-by: yaacov --- .../plan/adapter/vsphere/BUILD.bazel | 1 + .../plan/adapter/vsphere/builder.go | 14 +- .../plan/adapter/vsphere/builder_test.go | 18 +- .../plan/adapter/vsphere/validator.go | 3 - .../plan/adapter/vsphere/validator_test.go | 9 +- virt-v2v/cold/BUILD.bazel | 68 ++-- virt-v2v/cold/WORKSPACE | 174 +++++----- virt-v2v/cold/customize-image.go | 8 +- virt-v2v/cold/customize-rhel.go | 140 ++++++++ virt-v2v/cold/customize-rhel_test.go | 301 ++++++++++++++++++ virt-v2v/cold/entrypoint.go | 62 +++- .../cold/scripts/rhel/firstboot/README.md | 3 + virt-v2v/cold/scripts/rhel/run/README.md | 3 + .../scripts/rhel/run/network_config_util.sh | 97 ++++++ .../scripts/rhel/run/network_config_util_test | 56 ++++ 15 files changed, 811 insertions(+), 146 deletions(-) create mode 100644 virt-v2v/cold/customize-rhel.go create mode 100644 virt-v2v/cold/customize-rhel_test.go create mode 100644 virt-v2v/cold/scripts/rhel/firstboot/README.md create mode 100644 virt-v2v/cold/scripts/rhel/run/README.md create mode 100644 virt-v2v/cold/scripts/rhel/run/network_config_util.sh create mode 100644 virt-v2v/cold/scripts/rhel/run/network_config_util_test diff --git a/pkg/controller/plan/adapter/vsphere/BUILD.bazel b/pkg/controller/plan/adapter/vsphere/BUILD.bazel index f5e1062ae..965c8402b 100644 --- a/pkg/controller/plan/adapter/vsphere/BUILD.bazel +++ b/pkg/controller/plan/adapter/vsphere/BUILD.bazel @@ -63,6 +63,7 @@ go_test( "//pkg/controller/plan/util", "//pkg/controller/provider/model/vsphere", "//pkg/controller/provider/web", + "//pkg/controller/provider/web/base", "//pkg/controller/provider/web/vsphere", "//pkg/lib/logging", "//vendor/github.com/onsi/ginkgo/v2:ginkgo", diff --git a/pkg/controller/plan/adapter/vsphere/builder.go b/pkg/controller/plan/adapter/vsphere/builder.go index d26ddc9f2..3acd1bdbc 100644 --- a/pkg/controller/plan/adapter/vsphere/builder.go +++ b/pkg/controller/plan/adapter/vsphere/builder.go @@ -237,13 +237,14 @@ func (r *Builder) PodEnvironment(vmRef ref.Ref, sourceSecret *core.Secret) (env } func (r *Builder) mapMacStaticIps(vm *model.VM) (ipMap string, err error) { - if !isWindows(vm) { - return "", nil - } + // on windows machines we check if the interface origin is manual + // on linux we collect all networks. + isWindowsFlag := isWindows(vm) + configurations := []string{} gatewaySet := false for _, guestNetwork := range vm.GuestNetworks { - if guestNetwork.Origin == string(types.NetIpConfigInfoIpAddressOriginManual) { + if !isWindowsFlag || guestNetwork.Origin == string(types.NetIpConfigInfoIpAddressOriginManual) { gateway := "" if !gatewaySet { isIpv4 := net.IP.To4(net.ParseIP(guestNetwork.IP)) != nil @@ -269,7 +270,10 @@ func (r *Builder) mapMacStaticIps(vm *model.VM) (ipMap string, err error) { } } dnsString := strings.Join(guestNetwork.DNS, ",") - configurations = append(configurations, fmt.Sprintf("%s:ip:%s,%s,%d,%s", guestNetwork.MAC, guestNetwork.IP, gateway, guestNetwork.PrefixLength, dnsString)) + configurationString := fmt.Sprintf("%s:ip:%s,%s,%d,%s", guestNetwork.MAC, guestNetwork.IP, gateway, guestNetwork.PrefixLength, dnsString) + + // if DNS is "", we get configurationString with trailing comma, use TrimSuffix to remove it. + configurations = append(configurations, strings.TrimSuffix(configurationString, ",")) } } return strings.Join(configurations, "_"), nil diff --git a/pkg/controller/plan/adapter/vsphere/builder_test.go b/pkg/controller/plan/adapter/vsphere/builder_test.go index 3aa2374e6..2bef83dd7 100644 --- a/pkg/controller/plan/adapter/vsphere/builder_test.go +++ b/pkg/controller/plan/adapter/vsphere/builder_test.go @@ -67,8 +67,8 @@ var _ = Describe("vSphere builder", func() { }, }, "00:50:56:83:25:47:ip:172.29.3.193,172.29.3.1,16,8.8.8.8_00:50:56:83:25:47:ip:fe80::5da:b7a5:e0a2:a097,,64,fec0:0:0:ffff::1,fec0:0:0:ffff::2,fec0:0:0:ffff::3"), Entry("non-static ip", &model.VM{GuestID: "windows9Guest", GuestNetworks: []vsphere.GuestNetwork{{MAC: "00:50:56:83:25:47", IP: "172.29.3.193", Origin: string(types.NetIpConfigInfoIpAddressOriginDhcp)}}}, ""), - Entry("non windows vm", &model.VM{GuestID: "other", GuestNetworks: []vsphere.GuestNetwork{{MAC: "00:50:56:83:25:47", IP: "172.29.3.193", Origin: ManualOrigin}}}, ""), - Entry("no OS vm", &model.VM{GuestNetworks: []vsphere.GuestNetwork{{MAC: "00:50:56:83:25:47", IP: "172.29.3.193", Origin: ManualOrigin}}}, ""), + Entry("non windows vm", &model.VM{GuestID: "other", GuestNetworks: []vsphere.GuestNetwork{{MAC: "00:50:56:83:25:47", IP: "172.29.3.193", Origin: ManualOrigin}}}, "00:50:56:83:25:47:ip:172.29.3.193,,0"), + Entry("no OS vm", &model.VM{GuestNetworks: []vsphere.GuestNetwork{{MAC: "00:50:56:83:25:47", IP: "172.29.3.193", Origin: ManualOrigin}}}, "00:50:56:83:25:47:ip:172.29.3.193,,0"), Entry("multiple nics static ips", &model.VM{ GuestID: "windows9Guest", GuestNetworks: []vsphere.GuestNetwork{ @@ -116,6 +116,20 @@ var _ = Describe("vSphere builder", func() { }, }, }, "00:50:56:83:25:47:ip:172.29.3.193,172.29.3.1,16,8.8.8.8_00:50:56:83:25:47:ip:fe80::5da:b7a5:e0a2:a097,,64,fec0:0:0:ffff::1,fec0:0:0:ffff::2,fec0:0:0:ffff::3_00:50:56:83:25:48:ip:172.29.3.192,,24,4.4.4.4_00:50:56:83:25:48:ip:fe80::5da:b7a5:e0a2:a090,,32,fec0:0:0:ffff::4,fec0:0:0:ffff::5,fec0:0:0:ffff::6"), + Entry("single static ip without DNS", &model.VM{ + GuestID: "windows9Guest", + GuestNetworks: []vsphere.GuestNetwork{ + { + MAC: "00:50:56:83:25:47", + IP: "172.29.3.193", + Origin: ManualOrigin, + PrefixLength: 16, + }}, + GuestIpStacks: []vsphere.GuestIpStack{ + { + Gateway: "172.29.3.1", + }}, + }, "00:50:56:83:25:47:ip:172.29.3.193,172.29.3.1,16"), ) }) diff --git a/pkg/controller/plan/adapter/vsphere/validator.go b/pkg/controller/plan/adapter/vsphere/validator.go index f42911338..4c842d9a9 100644 --- a/pkg/controller/plan/adapter/vsphere/validator.go +++ b/pkg/controller/plan/adapter/vsphere/validator.go @@ -139,9 +139,6 @@ func (r *Validator) StaticIPs(vmRef ref.Ref) (ok bool, err error) { err = liberr.Wrap(err, "vm", vmRef) return } - if !isWindows(&vm.VM) { - return true, nil - } for _, nic := range vm.NICs { found := false diff --git a/pkg/controller/plan/adapter/vsphere/validator_test.go b/pkg/controller/plan/adapter/vsphere/validator_test.go index f8d6989d1..5735153ad 100644 --- a/pkg/controller/plan/adapter/vsphere/validator_test.go +++ b/pkg/controller/plan/adapter/vsphere/validator_test.go @@ -7,6 +7,7 @@ import ( "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" "github.com/konveyor/forklift-controller/pkg/controller/provider/model/vsphere" "github.com/konveyor/forklift-controller/pkg/controller/provider/web" + "github.com/konveyor/forklift-controller/pkg/controller/provider/web/base" model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/vsphere" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -36,6 +37,9 @@ func (m *mockInventory) Find(resource interface{}, ref ref.Ref) error { if ref.Name == "not_windows_guest" { res.VM.GuestID = "rhel8_64Guest" } + if ref.Name == "missing_from_invetory" { + return base.NotFoundError{} + } } return nil } @@ -88,7 +92,6 @@ var _ = Describe("vsphere validation tests", func() { } ok, err := validator.StaticIPs(ref.Ref{Name: vmName}) if shouldError { - Expect(err).NotTo(HaveOccurred()) Expect(ok).To(BeFalse()) } else { Expect(err).NotTo(HaveOccurred()) @@ -101,7 +104,9 @@ var _ = Describe("vsphere validation tests", func() { Entry("when the vm doesn't have static ips, and the plan set without static ip", "test", false, false), Entry("when the vm have static ips, and the plan set with static ip", "full_guest_network", true, false), Entry("when the vm have static ips, and the plan set without static ip", "test", false, false), - Entry("when the vm doesn't have static ips, and the plan set without static ip, vm is non-windows", "not_windows_guest", true, false), + Entry("when the vm doesn't have static ips, and the plan set without static ip, vm is non-windows", "not_windows_guest", false, false), + Entry("when the vm doesn't have static ips, and the plan set with static ip, vm is non-windows", "not_windows_guest", true, true), + Entry("when the vm doesn't exist", "missing_from_invetory", true, true), ) }) }) diff --git a/virt-v2v/cold/BUILD.bazel b/virt-v2v/cold/BUILD.bazel index 86081652b..0a44294d8 100644 --- a/virt-v2v/cold/BUILD.bazel +++ b/virt-v2v/cold/BUILD.bazel @@ -94,6 +94,7 @@ go_library( name = "cold_lib", srcs = [ "customize-image.go", + "customize-rhel.go", "embed-tool.go", "entrypoint.go", "xml-reader.go", @@ -102,6 +103,10 @@ go_library( "scripts/windows/9999-restore_config.ps1", "scripts/windows/9999-restore_config_init.bat", "scripts/windows/firstboot.bat", + "scripts/rhel/firstboot/README.md", + "scripts/rhel/run/README.md", + "scripts/rhel/run/network_config_util.sh", + "scripts/rhel/run/network_config_util_test", ], importpath = "github.com/konveyor/forklift-controller/virt-v2v/cold", visibility = ["//visibility:private"], @@ -134,7 +139,10 @@ container_image( go_test( name = "cold_test", - srcs = ["cold_test.go"], + srcs = [ + "cold_test.go", + "customize-rhel_test.go", + ], data = glob(["testdata/**"]), embed = [":cold_lib"], ) @@ -151,7 +159,7 @@ rpmtree( "@bash-0__5.1.8-9.el9.x86_64//rpm", "@bzip2-0__1.0.8-8.el9.x86_64//rpm", "@bzip2-libs-0__1.0.8-8.el9.x86_64//rpm", - "@ca-certificates-0__2024.2.69_v8.0.303-91.3.el9.x86_64//rpm", + "@ca-certificates-0__2024.2.69_v8.0.303-91.4.el9.x86_64//rpm", "@capstone-0__4.0.2-10.el9.x86_64//rpm", "@centos-gpg-keys-0__9.0-11.el9.x86_64//rpm", "@centos-stream-release-0__9.0-11.el9.x86_64//rpm", @@ -161,12 +169,12 @@ rpmtree( "@cpio-0__2.13-16.el9.x86_64//rpm", "@cracklib-0__2.9.6-27.el9.x86_64//rpm", "@cracklib-dicts-0__2.9.6-27.el9.x86_64//rpm", - "@crypto-policies-0__20240815-1.gite217f03.el9.x86_64//rpm", + "@crypto-policies-0__20240822-1.gitbaf3e06.el9.x86_64//rpm", "@cryptsetup-libs-0__2.7.2-1.el9.x86_64//rpm", - "@curl-minimal-0__7.76.1-30.el9.x86_64//rpm", + "@curl-minimal-0__7.76.1-31.el9.x86_64//rpm", "@cyrus-sasl-gssapi-0__2.1.27-21.el9.x86_64//rpm", "@cyrus-sasl-lib-0__2.1.27-21.el9.x86_64//rpm", - "@daxctl-libs-0__71.1-8.el9.x86_64//rpm", + "@daxctl-libs-0__78-2.el9.x86_64//rpm", "@dbus-1__1.12.20-8.el9.x86_64//rpm", "@dbus-broker-0__28-7.el9.x86_64//rpm", "@dbus-common-1__1.12.20-8.el9.x86_64//rpm", @@ -174,10 +182,10 @@ rpmtree( "@device-mapper-libs-9__1.02.198-2.el9.x86_64//rpm", "@diffutils-0__3.7-12.el9.x86_64//rpm", "@dmidecode-1__3.6-1.el9.x86_64//rpm", - "@dracut-0__057-67.git20240812.el9.x86_64//rpm", + "@dracut-0__057-70.git20240819.el9.x86_64//rpm", "@dwz-0__0.14-3.el9.x86_64//rpm", "@e2fsprogs-libs-0__1.46.5-5.el9.x86_64//rpm", - "@edk2-ovmf-0__20240524-2.el9.x86_64//rpm", + "@edk2-ovmf-0__20240524-3.el9.x86_64//rpm", "@efi-srpm-macros-0__6-2.el9.x86_64//rpm", "@elfutils-libelf-0__0.191-4.el9.x86_64//rpm", "@expat-0__2.5.0-2.el9.x86_64//rpm", @@ -210,11 +218,11 @@ rpmtree( "@groff-base-0__1.22.4-10.el9.x86_64//rpm", "@gsettings-desktop-schemas-0__40.0-6.el9.x86_64//rpm", "@gssproxy-0__0.8.4-7.el9.x86_64//rpm", - "@guestfs-tools-0__1.51.6-3.el9.x86_64//rpm", + "@guestfs-tools-0__1.51.6-5.el9.x86_64//rpm", "@gzip-0__1.12-1.el9.x86_64//rpm", "@hexedit-0__1.6-1.el9.x86_64//rpm", "@hivex-libs-0__1.3.21-3.el9.x86_64//rpm", - "@hwdata-0__0.348-9.14.el9.x86_64//rpm", + "@hwdata-0__0.348-9.15.el9.x86_64//rpm", "@inih-0__49-6.el9.x86_64//rpm", "@iproute-0__6.2.0-5.el9.x86_64//rpm", "@iproute-tc-0__6.2.0-5.el9.x86_64//rpm", @@ -226,8 +234,8 @@ rpmtree( "@kbd-0__2.4.0-10.el9.x86_64//rpm", "@kbd-legacy-0__2.4.0-10.el9.x86_64//rpm", "@kbd-misc-0__2.4.0-10.el9.x86_64//rpm", - "@kernel-core-0__5.14.0-495.el9.x86_64//rpm", - "@kernel-modules-core-0__5.14.0-495.el9.x86_64//rpm", + "@kernel-core-0__5.14.0-500.el9.x86_64//rpm", + "@kernel-modules-core-0__5.14.0-500.el9.x86_64//rpm", "@kernel-srpm-macros-0__1.0-13.el9.x86_64//rpm", "@keyutils-0__1.6.3-1.el9.x86_64//rpm", "@keyutils-libs-0__1.6.3-1.el9.x86_64//rpm", @@ -242,7 +250,7 @@ rpmtree( "@libassuan-0__2.5.5-3.el9.x86_64//rpm", "@libattr-0__2.5.1-3.el9.x86_64//rpm", "@libbasicobjects-0__0.1.1-53.el9.x86_64//rpm", - "@libblkid-0__2.37.4-18.el9.x86_64//rpm", + "@libblkid-0__2.37.4-20.el9.x86_64//rpm", "@libbpf-2__1.4.0-1.el9.x86_64//rpm", "@libbrotli-0__1.0.9-6.el9.x86_64//rpm", "@libcap-0__2.48-9.el9.x86_64//rpm", @@ -251,13 +259,13 @@ rpmtree( "@libcollection-0__0.7.0-53.el9.x86_64//rpm", "@libcom_err-0__1.46.5-5.el9.x86_64//rpm", "@libconfig-0__1.7.2-9.el9.x86_64//rpm", - "@libcurl-minimal-0__7.76.1-30.el9.x86_64//rpm", + "@libcurl-minimal-0__7.76.1-31.el9.x86_64//rpm", "@libdb-0__5.3.28-54.el9.x86_64//rpm", "@libeconf-0__0.4.1-4.el9.x86_64//rpm", "@libedit-0__3.1-38.20210216cvs.el9.x86_64//rpm", "@libev-0__4.33-5.el9.x86_64//rpm", "@libevent-0__2.1.12-6.el9.x86_64//rpm", - "@libfdisk-0__2.37.4-18.el9.x86_64//rpm", + "@libfdisk-0__2.37.4-20.el9.x86_64//rpm", "@libfdt-0__1.6.0-7.el9.x86_64//rpm", "@libffi-0__3.4.2-8.el9.x86_64//rpm", "@libfido2-0__1.13.0-2.el9.x86_64//rpm", @@ -275,7 +283,7 @@ rpmtree( "@libkcapi-hmaccalc-0__1.4.0-2.el9.x86_64//rpm", "@libksba-0__1.5.1-7.el9.x86_64//rpm", "@libmnl-0__1.0.4-15.el9.x86_64//rpm", - "@libmount-0__2.37.4-18.el9.x86_64//rpm", + "@libmount-0__2.37.4-20.el9.x86_64//rpm", "@libnbd-0__1.20.2-2.el9.x86_64//rpm", "@libnetfilter_conntrack-0__1.0.9-1.el9.x86_64//rpm", "@libnfnetlink-0__1.0.1-21.el9.x86_64//rpm", @@ -300,7 +308,7 @@ rpmtree( "@libsepol-0__3.6-1.el9.x86_64//rpm", "@libsigsegv-0__2.13-4.el9.x86_64//rpm", "@libslirp-0__4.4.0-8.el9.x86_64//rpm", - "@libsmartcols-0__2.37.4-18.el9.x86_64//rpm", + "@libsmartcols-0__2.37.4-20.el9.x86_64//rpm", "@libsoup-0__2.72.0-8.el9.x86_64//rpm", "@libssh-0__0.10.4-13.el9.x86_64//rpm", "@libssh-config-0__0.10.4-13.el9.x86_64//rpm", @@ -312,7 +320,7 @@ rpmtree( "@liburing-0__2.5-1.el9.x86_64//rpm", "@libusbx-0__1.0.26-1.el9.x86_64//rpm", "@libutempter-0__1.2.1-6.el9.x86_64//rpm", - "@libuuid-0__2.37.4-18.el9.x86_64//rpm", + "@libuuid-0__2.37.4-20.el9.x86_64//rpm", "@libverto-0__0.3.2-3.el9.x86_64//rpm", "@libverto-libev-0__0.3.2-3.el9.x86_64//rpm", "@libvirt-client-0__10.5.0-5.el9.x86_64//rpm", @@ -349,7 +357,7 @@ rpmtree( "@ncurses-0__6.2-10.20210508.el9.x86_64//rpm", "@ncurses-base-0__6.2-10.20210508.el9.x86_64//rpm", "@ncurses-libs-0__6.2-10.20210508.el9.x86_64//rpm", - "@ndctl-libs-0__71.1-8.el9.x86_64//rpm", + "@ndctl-libs-0__78-2.el9.x86_64//rpm", "@nettle-0__3.9.1-1.el9.x86_64//rpm", "@nfs-utils-1__2.5.4-27.el9.x86_64//rpm", "@npth-0__1.6-8.el9.x86_64//rpm", @@ -360,8 +368,8 @@ rpmtree( "@openldap-0__2.6.6-3.el9.x86_64//rpm", "@openssh-0__8.7p1-43.el9.x86_64//rpm", "@openssh-clients-0__8.7p1-43.el9.x86_64//rpm", - "@openssl-1__3.2.2-2.el9.x86_64//rpm", - "@openssl-libs-1__3.2.2-2.el9.x86_64//rpm", + "@openssl-1__3.2.2-4.el9.x86_64//rpm", + "@openssl-libs-1__3.2.2-4.el9.x86_64//rpm", "@osinfo-db-0__20240701-2.el9.x86_64//rpm", "@osinfo-db-tools-0__1.10.0-1.el9.x86_64//rpm", "@p11-kit-0__0.25.3-2.el9.x86_64//rpm", @@ -466,22 +474,22 @@ rpmtree( "@swtpm-0__0.8.0-2.el9.x86_64//rpm", "@swtpm-libs-0__0.8.0-2.el9.x86_64//rpm", "@swtpm-tools-0__0.8.0-2.el9.x86_64//rpm", - "@systemd-0__252-38.el9.x86_64//rpm", - "@systemd-container-0__252-38.el9.x86_64//rpm", - "@systemd-libs-0__252-38.el9.x86_64//rpm", - "@systemd-pam-0__252-38.el9.x86_64//rpm", - "@systemd-rpm-macros-0__252-38.el9.x86_64//rpm", - "@systemd-udev-0__252-38.el9.x86_64//rpm", + "@systemd-0__252-45.el9.x86_64//rpm", + "@systemd-container-0__252-45.el9.x86_64//rpm", + "@systemd-libs-0__252-45.el9.x86_64//rpm", + "@systemd-pam-0__252-45.el9.x86_64//rpm", + "@systemd-rpm-macros-0__252-45.el9.x86_64//rpm", + "@systemd-udev-0__252-45.el9.x86_64//rpm", "@tar-2__1.34-7.el9.x86_64//rpm", "@tpm2-tss-0__3.2.3-1.el9.x86_64//rpm", "@tzdata-0__2024a-2.el9.x86_64//rpm", "@unbound-libs-0__1.16.2-8.el9.x86_64//rpm", - "@unzip-0__6.0-56.el9.x86_64//rpm", + "@unzip-0__6.0-57.el9.x86_64//rpm", "@userspace-rcu-0__0.12.1-6.el9.x86_64//rpm", - "@util-linux-0__2.37.4-18.el9.x86_64//rpm", - "@util-linux-core-0__2.37.4-18.el9.x86_64//rpm", + "@util-linux-0__2.37.4-20.el9.x86_64//rpm", + "@util-linux-core-0__2.37.4-20.el9.x86_64//rpm", "@vim-minimal-2__8.2.2637-21.el9.x86_64//rpm", - "@virt-v2v-1__2.5.6-3.el9.x86_64//rpm", + "@virt-v2v-1__2.5.6-4.el9.x86_64//rpm", "@virtio-win-0__1.9.15-4.el9.x86_64//rpm", "@which-0__2.21-29.el9.x86_64//rpm", "@xfsprogs-0__6.4.0-4.el9.x86_64//rpm", diff --git a/virt-v2v/cold/WORKSPACE b/virt-v2v/cold/WORKSPACE index 6eb0928fb..b9c58ca9e 100644 --- a/virt-v2v/cold/WORKSPACE +++ b/virt-v2v/cold/WORKSPACE @@ -283,10 +283,10 @@ rpm( ) rpm( - name = "ca-certificates-0__2024.2.69_v8.0.303-91.3.el9.x86_64", - sha256 = "b465bbf264432808f2843ee4c155ea5b3da91dd4334d0101e3724d502baef529", + name = "ca-certificates-0__2024.2.69_v8.0.303-91.4.el9.x86_64", + sha256 = "345cfd71983f45555db1f5c23e155f8f6720d640b68f54538c512cdc7b791432", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/ca-certificates-2024.2.69_v8.0.303-91.3.el9.noarch.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/ca-certificates-2024.2.69_v8.0.303-91.4.el9.noarch.rpm", ], ) @@ -363,10 +363,10 @@ rpm( ) rpm( - name = "crypto-policies-0__20240815-1.gite217f03.el9.x86_64", - sha256 = "fa65498af3120f1b07d340803f033e823f279a06b0976b78ade45a3a065598de", + name = "crypto-policies-0__20240822-1.gitbaf3e06.el9.x86_64", + sha256 = "f01a7b6cd9d00c2954ef513925c5b8d5856f8b30910baccd877e54e343419fb1", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/crypto-policies-20240815-1.gite217f03.el9.noarch.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/crypto-policies-20240822-1.gitbaf3e06.el9.noarch.rpm", ], ) @@ -379,10 +379,10 @@ rpm( ) rpm( - name = "curl-minimal-0__7.76.1-30.el9.x86_64", - sha256 = "f1406f64b10e6d05c126878854558eb7971215dade206bdce31be1a5f9b973b8", + name = "curl-minimal-0__7.76.1-31.el9.x86_64", + sha256 = "3f1fa51412b82574a44a4af083fc5a1e59ada73214fd99c2e7faeddf6245e430", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/curl-minimal-7.76.1-30.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/curl-minimal-7.76.1-31.el9.x86_64.rpm", ], ) @@ -403,10 +403,10 @@ rpm( ) rpm( - name = "daxctl-libs-0__71.1-8.el9.x86_64", - sha256 = "8508b5909702514591d098a761ead3374e803e2b841afdb6a259c0ebc0928cac", + name = "daxctl-libs-0__78-2.el9.x86_64", + sha256 = "ea73c055c6217c16ddf5fde584c6473344ec1b03b4c89459a58440971da1ca5c", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/daxctl-libs-71.1-8.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/daxctl-libs-78-2.el9.x86_64.rpm", ], ) @@ -467,10 +467,10 @@ rpm( ) rpm( - name = "dracut-0__057-67.git20240812.el9.x86_64", - sha256 = "a95fa64575dd6a5499c9776ef5d781cf9c74ccdc7a292a71fdc441df39da4792", + name = "dracut-0__057-70.git20240819.el9.x86_64", + sha256 = "eac211c808c74f063a4c8ab9e0332309ee5973c790771708c79d7f44a1a0083d", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/dracut-057-67.git20240812.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/dracut-057-70.git20240819.el9.x86_64.rpm", ], ) @@ -491,10 +491,10 @@ rpm( ) rpm( - name = "edk2-ovmf-0__20240524-2.el9.x86_64", - sha256 = "3df8fdf3bbe5c495a4187dd273d0170cb086733d929efb232f02cd30eb4504de", + name = "edk2-ovmf-0__20240524-3.el9.x86_64", + sha256 = "31a3bb41da1243f3532965441b1176f499404fb8b7e214d6e81d4d20c3a6cd87", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/x86_64/os/Packages/edk2-ovmf-20240524-2.el9.noarch.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/x86_64/os/Packages/edk2-ovmf-20240524-3.el9.noarch.rpm", ], ) @@ -755,10 +755,10 @@ rpm( ) rpm( - name = "guestfs-tools-0__1.51.6-3.el9.x86_64", - sha256 = "6c60f887151fbe60372898f0b25509806136f7e1e4becf4b99b899aa1b5c0734", + name = "guestfs-tools-0__1.51.6-5.el9.x86_64", + sha256 = "969e43c14a60825bf95be175506bbbd68b2d89e484368f54784eb00da276ccc6", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/x86_64/os/Packages/guestfs-tools-1.51.6-3.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/x86_64/os/Packages/guestfs-tools-1.51.6-5.el9.x86_64.rpm", ], ) @@ -787,10 +787,10 @@ rpm( ) rpm( - name = "hwdata-0__0.348-9.14.el9.x86_64", - sha256 = "53650c92e8122af5422e612e1d01fb0e66797f6c2ba7a34989b4d7de173f3467", + name = "hwdata-0__0.348-9.15.el9.x86_64", + sha256 = "63bdecc9281f2fa5c02b2764a423b913e374406b1e0186246abe5926e3365cb6", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/hwdata-0.348-9.14.el9.noarch.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/hwdata-0.348-9.15.el9.noarch.rpm", ], ) @@ -883,18 +883,18 @@ rpm( ) rpm( - name = "kernel-core-0__5.14.0-495.el9.x86_64", - sha256 = "fc3030325597a20cd5f909c84fdc0d1cd8d7ed4fed4e6c720f8a17c3bf0e2f21", + name = "kernel-core-0__5.14.0-500.el9.x86_64", + sha256 = "cb2e86056f8b891685c07035822f98d64b85c3475484e974507f3701d7efb88d", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/kernel-core-5.14.0-495.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/kernel-core-5.14.0-500.el9.x86_64.rpm", ], ) rpm( - name = "kernel-modules-core-0__5.14.0-495.el9.x86_64", - sha256 = "7af993d593f0eac0076dde38714f5a3f5c1b87c2c510c190216a62817695f1b8", + name = "kernel-modules-core-0__5.14.0-500.el9.x86_64", + sha256 = "423123b2ee77bab95ca82ce380a3f1badc23ee079e17011566cf39c5d28194c1", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/kernel-modules-core-5.14.0-495.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/kernel-modules-core-5.14.0-500.el9.x86_64.rpm", ], ) @@ -1011,10 +1011,10 @@ rpm( ) rpm( - name = "libblkid-0__2.37.4-18.el9.x86_64", - sha256 = "27567d3a7d0c7141a4899ea5fb75c12d4a2b4427ecd27b2a96992b08c50e5293", + name = "libblkid-0__2.37.4-20.el9.x86_64", + sha256 = "b980b5b7115f03d7fca51a87084911afba3af759e3caa77838a813ea4813ad35", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libblkid-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm", ], ) @@ -1083,10 +1083,10 @@ rpm( ) rpm( - name = "libcurl-minimal-0__7.76.1-30.el9.x86_64", - sha256 = "564e24c2875391a543536ca634e7c94a437e3153e8215f024a1cd4850f616a99", + name = "libcurl-minimal-0__7.76.1-31.el9.x86_64", + sha256 = "7982f00ee466fe18348d9d8c133dced4767a2ea1ecc8e609fda017feaebf57f3", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libcurl-minimal-7.76.1-30.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libcurl-minimal-7.76.1-31.el9.x86_64.rpm", ], ) @@ -1131,10 +1131,10 @@ rpm( ) rpm( - name = "libfdisk-0__2.37.4-18.el9.x86_64", - sha256 = "97f67568083e01671dc72ca059eed70c6dfcfea0777cd14e98582d7a2f839ac6", + name = "libfdisk-0__2.37.4-20.el9.x86_64", + sha256 = "9a7b7ae009118a7923503d58ed16eaaa3dac717cfd7cc709186c8572da1d668e", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libfdisk-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libfdisk-2.37.4-20.el9.x86_64.rpm", ], ) @@ -1275,10 +1275,10 @@ rpm( ) rpm( - name = "libmount-0__2.37.4-18.el9.x86_64", - sha256 = "7a1385515c096d8f1e0f785a5f6a85e70cac13f49314b89c0ea4b36fe6fba365", + name = "libmount-0__2.37.4-20.el9.x86_64", + sha256 = "562bb6596fc1558cc5d2a8143b9fca71728f0a728f402842981d6a6c4e19846b", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libmount-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libmount-2.37.4-20.el9.x86_64.rpm", ], ) @@ -1475,10 +1475,10 @@ rpm( ) rpm( - name = "libsmartcols-0__2.37.4-18.el9.x86_64", - sha256 = "05ff1d03f17b5c2ab3b5357634efd4973cc52113a696a6adc990b9ac0589e301", + name = "libsmartcols-0__2.37.4-20.el9.x86_64", + sha256 = "2b264e1753186b54043cbb29d3ae4c9c8b7d685a4090bd550cabae19c159a311", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libsmartcols-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libsmartcols-2.37.4-20.el9.x86_64.rpm", ], ) @@ -1571,10 +1571,10 @@ rpm( ) rpm( - name = "libuuid-0__2.37.4-18.el9.x86_64", - sha256 = "a6a3787505fe4526cd57a727e19cc23a2d654d77c0377be3efbeb38a76e34593", + name = "libuuid-0__2.37.4-20.el9.x86_64", + sha256 = "880975f7b3ab5244889357ee328e7befd0b9f8231c60f277039346ccc54c99ce", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libuuid-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/libuuid-2.37.4-20.el9.x86_64.rpm", ], ) @@ -1867,10 +1867,10 @@ rpm( ) rpm( - name = "ndctl-libs-0__71.1-8.el9.x86_64", - sha256 = "499e71703fb7d2f87c2d652a5c477c8b30849cca5ec3aa7335675ccb019b68e0", + name = "ndctl-libs-0__78-2.el9.x86_64", + sha256 = "9056eb17a2071dca7f4c777ad8d15461c0a349f2281973d17478e9045d4c438a", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/ndctl-libs-71.1-8.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/ndctl-libs-78-2.el9.x86_64.rpm", ], ) @@ -1955,18 +1955,18 @@ rpm( ) rpm( - name = "openssl-1__3.2.2-2.el9.x86_64", - sha256 = "b3ba7969b2fcbf197d8f4cb60cc76f71de4378f378ccf3c89242bbb3a32c801f", + name = "openssl-1__3.2.2-4.el9.x86_64", + sha256 = "13f2a83bcfc5a1d415a1e7ea4042cef20a0c0488f7e899f399d31f96c50d1505", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/openssl-3.2.2-2.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/openssl-3.2.2-4.el9.x86_64.rpm", ], ) rpm( - name = "openssl-libs-1__3.2.2-2.el9.x86_64", - sha256 = "5b91e322cbbf82f0907c7e515815eecf0612f2fe6f8ab5f1d427a2ae598f4275", + name = "openssl-libs-1__3.2.2-4.el9.x86_64", + sha256 = "f618b202712317772ee17dbd7fe7e20a31a7a3fc2a4a6838147a81d3daea197d", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/openssl-libs-3.2.2-2.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/openssl-libs-3.2.2-4.el9.x86_64.rpm", ], ) @@ -2803,50 +2803,50 @@ rpm( ) rpm( - name = "systemd-0__252-38.el9.x86_64", - sha256 = "022a0a054a1c07e900d6e8acbd1ed6cd0bbbd7dfb9d6a9d1cb3839d88906822f", + name = "systemd-0__252-45.el9.x86_64", + sha256 = "e74f313f5cad93fb30b47fd9a92a20cf1ef4b1ca772e7239a99d764064476fd3", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-252-38.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-252-45.el9.x86_64.rpm", ], ) rpm( - name = "systemd-container-0__252-38.el9.x86_64", - sha256 = "709457b0cde8314d010fd693c2c7d1b9031472ca0d88e670277a90b61b8f6af3", + name = "systemd-container-0__252-45.el9.x86_64", + sha256 = "524d1844cb358257586934bd19de266f30233772f6564a6ffd7b6eac0e89c04c", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-container-252-38.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-container-252-45.el9.x86_64.rpm", ], ) rpm( - name = "systemd-libs-0__252-38.el9.x86_64", - sha256 = "e312c7d3642f44d3f2e0aef827258470094dc2b7851dce196d6787fd0ed9b494", + name = "systemd-libs-0__252-45.el9.x86_64", + sha256 = "b7f5b55b09627f9c102c2d7cb479f2cc82ddca034c5b9ceefdb766dbe51a1889", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-libs-252-38.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-libs-252-45.el9.x86_64.rpm", ], ) rpm( - name = "systemd-pam-0__252-38.el9.x86_64", - sha256 = "007ec0922d0a7006fa499534fdcd34cfb9f57d99ba97182360389eb3ff30a68e", + name = "systemd-pam-0__252-45.el9.x86_64", + sha256 = "45ec3730c1631e133c32f34d88d62ef95ac75ec60d26518a0c3c74688ceab0a0", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-pam-252-38.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-pam-252-45.el9.x86_64.rpm", ], ) rpm( - name = "systemd-rpm-macros-0__252-38.el9.x86_64", - sha256 = "4c78d828c73d1ac825be99e984e3cad8ea0c294c6190fdfc42413b1d9b231bf1", + name = "systemd-rpm-macros-0__252-45.el9.x86_64", + sha256 = "e86a97fb185af1de6b58c44fa12264805e81fa6a160b20704fd5ffb38ac85b4f", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-rpm-macros-252-38.el9.noarch.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-rpm-macros-252-45.el9.noarch.rpm", ], ) rpm( - name = "systemd-udev-0__252-38.el9.x86_64", - sha256 = "3489757dc98d5e72f0f0d151b0f2eeaf04804cb00ef6c837889e5cbe5a636cf2", + name = "systemd-udev-0__252-45.el9.x86_64", + sha256 = "58f046ecc8b93fb2477911b9915a3a014149775486ffae8da5bc1e1a176166c2", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-udev-252-38.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/systemd-udev-252-45.el9.x86_64.rpm", ], ) @@ -2883,10 +2883,10 @@ rpm( ) rpm( - name = "unzip-0__6.0-56.el9.x86_64", - sha256 = "31ef52d376488fb3c278e849bfc784da980652b358fac977ebc3ac8e0513ebff", + name = "unzip-0__6.0-57.el9.x86_64", + sha256 = "160c17021a9838c6bdcb799afcb7909590ff1b4790a4404a6ef73d021222fbb4", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/unzip-6.0-56.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/unzip-6.0-57.el9.x86_64.rpm", ], ) @@ -2899,18 +2899,18 @@ rpm( ) rpm( - name = "util-linux-0__2.37.4-18.el9.x86_64", - sha256 = "3d586977ecbd42beb6d66a000abc71c9d22ae49ccbe1a126932a6d5fe7032747", + name = "util-linux-0__2.37.4-20.el9.x86_64", + sha256 = "ad9855647f3380b806ed9cc30a8e503357eb63c533a3a1e3f1bba9a8ab882d81", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/util-linux-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/util-linux-2.37.4-20.el9.x86_64.rpm", ], ) rpm( - name = "util-linux-core-0__2.37.4-18.el9.x86_64", - sha256 = "bfbf56a83fa513542d01c3d3d1224bff8d32d2cd1f3b6b3d23e6f6159e19ec3e", + name = "util-linux-core-0__2.37.4-20.el9.x86_64", + sha256 = "13c3cd8ebecb7ee2b7fe4f37c1bd371746064ab6fb53ed0d83e256257ce18fb6", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/util-linux-core-2.37.4-18.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/x86_64/os/Packages/util-linux-core-2.37.4-20.el9.x86_64.rpm", ], ) @@ -2923,10 +2923,10 @@ rpm( ) rpm( - name = "virt-v2v-1__2.5.6-3.el9.x86_64", - sha256 = "1f08fe066958e10ea81ab4d10d093a74af8343e3d7a79b16addff81f2cfba599", + name = "virt-v2v-1__2.5.6-4.el9.x86_64", + sha256 = "8e2a23b3f72fc9c6c2f6f2730855acccb63b6a50f1bb5872e406ffc602b48214", urls = [ - "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/x86_64/os/Packages/virt-v2v-2.5.6-3.el9.x86_64.rpm", + "https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/x86_64/os/Packages/virt-v2v-2.5.6-4.el9.x86_64.rpm", ], ) diff --git a/virt-v2v/cold/customize-image.go b/virt-v2v/cold/customize-image.go index 645cffb88..5efee90d3 100644 --- a/virt-v2v/cold/customize-image.go +++ b/virt-v2v/cold/customize-image.go @@ -26,14 +26,13 @@ const ( // // Returns: // - error: An error if something goes wrong during the process, or nil if successful. -func CustomizeWindows(disks []string) error { +func CustomizeWindows(disks []string, dir string, t FileSystemTool) error { fmt.Printf("Customizing disks '%s'", disks) - t := EmbedTool{filesystem: &scriptFS} - err := t.CreateFilesFromFS(DIR) + err := t.CreateFilesFromFS(dir) if err != nil { return err } - windowsScriptsPath := filepath.Join(DIR, "scripts", "windows") + windowsScriptsPath := filepath.Join(dir, "scripts", "windows") initPath := filepath.Join(windowsScriptsPath, "9999-restore_config_init.bat") restoreScriptPath := filepath.Join(windowsScriptsPath, "9999-restore_config.ps1") firstbootPath := filepath.Join(windowsScriptsPath, "firstboot.bat") @@ -82,6 +81,7 @@ func getScriptArgs(argName string, values ...string) []string { func CustomizeDomainExec(extraArgs ...string) error { args := []string{"--verbose"} args = append(args, extraArgs...) + customizeCmd := exec.Command("virt-customize", args...) customizeCmd.Stdout = os.Stdout customizeCmd.Stderr = os.Stderr diff --git a/virt-v2v/cold/customize-rhel.go b/virt-v2v/cold/customize-rhel.go new file mode 100644 index 000000000..0b859a9fc --- /dev/null +++ b/virt-v2v/cold/customize-rhel.go @@ -0,0 +1,140 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +type FileSystemTool interface { + CreateFilesFromFS(dstDir string) error +} + +type DomainExecFunc func(args ...string) error + +func CustomizeLinux(execFunc DomainExecFunc, disks []string, dir string, t FileSystemTool) error { + fmt.Printf("Customizing disks '%v'\n", disks) + + var extraArgs []string + + // Step 1: Create files from the filesystem + if err := t.CreateFilesFromFS(dir); err != nil { + return fmt.Errorf("failed to create files from filesystem: %w", err) + } + + // Step 2: Handle static IP configuration + if err := handleStaticIPConfiguration(&extraArgs, dir); err != nil { + return err + } + + // Step 3: Add scripts + if err := addRunScripts(&extraArgs, dir); err != nil { + return err + } + if err := addFirstbootScripts(&extraArgs, dir); err != nil { + return err + } + + // Step 4: Add the disks to customize + addDisksToCustomize(&extraArgs, disks) + + // Step 5: Adds LUKS keys, if they exist + if err := addLuksKeysToCustomize(&extraArgs); err != nil { + return err + } + + // Step 6: Execute the customization with the collected arguments + if err := execFunc(extraArgs...); err != nil { + return fmt.Errorf("failed to execute domain customization: %w", err) + } + + return nil +} + +// handleStaticIPConfiguration processes the static IP configuration and returns the initial extraArgs +func handleStaticIPConfiguration(extraArgs *[]string, dir string) error { + envStaticIPs := os.Getenv("V2V_staticIPs") + if envStaticIPs != "" { + macToIPFilePath := filepath.Join(dir, "macToIP") + macToIPFileContent := strings.ReplaceAll(envStaticIPs, "_", "\n") + "\n" + + if err := os.WriteFile(macToIPFilePath, []byte(macToIPFileContent), 0755); err != nil { + return fmt.Errorf("failed to write MAC to IP mapping file: %w", err) + } + + *extraArgs = append(*extraArgs, "--upload", macToIPFilePath+":/tmp/macToIP") + } + + return nil +} + +// addFirstbootScripts appends firstboot script arguments to extraArgs +func addFirstbootScripts(extraArgs *[]string, dir string) error { + firstbootScriptsPath := filepath.Join(dir, "scripts", "rhel", "firstboot") + + firstBootScripts, err := getScripts(firstbootScriptsPath) + if err != nil { + return err + } + + if len(firstBootScripts) == 0 { + fmt.Println("No run scripts found in directory:", firstbootScriptsPath) + return nil + } + + *extraArgs = append(*extraArgs, getScriptArgs("firstboot", firstBootScripts...)...) + return nil +} + +// addRunScripts appends run script arguments to extraArgs +func addRunScripts(extraArgs *[]string, dir string) error { + runScriptsPath := filepath.Join(dir, "scripts", "rhel", "run") + + runScripts, err := getScripts(runScriptsPath) + if err != nil { + return err + } + + if len(runScripts) == 0 { + fmt.Println("No run scripts found in directory:", runScriptsPath) + return nil + } + + *extraArgs = append(*extraArgs, getScriptArgs("run", runScripts...)...) + return nil +} + +// getScripts retrieves all .sh scripts from the specified directory +func getScripts(directory string) ([]string, error) { + files, err := os.ReadDir(directory) + if err != nil { + return nil, fmt.Errorf("failed to read firstboot scripts directory: %w", err) + } + + var scripts []string + for _, file := range files { + if !file.IsDir() && strings.HasSuffix(file.Name(), ".sh") { + scriptPath := filepath.Join(directory, file.Name()) + scripts = append(scripts, scriptPath) + } + } + + return scripts, nil +} + +// addDisksToCustomize appends disk arguments to extraArgs +func addDisksToCustomize(extraArgs *[]string, disks []string) { + *extraArgs = append(*extraArgs, getScriptArgs("add", disks...)...) +} + +// addLuksKeysToCustomize appends key arguments to extraArgs +func addLuksKeysToCustomize(extraArgs *[]string) error { + luksArgs, err := addLUKSKeys() + if err != nil { + return fmt.Errorf("error adding LUKS kyes: %w", err) + } + *extraArgs = append(*extraArgs, luksArgs...) + + return nil +} diff --git a/virt-v2v/cold/customize-rhel_test.go b/virt-v2v/cold/customize-rhel_test.go new file mode 100644 index 000000000..805969d6f --- /dev/null +++ b/virt-v2v/cold/customize-rhel_test.go @@ -0,0 +1,301 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "reflect" + "testing" +) + +type MockEmbedTool struct { + files map[string][]byte // A map of file paths to their content + shouldFailCreateFiles bool // Flag to simulate failure in CreateFilesFromFS + shouldFailWriteFile bool // Flag to simulate failure in writeFileFromFS +} + +// CreateFilesFromFS mocks the creation of files from the embedded filesystem +func (m *MockEmbedTool) CreateFilesFromFS(dstDir string) error { + if m.shouldFailCreateFiles { + return fmt.Errorf("mock error in CreateFilesFromFS") + } + for file, content := range m.files { + dstFilePath := filepath.Join(dstDir, file) + if err := m.writeFileFromFS(file, dstFilePath); err != nil { + return err + } + if err := os.WriteFile(dstFilePath, content, 0755); err != nil { + return err + } + } + return nil +} + +// writeFileFromFS mocks writing a file from the embedded filesystem to the disk +func (m *MockEmbedTool) writeFileFromFS(_, dst string) error { + if m.shouldFailWriteFile { + return fmt.Errorf("mock error in writeFileFromFS") + } + // Simulate directory creation + dstDir := filepath.Dir(dst) + if _, err := os.Stat(dstDir); os.IsNotExist(err) { + if err := os.MkdirAll(dstDir, 0755); err != nil { + return err + } + } + return nil +} + +func mockCustomizeDomainExec(args ...string) error { + // Simulate the behavior of CustomizeDomainExec for testing + fmt.Printf("Mock CustomizeDomainExec called with args: %v\n", args) + return nil +} + +// Test the CustomizeRHEL function using the mocked EmbedTool +func TestCustomizeRHELWithMock(t *testing.T) { + // Create a temporary directory and add dummy .sh files + tempDir := t.TempDir() + + mockFiles := map[string][]byte{ + "scripts/rhel/run/test1.sh": []byte("#!/bin/bash\necho 'Running test1'"), + "scripts/rhel/firstboot/test2.sh": []byte("#!/bin/bash\necho 'Running firstboot test2'"), + } + + mockTool := &MockEmbedTool{ + files: mockFiles, + } + + // Run the CustomizeRHEL function + disks := []string{"disk1", "disk2"} + err := CustomizeLinux(mockCustomizeDomainExec, disks, tempDir, mockTool) + if err != nil { + t.Fatalf("CustomizeRHEL returned an error: %v", err) + } + + // Check if the files have been created on the disk + for filePath := range mockFiles { + expectedPath := filepath.Join(tempDir, filePath) + if _, err := os.Stat(expectedPath); os.IsNotExist(err) { + t.Fatalf("Expected file %s does not exist", expectedPath) + } + } +} + +func TestHandleStaticIPConfiguration(t *testing.T) { + // Mock the environment variable for static IPs + os.Setenv("V2V_staticIPs", "00:11:22:33:44:55:ip:192.168.1.100") + defer os.Unsetenv("V2V_staticIPs") + + // Create a temporary directory and add dummy .sh files + tempDir := t.TempDir() + + extraArgs := []string{} + err := handleStaticIPConfiguration(&extraArgs, tempDir) + if err != nil { + t.Fatalf("handleStaticIPConfiguration returned an error: %v", err) + } + + expectedFilePath := filepath.Join(tempDir, "macToIP") + if _, err := os.Stat(expectedFilePath); os.IsNotExist(err) { + t.Fatalf("Expected file %s does not exist", expectedFilePath) + } + + content, _ := os.ReadFile(expectedFilePath) + expectedContent := "00:11:22:33:44:55:ip:192.168.1.100\n" + if string(content) != expectedContent { + t.Fatalf("Content of %s is incorrect: got %s, want %s", expectedFilePath, string(content), expectedContent) + } + + if len(extraArgs) == 0 || !contains(extraArgs, "--upload") { + t.Fatalf("extraArgs does not contain expected '--upload' argument") + } +} + +func TestAddFirstbootScripts(t *testing.T) { + // Create a temporary directory and add dummy .sh files + tempDir := t.TempDir() + err := os.MkdirAll(filepath.Join(tempDir, "scripts", "rhel", "firstboot"), 0755) + if err != nil { + t.Fatalf("Error MkdirAll: %v", err) + } + err = os.WriteFile(filepath.Join(tempDir, "scripts", "rhel", "firstboot", "test.sh"), []byte{}, 0755) + if err != nil { + t.Fatalf("Error WriteFile: %v", err) + } + + extraArgs := []string{} + err = addFirstbootScripts(&extraArgs, tempDir) + if err != nil { + t.Fatalf("addFirstbootScripts returned an error: %v", err) + } + + if len(extraArgs) == 0 || !contains(extraArgs, "--firstboot") { + t.Fatalf("extraArgs does not contain expected '--firstboot' argument") + } +} + +func TestAddRunScripts(t *testing.T) { + // Create a temporary directory and add dummy .sh files + tempDir := t.TempDir() + err := os.MkdirAll(filepath.Join(tempDir, "scripts", "rhel", "run"), 0755) + if err != nil { + t.Fatalf("Error MkdirAll: %v", err) + } + err = os.WriteFile(filepath.Join(tempDir, "scripts", "rhel", "run", "test.sh"), []byte{}, 0755) + if err != nil { + t.Fatalf("Error WriteFile: %v", err) + } + + extraArgs := []string{} + err = addRunScripts(&extraArgs, tempDir) + if err != nil { + t.Fatalf("addRunScripts returned an error: %v", err) + } + + if len(extraArgs) == 0 || !contains(extraArgs, "--run") { + t.Fatalf("extraArgs does not contain expected '--run' argument") + } +} + +func TestGetScripts(t *testing.T) { + // Create a temporary directory and add dummy .sh files + tempDir := t.TempDir() + err := os.WriteFile(filepath.Join(tempDir, "test1.sh"), []byte{}, 0755) + if err != nil { + t.Fatalf("Error WriteFile: %v", err) + } + err = os.WriteFile(filepath.Join(tempDir, "test2.sh"), []byte{}, 0755) + if err != nil { + t.Fatalf("Error WriteFile: %v", err) + } + + scripts, err := getScripts(tempDir) + if err != nil { + t.Fatalf("getScripts returned an error: %v", err) + } + + expectedScripts := []string{ + filepath.Join(tempDir, "test1.sh"), + filepath.Join(tempDir, "test2.sh"), + } + if !reflect.DeepEqual(scripts, expectedScripts) { + t.Fatalf("getScripts returned incorrect scripts: got %v, want %v", scripts, expectedScripts) + } +} + +func TestAddDisksToCustomize(t *testing.T) { + disks := []string{"disk1", "disk2"} + extraArgs := []string{} + + addDisksToCustomize(&extraArgs, disks) + if !contains(extraArgs, "disk1") || !contains(extraArgs, "disk2") { + t.Fatalf("extraArgs does not contain expected disk arguments") + } +} + +// Helper function to check if a slice contains a string +func contains(slice []string, item string) bool { + for _, s := range slice { + if s == item { + return true + } + } + return false +} + +func TestAddFirstbootScripts_NoScripts(t *testing.T) { + // Create a temporary directory with no scripts + tempDir := t.TempDir() + err := os.MkdirAll(filepath.Join(tempDir, "scripts", "rhel", "firstboot"), 0755) + if err != nil { + t.Fatalf("Error MkdirAll: %v", err) + } + + extraArgs := []string{} + err = addFirstbootScripts(&extraArgs, tempDir) + if err != nil { + t.Fatalf("addFirstbootScripts returned an error: %v", err) + } + + // Ensure no "--firstboot" argument is added when no scripts are found + if contains(extraArgs, "--firstboot") { + t.Fatalf("extraArgs contains '--firstboot' argument when no scripts should have been found") + } +} + +func TestAddRunScripts_NoScripts(t *testing.T) { + // Create a temporary directory with no scripts + tempDir := t.TempDir() + err := os.MkdirAll(filepath.Join(tempDir, "scripts", "rhel", "run"), 0755) + if err != nil { + t.Fatalf("Error MkdirAll: %v", err) + } + + extraArgs := []string{} + err = addRunScripts(&extraArgs, tempDir) + if err != nil { + t.Fatalf("addRunScripts returned an error: %v", err) + } + + // Ensure no "--run" argument is added when no scripts are found + if contains(extraArgs, "--run") { + t.Fatalf("extraArgs contains '--run' argument when no scripts should have been found") + } +} + +func TestCustomizeRHEL_CreateFilesFromFSFails(t *testing.T) { + mockTool := &MockEmbedTool{ + files: map[string][]byte{}, + shouldFailCreateFiles: true, // Simulate failure in CreateFilesFromFS + } + + // Run the CustomizeRHEL function + disks := []string{"disk1", "disk2"} + err := CustomizeLinux(mockCustomizeDomainExec, disks, t.TempDir(), mockTool) + if err == nil { + t.Fatalf("Expected error in CustomizeRHEL due to CreateFilesFromFS failure, got nil") + } + + expectedError := "failed to create files from filesystem: mock error in CreateFilesFromFS" + if err.Error() != expectedError { + t.Fatalf("Expected error message '%s', got '%s'", expectedError, err.Error()) + } +} + +func TestHandleStaticIPConfiguration_WriteFileFails(t *testing.T) { + // Mock the environment variable for static IPs + os.Setenv("V2V_staticIPs", "00:11:22:33:44:55:ip:192.168.1.100") + defer os.Unsetenv("V2V_staticIPs") + + // Use an invalid directory to force a write failure + tempDir := "/invalid-dir" + + extraArgs := []string{} + err := handleStaticIPConfiguration(&extraArgs, tempDir) + if err == nil { + t.Fatalf("Expected error in handleStaticIPConfiguration due to write failure, got nil") + } +} + +func TestAddFirstbootScripts_ReadDirFails(t *testing.T) { + // Use an invalid directory to force a read failure + tempDir := "/invalid-dir" + + extraArgs := []string{} + err := addFirstbootScripts(&extraArgs, tempDir) + if err == nil { + t.Fatalf("Expected error in addFirstbootScripts due to read failure, got nil") + } +} + +func TestAddRunScripts_ReadDirFails(t *testing.T) { + // Use an invalid directory to force a read failure + tempDir := "/invalid-dir" + + extraArgs := []string{} + err := addRunScripts(&extraArgs, tempDir) + if err == nil { + t.Fatalf("Expected error in addRunScripts due to read failure, got nil") + } +} diff --git a/virt-v2v/cold/entrypoint.go b/virt-v2v/cold/entrypoint.go index b70f1f844..b03af16b6 100644 --- a/virt-v2v/cold/entrypoint.go +++ b/virt-v2v/cold/entrypoint.go @@ -108,7 +108,20 @@ func customizeVM(source string, xmlFilePath string) error { } if source == vSphere { if strings.Contains(operatingSystem, "win") { - err = CustomizeWindows(disks) + t := EmbedTool{filesystem: &scriptFS} + + err = CustomizeWindows(disks, DIR, &t) + if err != nil { + fmt.Println("Error customizing disk image:", err) + return err + } + } + + // Linux + if !strings.Contains(operatingSystem, "win") { + t := EmbedTool{filesystem: &scriptFS} + + err = CustomizeLinux(CustomizeDomainExec, disks, DIR, &t) if err != nil { fmt.Println("Error customizing disk image:", err) return err @@ -177,20 +190,14 @@ func buildCommand() []string { virtV2vArgs = append(virtV2vArgs, "--mac", macToIp) } } - // Adds LUKS keys, if exist. - if _, err := os.Stat(LUKSDIR); err == nil { - files, err := getFilesInPath(LUKSDIR) - if err != nil { - fmt.Println("Error reading files in LUKS directory ", err) - os.Exit(1) - } - for _, file := range files { - virtV2vArgs = append(virtV2vArgs, "--key", fmt.Sprintf("all:file:%s", file)) - } - } else if !os.IsNotExist(err) { - fmt.Println("Error accessing the LUKS directory ", err) + + // Adds LUKS keys, if they exist + luksArgs, err := addLUKSKeys() + if err != nil { + fmt.Println("Error adding LUKS kyes ", err) os.Exit(1) } + virtV2vArgs = append(virtV2vArgs, luksArgs...) if info, err := os.Stat(VDDK); err == nil && info.IsDir() { virtV2vArgs = append(virtV2vArgs, @@ -204,6 +211,35 @@ func buildCommand() []string { return virtV2vArgs } +// addLUKSKeys checks the LUKS directory for key files and returns the appropriate +// arguments for a 'virt-' command to add these keys. +// +// Returns a slice of strings representing the LUKS key arguments, or an error if +// there's an issue accessing the directory or reading the files. +func addLUKSKeys() ([]string, error) { + var luksArgs []string + + if _, err := os.Stat(LUKSDIR); err == nil { + files, err := getFilesInPath(LUKSDIR) + if err != nil { + fmt.Println("Error reading files in LUKS directory", err) + os.Exit(1) + } + + var luksFiles []string + for _, file := range files { + luksFiles = append(luksFiles, fmt.Sprintf("all:file:%s", file)) + } + + luksArgs = append(luksArgs, getScriptArgs("key", luksFiles...)...) + } else if !os.IsNotExist(err) { + fmt.Println("Error accessing the LUKS directory", err) + os.Exit(1) + } + + return luksArgs, nil +} + func getFilesInPath(rootPath string) (paths []string, err error) { files, err := os.ReadDir(rootPath) if err != nil { diff --git a/virt-v2v/cold/scripts/rhel/firstboot/README.md b/virt-v2v/cold/scripts/rhel/firstboot/README.md new file mode 100644 index 000000000..65b23d18c --- /dev/null +++ b/virt-v2v/cold/scripts/rhel/firstboot/README.md @@ -0,0 +1,3 @@ +# First boot files + +An embedded filesystem for files that will be added for the first boot on the migrated virtual machine filesystem using virt-customize --firstboot argument. \ No newline at end of file diff --git a/virt-v2v/cold/scripts/rhel/run/README.md b/virt-v2v/cold/scripts/rhel/run/README.md new file mode 100644 index 000000000..d86252482 --- /dev/null +++ b/virt-v2v/cold/scripts/rhel/run/README.md @@ -0,0 +1,3 @@ +# Run files + +An embedded filesystem for files that will be run on the migrated virtual machine filesystem using virt-customize --run argument. \ No newline at end of file diff --git a/virt-v2v/cold/scripts/rhel/run/network_config_util.sh b/virt-v2v/cold/scripts/rhel/run/network_config_util.sh new file mode 100644 index 000000000..f6fe05fb1 --- /dev/null +++ b/virt-v2v/cold/scripts/rhel/run/network_config_util.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# Global variables with default values +V2V_MAP_FILE="${V2V_MAP_FILE:-/tmp/macToIP}" +NETWORK_SCRIPTS_DIR="${NETWORK_SCRIPTS_DIR:-/etc/sysconfig/network-scripts}" +NETWORK_CONNECTIONS_DIR="${NETWORK_CONNECTIONS_DIR:-/etc/NetworkManager/system-connections}" +UDEV_RULES_FILE="${UDEV_RULES_FILE:-/etc/udev/rules.d/70-persistent-net.rules}" + +# Check if udev rules file exists +if [ -f "$UDEV_RULES_FILE" ]; then + echo "File $UDEV_RULES_FILE already exists. Exiting." + exit 0 +fi + +# Add log file descriptot and dump it to stdout +exec 3>&1 +log() { + echo $@ >&3 +} + +# Validate MAC address and IPv4 address and extract them +extract_mac_ip() { + S_HW="" + S_IP="" + if [[ "$1" =~ ^([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}):ip:([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) ]]; then + S_HW="${BASH_REMATCH[1]}" + S_IP="${BASH_REMATCH[2]}" + fi +} + +# Create udev rules based on the macToip mapping + ifcfg network scripts +udev_from_ifcfg() { + # Read the mapping file line by line + while IFS= read -r line; do + # Extract S_HW and S_IP + extract_mac_ip "$line" + + # If S_HW and S_IP were extracted, proceed + [[ -z "$S_HW" || -z "$S_IP" ]] && continue + + # Source the matching file, if found + IFCFG=$(grep -l "IPADDR=$S_IP" "$NETWORK_SCRIPTS_DIR"/*) + [[ -z "$IFCFG" ]] && continue + source "$IFCFG" + + echo "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"$S_HW\",NAME=\"$DEVICE\"" + + done < "$V2V_MAP_FILE" +} + +# Create udev rules based on the macToip mapping + network manager connections +udev_from_nm() { + # Read the mapping file line by line + while IFS= read -r line; do + # Extract S_HW and S_IP + extract_mac_ip "$line" + + # If S_HW and S_IP were extracted, proceed + [[ -z "$S_HW" || -z "$S_IP" ]] && continue + + # Find the matching NetworkManager connection file + NM_FILE=$(grep -El "address[0-9]*=$S_IP" "$NETWORK_CONNECTIONS_DIR"/*) + [[ -z "$NM_FILE" ]] && continue + + # Extract the DEVICE (interface name) from the matching file + DEVICE=$(grep -oP '^interface-name=\K.*' "$NM_FILE") + [[ -z "$DEVICE" ]] && continue + + echo "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"$S_HW\",NAME=\"$DEVICE\"" + done < "$V2V_MAP_FILE" +} + +# Checks for duplicate hardware addresses +check_dupe_hws() { + input=$(cat) + + # Extract MAC addresses, convert to uppercase, sort them, and find duplicates + dupes=$(grep -io -E "[0-9A-F:]{17}" <<< "$input" | tr 'a-f' 'A-F' | sort | uniq -d) + + # If duplicates are found, print an error and exit + if [ -n "$dupes" ]; then + echo "ERR: Duplicate hw: $dupes" + exit 2 + fi + + echo "$input" +} + +# Create udev rules check for duplicates and write them to udev file +main() { + { + udev_from_ifcfg + udev_from_nm + } | check_dupe_hws > "$UDEV_RULES_FILE" +} + +main diff --git a/virt-v2v/cold/scripts/rhel/run/network_config_util_test b/virt-v2v/cold/scripts/rhel/run/network_config_util_test new file mode 100644 index 000000000..1ff41c2e2 --- /dev/null +++ b/virt-v2v/cold/scripts/rhel/run/network_config_util_test @@ -0,0 +1,56 @@ +#!/bin/bash + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" + +# Temporary directory for testing +TEST_DIR=$(mktemp -d) + +# Paths for the test +export V2V_MAP_FILE="$TEST_DIR/macToIP" +export NETWORK_SCRIPTS_DIR="$TEST_DIR/network-scripts" +export NETWORK_CONNECTIONS_DIR="$TEST_DIR/system-connections" +export UDEV_RULES_FILE="$TEST_DIR/70-persistent-net.rules" + +# Clean up from previous runs +rm -f "$UDEV_RULES_FILE" +rm -rf "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR" +mkdir -p "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR" + +# Create mock data +echo -e "aa:bb:cc:dd:ee:ff:ip:192.168.1.10\naa:bb:cc:dd:ee:fe:ip:192.168.1.11\naa:bb:cc:dd:ee:fd:ip:2001:0db8:85a3:0000:0000:8a2e:0370:7334\n" > "$V2V_MAP_FILE" +echo -e "DEVICE=eth0\nIPADDR=192.168.1.10" > "$NETWORK_SCRIPTS_DIR/ifcfg-eth0" +echo -e "[connection]\ninterface-name=eth3\naddress1=192.168.1.11/24" > "$NETWORK_CONNECTIONS_DIR/eth1 but with spaces.nmconnection" + +# Source the script under test +source ${SCRIPT_DIR}/network_config_util.sh + +# Run the script +main + +echo -e "\nTest output:" +cat $UDEV_RULES_FILE + +# Test 1: Verify the udev rules file was created +if [ ! -f "$UDEV_RULES_FILE" ]; then + echo "Test 1 Failed: UDEV_RULES_FILE not created." + exit 1 +fi + +# Test 2: Verify the content of the udev rules file +EXPECTED_RULE="SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"aa:bb:cc:dd:ee:ff\",NAME=\"eth0\"" +if ! grep -q "$EXPECTED_RULE" "$UDEV_RULES_FILE"; then + echo "Test 2 Failed: (ifcfg) Expected udev rule not found in $UDEV_RULES_FILE." + exit 1 +fi + +# Test 3: Verify the content of the udev rules file +EXPECTED_RULE="SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"aa:bb:cc:dd:ee:fe\",NAME=\"eth3\"" +if ! grep -q "$EXPECTED_RULE" "$UDEV_RULES_FILE"; then + echo "Test 3 Failed: (nm) Expected udev rule not found in $UDEV_RULES_FILE." + exit 1 +fi + +echo "All tests passed successfully." + +# Clean up test environment +rm -rf "$TEST_DIR"