diff --git a/.travis.yml b/.travis.yml index fe01e42b5a..763bd64fc5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ go: - 1.7 dist: trusty sudo: required +env: + - TAGS='exclude_graphdriver_ostree' before_install: - sudo apt-get -qq update - sudo apt-get -qq install btrfs-tools libdevmapper-dev script: - make install.tools - make local-binary docs local-cross local-validate - - sudo PATH="$PATH" make local-test-unit local-test-integration + - sudo -E PATH="$PATH" make local-test-unit local-test-integration diff --git a/drivers/driver_linux.go b/drivers/driver_linux.go index 94f7270eae..46d8eb4810 100644 --- a/drivers/driver_linux.go +++ b/drivers/driver_linux.go @@ -59,6 +59,7 @@ var ( "btrfs", "zfs", "vfs", + "ostree", } // FsNames maps filesystem id to name of the filesystem. diff --git a/drivers/ostree/driver.go b/drivers/ostree/driver.go new file mode 100644 index 0000000000..54f1057806 --- /dev/null +++ b/drivers/ostree/driver.go @@ -0,0 +1,182 @@ +// +build !exclude_graphdriver_ostree + +package ostree + +import ( + "fmt" + "os" + "os/exec" + "strings" + "time" + + "github.com/containers/storage/drivers" + "github.com/containers/storage/drivers/overlay" + "github.com/containers/storage/pkg/idtools" + "github.com/containers/storage/pkg/system" + "github.com/ostreedev/ostree-go/pkg/otbuiltin" +) + +func init() { + graphdriver.Register("ostree", Init) +} + +// Init returns a new OSTREE driver. +// This sets the home directory for the driver and returns NaiveDiffDriver. +func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { + overlay, err := overlay.Init(home, options, uidMaps, gidMaps) + if err != nil { + return nil, err + } + + repoLocation := fmt.Sprintf("%s/.repo", home) + for _, option := range options { + if strings.HasPrefix(option, "ostree.repo=") { + repoLocation = option[12:] + } + } + + _, err = os.Stat(repoLocation) + if err != nil { + idMappings := idtools.NewIDMappingsFromMaps(uidMaps, gidMaps) + rootIDs := idMappings.RootPair() + if err := idtools.MkdirAllAndChown(repoLocation, 0700, rootIDs); err != nil { + return nil, err + } + err := exec.Command("ostree", fmt.Sprintf("--repo=%s", repoLocation), "init").Run() + if err != nil { + return nil, err + } + } + + repo, err := otbuiltin.OpenRepo(repoLocation) + if err != nil { + return nil, err + } + + d := &Driver{ + home: home, + overlay: overlay, + convert: make(map[string]bool), + } + d.repo = repo + d.repoLocation = repoLocation + return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil +} + +// Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver +type Driver struct { + home string + overlay graphdriver.Driver + repo *otbuiltin.Repo + repoLocation string + convert map[string]bool +} + +func (d *Driver) String() string { + return "ostree" +} + +// Status is used for implementing the graphdriver.ProtoDriver interface. OSTREE does not currently have any status information. +func (d *Driver) Status() [][2]string { + return d.overlay.Status() +} + +// Metadata is used for implementing the graphdriver.ProtoDriver interface. OSTREE does not currently have any meta data. +func (d *Driver) Metadata(id string) (map[string]string, error) { + return d.overlay.Metadata(id) +} + +// Cleanup is used to implement graphdriver.ProtoDriver. There is no cleanup required for this driver. +func (d *Driver) Cleanup() error { + return d.overlay.Cleanup() +} + +// CreateReadWrite creates a layer that is writable for use as a container +// file system. +func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { + return d.overlay.CreateReadWrite(id, parent, opts) +} + +// Create prepares the filesystem for the OSTREE driver and copies the directory for the given id under the parent. +func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { + d.convert[id] = true + return d.overlay.Create(id, parent, opts) +} + +func getDir(home, id string) string { + return fmt.Sprintf("%s/%s/diff", home, id) +} + +// Create prepares the filesystem for the OSTREE driver and copies the directory for the given id under the parent. +func (d *Driver) convertToOSTree(root, id string) error { + _, err := d.repo.PrepareTransaction() + if err != nil { + return err + } + + commitOpts := otbuiltin.NewCommitOptions() + commitOpts.Timestamp = time.Now() + commitOpts.Parent = "0000000000000000000000000000000000000000000000000000000000000000" + branch := fmt.Sprintf("ocilayer/%s", id) + + _, err = d.repo.Commit(root, branch, commitOpts) + if err != nil { + return err + } + + _, err = d.repo.CommitTransaction() + if err != nil { + return err + } + + err = system.EnsureRemoveAll(root) + if err != nil { + return err + } + + checkoutOpts := otbuiltin.NewCheckoutOptions() + err = otbuiltin.Checkout(d.repoLocation, root, branch, checkoutOpts) + if err != nil { + return err + } + return nil +} + +// Remove deletes the content from the directory for a given id. +func (d *Driver) Remove(id string) error { + opts := otbuiltin.NewPruneOptions() + branch := fmt.Sprintf("ocilayer/%s", id) + opts.DeleteCommit = branch + _, err := otbuiltin.Prune(d.repoLocation, opts) + return err +} + +// Get returns the directory for the given id. +func (d *Driver) Get(id, mountLabel string) (string, error) { + path, err := d.overlay.Get(id, mountLabel) + return path, err +} + +func (d *Driver) Put(id string) error { + root := getDir(d.home, id) + + _, convert := d.convert[id] + if convert { + err := d.convertToOSTree(root, id) + if err != nil { + return err + } + } + + return d.overlay.Put(id) +} + +// Exists checks to see if the directory exists for the given id. +func (d *Driver) Exists(id string) bool { + return d.overlay.Exists(id) +} + +// AdditionalImageStores returns additional image stores supported by the driver +func (d *Driver) AdditionalImageStores() []string { + return d.overlay.AdditionalImageStores() +} diff --git a/drivers/ostree/driver_stub.go b/drivers/ostree/driver_stub.go new file mode 100644 index 0000000000..6e9f53c77a --- /dev/null +++ b/drivers/ostree/driver_stub.go @@ -0,0 +1,18 @@ +// +build exclude_graphdriver_ostree + +package ostree + +import ( + "fmt" + + "github.com/containers/storage/drivers" + "github.com/containers/storage/pkg/idtools" +) + +func init() { + graphdriver.Register("ostree", Init) +} + +func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { + return nil, fmt.Errorf("ostree driver not supported") +}