Skip to content

Commit

Permalink
POC Trunk/OCI binary distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
theory committed Jun 11, 2024
1 parent 85db4db commit 22a728a
Show file tree
Hide file tree
Showing 6 changed files with 583 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ results/
*.dll
tmp/
*.o
*.bc
regression.diffs
regression.out
/sql/semver--?.??.?.sql
/semver-*
/latest-changes.md
/src/*.bc
/semver_binary_copy.bin
/.vscode
/*.bin
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ DISTVERSION = $(shell grep -m 1 '[[:space:]]\{3\}"version":' META.json | \
sed -e 's/[[:space:]]*"version":[[:space:]]*"\([^"]*\)",\{0,1\}/\1/')

MODULEDIR = $(EXTENSION)
DATA = $(wildcard sql/*.sql)
DESCRIPTION = A Postgres data type for the Semantic Version format with support for btree and hash indexing.
REPO_URL = https://github.com/theory/pg-semver
DATA = $(wildcard sql/*--*.sql) sql/$(EXTENSION)--$(EXTVERSION).sql
DOCS = $(wildcard doc/*.mmd)
TESTS = $(wildcard test/sql/*.sql)
REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
Expand All @@ -22,6 +24,7 @@ endif

PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
include ./trunk.mk

all: sql/$(EXTENSION)--$(EXTVERSION).sql

Expand Down
37 changes: 37 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
version: "3.9"
name: trunking

# Name the network for all of the services to join.
networks:
default:
name: pgxnnet

services:
zot:
image: ghcr.io/project-zot/zot-linux-arm64:latest
container_name: zot
ports:
- 5000:5000
hostname: zot

linux:
image: pgxn/pgxn-tools
platform: "linux/amd64"
container_name: linux
# stdin_open: true
# tty: true # Keep it running
working_dir: /work
volumes:
- ".:/work"
entrypoint:
- "/bin/sh"
- -ecx
- |
cd /tmp
curl -LO "https://github.com/oras-project/oras/releases/download/v1.2.0/oras_1.2.0_linux_amd64.tar.gz"
mkdir -p oras-install/
tar -zxf oras_1.2.0_*.tar.gz -C oras-install/
sudo mv oras-install/oras /usr/local/bin/
rm -rf oras_1.2.0_*.tar.gz oras-install/
pg-start 16 rsync jq
tail -f /dev/null
155 changes: 155 additions & 0 deletions install_trunk
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/bin/bash

# POC for installing Trunk format binaries created with trunk.mk. Requires:
#
# * bash
# * tar
# * shasum
# * jq
# * uname
# * pg_config
# * rsync

trap 'exit' ERR
set -E

install_trunk() {
local trunk=$1

if [ -z "$trunk" ]; then
printf "Usage:\n\n %s PACKAGE_PATH\n" "$0"
exit 1
fi

# Determine the platform.
local my_os my_osv my_arch platform
my_os=$(uname | tr '[:upper:]' '[:lower:]')
my_osv=$(uname -r)
my_arch="$(uname -m)"
if [ "$my_arch" == "x86_64" ]; then my_arch=amd64; fi
if [ "$my_os" == "darwin" ]; then
platform="$my_os/$my_arch:$my_osv"
else
platform="$my_os/$my_arch"
fi

# Fetch the file name.
local file
file=$(oras manifest fetch --plain-http --platform "$platform" "$trunk" | jq -r '.layers[0].annotations["org.opencontainers.image.title"]')

# Download.
oras pull --no-tty --plain-http --platform "$platform" "$trunk"

# Unpack.
printf "Unpacking %s\n" "$file"
tar zxf "$file"

# Go into the directory
local dir="${file%.*}"
cd "$dir" || exit

# Verify the checksums.
printf "Verifying all checksums..."
shasum --check -b --strict < digests
printf "Done!\n"

# Verify the Trunk version
printf "Verifying compatibility with Trunk package 0.1.0\n"
local tv
tv=$(jq -r .trunk trunk.json)
if [ "$tv" != "0.1.0" ]; then
printf "Unsupported Trunk format version %s\n" "$tv"
exit 1
fi

# Verify the Postgres version.
printf "Verifying compatibility with PostgreSQL %s\n" "$my_pg"
local pkg_pg my_pg
pkg_pg=$(jq -r .postgres.version trunk.json)
my_pg=$(pg_config --version | sed -E 's/^[^ ]+ ([^ ]+).*$/\1/')
if [ "$pkg_pg" != "$my_pg" ]; then
printf "Trunk package contains binaries for Postgres %s but this host runs Postgres %s\n" "$pkg_pg" "$my_pg"
exit 1
fi

printf "Verifying compatibility with %s/%s:%s \n" "$my_os" "$my_arch" "$my_osv"
local pkg_os
pkg_os=$(jq -r .platform.os trunk.json)
if [ "$pkg_os" != "any" ]; then
# Verify the OS
if [ "$pkg_os" != "$my_os" ]; then
printf "Trunk package contains %s binaries but this host runs %s\n" "$pkg_os" "$my_os"
exit 1
fi

# Verify the architecture.
local pkg_arch
pkg_arch=$(jq -r .platform.arch trunk.json)
if [ "$pkg_arch" != "$my_arch" ]; then
printf "Trunk package contains %s binaries but this host runs %s\n" "$pkg_arch" "$my_arch"
exit 1
fi
fi

# Make sure we have install directories.
if [ ! -d 'install' ]; then
printf "Package contains no install files; exiting\n"
exit 1
fi

cd 'install' || exit
for subdir in *; do
[[ -d "$subdir" ]] || continue
case $subdir in
share)
install_dir "$subdir" "$(pg_config --sharedir)"
;;
pkglib)
install_dir "$subdir" "$(pg_config --pkglibdir)"
;;
pkginclude)
install_dir "$subdir" "$(pg_config --pkgincludedir)"
;;
lib)
install_dir "$subdir" "$(pg_config --libdir)"
;;
include)
install_dir "$subdir" "$(pg_config --includedir)"
;;
bin)
install_dir "$subdir" "$(pg_config --bindir)"
;;
doc)
install_dir "$subdir" "$(pg_config --docdir)"
;;
man)
install_dir "$subdir" "$(pg_config --mandir)"
;;
html)
install_dir "$subdir" "$(pg_config --htmldir)"
;;
locale)
install_dir "$subdir" "$(pg_config --localedir)"
;;
sysconf)
install_dir "$subdir" "$(pg_config --sysconfdir)"
;;
*)
printf "Unknown install directory %s; skipping\n" "$subdir"
;;
esac
done

}

install_dir() {
local src="$1"
local dst="$2"
printf "Installing %s into %s..." "$src" "$dst"
cd "$src" || exit
rsync -q -a -v . "$dst" || exit
printf "Done\n"
cd ..
}

install_trunk "$@"
96 changes: 96 additions & 0 deletions push_trunk
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/bash

# POC for publishing Trunk packages to an OCI repository with an image index
# to allow pulling a platform-specific binary. Requires:
#
# * oras
# * jq
# * zot: docker run -d -p 5000:5000 --name oras-quickstart ghcr.io/project-zot/zot-linux-arm64:latest
#
# Inspired by the Homebrew implementation of the pattern as referenced in
# https://github.com/oras-project/oras/issues/237, and with thanks to the
# denizens of the #oras and #zot channels on the CNCF Slack.

set -e

# Onlyl testing semver for Darwin and Linux rn.
REPO=localhost:5000/theory/semver
LINUX_AMD64_TRUNK=semver-0.32.1+pg16-linux-amd64
DARWIN_ARM64_TRUNK=semver-0.32.1+pg16-darwin-arm64-23.5.0

# OCI types to create.
ARTIFACT_TYPE=application/vnd.pgxn.trunk.layer.v1
MEDIA_TYPE=application/vnd.oci.image.layer.v1.tar+gzip
CONFIG_TYPE=application/vnd.oci.image.config.v1+json
OCI_DIR=oci_dir
INDEX_FILE=image_index.json

# Push the Darwin image and grab the resulting digest.
DIGEST_DARWIN_ARM64=$(oras push --no-tty \
--oci-layout "$OCI_DIR" \
--artifact-type "${ARTIFACT_TYPE}" \
--config "${DARWIN_ARM64_TRUNK}_config.json":"$CONFIG_TYPE" \
--format go-template='{{.digest}}' \
--annotation-file "${DARWIN_ARM64_TRUNK}_annotations.json" \
"$DARWIN_ARM64_TRUNK.trunk":"$MEDIA_TYPE"
)

# Push the Linux image and grab the resulting digest.
DIGEST_LINUX_AMD64=$(oras push --no-tty \
--oci-layout "$OCI_DIR" \
--artifact-type "${ARTIFACT_TYPE}" \
--config "${LINUX_AMD64_TRUNK}_config.json":"$CONFIG_TYPE" \
--format go-template='{{.digest}}' \
--annotation-file "${LINUX_AMD64_TRUNK}_annotations.json" \
"$LINUX_AMD64_TRUNK.trunk":"$MEDIA_TYPE"
)


# Create the image manifest for Darwin.
trunk_anno=$(jq -c '.["$manifest"] | with_entries(select(.key | startswith("org.pgxn.trunk.")))' "${DARWIN_ARM64_TRUNK}_annotations.json")
DARWIN_ARM64_MANIFEST=$(oras manifest fetch --oci-layout "$OCI_DIR@${DIGEST_DARWIN_ARM64}" --pretty --descriptor | jq --argjson anno "$trunk_anno" '{
mediaType: .mediaType,
size: .size,
digest: .digest,
platform: {
architecture: "arm64",
os: "darwin",
"os.version": "23.5.0"
},
annotations: $anno
}')

# Create the image manifest for Linux.
trunk_anno=$(jq -c '.["$manifest"] | with_entries(select(.key | startswith("org.pgxn.trunk.")))' "${LINUX_AMD64_TRUNK}_annotations.json")
LINUX_AMD64_MANIFEST=$(oras manifest fetch --oci-layout "$OCI_DIR@${DIGEST_LINUX_AMD64}" --pretty --descriptor | jq --argjson anno "$trunk_anno" '{
mediaType: .mediaType,
size: .size,
digest: .digest,
platform: {
architecture: "amd64",
os: "linux"
},
annotations: $anno
}')

# Write out the resulting image index.
jq -n --argjson amd64 "$LINUX_AMD64_MANIFEST" --argjson arm64 "$DARWIN_ARM64_MANIFEST" --argjson annotations "$(cat semver_annotations.json)" '{
schemaVersion: 2,
mediaType: "application/vnd.oci.image.index.v1+json",
manifests: [$amd64, $arm64],
annotations: $annotations
}' > "$INDEX_FILE"

# Push the image index to the registry
oras manifest push --oci-layout ./"$OCI_DIR":image-index "$INDEX_FILE"

# View the local manifest
#oras manifest get --pretty --oci-layout ./"$OCI_DIR":image-index

# Push the index and artifacts to the registry
oras cp --from-oci-layout ./"$OCI_DIR":image-index --to-plain-http "${REPO}:v1"

# View the remote image index manifest.
oras manifest get --plain-http "${REPO}:v1" | jq

rm -rf "$OCI_DIR" "$INDEX_FILE"
Loading

0 comments on commit 22a728a

Please sign in to comment.