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  }