github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/bundle.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package tests 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "fmt" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "strings" 16 17 spec "github.com/opencontainers/specs/specs-go" 18 ) 19 20 const image = "busybox" 21 22 const tmpDir = "/tmp" 23 24 const configTemplate = "src/github.com/kata-containers/tests/data/config.json" 25 26 // Bundle represents the root directory where config.json and rootfs are 27 type Bundle struct { 28 // Config represents the config.json 29 Config *spec.Spec 30 31 // Path to the bundle 32 Path string 33 } 34 35 // NewBundle creates a new bundle 36 func NewBundle(workload []string) (*Bundle, error) { 37 path, err := ioutil.TempDir("", "bundle") 38 if err != nil { 39 return nil, err 40 } 41 42 if err := createRootfs(path); err != nil { 43 return nil, err 44 } 45 46 gopath := os.Getenv("GOPATH") 47 if gopath == "" { 48 return nil, fmt.Errorf("GOPATH is not set") 49 } 50 51 configTemplatePath := filepath.Join(gopath, configTemplate) 52 content, err := ioutil.ReadFile(configTemplatePath) 53 if err != nil { 54 return nil, err 55 } 56 57 var config spec.Spec 58 err = json.Unmarshal(content, &config) 59 if err != nil { 60 return nil, err 61 } 62 63 // By default, let's not create a terminal 64 config.Process.Terminal = false 65 66 config.Process.Args = workload 67 68 bundle := &Bundle{ 69 Path: path, 70 Config: &config, 71 } 72 73 err = bundle.Save() 74 if err != nil { 75 return nil, err 76 } 77 78 return bundle, nil 79 } 80 81 // createRootfs creates a rootfs in the specific bundlePath 82 func createRootfs(bundlePath string) error { 83 if bundlePath == "" { 84 return fmt.Errorf("bundle path should not be empty") 85 } 86 87 rootfsDir := filepath.Join(bundlePath, "rootfs") 88 if err := os.MkdirAll(rootfsDir, 0755); err != nil { 89 return err 90 } 91 92 // create container 93 var container bytes.Buffer 94 createCmd := exec.Command("docker", "create", image) 95 createCmd.Stdout = &container 96 if err := createCmd.Run(); err != nil { 97 return err 98 } 99 containerName := strings.TrimRight(container.String(), "\n") 100 101 // export container 102 tarFile, err := ioutil.TempFile(tmpDir, "tar") 103 if err != nil { 104 return err 105 } 106 defer tarFile.Close() 107 108 exportCmd := exec.Command("docker", "export", "-o", tarFile.Name(), containerName) 109 if err := exportCmd.Run(); err != nil { 110 return err 111 } 112 defer os.Remove(tarFile.Name()) 113 114 // extract container 115 tarCmd := exec.Command("tar", "-C", rootfsDir, "-pxf", tarFile.Name()) 116 if err := tarCmd.Run(); err != nil { 117 return err 118 } 119 120 // remove container 121 rmCmd := exec.Command("docker", "rm", "-f", containerName) 122 return rmCmd.Run() 123 } 124 125 // Save to disk the Config 126 func (b *Bundle) Save() error { 127 content, err := json.Marshal(b.Config) 128 if err != nil { 129 return err 130 } 131 132 configFile := filepath.Join(b.Path, "config.json") 133 err = ioutil.WriteFile(configFile, content, 0644) 134 if err != nil { 135 return err 136 } 137 138 return nil 139 } 140 141 // Remove the bundle files and directories 142 func (b *Bundle) Remove() error { 143 return os.RemoveAll(b.Path) 144 }