Skip to content

Commit 7e8bac8

Browse files
refactor(ctrlp): add core agent
Refactor the node,pool,volume agent into a single core agent. Tidy up the Errors throughout the control plane stack allowing us to get more concise error kinds at the rest layer and also at each agent endpoint, which will allow us to expose the correct http responses at the openapi spec, which will be done as another PR.
1 parent d9cebab commit 7e8bac8

File tree

49 files changed

+3164
-2927
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3164
-2927
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

control-plane/agents/Cargo.toml

+3-15
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,13 @@ authors = ["Tiago Castro <tiago.castro@mayadata.io>"]
55
edition = "2018"
66

77
[[bin]]
8-
name = "kiiss"
9-
path = "kiiss/src/server.rs"
10-
11-
[[bin]]
12-
name = "node"
13-
path = "node/src/server.rs"
14-
15-
[[bin]]
16-
name = "pool"
17-
path = "pool/src/server.rs"
18-
19-
[[bin]]
20-
name = "volume"
21-
path = "volume/src/server.rs"
8+
name = "core"
9+
path = "core/src/server.rs"
2210

2311
[[bin]]
2412
name = "jsongrpc"
2513
path = "jsongrpc/src/server.rs"
2614

27-
2815
[lib]
2916
name = "common"
3017
path = "common/src/lib.rs"
@@ -50,6 +37,7 @@ tracing-futures = "0.2.4"
5037
rpc = { path = "../../rpc" }
5138
url = "2.2.0"
5239
http = "0.2.1"
40+
paste = "1.0.4"
5341

5442
[dev-dependencies]
5543
composer = { path = "../../composer" }
+300
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
use mbus_api::{
2+
message_bus::v0::BusError,
3+
v0::*,
4+
ErrorChain,
5+
ReplyError,
6+
ReplyErrorKind,
7+
ResourceKind,
8+
};
9+
use snafu::{Error, Snafu};
10+
use tonic::Code;
11+
12+
/// Common error type for send/receive
13+
#[derive(Debug, Snafu)]
14+
#[snafu(visibility = "pub")]
15+
#[allow(missing_docs)]
16+
pub enum SvcError {
17+
#[snafu(display("Failed to get node '{}' from the node agent", node))]
18+
BusGetNode { node: String, source: BusError },
19+
#[snafu(display("Failed to get nodes from the node agent"))]
20+
BusGetNodes { source: BusError },
21+
#[snafu(display("Node '{}' is not online", node))]
22+
NodeNotOnline { node: NodeId },
23+
#[snafu(display(
24+
"Timed out after '{:?}' attempting to connect to node '{}' via gRPC endpoint '{}'",
25+
timeout,
26+
node_id,
27+
endpoint
28+
))]
29+
GrpcConnectTimeout {
30+
node_id: String,
31+
endpoint: String,
32+
timeout: std::time::Duration,
33+
},
34+
#[snafu(display("Failed to connect to node via gRPC"))]
35+
GrpcConnect { source: tonic::transport::Error },
36+
#[snafu(display("Node '{}' has invalid gRPC URI '{}'", node_id, uri))]
37+
GrpcConnectUri {
38+
node_id: String,
39+
uri: String,
40+
source: http::uri::InvalidUri,
41+
},
42+
#[snafu(display(
43+
"gRPC request '{}' for '{}' failed with '{}'",
44+
request,
45+
resource.to_string(),
46+
source
47+
))]
48+
GrpcRequestError {
49+
resource: ResourceKind,
50+
request: String,
51+
source: tonic::Status,
52+
},
53+
#[snafu(display("Node '{}' not found", node_id))]
54+
NodeNotFound { node_id: NodeId },
55+
#[snafu(display("Pool '{}' not found", pool_id))]
56+
PoolNotFound { pool_id: PoolId },
57+
#[snafu(display("Nexus '{}' not found", nexus_id))]
58+
NexusNotFound { nexus_id: String },
59+
#[snafu(display("Replica '{}' not found", replica_id))]
60+
ReplicaNotFound { replica_id: ReplicaId },
61+
#[snafu(display("Invalid filter value: {:?}", filter))]
62+
InvalidFilter { filter: Filter },
63+
#[snafu(display("Operation failed due to insufficient resources"))]
64+
NotEnoughResources { source: NotEnough },
65+
#[snafu(display("Failed to deserialise JsonRpc response"))]
66+
JsonRpcDeserialise { source: serde_json::Error },
67+
#[snafu(display(
68+
"Json RPC call failed for method '{}' with parameters '{}'. Error {}",
69+
method,
70+
params,
71+
error,
72+
))]
73+
JsonRpc {
74+
method: String,
75+
params: String,
76+
error: String,
77+
},
78+
#[snafu(display("Internal error: {}", details))]
79+
Internal { details: String },
80+
#[snafu(display("Message Bus error"))]
81+
MBusError { source: mbus_api::Error },
82+
#[snafu(display("Invalid Arguments"))]
83+
InvalidArguments {},
84+
}
85+
86+
impl From<mbus_api::Error> for SvcError {
87+
fn from(source: mbus_api::Error) -> Self {
88+
Self::MBusError {
89+
source,
90+
}
91+
}
92+
}
93+
94+
impl From<NotEnough> for SvcError {
95+
fn from(source: NotEnough) -> Self {
96+
Self::NotEnoughResources {
97+
source,
98+
}
99+
}
100+
}
101+
102+
impl From<SvcError> for ReplyError {
103+
fn from(error: SvcError) -> Self {
104+
#[allow(deprecated)]
105+
let desc: &String = &error.description().to_string();
106+
match error {
107+
SvcError::BusGetNode {
108+
source, ..
109+
} => source,
110+
SvcError::BusGetNodes {
111+
source,
112+
} => source,
113+
SvcError::GrpcRequestError {
114+
source,
115+
request,
116+
resource,
117+
} => grpc_to_reply_error(SvcError::GrpcRequestError {
118+
source,
119+
request,
120+
resource,
121+
}),
122+
123+
SvcError::InvalidArguments {
124+
..
125+
} => ReplyError {
126+
kind: ReplyErrorKind::InvalidArgument,
127+
resource: ResourceKind::Unknown,
128+
source: desc.to_string(),
129+
extra: error.full_string(),
130+
},
131+
132+
SvcError::NodeNotOnline {
133+
..
134+
} => ReplyError {
135+
kind: ReplyErrorKind::FailedPrecondition,
136+
resource: ResourceKind::Node,
137+
source: desc.to_string(),
138+
extra: error.full_string(),
139+
},
140+
141+
SvcError::GrpcConnectTimeout {
142+
..
143+
} => ReplyError {
144+
kind: ReplyErrorKind::Timeout,
145+
resource: ResourceKind::Unknown,
146+
source: desc.to_string(),
147+
extra: error.full_string(),
148+
},
149+
150+
SvcError::GrpcConnectUri {
151+
..
152+
} => ReplyError {
153+
kind: ReplyErrorKind::Internal,
154+
resource: ResourceKind::Unknown,
155+
source: desc.to_string(),
156+
extra: error.full_string(),
157+
},
158+
159+
SvcError::GrpcConnect {
160+
source,
161+
} => ReplyError {
162+
kind: ReplyErrorKind::Internal,
163+
resource: ResourceKind::Unknown,
164+
source: desc.to_string(),
165+
extra: source.to_string(),
166+
},
167+
168+
SvcError::NotEnoughResources {
169+
..
170+
} => ReplyError {
171+
kind: ReplyErrorKind::ResourceExhausted,
172+
resource: ResourceKind::Unknown,
173+
source: desc.to_string(),
174+
extra: error.full_string(),
175+
},
176+
SvcError::JsonRpcDeserialise {
177+
..
178+
} => ReplyError {
179+
kind: ReplyErrorKind::Internal,
180+
resource: ResourceKind::JsonGrpc,
181+
source: desc.to_string(),
182+
extra: error.full_string(),
183+
},
184+
SvcError::JsonRpc {
185+
..
186+
} => ReplyError {
187+
kind: ReplyErrorKind::Internal,
188+
resource: ResourceKind::JsonGrpc,
189+
source: desc.to_string(),
190+
extra: error.full_string(),
191+
},
192+
SvcError::NodeNotFound {
193+
..
194+
} => ReplyError {
195+
kind: ReplyErrorKind::NotFound,
196+
resource: ResourceKind::Node,
197+
source: desc.to_string(),
198+
extra: error.full_string(),
199+
},
200+
SvcError::PoolNotFound {
201+
..
202+
} => ReplyError {
203+
kind: ReplyErrorKind::NotFound,
204+
resource: ResourceKind::Pool,
205+
source: desc.to_string(),
206+
extra: error.full_string(),
207+
},
208+
SvcError::ReplicaNotFound {
209+
..
210+
} => ReplyError {
211+
kind: ReplyErrorKind::NotFound,
212+
resource: ResourceKind::Replica,
213+
source: desc.to_string(),
214+
extra: error.full_string(),
215+
},
216+
SvcError::NexusNotFound {
217+
..
218+
} => ReplyError {
219+
kind: ReplyErrorKind::NotFound,
220+
resource: ResourceKind::Nexus,
221+
source: desc.to_string(),
222+
extra: error.full_string(),
223+
},
224+
SvcError::InvalidFilter {
225+
..
226+
} => ReplyError {
227+
kind: ReplyErrorKind::Internal,
228+
resource: ResourceKind::Unknown,
229+
source: desc.to_string(),
230+
extra: error.full_string(),
231+
},
232+
SvcError::Internal {
233+
..
234+
} => ReplyError {
235+
kind: ReplyErrorKind::Internal,
236+
resource: ResourceKind::Unknown,
237+
source: desc.to_string(),
238+
extra: error.full_string(),
239+
},
240+
SvcError::MBusError {
241+
source,
242+
} => source.into(),
243+
}
244+
}
245+
}
246+
247+
fn grpc_to_reply_error(error: SvcError) -> ReplyError {
248+
match error {
249+
SvcError::GrpcRequestError {
250+
source,
251+
request,
252+
resource,
253+
} => {
254+
let kind = match source.code() {
255+
Code::Ok => ReplyErrorKind::Internal,
256+
Code::Cancelled => ReplyErrorKind::Internal,
257+
Code::Unknown => ReplyErrorKind::Internal,
258+
Code::InvalidArgument => ReplyErrorKind::InvalidArgument,
259+
Code::DeadlineExceeded => ReplyErrorKind::DeadlineExceeded,
260+
Code::NotFound => ReplyErrorKind::NotFound,
261+
Code::AlreadyExists => ReplyErrorKind::AlreadyExists,
262+
Code::PermissionDenied => ReplyErrorKind::PermissionDenied,
263+
Code::ResourceExhausted => ReplyErrorKind::ResourceExhausted,
264+
Code::FailedPrecondition => ReplyErrorKind::FailedPrecondition,
265+
Code::Aborted => ReplyErrorKind::Aborted,
266+
Code::OutOfRange => ReplyErrorKind::OutOfRange,
267+
Code::Unimplemented => ReplyErrorKind::Unimplemented,
268+
Code::Internal => ReplyErrorKind::Internal,
269+
Code::Unavailable => ReplyErrorKind::Unavailable,
270+
Code::DataLoss => ReplyErrorKind::Internal,
271+
Code::Unauthenticated => ReplyErrorKind::Unauthenticated,
272+
Code::__NonExhaustive => ReplyErrorKind::Internal,
273+
};
274+
let extra = format!("{}::{}", request, source.to_string());
275+
ReplyError {
276+
kind,
277+
resource,
278+
source: "SvcError::GrpcRequestError".to_string(),
279+
extra,
280+
}
281+
}
282+
_ => unreachable!("Expected a GrpcRequestError!"),
283+
}
284+
}
285+
286+
/// Not enough resources available
287+
#[derive(Debug, Snafu)]
288+
#[allow(missing_docs)]
289+
pub enum NotEnough {
290+
#[snafu(display(
291+
"Not enough suitable pools available, {}/{}",
292+
have,
293+
need
294+
))]
295+
OfPools { have: u64, need: u64 },
296+
#[snafu(display("Not enough replicas available, {}/{}", have, need))]
297+
OfReplicas { have: u64, need: u64 },
298+
#[snafu(display("Not enough nexuses available, {}/{}", have, need))]
299+
OfNexuses { have: u64, need: u64 },
300+
}

0 commit comments

Comments
 (0)