Skip to main content

krill/api/
status.rs

1//! Error reporting.
2
3use std::fmt;
4use std::collections::HashMap;
5use rpki::ca::csr::BgpsecCsr;
6use rpki::ca::idexchange::{
7    CaHandle, ChildHandle, ParentHandle, PublisherHandle
8};
9use rpki::ca::provisioning::ResourceClassName;
10use rpki::ca::publication::Base64;
11use rpki::crypto::KeyIdentifier;
12use rpki::repository::resources::Asn;
13use serde::{Deserialize, Serialize, Serializer};
14use serde::ser::SerializeStruct;
15use crate::commons::error::RoaDeltaError;
16use super::roa::RoaPayload;
17
18
19//------------ Success -------------------------------------------------------
20
21/// An empty, successful API response.
22///
23/// This type needs to be used instead of `()` to make conversion into
24/// [`Report`][crate::cli::report::Report] work.
25#[derive(Clone, Copy, Debug)]
26pub struct Success;
27
28impl fmt::Display for Success {
29    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30        f.write_str("Ok")
31    }
32}
33
34impl Serialize for Success {
35    fn serialize<S: Serializer>(
36        &self, serializer: S
37    ) -> Result<S::Ok, S::Error> {
38        let mut serializer = serializer.serialize_struct("Success", 1)?;
39        serializer.serialize_field("status", "Ok")?;
40        serializer.end()
41    }
42}
43
44
45//------------ ErrorResponse -------------------------------------------------
46
47/// An API error response.
48#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
49pub struct ErrorResponse {
50    /// The error label.
51    pub label: String,
52
53    /// The error message.
54    pub msg: String,
55
56    /// Arguments with details about the error.
57    pub args: HashMap<String, String>,
58
59    /// Optional ROA delta error.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub delta_error: Option<RoaDeltaError>,
62}
63
64impl ErrorResponse {
65    pub fn new(label: &str, msg: impl fmt::Display) -> Self {
66        ErrorResponse {
67            label: label.to_string(),
68            msg: msg.to_string(),
69            args: HashMap::new(),
70            delta_error: None,
71        }
72    }
73
74    pub fn with_arg(mut self, key: &str, value: impl fmt::Display) -> Self {
75        self.args.insert(key.to_string(), value.to_string());
76        self
77    }
78
79    pub fn with_cause(self, cause: impl fmt::Display) -> Self {
80        self.with_arg("cause", cause)
81    }
82
83    pub fn with_publisher(self, publisher: &PublisherHandle) -> Self {
84        self.with_arg("publisher", publisher)
85    }
86
87    pub fn with_uri(self, uri: impl fmt::Display) -> Self {
88        self.with_arg("uri", uri)
89    }
90
91    pub fn with_base_uri(self, base_uri: impl fmt::Display) -> Self {
92        self.with_arg("base_uri", base_uri)
93    }
94
95    pub fn with_ca(self, ca: &CaHandle) -> Self {
96        self.with_arg("ca", ca)
97    }
98
99    pub fn with_parent(self, parent: &ParentHandle) -> Self {
100        self.with_arg("parent", parent)
101    }
102
103    pub fn with_child(self, child: &ChildHandle) -> Self {
104        self.with_arg("child", child)
105    }
106
107    pub fn with_auth(self, auth: impl Into<RoaPayload>) -> Self {
108        let auth = auth.into();
109        let mut res = self
110            .with_arg("prefix", auth.prefix)
111            .with_arg("asn", auth.asn);
112
113        if let Some(max) = auth.max_length {
114            res = res.with_arg("max_length", max)
115        }
116
117        res
118    }
119
120    pub fn with_asn(self, asn: Asn) -> Self {
121        self.with_arg("asn", asn)
122    }
123
124    pub fn with_bgpsec_csr(self, csr: &BgpsecCsr) -> Self {
125        let base64 = Base64::from_content(csr.to_captured().as_slice());
126        self.with_arg("bgpsec_csr", base64)
127    }
128
129    pub fn with_roa_delta_error(
130        mut self,
131        roa_delta_error: &RoaDeltaError,
132    ) -> Self {
133        self.delta_error = Some(roa_delta_error.clone());
134        self
135    }
136
137    pub fn with_key_identifier(self, ki: &KeyIdentifier) -> Self {
138        self.with_arg("key_id", ki)
139    }
140
141    pub fn with_resource_class(self, class_name: &ResourceClassName) -> Self {
142        self.with_arg("class_name", class_name)
143    }
144}
145
146impl fmt::Display for ErrorResponse {
147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148        write!(f, "{}", &serde_json::to_string(&self).unwrap())
149    }
150}
151