github.com/dahs81/otto@v0.2.1-0.20160126165905-6400716cf085/helper/vagrant/layered.go (about)

     1  package vagrant
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"log"
     9  	"os"
    10  	"path/filepath"
    11  	"time"
    12  
    13  	"github.com/boltdb/bolt"
    14  	"github.com/hashicorp/otto/context"
    15  	"github.com/hashicorp/terraform/dag"
    16  )
    17  
    18  // Layered is a Vagrant environment that is created using a series of
    19  // "layers". Otto manages these layers and this library automatically prunes
    20  // unused layers. This library will also do the multi-process locking
    21  // necessary to prevent races.
    22  //
    23  // To update a layer (change it), you should create a Layer with a new ID.
    24  // IDs should be considered immutable for all time. This is to prevent breaking
    25  // other environments. Once a layer is safely no longer in use by anybody
    26  // for a sufficient period of time, Otto will automatically prune it.
    27  //
    28  // Layered itself doesn't manage the final Vagrant environment. This should
    29  // be done outside of this using functions like Dev. Accounting should be done
    30  // to avoid layers being pruned with `AddLeaf`, `RemoveLeaf`. If these
    31  // aren't called layers underneath may be pruned which can corrupt leaves.
    32  type Layered struct {
    33  	// Layers are layers that are important for this run. This must include
    34  	// all the Vagrantfiles for all the potential layers since we might need
    35  	// to run all of them.
    36  	Layers []*Layer
    37  
    38  	// DataDir is the directory where Layered can write data to.
    39  	DataDir string
    40  }
    41  
    42  // Layer is a single layer of the Layered Vagrant environment.
    43  type Layer struct {
    44  	// ID is a unique ID for the layer. See the note in Layered about
    45  	// generating a new ID for every change/iteration in the Vagrantfile.
    46  	ID string
    47  
    48  	// Vagrantfile is the path to the Vagrantfile to bring up for this
    49  	// layer. The Vagrantfile should handle all provisioning. This
    50  	// Vagrantfile will be copied to another directory, so any paths
    51  	// in it should be relative to the Vagrantfile.
    52  	Vagrantfile string
    53  }
    54  
    55  // Graph will return the full graph that is currently encoded.
    56  func (l *Layered) Graph() (*dag.AcyclicGraph, error) {
    57  	db, err := l.db()
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	defer db.Close()
    62  
    63  	return l.graph(db)
    64  }
    65  
    66  // Build will build all the layers that are defined in this Layered
    67  // struct. It will automatically output to the UI as needed.
    68  //
    69  // This will automatically acquire a process-lock to ensure that no duplicate
    70  // layers are ever built. The process lock usually assumes that Otto is
    71  // being run by the same user.
    72  func (l *Layered) Build(ctx *context.Shared) error {
    73  	// Grab the DB and initialize all the layers. This just inserts a
    74  	// pending layer if it doesn't exist, as well as sets up the edges.
    75  	db, err := l.db()
    76  	if err != nil {
    77  		return err
    78  	}
    79  	vs, err := l.init(db)
    80  	db.Close()
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	// Go through each layer and build it. This will be a no-op if the
    86  	// layer is already built.
    87  	for i, v := range vs {
    88  		var last *layerVertex
    89  		if i > 0 {
    90  			last = vs[i-1]
    91  		}
    92  
    93  		if err := l.buildLayer(v, last, ctx); err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  // Prune will destroy all layers that haven't been used in a certain
   102  // amount of time.
   103  //
   104  // TODO: "certain amount of time" for now we just prune any orphans
   105  func (l *Layered) Prune(ctx *context.Shared) (int, error) {
   106  	db, err := l.db()
   107  	if err != nil {
   108  		return 0, err
   109  	}
   110  	defer db.Close()
   111  
   112  	graph, err := l.graph(db)
   113  	if err != nil {
   114  		return 0, err
   115  	}
   116  
   117  	log.Printf("[DEBUG] vagrant: layer graph: \n%s", graph.String())
   118  
   119  	// Get all the bad roots. These are anything without something depending
   120  	// on it except for the main "root"
   121  	roots := make([]dag.Vertex, 0)
   122  	for _, v := range graph.Vertices() {
   123  		if v == "root" {
   124  			continue
   125  		}
   126  		if graph.UpEdges(v).Len() == 0 {
   127  			roots = append(roots, v)
   128  		}
   129  	}
   130  	if len(roots) == 0 {
   131  		return 0, nil
   132  	}
   133  
   134  	// Go through the remaining roots, these are the environments
   135  	// that must be destroyed.
   136  	count := 0
   137  	for _, root := range roots {
   138  		err := graph.DepthFirstWalk([]dag.Vertex{root},
   139  			func(v dag.Vertex, depth int) error {
   140  				if err := l.pruneLayer(db, v.(*layerVertex), ctx); err != nil {
   141  					return err
   142  				}
   143  
   144  				count++
   145  				return nil
   146  			})
   147  		if err != nil {
   148  			return count, err
   149  		}
   150  	}
   151  
   152  	return count, nil
   153  }
   154  
   155  // ConfigureEnv configures the Vagrant instance with the proper environment
   156  // variables to be able to execute things.
   157  //
   158  // Once the env is used, SetEnvStatus should be used to modify the env
   159  // status around it. This is critical to make sure layers don't get pruned.
   160  func (l *Layered) ConfigureEnv(v *Vagrant) error {
   161  	// Get the final layer
   162  	layer := l.Layers[len(l.Layers)-1]
   163  
   164  	// Get the path for the final layer and add it to the environment
   165  	path := filepath.Join(l.layerPath(layer), "Vagrantfile")
   166  	if v.Env == nil {
   167  		v.Env = make(map[string]string)
   168  	}
   169  	v.Env[layerID] = layer.ID
   170  	v.Env[layerPathEnv] = path
   171  
   172  	return nil
   173  }
   174  
   175  // SetEnv configures the status of an env, persisting that its ready or
   176  // deleted which controls whether layers get pruned or not.
   177  //
   178  // The Vagrant pointer given must already be configured using ConfigureEnv.
   179  func (l *Layered) SetEnv(v *Vagrant, state envState) error {
   180  	// Update the DB with our environment
   181  	db, err := l.db()
   182  	if err != nil {
   183  		return err
   184  	}
   185  	defer db.Close()
   186  	return db.Update(func(tx *bolt.Tx) error {
   187  		bucket := tx.Bucket(boltEnvsBucket)
   188  		key := []byte(v.DataDir)
   189  
   190  		// If the state is deleted then call it good
   191  		if state == envStateDeleted {
   192  			return bucket.Delete(key)
   193  		}
   194  
   195  		// Otherwise we're inserting
   196  		layerId, ok := v.Env[layerID]
   197  		if !ok {
   198  			return fmt.Errorf("Vagrant environment not configured with layer ID.")
   199  		}
   200  
   201  		return bucket.Put(key, []byte(layerId))
   202  	})
   203  }
   204  
   205  // RemoveEnv will remove the environment from the tracked layers.
   206  func (l *Layered) RemoveEnv(v *Vagrant) error {
   207  	db, err := l.db()
   208  	if err != nil {
   209  		return err
   210  	}
   211  	defer db.Close()
   212  
   213  	return db.Update(func(tx *bolt.Tx) error {
   214  		bucket := tx.Bucket(boltEnvsBucket)
   215  		key := []byte(v.DataDir)
   216  		return bucket.Delete(key)
   217  	})
   218  }
   219  
   220  // Pending returns a list of layers that are pending creation.
   221  // Note that between calling this and calling something like Build(),
   222  // this state may be different.
   223  func (l *Layered) Pending() ([]string, error) {
   224  	// Grab the DB and initialize all the layers. This just inserts a
   225  	// pending layer if it doesn't exist, as well as sets up the edges.
   226  	db, err := l.db()
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  	vs, err := l.init(db)
   231  	db.Close()
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  
   236  	result := make([]string, 0, len(vs))
   237  	for _, v := range vs {
   238  		if v.State != layerStateReady {
   239  			result = append(result, v.Layer.ID)
   240  		}
   241  	}
   242  
   243  	return result, nil
   244  }
   245  
   246  func (l *Layered) buildLayer(v *layerVertex, lastV *layerVertex, ctx *context.Shared) error {
   247  	log.Printf("[DEBUG] vagrant: building layer: %s", v.Layer.ID)
   248  
   249  	layer := v.Layer
   250  	path := v.Path
   251  
   252  	// Build the Vagrant instance. We use this a bit later
   253  	vagrant := &Vagrant{
   254  		Dir:     path,
   255  		DataDir: filepath.Join(path, ".vagrant"),
   256  		Ui:      ctx.Ui,
   257  	}
   258  	if lastV != nil {
   259  		vagrant.Env = map[string]string{
   260  			layerPathEnv: filepath.Join(lastV.Path, "Vagrantfile"),
   261  		}
   262  	}
   263  
   264  	// Layer isn't ready, so grab the lock on the layer and build it
   265  	// TODO: multi-process lock
   266  
   267  	// Once we have the lock, we check shortly in the DB if it is already
   268  	// ready. If it is ready, we yield the lock and we're done!
   269  	db, err := l.db()
   270  	if err != nil {
   271  		return err
   272  	}
   273  	layerV, err := l.readLayer(db, layer)
   274  	if err != nil {
   275  		db.Close()
   276  		return err
   277  	}
   278  	if layerV.State == layerStateReady {
   279  		log.Printf("[DEBUG] vagrant: layer already ready, will verify: %s", v.Layer.ID)
   280  
   281  		// Touch the layer so that it is recently used, even if its not
   282  		// actually ready.
   283  		err = l.updateLayer(db, layer, func(v *layerVertex) {
   284  			v.Touch()
   285  		})
   286  		if err != nil {
   287  			db.Close()
   288  			return err
   289  		}
   290  
   291  		// Verify the layer is actually ready! If it isn't, then
   292  		// we have to recreate it.
   293  		ctx.Ui.Header(fmt.Sprintf("Verifying created layer: %s", layer.ID))
   294  		ok, err := l.verifyLayer(vagrant)
   295  		if ok || err != nil {
   296  			// It is ready or there is an error.
   297  			db.Close()
   298  			return err
   299  		}
   300  
   301  		// Layer is invalid! Delete it from the DB and then recreate it
   302  		err = l.updateLayer(db, layer, func(v *layerVertex) {
   303  			v.State = layerStatePending
   304  		})
   305  		if err != nil {
   306  			db.Close()
   307  			return err
   308  		}
   309  
   310  		// Continue!
   311  	}
   312  	db.Close()
   313  
   314  	// Tell the user things are happening
   315  	ctx.Ui.Header(fmt.Sprintf("Creating layer: %s", layer.ID))
   316  
   317  	// Prepare the build directory
   318  	if err := os.MkdirAll(path, 0755); err != nil {
   319  		return err
   320  	}
   321  
   322  	// Copy the Vagrantfile into the destination path
   323  	src, err := os.Open(layer.Vagrantfile)
   324  	if err != nil {
   325  		return err
   326  	}
   327  	dst, err := os.Create(filepath.Join(path, "Vagrantfile"))
   328  	if err == nil {
   329  		_, err = io.Copy(dst, src)
   330  	}
   331  	src.Close()
   332  	dst.Close()
   333  	if err != nil {
   334  		return err
   335  	}
   336  
   337  	// Destroy and recreate the machine
   338  	if err := vagrant.ExecuteSilent("destroy", "-f"); err != nil {
   339  		return err
   340  	}
   341  	if err := vagrant.Execute("up"); err != nil {
   342  		return err
   343  	}
   344  	if err := vagrant.Execute("halt"); err != nil {
   345  		return err
   346  	}
   347  
   348  	// Update the layer state that it is "ready"
   349  	db, err = l.db()
   350  	if err != nil {
   351  		return err
   352  	}
   353  	defer db.Close()
   354  
   355  	return l.updateLayer(db, layer, func(v *layerVertex) {
   356  		v.State = layerStateReady
   357  		v.Touch()
   358  	})
   359  }
   360  
   361  func (l *Layered) pruneLayer(db *bolt.DB, v *layerVertex, ctx *context.Shared) error {
   362  	log.Printf("[DEBUG] vagrant: pruning layer: %s", v.Layer.ID)
   363  
   364  	layer := v.Layer
   365  	path := v.Path
   366  
   367  	// First check if the layer even exists
   368  	exists, err := l.checkLayer(db, layer)
   369  	if err != nil {
   370  		return err
   371  	}
   372  	if !exists {
   373  		log.Printf("[DEBUG] vagrant: layer doesn't exist already: %s", v.Layer.ID)
   374  		return l.deleteLayer(db, layer, path)
   375  	}
   376  
   377  	ctx.Ui.Header(fmt.Sprintf(
   378  		"Deleting layer '%s'...", layer.ID))
   379  
   380  	// First, note that the layer is no longer ready
   381  	err = l.updateLayer(db, layer, func(v *layerVertex) {
   382  		v.State = layerStatePending
   383  	})
   384  	if err != nil {
   385  		return err
   386  	}
   387  
   388  	// Check the path. If the path doesn't exist, then it is already destroyed.
   389  	// If the path does exist, then we do an actual vagrant destroy
   390  	_, err = os.Stat(path)
   391  	if err != nil && !os.IsNotExist(err) {
   392  		return err
   393  	}
   394  	if err == nil {
   395  		vagrant := &Vagrant{
   396  			Dir:     path,
   397  			DataDir: filepath.Join(path, ".vagrant"),
   398  			Ui:      ctx.Ui,
   399  		}
   400  		if err := vagrant.Execute("destroy", "-f"); err != nil {
   401  			return err
   402  		}
   403  	}
   404  
   405  	// Delete the layer
   406  	return l.deleteLayer(db, layer, path)
   407  }
   408  
   409  func (l *Layered) layerPath(layer *Layer) string {
   410  	return filepath.Join(l.DataDir, "layers", layer.ID)
   411  }
   412  
   413  // db returns the database handle, and sets up the DB if it has never been created.
   414  func (l *Layered) db() (*bolt.DB, error) {
   415  	// Make the directory to store our DB
   416  	if err := os.MkdirAll(l.DataDir, 0755); err != nil {
   417  		return nil, err
   418  	}
   419  
   420  	// Create/Open the DB
   421  	db, err := bolt.Open(filepath.Join(l.DataDir, "vagrant-layered.db"), 0644, nil)
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  
   426  	// Create the buckets
   427  	err = db.Update(func(tx *bolt.Tx) error {
   428  		for _, b := range boltBuckets {
   429  			if _, err := tx.CreateBucketIfNotExists(b); err != nil {
   430  				return err
   431  			}
   432  		}
   433  
   434  		return nil
   435  	})
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  
   440  	// Check the data version
   441  	var version byte
   442  	err = db.Update(func(tx *bolt.Tx) error {
   443  		bucket := tx.Bucket(boltVagrantBucket)
   444  		data := bucket.Get([]byte("version"))
   445  		if data == nil || len(data) == 0 {
   446  			version = boltDataVersion
   447  			return bucket.Put([]byte("version"), []byte{boltDataVersion})
   448  		}
   449  
   450  		version = data[0]
   451  		return nil
   452  	})
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	if version > boltDataVersion {
   458  		return nil, fmt.Errorf(
   459  			"Vagrant layer data version is higher than this version of Otto knows how\n"+
   460  				"to handle! This version of Otto can read up to version %d,\n"+
   461  				"but version %d data file found.\n\n"+
   462  				"This means that a newer version of Otto touched this data,\n"+
   463  				"or the data was corrupted in some other way.",
   464  			boltDataVersion, version)
   465  	}
   466  
   467  	return db, nil
   468  }
   469  
   470  // verifyLayer verifies that a layer is valid/ready.
   471  func (l *Layered) verifyLayer(v *Vagrant) (bool, error) {
   472  	// The callback for checking the state
   473  	var ok bool
   474  	cb := func(o *Output) {
   475  		if o.Type == "state" && len(o.Data) > 0 {
   476  			ok = o.Data[0] != "not_created"
   477  		}
   478  	}
   479  
   480  	// Save the old callbacks
   481  	oldCb := v.Callbacks
   482  	defer func() { v.Callbacks = oldCb }()
   483  
   484  	// Register a callback for the state
   485  	v.Callbacks = map[string]OutputCallback{"state": cb}
   486  
   487  	// Check it
   488  	err := v.ExecuteSilent("status")
   489  	return ok, err
   490  }
   491  
   492  // init initializes the database for this layer setup.
   493  func (l *Layered) init(db *bolt.DB) ([]*layerVertex, error) {
   494  	layerVertices := make([]*layerVertex, len(l.Layers))
   495  	for i, layer := range l.Layers {
   496  		var parent *Layer
   497  		if i > 0 {
   498  			parent = l.Layers[i-1]
   499  		}
   500  
   501  		layerVertex, err := l.initLayer(db, layer, parent)
   502  		if err != nil {
   503  			return nil, err
   504  		}
   505  
   506  		layerVertices[i] = layerVertex
   507  		if parent != nil {
   508  			// We have a prior layer, so setup the edge pointer
   509  			err = db.Update(func(tx *bolt.Tx) error {
   510  				bucket := tx.Bucket(boltEdgesBucket)
   511  				return bucket.Put(
   512  					[]byte(layer.ID),
   513  					[]byte(parent.ID))
   514  			})
   515  			if err != nil {
   516  				return nil, err
   517  			}
   518  		}
   519  	}
   520  
   521  	return layerVertices, nil
   522  }
   523  
   524  // initLayer sets up the layer in the database
   525  func (l *Layered) initLayer(db *bolt.DB, layer *Layer, parent *Layer) (*layerVertex, error) {
   526  	var parentID string
   527  	if parent != nil {
   528  		parentID = parent.ID
   529  	}
   530  
   531  	var result layerVertex
   532  	err := db.Update(func(tx *bolt.Tx) error {
   533  		bucket := tx.Bucket(boltLayersBucket)
   534  		key := []byte(layer.ID)
   535  		data := bucket.Get(key)
   536  		if len(data) > 0 {
   537  			var v layerVertex
   538  			if err := l.structRead(&v, data); err != nil {
   539  				return err
   540  			}
   541  
   542  			if v.Parent == parentID {
   543  				result = v
   544  				return nil
   545  			}
   546  
   547  			// The parent didn't match, so we just initialize a new
   548  			// entry below. This will also force the destruction of the
   549  			// old environment.
   550  		}
   551  
   552  		// Vertex doesn't exist. Create it and save it
   553  		result = layerVertex{
   554  			Layer:  layer,
   555  			State:  layerStatePending,
   556  			Parent: parentID,
   557  			Path:   l.layerPath(layer),
   558  		}
   559  		data, err := l.structData(&result)
   560  		if err != nil {
   561  			return err
   562  		}
   563  
   564  		// Write the pending layer
   565  		return bucket.Put(key, data)
   566  	})
   567  
   568  	return &result, err
   569  }
   570  
   571  func (l *Layered) checkLayer(db *bolt.DB, layer *Layer) (bool, error) {
   572  	var result bool
   573  	err := db.View(func(tx *bolt.Tx) error {
   574  		bucket := tx.Bucket(boltLayersBucket)
   575  		key := []byte(layer.ID)
   576  		data := bucket.Get(key)
   577  		result = len(data) > 0
   578  		return nil
   579  	})
   580  
   581  	return result, err
   582  }
   583  
   584  func (l *Layered) readLayer(db *bolt.DB, layer *Layer) (*layerVertex, error) {
   585  	var result layerVertex
   586  	err := db.View(func(tx *bolt.Tx) error {
   587  		bucket := tx.Bucket(boltLayersBucket)
   588  		key := []byte(layer.ID)
   589  		data := bucket.Get(key)
   590  		if len(data) > 0 {
   591  			return l.structRead(&result, data)
   592  		}
   593  
   594  		return fmt.Errorf("layer %s not found", layer.ID)
   595  	})
   596  
   597  	return &result, err
   598  }
   599  
   600  func (l *Layered) updateLayer(db *bolt.DB, layer *Layer, f func(*layerVertex)) error {
   601  	return db.Update(func(tx *bolt.Tx) error {
   602  		bucket := tx.Bucket(boltLayersBucket)
   603  		key := []byte(layer.ID)
   604  		data := bucket.Get(key)
   605  		if len(data) == 0 {
   606  			// This should never happen through this struct
   607  			panic(fmt.Errorf("layer %s not found", layer.ID))
   608  		}
   609  
   610  		// Read the vertex, call the function to modify it
   611  		var v layerVertex
   612  		if err := l.structRead(&v, data); err != nil {
   613  			return err
   614  		}
   615  		f(&v)
   616  
   617  		// Save the resulting layer data
   618  		data, err := l.structData(&v)
   619  		if err != nil {
   620  			return err
   621  		}
   622  		return bucket.Put(key, data)
   623  	})
   624  }
   625  
   626  func (l *Layered) deleteLayer(db *bolt.DB, layer *Layer, path string) error {
   627  	if err := os.RemoveAll(path); err != nil {
   628  		return err
   629  	}
   630  
   631  	return db.Update(func(tx *bolt.Tx) error {
   632  		// Delete the layer itself
   633  		bucket := tx.Bucket(boltLayersBucket)
   634  		key := []byte(layer.ID)
   635  		if err := bucket.Delete(key); err != nil {
   636  			return err
   637  		}
   638  
   639  		// Delete all the edges
   640  		bucket = tx.Bucket(boltEdgesBucket)
   641  		if err := bucket.Delete(key); err != nil {
   642  			return err
   643  		}
   644  
   645  		// Find any values
   646  		return bucket.ForEach(func(k, data []byte) error {
   647  			if string(data) == layer.ID {
   648  				return bucket.Delete(k)
   649  			}
   650  
   651  			return nil
   652  		})
   653  	})
   654  }
   655  
   656  func (l *Layered) graph(db *bolt.DB) (*dag.AcyclicGraph, error) {
   657  	graph := new(dag.AcyclicGraph)
   658  	graph.Add("root")
   659  
   660  	// First, add all the layers
   661  	layers := make(map[string]*layerVertex)
   662  	err := db.View(func(tx *bolt.Tx) error {
   663  		bucket := tx.Bucket(boltLayersBucket)
   664  		return bucket.ForEach(func(k, data []byte) error {
   665  			var v layerVertex
   666  			if err := l.structRead(&v, data); err != nil {
   667  				return err
   668  			}
   669  
   670  			// Add this layer to the graph
   671  			graph.Add(&v)
   672  
   673  			// Store the mapping for later
   674  			layers[v.Layer.ID] = &v
   675  			return nil
   676  		})
   677  	})
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  
   682  	// Next, connect the layers
   683  	err = db.View(func(tx *bolt.Tx) error {
   684  		bucket := tx.Bucket(boltEdgesBucket)
   685  		return bucket.ForEach(func(k, data []byte) error {
   686  			from := layers[string(k)]
   687  			to := layers[string(data)]
   688  			if from != nil && to != nil {
   689  				graph.Connect(dag.BasicEdge(from, to))
   690  			}
   691  
   692  			return nil
   693  		})
   694  	})
   695  	if err != nil {
   696  		return nil, err
   697  	}
   698  
   699  	// Finally, add and connect all the envs
   700  	err = db.View(func(tx *bolt.Tx) error {
   701  		bucket := tx.Bucket(boltEnvsBucket)
   702  		return bucket.ForEach(func(k, data []byte) error {
   703  			key := fmt.Sprintf("env-%s", string(k))
   704  			graph.Add(key)
   705  
   706  			// Connect the env to the layer it depends on
   707  			to := &layerVertex{Layer: &Layer{ID: string(data)}}
   708  			graph.Connect(dag.BasicEdge(key, to))
   709  
   710  			// Connect the root to the environment that is active
   711  			graph.Connect(dag.BasicEdge("root", key))
   712  			return nil
   713  		})
   714  	})
   715  	if err != nil {
   716  		return nil, err
   717  	}
   718  
   719  	return graph, nil
   720  }
   721  
   722  func (l *Layered) structData(d interface{}) ([]byte, error) {
   723  	// Let's just output it in human-readable format to make it easy
   724  	// for debugging. Disk space won't matter that much for this data.
   725  	return json.MarshalIndent(d, "", "\t")
   726  }
   727  
   728  func (l *Layered) structRead(d interface{}, raw []byte) error {
   729  	dec := json.NewDecoder(bytes.NewReader(raw))
   730  	return dec.Decode(d)
   731  }
   732  
   733  var (
   734  	boltVagrantBucket = []byte("vagrant")
   735  	boltLayersBucket  = []byte("layers")
   736  	boltEdgesBucket   = []byte("edges")
   737  	boltEnvsBucket    = []byte("envs")
   738  	boltBuckets       = [][]byte{
   739  		boltVagrantBucket,
   740  		boltLayersBucket,
   741  		boltEdgesBucket,
   742  		boltEnvsBucket,
   743  	}
   744  )
   745  
   746  var (
   747  	boltDataVersion byte = 1
   748  )
   749  
   750  const (
   751  	// layerPathEnv is the path to the previous layer
   752  	layerPathEnv = "OTTO_VAGRANT_LAYER_PATH"
   753  
   754  	// layerID is the ID of the previous layer
   755  	layerID = "OTTO_VAGRANT_LAYER_ID"
   756  )
   757  
   758  // layerVertex is the type of vertex in the graph that is used to track
   759  // layer usage throughout Otto.
   760  type layerVertex struct {
   761  	Layer    *Layer     `json:"layer"`
   762  	State    layerState `json:"state"`
   763  	Parent   string     `json:"parent"`
   764  	Path     string     `json:"path"`
   765  	LastUsed time.Time  `json:"last_used"`
   766  }
   767  
   768  func (v *layerVertex) Hashcode() interface{} {
   769  	return fmt.Sprintf("layer-%s", v.Layer.ID)
   770  }
   771  
   772  func (v *layerVertex) Name() string {
   773  	return v.Layer.ID
   774  }
   775  
   776  // Touch is used to update the last used time
   777  func (v *layerVertex) Touch() {
   778  	v.LastUsed = time.Now().UTC()
   779  }
   780  
   781  type layerState byte
   782  
   783  const (
   784  	layerStateInvalid layerState = iota
   785  	layerStatePending
   786  	layerStateReady
   787  )
   788  
   789  type envState byte
   790  
   791  const (
   792  	envStateInvalid envState = iota
   793  	envStateDeleted
   794  	envStateReady
   795  )