containerd_snapshots/
lib.rs

1/*
2   Copyright The containerd Authors.
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17//! Remote snapshotter extension for containerd.
18//!
19//! Snapshots crate implements containerd's proxy plugin for snapshotting. It aims hide the underlying
20//! complexity of GRPC interfaces, streaming and request/response conversions and provide one
21//! [crate::Snapshotter] trait to implement.
22//!
23//! # Proxy plugins
24//! A proxy plugin is configured using containerd's config file and will be loaded alongside the
25//! internal plugins when containerd is started. These plugins are connected to containerd using a
26//! local socket serving one of containerd's GRPC API services. Each plugin is configured with a
27//! type and name just as internal plugins are.
28//!
29//! # How to use from containerd
30//! Add the following to containerd's configuration file:
31//! ```toml
32//! [proxy_plugins]
33//!   [proxy_plugins.custom]
34//!     type = "snapshot"
35//!     address = "/tmp/snap2.sock"
36//! ```
37//! Start containerd daemon:
38//! ```bash
39//! containerd --config /path/config.toml
40//! ```
41//!
42//! Run remote snapshotter instance:
43//! ```bash
44//! $ cargo run --example snapshotter /tmp/snap2.sock
45//! ```
46//! Now specify `custom` snapshotter when pulling an image with `ctr`:
47//! ```bash
48//! $ ctr i pull --snapshotter custom docker.io/library/hello-world:latest
49//! ```
50//!
51
52// No way to derive Eq with tonic :(
53// See https://github.com/hyperium/tonic/issues/1056
54#![allow(clippy::derive_partial_eq_without_eq)]
55
56use std::{collections::HashMap, fmt::Debug, ops::AddAssign, time::SystemTime};
57
58use serde::{Deserialize, Serialize};
59use tokio_stream::Stream;
60pub use tonic;
61
62mod convert;
63mod wrap;
64
65pub use wrap::server;
66
67/// Generated GRPC apis.
68pub mod api {
69    /// Generated snapshots bindings.
70    pub mod snapshots {
71        pub mod v1 {
72            tonic::include_proto!("containerd.services.snapshots.v1");
73        }
74    }
75
76    /// Generated `containerd.types` types.
77    pub mod types {
78        tonic::include_proto!("containerd.types");
79    }
80}
81
82/// Snapshot kinds.
83#[derive(Debug, Serialize, Deserialize, PartialEq, Default)]
84pub enum Kind {
85    #[default]
86    Unknown,
87    View,
88    Active,
89    Committed,
90}
91
92/// Information about a particular snapshot.
93#[derive(Debug, Serialize, Deserialize)]
94pub struct Info {
95    /// Active or committed snapshot.
96    pub kind: Kind,
97    /// Name of key of snapshot.
98    pub name: String,
99    /// Name of parent snapshot.
100    pub parent: String,
101    /// Labels for a snapshot.
102    pub labels: HashMap<String, String>,
103    /// Created time.
104    pub created_at: SystemTime,
105    /// Last updated time.
106    pub updated_at: SystemTime,
107}
108
109impl Default for Info {
110    fn default() -> Self {
111        Info {
112            kind: Default::default(),
113            name: Default::default(),
114            parent: Default::default(),
115            labels: Default::default(),
116            created_at: SystemTime::now(),
117            updated_at: SystemTime::now(),
118        }
119    }
120}
121
122/// Defines statistics for disk resources consumed by the snapshot.
123///
124// These resources only include the resources consumed by the snapshot itself and does not include
125// resources usage by the parent.
126#[derive(Debug, Default)]
127pub struct Usage {
128    /// Number of inodes in use.
129    pub inodes: i64,
130    /// Provides usage of snapshot in bytes.
131    pub size: i64,
132}
133
134/// Add the provided usage to the current usage.
135impl AddAssign for Usage {
136    fn add_assign(&mut self, rhs: Self) {
137        self.inodes += rhs.inodes;
138        self.size += rhs.size;
139    }
140}
141
142/// Snapshotter defines the methods required to implement a snapshot snapshotter for
143/// allocating, snapshotting and mounting filesystem changesets. The model works
144/// by building up sets of changes with parent-child relationships.
145///
146/// A snapshot represents a filesystem state. Every snapshot has a parent, where
147/// the empty parent is represented by the empty string. A diff can be taken
148/// between a parent and its snapshot to generate a classic layer.
149#[tonic::async_trait]
150pub trait Snapshotter: Send + Sync + 'static {
151    /// Error type returned from the underlying snapshotter implementation.
152    ///
153    /// This type must be convertable to GRPC status.
154    type Error: Debug + Into<tonic::Status> + Send;
155
156    /// Returns the info for an active or committed snapshot by name or key.
157    ///
158    /// Should be used for parent resolution, existence checks and to discern
159    /// the kind of snapshot.
160    async fn stat(&self, key: String) -> Result<Info, Self::Error>;
161
162    /// Update updates the info for a snapshot.
163    ///
164    /// Only mutable properties of a snapshot may be updated.
165    async fn update(
166        &self,
167        info: Info,
168        fieldpaths: Option<Vec<String>>,
169    ) -> Result<Info, Self::Error>;
170
171    /// Usage returns the resource usage of an active or committed snapshot
172    /// excluding the usage of parent snapshots.
173    ///
174    /// The running time of this call for active snapshots is dependent on
175    /// implementation, but may be proportional to the size of the resource.
176    /// Callers should take this into consideration.
177    async fn usage(&self, key: String) -> Result<Usage, Self::Error>;
178
179    /// Mounts returns the mounts for the active snapshot transaction identified
180    /// by key.
181    ///
182    /// Can be called on an read-write or readonly transaction. This is
183    /// available only for active snapshots.
184    ///
185    /// This can be used to recover mounts after calling View or Prepare.
186    async fn mounts(&self, key: String) -> Result<Vec<api::types::Mount>, Self::Error>;
187
188    /// Creates an active snapshot identified by key descending from the provided parent.
189    /// The returned mounts can be used to mount the snapshot to capture changes.
190    ///
191    /// If a parent is provided, after performing the mounts, the destination will start
192    /// with the content of the parent. The parent must be a committed snapshot.
193    /// Changes to the mounted destination will be captured in relation to the parent.
194    /// The default parent, "", is an empty directory.
195    ///
196    /// The changes may be saved to a committed snapshot by calling [Snapshotter::commit]. When
197    /// one is done with the transaction, [Snapshotter::remove] should be called on the key.
198    ///
199    /// Multiple calls to [Snapshotter::prepare] or [Snapshotter::view] with the same key should fail.
200    async fn prepare(
201        &self,
202        key: String,
203        parent: String,
204        labels: HashMap<String, String>,
205    ) -> Result<Vec<api::types::Mount>, Self::Error>;
206
207    /// View behaves identically to [Snapshotter::prepare] except the result may not be
208    /// committed back to the snapshot snapshotter. View call returns a readonly view on
209    /// the parent, with the active snapshot being tracked by the given key.
210    ///
211    /// This method operates identically to [Snapshotter::prepare], except that mounts returned
212    /// may have the readonly flag set. Any modifications to the underlying
213    /// filesystem will be ignored. Implementations may perform this in a more
214    /// efficient manner that differs from what would be attempted with [Snapshotter::prepare].
215    ///
216    /// Commit may not be called on the provided key and will return an error.
217    /// To collect the resources associated with key, [Snapshotter::remove] must be called with
218    /// key as the argument.
219    async fn view(
220        &self,
221        key: String,
222        parent: String,
223        labels: HashMap<String, String>,
224    ) -> Result<Vec<api::types::Mount>, Self::Error>;
225
226    /// Capture the changes between key and its parent into a snapshot identified by name.
227    ///
228    /// The name can then be used with the snapshotter's other methods to create subsequent snapshots.
229    ///
230    /// A committed snapshot will be created under name with the parent of the
231    /// active snapshot.
232    ///
233    /// After commit, the snapshot identified by key is removed.
234    async fn commit(
235        &self,
236        name: String,
237        key: String,
238        labels: HashMap<String, String>,
239    ) -> Result<(), Self::Error>;
240
241    /// Remove the committed or active snapshot by the provided key.
242    ///
243    /// All resources associated with the key will be removed.
244    ///
245    /// If the snapshot is a parent of another snapshot, its children must be
246    /// removed before proceeding.
247    async fn remove(&self, key: String) -> Result<(), Self::Error>;
248
249    /// Cleaner defines a type capable of performing asynchronous resource cleanup.
250    ///
251    /// Cleaner interface should be used by snapshotters which implement fast
252    /// removal and deferred resource cleanup. This prevents snapshots from needing
253    /// to perform lengthy resource cleanup before acknowledging a snapshot key
254    /// has been removed and available for re-use. This is also useful when
255    /// performing multi-key removal with the intent of cleaning up all the
256    /// resources after each snapshot key has been removed.
257    async fn clear(&self) -> Result<(), Self::Error> {
258        Ok(())
259    }
260
261    /// The type of the stream that returns all snapshots.
262    ///
263    /// An instance of this type is returned by [`Snapshotter::list`] on success.
264    type InfoStream: Stream<Item = Result<Info, Self::Error>> + Send + 'static;
265
266    /// Returns a stream containing all snapshots.
267    ///
268    /// Once `type_alias_impl_trait` is stabilized or if the implementer is willing to use unstable
269    /// features, this function can be implemented using `try_stream` and `yield`. For example, a
270    /// function that lists a single snapshot with the default values would be implemented as
271    /// follows:
272    ///
273    ///```ignore
274    ///     type InfoStream = impl Stream<Item = Result<Info, Self::Error>> + Send + 'static;
275    ///     fn list(&self) -> Result<Self::InfoStream, Self::Error> {
276    ///         Ok(async_stream::try_stream! {
277    ///             yield Info::default();
278    ///         })
279    ///     }
280    /// ```
281    async fn list(
282        &self,
283        snapshotter: String,
284        filters: Vec<String>,
285    ) -> Result<Self::InfoStream, Self::Error>;
286}