Skip to content

Commit

Permalink
Merge pull request #40 from tylerslaton/private-docker-registry
Browse files Browse the repository at this point in the history
feat: add support for private docker registries
  • Loading branch information
exdx authored Aug 14, 2022
2 parents 1d3388e + e7cc9d6 commit 61b7f8b
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 7 deletions.
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 <username> -p <password>
```

**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 `<container_runtime> 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
Expand Down
44 changes: 41 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<Config> {
Expand All @@ -53,7 +58,7 @@ pub fn get_args() -> Result<Config> {
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"),
)
Expand All @@ -65,6 +70,24 @@ pub fn get_args() -> Result<Config> {
.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")
Expand All @@ -80,6 +103,9 @@ pub fn get_args() -> Result<Config> {
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!(
Expand All @@ -93,6 +119,8 @@ pub fn get_args() -> Result<Config> {
content_path,
write_to_stdout,
log_level,
username,
password,
})
}

Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down

0 comments on commit 61b7f8b

Please sign in to comment.