github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/executables/runtime.go (about) 1 //go:generate goderive . 2 3 package executables 4 5 import ( 6 "bytes" 7 "compress/gzip" 8 "encoding/base64" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 15 "github.com/caos/orbos/internal/helpers" 16 ) 17 18 var executables map[string][]byte 19 20 var populate = func() {} 21 22 func Populate() { 23 populate() 24 } 25 26 func PreBuilt(name string) []byte { 27 executable, ok := executables[name] 28 if !ok { 29 panic(fmt.Errorf("%s was not prebuilt", name)) 30 } 31 return executable 32 } 33 34 func PreBuild(packables <-chan PackableTuple) (err error) { 35 sp := selfPath() 36 tmpFile := filepath.Join(sp, "prebuilt.tmp") 37 outFile := filepath.Join(sp, "prebuilt.go") 38 prebuilt, err := os.Create(tmpFile) 39 if err != nil { 40 return fmt.Errorf("creating %s failed: %w", tmpFile, err) 41 } 42 defer func() { 43 if err != nil { 44 os.Remove(tmpFile) 45 panic(err) 46 } 47 err = os.Rename(tmpFile, outFile) 48 }() 49 50 if _, err = prebuilt.WriteString(`package executables 51 52 func init() { 53 populate = func(){ 54 executables = map[string][]byte{`); err != nil { 55 return err 56 } 57 58 for pt := range deriveFmapPack(pack, packables) { 59 packable, packed, packErr := pt() 60 err = helpers.Concat(err, packErr) 61 if packErr != nil { 62 continue 63 } 64 65 _, packErr = prebuilt.WriteString(fmt.Sprintf(` 66 "%s": unpack("%s"),`, packable.key, *packed)) 67 err = helpers.Concat(err, packErr) 68 } 69 70 if err != nil { 71 os.Remove(prebuilt.Name()) 72 return err 73 } 74 75 _, err = prebuilt.WriteString(` 76 } 77 } 78 } 79 `) 80 return err 81 } 82 83 func packedTupleFunc(packable *packable) func(*string, error) packedTuple { 84 return func(packed *string, err error) packedTuple { 85 return deriveTuplePacked(packable, packed, err) 86 } 87 } 88 89 type packable struct { 90 key string 91 data io.ReadCloser 92 } 93 94 type PackableTuple func() (*packable, error) 95 96 func NewPackableTuple(key string, data io.ReadCloser) PackableTuple { 97 return deriveTuplePackable(&packable{ 98 key: key, 99 data: data, 100 }, nil) 101 } 102 103 type packedTuple func() (*packable, *string, error) 104 105 func pack(packableTuple PackableTuple) packedTuple { 106 107 packable, err := packableTuple() 108 defer func() { 109 if packable != nil { 110 packable.data.Close() 111 } 112 }() 113 114 packedTuple := packedTupleFunc(packable) 115 if err != nil { 116 return packedTuple(nil, err) 117 } 118 119 gzipBuffer := new(bytes.Buffer) 120 defer gzipBuffer.Reset() 121 122 gzipWriter := gzip.NewWriter(gzipBuffer) 123 _, err = io.Copy(gzipWriter, packable.data) 124 if err != nil { 125 return packedTuple(nil, fmt.Errorf("gzipping failed: %w", err)) 126 } 127 128 if err := packable.data.Close(); err != nil { 129 return packedTuple(nil, fmt.Errorf("closing data failed: %w", err)) 130 } 131 132 if err := gzipWriter.Close(); err != nil { 133 return packedTuple(nil, fmt.Errorf("closing gzip writer failed: %w", err)) 134 } 135 136 packed := base64.StdEncoding.EncodeToString(gzipBuffer.Bytes()) 137 138 return packedTuple(&packed, nil) 139 } 140 141 func unpack(executable string) []byte { 142 gzipNodeAgent, err := base64.StdEncoding.DecodeString(executable) 143 if err != nil { 144 panic(fmt.Errorf("decoding node agent from base64 failed: %w", err)) 145 } 146 bytesReader := bytes.NewReader(gzipNodeAgent) 147 148 gzipReader, err := gzip.NewReader(bytesReader) 149 if err != nil { 150 panic(fmt.Errorf("ungzipping node agent failed: %w", err)) 151 } 152 defer gzipReader.Close() 153 154 unpacked, err := ioutil.ReadAll(gzipReader) 155 if err != nil { 156 panic(fmt.Errorf("reading unpacked node agent failed: %w", err)) 157 } 158 return unpacked 159 }