#!/bin/sh /etc/rc.common START=99 STOP=01 USE_PROCD=1 log() { echo "${@}"|logger -t crun.init -p info } is_container_running() { crun list |tail -n +2|grep -wq "^${1}" return $? } configure_lxc_container() { local requested_state name ctype du_status BUNDLE section ctype="${1}" name="${2}" requested_state="${3}" du_status="${4}" BUNDLE="${5}" section="${6}" if [ "${ctype}" != "lxc" ]; then return 0; fi if [ "${du_status}" = "Uninstalling" ]; then lxc-stop -q -k "${name}" if [ -d "${BUNDLE:?}/${name:?}" ]; then rm -rf "${BUNDLE:?}/${name:?}" fi # If directory still exists then uninstall failed if [ -d "${BUNDLE}/${name}" ]; then uci_set ocicontainer "${section}" du_status Uninstalling_failed uci_set ocicontainer "${section}" fault_string "Failed to remove ${BUNDLE}/${name}" log "LXC container ${name} remove failed" else uci_set ocicontainer "${section}" du_status Uninstalling_success log "LXC container ${name} removed" fi return 0; fi if [ "${requested_state}" = "Idle" ]; then lxc-stop -q -k "${name}" elif [ "${requested_state}" = "Active" ]; then lxc-start -q "${name}" >/dev/null 2>&1 fi } configure_crun_container() { local name type autostart du_status requested_state url username password capability envlist local BRIDGE BUNDLE BOOT PERM local RUNNER="/etc/swmodd/run.sh" BUNDLE="${2}" BRIDGE="${3}" BOOT="${4}" TIMEOUT="${5}" config_get name "${1}" name "" config_get type "${1}" type "" config_get_bool autostart "${1}" autostart 1 config_get du_status "${1}" du_status "" config_get requested_state "${1}" requested_state "" config_get url "${1}" url "" config_get username "${1}" username "" config_get password "${1}" password "" config_get capability "${1}" capability "" config_get envlist "${1}" env_var "" if [ -n "${envlist}" ]; then envlist="${envlist// /;}" fi if [ -n "${capability}" ]; then PERM="-p ${capability// /,}" fi if [ -z "${name}" ] || [ -z "${type}" ] || [ -z "${du_status}" ]; then return 0; fi if [ "${type}" != "crun" ]; then configure_lxc_container "${type}" "${name}" "${requested_state}" "${du_status}" "${BUNDLE}" "${1}" return 0; fi if [ "${du_status}" = "Installing" ]; then local result log "Pull image from registry" uci_set ocicontainer "${1}" du_status Installing_start uci_set ocicontainer "${1}" username "" uci_set ocicontainer "${1}" password "" result=$(${RUNNER} -b "${BUNDLE}" -n "${name}" -r "${url}" -l "${username}:${password}" -t "${TIMEOUT}") if [ "$?" -eq 0 ]; then result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_description")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" description "${result}" fi result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_vendor")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" vendor "${result}" fi result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_version")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" version "${result}" fi uci_set ocicontainer "${1}" du_status Installing_success du_status="Installed" else uci_set ocicontainer "${1}" du_status Installing_failed uci_set ocicontainer "${1}" fault_string "${result}" return 0; fi fi if [ "${du_status}" = "Uninstalling" ]; then ubus call service delete "{\"name\":\"crun\",\"instance\":\"${name}\"}" if is_container_running "${name}"; then crun kill --all "${name}" 9 fi ${RUNNER} -c -n "${name}" if [ -d "${BUNDLE:?}/${name:?}" ]; then rm -rf "${BUNDLE:?}/${name:?}" fi # If directory still exists then uninstall failed if [ -d "${BUNDLE}/${name}" ]; then uci_set ocicontainer "${1}" du_status Uninstalling_failed uci_set ocicontainer "${1}" fault_string "Failed to remove ${BUNDLE}/${name}" else uci_set ocicontainer "${1}" du_status Uninstalling_success fi # Delete the uci config section after uninstall log "CRUN container ${name} removed" return 0; fi if [ ! -d "${BUNDLE:?}/${name:?}" ]; then log "Crun container {${BUNDLE:?}/${name:?}} not available" return 0; fi if [ "${du_status}" != "Installed" ]; then return 0; fi if [ "${BOOT}" -eq "1" ]; then if [ "${autostart}" -eq 1 ]; then ${RUNNER} -U -b "${BUNDLE}" -n "${name}" -e "${envlist}" ${PERM} result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_description")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" description "${result}" fi result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_vendor")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" vendor "${result}" fi result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_version")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" version "${result}" fi uci_set ocicontainer "${1}" requested_state "Active" else uci_set ocicontainer "${1}" requested_state "Idle" return 0; fi else log "Container [$name] req_status [${requested_state}]" if [ "${requested_state}" = "Idle" ]; then if is_container_running "${name}"; then crun pause "${name}" else return 0; fi elif [ "${requested_state}" = "Active" ]; then if is_container_running "${name}"; then ${RUNNER} -u -n "${name}" -i "${BRIDGE}" ${PERM} crun resume "${name}" else ${RUNNER} -U -b "${BUNDLE}" -n "${name}" -e "${envlist}" ${PERM} result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_description")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" description "${result}" fi result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter "@.annotations.org_opencontainers_image_vendor")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" vendor "${result}" fi result="$(cat ${BUNDLE}/${name}/config.json |jsonfilter -e "@.annotations.org_opencontainers_image_version")" if [ "${result}" != "null" ]; then uci_set ocicontainer "${1}" version "${result}" fi fi else return 0; fi fi procd_open_instance "${name}" procd_set_param stdout 1 procd_set_param stderr 1 procd_set_param command "${RUNNER}" procd_append_param command -b "${BUNDLE}" -n "${name}" -i "${BRIDGE}" #procd_set_param respawn procd_close_instance "${name}" } boot() { start "bootstrap" } start_service() { local bundle root env bridge boot # Check if crun present if ! command -v crun >/dev/null 2>&1; then log "CRUN binary not found" return 0; fi if [ "${1}" = "bootstrap" ]; then boot=1 else boot=0 fi # crun default runtime directory /run, if not present then create if [ ! -d "/run" ]; then if [ ! -L "/run" ]; then ln -fs /var/run /run fi fi config_load swmodd config_get root globals root "" config_get bridge globals lan_bridge "br-lan" config_get timeout globals oci_pull_timeout "10" env=$(uci -q get swmodd.@execenv[0].name) if [ -z "${root}" ] || [ -z "${bridge}" ]; then log "# Base bundle root[$root] or bridge[$bridge] not defined" return 0; fi bundle="${root}/${env}" if [ -f "${bundle}/ocicontainer" ]; then UCI_CONFIG_DIR="${bundle}" config_load ocicontainer config_foreach configure_crun_container du_eu_assoc "${bundle}" "${bridge}" "${boot}" "${timeout}" uci_commit ocicontainer # Add a timer for DuStateChange! (sleep 5 && ubus -t 5 call swmodules reload) & else log "${bundle}/ocicontainer not present" fi } stop_service() { local cid cid="$(crun list|tail -n +2 |awk '{printf $1 " "}')" for f in $cid; do crun kill --all "${f}" 9 done } reload_service() { start } service_triggers() { procd_add_reload_trigger "crun" "network" }