leases: support resource management

Add three methods for lease service so that the client can use it to
manage the resource by lease, not just gc.root label. With the following
methods, it is easy for client to maintain their own cache system.

```
 - AddResource(context.Context, Lease, Resource) error
 - RemoveResource(context.Context, Lease, Resource) error
 - ListResources(context.Context, Lease) ([]Resource, error)
```

And the resource is to be

```golang
type Resource {
  ID   string
  Type string
}
```

For the snapshots, the Type field will be formatted by
snapshots/%{type}, like snapshots/overlayfs.

fix: #3295

Signed-off-by: Wei Fu <fuweid89@gmail.com>
This commit is contained in:
Wei Fu
2019-05-26 23:54:48 +08:00
parent 0e7a3c9e51
commit 8a388d6238
10 changed files with 1930 additions and 34 deletions

View File

@@ -264,3 +264,181 @@ func TestLeasesList(t *testing.T) {
}
}
}
func TestLeaseResource(t *testing.T) {
ctx, db, cancel := testEnv(t)
defer cancel()
var (
leaseID = "l1"
lease = leases.Lease{
ID: leaseID,
}
snapshotterKey = "RstMI3X8vguKoPFkmIStZ5fQFI7F1L0o"
)
// prepare lease
if err := db.Update(func(tx *bolt.Tx) error {
_, err0 := NewLeaseManager(tx).Create(ctx, leases.WithID(leaseID))
return err0
}); err != nil {
t.Fatal(err)
}
testCases := []struct {
lease leases.Lease
resource leases.Resource
err error
}{
{
lease: lease,
resource: leases.Resource{
ID: "sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912",
Type: "content",
},
},
{
lease: lease,
resource: leases.Resource{
ID: "d2UdcINOwrBTQG9kS8rySAM3eMNBSojH",
Type: "ingests",
},
},
{
// allow to add resource which exists
lease: lease,
resource: leases.Resource{
ID: "d2UdcINOwrBTQG9kS8rySAM3eMNBSojH",
Type: "ingests",
},
},
{
// not allow to reference to lease
lease: lease,
resource: leases.Resource{
ID: "xCAV3F6PddlXitbtby0Vo23Qof6RTWpG",
Type: "leases",
},
err: errdefs.ErrNotImplemented,
},
{
// not allow to reference to container
lease: lease,
resource: leases.Resource{
ID: "05O9ljptPu5Qq9kZGOacEfymBwQFM8ZH",
Type: "containers",
},
err: errdefs.ErrNotImplemented,
},
{
// not allow to reference to image
lease: lease,
resource: leases.Resource{
ID: "qBUHpWBn03YaCt9cL3PPGKWoxBqTlLfu",
Type: "image",
},
err: errdefs.ErrNotImplemented,
},
{
lease: lease,
resource: leases.Resource{
ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2",
Type: "snapshots",
},
err: errdefs.ErrInvalidArgument,
},
{
lease: lease,
resource: leases.Resource{
ID: snapshotterKey,
Type: "snapshots/overlayfs",
},
},
{
lease: lease,
resource: leases.Resource{
ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2",
Type: "snapshots/overlayfs/type1",
},
err: errdefs.ErrInvalidArgument,
},
{
lease: leases.Lease{
ID: "non-found",
},
resource: leases.Resource{
ID: "HMemOhlygombYhkhHhAZj5aRbDy2a3z2",
Type: "snapshots/overlayfs",
},
err: errdefs.ErrNotFound,
},
}
idxList := make(map[leases.Resource]bool)
for i, tc := range testCases {
if err := db.Update(func(tx *bolt.Tx) error {
err0 := NewLeaseManager(tx).AddResource(ctx, tc.lease, tc.resource)
if got := errors.Cause(err0); got != tc.err {
return errors.Errorf("expect error (%v), but got (%v)", tc.err, err0)
}
if err0 == nil {
// not visited yet
idxList[tc.resource] = false
}
return nil
}); err != nil {
t.Fatalf("failed to run case %d with resource: %v", i, err)
}
}
// check list function
var gotList []leases.Resource
if err := db.View(func(tx *bolt.Tx) error {
var err error
gotList, err = NewLeaseManager(tx).ListResources(ctx, lease)
return err
}); err != nil {
t.Fatal(err)
}
if len(gotList) != len(idxList) {
t.Fatalf("expected (%d) resources, but got (%d)", len(idxList), len(gotList))
}
for _, r := range gotList {
visited, ok := idxList[r]
if !ok {
t.Fatalf("unexpected resource(%v)", r)
}
if visited {
t.Fatalf("duplicate resource(%v)", r)
}
idxList[r] = true
}
// remove snapshots
if err := db.Update(func(tx *bolt.Tx) error {
return NewLeaseManager(tx).DeleteResource(ctx, lease, leases.Resource{
ID: snapshotterKey,
Type: "snapshots/overlayfs",
})
}); err != nil {
t.Fatal(err)
}
// check list number
if err := db.View(func(tx *bolt.Tx) error {
var err error
gotList, err = NewLeaseManager(tx).ListResources(ctx, lease)
return err
}); err != nil {
t.Fatal(err)
}
if len(gotList)+1 != len(idxList) {
t.Fatalf("expected (%d) resources, but got (%d)", len(idxList)-1, len(gotList))
}
}