Skip to content

Commit

Permalink
Merge pull request #1826 from giuseppe/put-partial-layers
Browse files Browse the repository at this point in the history
store: new API ApplyStagedLayer
  • Loading branch information
openshift-merge-bot[bot] authored Feb 16, 2024
2 parents 8a099ec + d36d6c1 commit 6f63bc4
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 16 deletions.
4 changes: 2 additions & 2 deletions drivers/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ type DriverWithDiffer interface {
// ApplyDiffWithDiffer applies the changes using the callback function.
// If id is empty, then a staging directory is created. The staging directory is guaranteed to be usable with ApplyDiffFromStagingDirectory.
ApplyDiffWithDiffer(id, parent string, options *ApplyDiffWithDifferOpts, differ Differ) (output DriverWithDifferOutput, err error)
// ApplyDiffFromStagingDirectory applies the changes using the specified staging directory.
ApplyDiffFromStagingDirectory(id, parent, stagingDirectory string, diffOutput *DriverWithDifferOutput, options *ApplyDiffWithDifferOpts) error
// ApplyDiffFromStagingDirectory applies the changes using the diffOutput target directory.
ApplyDiffFromStagingDirectory(id, parent string, diffOutput *DriverWithDifferOutput, options *ApplyDiffWithDifferOpts) error
// CleanupStagingDirectory cleanups the staging directory. It can be used to cleanup the staging directory on errors
CleanupStagingDirectory(stagingDirectory string) error
// DifferTarget gets the location where files are stored for the layer.
Expand Down
3 changes: 2 additions & 1 deletion drivers/overlay/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -2124,7 +2124,8 @@ func (d *Driver) ApplyDiffWithDiffer(id, parent string, options *graphdriver.App
}

// ApplyDiffFromStagingDirectory applies the changes using the specified staging directory.
func (d *Driver) ApplyDiffFromStagingDirectory(id, parent, stagingDirectory string, diffOutput *graphdriver.DriverWithDifferOutput, options *graphdriver.ApplyDiffWithDifferOpts) error {
func (d *Driver) ApplyDiffFromStagingDirectory(id, parent string, diffOutput *graphdriver.DriverWithDifferOutput, options *graphdriver.ApplyDiffWithDifferOpts) error {
stagingDirectory := diffOutput.Target
if filepath.Dir(stagingDirectory) != d.getStagingDir() {
return fmt.Errorf("%q is not a staging directory", stagingDirectory)
}
Expand Down
24 changes: 18 additions & 6 deletions layers.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ type DiffOptions struct {
Compression *archive.Compression
}

// stagedLayerOptions are the options passed to .create to populate a staged
// layer
type stagedLayerOptions struct {
DiffOutput *drivers.DriverWithDifferOutput
DiffOptions *drivers.ApplyDiffWithDifferOpts
}

// roLayerStore wraps a graph driver, adding the ability to refer to layers by
// name, and keeping track of parent-child relationships, along with a list of
// all known layers.
Expand Down Expand Up @@ -267,7 +274,7 @@ type rwLayerStore interface {
// underlying drivers do not themselves distinguish between writeable
// and read-only layers. Returns the new layer structure and the size of the
// diff which was applied to its parent to initialize its contents.
create(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, diff io.Reader) (*Layer, int64, error)
create(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, diff io.Reader, slo *stagedLayerOptions) (*Layer, int64, error)

// updateNames modifies names associated with a layer based on (op, names).
updateNames(id string, names []string, op updateNameOperation) error
Expand Down Expand Up @@ -312,8 +319,8 @@ type rwLayerStore interface {
// CleanupStagingDirectory cleanups the staging directory. It can be used to cleanup the staging directory on errors
CleanupStagingDirectory(stagingDirectory string) error

// ApplyDiffFromStagingDirectory uses stagingDirectory to create the diff.
ApplyDiffFromStagingDirectory(id, stagingDirectory string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffWithDifferOpts) error
// applyDiffFromStagingDirectory uses diffOutput.Target to create the diff.
applyDiffFromStagingDirectory(id string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffWithDifferOpts) error

// DifferTarget gets the location where files are stored for the layer.
DifferTarget(id string) (string, error)
Expand Down Expand Up @@ -1232,7 +1239,7 @@ func (r *layerStore) PutAdditionalLayer(id string, parentLayer *Layer, names []s
}

// Requires startWriting.
func (r *layerStore) create(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, diff io.Reader) (layer *Layer, size int64, err error) {
func (r *layerStore) create(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, diff io.Reader, slo *stagedLayerOptions) (layer *Layer, size int64, err error) {
if moreOptions == nil {
moreOptions = &LayerOptions{}
}
Expand Down Expand Up @@ -1426,6 +1433,11 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
cleanupFailureContext = "applying layer diff"
return nil, -1, err
}
} else if slo != nil {
if err := r.applyDiffFromStagingDirectory(layer.ID, slo.DiffOutput, slo.DiffOptions); err != nil {
cleanupFailureContext = "applying staged directory diff"
return nil, -1, err
}
} else {
// applyDiffWithOptions() would have updated r.bycompressedsum
// and r.byuncompressedsum for us, but if we used a template
Expand Down Expand Up @@ -2414,7 +2426,7 @@ func (r *layerStore) DifferTarget(id string) (string, error) {
}

// Requires startWriting.
func (r *layerStore) ApplyDiffFromStagingDirectory(id, stagingDirectory string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffWithDifferOpts) error {
func (r *layerStore) applyDiffFromStagingDirectory(id string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffWithDifferOpts) error {
ddriver, ok := r.driver.(drivers.DriverWithDiffer)
if !ok {
return ErrNotSupported
Expand All @@ -2433,7 +2445,7 @@ func (r *layerStore) ApplyDiffFromStagingDirectory(id, stagingDirectory string,
}
}

err := ddriver.ApplyDiffFromStagingDirectory(layer.ID, layer.Parent, stagingDirectory, diffOutput, options)
err := ddriver.ApplyDiffFromStagingDirectory(layer.ID, layer.Parent, diffOutput, options)
if err != nil {
return err
}
Expand Down
60 changes: 54 additions & 6 deletions store.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ type metadataStore interface {
rwMetadataStore
}

// ApplyStagedLayerOptions contains options to pass to ApplyStagedLayer
type ApplyStagedLayerOptions struct {
ID string // Mandatory
ParentLayer string // Optional
Names []string // Optional
MountLabel string // Optional
Writeable bool // Optional
LayerOptions *LayerOptions // Optional

DiffOutput *drivers.DriverWithDifferOutput // Mandatory
DiffOptions *drivers.ApplyDiffWithDifferOpts // Mandatory
}

// An roBigDataStore wraps up the read-only big-data related methods of the
// various types of file-based lookaside stores that we implement.
type roBigDataStore interface {
Expand Down Expand Up @@ -318,11 +331,21 @@ type Store interface {
ApplyDiffWithDiffer(to string, options *drivers.ApplyDiffWithDifferOpts, differ drivers.Differ) (*drivers.DriverWithDifferOutput, error)

// ApplyDiffFromStagingDirectory uses stagingDirectory to create the diff.
// Deprecated: it will be removed soon. Use ApplyStagedLayer instead.
ApplyDiffFromStagingDirectory(to, stagingDirectory string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffWithDifferOpts) error

// CleanupStagingDirectory cleanups the staging directory. It can be used to cleanup the staging directory on errors
// Deprecated: it will be removed soon. Use CleanupStagedLayer instead.
CleanupStagingDirectory(stagingDirectory string) error

// ApplyStagedLayer combines the functions of CreateLayer and ApplyDiffFromStagingDirectory,
// marking the layer for automatic removal if applying the diff fails
// for any reason.
ApplyStagedLayer(args ApplyStagedLayerOptions) (*Layer, error)

// CleanupStagedLayer cleanups the staging directory. It can be used to cleanup the staging directory on errors
CleanupStagedLayer(diffOutput *drivers.DriverWithDifferOutput) error

// DifferTarget gets the path to the differ target.
DifferTarget(id string) (string, error)

Expand Down Expand Up @@ -1421,8 +1444,7 @@ func (s *store) canUseShifting(uidmap, gidmap []idtools.IDMap) bool {
return true
}

func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader) (*Layer, int64, error) {
var parentLayer *Layer
func (s *store) putLayer(id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader, slo *stagedLayerOptions) (*Layer, int64, error) {
rlstore, rlstores, err := s.bothLayerStoreKinds()
if err != nil {
return nil, -1, err
Expand All @@ -1435,6 +1457,8 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
return nil, -1, err
}
defer s.containerStore.stopWriting()

var parentLayer *Layer
var options LayerOptions
if lOptions != nil {
options = *lOptions
Expand Down Expand Up @@ -1508,7 +1532,11 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
GIDMap: copyIDMap(gidMap),
}
}
return rlstore.create(id, parentLayer, names, mountLabel, nil, &layerOptions, writeable, diff)
return rlstore.create(id, parentLayer, names, mountLabel, nil, &layerOptions, writeable, diff, slo)
}

func (s *store) PutLayer(id, parent string, names []string, mountLabel string, writeable bool, lOptions *LayerOptions, diff io.Reader) (*Layer, int64, error) {
return s.putLayer(id, parent, names, mountLabel, writeable, lOptions, diff, nil)
}

func (s *store) CreateLayer(id, parent string, names []string, mountLabel string, writeable bool, options *LayerOptions) (*Layer, error) {
Expand Down Expand Up @@ -1718,7 +1746,7 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore roImageStore, rlst
}
}
layerOptions.TemplateLayer = layer.ID
mappedLayer, _, err := rlstore.create("", parentLayer, nil, layer.MountLabel, nil, &layerOptions, false, nil)
mappedLayer, _, err := rlstore.create("", parentLayer, nil, layer.MountLabel, nil, &layerOptions, false, nil, nil)
if err != nil {
return nil, fmt.Errorf("creating an ID-mapped copy of layer %q: %w", layer.ID, err)
}
Expand Down Expand Up @@ -1889,7 +1917,7 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
options.Flags[mountLabelFlag] = mountLabel
}

clayer, _, err := rlstore.create(layer, imageTopLayer, nil, mlabel, options.StorageOpt, layerOptions, true, nil)
clayer, _, err := rlstore.create(layer, imageTopLayer, nil, mlabel, options.StorageOpt, layerOptions, true, nil, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2954,22 +2982,42 @@ func (s *store) Diff(from, to string, options *DiffOptions) (io.ReadCloser, erro
}

func (s *store) ApplyDiffFromStagingDirectory(to, stagingDirectory string, diffOutput *drivers.DriverWithDifferOutput, options *drivers.ApplyDiffWithDifferOpts) error {
if stagingDirectory != diffOutput.Target {
return fmt.Errorf("invalid value for staging directory, it must be the same as the differ target directory")
}
_, err := writeToLayerStore(s, func(rlstore rwLayerStore) (struct{}, error) {
if !rlstore.Exists(to) {
return struct{}{}, ErrLayerUnknown
}
return struct{}{}, rlstore.ApplyDiffFromStagingDirectory(to, stagingDirectory, diffOutput, options)
return struct{}{}, rlstore.applyDiffFromStagingDirectory(to, diffOutput, options)
})
return err
}

func (s *store) ApplyStagedLayer(args ApplyStagedLayerOptions) (*Layer, error) {
slo := stagedLayerOptions{
DiffOutput: args.DiffOutput,
DiffOptions: args.DiffOptions,
}

layer, _, err := s.putLayer(args.ID, args.ParentLayer, args.Names, args.MountLabel, args.Writeable, args.LayerOptions, nil, &slo)
return layer, err
}

func (s *store) CleanupStagingDirectory(stagingDirectory string) error {
_, err := writeToLayerStore(s, func(rlstore rwLayerStore) (struct{}, error) {
return struct{}{}, rlstore.CleanupStagingDirectory(stagingDirectory)
})
return err
}

func (s *store) CleanupStagedLayer(diffOutput *drivers.DriverWithDifferOutput) error {
_, err := writeToLayerStore(s, func(rlstore rwLayerStore) (struct{}, error) {
return struct{}{}, rlstore.CleanupStagingDirectory(diffOutput.Target)
})
return err
}

func (s *store) ApplyDiffWithDiffer(to string, options *drivers.ApplyDiffWithDifferOpts, differ drivers.Differ) (*drivers.DriverWithDifferOutput, error) {
return writeToLayerStore(s, func(rlstore rwLayerStore) (*drivers.DriverWithDifferOutput, error) {
if to != "" && !rlstore.Exists(to) {
Expand Down
2 changes: 1 addition & 1 deletion userns.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ outer:

// We need to create a temporary layer so we can mount it and lookup the
// maximum IDs used.
clayer, _, err := rlstore.create("", topLayer, nil, "", nil, layerOptions, false, nil)
clayer, _, err := rlstore.create("", topLayer, nil, "", nil, layerOptions, false, nil, nil)
if err != nil {
return 0, err
}
Expand Down

0 comments on commit 6f63bc4

Please sign in to comment.