github.com/mgoltzsche/ctnr@v0.7.1-alpha/bundle/store/bundlestore.go (about)

     1  package store
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"time"
     8  
     9  	"github.com/mgoltzsche/ctnr/bundle"
    10  	exterrors "github.com/mgoltzsche/ctnr/pkg/errors"
    11  	"github.com/mgoltzsche/ctnr/pkg/log"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  var _ bundle.BundleStore = &BundleStore{}
    16  
    17  type BundleStore struct {
    18  	dir   string
    19  	debug log.FieldLogger
    20  	info  log.FieldLogger
    21  }
    22  
    23  func NewBundleStore(dir string, info log.FieldLogger, debug log.FieldLogger) *BundleStore {
    24  	return &BundleStore{dir, debug, info}
    25  }
    26  
    27  func (s *BundleStore) Bundles() (l []bundle.Bundle, err error) {
    28  	fl, e := ioutil.ReadDir(s.dir)
    29  	l = make([]bundle.Bundle, 0, len(fl))
    30  	if e != nil && !os.IsNotExist(e) {
    31  		return l, errors.Wrap(err, "bundles")
    32  	}
    33  	for _, f := range fl {
    34  		if f.IsDir() {
    35  			c, e := s.Bundle(f.Name())
    36  			if e == nil {
    37  				l = append(l, c)
    38  			} else {
    39  				err = exterrors.Append(err, e)
    40  			}
    41  		}
    42  	}
    43  	return
    44  }
    45  
    46  func (s *BundleStore) Bundle(id string) (r bundle.Bundle, err error) {
    47  	return bundle.NewBundle(filepath.Join(s.dir, id))
    48  }
    49  
    50  func (s *BundleStore) CreateBundle(id string, update bool) (b *bundle.LockedBundle, err error) {
    51  	dir := filepath.Join(s.dir, id)
    52  	if id == "" {
    53  		if err = os.MkdirAll(s.dir, 0750); err != nil {
    54  			return nil, errors.Wrap(err, "create bundle")
    55  		}
    56  		if dir, err = ioutil.TempDir(s.dir, ""); err != nil {
    57  			return nil, errors.Wrap(err, "create bundle")
    58  		}
    59  		update = true
    60  	}
    61  	return bundle.CreateLockedBundle(dir, update)
    62  }
    63  
    64  // Deletes all bundles that have not been used longer than the given TTL.
    65  func (s *BundleStore) BundleGC(ttl time.Duration, containers bundle.ContainerStore) (r []bundle.Bundle, err error) {
    66  	s.debug.Printf("Running bundle GC with TTL of %s", ttl)
    67  	before := time.Now().Add(-ttl)
    68  	l, err := s.Bundles()
    69  	r = make([]bundle.Bundle, 0, len(l))
    70  	for _, b := range l {
    71  		gcd, e := gc(b, before, containers)
    72  		if e != nil {
    73  			if gcd {
    74  				s.debug.WithField("id", b.ID()).Println("bundle gc:", e)
    75  			}
    76  		} else if gcd {
    77  			s.debug.WithField("id", b.ID()).Printf("bundle garbage collected")
    78  			r = append(r, b)
    79  		}
    80  	}
    81  	return
    82  }
    83  
    84  func gc(b bundle.Bundle, before time.Time, containers bundle.ContainerStore) (r bool, err error) {
    85  	defer exterrors.Wrapd(&err, "bundle gc check")
    86  	lastUsed, err := b.LastUsed()
    87  	if err != nil {
    88  		return false, err
    89  	}
    90  	if lastUsed.Before(before) {
    91  		// lock bundle
    92  		lb, err := bundle.OpenLockedBundle(b)
    93  		if err != nil {
    94  			return false, err
    95  		}
    96  		defer func() {
    97  			err = exterrors.Append(err, lb.Close())
    98  		}()
    99  
   100  		// Check bundle usage time against expiry time
   101  		if lastUsed, err = b.LastUsed(); err != nil {
   102  			return true, err
   103  		}
   104  		if !lastUsed.Before(before) {
   105  			return false, nil
   106  		}
   107  
   108  		// Check if container is running
   109  		exists, err := containers.Exist(b.ID())
   110  		if err != nil {
   111  			return true, err
   112  		}
   113  		if exists {
   114  			return false, nil
   115  		}
   116  
   117  		return true, lb.Delete()
   118  	}
   119  	return
   120  }