Skip to content

Commit 216af80

Browse files
committed
feat(cli): virtual_host S3 addressing in athena.toml
Add `[artifact_repository.s3] virtual_host` (bool, default false = path-style, what MinIO / most S3-compatible stores want). When true the CLI's object_store client uses virtual-hosted-style requests; resolved to a bool on S3Ref so publish / submit / emulate use one style for the binary tarball and load/save_artifact objects alike. CLI-side only for now: the in-pod Argo executor auto-detects until upstream Argo exposes the toggle on its S3 artifact. Regenerates the describe/ls metadata goldens (S3Ref's bool); emitted WorkflowTemplate YAML is unchanged.
1 parent 76dd83c commit 216af80

6 files changed

Lines changed: 44 additions & 6 deletions

File tree

crates/cargo-athena-core/src/lib.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,13 @@ pub struct S3Repo {
680680
pub region: String,
681681
#[serde(default)]
682682
pub insecure: bool,
683+
/// `true` for virtual-hosted-style addressing (`https://<bucket>.<endpoint>/<key>`)
684+
/// instead of the default path-style (`https://<endpoint>/<bucket>/<key>`).
685+
/// Default false (path-style): what MinIO and most S3-compatible stores
686+
/// want. CLI-side only for now; the in-pod Argo executor auto-detects
687+
/// until upstream Argo exposes the toggle on its S3 artifact.
688+
#[serde(default)]
689+
pub virtual_host: bool,
683690
pub access_key_secret: SecretRef,
684691
pub secret_key_secret: SecretRef,
685692
}
@@ -884,6 +891,13 @@ pub struct S3Ref {
884891
pub region: String,
885892
pub insecure: bool,
886893
pub key: String,
894+
/// Virtual-hosted-style addressing (else path-style). A provider-wide
895+
/// property of the configured repo, carried here so the CLI's S3
896+
/// client uses one addressing style for the binary tarball and for
897+
/// `load`/`save_artifact!` objects alike. `#[serde(default)]`: absent
898+
/// in metadata from an older binary reads as false (path-style).
899+
#[serde(default)]
900+
pub virtual_host: bool,
887901
}
888902

889903
impl S3Ref {
@@ -899,6 +913,7 @@ impl S3Ref {
899913
region: repo.region.clone(),
900914
insecure: repo.insecure,
901915
key,
916+
virtual_host: repo.virtual_host,
902917
}
903918
}
904919
}
@@ -1057,7 +1072,7 @@ impl ContainerRunMeta {
10571072
/// Derive the runner metadata from one built Argo template.
10581073
/// `input_types` is parallel to the template's input parameters
10591074
/// (same order); empty when unknown.
1060-
fn from_template(t: &api::Template, input_types: &[&str]) -> Self {
1075+
fn from_template(t: &api::Template, input_types: &[&str], virtual_host: bool) -> Self {
10611076
let kind = if t.container.is_some() {
10621077
"container"
10631078
} else if t.dag.is_some() || !t.steps.is_empty() {
@@ -1082,6 +1097,10 @@ impl ContainerRunMeta {
10821097
region: s.region.clone(),
10831098
insecure: s.insecure,
10841099
key: s.key.clone(),
1100+
// The emitted Argo artifact doesn't carry an addressing
1101+
// style; the configured repo's setting (threaded in)
1102+
// applies to every object in that repo.
1103+
virtual_host,
10851104
},
10861105
path: a.path.clone(),
10871106
})
@@ -2418,7 +2437,11 @@ pub fn entrypoint_impl<E: Template>(
24182437
.map(|b| {
24192438
let t = b(&ctx);
24202439
let it = collector.types.get(&t.name).copied().unwrap_or(&[]);
2421-
let mut m = ContainerRunMeta::from_template(&t, it);
2440+
let mut m = ContainerRunMeta::from_template(
2441+
&t,
2442+
it,
2443+
ctx.config().artifact_repository.s3.virtual_host,
2444+
);
24222445
m.package = krate.to_string();
24232446
m.synthetic = collector.synthetic.contains(&t.name);
24242447
m
@@ -2451,7 +2474,11 @@ pub fn entrypoint_impl<E: Template>(
24512474
.unwrap_or_else(|| panic!("no template named {name:?} (or {full:?})"));
24522475
let resolved = tpl.name.clone();
24532476
let input_types = collector.types.get(&resolved).copied().unwrap_or(&[]);
2454-
let mut meta = ContainerRunMeta::from_template(&tpl, input_types);
2477+
let mut meta = ContainerRunMeta::from_template(
2478+
&tpl,
2479+
input_types,
2480+
ctx.config().artifact_repository.s3.virtual_host,
2481+
);
24552482
meta.package = krate.to_string();
24562483
meta.synthetic = collector.synthetic.contains(&resolved);
24572484
println!(

crates/cargo-athena/src/emulate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,10 @@ pub(crate) fn s3_store(s3: &S3Ref) -> object_store::aws::AmazonS3 {
727727
let mut b = AmazonS3Builder::new()
728728
.with_bucket_name(&s3.bucket)
729729
.with_region(&s3.region)
730+
// Path-style by default (object_store's default, what MinIO and
731+
// most S3-compatible stores want); virtual-hosted when the repo
732+
// config opts in via `[artifact_repository.s3] virtual_host`.
733+
.with_virtual_hosted_style_request(s3.virtual_host)
730734
.with_allow_http(s3.insecure);
731735
// `AWS_ENDPOINT_URL` (AWS-SDK standard) overrides the config
732736
// endpoint — needed when S3 is reached differently from here than

docs/src/configuration.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,15 @@ template as an Argo `s3{}` artifact source.
4747
| `bucket` | Bucket name. |
4848
| `region` | S3 region. |
4949
| `insecure` | `true` for plain HTTP (e.g. local MinIO). |
50+
| `virtual_host` | `true` for virtual-hosted-style addressing (`https://<bucket>.<endpoint>/<key>`). Default `false` = path-style (`https://<endpoint>/<bucket>/<key>`), which MinIO and most S3-compatible stores want. See note below. |
5051
| `access_key_secret` / `secret_key_secret` | Kubernetes `{ name, key }` secret selectors for credentials. |
5152

53+
> `virtual_host` currently steers the **`cargo athena` CLI's** S3 client
54+
> only (`publish` / `submit` / `emulate`). In-pod, Argo's executor
55+
> auto-detects the addressing style, so set it on a provider that needs
56+
> virtual-hosted and confirm your cluster's Argo reaches the bucket the
57+
> same way. Leave it unset (path-style) for MinIO and the common case.
58+
5259
The binary tarball's object key is `{crate}/<tag>/{bin}.tar.gz`, where
5360
`<tag>` is the build-time [version tag](cli.md#versioning) - the kebab of
5461
your crate's semver on a clean release build (`1.2.3` -> `1-2-3`), or
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"name":"cargo-athena-example-smoke-fetch","package":"cargo-athena-example-smoke","kind":"container","synthetic":false,"image":"ghcr.io/acme/fetch:1.2.3","command":["/bin/sh","-c"],"args":["set -e\ncase \"$(uname -m)\" in\n x86_64) __t=x86_64-unknown-linux-musl ;;\n aarch64|arm64) __t=aarch64-unknown-linux-musl ;;\n *) echo \"athena: unsupported arch $(uname -m)\" >&2; exit 1 ;;\nesac\nchmod +x /athena/bin/app-$__t\nexport CARGO_ATHENA_OUTPUT=/athena/result\nexec /athena/bin/app-$__t \"$@\"\n","--","{{inputs.parameters.url}}"],"work_dir":"/athena","params":[{"name":"url","ty":"String"}],"binary_artifact":{"s3":{"endpoint":"s3.amazonaws.com","bucket":"athena-artifacts","region":"us-east-1","insecure":false,"key":"cargo-athena-example-smoke/0-0-0/smoke-ns.tar.gz"},"path":"/athena/bin"},"input_artifacts":[],"output_artifacts":[],"host_paths":["/secrets/token"],"result_path":"/athena/result"}
1+
{"name":"cargo-athena-example-smoke-fetch","package":"cargo-athena-example-smoke","kind":"container","synthetic":false,"image":"ghcr.io/acme/fetch:1.2.3","command":["/bin/sh","-c"],"args":["set -e\ncase \"$(uname -m)\" in\n x86_64) __t=x86_64-unknown-linux-musl ;;\n aarch64|arm64) __t=aarch64-unknown-linux-musl ;;\n *) echo \"athena: unsupported arch $(uname -m)\" >&2; exit 1 ;;\nesac\nchmod +x /athena/bin/app-$__t\nexport CARGO_ATHENA_OUTPUT=/athena/result\nexec /athena/bin/app-$__t \"$@\"\n","--","{{inputs.parameters.url}}"],"work_dir":"/athena","params":[{"name":"url","ty":"String"}],"binary_artifact":{"s3":{"endpoint":"s3.amazonaws.com","bucket":"athena-artifacts","region":"us-east-1","insecure":false,"key":"cargo-athena-example-smoke/0-0-0/smoke-ns.tar.gz","virtual_host":false},"path":"/athena/bin"},"input_artifacts":[],"output_artifacts":[],"host_paths":["/secrets/token"],"result_path":"/athena/result"}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"name":"cargo-athena-example-smoke-pipeline-ns","package":"cargo-athena-example-smoke","kind":"workflow","synthetic":false,"image":"","command":[],"args":[],"work_dir":"/athena","params":[{"name":"env","ty":"String"}],"binary_artifact":null,"input_artifacts":[],"output_artifacts":[],"host_paths":[],"result_path":null},{"name":"cargo-athena-example-smoke-fetch","package":"cargo-athena-example-smoke","kind":"container","synthetic":false,"image":"ghcr.io/acme/fetch:1.2.3","command":["/bin/sh","-c"],"args":["set -e\ncase \"$(uname -m)\" in\n x86_64) __t=x86_64-unknown-linux-musl ;;\n aarch64|arm64) __t=aarch64-unknown-linux-musl ;;\n *) echo \"athena: unsupported arch $(uname -m)\" >&2; exit 1 ;;\nesac\nchmod +x /athena/bin/app-$__t\nexport CARGO_ATHENA_OUTPUT=/athena/result\nexec /athena/bin/app-$__t \"$@\"\n","--","{{inputs.parameters.url}}"],"work_dir":"/athena","params":[{"name":"url","ty":"String"}],"binary_artifact":{"s3":{"endpoint":"s3.amazonaws.com","bucket":"athena-artifacts","region":"us-east-1","insecure":false,"key":"cargo-athena-example-smoke/0-0-0/smoke-ns.tar.gz"},"path":"/athena/bin"},"input_artifacts":[],"output_artifacts":[],"host_paths":["/secrets/token"],"result_path":"/athena/result"},{"name":"cargo-athena-example-smoke-transform","package":"cargo-athena-example-smoke","kind":"container","synthetic":false,"image":"busybox:1.36-musl","command":["/bin/sh","-c"],"args":["set -e\ncase \"$(uname -m)\" in\n x86_64) __t=x86_64-unknown-linux-musl ;;\n aarch64|arm64) __t=aarch64-unknown-linux-musl ;;\n *) echo \"athena: unsupported arch $(uname -m)\" >&2; exit 1 ;;\nesac\nchmod +x /athena/bin/app-$__t\nexport CARGO_ATHENA_OUTPUT=/athena/result\nexec /athena/bin/app-$__t \"$@\"\n","--","{{inputs.parameters.data}}","{{inputs.parameters.factor}}"],"work_dir":"/athena","params":[{"name":"data","ty":"String"},{"name":"factor","ty":"i64"}],"binary_artifact":{"s3":{"endpoint":"s3.amazonaws.com","bucket":"athena-artifacts","region":"us-east-1","insecure":false,"key":"cargo-athena-example-smoke/0-0-0/smoke-ns.tar.gz"},"path":"/athena/bin"},"input_artifacts":[],"output_artifacts":[],"host_paths":[],"result_path":"/athena/result"}]
1+
[{"name":"cargo-athena-example-smoke-pipeline-ns","package":"cargo-athena-example-smoke","kind":"workflow","synthetic":false,"image":"","command":[],"args":[],"work_dir":"/athena","params":[{"name":"env","ty":"String"}],"binary_artifact":null,"input_artifacts":[],"output_artifacts":[],"host_paths":[],"result_path":null},{"name":"cargo-athena-example-smoke-fetch","package":"cargo-athena-example-smoke","kind":"container","synthetic":false,"image":"ghcr.io/acme/fetch:1.2.3","command":["/bin/sh","-c"],"args":["set -e\ncase \"$(uname -m)\" in\n x86_64) __t=x86_64-unknown-linux-musl ;;\n aarch64|arm64) __t=aarch64-unknown-linux-musl ;;\n *) echo \"athena: unsupported arch $(uname -m)\" >&2; exit 1 ;;\nesac\nchmod +x /athena/bin/app-$__t\nexport CARGO_ATHENA_OUTPUT=/athena/result\nexec /athena/bin/app-$__t \"$@\"\n","--","{{inputs.parameters.url}}"],"work_dir":"/athena","params":[{"name":"url","ty":"String"}],"binary_artifact":{"s3":{"endpoint":"s3.amazonaws.com","bucket":"athena-artifacts","region":"us-east-1","insecure":false,"key":"cargo-athena-example-smoke/0-0-0/smoke-ns.tar.gz","virtual_host":false},"path":"/athena/bin"},"input_artifacts":[],"output_artifacts":[],"host_paths":["/secrets/token"],"result_path":"/athena/result"},{"name":"cargo-athena-example-smoke-transform","package":"cargo-athena-example-smoke","kind":"container","synthetic":false,"image":"busybox:1.36-musl","command":["/bin/sh","-c"],"args":["set -e\ncase \"$(uname -m)\" in\n x86_64) __t=x86_64-unknown-linux-musl ;;\n aarch64|arm64) __t=aarch64-unknown-linux-musl ;;\n *) echo \"athena: unsupported arch $(uname -m)\" >&2; exit 1 ;;\nesac\nchmod +x /athena/bin/app-$__t\nexport CARGO_ATHENA_OUTPUT=/athena/result\nexec /athena/bin/app-$__t \"$@\"\n","--","{{inputs.parameters.data}}","{{inputs.parameters.factor}}"],"work_dir":"/athena","params":[{"name":"data","ty":"String"},{"name":"factor","ty":"i64"}],"binary_artifact":{"s3":{"endpoint":"s3.amazonaws.com","bucket":"athena-artifacts","region":"us-east-1","insecure":false,"key":"cargo-athena-example-smoke/0-0-0/smoke-ns.tar.gz","virtual_host":false},"path":"/athena/bin"},"input_artifacts":[],"output_artifacts":[],"host_paths":[],"result_path":"/athena/result"}]

0 commit comments

Comments
 (0)