| package containerd | |
| import ( | |
| "context" | |
| "time" | |
| "github.com/containerd/containerd/leases" | |
| "github.com/containerd/log" | |
| ) | |
| const ( | |
| leaseExpireDuration = 8 * time.Hour | |
| expireLabel = "containerd.io/gc.expire" // Copied from containerd | |
| pruneLeaseLabel = "moby/prune.images" | |
| pruneLeaseFilter = `labels."moby/prune.images"` | |
| ) | |
| // withLease is used to prevent content or snapshots from being eligible for | |
| // garbage collection while they are being used. Leases should always be | |
| // released when complete to make the resources eligible again. | |
| // If cancellable is set to true, then the lease will remain if the context | |
| // is canceled until its expiration or deletion via prune. | |
| func (i *ImageService) withLease(ctx context.Context, cancellable bool) (context.Context, func(), error) { | |
| _, ok := leases.FromContext(ctx) | |
| if ok { | |
| return ctx, func() {}, nil | |
| } | |
| ls := i.client.LeasesService() | |
| expireAt := time.Now().Add(leaseExpireDuration) | |
| l, err := ls.Create(ctx, | |
| leases.WithRandomID(), | |
| leases.WithLabels(map[string]string{ | |
| pruneLeaseLabel: "true", | |
| expireLabel: expireAt.Format(time.RFC3339), | |
| })) | |
| if err != nil { | |
| return ctx, func() {}, err | |
| } | |
| ctx = leases.WithLease(ctx, l.ID) | |
| return ctx, func() { | |
| if ctx.Err() != nil && cancellable { | |
| log.G(ctx).WithFields(log.Fields{"lease": l.ID, "expires_at": expireAt}).Info("Cancel with lease, leased resources will remain until expiration") | |
| return | |
| } | |
| if err := ls.Delete(context.WithoutCancel(ctx), l); err != nil { | |
| log.G(ctx).WithError(err).WithFields(log.Fields{"lease": l.ID, "expires_at": expireAt}).Warn("Error deleting lease, leased resources will remain until expiration") | |
| } | |
| }, nil | |
| } |