From daaf5f9d88e3e554ffc51c0cfb76677ac961beeb Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 3 Nov 2017 16:52:17 +0100 Subject: [PATCH] ostree: new storage Skopeo needs a bugfix from: https://github.com/containers/image/pull/305 which is not merged yet. Just apply this patch: diff --git a/vendor/github.com/containers/image/storage/storage_image.go b/vendor/github.com/containers/image/storage/storage_image.go index 08fa71b..5edccce 100644 --- a/vendor/github.com/containers/image/storage/storage_image.go +++ b/vendor/github.com/containers/image/storage/storage_image.go @@ -174,7 +174,7 @@ func (s *storageImageDestination) putBlob(stream io.Reader, blobinfo types.BlobI id = ddigest.Canonical.FromBytes([]byte(parentLayer + "+" + digest.String())).Hex() } // Attempt to create the identified layer and import its contents. - layer, uncompressedSize, err := s.imageRef.transport.store.PutLayer(id, parentLayer, nil, "", true, multi) + layer, uncompressedSize, err := s.imageRef.transport.store.PutLayer(id, parentLayer, nil, "", false, multi) if err != nil && errors.Cause(err) != storage.ErrDuplicateID { logrus.Debugf("error importing layer blob %q as %q: %v", blobinfo.Digest, id, err) return errorBlobInfo, err Signed-off-by: Giuseppe Scrivano --- .travis.yml | 4 +- drivers/driver_linux.go | 1 + drivers/ostree/driver.go | 178 ++++++++++++++++++++++++++++ drivers/ostree/driver_stub.go | 18 +++ drivers/register/register_ostree.go | 8 ++ 5 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 drivers/ostree/driver.go create mode 100644 drivers/ostree/driver_stub.go create mode 100644 drivers/register/register_ostree.go 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..71bc3e49ff --- /dev/null +++ b/drivers/ostree/driver.go @@ -0,0 +1,178 @@ +// +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 && !os.IsNotExist(err) { + return nil, err + } else if err != nil { + idMappings := idtools.NewIDMappingsFromMaps(uidMaps, gidMaps) + rootIDs := idMappings.RootPair() + if err := idtools.MkdirAllAndChown(repoLocation, 0700, rootIDs); err != nil { + return nil, fmt.Errorf("Could not create OSTree repository directory: %v", err) + } + + if err := exec.Command("ostree", fmt.Sprintf("--repo=%s", repoLocation), "init").Run(); err != nil { + return nil, fmt.Errorf("Could not create OSTree repository: %v", err) + } + } + + repo, err := otbuiltin.OpenRepo(repoLocation) + if err != nil { + return nil, fmt.Errorf("Could not open the OSTree repository: %v", 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 { + if _, err := d.repo.PrepareTransaction(); err != nil { + return fmt.Errorf("Could not prepare the OSTree transaction: %v", err) + } + + commitOpts := otbuiltin.NewCommitOptions() + commitOpts.Timestamp = time.Now() + commitOpts.Parent = "0000000000000000000000000000000000000000000000000000000000000000" + branch := fmt.Sprintf("ocilayer/%s", id) + + if _, err := d.repo.Commit(root, branch, commitOpts); err != nil { + return fmt.Errorf("Could not commit the layer: %v", err) + } + + if _, err := d.repo.CommitTransaction(); err != nil { + return fmt.Errorf("Could not complete the OSTree transaction: %v", err) + } + + if err := system.EnsureRemoveAll(root); err != nil { + return err + } + + checkoutOpts := otbuiltin.NewCheckoutOptions() + if err := otbuiltin.Checkout(d.repoLocation, root, branch, checkoutOpts); err != nil { + return fmt.Errorf("Could not checkout from OSTree: %v", err) + } + return nil +} + +// Remove deletes the content from the directory for a given id. +func (d *Driver) Remove(id string) error { + branch := fmt.Sprintf("ocilayer/%s", id) + if err := exec.Command("ostree", fmt.Sprintf("--repo=%s", d.repoLocation), "refs", "--delete", branch).Run(); err != nil { + return fmt.Errorf("Could not delete OSTree branch: %v", err) + } + return nil +} + +// 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 { + if err := d.convertToOSTree(root, id); 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") +} diff --git a/drivers/register/register_ostree.go b/drivers/register/register_ostree.go new file mode 100644 index 0000000000..94e2c5a2a3 --- /dev/null +++ b/drivers/register/register_ostree.go @@ -0,0 +1,8 @@ +// +build !exclude_graphdriver_ostree + +package register + +import ( + // register the ostree graphdriver + _ "github.com/containers/storage/drivers/ostree" +)