From a6944050cc3175f49f2945eae9b4215585118196 Mon Sep 17 00:00:00 2001 From: Mikhail Klementev Date: Thu, 15 Jun 2023 15:24:29 +0000 Subject: [PATCH] feat: implement openSUSE 42+ support --- .github/workflows/e2e.yml | 13 ++- .github/workflows/ubuntu.yml | 11 +- cache/cache.go | 2 +- cache/cache_test.go | 4 +- container/container.go | 2 +- distro/centos/centos.go | 4 + distro/debian/debian.go | 4 + distro/distro.go | 11 ++ distro/id.go | 7 +- distro/opensuse/opensuse.go | 185 ++++++++++++++++++++++++++++++ distro/oraclelinux/oraclelinux.go | 4 + distro/ubuntu/ubuntu.go | 5 + kernel.go | 5 +- kernel/kernel.go | 6 +- kernel/kernel_linux.go | 14 +-- main.go | 1 + 16 files changed, 253 insertions(+), 25 deletions(-) create mode 100644 distro/opensuse/opensuse.go diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 21eeac5..2253ffb 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -40,7 +40,16 @@ jobs: { distro: Debian, release: 9 }, { distro: Debian, release: 10 }, { distro: Debian, release: 11 }, - { distro: Debian, release: 12 } + { distro: Debian, release: 12 }, + { distro: OpenSUSE, release: "42.1" }, + { distro: OpenSUSE, release: "42.2" }, + { distro: OpenSUSE, release: "42.3" }, + { distro: OpenSUSE, release: "15.0" }, + { distro: OpenSUSE, release: "15.1" }, + { distro: OpenSUSE, release: "15.2" }, + { distro: OpenSUSE, release: "15.3" }, + { distro: OpenSUSE, release: "15.4" }, + { distro: OpenSUSE, release: "15.5" } ] steps: @@ -115,7 +124,7 @@ jobs: echo 'WorkingDirectory=/root/test' >> test.service echo 'TimeoutStopSec=1' >> test.service echo 'ExecStart=/usr/local/bin/out-of-tree kernel autogen --threads=4 --max=256 --shuffle' >> test.service - echo 'ExecStart=/usr/local/bin/out-of-tree pew --qemu-timeout=4m --threads=4 --include-internal-errors' >> test.service + echo 'ExecStart=/usr/local/bin/out-of-tree pew --qemu-timeout=10m --threads=4 --include-internal-errors' >> test.service scp test.service root@$IP:/etc/systemd/system/test.service diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index a986161..30dafb1 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -114,7 +114,16 @@ jobs: { distro: Debian, release: 9 }, { distro: Debian, release: 10 }, { distro: Debian, release: 11 }, - { distro: Debian, release: 12 } + { distro: Debian, release: 12 }, + { distro: OpenSUSE, release: "42.1" }, + { distro: OpenSUSE, release: "42.2" }, + { distro: OpenSUSE, release: "42.3" }, + # { distro: OpenSUSE, release: "15.0" }, + { distro: OpenSUSE, release: "15.1" }, + { distro: OpenSUSE, release: "15.2" }, + { distro: OpenSUSE, release: "15.3" }, + { distro: OpenSUSE, release: "15.4" }, + { distro: OpenSUSE, release: "15.5" } ] steps: diff --git a/cache/cache.go b/cache/cache.go index 2f384e5..ca95e93 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -39,7 +39,7 @@ func unpackTar(archive, destination string) (err error) { return } -func DownloadQemuImage(path, file string) (err error) { +func DownloadRootFS(path, file string) (err error) { tmp, err := fs.TempDir() if err != nil { return diff --git a/cache/cache_test.go b/cache/cache_test.go index e834ebd..9f541e5 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -9,7 +9,7 @@ import ( "code.dumpstack.io/tools/out-of-tree/fs" ) -func TestDownloadQemuImage(t *testing.T) { +func TestDownloadRootFS(t *testing.T) { tmp, err := ioutil.TempDir("", "out-of-tree_") if err != nil { return @@ -18,7 +18,7 @@ func TestDownloadQemuImage(t *testing.T) { file := "out_of_tree_ubuntu_12__04.img" - err = DownloadQemuImage(tmp, file) + err = DownloadRootFS(tmp, file) if err != nil { t.Fatal(err) } diff --git a/container/container.go b/container/container.go index 07eee6b..6758cf6 100644 --- a/container/container.go +++ b/container/container.go @@ -410,7 +410,7 @@ func (c Container) Kernels() (kernels []distro.KernelInfo, err error) { InitrdPath: filepath.Join(boot, initrdFile), ModulesPath: filepath.Join(libmodules, krel.Name()), - RootFS: config.File("images", c.name+".img"), + RootFS: config.File("images", c.dist.RootFS()), } kernels = append(kernels, ki) diff --git a/distro/centos/centos.go b/distro/centos/centos.go index 9a04979..0cb7776 100644 --- a/distro/centos/centos.go +++ b/distro/centos/centos.go @@ -210,3 +210,7 @@ func (centos CentOS) Install(pkgname string, headers bool) (err error) { return } + +func (centos CentOS) RootFS() string { + return fmt.Sprintf("out_of_tree_centos_%s.img", centos.release) +} diff --git a/distro/debian/debian.go b/distro/debian/debian.go index 929004c..78c636e 100644 --- a/distro/debian/debian.go +++ b/distro/debian/debian.go @@ -527,3 +527,7 @@ func (d Debian) cleanup(pkgname string) { log.Warn().Err(err).Msg("cleanup") } } + +func (d Debian) RootFS() string { + return fmt.Sprintf("out_of_tree_debian_%s.img", d.release.String()) +} diff --git a/distro/distro.go b/distro/distro.go index 0463f37..6b459e2 100644 --- a/distro/distro.go +++ b/distro/distro.go @@ -14,6 +14,7 @@ type distribution interface { Packages() (packages []string, err error) Install(pkg string, headers bool) (err error) Kernels() (kernels []KernelInfo, err error) + RootFS() string } func Register(d distribution) { @@ -88,3 +89,13 @@ func (d Distro) Equal(to Distro) bool { } return false } + +func (d Distro) RootFS() string { + for _, dd := range distros { + if dd.Equal(d) { + return dd.RootFS() + } + } + + return "" +} diff --git a/distro/id.go b/distro/id.go index 93cf84d..3cb8f8a 100644 --- a/distro/id.go +++ b/distro/id.go @@ -18,10 +18,12 @@ const ( Debian // OracleLinux https://www.oracle.com/linux/ OracleLinux + // OpenSUSE https://opensuse.org/ + OpenSUSE ) var IDs = []ID{ - None, Ubuntu, CentOS, Debian, OracleLinux, + None, Ubuntu, CentOS, Debian, OracleLinux, OpenSUSE, } var nameStrings = [...]string{ @@ -30,6 +32,7 @@ var nameStrings = [...]string{ "CentOS", "Debian", "OracleLinux", + "openSUSE", } func NewID(name string) (id ID, err error) { @@ -52,6 +55,8 @@ func (id *ID) UnmarshalTOML(data []byte) (err error) { *id = Debian } else if strings.EqualFold(name, "OracleLinux") { *id = OracleLinux + } else if strings.EqualFold(name, "openSUSE") { + *id = OpenSUSE } else if name != "" { err = fmt.Errorf("distro %s is not supported", name) } else { diff --git a/distro/opensuse/opensuse.go b/distro/opensuse/opensuse.go new file mode 100644 index 0000000..0f514b5 --- /dev/null +++ b/distro/opensuse/opensuse.go @@ -0,0 +1,185 @@ +package opensuse + +import ( + "fmt" + "strings" + + "code.dumpstack.io/tools/out-of-tree/container" + "code.dumpstack.io/tools/out-of-tree/distro" +) + +func init() { + releases := []string{ + "42.1", "42.2", "42.3", + "15.0", "15.1", "15.2", "15.3", "15.4", "15.5", + } + + for _, release := range releases { + distro.Register(OpenSUSE{release: release}) + } +} + +type OpenSUSE struct { + release string +} + +func (suse OpenSUSE) Equal(d distro.Distro) bool { + return suse.release == d.Release && distro.OpenSUSE == d.ID +} + +func (suse OpenSUSE) Distro() distro.Distro { + return distro.Distro{ID: distro.OpenSUSE, Release: suse.release} +} + +func (suse OpenSUSE) Packages() (pkgs []string, err error) { + c, err := container.New(suse.Distro()) + if err != nil { + return + } + + var name string + if strings.HasPrefix(suse.release, "42") { + name = "opensuse/leap:42" + } else if strings.HasPrefix(suse.release, "15") { + name = "opensuse/leap:" + suse.release + } + + err = c.Build(name, suse.envs(), suse.runs()) + if err != nil { + return + } + + cmd := "zypper search -s --match-exact kernel-default | grep x86_64 " + + "| cut -d '|' -f 4 | sed 's/ //g'" + + output, err := c.Run("", []string{cmd}) + if err != nil { + return + } + + for _, pkg := range strings.Fields(output) { + pkgs = append(pkgs, pkg) + } + + return +} + +func (suse OpenSUSE) Kernels() (kernels []distro.KernelInfo, err error) { + c, err := container.New(suse.Distro()) + if err != nil { + return + } + + return c.Kernels() +} + +func (suse OpenSUSE) envs() (envs []string) { + return +} + +func (suse OpenSUSE) runs() (commands []string) { + cmdf := func(f string, s ...interface{}) { + commands = append(commands, fmt.Sprintf(f, s...)) + } + + main := "http://download.opensuse.org/" + discontinued := "http://ftp.gwdg.de/pub/opensuse/discontinued/" + + var repourls []string + + if strings.HasPrefix(suse.release, "42") { + dist := discontinued + "distribution/leap/%s/repo/oss/suse/" + update := discontinued + "update/leap/%s/oss/" + repourls = append(repourls, + fmt.Sprintf(dist, suse.release), + fmt.Sprintf(update, suse.release), + ) + } else if strings.HasPrefix(suse.release, "15") { + dist := main + "distribution/leap/%s/repo/oss/" + update := main + "update/leap/%s/oss/" + repourls = append(repourls, + fmt.Sprintf(dist, suse.release), + fmt.Sprintf(update, suse.release), + ) + + switch suse.release { + case "15.3", "15.4", "15.5": + sle := main + "update/leap/%s/sle/" + repourls = append(repourls, + fmt.Sprintf(sle, suse.release), + ) + } + } + + cmdf("rm /etc/zypp/repos.d/*") + + for i, repourl := range repourls { + cmdf(`echo -e `+ + `"[%d]\n`+ + `name=%d\n`+ + `enabled=1\n`+ + `autorefresh=0\n`+ + `gpgcheck=0\n`+ + `baseurl=%s" > /etc/zypp/repos.d/%d.repo`, + i, i, repourl, i, + ) + } + + cmdf("zypper -n refresh") + cmdf("zypper -n update") + + params := "--no-recommends --force-resolution --replacefiles" + cmdf("zypper --no-refresh -n install %s -t pattern devel_kernel", params) + + // Cache dependencies + cmdf("zypper -n install %s kernel-default kernel-default-devel "+ + "&& zypper -n remove -U kernel-default kernel-default-devel", + params) + + cmdf("zypper --no-refresh -n install %s kmod which", params) + return +} + +func (suse OpenSUSE) Install(version string, headers bool) (err error) { + var commands []string + cmdf := func(f string, s ...interface{}) { + commands = append(commands, fmt.Sprintf(f, s...)) + } + + installcmd := "zypper --no-refresh -n " + + "install --force-resolution --capability" + cmdf("%s kernel-default=%s", installcmd, version) + if headers { + cmdf("%s kernel-default-devel=%s", installcmd, version) + } + + cmdf("dracut " + + "--add-drivers 'ata_piix libata' " + + "--force-drivers 'e1000 ext4 sd_mod rfkill af_packet' " + + "-f /boot/initrd-$(ls /lib/modules) $(ls /lib/modules)") + + cmdf("cp -r /boot /target/") + cmdf("cp -r /lib/modules /target/lib/") + cmdf("cp -r /usr/src /target/usr/") + + c, err := container.New(suse.Distro()) + if err != nil { + return + } + + for i := range c.Volumes { + c.Volumes[i].Dest = "/target" + c.Volumes[i].Dest + } + + _, err = c.Run("", commands) + if err != nil { + return + } + + return +} + +func (suse OpenSUSE) RootFS() string { + return fmt.Sprintf("out_of_tree_opensuse_%s.img", + strings.Split(suse.release, ".")[0]) +} diff --git a/distro/oraclelinux/oraclelinux.go b/distro/oraclelinux/oraclelinux.go index 71d548c..a794f84 100644 --- a/distro/oraclelinux/oraclelinux.go +++ b/distro/oraclelinux/oraclelinux.go @@ -216,3 +216,7 @@ func (ol OracleLinux) Install(pkgname string, headers bool) (err error) { return } + +func (ol OracleLinux) RootFS() string { + return fmt.Sprintf("out_of_tree_oraclelinux_%s.img", ol.release) +} diff --git a/distro/ubuntu/ubuntu.go b/distro/ubuntu/ubuntu.go index 210afc1..f5dbe28 100644 --- a/distro/ubuntu/ubuntu.go +++ b/distro/ubuntu/ubuntu.go @@ -154,3 +154,8 @@ func (u Ubuntu) Install(pkgname string, headers bool) (err error) { return } + +func (u Ubuntu) RootFS() string { + return fmt.Sprintf("out_of_tree_ubuntu_%s.img", + strings.Replace(u.release, ".", "__", -1)) +} diff --git a/kernel.go b/kernel.go index ce0fc9c..13a14d7 100644 --- a/kernel.go +++ b/kernel.go @@ -176,8 +176,7 @@ func (cmd *KernelCmd) Generate(g *Globals, km config.Target) (err error) { log.Info().Msgf("Generating for target %v", km) - _, err = kernel.GenRootfsImage(container.Image{Name: km.DockerName()}, - !cmd.NoDownload) + _, err = kernel.GenRootfsImage(km.Distro.RootFS(), !cmd.NoDownload) if err != nil || cmd.shutdown { return } @@ -267,7 +266,7 @@ func (cmd *KernelListRemoteCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error Kernel: config.Kernel{Regex: ".*"}, } - _, err = kernel.GenRootfsImage(container.Image{Name: km.DockerName()}, false) + _, err = kernel.GenRootfsImage(km.Distro.RootFS(), false) if err != nil { return } diff --git a/kernel/kernel.go b/kernel/kernel.go index 268803e..d25ee07 100644 --- a/kernel/kernel.go +++ b/kernel/kernel.go @@ -18,7 +18,6 @@ import ( "code.dumpstack.io/tools/out-of-tree/cache" "code.dumpstack.io/tools/out-of-tree/config" - "code.dumpstack.io/tools/out-of-tree/container" "code.dumpstack.io/tools/out-of-tree/fs" ) @@ -71,15 +70,14 @@ func vsyscallAvailable() (available bool, err error) { return } -func GenRootfsImage(d container.Image, download bool) (rootfs string, err error) { +func GenRootfsImage(imageFile string, download bool) (rootfs string, err error) { imagesPath := config.Dir("images") - imageFile := d.Name + ".img" rootfs = filepath.Join(imagesPath, imageFile) if !fs.PathExists(rootfs) { if download { log.Info().Msgf("%v not available, start download", imageFile) - err = cache.DownloadQemuImage(imagesPath, imageFile) + err = cache.DownloadRootFS(imagesPath, imageFile) } } return diff --git a/kernel/kernel_linux.go b/kernel/kernel_linux.go index 5a31d9c..063dc4a 100644 --- a/kernel/kernel_linux.go +++ b/kernel/kernel_linux.go @@ -15,8 +15,6 @@ import ( "github.com/rs/zerolog/log" "github.com/zcalusic/sysinfo" - "code.dumpstack.io/tools/out-of-tree/config" - "code.dumpstack.io/tools/out-of-tree/container" "code.dumpstack.io/tools/out-of-tree/distro" "code.dumpstack.io/tools/out-of-tree/fs" ) @@ -46,16 +44,12 @@ func GenHostKernels(download bool) (kernels []distro.KernelInfo, err error) { } // only for compatibility, docker is not really used - dii := container.Image{ - Name: config.Target{ - Distro: distro.Distro{ - ID: distroType, - Release: si.OS.Version, - }, - }.DockerName(), + dist := distro.Distro{ + ID: distroType, + Release: si.OS.Version, } - rootfs, err := GenRootfsImage(dii, download) + rootfs, err := GenRootfsImage(dist.RootFS(), download) if err != nil { return } diff --git a/main.go b/main.go index 24a6f79..4009a24 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ import ( _ "code.dumpstack.io/tools/out-of-tree/distro/centos" _ "code.dumpstack.io/tools/out-of-tree/distro/debian" + _ "code.dumpstack.io/tools/out-of-tree/distro/opensuse" _ "code.dumpstack.io/tools/out-of-tree/distro/oraclelinux" _ "code.dumpstack.io/tools/out-of-tree/distro/ubuntu"