| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | // Copyright 2020 Mikhail Klementev. All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a AGPLv3 license | 
					
						
							|  |  |  | // (or later) that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | package artifact | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/sha1" | 
					
						
							|  |  |  | 	"encoding/hex" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/go-git/go-git/v5" | 
					
						
							| 
									
										
										
										
											2023-03-18 21:30:07 +00:00
										 |  |  | 	"github.com/rs/zerolog/log" | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	"code.dumpstack.io/tools/out-of-tree/config/dotfiles" | 
					
						
							| 
									
										
										
										
											2023-05-23 21:33:50 +00:00
										 |  |  | 	"code.dumpstack.io/tools/out-of-tree/distro" | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	"code.dumpstack.io/tools/out-of-tree/qemu" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | func PreloadModules(q *qemu.System, ka Artifact, ki distro.KernelInfo, | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	dockerTimeout time.Duration) (err error) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, pm := range ka.Preload { | 
					
						
							|  |  |  | 		err = preload(q, ki, pm, dockerTimeout) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | func preload(q *qemu.System, ki distro.KernelInfo, pm PreloadModule, | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	dockerTimeout time.Duration) (err error) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var workPath, cache string | 
					
						
							|  |  |  | 	if pm.Path != "" { | 
					
						
							| 
									
										
										
										
											2024-05-23 10:19:46 +00:00
										 |  |  | 		log.Debug().Msg("Use non-git path for preload module (no cache)") | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 		workPath = pm.Path | 
					
						
							|  |  |  | 	} else if pm.Repo != "" { | 
					
						
							|  |  |  | 		workPath, cache, err = cloneOrPull(pm.Repo, ki) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 		err = errors.New("no repo/path in preload entry") | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = buildAndInsmod(workPath, q, ki, dockerTimeout, cache) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	time.Sleep(pm.TimeoutAfterLoad.Duration) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-23 21:33:50 +00:00
										 |  |  | func buildAndInsmod(workPath string, q *qemu.System, ki distro.KernelInfo, | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	dockerTimeout time.Duration, cache string) (err error) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	tmp, err := tempDir() | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(tmp) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	var af string | 
					
						
							|  |  |  | 	if pathExists(cache) { | 
					
						
							|  |  |  | 		af = cache | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 		af, err = buildPreload(workPath, tmp, ki, dockerTimeout) | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if cache != "" { | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 			err = CopyFile(af, cache) | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	output, err := q.CopyAndInsmod(af) | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-05-23 10:19:46 +00:00
										 |  |  | 		log.Error().Err(err).Msg(output) | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-23 21:33:50 +00:00
										 |  |  | func buildPreload(workPath, tmp string, ki distro.KernelInfo, | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	dockerTimeout time.Duration) (af string, err error) { | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	ka, err := Artifact{}.Read(workPath + "/.out-of-tree.toml") | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2023-05-18 16:43:15 +00:00
										 |  |  | 		log.Warn().Err(err).Msg("preload") | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ka.SourcePath = workPath | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	km := Target{ | 
					
						
							| 
									
										
										
										
											2023-05-18 18:48:09 +00:00
										 |  |  | 		Distro: ki.Distro, | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 		Kernel: Kernel{Regex: ki.KernelRelease}, | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	ka.Targets = []Target{km} | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ka.Docker.Timeout.Duration != 0 { | 
					
						
							|  |  |  | 		dockerTimeout = ka.Docker.Timeout.Duration | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-07 22:06:04 +00:00
										 |  |  | 	_, af, _, err = Build(log.Logger, tmp, ka, ki, dockerTimeout, false) | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | func pathExists(path string) bool { | 
					
						
							|  |  |  | 	if _, err := os.Stat(path); err != nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func tempDir() (string, error) { | 
					
						
							|  |  |  | 	return os.MkdirTemp(dotfiles.Dir("tmp"), "") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-23 21:33:50 +00:00
										 |  |  | func cloneOrPull(repo string, ki distro.KernelInfo) (workPath, cache string, | 
					
						
							| 
									
										
										
										
											2023-05-21 20:31:47 +00:00
										 |  |  | 	err error) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	base := dotfiles.Dir("preload") | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 	workPath = filepath.Join(base, "/repos/", sha1sum(repo)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var r *git.Repository | 
					
						
							| 
									
										
										
										
											2024-02-20 13:25:31 +00:00
										 |  |  | 	if pathExists(workPath) { | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 		r, err = git.PlainOpen(workPath) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var w *git.Worktree | 
					
						
							|  |  |  | 		w, err = r.Worktree() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		err = w.Pull(&git.PullOptions{}) | 
					
						
							|  |  |  | 		if err != nil && err != git.NoErrAlreadyUpToDate { | 
					
						
							| 
									
										
										
										
											2024-05-23 10:19:46 +00:00
										 |  |  | 			log.Error().Err(err).Msgf("pull %s error", repo) | 
					
						
							| 
									
										
										
										
											2020-06-14 20:14:59 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		r, err = git.PlainClone(workPath, false, &git.CloneOptions{URL: repo}) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ref, err := r.Head() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cachedir := filepath.Join(base, "/cache/") | 
					
						
							|  |  |  | 	os.MkdirAll(cachedir, 0700) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	filename := sha1sum(repo + ki.KernelPath + ref.Hash().String()) | 
					
						
							|  |  |  | 	cache = filepath.Join(cachedir, filename) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func sha1sum(data string) string { | 
					
						
							|  |  |  | 	h := sha1.Sum([]byte(data)) | 
					
						
							|  |  |  | 	return hex.EncodeToString(h[:]) | 
					
						
							|  |  |  | } |