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 }