-
Notifications
You must be signed in to change notification settings - Fork 154
/
cas.go
172 lines (149 loc) · 9.29 KB
/
cas.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package cas
import (
"context"
"fmt"
"io"
"strings"
"github.com/lf-edge/edge-containers/pkg/resolver"
"github.com/lf-edge/eve/pkg/pillar/types"
)
// BlobInfo holds the info of a blob present in CAS's blob store
type BlobInfo struct {
// Digest to identify the blob uniquely. The format will/should be <algo>:<hash> (currently supporting only sha256:<hash>).
Digest string
// Size of the blob
Size int64
// Labels to add/define properties for the blob
Labels map[string]string
}
// CAS provides methods to interact with CAS clients
// Context handling should be taken care by the underlying implementor.
//
//nolint:interfacebloat
type CAS interface {
// Blob APIs
// CheckBlobExists: returns true if the blob exists.
// Arg 'blobHash' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
CheckBlobExists(blobHash string) bool
// GetBlobInfo: returns BlobInfo of type BlobInfo for the given blobHash.
// Arg 'blobHash' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
// Returns error if no blob is found for the given 'blobHash'.
GetBlobInfo(blobHash string) (*BlobInfo, error)
// ListBlobInfo: returns list of BlobInfo for all the blob present in CAS
ListBlobInfo() ([]*BlobInfo, error)
// ListBlobsMediaTypes get a map of all blobs and their media types.
// If a blob does not have a media type, it is not returned here.
// If you want *all* blobs, whether or not it has a type, use ListBlobInfo
ListBlobsMediaTypes() (map[string]string, error)
// IngestBlob: parses the given one or more `blobs` (BlobStatus) and for each blob reads the blob data from
// BlobStatus.Path and ingests it into CAS's blob store.
// Accepts a custom context. If ctx is nil, then default context will be used.
// Returns a list of loaded BlobStatus and an error is thrown if the read blob's hash does not match with the
// respective BlobStatus.Sha256 or if there is an exception while reading the blob data.
// In case of exception, the returned list of loaded blob will contain all the blob that were loaded until that point.
IngestBlob(ctx context.Context, blobs ...types.BlobStatus) ([]types.BlobStatus, error)
// UpdateBlobInfo updates BlobInfo of a blob in CAS.
// Arg is BlobInfo type struct in which BlobInfo.Digest is mandatory, and other field to be fill only if need to be updated
// Returns error is no blob is found match blobInfo.Digest
UpdateBlobInfo(blobInfo BlobInfo) error
// ReadBlob: returns a reader to consume the raw data of the blob which matches the given arg 'blobHash'.
// Returns error if no blob is found for the given 'blobHash'.
// Arg 'blobHash' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
ReadBlob(ctx context.Context, blobHash string) (io.Reader, error)
// RemoveBlob: removes a blob which matches the given arg 'blobHash'.
// To keep this method idempotent, no error is returned if the given arg 'blobHash' does not match any blob.
// Arg 'blobHash' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
RemoveBlob(blobHash string) error
// Children: returns a list of child blob hashes if the given arg 'blobHash' belongs to a
// index or a manifest blob, else an empty list is returned.
// Format of returned blob hash list and arg 'blobHash' is <algo>:<hash> (currently supporting only sha256:<hash>)
Children(blobHash string) ([]string, error)
// Image APIs
// CreateImage: creates a reference which points to a blob with 'blobHash'. 'blobHash' must belong to a index blob
// Arg 'blobHash' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
// Returns error if no blob is found matching the given 'blobHash' or if the given 'blobHash' does not belong to an index.
CreateImage(reference, mediaType, blobHash string) error
// GetImageHash: returns a blob hash of format <algo>:<hash> (currently supporting only sha256:<hash>) which the given 'reference' is pointing to.
// Returns error if the given 'reference' is not found.
GetImageHash(reference string) (string, error)
// GetImageLabels returns the labels set on the image.
// Returns error if the given reference is not found
GetImageLabels(reference string) (map[string]string, error)
// ListImages: returns a list of references
ListImages() ([]string, error)
// RemoveImage removes an reference from CAS
// To keep this method idempotent, no error is returned if the given 'reference' is not found.
RemoveImage(reference string) error
// ReplaceImage: replaces the blob hash to which the given 'reference' is pointing to with the given 'blobHash'.
// Returns error if the given 'reference' or a blob matching the given arg 'blobHash' is not found.
// Returns if the given 'blobHash' does not belong to an index.
// Arg 'blobHash' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
ReplaceImage(reference, mediaType, blobHash string) error
// Snapshot APIs
// CreateSnapshotForImage: creates an snapshot with the given snapshotID for the given 'reference'
// Arg 'snapshotID' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
CreateSnapshotForImage(snapshotID, reference string) error
// MountSnapshot: mounts the snapshot on the given target path
// Arg 'snapshotID' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
MountSnapshot(snapshotID, targetPath string) error
// SnapshotUsage returns current usage of snapshot in bytes
// We create snapshots for every layer of image and one active snapshot on top of them
// which presents the writable layer to store modified files
// If parents defined also adds usage of all parents of provided snapshot,
// not only the top active one
SnapshotUsage(snapshotID string, parents bool) (int64, error)
// ListSnapshots returns a list of snapshotIDs where each entry is of format <algo>:<hash> (currently supporting only sha256:<hash>).
ListSnapshots() ([]string, error)
// RemoveSnapshot removes a snapshot matching the given 'snapshotID'.
// Arg 'snapshotID' should be of format <algo>:<hash> (currently supporting only sha256:<hash>).
// To keep this method idempotent, no error is returned if the given 'snapshotID' is not found.
RemoveSnapshot(snapshotID string) error
// PrepareContainerRootDir creates a reference pointing to the rootBlob and prepares a writable snapshot
// from the reference. Before preparing container's root directory, this API must remove any existing state
// that may have accumulated (like existing snapshots being available, etc.)
// This effectively voids any kind of caching, but on the flip side frees us
// from cache invalidation. Additionally this API should deposit an OCI config json file and image name
// next to the rootfs so that the effective structure becomes:
// rootPath/rootfs, rootPath/image-config.json, rootPath/image-name
// The rootPath is expected to end in a basename that becomes the snapshotID
PrepareContainerRootDir(rootPath, reference, rootBlobSha string) error
// UnmountContainerRootDir unmounts container's rootPath.
// with force flag will use MNT_FORCE
// if not mounted will not return error
UnmountContainerRootDir(rootPath string, force bool) error
// RemoveContainerRootDir removes contents of a container's rootPath, existing snapshot and reference.
RemoveContainerRootDir(rootPath string) error
// IngestBlobsAndCreateImage is a combination of IngestBlobs and CreateImage APIs,
// but this API will add a lock, upload all the blobs, add reference to the blobs and release the lock.
// By adding a lock before uploading the blobs we prevent the unreferenced blobs from getting GCed.
// We will assume that the first blob in the list will be the root blob for which the reference will be created.
// Returns an error if the read blob's hash does not match with the respective BlobStatus.Sha256 or
// if there is an exception while reading the blob data.
// NOTE: This either loads all the blobs or loads nothing. In other words, in case of error,
// this API will GC all blobs that were loaded until that point.
IngestBlobsAndCreateImage(reference string, root types.BlobStatus, blobs ...types.BlobStatus) ([]types.BlobStatus, error)
// Resolver get an interface that satisfies resolver.ResolverCloser to communicate directly with a generic CAS
Resolver(ctx context.Context) (resolver.ResolverCloser, error)
// CtrNewUserServicesCtx() returns a context and a cancel function
CtrNewUserServicesCtx() (context.Context, context.CancelFunc)
// CloseClient closes (only) the respective CAS client initialized while calling `NewCAS()`.
CloseClient() error
}
type casDesc struct {
constructor func() CAS
}
var knownCASHandlers = map[string]casDesc{
"containerd": {constructor: newContainerdCAS},
}
// CheckAndCorrectBlobHash checks if the blobHash has hash algo sha256 as prefix. If not then it'll prepend it.
func CheckAndCorrectBlobHash(blobHash string) string {
return fmt.Sprintf("sha256:%s", strings.TrimPrefix(blobHash, "sha256:"))
}
// NewCAS returns new CAS object with a new client of underlying implementor(selectedCAS).
// It's the caller/user's responsibility to close the respective client after use by calling CAS.CloseClient().
func NewCAS(selectedCAS string) (CAS, error) {
if _, found := knownCASHandlers[selectedCAS]; !found {
return nil, fmt.Errorf("Unknown CAS handler %s", selectedCAS)
}
return knownCASHandlers[selectedCAS].constructor(), nil
}