rightsize_docker/
provider.rs1use rightsize::backend::{BackendProvider, SandboxBackend};
7use rightsize::error::Result;
8
9use crate::backend::DockerBackend;
10use crate::client::DockerClient;
11
12pub struct DockerBackendProvider;
17
18impl BackendProvider for DockerBackendProvider {
19 fn name(&self) -> &str {
20 "docker"
21 }
22
23 fn priority(&self) -> u32 {
24 10
25 }
26
27 fn is_supported(&self) -> bool {
28 blocking_ping(DockerClient::from_env().socket_path())
38 }
39
40 fn unsupported_reason(&self) -> String {
41 "no reachable Docker-API socket (Docker/Podman/Colima not running?)".to_string()
42 }
43
44 fn create(&self) -> Result<Box<dyn SandboxBackend>> {
45 Ok(Box::new(DockerBackend::connecting_to_env()))
46 }
47}
48
49fn blocking_ping(socket_path: &std::path::Path) -> bool {
53 use std::io::{Read, Write};
54 use std::os::unix::net::UnixStream;
55 use std::time::Duration;
56
57 let probe = || -> std::io::Result<bool> {
58 let mut stream = UnixStream::connect(socket_path)?;
59 stream.set_read_timeout(Some(Duration::from_secs(2)))?;
60 stream.set_write_timeout(Some(Duration::from_secs(2)))?;
61 stream.write_all(b"GET /_ping HTTP/1.1\r\nHost: docker\r\nConnection: close\r\n\r\n")?;
62 let mut response = Vec::new();
63 let _ = stream.read_to_end(&mut response);
64 let text = String::from_utf8_lossy(&response);
65 let status_line = text.lines().next().unwrap_or_default();
66 Ok(status_line
67 .split_whitespace()
68 .nth(1)
69 .and_then(|code| code.parse::<u16>().ok())
70 .map(|code| (200..300).contains(&code))
71 .unwrap_or(false))
72 };
73 probe().unwrap_or(false)
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn name_and_priority_are_pinned() {
82 let provider = DockerBackendProvider;
83 assert_eq!(provider.name(), "docker");
84 assert_eq!(provider.priority(), 10);
85 }
86
87 #[test]
88 fn unsupported_reason_names_the_daemon_socket() {
89 let provider = DockerBackendProvider;
90 let reason = provider.unsupported_reason();
91 assert!(reason.to_lowercase().contains("docker"));
92 }
93}