---
name: eocube-storage-cli
description: "Move data in and out of EOCube S3 object storage from a notebook terminal or a laptop: eocube auth and STS credentials, eocube services storage ls, upload, download, rm, share and check, the primary versus personal endpoints, path-style addressing, the MinIO client, and bulk STAC asset download."
license: Apache-2.0
compatibility: "EOCube.RO JupyterHub notebooks (notebooks.eocube.ro) and laptops with `pip install eocube[cli]`; `mcli` is preinstalled in the notebook image."
---

## Two endpoints, one region

| Storage | Endpoint | Use |
|---|---|---|
| Primary | https://storage.svc.uvt-01.eocube.ro | Shared and published datasets. |
| Personal | https://s3.svc.uvt-01.eocube.ro | The user's own bucket. |

Region `ro-west-uvt-01`, path-style addressing (`AWS_VIRTUAL_HOSTING=FALSE`). Access is
decided by the user's SSO roles and groups; credentials are short-lived STS tokens.

## Identity and credentials

```bash
eocube auth info                      # who am I, which context
eocube auth login                     # browser flow; add --device-flow on a headless host
eocube auth get-storage-credentials --as-json --duration 3600
eocube auth get-storage-credentials --endpoint https://s3.svc.uvt-01.eocube.ro --as-json
```

Inside notebook pods `AWS_*` variables are already injected and renewed by the hub; mint
credentials only for other tools or other machines. When anything returns 403, run
`eocube doctor` before debugging further.

## Everyday transfers

```bash
eocube services storage ls                        # root of the default backend
eocube services storage ls --user -l shared/      # personal bucket, long listing
eocube services storage ls --recursive --json prefix/
eocube services storage upload local.tif remote/prefix/local.tif
eocube services storage upload --user local.tif prefix/local.tif
eocube services storage download remote/prefix/local.tif ./local.tif --force
eocube services storage share remote/prefix/local.tif --expires 24h
eocube services storage rm remote/prefix/old.tif --yes
eocube services storage check --write-probe
```

- `--user` targets the personal bucket; `--backend <name>` picks a configured storage.
- `share` prints a presigned URL; it stops working at `--expires` or when the signing
  credentials end, whichever comes first.
- `rm` is irreversible: list first, confirm with the user, then delete.

From an agent, `storage_ls` (MCP) is the quick read-only listing; uploads and downloads
are CLI or Python (`fs` / `user_fs` from `eocube.integrations.notebooks`).

## Bulk download of a STAC search

```bash
eocube services stac search --collections <collection-id> --county Arad --json > dataset.json
eocube services stac download dataset.json --destination ./data --roles data --workers 4
```

`--dry-run` shows the plan and sizes first; `--assets <name>` picks specific assets;
interrupted downloads resume. The sidecar MCP server has no download tool.

## MinIO client for large or recursive jobs

```bash
eval "$(eocube auth get-storage-credentials --as-json | python -c '
import json,sys; c=json.load(sys.stdin)
print(f"AK={c[\"AccessKeyId\"]} SK={c[\"SecretAccessKey\"]} ST={c[\"SessionToken\"]}")')"
mcli alias set eocube https://storage.svc.uvt-01.eocube.ro "$AK" "$SK" --api S3v4 --path on
mcli ls eocube/<bucket>/
mcli mirror ./out eocube/<bucket>/<prefix>/
```

Inspect the JSON field names with `--as-json` first; set the session token with
`MC_HOST_eocube` or re-run `alias set` when it rotates. Any S3 client works with the same
endpoint, region and path-style setting (`s3cmd`, `aws s3 --endpoint-url`, `s3fs`).

## Pitfalls

- Virtual-hosted addressing (`bucket.storage.svc...`) does not resolve; always path-style.
- Credentials from `get-storage-credentials` expire after `--duration` seconds (default
  3600); scripts must re-mint.
- Writing into a bucket you can only read fails with 403; `eocube doctor` and
  `storage check --write-probe` tell you which.
- Never `rm` recursively under a user's home or bucket without an explicit, confirmed list.
