From e2d66db16f5e364c52132b5489fa9bca405c0fb2 Mon Sep 17 00:00:00 2001 From: Mikhail Klementev Date: Tue, 23 May 2023 22:36:46 +0000 Subject: [PATCH] feat: add kernel install to distro interface --- distro/centos/centos.go | 45 ++++++++++++ distro/debian/debian.go | 51 +++++++++++-- distro/distro.go | 13 ++++ distro/oraclelinux/oraclelinux.go | 25 +++++-- distro/ubuntu/ubuntu.go | 25 +++++-- kernel.go | 3 +- kernel/kernel.go | 118 ------------------------------ 7 files changed, 143 insertions(+), 137 deletions(-) diff --git a/distro/centos/centos.go b/distro/centos/centos.go index d40d438..c2343e1 100644 --- a/distro/centos/centos.go +++ b/distro/centos/centos.go @@ -158,3 +158,48 @@ func (centos CentOS) runs() (commands []string) { return } + +func (centos CentOS) Install(pkgname string, headers bool) (err error) { + var headerspkg string + if headers { + headerspkg = strings.Replace(pkgname, "kernel", "kernel-devel", -1) + } + + var commands []string + cmdf := func(f string, s ...interface{}) { + commands = append(commands, fmt.Sprintf(f, s...)) + } + + cmdf("yum -y install %s %s", pkgname, headerspkg) + + version := strings.Replace(pkgname, "kernel-", "", -1) + + if centos.release <= "7" { + cmdf("dracut -v --add-drivers 'e1000 ext4' -f "+ + "/boot/initramfs-%s.img %s", version, version) + } else { + cmdf("dracut -v --add-drivers 'ata_piix libata' "+ + "--force-drivers 'e1000 ext4 sd_mod' -f "+ + "/boot/initramfs-%s.img %s", version, version) + } + + cmdf("cp -r /boot /target/") + cmdf("cp -r /lib/modules /target/lib/") + cmdf("cp -r /usr/src /target/usr/") + + c, err := container.New(centos.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 +} diff --git a/distro/debian/debian.go b/distro/debian/debian.go index 6b19633..dc65480 100644 --- a/distro/debian/debian.go +++ b/distro/debian/debian.go @@ -348,8 +348,13 @@ func (d Debian) Kernels() (kernels []distro.KernelInfo, err error) { return } -func Volumes(km config.Target, pkgname string) (volumes []container.Volume) { - pkgdir := filepath.Join("volumes", km.DockerName(), pkgname) +func (d Debian) volumes(pkgname string) (volumes []container.Volume) { + c, err := container.New(d.Distro()) + if err != nil { + return + } + + pkgdir := filepath.Join("volumes", c.Name(), pkgname) volumes = append(volumes, container.Volume{ Src: config.Dir(pkgdir, "/lib/modules"), @@ -369,7 +374,13 @@ func Volumes(km config.Target, pkgname string) (volumes []container.Volume) { return } -func Install(km config.Target, pkgname string, headers bool) (cmds []string, err error) { +func (d Debian) Install(pkgname string, headers bool) (err error) { + defer func() { + if err != nil { + d.cleanup(pkgname) + } + }() + dk, err := getCachedKernel(pkgname + ".deb") if err != nil { return @@ -382,9 +393,11 @@ func Install(km config.Target, pkgname string, headers bool) (cmds []string, err pkgs = []snapshot.Package{dk.Image} } + var cmds []string + for _, pkg := range pkgs { found, newurl := cache.PackageURL( - km.Distro.ID, + distro.Debian, pkg.Deb.URL, ) if found { @@ -402,15 +415,39 @@ func Install(km config.Target, pkgname string, headers bool) (cmds []string, err cmds = append(cmds, "dpkg -i ./*.deb") + c, err := container.New(d.Distro()) + if err != nil { + return + } + + c.Volumes = d.volumes(pkgname) + for i := range c.Volumes { + c.Volumes[i].Dest = "/target" + c.Volumes[i].Dest + } + + cmds = append(cmds, "cp -r /boot /target/") + cmds = append(cmds, "cp -r /lib/modules /target/lib/") + cmds = append(cmds, "cp -r /usr/src /target/usr/") + + _, err = c.Run("", cmds) + if err != nil { + return + } + return } -func Cleanup(km config.Target, pkgname string) { - pkgdir := config.Dir(filepath.Join("volumes", km.DockerName(), pkgname)) +func (d Debian) cleanup(pkgname string) { + c, err := container.New(d.Distro()) + if err != nil { + return + } + + pkgdir := config.Dir(filepath.Join("volumes", c.Name(), pkgname)) log.Debug().Msgf("cleanup %s", pkgdir) - err := os.RemoveAll(pkgdir) + err = os.RemoveAll(pkgdir) if err != nil { log.Warn().Err(err).Msg("cleanup") } diff --git a/distro/distro.go b/distro/distro.go index 80c1f58..ed102c5 100644 --- a/distro/distro.go +++ b/distro/distro.go @@ -1,6 +1,7 @@ package distro import ( + "errors" "sync" ) @@ -11,6 +12,7 @@ type distribution interface { Distro() Distro Equal(Distro) bool Packages() (packages []string, err error) + Install(pkg string, headers bool) (err error) Kernels() (kernels []KernelInfo, err error) } @@ -54,6 +56,17 @@ func (d Distro) Packages() (packages []string, err error) { return } +func (d Distro) Install(pkg string, headers bool) (err error) { + for _, dd := range distros { + if !dd.Equal(d) { + continue + } + + return dd.Install(pkg, headers) + } + return errors.New("not found") +} + func (d Distro) Kernels() (kernels []KernelInfo, err error) { for _, dd := range distros { if dd.Equal(d) { diff --git a/distro/oraclelinux/oraclelinux.go b/distro/oraclelinux/oraclelinux.go index e6f0b0f..c6dda3a 100644 --- a/distro/oraclelinux/oraclelinux.go +++ b/distro/oraclelinux/oraclelinux.go @@ -96,7 +96,7 @@ func (ol OracleLinux) runs() (commands []string) { return } -func Install(km config.Target, pkgname string, headers bool) (commands []string, err error) { +func (ol OracleLinux) Install(pkgname string, headers bool) (err error) { var headerspkg string if headers { if strings.Contains(pkgname, "uek") { @@ -108,6 +108,7 @@ func Install(km config.Target, pkgname string, headers bool) (commands []string, } } + var commands []string cmdf := func(f string, s ...interface{}) { commands = append(commands, fmt.Sprintf(f, s...)) } @@ -121,7 +122,7 @@ func Install(km config.Target, pkgname string, headers bool) (commands []string, version = strings.Replace(pkgname, "kernel-", "", -1) } - if km.Distro.Release <= "7" { + if ol.release <= "7" { cmdf("dracut -v --add-drivers 'e1000 ext4' -f "+ "/boot/initramfs-%s.img %s", version, version) } else { @@ -130,9 +131,23 @@ func Install(km config.Target, pkgname string, headers bool) (commands []string, "/boot/initramfs-%s.img %s", version, version) } - return -} + cmdf("cp -r /boot /target/") + cmdf("cp -r /lib/modules /target/lib/") + cmdf("cp -r /usr/src /target/usr/") + + c, err := container.New(ol.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 + } -func Cleanup(km config.Target, pkgname string) { return } diff --git a/distro/ubuntu/ubuntu.go b/distro/ubuntu/ubuntu.go index 055493a..210afc1 100644 --- a/distro/ubuntu/ubuntu.go +++ b/distro/ubuntu/ubuntu.go @@ -122,22 +122,35 @@ func (u Ubuntu) runs() (commands []string) { return } -func Install(km config.Target, pkgname string, headers bool) (commands []string, err error) { - +func (u Ubuntu) Install(pkgname string, headers bool) (err error) { var headerspkg string if headers { headerspkg = strings.Replace(pkgname, "image", "headers", -1) } + var commands []string cmdf := func(f string, s ...interface{}) { commands = append(commands, fmt.Sprintf(f, s...)) } cmdf("apt-get install -y %s %s", pkgname, headerspkg) + cmdf("cp -r /boot /target/") + cmdf("cp -r /lib/modules /target/lib/") + cmdf("cp -r /usr/src /target/usr/") + + c, err := container.New(u.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 Cleanup(km config.Target, pkgname string) { - return -} diff --git a/kernel.go b/kernel.go index cfd669d..5faeb76 100644 --- a/kernel.go +++ b/kernel.go @@ -129,7 +129,8 @@ func (cmd KernelCmd) Generate(g *Globals, km config.Target, max int, return } - err = kernel.InstallKernel(km, p, cmd.Force, !cmd.NoHeaders) + // TODO cmd.Force + err = km.Distro.Install(p, !cmd.NoHeaders) if err == nil { max-- break diff --git a/kernel/kernel.go b/kernel/kernel.go index 2172a69..fcc1a06 100644 --- a/kernel/kernel.go +++ b/kernel/kernel.go @@ -5,7 +5,6 @@ package kernel import ( - "fmt" "io/ioutil" "math/rand" "os" @@ -20,10 +19,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/distro" - "code.dumpstack.io/tools/out-of-tree/distro/debian" - "code.dumpstack.io/tools/out-of-tree/distro/oraclelinux" - "code.dumpstack.io/tools/out-of-tree/distro/ubuntu" "code.dumpstack.io/tools/out-of-tree/fs" ) @@ -65,119 +60,6 @@ func vsyscallAvailable() (available bool, err error) { return } -func InstallKernel(sk config.Target, pkgname string, force, headers bool) (err error) { - slog := log.With(). - Str("distro_type", sk.Distro.ID.String()). - Str("distro_release", sk.Distro.Release). - Str("pkg", pkgname). - Logger() - - c, err := container.New(sk.Distro) // TODO conf - if err != nil { - return - } - - searchdir := "" - for _, volume := range c.Volumes { - if volume.Dest == "/lib/modules" { - searchdir = volume.Src - } - } - - if sk.Distro.ID == distro.Debian { - // TODO We need some kind of API for that - searchdir = config.Dir("volumes", sk.DockerName()) - } - - moddirs, err := ioutil.ReadDir(searchdir) - if err != nil { - return - } - - for _, krel := range moddirs { - if strings.Contains(pkgname, krel.Name()) { - if force { - slog.Info().Msg("Reinstall") - } else { - slog.Info().Msg("Already installed") - return - } - } - } - - if sk.Distro.ID == distro.Debian { - // Debian has different kernels (package version) by the - // same name (ABI), so we need to separate /boot - c.Volumes = debian.Volumes(sk, pkgname) - } - - slog.Debug().Msgf("Installing kernel") - - var commands []string - - // TODO install/cleanup kernel interface - switch sk.Distro.ID { - case distro.Ubuntu: - commands, err = ubuntu.Install(sk, pkgname, headers) - if err != nil { - return - } - defer func() { - if err != nil { - ubuntu.Cleanup(sk, pkgname) - } - }() - case distro.OracleLinux, distro.CentOS: - commands, err = oraclelinux.Install(sk, pkgname, headers) - if err != nil { - return - } - defer func() { - if err != nil { - oraclelinux.Cleanup(sk, pkgname) - } - }() - case distro.Debian: - commands, err = debian.Install(sk, pkgname, headers) - if err != nil { - return - } - defer func() { - if err != nil { - debian.Cleanup(sk, pkgname) - } - }() - default: - err = fmt.Errorf("%s not yet supported", sk.Distro.ID.String()) - return - } - - cmd := "true" - for _, command := range commands { - cmd += fmt.Sprintf(" && %s", command) - } - - for i := range c.Volumes { - c.Volumes[i].Dest = "/target" + c.Volumes[i].Dest - } - - cmd += " && cp -r /boot /target/" - cmd += " && cp -r /lib/modules /target/lib/" - if sk.Distro.ID == distro.Debian { - cmd += " && cp -rL /usr/src /target/usr/" - } else { - cmd += " && cp -r /usr/src /target/usr/" - } - - _, err = c.Run("", []string{cmd}) - if err != nil { - return - } - - slog.Debug().Msgf("Success") - return -} - func GenRootfsImage(d container.Image, download bool) (rootfs string, err error) { imagesPath := config.Dir("images") imageFile := d.Name + ".img"