Files
meta-arm/meta-arm-autonomy/classes/docker_extern_containers.bbclass
T
Nathan Dunne 1682eb1f44 arm-autonomy/containers: Allow multiple docker images to be included
Added docker_extern_containers bbclass that installs external docker images
that have been exported. The import-docker-image recipe has been renamed to
import-docker-containers and updated to install a new init script that imports
all of the docker containers when the image boots. The new init script now
attempts to start the docker daemon if it is not already running.

Issue-Id: SCM-1811
Signed-off-by: Nathan Dunne <Nathan.Dunne@arm.com>
Change-Id: Icd8222775ca9f640856a4ad4b51b18de17e5680d
Signed-off-by: Jon Mason <jon.mason@arm.com>
2021-03-11 09:26:19 -05:00

237 lines
9.6 KiB
Plaintext

#
# This class allows docker image tarballs to be installed in the rootfs
#
# The images can be selected using the variable CONTAINER_IMAGE_FILES
# which should contain a space seperated list of absolute paths or yocto urls
# for docker images that have been exported using docker export:
# - https://docs.docker.com/engine/reference/commandline/export/
#
# There are 4 supported formats for CONTAINER_IMAGE_FILES entries:
#
# - http/https url
# - CONTAINER_IMAGE_FILES = "https://[url]:[port]/alpine.tar;md5sum=..."
# - Note that a checksum (md5sum or sha256sum) must be provided for http(s)
#
# - file:// absolute local path from root
# - CONTAINER_IMAGE_FILES = "file:///containers/alpine2.tar"
# - In this case the filename will be added to SRC_URI and the path from '/'
# added to FILESEXTRAPATHS
#
# - file:// path relative to FILESEXTRAPATHS
# - CONTAINER_IMAGE_FILES = "file://foo/alpine3.tar"
# FILESEXTRAPATHS .= "/containers:"
# - In this case the filename will be added to SRC_URI and the preceding path
# added to FILESOVERRIDES, so that the full path to the container file will
# be available in FILESPATH when it is generated by combining
# FILESEXTRAPATHS and FILESOVERRIDES.
#
# - plain absolute local path from root
# - CONTAINER_IMAGE_FILES = "/containers/foo/bar/alpine4.tar"
# - This will be treated the same as an file:// path from root. Plain paths
# must be absolute, and cannot be relative to FILESEXTRAPATHS
#
# It is not recommended to use other yocto URL types, as they may result in
# undefined behaviour.
#
# A semicolon seperated list of extra parameters can follow each image path:
# - conname : the name that will be attached when the image is imported
# (default: [filename, without extension])
# - contag : the tag that will be attached when the image is imported
# (default: local)
# - conkeep : Flag for whether the exported container image file should be
# kept once the import has been completed
# (default: 0)
#
# e.g.
# CONTAINER_IMAGE_FILES = "\
# https://[url]:[port]/alpine.tar;md5sum=[checksum];conkeep=1 \
# file:///containers/alpine2.tar;contag=latest;conname=docker2 \
# file://foo/alpine3.tar \
# /containers/foo/bar/alpine4.tar;contag=1.0;conkeep=1 \
# "
#
# Resulting Manifest:
# ARCHIVE NAME TAG KEEP
# alpine.tar alpine local 1
# alpine2.tar docker2 latest 0
# alpine3.tar alpine3 local 0
# alpine4.tar alpine4 1.0 1
#
# Other configurable variables:
# CONTAINERS_INSTALL_DIR : The folder underneath where the docker
# images will be stored
# (default: "/usr/share/docker/images")
# CONTAINERS_MANIFEST : The name of the manifest file containing image
# parameters, also stored in CONTAINERS_INSTALL_DIR
# (default: "containers.manifest")
# CONTAINERS_TAG_DEFAULT : Use this to change the value that will be used as
# contag if no value is provided
# (default: "local")
# CONTAINERS_KEEP_DEFAULT : Use this to change the value that will be used for
# conkeep if no value is provided
# (default: "0")
#
# CONTAINERS_SRC_URI_EXTRA_PARAMS : Additional parameters that are added to all
# container entries in SRC_URI.
# (default: "")
inherit features_check
REQUIRED_DISTRO_FEATURES = "docker"
RDEPENDS_${PN} = "packagegroup-docker-runtime-minimal"
CONTAINER_IMAGE_FILES ??= ""
CONTAINERS_INSTALL_DIR ?= "${datadir}/docker/images"
CONTAINERS_MANIFEST ?= "containers.manifest"
CONTAINERS_TAG_DEFAULT ??= "local"
CONTAINERS_KEEP_DEFAULT ??= "0"
CONTAINERS_SRC_URI_EXTRA_PARAMS ?= ""
# Always make sure the tar files are not extracted
CONTAINERS_SRC_URI_EXTRA_PARAMS_append = ";unpack=0;subdir=containers"
# Parse the CONTAINER_IMAGE_FILES variable and add entries to SRC_URI
# complete with all parameters. Default values are added if no value
# is provided
#
# The variables FILESEXTRAPATHS and FILESOVERRIDES are use to prevent the
# fetcher from re-creating the local directory structure underneath
# ${WORKDIR}/containers, so that all exported images can be found in one
# directory
python __anonymous() {
import re
# Patterns for identifying parameters
containerfile_pattern = re.compile(r"^([^;]+);")
containername_pattern = re.compile(r";conname=([^;]+);?")
containertag_pattern = re.compile(r";contag=([^;]+);?")
containerkeep_pattern = re.compile(r";conkeep=([10]);?")
container_files = d.getVar('CONTAINER_IMAGE_FILES')
# Skip if no container files are provided
if not container_files:
raise bb.parse.SkipRecipe("CONTAINER_IMAGE_FILES is empty!")
# Parse each entry of the variable
for entry in container_files.split():
if entry.startswith('/'):
# Simple absolute local filepath specified
conname = "local"
contag = d.getVar('CONTAINERS_TAG_DEFAULT')
conkeep = d.getVar('CONTAINERS_KEEP_DEFAULT')
# retrieve parameter values if they are provided
f = containerfile_pattern.search(entry)
n = containername_pattern.search(entry)
t = containertag_pattern.search(entry)
k = containerkeep_pattern.search(entry)
if f:
entry = f.group(1)
if n:
conname = n.group(1)
else:
# get filename for default conname
conname = os.path.splitext(os.path.basename(entry))[0]
if t:
contag = t.group(1)
if k:
conkeep = k.group(1)
entry = os.path.realpath(entry)
if not os.path.exists(entry):
raise bb.parse.SkipRecipe("CONTAINER_IMAGE_FILES entry does not exist: \n" + entry)
filedir, filename = os.path.split(entry)
d.appendVar('SRC_URI', ' file://' + filename + ';' + \
d.getVar('CONTAINERS_SRC_URI_EXTRA_PARAMS') + \
';conname=' + conname + \
';contag=' + contag + \
';conkeep=' + conkeep \
)
# Prevent local fetcher from re-creating dir structure
d.appendVar('FILESEXTRAPATHS', filedir+':')
else:
# Yocto url with fetcher prefix
type = path = parm = None
try:
type, _, path, _, _, parm = bb.fetch.decodeurl(entry)
except:
raise bb.parse.SkipRecipe("CONTAINER_IMAGE_FILES contains an invalid entry: " + entry)
src_uri_entry_suffix = ';' + d.getVar('CONTAINERS_SRC_URI_EXTRA_PARAMS')
# default container name is filename without extension
if not 'conname' in parm:
conname = os.path.splitext(os.path.basename(path))[0]
src_uri_entry_suffix += ';conname=' + conname
# Set other default values if they are missing
if not 'contag' in parm:
src_uri_entry_suffix += ';contag=' + d.getVar('CONTAINERS_TAG_DEFAULT')
if not 'conkeep' in parm:
src_uri_entry_suffix += ';conkeep=' + d.getVar('CONTAINERS_KEEP_DEFAULT')
# Type specifc operations
if type.startswith('http'):
# Ensure http(s) urls have an md5sum or sha256
if not ( 'md5sum' in parm or 'sha256sum' in parm ):
raise bb.parse.SkipRecipe("CONTAINER_IMAGE_FILES entry is missing a checksum, provide either md5sum or sha256sum to resolve:\n" + entry)
if type == 'file':
# Prevent local fetcher from re-creating dir structure
filename_params = os.path.split(entry)[1]
filedir = os.path.split(path)[0]
if filedir.startswith('/'):
# Path is from the root
d.appendVar('FILESEXTRAPATHS', filedir + ':')
else:
# Path is relative to FILESEXTRAPATHS
d.appendVar('FILESOVERRIDES', ':' + filedir)
# Add filename and params to SRC_URI
d.appendVar('SRC_URI', ' file://' + filename_params + src_uri_entry_suffix)
else:
# Add full entry to SRC_URI
d.appendVar('SRC_URI', ' ' + entry + src_uri_entry_suffix)
}
# Create manifest file based on SRC_URI params
python containers_manifest() {
condir = d.getVar('WORKDIR') + "/containers"
with open (os.path.join(condir, d.getVar('CONTAINERS_MANIFEST')), 'w') as manfile:
# Parse SRC_URI for files with ;conname= parameter
src_uri = d.getVar('SRC_URI')
for entry in src_uri.split():
_, _, path, _, _, parm = bb.fetch.decodeurl(entry)
if 'conname' in parm:
dstname = os.path.basename(path)
manfile.write(dstname + " " + parm['conname'] + " " + \
parm['contag'] + " " + parm['conkeep'] + '\n'
)
}
# Read manifest and install container images
do_install() {
local archive name tag keep
install -d "${D}${CONTAINERS_INSTALL_DIR}"
install -m 644 "${WORKDIR}/containers/${CONTAINERS_MANIFEST}" "${D}${CONTAINERS_INSTALL_DIR}"
while read -r archive name tag keep _; do
[ -f "${WORKDIR}/containers/${archive}" ] || bbfatal "${archive} does not exist"
install -m 644 "${WORKDIR}/containers/${archive}" "${D}${CONTAINERS_INSTALL_DIR}"
done < "${WORKDIR}/containers/${CONTAINERS_MANIFEST}"
}
FILES_${PN} += "${CONTAINERS_INSTALL_DIR}"
do_install[prefuncs]+= "containers_manifest"