github.com/hpcng/singularity@v3.1.1+incompatible/pkg/ocibundle/tools/oci.go (about)

     1  // Copyright (c) 2019, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package tools
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"syscall"
    14  
    15  	specs "github.com/opencontainers/runtime-spec/specs-go"
    16  
    17  	"github.com/opencontainers/runtime-tools/generate"
    18  )
    19  
    20  // RootFs is the default root path for OCI bundle
    21  type RootFs string
    22  
    23  // Path returns the root path inside bundle
    24  func (r RootFs) Path() string {
    25  	return filepath.Join(string(r), "rootfs")
    26  }
    27  
    28  // Volumes is the parent volumes path
    29  type Volumes string
    30  
    31  // Path returns the volumes path inside bundle
    32  func (v Volumes) Path() string {
    33  	return filepath.Join(string(v), "volumes")
    34  }
    35  
    36  // Config is the OCI configuration path
    37  type Config string
    38  
    39  // Path returns the OCI configuration path
    40  func (c Config) Path() string {
    41  	return filepath.Join(string(c), "config.json")
    42  }
    43  
    44  // RunScript is the default process argument
    45  const RunScript = "/.singularity.d/actions/run"
    46  
    47  // GenerateBundleConfig generates a minimal OCI bundle directory
    48  // with the provided OCI configuration or a default one
    49  // if there is no configuration
    50  func GenerateBundleConfig(bundlePath string, config *specs.Spec) (*generate.Generator, error) {
    51  	var err error
    52  	var g generate.Generator
    53  
    54  	oldumask := syscall.Umask(0)
    55  	defer syscall.Umask(oldumask)
    56  
    57  	rootFsDir := RootFs(bundlePath).Path()
    58  	if err := os.MkdirAll(rootFsDir, 0700); err != nil {
    59  		return nil, fmt.Errorf("failed to create %s: %s", rootFsDir, err)
    60  	}
    61  	volumesDir := Volumes(bundlePath).Path()
    62  	if err := os.MkdirAll(volumesDir, 0755); err != nil {
    63  		return nil, fmt.Errorf("failed to create %s: %s", volumesDir, err)
    64  	}
    65  	defer func() {
    66  		if err != nil {
    67  			DeleteBundle(bundlePath)
    68  		}
    69  	}()
    70  
    71  	if config == nil {
    72  		// generate and write config.json in bundle
    73  		g, err = generate.New(runtime.GOOS)
    74  		if err != nil {
    75  			return nil, fmt.Errorf("failed to generate OCI config: %s", err)
    76  		}
    77  		g.SetProcessArgs([]string{RunScript})
    78  	} else {
    79  		g = generate.Generator{
    80  			Config:       config,
    81  			HostSpecific: true,
    82  		}
    83  	}
    84  	g.SetRootPath(rootFsDir)
    85  	return &g, nil
    86  }
    87  
    88  // SaveBundleConfig creates config.json in OCI bundle directory and
    89  // saves OCI configuration
    90  func SaveBundleConfig(bundlePath string, g *generate.Generator) error {
    91  	options := generate.ExportOptions{}
    92  	return g.SaveToFile(Config(bundlePath).Path(), options)
    93  }
    94  
    95  // DeleteBundle deletes bundle directory
    96  func DeleteBundle(bundlePath string) error {
    97  	if err := os.RemoveAll(Volumes(bundlePath).Path()); err != nil {
    98  		return fmt.Errorf("failed to delete volumes directory: %s", err)
    99  	}
   100  	if err := os.Remove(RootFs(bundlePath).Path()); err != nil {
   101  		return fmt.Errorf("failed to delete rootfs directory: %s", err)
   102  	}
   103  	if err := os.Remove(Config(bundlePath).Path()); err != nil {
   104  		return fmt.Errorf("failed to delete config.json file: %s", err)
   105  	}
   106  	if err := os.Remove(bundlePath); err != nil && !os.IsExist(err) {
   107  		return fmt.Errorf("failed to delete bundle %s directory: %s", bundlePath, err)
   108  	}
   109  	return nil
   110  }