containerd_shimkit/sandbox/
error.rs

1//! Error types used by shims
2//! This handles converting to the appropriate ttrpc error codes
3
4use anyhow::Error as AnyError;
5use containerd_shim::Error as ShimError;
6use containerd_shim::protos::ttrpc;
7use oci_spec::OciSpecError;
8use thiserror::Error;
9
10#[derive(Debug, Error)]
11pub enum Error {
12    /// An error occurred while parsing the OCI spec
13    #[error("{0}")]
14    Oci(#[from] OciSpecError),
15    /// An error that can occur while setting up the environment for the container
16    #[error("{0}")]
17    Stdio(#[from] std::io::Error),
18    #[error("{0}")]
19    Others(String),
20    /// Errors to/from the containerd shim library.
21    #[error("{0}")]
22    Shim(#[from] ShimError),
23    /// Requested item is not found
24    #[error("not found: {0}")]
25    NotFound(String),
26    /// Requested item already exists
27    #[error("already exists: {0}")]
28    AlreadyExists(String),
29    /// Supplied arguments/options/config is invalid
30    #[error("invalid argument: {0}")]
31    InvalidArgument(String),
32    /// Any other error
33    #[error("{0}")]
34    Any(#[from] AnyError),
35    /// The operation was rejected because the system is not in a state required for the operation's
36    #[error("{0}")]
37    FailedPrecondition(String),
38    /// Error while parsing JSON
39    #[error("{0}")]
40    Json(#[from] serde_json::Error),
41    /// Error from the system
42    #[cfg(unix)]
43    #[error("{0}")]
44    Errno(#[from] nix::errno::Errno),
45    /// Errors from libcontainer
46    #[cfg(unix)]
47    #[error("{0}")]
48    Libcontainer(#[from] libcontainer::error::LibcontainerError),
49    #[error("{0}")]
50    Containerd(String),
51}
52
53pub type Result<T, E = Error> = ::std::result::Result<T, E>;
54
55impl From<Error> for ttrpc::Error {
56    fn from(e: Error) -> Self {
57        match e {
58            Error::Shim(ref s) => match s {
59                ShimError::InvalidArgument(s) => {
60                    ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::INVALID_ARGUMENT, s))
61                }
62                ShimError::NotFoundError(s) => {
63                    ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::NOT_FOUND, s))
64                }
65                _ => ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::UNKNOWN, s)),
66            },
67            Error::NotFound(ref s) => {
68                ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::NOT_FOUND, s))
69            }
70            Error::AlreadyExists(ref s) => {
71                ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::ALREADY_EXISTS, s))
72            }
73            Error::InvalidArgument(ref s) => {
74                ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::INVALID_ARGUMENT, s))
75            }
76            Error::FailedPrecondition(ref s) => {
77                ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::FAILED_PRECONDITION, s))
78            }
79            Error::Oci(ref _s) => {
80                ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::UNKNOWN, e.to_string()))
81            }
82            Error::Any(ref s) => {
83                ttrpc::Error::RpcStatus(ttrpc::get_status(ttrpc::Code::UNKNOWN, s))
84            }
85            _ => ttrpc::Error::Others(e.to_string()),
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use thiserror::Error;
93
94    use super::*;
95
96    #[derive(Debug, Error)]
97    enum TestError {
98        #[error("{0}")]
99        AnError(String),
100    }
101
102    #[test]
103    fn test_error_to_ttrpc_status() {
104        let e = Error::InvalidArgument("invalid argument".to_string());
105        let t: ttrpc::Error = e.into();
106        match t {
107            ttrpc::Error::RpcStatus(s) => {
108                assert_eq!(s.code(), ttrpc::Code::INVALID_ARGUMENT);
109                assert_eq!(s.message, "invalid argument");
110            }
111            _ => panic!("unexpected error"),
112        }
113
114        let e = Error::NotFound("not found".to_string());
115        let t: ttrpc::Error = e.into();
116        match t {
117            ttrpc::Error::RpcStatus(s) => {
118                assert_eq!(s.code(), ttrpc::Code::NOT_FOUND);
119                assert_eq!(s.message, "not found");
120            }
121            _ => panic!("unexpected error"),
122        }
123
124        let e = Error::AlreadyExists("already exists".to_string());
125        let t: ttrpc::Error = e.into();
126        match t {
127            ttrpc::Error::RpcStatus(s) => {
128                assert_eq!(s.code(), ttrpc::Code::ALREADY_EXISTS);
129                assert_eq!(s.message, "already exists");
130            }
131            _ => panic!("unexpected error"),
132        }
133
134        let e = Error::FailedPrecondition("failed precondition".to_string());
135        let t: ttrpc::Error = e.into();
136        match t {
137            ttrpc::Error::RpcStatus(s) => {
138                assert_eq!(s.code(), ttrpc::Code::FAILED_PRECONDITION);
139                assert_eq!(s.message, "failed precondition");
140            }
141            _ => panic!("unexpected error"),
142        }
143
144        let e = Error::Shim(ShimError::InvalidArgument("invalid argument".to_string()));
145        let t: ttrpc::Error = e.into();
146        match t {
147            ttrpc::Error::RpcStatus(s) => {
148                assert_eq!(s.code(), ttrpc::Code::INVALID_ARGUMENT);
149                assert_eq!(s.message, "invalid argument");
150            }
151            _ => panic!("unexpected error"),
152        }
153
154        let e = Error::Any(AnyError::new(TestError::AnError("any error".to_string())));
155        let t: ttrpc::Error = e.into();
156        match t {
157            ttrpc::Error::RpcStatus(s) => {
158                assert_eq!(s.code(), ttrpc::Code::UNKNOWN);
159                assert_eq!(s.message, "any error");
160            }
161            _ => panic!("unexpected error"),
162        }
163    }
164}