podman_api/api/
exec.rs

1use crate::{
2    conn::{tty, Headers, Payload},
3    opts, Result, Value,
4};
5
6use containers_api::url;
7
8#[derive(Debug)]
9/// [Api Reference](https://docs.podman.io/en/latest/_static/api.html?version=v4.3.1#tag/Exec)
10pub struct Exec {
11    podman: crate::Podman,
12    id: crate::Id,
13    is_tty: bool,
14    is_unchecked: bool,
15}
16
17impl Exec {
18    ///Exports an interface exposing operations against a Exec instance with TTY
19    pub(crate) fn new_tty(podman: crate::Podman, id: impl Into<crate::Id>) -> Self {
20        Exec {
21            podman,
22            id: id.into(),
23            is_tty: true,
24            is_unchecked: false,
25        }
26    }
27
28    ///Exports an interface exposing operations against a Exec instance without TTY
29    pub(crate) fn new_raw(podman: crate::Podman, id: impl Into<crate::Id>) -> Self {
30        Exec {
31            podman,
32            id: id.into(),
33            is_tty: false,
34            is_unchecked: false,
35        }
36    }
37
38    ///Exports an interface exposing operations against a Exec instance with unchecked TTY state
39    pub(crate) fn new_unchecked(podman: crate::Podman, id: impl Into<crate::Id>) -> Self {
40        Exec {
41            podman,
42            id: id.into(),
43            is_tty: false,
44            is_unchecked: true,
45        }
46    }
47
48    ///A getter for Exec id
49    pub fn id(&self) -> &crate::Id {
50        &self.id
51    }
52}
53
54#[derive(Debug)]
55/// Handle for Podman Execs.
56pub struct Execs {
57    podman: crate::Podman,
58}
59
60impl Execs {
61    ///Exports an interface for interacting with Podman Execs.
62    pub fn new(podman: crate::Podman) -> Self {
63        Execs { podman }
64    }
65
66    ///Returns a reference to a set of operations available to a specific Exec.
67    pub fn get(&self, id: impl Into<crate::Id>) -> Exec {
68        Exec::new_unchecked(self.podman.clone(), id)
69    }
70}
71
72impl Exec {
73    api_doc! {
74    Exec => StartLibpod
75    |
76    /// Starts a previously set up exec instance. If `detach` is true, this endpoint returns
77    /// immediately after starting the command. Otherwise, it sets up an interactive session
78    /// with the command.
79    ///
80    /// To create an exec instance use [`Container::create_exec`](crate::api::Container::create_exec).
81    ///
82    /// Examples:
83    ///
84    /// ```no_run
85    /// async {
86    ///     use podman_api::Podman;
87    ///     use futures_util::StreamExt;
88    ///     let podman = Podman::unix("/run/user/1000/podman/podman.sock");
89    ///     let container = podman.containers().get("451b27c6b9d3");
90    ///
91    ///     let exec = container
92    ///         .create_exec(
93    ///             &podman_api::opts::ExecCreateOpts::builder()
94    ///                 .command(["cat", "/some/path/in/container"])
95    ///                 .build(),
96    ///         )
97    ///         .await
98    ///         .unwrap();
99    ///
100    ///     let opts = Default::default();
101    ///     let mut stream = exec.start(&opts).await.unwrap().unwrap();
102    ///
103    ///     while let Some(chunk) = stream.next().await {
104    ///         println!("{:?}", chunk.unwrap());
105    ///     }
106    /// };
107    /// ```
108    pub async fn start<'exec>(
109        &'exec self,
110        opts: &'exec opts::ExecStartOpts,
111    ) -> Result<Option<tty::Multiplexer<'exec>>> {
112        if self.is_unchecked {
113            return Err(crate::Error::UncheckedExec);
114        }
115
116        let ep = format!("/libpod/exec/{}/start", &self.id);
117
118        let payload = Payload::Json(
119            opts.serialize()
120                .map_err(|e| crate::conn::Error::Any(Box::new(e)))?,
121        );
122
123        let detach = opts.params.get("Detach").and_then(|value| value.as_bool()).unwrap_or(false);
124
125        if !detach {
126            self.podman.post_upgrade_stream(ep, payload).await.map(|x| {
127                if self.is_tty {
128                    Some(tty::Multiplexer::new(x, tty::decode_raw))
129                } else {
130                    Some(tty::Multiplexer::new(x, tty::decode_chunk))
131                }
132            })
133        } else {
134            self.podman.post(ep, payload, None).await.map(|_| None)
135        }
136    }}
137
138    api_doc! {
139    Exec => InspectLibpod
140    |
141    /// Returns low-level information about an exec instance.
142    ///
143    /// Examples:
144    ///
145    /// ```no_run
146    /// async {
147    ///     use podman_api::Podman;
148    ///     use futures_util::StreamExt;
149    ///     let podman = Podman::unix("/run/user/1000/podman/podman.sock");
150    ///     let container = podman.containers().get("451b27c6b9d3");
151    ///
152    ///     let exec = container
153    ///         .create_exec(
154    ///             &podman_api::opts::ExecCreateOpts::builder()
155    ///                 .command(["cat", "/some/path/in/container"])
156    ///                 .build(),
157    ///         )
158    ///         .await
159    ///         .unwrap();
160    ///
161    ///     match exec.inspect().await {
162    ///         Ok(info) => println!("{:?}", info),
163    ///         Err(e) => eprintln!("{}", e)
164    ///     }
165    /// };
166    /// ```
167    pub async fn inspect(&self) -> Result<Value> {
168        let ep = format!("/libpod/exec/{}/json", &self.id);
169        self.podman.get_json(&ep).await
170    }}
171
172    api_doc! {
173    Exec => ResizeLibpod
174    |
175    /// Resize the TTY session used by an exec instance. This endpoint only works if
176    /// tty was specified as part of creating and starting the exec instance.
177    ///
178    /// Examples:
179    ///
180    /// ```no_run
181    /// use futures_util::StreamExt;
182    /// async {
183    ///     use podman_api::Podman;
184    ///     let podman = Podman::unix("/run/user/1000/podman/podman.sock");
185    ///     let container = podman.containers().get("451b27c6b9d3");
186    ///
187    ///     let exec = container
188    ///         .create_exec(
189    ///             &podman_api::opts::ExecCreateOpts::builder()
190    ///                 .command(["cat", "/some/path/in/container"])
191    ///                 .build(),
192    ///         )
193    ///         .await
194    ///         .unwrap();
195    ///
196    ///     if let Err(e) = exec.resize(1280, 720).await {
197    ///         eprintln!("{}", e);
198    ///     }
199    /// };
200    /// ```
201    pub async fn resize(&self, width: usize, heigth: usize) -> Result<()> {
202        let ep = url::construct_ep(
203            format!("/libpod/exec/{}/resize", &self.id),
204            Some(url::encoded_pairs([
205                ("h", heigth.to_string()),
206                ("w", width.to_string()),
207            ])),
208        );
209        self.podman.post(&ep, Payload::None::<&str>, Headers::none()).await.map(|_| ())
210    }}
211}