mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-31 13:03:02 +02:00
confd: add support for fetching container images over ftp/http/https
- Anonymous FTP, or URL encoded ftp://user:hostname@addr/oci.tar.gz - HTTP/HTTPS fetched with curl, optional credentials support - Verify download against an optional sha256 checksum Ensure the unpacked directory name does not contain a ':', it is a restricted character and cannot be part of the file name. If this syntax is used we retain it as the name and retag it after load. Fix #801 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
DOWNLOADS=/var/lib/containers/oci
|
||||
BUILTIN=/lib/oci
|
||||
checksum=""
|
||||
all=""
|
||||
env=""
|
||||
port=""
|
||||
@@ -10,6 +12,72 @@ log()
|
||||
logger -I $PPID -t container -p local1.notice -- "$*"
|
||||
}
|
||||
|
||||
check()
|
||||
{
|
||||
file=$1
|
||||
|
||||
if [ -z "$checksum" ]; then
|
||||
log "no checksum to verify $file against, continuing."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if echo "${checksum} ${file}" | "$cmdsum" -c -s; then
|
||||
log "$file checksum verified OK."
|
||||
return 0
|
||||
fi
|
||||
|
||||
got=$("$cmdsum" "${file}" | awk '{print $1}')
|
||||
log "$file checksum mismatch, got $got, expected $checksum, removing file."
|
||||
rm -f "$file"
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Fetch an OCI image over ftp/http/https. Use wget for FTP, which curl
|
||||
# empirically does not work well with. Log progress+ & error to syslog.
|
||||
fetch()
|
||||
{
|
||||
url=$1
|
||||
file=$(basename "$url")
|
||||
dst="$DOWNLOADS/$file"
|
||||
|
||||
cd "$DOWNLOADS" || return
|
||||
if [ -e "$file" ]; then
|
||||
log "$file already available."
|
||||
if check "$file"; then
|
||||
echo "$dst"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Fetching $url"
|
||||
|
||||
if echo "$url" | grep -qE "^ftp://"; then
|
||||
cmd="wget -q $url"
|
||||
elif echo "$url" | grep -qE "^https?://"; then
|
||||
cmd="curl $creds -sSL --fail -o \"$file\" $url"
|
||||
else
|
||||
log "Unsupported URL scheme: $url"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if out=$(eval "$cmd" 2>&1); then
|
||||
log "$file downloaded successfully."
|
||||
if check "$file"; then
|
||||
echo "$dst"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# log error message from backend
|
||||
while IFS= read -r line; do
|
||||
log "$line"
|
||||
done <<EOF
|
||||
$out
|
||||
EOF
|
||||
return 1
|
||||
}
|
||||
|
||||
# Unpacks a given oci-archive.tar[.gz] in the current directory. Sanity
|
||||
# checks, at least one index.json in the top-level dir of the archive.
|
||||
# If there are more index files, this function does not handle them.
|
||||
@@ -26,6 +94,11 @@ unpack_archive()
|
||||
oci-archive:*) # Packed OCI image, .tar or .tar.gz format
|
||||
file=${image#oci-archive:}
|
||||
;;
|
||||
ftp://* | http://* | https://*)
|
||||
if ! file=$(fetch "$image"); then
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*) # docker://*, docker-archive:*, or URL
|
||||
echo "$image"
|
||||
return 0
|
||||
@@ -33,10 +106,10 @@ unpack_archive()
|
||||
esac
|
||||
|
||||
if [ ! -e "$file" ]; then
|
||||
if [ -e "/var/lib/containers/oci/$file" ]; then
|
||||
file="/var/lib/containers/oci/$file"
|
||||
elif [ -e "/lib/oci/$file" ]; then
|
||||
file="/lib/oci/$file"
|
||||
if [ -e "$DOWNLOADS/$file" ]; then
|
||||
file="$DOWNLOADS/$file"
|
||||
elif [ -e "$BUILTIN/$file" ]; then
|
||||
file="$BUILTIN/$file"
|
||||
else
|
||||
log "Error: cannot find OCI archive $file in search path."
|
||||
exit 1
|
||||
@@ -58,10 +131,18 @@ unpack_archive()
|
||||
|
||||
[ -n "$quiet" ] || log "Extracting OCI archive $file ..."
|
||||
tar xf "$file" || (log "Error: failed unpacking $file in $(pwd)"; exit 1)
|
||||
remove=true
|
||||
fi
|
||||
|
||||
dir=$(dirname "$index")
|
||||
if echo "$dir" | grep -q ":"; then
|
||||
if [ -z "$name" ]; then
|
||||
name="$dir"
|
||||
fi
|
||||
sanitized_dir=$(echo "$dir" | cut -d':' -f1)
|
||||
mv "$dir" "$sanitized_dir" || (log "Error: failed renaming $dir to $sanitized_dir"; exit 1)
|
||||
dir="$sanitized_dir"
|
||||
fi
|
||||
|
||||
[ -n "$quiet" ] || log "Loading OCI image $dir ..."
|
||||
podman load -qi "$dir" >/dev/null
|
||||
|
||||
@@ -73,10 +154,6 @@ unpack_archive()
|
||||
name=$dir
|
||||
fi
|
||||
|
||||
if [ "$remove" = "true" ]; then
|
||||
rm -rf "$file"
|
||||
fi
|
||||
|
||||
echo "$name"
|
||||
}
|
||||
|
||||
@@ -102,7 +179,9 @@ create()
|
||||
|
||||
# Unpack and load docker-archive/oci/oci-archive, returning image
|
||||
# name, or return docker:// URL for download.
|
||||
image=$(unpack_archive "$image")
|
||||
if ! image=$(unpack_archive "$image"); then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$logging" ]; then
|
||||
logging="--log-driver k8s-file --log-opt path=/run/containers/$name.fifo"
|
||||
@@ -247,6 +326,7 @@ options:
|
||||
--dns-search LIST Set host lookup search list when creating container
|
||||
--cap-add CAP Add capability to unprivileged container
|
||||
--cap-drop CAP Drop capability, for privileged containter
|
||||
--checksum TYPE:SUM Use md5/sha256/sha512 to verify ftp/http/https archives
|
||||
-c, --creds USR[:PWD] Credentials to pass to curl -u for remote ops
|
||||
-d, --detach Detach a container started with 'run IMG [CMD]'
|
||||
-e, --env FILE Environment variables when creating container
|
||||
@@ -306,6 +386,25 @@ while [ "$1" != "" ]; do
|
||||
shift
|
||||
caps="$caps --cap-drop=$1"
|
||||
;;
|
||||
--checksum)
|
||||
shift
|
||||
type="${1%%:*}"
|
||||
checksum="${1#*:}"
|
||||
case "$type" in
|
||||
md5)
|
||||
cmdsum=md5sum
|
||||
;;
|
||||
sha256)
|
||||
cmdsum=sha256sum
|
||||
;;
|
||||
sha512)
|
||||
cmdsum=sha512sum
|
||||
;;
|
||||
*)
|
||||
err 1 "Unsupported checksum type: $type"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-c | --creds)
|
||||
shift
|
||||
creds="-u $1"
|
||||
@@ -350,7 +449,6 @@ while [ "$1" != "" ]; do
|
||||
--log-path)
|
||||
shift
|
||||
logging="$logging --log-opt path=$1"
|
||||
log_path="$1"
|
||||
;;
|
||||
-m | --mount)
|
||||
shift
|
||||
@@ -455,25 +553,12 @@ case $cmd in
|
||||
usage
|
||||
;;
|
||||
load)
|
||||
url=$1
|
||||
name=$2
|
||||
# shellcheck disable=SC2086
|
||||
if echo "$url" | grep -q "://"; then
|
||||
file=$(basename "$url")
|
||||
curl -k $creds -Lo "$file" "$url"
|
||||
else
|
||||
file="$url"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
name=$(unpack_archive "$file" $name)
|
||||
name=$(unpack_archive "$1" $2)
|
||||
[ -n "$name" ] || exit 1
|
||||
|
||||
# Show resulting image(s) matching $name
|
||||
if [ -n "$name" ]; then
|
||||
podman images -n "$name"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
podman images -n "$name"
|
||||
;;
|
||||
locate) # Find where the host's ifname lives
|
||||
if [ -z "$network" ]; then
|
||||
@@ -500,7 +585,7 @@ case $cmd in
|
||||
podman images $all --format "{{.Repository}}:{{.Tag}}"
|
||||
;;
|
||||
oci)
|
||||
find /lib/oci /var/lib/containers/oci -type f 2>/dev/null
|
||||
find $BUILTIN $DOWNLOADS -type f 2>/dev/null
|
||||
;;
|
||||
*)
|
||||
podman ps $all --format "{{.Names}}"
|
||||
|
||||
@@ -175,6 +175,16 @@ static int add(const char *name, struct lyd_node *cif)
|
||||
if (lydx_is_enabled(cif, "manual"))
|
||||
fprintf(fp, " --manual");
|
||||
|
||||
node = lydx_get_descendant(lyd_child(cif), "checksum", NULL);
|
||||
if (node) {
|
||||
if ((string = lydx_get_cattr(node, "md5")))
|
||||
fprintf(fp, " --checksum md5:%s", string);
|
||||
if ((string = lydx_get_cattr(node, "sha256")))
|
||||
fprintf(fp, " --checksum sha256:%s", string);
|
||||
if ((string = lydx_get_cattr(node, "sha512")))
|
||||
fprintf(fp, " --checksum sha512:%s", string);
|
||||
}
|
||||
|
||||
fprintf(fp, " create %s %s", name, image);
|
||||
|
||||
if ((string = lydx_get_cattr(cif, "command")))
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# REMEMBER TO UPDATE infix-interfaces ALSO IN confd.inc
|
||||
MODULES=(
|
||||
"infix-interfaces@2024-11-12.yang -e vlan-filtering -e containers"
|
||||
"infix-containers@2024-10-14.yang"
|
||||
"infix-containers@2024-11-15.yang"
|
||||
)
|
||||
|
||||
@@ -26,24 +26,26 @@ module infix-containers {
|
||||
prefix infix-sys;
|
||||
}
|
||||
|
||||
revision 2024-11-12 {
|
||||
description "Deprecate read-only, it is now always true.";
|
||||
revision 2024-11-15 {
|
||||
description "Two major changes:
|
||||
- Add support for ftp/http/https images with checksum
|
||||
- Deprecate read-only, it is now always true";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2024-10-14 {
|
||||
revision 2024-10-14 {
|
||||
description "Two major changes:
|
||||
- Allow changing name of host interfaces inside container
|
||||
- Support hostname format specifiers, like ietf-system";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2024-03-27 {
|
||||
revision 2024-03-27 {
|
||||
description "Add support for capabilities.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2024-02-01 {
|
||||
revision 2024-02-01 {
|
||||
description "Initial revision";
|
||||
reference "internal";
|
||||
}
|
||||
@@ -138,6 +140,13 @@ module infix-containers {
|
||||
oci-archive:/lib/oci/archive -- Use archive:latest from OCI archive
|
||||
May be in .tar or .tar.gz format
|
||||
|
||||
Additionally, the following URIs are also supported for setups
|
||||
that do not use a HUB or similar. Recommend using 'checksum'!
|
||||
|
||||
ftp://addr/path/to/archive -- Downloaded using wget
|
||||
http://addr/path/to/archive -- Downloaded using curl
|
||||
https://addr/path/to/archive -- Downloaded using curl
|
||||
|
||||
Note: if a remote repository cannot be reached, the creation of the
|
||||
container will be put on a queue that retries pull every time
|
||||
there is a route change in the host's system.";
|
||||
@@ -145,6 +154,35 @@ module infix-containers {
|
||||
type string;
|
||||
}
|
||||
|
||||
container checksum {
|
||||
description "Checksum for ftp/http/https OCI archives.";
|
||||
choice checksum {
|
||||
leaf md5 {
|
||||
description "MD5 checksum for the archive.";
|
||||
type string {
|
||||
length "32";
|
||||
pattern "[a-fA-F0-9]{32}";
|
||||
}
|
||||
}
|
||||
|
||||
leaf sha256 {
|
||||
description "SHA256 checksum for the archive.";
|
||||
type string {
|
||||
length "64";
|
||||
pattern "[a-fA-F0-9]{64}";
|
||||
}
|
||||
}
|
||||
|
||||
leaf sha512 {
|
||||
description "SHA512 checksum for the archive.";
|
||||
type string {
|
||||
length "128";
|
||||
pattern "[a-fA-F0-9]{128}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf image-id {
|
||||
description "Docker image ID, exact hash used.";
|
||||
config false;
|
||||
|
||||
@@ -75,11 +75,15 @@
|
||||
<COMMAND name="creds" help="Credentials for remote access">
|
||||
<PARAM name="creds" ptype="/STRING" help="username[:password]"/>
|
||||
</COMMAND>
|
||||
<COMMAND name="checksum" help="Checksum to verify against (SHA56)">
|
||||
<PARAM name="sha" ptype="/STRING" help="SHA256"/>
|
||||
</COMMAND>
|
||||
</SWITCH>
|
||||
<ACTION sym="script" in="tty" out="tty" interrupt="true">
|
||||
creds=${KLISH_PARAM_creds:+-c $KLISH_PARAM_creds}
|
||||
sha=${KLISH_PARAM_sha:+--checksum $KLISH_PARAM_sha}
|
||||
cd /var/lib/containers/oci
|
||||
doas container $creds load $KLISH_PARAM_url $KLISH_PARAM_name
|
||||
doas container $creds $sha load $KLISH_PARAM_url $KLISH_PARAM_name
|
||||
</ACTION>
|
||||
</COMMAND>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user