github.com/nak3/source-to-image@v1.1.10-0.20180319140719-2ed55639898d/pkg/util/injection.go (about) 1 package util 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/openshift/source-to-image/pkg/api" 11 "github.com/openshift/source-to-image/pkg/util/fs" 12 ) 13 14 // FixInjectionsWithRelativePath fixes the injections that does not specify the 15 // destination directory or the directory is relative to use the provided 16 // working directory. 17 func FixInjectionsWithRelativePath(workdir string, injections api.VolumeList) api.VolumeList { 18 if len(injections) == 0 { 19 return injections 20 } 21 newList := api.VolumeList{} 22 for _, injection := range injections { 23 changed := false 24 if filepath.Clean(filepath.FromSlash(injection.Destination)) == "." { 25 injection.Destination = filepath.ToSlash(workdir) 26 changed = true 27 } 28 if filepath.ToSlash(injection.Destination)[0] != '/' { 29 injection.Destination = filepath.ToSlash(filepath.Join(workdir, injection.Destination)) 30 changed = true 31 } 32 if changed { 33 glog.V(5).Infof("Using %q as a destination for injecting %q", injection.Destination, injection.Source) 34 } 35 newList = append(newList, injection) 36 } 37 return newList 38 } 39 40 // ExpandInjectedFiles returns a flat list of all files that are injected into a 41 // container. All files from nested directories are returned in the list. 42 func ExpandInjectedFiles(fs fs.FileSystem, injections api.VolumeList) ([]string, error) { 43 result := []string{} 44 for _, s := range injections { 45 if _, err := os.Stat(s.Source); err != nil { 46 return nil, err 47 } 48 err := fs.Walk(s.Source, func(path string, f os.FileInfo, err error) error { 49 if err != nil { 50 return err 51 } 52 53 // Detected files will be truncated. k8s' AtomicWriter creates 54 // directories and symlinks to directories in order to inject files. 55 // An attempt to truncate either a dir or symlink to a dir will fail. 56 // Thus, we need to dereference symlinks to see if they might point 57 // to a directory. 58 // Do not try to simplify this logic to simply return nil if a symlink 59 // is detected. During the tar transfer to an assemble image, symlinked 60 // files are turned concrete (i.e. they will be turned into regular files 61 // containing the content of their target). These newly concrete files 62 // need to be truncated as well. 63 64 if f.Mode()&os.ModeSymlink != 0 { 65 linkDest, err := filepath.EvalSymlinks(path) 66 if err != nil { 67 return fmt.Errorf("unable to evaluate symlink [%v]: %v", path, err) 68 } 69 // Evaluate the destination of the link. 70 f, err = os.Lstat(linkDest) 71 if err != nil { 72 // This is not a fatal error. If AtomicWrite tried multiple times, a symlink might not point 73 // to a valid destination. 74 glog.Warningf("Unable to lstat symlink destination [%s]->[%s]. err: %v. Partial atomic write?", path, linkDest, err) 75 return nil 76 } 77 } 78 79 if f.IsDir() { 80 return nil 81 } 82 83 newPath := filepath.ToSlash(filepath.Join(s.Destination, strings.TrimPrefix(path, s.Source))) 84 result = append(result, newPath) 85 return nil 86 }) 87 if err != nil { 88 return nil, err 89 } 90 } 91 return result, nil 92 } 93 94 // CreateInjectedFilesRemovalScript creates a shell script that contains truncation 95 // of all files we injected into the container. The path to the script is returned. 96 // When the scriptName is provided, it is also truncated together with all 97 // secrets. 98 func CreateInjectedFilesRemovalScript(files []string, scriptName string) (string, error) { 99 rmScript := "set -e\n" 100 for _, s := range files { 101 rmScript += fmt.Sprintf("truncate -s0 %q\n", s) 102 } 103 104 f, err := ioutil.TempFile("", "s2i-injection-remove") 105 if err != nil { 106 return "", err 107 } 108 if len(scriptName) > 0 { 109 rmScript += fmt.Sprintf("truncate -s0 %q\n", scriptName) 110 } 111 rmScript += "set +e\n" 112 err = ioutil.WriteFile(f.Name(), []byte(rmScript), 0700) 113 return f.Name(), err 114 } 115 116 // HandleInjectionError handles the error caused by injection and provide 117 // reasonable suggestion to users. 118 func HandleInjectionError(p api.VolumeSpec, err error) error { 119 if err == nil { 120 return nil 121 } 122 if strings.Contains(err.Error(), "no such file or directory") { 123 glog.Errorf("The destination directory for %q injection must exist in container (%q)", p.Source, p.Destination) 124 return err 125 } 126 glog.Errorf("Error occurred during injecting %q to %q: %v", p.Source, p.Destination, err) 127 return err 128 }