diff --git a/README.md b/README.md index 8945274..cb8dc74 100644 --- a/README.md +++ b/README.md @@ -58,15 +58,15 @@ By default, dcp will copy content to the current directory `.`. For example, let try issuing the following command: ``` -$ dcp tyslaton/sample-catalog:v0.0.4 -p configs +$ dcp tyslaton/sample-catalog:v0.0.4 -c configs ``` -This command will copy the `configs` directory (specified via the `-p` flag) from the image to the current directory. +This command will copy the `configs` directory (specified via the `c` flag) from the image to the current directory. For further configuration, lets try: ``` -$ dcp tyslaton/sample-catalog:v0.0.4 -d output -p configs +$ dcp tyslaton/sample-catalog:v0.0.4 -d output -c configs ``` This command pulls down the requested image, only extracting @@ -76,9 +76,22 @@ locally (specified via the `-d` flag). Another example, for copying only the manifests directory: ``` -$ dcp quay.io/tflannag/bundles:resolveset-v0.0.2 -p manifests +$ dcp quay.io/tflannag/bundles:resolveset-v0.0.2 -c manifests ``` +Lastly, we can reference a private registry by providing a username +and password (specified via the `-u` and `-p` flags). + +``` +$ dcp quay.io/tyslaton/sample-catalog-private:latest -u -p +``` + +**Note**: This serves as a convenient way to connect to private +registries but is insecure locally as your credentials are saved in +your shell's history. If you would like to remain completely secure then +login via ` login` and pull the image locally. `dcp` +will then be able to notice the image locally pulled and process it. + ## Testing If you would like to run the test suite, you just need to run the standard cargo command. This will run all relevant diff --git a/src/lib.rs b/src/lib.rs index 1ba2f63..72fdd28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,10 @@ use anyhow::{anyhow, Result}; use clap::{App, Arg}; -use docker_api::api::{ContainerCreateOpts, PullOpts, RmContainerOpts}; +use docker_api::api::{ContainerCreateOpts, PullOpts, RegistryAuth, RmContainerOpts}; use futures_util::{StreamExt, TryStreamExt}; use podman_api::opts::ContainerCreateOpts as PodmanContainerCreateOpts; use podman_api::opts::PullOpts as PodmanPullOpts; +use podman_api::opts::RegistryAuth as PodmanRegistryAuth; use std::path::PathBuf; use tar::Archive; @@ -28,6 +29,10 @@ pub struct Config { write_to_stdout: bool, // What level of logs to output log_level: String, + // Username for singing into a private registry + username: String, + // Password for signing into a private registry + password: String, } pub fn get_args() -> Result { @@ -53,7 +58,7 @@ pub fn get_args() -> Result { Arg::with_name("content-path") .value_name("CONTENT-PATH") .help("Where in the container filesystem the content to extract is") - .short("p") + .short("c") .default_value("/") .long("content-path"), ) @@ -65,6 +70,24 @@ pub fn get_args() -> Result { .short("w") .long("write-to-stdout"), ) + .arg( + Arg::with_name("username") + .value_name("USERNAME") + .help("Username used for singing into a private registry.") + .short("u") + .long("username") + .default_value(""), + + ) + .arg( + Arg::with_name("password") + .value_name("PASSWORD") + .help("Password used for signing into a private registry. * WARNING *: Writing credentials to your terminal is risky. Be sure you are okay with them showing up in your history") + .short("p") + .long("password") + .default_value(""), + + ) .arg( Arg::with_name("log-level") .value_name("LOG-LEVEL") @@ -80,6 +103,9 @@ pub fn get_args() -> Result { let content_path = matches.value_of("content-path").unwrap().to_string(); let write_to_stdout = matches.is_present("write-to-stdout"); let log_level = matches.value_of("log-level").unwrap().to_string(); + // TODO (tyslaton): Need to come up with a way for this to be extracted from the docker config to be more secure locally. + let username = matches.value_of("username").unwrap().to_string(); + let password = matches.value_of("password").unwrap().to_string(); if write_to_stdout { return Err(anyhow!( @@ -93,6 +119,8 @@ pub fn get_args() -> Result { content_path, write_to_stdout, log_level, + username, + password, }) } @@ -132,7 +160,12 @@ pub async fn run(config: Config) -> Result<()> { }; if let Some(docker) = &rt.docker { - let pull_opts = PullOpts::builder().image(repo).tag(tag).build(); + let auth = RegistryAuth::builder() + .username(config.username) + .password(config.password) + .build(); + let pull_opts = PullOpts::builder().image(repo).tag(tag).auth(auth).build(); + let images = docker.images(); let mut stream = images.pull(&pull_opts); @@ -147,8 +180,13 @@ pub async fn run(config: Config) -> Result<()> { } } } else { + let auth = PodmanRegistryAuth::builder() + .username(config.username) + .password(config.password) + .build(); let pull_opts = PodmanPullOpts::builder() .reference(config.image.clone().trim()) + .auth(auth) .build(); let images = rt.podman.as_ref().unwrap().images(); let mut stream = images.pull(&pull_opts);