| 111 | } |
| 112 | |
| 113 | func applyLayers(ctx context.Context, layers []Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts []snapshots.Opt, applyOpts []diff.ApplyOpt) error { |
| 114 | var ( |
| 115 | parent = identity.ChainID(chain[:len(chain)-1]) |
| 116 | chainID = identity.ChainID(chain) |
| 117 | layer = layers[len(layers)-1] |
| 118 | diff ocispec.Descriptor |
| 119 | key string |
| 120 | mounts []mount.Mount |
| 121 | err error |
| 122 | ) |
| 123 | |
| 124 | for { |
| 125 | key = fmt.Sprintf(snapshots.UnpackKeyFormat, uniquePart(), chainID) |
| 126 | |
| 127 | // Prepare snapshot with from parent, label as root |
| 128 | mounts, err = sn.Prepare(ctx, key, parent.String(), opts...) |
| 129 | if err != nil { |
| 130 | if errdefs.IsNotFound(err) && len(layers) > 1 { |
| 131 | if err := applyLayers(ctx, layers[:len(layers)-1], chain[:len(chain)-1], sn, a, opts, applyOpts); err != nil { |
| 132 | if !errdefs.IsAlreadyExists(err) { |
| 133 | return err |
| 134 | } |
| 135 | } |
| 136 | // Do no try applying layers again |
| 137 | layers = nil |
| 138 | continue |
| 139 | } else if errdefs.IsAlreadyExists(err) { |
| 140 | // Try a different key |
| 141 | continue |
| 142 | } |
| 143 | |
| 144 | // Already exists should have the caller retry |
| 145 | return fmt.Errorf("failed to prepare extraction snapshot %q: %w", key, err) |
| 146 | |
| 147 | } |
| 148 | break |
| 149 | } |
| 150 | defer func() { |
| 151 | if err != nil { |
| 152 | if !errdefs.IsAlreadyExists(err) { |
| 153 | log.G(ctx).WithError(err).WithField("key", key).Infof("apply failure, attempting cleanup") |
| 154 | } |
| 155 | |
| 156 | if rerr := sn.Remove(ctx, key); rerr != nil { |
| 157 | log.G(ctx).WithError(rerr).WithField("key", key).Warnf("extraction snapshot removal failed") |
| 158 | } |
| 159 | } |
| 160 | }() |
| 161 | |
| 162 | diff, err = a.Apply(ctx, layer.Blob, mounts, applyOpts...) |
| 163 | if err != nil { |
| 164 | err = fmt.Errorf("failed to extract layer %s: %w", layer.Diff.Digest, err) |
| 165 | return err |
| 166 | } |
| 167 | if diff.Digest != layer.Diff.Digest { |
| 168 | err = fmt.Errorf("wrong diff id calculated on extraction %q", diff.Digest) |
| 169 | return err |
| 170 | } |