167 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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.
 | |
| 
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"crypto/sha1"
 | |
| 	"encoding/hex"
 | |
| 	"errors"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"os/user"
 | |
| 	"path/filepath"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/go-git/go-git/v5"
 | |
| 	"github.com/rs/zerolog/log"
 | |
| 
 | |
| 	"code.dumpstack.io/tools/out-of-tree/config"
 | |
| 	"code.dumpstack.io/tools/out-of-tree/qemu"
 | |
| )
 | |
| 
 | |
| func preloadModules(q *qemu.System, ka config.Artifact, ki config.KernelInfo,
 | |
| 	dockerTimeout time.Duration) (err error) {
 | |
| 
 | |
| 	for _, pm := range ka.Preload {
 | |
| 		err = preload(q, ki, pm, dockerTimeout)
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func preload(q *qemu.System, ki config.KernelInfo, pm config.PreloadModule,
 | |
| 	dockerTimeout time.Duration) (err error) {
 | |
| 
 | |
| 	var workPath, cache string
 | |
| 	if pm.Path != "" {
 | |
| 		log.Print("Use non-git path for preload module (no cache)")
 | |
| 		workPath = pm.Path
 | |
| 	} else if pm.Repo != "" {
 | |
| 		workPath, cache, err = cloneOrPull(pm.Repo, ki)
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	} else {
 | |
| 		errors.New("No repo/path in preload entry")
 | |
| 	}
 | |
| 
 | |
| 	err = buildAndInsmod(workPath, q, ki, dockerTimeout, cache)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	time.Sleep(pm.TimeoutAfterLoad.Duration)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func buildAndInsmod(workPath string, q *qemu.System, ki config.KernelInfo,
 | |
| 	dockerTimeout time.Duration, cache string) (err error) {
 | |
| 
 | |
| 	tmp, err := ioutil.TempDir("", "out-of-tree_")
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	defer os.RemoveAll(tmp)
 | |
| 
 | |
| 	var artifact string
 | |
| 	if exists(cache) {
 | |
| 		artifact = cache
 | |
| 	} else {
 | |
| 		artifact, err = buildPreload(workPath, tmp, ki, dockerTimeout)
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 		if cache != "" {
 | |
| 			err = copyFile(artifact, cache)
 | |
| 			if err != nil {
 | |
| 				return
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	output, err := q.CopyAndInsmod(artifact)
 | |
| 	if err != nil {
 | |
| 		log.Print(output)
 | |
| 		return
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func buildPreload(workPath, tmp string, ki config.KernelInfo,
 | |
| 	dockerTimeout time.Duration) (artifact string, err error) {
 | |
| 
 | |
| 	ka, err := config.ReadArtifactConfig(workPath + "/.out-of-tree.toml")
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ka.SourcePath = workPath
 | |
| 
 | |
| 	km := config.KernelMask{DistroType: ki.DistroType,
 | |
| 		DistroRelease: ki.DistroRelease,
 | |
| 		ReleaseMask:   ki.KernelRelease,
 | |
| 	}
 | |
| 	ka.SupportedKernels = []config.KernelMask{km}
 | |
| 
 | |
| 	if ka.Docker.Timeout.Duration != 0 {
 | |
| 		dockerTimeout = ka.Docker.Timeout.Duration
 | |
| 	}
 | |
| 
 | |
| 	_, artifact, _, err = build(tmp, ka, ki, dockerTimeout)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func cloneOrPull(repo string, ki config.KernelInfo) (workPath, cache string, err error) {
 | |
| 	usr, err := user.Current()
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	base := filepath.Join(usr.HomeDir, "/.out-of-tree/preload/")
 | |
| 	workPath = filepath.Join(base, "/repos/", sha1sum(repo))
 | |
| 
 | |
| 	var r *git.Repository
 | |
| 	if exists(workPath) {
 | |
| 		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 {
 | |
| 			log.Print(repo, "pull error:", err)
 | |
| 		}
 | |
| 	} 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[:])
 | |
| }
 |