1package baggageclaim 2 3import ( 4 "context" 5 "encoding/json" 6 "io" 7 8 "code.cloudfoundry.org/lager" 9) 10 11type Encoding string 12 13const GzipEncoding Encoding = "gzip" 14const ZstdEncoding Encoding = "zstd" 15 16//go:generate counterfeiter . Client 17 18// Client represents a client connection to a BaggageClaim server. 19type Client interface { 20 // CreateVolume will create a volume on the remote server. By passing in a 21 // VolumeSpec with a different strategy you can choose the type of volume 22 // that you want to create. 23 // 24 // You are required to pass in a logger to the call to retain context across 25 // the library boundary. 26 // 27 // CreateVolume returns the volume that was created or an error as to why it 28 // could not be created. 29 CreateVolume(lager.Logger, string, VolumeSpec) (Volume, error) 30 31 // ListVolumes lists the volumes that are present on the server. A 32 // VolumeProperties object can be passed in to filter the volumes that are in 33 // the response. 34 // 35 // You are required to pass in a logger to the call to retain context across 36 // the library boundary. 37 // 38 // ListVolumes returns the volumes that were found or an error as to why they 39 // could not be listed. 40 ListVolumes(lager.Logger, VolumeProperties) (Volumes, error) 41 42 // LookupVolume finds a volume that is present on the server. It takes a 43 // string that corresponds to the Handle of the Volume. 44 // 45 // You are required to pass in a logger to the call to retain context across 46 // the library boundary. 47 // 48 // LookupVolume returns a bool if the volume is found with the matching volume 49 // or an error as to why the volume could not be found. 50 LookupVolume(lager.Logger, string) (Volume, bool, error) 51 52 // DestroyVolumes deletes the list of volumes that is present on the server. It takes 53 // a string of volumes 54 // 55 // You are required to pass in a logger to the call to retain context across 56 // the library boundary. 57 // 58 // DestroyVolumes returns an error if any of the volume deletion fails. It does not 59 // return an error if volumes were not found on the server. 60 // DestroyVolumes returns an error as to why one or more volumes could not be deleted. 61 DestroyVolumes(lager.Logger, []string) error 62 63 // DestroyVolume deletes the volume with the provided handle that is present on the server. 64 // 65 // You are required to pass in a logger to the call to retain context across 66 // the library boundary. 67 // 68 // DestroyVolume returns an error if the volume deletion fails. It does not 69 // return an error if the volume was not found on the server. 70 DestroyVolume(lager.Logger, string) error 71} 72 73//go:generate counterfeiter . Volume 74 75// Volume represents a volume in the BaggageClaim system. 76type Volume interface { 77 // Handle returns a per-server unique identifier for the volume. The URL of 78 // the server and a handle is enough to universally identify a volume. 79 Handle() string 80 81 // Path returns the filesystem path to the volume on the server. This can be 82 // supplied to other systems in order to let them use the volume. 83 Path() string 84 85 // SetProperty sets a property on the Volume. Properties can be used to 86 // filter the results in the ListVolumes call above. 87 SetProperty(key string, value string) error 88 89 // SetPrivileged namespaces or un-namespaces the UID/GID ownership of the 90 // volume's contents. 91 SetPrivileged(bool) error 92 93 // GetPrivileged returns a bool indicating if the volume is privileged. 94 GetPrivileged() (bool, error) 95 96 // StreamIn calls BaggageClaim API endpoint in order to initialize tarStream 97 // to stream the contents of the Reader into this volume at the specified path. 98 StreamIn(ctx context.Context, path string, encoding Encoding, tarStream io.Reader) error 99 100 StreamOut(ctx context.Context, path string, encoding Encoding) (io.ReadCloser, error) 101 102 // Properties returns the currently set properties for a Volume. An error is 103 // returned if these could not be retrieved. 104 Properties() (VolumeProperties, error) 105 106 // Destroy removes the volume and its contents. Note that it does not 107 // safeguard against child volumes being present. 108 Destroy() error 109} 110 111//go:generate counterfeiter . VolumeFuture 112 113type VolumeFuture interface { 114 // Wait will wait until the future has been provided with a value, which is 115 // either the volume that was created or an error as to why it could not be 116 // created. 117 Wait() (Volume, error) 118 119 // Destroy removes the future from the remote server. This can be used to 120 // either stop waiting for a value, or remove the value from the remote 121 // server after it is no longer needed. 122 Destroy() error 123} 124 125// Volumes represents a list of Volume object. 126type Volumes []Volume 127 128func (v Volumes) Handles() []string { 129 var handles []string 130 for _, vol := range v { 131 handles = append(handles, vol.Handle()) 132 } 133 return handles 134} 135 136// VolumeProperties represents the properties for a particular volume. 137type VolumeProperties map[string]string 138 139// VolumeSpec is a specification representing the kind of volume that you'd 140// like from the server. 141type VolumeSpec struct { 142 // Strategy is the information that the server requires to materialise the 143 // volume. There are examples of these in this package. 144 Strategy Strategy 145 146 // Properties is the set of initial properties that the Volume should have. 147 Properties VolumeProperties 148 149 // Privileged is used to determine whether or not we need to perform a UID 150 // translation of the files in the volume so that they can be read by a 151 // non-privileged user. 152 Privileged bool 153} 154 155type Strategy interface { 156 Encode() *json.RawMessage 157} 158 159// ImportStrategy creates a volume by copying a directory from the host. 160type ImportStrategy struct { 161 // The location on the host to import. If the path is a directory, its 162 // contents will be copied in. If the path is a file, it is assumed to be a 163 // .tar.gz file, and its contents will be unpacked in to the volume. 164 Path string 165 166 // Follow symlinks and import them as files instead of links. 167 FollowSymlinks bool 168} 169 170func (strategy ImportStrategy) Encode() *json.RawMessage { 171 payload, _ := json.Marshal(struct { 172 Type string `json:"type"` 173 Path string `json:"path"` 174 FollowSymlinks bool `json:"follow_symlinks"` 175 }{ 176 Type: "import", 177 Path: strategy.Path, 178 FollowSymlinks: strategy.FollowSymlinks, 179 }) 180 181 msg := json.RawMessage(payload) 182 return &msg 183} 184 185// COWStrategy creates a Copy-On-Write layer of another Volume. 186type COWStrategy struct { 187 // The parent volume that we should base the new volume on. 188 Parent Volume 189} 190 191func (strategy COWStrategy) Encode() *json.RawMessage { 192 payload, _ := json.Marshal(struct { 193 Type string `json:"type"` 194 Volume string `json:"volume"` 195 }{ 196 Type: "cow", 197 Volume: strategy.Parent.Handle(), 198 }) 199 200 msg := json.RawMessage(payload) 201 return &msg 202} 203 204// EmptyStrategy created a new empty volume. 205type EmptyStrategy struct{} 206 207func (EmptyStrategy) Encode() *json.RawMessage { 208 msg := json.RawMessage(`{"type":"empty"}`) 209 return &msg 210} 211