Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/mods-and-plugins/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,26 @@ GENERIC_PACKS_SUFFIX=.zip

would expand to `https://cdn.example.org/configs-v9.0.1.zip,https://cdn.example.org/mods-v4.3.6.zip`.

### Generic packs from an OCI registry

An entry can also reference a pack stored as an [OCI](https://opencontainers.org/) artifact in a container registry by prefixing it with `oci://`. The reference may use a tag or an immutable `@sha256:` digest:

```
GENERIC_PACKS=oci://ghcr.io/itzg/oci-modpack-template/tech:latest,oci://ghcr.io/itzg/oci-modpack-template/magic:latest
```

OCI, URL, and local-path entries can be mixed in the same list and are applied in the order given. Each artifact's layers are pulled into a content-addressed cache under `/data/packs/oci`, so a digest already on disk (for example a base layer shared between packs) is not downloaded again. `GENERIC_PACKS_PREFIX`/`GENERIC_PACKS_SUFFIX`, `GENERIC_PACKS_DISABLE_MODS`, and the update/checksum behaviour below all apply to OCI entries exactly as they do to URLs.

The artifact must be a Minecraft modpack artifact (artifact type `application/vnd.itzg.minecraft.modpack.v1+json` with `…modpack.layer.v1.tar+gzip` layers); any other reference is rejected before its contents touch `/data`. Validation and registry authentication are handled by `mc-image-helper`.

For a private registry, point `GENERIC_PACKS_OCI_AUTH_FILE` at a registry login file (the `auth.json`/`config.json` produced by `docker login`, `podman login`, etc.):

```
GENERIC_PACKS_OCI_AUTH_FILE=/run/secrets/registry-auth.json
```

When it is unset, a credentials file at `~/.config/containers/auth.json` or `~/.docker/config.json` is used if present, otherwise the pull is anonymous.

If applying large generic packs, the update can be time-consuming. To skip the update set `SKIP_GENERIC_PACK_UPDATE_CHECK` to "true". Conversely, the generic pack(s) can be forced to be applied by setting `FORCE_GENERIC_PACK_UPDATE` to "true".

The most time-consuming portion of the generic pack update is generating and comparing the SHA1 checksum. To skip the checksum generation, set `SKIP_GENERIC_PACK_CHECKSUM` to "true".
Expand Down
33 changes: 32 additions & 1 deletion scripts/start-setupModpack
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,38 @@ function handleGenericPacks() {
packFiles=()
for packEntry in "${packs[@]}"; do
pack="${GENERIC_PACKS_PREFIX}${packEntry}${GENERIC_PACKS_SUFFIX}"
if isURL "${pack}"; then
if isOCIRef "${pack}"; then
# All OCI refs share one staging dir so layers common to multiple
# sibling artifacts (the point of layered distribution) are pulled
# exactly once across all of GENERIC_PACKS.
mkdir -p /data/packs/oci /data/.tmp
log "Pulling OCI generic pack from $pack"
# A list file is used rather than stdout because mc-image-helper INFO
# logs share that stream; it holds one absolute layer path per line in
# apply order.
layerListFile=$(mktemp -p /data/.tmp)
ociArgs=(install-oci-pack
--ref "$pack"
--output-directory /data/packs/oci
--filename-strategy digest
--layer-list-file "$layerListFile")
if [[ "${GENERIC_PACKS_OCI_AUTH_FILE:-}" ]]; then
ociArgs+=(--auth-file "${GENERIC_PACKS_OCI_AUTH_FILE}")
fi
if ! mc-image-helper "${ociArgs[@]}"; then
logError "Failed to pull OCI generic pack $pack"
logError "(OCI generic packs require mc-image-helper with install-oci-pack support)"
rm -f "$layerListFile"
exit 2
fi
mapfile -t ociLayers < "$layerListFile"
rm -f "$layerListFile"
if [ ${#ociLayers[@]} -eq 0 ]; then
logError "OCI generic pack $pack resolved to zero layers"
exit 2
fi
packFiles+=("${ociLayers[@]}")
elif isURL "${pack}"; then
mkdir -p /data/packs
log "Downloading generic pack from $pack"
if ! outfile=$(get -o /data/packs --output-filename --skip-up-to-date "$pack"); then
Expand Down
6 changes: 6 additions & 0 deletions scripts/start-utils
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ function isURL() {
[[ $value =~ ^(https?|ftp):// ]]
}

function isOCIRef() {
local value=$1

[[ $value =~ ^oci:// ]]
}

function isValidFileURL() {
suffix=${1:?Missing required suffix arg}
url=${2:?Missing required url arg}
Expand Down
18 changes: 18 additions & 0 deletions tests/setuponlytests/generic-packs-oci/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
services:
mc:
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
environment:
EULA: "true"
SETUP_ONLY: "true"
# two OCI packs that share a common base layer; the shared blob is
# pulled into /data/packs/oci once and reused for the second pack
GENERIC_PACKS: oci://ghcr.io/itzg/oci-modpack-template/tech:latest,oci://ghcr.io/itzg/oci-modpack-template/magic:latest
LOG_TIMESTAMP: "true"
# the following are only used to speed up test execution
TYPE: CUSTOM
CUSTOM_SERVER: /servers/fake.jar
VERSION: 1.18.1
DEBUG: "true"
volumes:
- ./data:/data
- ./fake.jar:/servers/fake.jar
Empty file.
1 change: 1 addition & 0 deletions tests/setuponlytests/generic-packs-oci/require.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[[ $EXTENDED_TESTS ]] || exit 1
7 changes: 7 additions & 0 deletions tests/setuponlytests/generic-packs-oci/verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set -e
# OCI layers were cached
[ -d /data/packs/oci ]
compgen -G "/data/packs/oci/sha256:*" > /dev/null
# pack content was extracted and applied to /data
[ -d /data/mods ]
compgen -G "/data/mods/*" > /dev/null