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  }