talos_api_rs/resources/
logs.rs1use crate::api::generated::machine::LogsRequest as ProtoLogsRequest;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum ContainerDriver {
12 #[default]
14 Containerd,
15 Cri,
17}
18
19impl From<ContainerDriver> for i32 {
20 fn from(driver: ContainerDriver) -> Self {
21 match driver {
22 ContainerDriver::Containerd => 0,
23 ContainerDriver::Cri => 1,
24 }
25 }
26}
27
28impl std::fmt::Display for ContainerDriver {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 ContainerDriver::Containerd => write!(f, "containerd"),
32 ContainerDriver::Cri => write!(f, "cri"),
33 }
34 }
35}
36
37#[derive(Debug, Clone, Default)]
39pub struct LogsRequest {
40 pub namespace: String,
42 pub id: String,
44 pub driver: ContainerDriver,
46 pub follow: bool,
48 pub tail_lines: i32,
50}
51
52impl LogsRequest {
53 #[must_use]
55 pub fn new(id: impl Into<String>) -> Self {
56 Self {
57 namespace: String::new(),
58 id: id.into(),
59 driver: ContainerDriver::Containerd,
60 follow: false,
61 tail_lines: 0,
62 }
63 }
64
65 #[must_use]
67 pub fn with_namespace(namespace: impl Into<String>, id: impl Into<String>) -> Self {
68 Self {
69 namespace: namespace.into(),
70 id: id.into(),
71 driver: ContainerDriver::Containerd,
72 follow: false,
73 tail_lines: 0,
74 }
75 }
76
77 #[must_use]
79 pub fn builder(id: impl Into<String>) -> LogsRequestBuilder {
80 LogsRequestBuilder::new(id)
81 }
82}
83
84impl From<LogsRequest> for ProtoLogsRequest {
85 fn from(req: LogsRequest) -> Self {
86 Self {
87 namespace: req.namespace,
88 id: req.id,
89 driver: req.driver.into(),
90 follow: req.follow,
91 tail_lines: req.tail_lines,
92 }
93 }
94}
95
96#[derive(Debug, Clone)]
98pub struct LogsRequestBuilder {
99 namespace: String,
100 id: String,
101 driver: ContainerDriver,
102 follow: bool,
103 tail_lines: i32,
104}
105
106impl LogsRequestBuilder {
107 #[must_use]
109 pub fn new(id: impl Into<String>) -> Self {
110 Self {
111 namespace: String::new(),
112 id: id.into(),
113 driver: ContainerDriver::Containerd,
114 follow: false,
115 tail_lines: 0,
116 }
117 }
118
119 #[must_use]
121 pub fn namespace(mut self, namespace: impl Into<String>) -> Self {
122 self.namespace = namespace.into();
123 self
124 }
125
126 #[must_use]
128 pub fn driver(mut self, driver: ContainerDriver) -> Self {
129 self.driver = driver;
130 self
131 }
132
133 #[must_use]
135 pub fn follow(mut self, follow: bool) -> Self {
136 self.follow = follow;
137 self
138 }
139
140 #[must_use]
142 pub fn tail(mut self, lines: i32) -> Self {
143 self.tail_lines = lines;
144 self
145 }
146
147 #[must_use]
149 pub fn build(self) -> LogsRequest {
150 LogsRequest {
151 namespace: self.namespace,
152 id: self.id,
153 driver: self.driver,
154 follow: self.follow,
155 tail_lines: self.tail_lines,
156 }
157 }
158}
159
160#[derive(Debug, Clone)]
162pub struct LogsResponse {
163 data: Vec<u8>,
165 pub node: Option<String>,
167}
168
169impl LogsResponse {
170 #[must_use]
172 pub fn new(data: Vec<u8>, node: Option<String>) -> Self {
173 Self { data, node }
174 }
175
176 #[must_use]
178 pub fn as_bytes(&self) -> &[u8] {
179 &self.data
180 }
181
182 pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
184 std::str::from_utf8(&self.data)
185 }
186
187 #[must_use]
189 pub fn as_string_lossy(&self) -> std::borrow::Cow<'_, str> {
190 String::from_utf8_lossy(&self.data)
191 }
192
193 #[must_use]
195 pub fn len(&self) -> usize {
196 self.data.len()
197 }
198
199 #[must_use]
201 pub fn is_empty(&self) -> bool {
202 self.data.is_empty()
203 }
204
205 #[must_use]
207 pub fn lines(&self) -> Vec<&str> {
208 self.as_str()
209 .map(|s| s.lines().collect())
210 .unwrap_or_default()
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_logs_request_new() {
220 let req = LogsRequest::new("kubelet");
221 assert_eq!(req.id, "kubelet");
222 assert!(req.namespace.is_empty());
223 assert!(!req.follow);
224 }
225
226 #[test]
227 fn test_logs_request_with_namespace() {
228 let req = LogsRequest::with_namespace("system", "kubelet");
229 assert_eq!(req.namespace, "system");
230 assert_eq!(req.id, "kubelet");
231 }
232
233 #[test]
234 fn test_logs_request_builder() {
235 let req = LogsRequest::builder("etcd")
236 .namespace("system")
237 .driver(ContainerDriver::Cri)
238 .follow(true)
239 .tail(100)
240 .build();
241
242 assert_eq!(req.id, "etcd");
243 assert_eq!(req.namespace, "system");
244 assert_eq!(req.driver, ContainerDriver::Cri);
245 assert!(req.follow);
246 assert_eq!(req.tail_lines, 100);
247 }
248
249 #[test]
250 fn test_container_driver() {
251 assert_eq!(i32::from(ContainerDriver::Containerd), 0);
252 assert_eq!(i32::from(ContainerDriver::Cri), 1);
253 assert_eq!(ContainerDriver::Cri.to_string(), "cri");
254 }
255
256 #[test]
257 fn test_proto_conversion() {
258 let req = LogsRequest::builder("kubelet")
259 .follow(true)
260 .tail(50)
261 .build();
262
263 let proto: ProtoLogsRequest = req.into();
264 assert_eq!(proto.id, "kubelet");
265 assert!(proto.follow);
266 assert_eq!(proto.tail_lines, 50);
267 }
268}