feat: add kernel install to distro interface
This commit is contained in:
		| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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") | ||||
| 	} | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										118
									
								
								kernel/kernel.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								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" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user