1
1
use anyhow:: { anyhow, Result } ;
2
2
use clap:: { App , Arg } ;
3
3
use docker_api:: api:: { ContainerCreateOpts , PullOpts , RmContainerOpts } ;
4
- use docker_api:: Docker ;
5
4
use futures_util:: { StreamExt , TryStreamExt } ;
5
+ use podman_api:: opts:: ContainerCreateOpts as PodmanContainerCreateOpts ;
6
+ use podman_api:: opts:: PullOpts as PodmanPullOpts ;
6
7
use std:: path:: PathBuf ;
7
8
use tar:: Archive ;
8
9
9
10
mod image;
11
+ mod runtime;
10
12
11
13
extern crate pretty_env_logger;
12
14
#[ macro_use]
13
15
extern crate log;
14
16
15
- const DOCKER_SOCKET : & str = "unix:///var/run/docker.sock" ;
16
17
pub const VERSION : & str = "0.2.1" ;
17
18
18
19
#[ derive( Debug ) ]
@@ -96,6 +97,7 @@ pub fn get_args() -> Result<Config> {
96
97
}
97
98
98
99
/// Run runs a sequence of events with the provided image
100
+ /// Run supports copying container filesystems running on both the docker and podman runtimes
99
101
/// 1. Pull down the image
100
102
/// 2. Create a container, receiving the container id as a response
101
103
/// 3. Copy the container content to the specified directory
@@ -105,8 +107,6 @@ pub async fn run(config: Config) -> Result<()> {
105
107
. parse_filters ( & config. log_level . clone ( ) )
106
108
. init ( ) ;
107
109
108
- let docker = Docker :: new ( DOCKER_SOCKET ) ?;
109
-
110
110
let image = image:: Image {
111
111
image : config. image . clone ( ) ,
112
112
} ;
@@ -125,42 +125,97 @@ pub async fn run(config: Config) -> Result<()> {
125
125
}
126
126
}
127
127
128
- let pull_opts = PullOpts :: builder ( ) . image ( repo) . tag ( tag) . build ( ) ;
129
- let images = docker. images ( ) ;
130
- let mut stream = images. pull ( & pull_opts) ;
128
+ let mut rt = runtime:: Runtime {
129
+ docker : & None ,
130
+ podman : & None ,
131
+ } ;
132
+ match runtime:: set ( ) {
133
+ Some ( docker) => rt = docker,
134
+ Some ( podman) => rt = podman,
135
+ None => {
136
+ error ! ( "❌ neither docker or podman sockets were found running on this host" ) ;
137
+ return Err ( anyhow ! ( "no valid container runtime" ) ) ;
138
+ }
139
+ } ;
140
+
141
+ if let Some ( docker) = rt. docker {
142
+ let pull_opts = PullOpts :: builder ( ) . image ( repo) . tag ( tag) . build ( ) ;
143
+ let images = docker. images ( ) ;
144
+ let mut stream = images. pull ( & pull_opts) ;
131
145
132
- while let Some ( pull_result) = stream. next ( ) . await {
133
- match pull_result {
134
- Ok ( output) => {
135
- debug ! ( "🔧 {:?}" , output) ;
146
+ while let Some ( pull_result) = stream. next ( ) . await {
147
+ match pull_result {
148
+ Ok ( output) => {
149
+ debug ! ( "🔧 {:?}" , output) ;
150
+ }
151
+ Err ( e) => {
152
+ error ! ( "❌ {}" , e) ;
153
+ }
136
154
}
137
- Err ( e) => {
138
- error ! ( "❌ {}" , e) ;
155
+ }
156
+ } else {
157
+ // TODO set tag
158
+ let pull_opts = PodmanPullOpts :: builder ( ) . reference ( repo) . build ( ) ;
159
+ let images = rt. podman . as_ref ( ) . unwrap ( ) . images ( ) ;
160
+ let mut stream = images. pull ( & pull_opts) ;
161
+
162
+ while let Some ( pull_result) = stream. next ( ) . await {
163
+ match pull_result {
164
+ Ok ( output) => {
165
+ debug ! ( "🔧 {:?}" , output) ;
166
+ }
167
+ Err ( e) => {
168
+ error ! ( "❌ {}" , e) ;
169
+ }
139
170
}
140
171
}
141
172
}
142
173
143
174
// note(tflannag): Use a "dummy" command "FROM SCRATCH" container images.
144
175
let cmd = vec ! [ "" ] ;
145
- let create_opts = ContainerCreateOpts :: builder ( config. image . clone ( ) )
146
- . cmd ( & cmd)
147
- . build ( ) ;
148
- let container = docker. containers ( ) . create ( & create_opts) . await ?;
149
- let id = container. id ( ) ;
150
- debug ! ( "📦 Created container with id: {:?}" , id) ;
176
+ let mut id = String :: new ( ) ;
177
+ if let Some ( docker) = rt. docker {
178
+ let create_opts = ContainerCreateOpts :: builder ( config. image . clone ( ) )
179
+ . cmd ( & cmd)
180
+ . build ( ) ;
181
+ let container = docker. containers ( ) . create ( & create_opts) . await ?;
182
+ id = container. id ( ) . to_string ( ) ;
183
+ debug ! ( "📦 Created container with id: {:?}" , id) ;
184
+ } else {
185
+ let create_opts = PodmanContainerCreateOpts :: builder ( )
186
+ . image ( config. image . clone ( ) )
187
+ . command ( & cmd)
188
+ . build ( ) ;
189
+ let container = rt. podman . as_ref ( ) . unwrap ( ) . containers ( ) . create ( & create_opts) . await ?;
190
+ id = container. id ;
191
+ debug ! ( "📦 Created container with id: {:?}" , id) ;
192
+ }
151
193
152
194
let mut content_path = PathBuf :: new ( ) ;
153
195
content_path. push ( & config. content_path ) ;
154
196
155
197
let mut download_path = PathBuf :: new ( ) ;
156
198
download_path. push ( & config. download_path ) ;
157
199
158
- let bytes = docker
159
- . containers ( )
160
- . get ( & * id)
161
- . copy_from ( & content_path)
162
- . try_concat ( )
163
- . await ?;
200
+ let mut bytes = Vec :: new ( ) ;
201
+ if let Some ( docker) = rt. docker {
202
+ bytes = docker
203
+ . containers ( )
204
+ . get ( & * id)
205
+ . copy_from ( & content_path)
206
+ . try_concat ( )
207
+ . await ?;
208
+ } else {
209
+ bytes = rt
210
+ . podman
211
+ . as_ref ( )
212
+ . unwrap ( )
213
+ . containers ( )
214
+ . get ( & * id)
215
+ . copy_from ( & content_path)
216
+ . try_concat ( )
217
+ . await ?;
218
+ }
164
219
165
220
let mut archive = Archive :: new ( & bytes[ ..] ) ;
166
221
if config. write_to_stdout {
@@ -174,12 +229,32 @@ pub async fn run(config: Config) -> Result<()> {
174
229
download_path. display( )
175
230
) ;
176
231
177
- let delete_opts = RmContainerOpts :: builder ( ) . force ( true ) . build ( ) ;
178
- if let Err ( e) = docker. containers ( ) . get ( & * id) . remove ( & delete_opts) . await {
179
- error ! ( "❌ Error cleaning up container {}" , e) ;
232
+ if let Some ( docker) = rt. docker {
233
+ let delete_opts = RmContainerOpts :: builder ( ) . force ( true ) . build ( ) ;
234
+ if let Err ( e) = docker. containers ( ) . get ( & * id) . remove ( & delete_opts) . await {
235
+ error ! ( "❌ Error cleaning up container {}" , e) ;
236
+ Ok ( ( ) )
237
+ } else {
238
+ debug ! ( "📦 Cleaned up container {:?} successfully" , id) ;
239
+ Ok ( ( ) )
240
+ }
241
+ } else {
242
+ match rt
243
+ . podman
244
+ . as_ref ( )
245
+ . unwrap ( )
246
+ . containers ( )
247
+ . prune ( & Default :: default ( ) )
248
+ . await
249
+ {
250
+ Ok ( _) => {
251
+ debug ! ( "📦 Cleaned up container {:?} successfully" , id) ;
252
+ Ok ( ( ) )
253
+ }
254
+ Err ( e) => {
255
+ eprintln ! ( "{}" , e) ;
256
+ Ok ( ( ) )
257
+ }
258
+ }
180
259
}
181
-
182
- debug ! ( "📦 Cleaned up container {:?} successfully" , id) ;
183
-
184
- Ok ( ( ) )
185
260
}
0 commit comments