12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640 |
- #!/bin/sh
- # shellcheck disable=2015,2039,2162,2166
- #
- # ds-identify is configured via /etc/cloud/ds-identify.cfg
- # or on the kernel command line. It takes the following inputs:
- #
- # datasource: can specify the datasource that should be used.
- # kernel command line option: ci.datasource=<dsname> or ci.ds=<dsname>
- # example line in /etc/cloud/ds-identify.cfg:
- # datasource: Ec2
- #
- # policy: a string that indicates how ds-identify should operate.
- #
- # The format is:
- # <mode>,found=value,maybe=value,notfound=value
- # default setting is:
- # search,found=all,maybe=all,notfound=disabled
- #
- # kernel command line option: ci.di.policy=<policy>
- # example line in /etc/cloud/ds-identify.cfg:
- # policy: search,found=all,maybe=none,notfound=disabled
- #
- #
- # Mode:
- # disabled: disable cloud-init
- # enabled: enable cloud-init.
- # ds-identify writes no config and just exits success.
- # the caller (cloud-init-generator) then enables cloud-init to
- # run just without any aid from ds-identify.
- # search: determine which source or sources should be used
- # and write the result (datasource_list) to
- # /run/cloud-init/cloud.cfg
- # report: basically 'dry run' for search. results are still written
- # to the file, but are namespaced under the top level key
- # 'di_report' Thus cloud-init is not affected, but can still
- # see the result.
- #
- # found,maybe,notfound:
- # found: (default=all)
- # first: use the first found do no further checking
- # all: enable all DS_FOUND
- #
- # maybe: (default=all)
- # if nothing returned 'found', then how to handle maybe.
- # no network sources are allowed to return 'maybe'.
- # all: enable all DS_MAYBE
- # none: ignore any DS_MAYBE
- #
- # notfound: (default=disabled)
- # disabled: disable cloud-init
- # enabled: enable cloud-init
- #
- # ci.datasource.ec2.strict_id: (true|false|warn[,0-9])
- # if ec2 datasource does not strictly match,
- # return not_found if true
- # return maybe if false or warn*.
- #
- set -u
- set -f
- UNAVAILABLE="unavailable"
- CR="
- "
- ERROR="error"
- DI_ENABLED="enabled"
- DI_DISABLED="disabled"
- DI_DEBUG_LEVEL="${DEBUG_LEVEL:-1}"
- PATH_ROOT=${PATH_ROOT:-""}
- PATH_RUN=${PATH_RUN:-"${PATH_ROOT}/run"}
- PATH_SYS_CLASS_DMI_ID=${PATH_SYS_CLASS_DMI_ID:-${PATH_ROOT}/sys/class/dmi/id}
- PATH_SYS_HYPERVISOR=${PATH_SYS_HYPERVISOR:-${PATH_ROOT}/sys/hypervisor}
- PATH_SYS_CLASS_BLOCK=${PATH_SYS_CLASS_BLOCK:-${PATH_ROOT}/sys/class/block}
- PATH_DEV_DISK="${PATH_DEV_DISK:-${PATH_ROOT}/dev/disk}"
- PATH_VAR_LIB_CLOUD="${PATH_VAR_LIB_CLOUD:-${PATH_ROOT}/var/lib/cloud}"
- PATH_DI_CONFIG="${PATH_DI_CONFIG:-${PATH_ROOT}/etc/cloud/ds-identify.cfg}"
- PATH_PROC_CMDLINE="${PATH_PROC_CMDLINE:-${PATH_ROOT}/proc/cmdline}"
- PATH_PROC_1_CMDLINE="${PATH_PROC_1_CMDLINE:-${PATH_ROOT}/proc/1/cmdline}"
- PATH_PROC_1_ENVIRON="${PATH_PROC_1_ENVIRON:-${PATH_ROOT}/proc/1/environ}"
- PATH_PROC_UPTIME=${PATH_PROC_UPTIME:-${PATH_ROOT}/proc/uptime}
- PATH_ETC_CLOUD="${PATH_ETC_CLOUD:-${PATH_ROOT}/etc/cloud}"
- PATH_ETC_CI_CFG="${PATH_ETC_CI_CFG:-${PATH_ETC_CLOUD}/cloud.cfg}"
- PATH_ETC_CI_CFG_D="${PATH_ETC_CI_CFG_D:-${PATH_ETC_CI_CFG}.d}"
- PATH_RUN_CI="${PATH_RUN_CI:-${PATH_RUN}/cloud-init}"
- PATH_RUN_CI_CFG=${PATH_RUN_CI_CFG:-${PATH_RUN_CI}/cloud.cfg}
- PATH_RUN_DI_RESULT=${PATH_RUN_DI_RESULT:-${PATH_RUN_CI}/.ds-identify.result}
- DI_LOG="${DI_LOG:-${PATH_RUN_CI}/ds-identify.log}"
- _DI_LOGGED=""
- # set DI_MAIN='noop' in environment to source this file with no main called.
- DI_MAIN=${DI_MAIN:-main}
- DI_BLKID_OUTPUT=""
- DI_DEFAULT_POLICY="search,found=all,maybe=all,notfound=${DI_DISABLED}"
- DI_DEFAULT_POLICY_NO_DMI="search,found=all,maybe=all,notfound=${DI_ENABLED}"
- DI_DMI_CHASSIS_ASSET_TAG=""
- DI_DMI_PRODUCT_NAME=""
- DI_DMI_SYS_VENDOR=""
- DI_DMI_PRODUCT_SERIAL=""
- DI_DMI_PRODUCT_UUID=""
- DI_FS_LABELS=""
- DI_FS_UUIDS=""
- DI_ISO9660_DEVS=""
- DI_KERNEL_CMDLINE=""
- DI_VIRT=""
- DI_PID_1_PRODUCT_NAME=""
- DI_UNAME_KERNEL_NAME=""
- DI_UNAME_KERNEL_RELEASE=""
- DI_UNAME_KERNEL_VERSION=""
- DI_UNAME_MACHINE=""
- DI_UNAME_NODENAME=""
- DI_UNAME_OPERATING_SYSTEM=""
- DI_UNAME_CMD_OUT=""
- DS_FOUND=0
- DS_NOT_FOUND=1
- DS_MAYBE=2
- DI_DSNAME=""
- # this has to match the builtin list in cloud-init, it is what will
- # be searched if there is no setting found in config.
- DI_DSLIST_DEFAULT="MAAS ConfigDrive NoCloud AltCloud Azure Bigstep \
- CloudSigma CloudStack DigitalOcean AliYun Ec2 GCE OpenNebula OpenStack \
- OVF SmartOS Scaleway Hetzner IBMCloud Oracle Exoscale RbxCloud"
- DI_DSLIST=""
- DI_MODE=""
- DI_ON_FOUND=""
- DI_ON_MAYBE=""
- DI_ON_NOTFOUND=""
- DI_EC2_STRICT_ID_DEFAULT="true"
- _IS_IBM_CLOUD=""
- error() {
- set -- "ERROR:" "$@";
- debug 0 "$@"
- stderr "$@"
- }
- warn() {
- set -- "WARN:" "$@"
- debug 0 "$@"
- stderr "$@"
- }
- stderr() { echo "$@" 1>&2; }
- debug() {
- local lvl="$1"
- shift
- [ "$lvl" -gt "${DI_DEBUG_LEVEL}" ] && return
- if [ "$_DI_LOGGED" != "$DI_LOG" ]; then
- # first time here, open file descriptor for append
- case "$DI_LOG" in
- stderr) :;;
- ?*/*)
- if [ ! -d "${DI_LOG%/*}" ]; then
- mkdir -p "${DI_LOG%/*}" || {
- stderr "ERROR:" "cannot write to $DI_LOG"
- DI_LOG="stderr"
- }
- fi
- esac
- if [ "$DI_LOG" = "stderr" ]; then
- exec 3>&2
- else
- ( exec 3>>"$DI_LOG" ) && exec 3>>"$DI_LOG" || {
- stderr "ERROR: failed writing to $DI_LOG. logging to stderr.";
- exec 3>&2
- DI_LOG="stderr"
- }
- fi
- _DI_LOGGED="$DI_LOG"
- fi
- echo "$@" 1>&3
- }
- dmi_decode() {
- local sys_field="$1" dmi_field="" val=""
- command -v dmidecode >/dev/null 2>&1 || {
- warn "No dmidecode program. Cannot read $sys_field."
- return 1
- }
- case "$1" in
- sys_vendor) dmi_field="system-manufacturer";;
- product_name) dmi_field="system-product-name";;
- product_uuid) dmi_field="system-uuid";;
- product_serial) dmi_field="system-serial-number";;
- chassis_asset_tag) dmi_field="chassis-asset-tag";;
- *) error "Unknown field $sys_field. Cannot call dmidecode."
- return 1;;
- esac
- val=$(dmidecode --quiet "--string=$dmi_field" 2>/dev/null) || return 1
- _RET="$val"
- }
- get_dmi_field() {
- local path="${PATH_SYS_CLASS_DMI_ID}/$1"
- _RET="$UNAVAILABLE"
- if [ -d "${PATH_SYS_CLASS_DMI_ID}" ]; then
- if [ -f "$path" ] && [ -r "$path" ]; then
- read _RET < "${path}" || _RET="$ERROR"
- return
- fi
- # if `/sys/class/dmi/id` exists, but not the object we're looking for,
- # do *not* fallback to dmidecode!
- return
- fi
- dmi_decode "$1" || _RET="$ERROR"
- return
- }
- block_dev_with_label() {
- local p="${PATH_DEV_DISK}/by-label/$1"
- [ -b "$p" ] || return 1
- _RET=$p
- return 0
- }
- ensure_sane_path() {
- local t
- for t in /sbin /usr/sbin /bin /usr/bin; do
- case ":$PATH:" in
- *:$t:*|*:$t/:*) continue;;
- esac
- PATH="${PATH:+${PATH}:}$t"
- done
- }
- read_fs_info() {
- cached "${DI_BLKID_OUTPUT}" && return 0
- # do not rely on links in /dev/disk which might not be present yet.
- # Note that blkid < 2.22 (centos6, trusty) do not output DEVNAME.
- # that means that DI_ISO9660_DEVS will not be set.
- if is_container; then
- # blkid will in a container, or at least currently in lxd
- # not provide useful information.
- DI_FS_LABELS="$UNAVAILABLE:container"
- DI_ISO9660_DEVS="$UNAVAILABLE:container"
- return
- fi
- local oifs="$IFS" line="" delim=","
- local ret=0 out="" labels="" dev="" label="" ftype="" isodevs="" uuids=""
- out=$(blkid -c /dev/null -o export) || {
- ret=$?
- error "failed running [$ret]: blkid -c /dev/null -o export"
- DI_FS_LABELS="$UNAVAILABLE:error"
- DI_ISO9660_DEVS="$UNAVAILABLE:error"
- return $ret
- }
- # 'set --' will collapse multiple consecutive entries in IFS for
- # whitespace characters (\n, tab, " ") so we cannot rely on getting
- # empty lines in "$@" below.
- # shellcheck disable=2086
- { IFS="$CR"; set -- $out; IFS="$oifs"; }
- for line in "$@"; do
- case "${line}" in
- DEVNAME=*)
- [ -n "$dev" -a "$ftype" = "iso9660" ] &&
- isodevs="${isodevs},${dev}=$label"
- ftype=""; dev=""; label="";
- dev=${line#DEVNAME=};;
- LABEL=*) label="${line#LABEL=}";
- labels="${labels}${line#LABEL=}${delim}";;
- TYPE=*) ftype=${line#TYPE=};;
- UUID=*) uuids="${uuids}${line#UUID=}$delim";;
- esac
- done
- [ -n "$dev" -a "$ftype" = "iso9660" ] &&
- isodevs="${isodevs},${dev}=$label"
- DI_FS_LABELS="${labels%${delim}}"
- DI_FS_UUIDS="${uuids%${delim}}"
- DI_ISO9660_DEVS="${isodevs#,}"
- }
- cached() {
- [ -n "$1" ] && _RET="$1" && return || return 1
- }
- detect_virt() {
- local virt="${UNAVAILABLE}" r="" out=""
- if [ -d /run/systemd ]; then
- out=$(systemd-detect-virt 2>&1)
- r=$?
- if [ $r -eq 0 ] || { [ $r -ne 0 ] && [ "$out" = "none" ]; }; then
- virt="$out"
- fi
- elif [ "$DI_UNAME_KERNEL_NAME" = "FreeBSD" ]; then
- # Map FreeBSD's vm_guest names to those systemd-detect-virt that
- # don't match up. See
- # https://github.com/freebsd/freebsd/blob/master/sys/kern/subr_param.c#L144-L160
- # https://www.freedesktop.org/software/systemd/man/systemd-detect-virt.html
- #
- # systemd | kern.vm_guest
- # ---------------------+---------------
- # none | none
- # kvm | kvm
- # vmware | vmware
- # microsoft | hv
- # oracle | vbox
- # xen | xen
- # parallels | parallels
- # bhyve | bhyve
- # vm-other | generic
- out=$(sysctl -qn kern.vm_guest 2>/dev/null) && {
- case "$out" in
- hv) virt="microsoft" ;;
- vbox) virt="oracle" ;;
- generic) "vm-other";;
- *) virt="$out"
- esac
- }
- fi
- _RET="$virt"
- }
- read_virt() {
- cached "$DI_VIRT" && return 0
- detect_virt
- DI_VIRT=${_RET}
- }
- is_container() {
- case "${DI_VIRT}" in
- container-other|lxc|lxc-libvirt|systemd-nspawn|docker|rkt) return 0;;
- *) return 1;;
- esac
- }
- read_kernel_cmdline() {
- cached "${DI_KERNEL_CMDLINE}" && return
- local cmdline="" fpath="${PATH_PROC_CMDLINE}"
- if is_container; then
- local p1path="${PATH_PROC_1_CMDLINE}" x=""
- cmdline="${UNAVAILABLE}:container"
- if [ -f "$p1path" ] && x=$(tr '\0' ' ' < "$p1path"); then
- cmdline=$x
- fi
- elif [ -f "$fpath" ]; then
- read cmdline <"$fpath"
- else
- cmdline="${UNAVAILABLE}:no-cmdline"
- fi
- DI_KERNEL_CMDLINE="$cmdline"
- }
- read_dmi_chassis_asset_tag() {
- cached "${DI_DMI_CHASSIS_ASSET_TAG}" && return
- get_dmi_field chassis_asset_tag
- DI_DMI_CHASSIS_ASSET_TAG="$_RET"
- }
- read_dmi_sys_vendor() {
- cached "${DI_DMI_SYS_VENDOR}" && return
- get_dmi_field sys_vendor
- DI_DMI_SYS_VENDOR="$_RET"
- }
- read_dmi_product_name() {
- cached "${DI_DMI_PRODUCT_NAME}" && return
- get_dmi_field product_name
- DI_DMI_PRODUCT_NAME="$_RET"
- }
- read_dmi_product_uuid() {
- cached "${DI_DMI_PRODUCT_UUID}" && return
- get_dmi_field product_uuid
- DI_DMI_PRODUCT_UUID="$_RET"
- }
- read_dmi_product_serial() {
- cached "${DI_DMI_PRODUCT_SERIAL}" && return
- get_dmi_field product_serial
- DI_DMI_PRODUCT_SERIAL="$_RET"
- }
- # shellcheck disable=2034
- read_uname_info() {
- # run uname, and parse output.
- # uname is tricky to parse as it outputs always in a given order
- # independent of option order. kernel-version is known to have spaces.
- # 1 -s kernel-name
- # 2 -n nodename
- # 3 -r kernel-release
- # 4.. -v kernel-version(whitespace)
- # N-2 -m machine
- # N-1 -o operating-system
- cached "${DI_UNAME_CMD_OUT}" && return
- local out="${1:-}" ret=0 buf=""
- if [ -z "$out" ]; then
- out=$(uname -snrvmo) || {
- ret=$?
- error "failed reading uname with 'uname -snrvmo'"
- return $ret
- }
- fi
- # shellcheck disable=2086
- set -- $out
- DI_UNAME_KERNEL_NAME="$1"
- DI_UNAME_NODENAME="$2"
- DI_UNAME_KERNEL_RELEASE="$3"
- shift 3
- while [ $# -gt 2 ]; do
- buf="$buf $1"
- shift
- done
- DI_UNAME_KERNEL_VERSION="${buf# }"
- DI_UNAME_MACHINE="$1"
- DI_UNAME_OPERATING_SYSTEM="$2"
- DI_UNAME_CMD_OUT="$out"
- return 0
- }
- parse_yaml_array() {
- # parse a yaml single line array value ([1,2,3], not key: [1,2,3]).
- # supported with or without leading and closing brackets
- # ['1'] or [1]
- # '1', '2'
- local val="$1" oifs="$IFS" ret="" tok=""
- # i386/14.04 (dash=0.5.7-4ubuntu1): the following outputs "[foo"
- # sh -c 'n="$1"; echo ${n#[}' -- "[foo"
- # the fix was to quote the open bracket (val=${val#"["}) (LP: #1689648)
- val=${val#"["}
- val=${val%"]"}
- # shellcheck disable=2086
- { IFS=","; set -- $val; IFS="$oifs"; }
- for tok in "$@"; do
- trim "$tok"
- unquote "$_RET"
- ret="${ret} $_RET"
- done
- _RET="${ret# }"
- }
- read_datasource_list() {
- cached "$DI_DSLIST" && return
- local dslist=""
- # if DI_DSNAME is set directly, then avoid parsing config.
- if [ -n "${DI_DSNAME}" ]; then
- dslist="${DI_DSNAME}"
- fi
- # LP: #1582323. cc:{'datasource_list': ['name']}
- # more generically cc:<yaml>[end_cc]
- local cb="]" ob="["
- case "$DI_KERNEL_CMDLINE" in
- *cc:*datasource_list*)
- t=${DI_KERNEL_CMDLINE##*datasource_list}
- t=${t%%$cb*}
- t=${t##*$ob}
- parse_yaml_array "$t"
- dslist=${_RET}
- ;;
- esac
- if [ -z "$dslist" ] && check_config datasource_list; then
- debug 1 "$_RET_fname set datasource_list: $_RET"
- parse_yaml_array "$_RET"
- dslist=${_RET}
- fi
- if [ -z "$dslist" ]; then
- dslist=${DI_DSLIST_DEFAULT}
- debug 1 "no datasource_list found, using default: $dslist"
- fi
- DI_DSLIST=$dslist
- return 0
- }
- read_pid1_product_name() {
- local oifs="$IFS" out="" tok="" key="" val="" product_name="${UNAVAILABLE}"
- cached "${DI_PID_1_PRODUCT_NAME}" && return
- [ -r "${PATH_PROC_1_ENVIRON}" ] || return
- out=$(tr '\0' '\n' <"${PATH_PROC_1_ENVIRON}")
- # shellcheck disable=2086
- { IFS="$CR"; set -- $out; IFS="$oifs"; }
- for tok in "$@"; do
- key=${tok%%=*}
- [ "$key" != "$tok" ] || continue
- val=${tok#*=}
- [ "$key" = "product_name" ] && product_name="$val" && break
- done
- DI_PID_1_PRODUCT_NAME="$product_name"
- }
- dmi_chassis_asset_tag_matches() {
- is_container && return 1
- case "${DI_DMI_CHASSIS_ASSET_TAG}" in
- $1) return 0;;
- esac
- return 1
- }
- dmi_product_name_matches() {
- is_container && return 1
- case "${DI_DMI_PRODUCT_NAME}" in
- $1) return 0;;
- esac
- return 1
- }
- dmi_product_serial_matches() {
- is_container && return 1
- case "${DI_DMI_PRODUCT_SERIAL}" in
- $1) return 0;;
- esac
- return 1
- }
- dmi_sys_vendor_is() {
- is_container && return 1
- [ "${DI_DMI_SYS_VENDOR}" = "$1" ]
- }
- has_fs_with_uuid() {
- case ",${DI_FS_UUIDS}," in
- *,$1,*) return 0;;
- esac
- return 1
- }
- has_fs_with_label() {
- # has_fs_with_label(label1[ ,label2 ..])
- # return 0 if a there is a filesystem that matches any of the labels.
- local label=""
- for label in "$@"; do
- case ",${DI_FS_LABELS}," in
- *,$label,*) return 0;;
- esac
- done
- return 1
- }
- nocase_equal() {
- # nocase_equal(a, b)
- # return 0 if case insenstive comparision a.lower() == b.lower()
- # different lengths
- [ "${#1}" = "${#2}" ] || return 1
- # case sensitive equal
- [ "$1" = "$2" ] && return 0
- local delim="-delim-"
- # shellcheck disable=2018,2019
- out=$(echo "$1${delim}$2" | tr A-Z a-z)
- [ "${out#*${delim}}" = "${out%${delim}*}" ]
- }
- check_seed_dir() {
- # check_seed_dir(name, [required])
- # check the seed dir /var/lib/cloud/seed/<name> for 'required'
- # required defaults to 'meta-data'
- local name="$1"
- local dir="${PATH_VAR_LIB_CLOUD}/seed/$name"
- [ -d "$dir" ] || return 1
- shift
- if [ $# -eq 0 ]; then
- set -- meta-data
- fi
- local f=""
- for f in "$@"; do
- [ -f "$dir/$f" ] || return 1
- done
- return 0
- }
- check_writable_seed_dir() {
- # ubuntu core bind-mounts /writable/system-data/var/lib/cloud
- # over the top of /var/lib/cloud, but the mount might not be done yet.
- local wdir="/writable/system-data"
- [ -d "${PATH_ROOT}$wdir" ] || return 1
- local sdir="${PATH_ROOT}$wdir${PATH_VAR_LIB_CLOUD#${PATH_ROOT}}"
- local PATH_VAR_LIB_CLOUD="$sdir"
- check_seed_dir "$@"
- }
- probe_floppy() {
- cached "${STATE_FLOPPY_PROBED}" && return "${STATE_FLOPPY_PROBED}"
- local fpath=/dev/floppy
- [ -b "$fpath" ] ||
- { STATE_FLOPPY_PROBED=1; return 1; }
- modprobe --use-blacklist floppy >/dev/null 2>&1 ||
- { STATE_FLOPPY_PROBED=1; return 1; }
- udevadm settle "--exit-if-exists=$fpath" ||
- { STATE_FLOPPY_PROBED=1; return 1; }
- [ -b "$fpath" ]
- STATE_FLOPPY_PROBED=$?
- return "${STATE_FLOPPY_PROBED}"
- }
- dscheck_CloudStack() {
- is_container && return ${DS_NOT_FOUND}
- dmi_product_name_matches "CloudStack*" && return $DS_FOUND
- return $DS_NOT_FOUND
- }
- dscheck_Exoscale() {
- dmi_product_name_matches "Exoscale*" && return $DS_FOUND
- return $DS_NOT_FOUND
- }
- dscheck_CloudSigma() {
- # http://paste.ubuntu.com/23624795/
- dmi_product_name_matches "CloudSigma" && return $DS_FOUND
- return $DS_NOT_FOUND
- }
- check_config() {
- # check_config(key [,file_globs])
- # somewhat hackily read through file_globs for 'key'
- # file_globs are expanded via path expansion and
- # default to /etc/cloud/cloud.cfg /etc/cloud/cloud.cfg.d/*.cfg
- # currently does not respect any hierarchy in searching for key.
- local key="$1" files=""
- shift
- if [ $# -eq 0 ]; then
- files="${PATH_ETC_CI_CFG} ${PATH_ETC_CI_CFG_D}/*.cfg"
- else
- files="$*"
- fi
- # shellcheck disable=2086
- { set +f; set -- $files; set -f; }
- if [ "$1" = "$files" -a ! -f "$1" ]; then
- return 1
- fi
- local fname="" line="" ret="" found=0 found_fn=""
- # shellcheck disable=2094
- for fname in "$@"; do
- [ -f "$fname" ] || continue
- while read line; do
- line=${line%%#*}
- case "$line" in
- $key:\ *|$key:)
- ret=${line#*:};
- ret=${ret# };
- found=$((found+1))
- found_fn="$fname";;
- esac
- done <"$fname"
- done
- if [ $found -ne 0 ]; then
- _RET="$ret"
- _RET_fname="$found_fn"
- return 0
- fi
- return 1
- }
- dscheck_MAAS() {
- is_container && return "${DS_NOT_FOUND}"
- # heuristic check for ephemeral boot environment
- # for maas that do not set 'ci.dsname=' in the ephemeral environment
- # these have iscsi root and cloud-config-url on the cmdline.
- local maasiqn="iqn.2004-05.com.ubuntu:maas"
- case "${DI_KERNEL_CMDLINE}" in
- *cloud-config-url=*${maasiqn}*|*${maasiqn}*cloud-config-url=*)
- return ${DS_FOUND}
- ;;
- esac
- # check config files written by maas for installed system.
- if check_config "MAAS"; then
- return "${DS_FOUND}"
- fi
- return ${DS_NOT_FOUND}
- }
- dscheck_NoCloud() {
- local fslabel="cidata CIDATA" d=""
- case " ${DI_KERNEL_CMDLINE} " in
- *\ ds=nocloud*) return ${DS_FOUND};;
- esac
- case " ${DI_DMI_PRODUCT_SERIAL} " in
- *\ ds=nocloud*) return ${DS_FOUND};;
- esac
- for d in nocloud nocloud-net; do
- check_seed_dir "$d" meta-data user-data && return ${DS_FOUND}
- check_writable_seed_dir "$d" meta-data user-data && return ${DS_FOUND}
- done
- if has_fs_with_label $fslabel; then
- return ${DS_FOUND}
- fi
- return ${DS_NOT_FOUND}
- }
- is_ds_enabled() {
- local name="$1" pad=" ${DI_DSLIST} "
- [ "${pad#* $name }" != "${pad}" ]
- }
- check_configdrive_v2() {
- # look in /config-drive <vlc>/seed/config_drive for a directory
- # openstack/YYYY-MM-DD format with a file meta_data.json
- local d=""
- local vlc_config_drive_path="${PATH_VAR_LIB_CLOUD}/seed/config_drive"
- for d in /config-drive $vlc_config_drive_path; do
- set +f; set -- "$d/openstack/"2???-??-??/meta_data.json; set -f;
- [ -f "$1" ] && return ${DS_FOUND}
- done
- # at least one cloud (softlayer) seeds config drive with only 'latest'.
- local lpath="openstack/latest/meta_data.json"
- if [ -e "$vlc_config_drive_path/$lpath" ]; then
- debug 1 "config drive seeded directory had only 'latest'"
- return ${DS_FOUND}
- fi
- local ibm_enabled=false
- is_ds_enabled "IBMCloud" && ibm_enabled=true
- debug 1 "is_ds_enabled(IBMCloud) = $ibm_enabled."
- [ "$ibm_enabled" = "true" ] && is_ibm_cloud && return ${DS_NOT_FOUND}
- if has_fs_with_label CONFIG-2 config-2; then
- return ${DS_FOUND}
- fi
- return ${DS_NOT_FOUND}
- }
- check_configdrive_v1() {
- # FIXME: this has to check any file system that is vfat...
- # for now, just return not found.
- return ${DS_NOT_FOUND}
- }
- dscheck_ConfigDrive() {
- local ret=""
- check_configdrive_v2
- ret=$?
- [ $DS_FOUND -eq $ret ] && return $ret
- check_configdrive_v1
- }
- dscheck_DigitalOcean() {
- dmi_sys_vendor_is DigitalOcean && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- dscheck_OpenNebula() {
- check_seed_dir opennebula && return ${DS_FOUND}
- has_fs_with_label "CONTEXT" && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- dscheck_RbxCloud() {
- has_fs_with_label "CLOUDMD" "cloudmd" && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- ovf_vmware_guest_customization() {
- # vmware guest customization
- # virt provider must be vmware
- [ "${DI_VIRT}" = "vmware" ] || return 1
- # we have to have the plugin to do vmware customization
- local found="" pkg="" pre="${PATH_ROOT}/usr/lib"
- local ppath="plugins/vmsvc/libdeployPkgPlugin.so"
- for pkg in vmware-tools open-vm-tools; do
- if [ -f "$pre/$pkg/$ppath" -o -f "${pre}64/$pkg/$ppath" ]; then
- found="$pkg"; break;
- fi
- done
- [ -n "$found" ] || return 1
- # vmware customization is disabled by default
- # (disable_vmware_customization=true). If it is set to false, then
- # user has requested customization.
- local key="disable_vmware_customization"
- if check_config "$key"; then
- debug 2 "${_RET_fname} set $key to $_RET"
- case "$_RET" in
- 0|false|False) return 0;;
- *) return 1;;
- esac
- fi
- return 1
- }
- ovf_vmware_transport_guestinfo() {
- [ "${DI_VIRT}" = "vmware" ] || return 1
- command -v vmware-rpctool >/dev/null 2>&1 || return 1
- local out="" ret=""
- out=$(vmware-rpctool "info-get guestinfo.ovfEnv" 2>&1)
- ret=$?
- if [ $ret -ne 0 ]; then
- debug 1 "Running on vmware but rpctool query returned $ret: $out"
- return 1
- fi
- case "$out" in
- "<?xml"*|"<?XML"*) :;;
- *) debug 1 "guestinfo.ovfEnv had non-xml content: $out";
- return 1;;
- esac
- debug 1 "Found guestinfo transport."
- return 0
- }
- is_cdrom_ovf() {
- local dev="$1" label="$2"
- # skip devices that don't look like cdrom paths.
- case "$dev" in
- /dev/sr[0-9]|/dev/hd[a-z]) :;;
- *) debug 1 "skipping iso dev $dev"
- return 1;;
- esac
- debug 1 "got label=$label"
- # fast path known 'OVF' labels
- case "$label" in
- OVF-TRANSPORT|ovf-transport|OVFENV|ovfenv|OVF\ ENV|ovf\ env) return 0;;
- esac
- # explicitly skip known labels of other types. rd_rdfe is azure.
- case "$label" in
- config-2|CONFIG-2|rd_rdfe_stable*|cidata|CIDATA) return 1;;
- esac
- # skip device which size is 10MB or larger
- local size="" sfile="${PATH_SYS_CLASS_BLOCK}/${dev##*/}/size"
- [ -f "$sfile" ] || return 1
- read size <"$sfile" || { warn "failed reading from $sfile"; return 1; }
- # size is in 512 byte units. so convert to MB (integer division)
- if [ $((size/2048)) -ge 10 ]; then
- debug 2 "$dev: size $((size/2048))MB is considered too large for OVF"
- return 1
- fi
- local idstr="http://schemas.dmtf.org/ovf/environment/1"
- grep --quiet --ignore-case "$idstr" "${PATH_ROOT}$dev"
- }
- has_ovf_cdrom() {
- # DI_ISO9660_DEVS is <device>=label,<device>=label2
- # like /dev/sr0=OVF-TRANSPORT,/dev/other=with spaces
- if [ "${DI_ISO9660_DEVS#${UNAVAILABLE}:}" = "${DI_ISO9660_DEVS}" ]; then
- local oifs="$IFS"
- # shellcheck disable=2086
- { IFS=","; set -- ${DI_ISO9660_DEVS}; IFS="$oifs"; }
- for tok in "$@"; do
- is_cdrom_ovf "${tok%%=*}" "${tok#*=}" && return 0
- done
- fi
- return 1
- }
- dscheck_OVF() {
- check_seed_dir ovf ovf-env.xml && return "${DS_FOUND}"
- [ "${DI_VIRT}" = "none" ] && return ${DS_NOT_FOUND}
- # Azure provides ovf. Skip false positive by dis-allowing.
- is_azure_chassis && return $DS_NOT_FOUND
- ovf_vmware_transport_guestinfo && return "${DS_FOUND}"
- has_ovf_cdrom && return "${DS_FOUND}"
- ovf_vmware_guest_customization && return "${DS_FOUND}"
- return ${DS_NOT_FOUND}
- }
- is_azure_chassis() {
- local azure_chassis="7783-7084-3265-9085-8269-3286-77"
- dmi_chassis_asset_tag_matches "${azure_chassis}"
- }
- dscheck_Azure() {
- # http://paste.ubuntu.com/23630873/
- # $ grep /sr0 /run/blkid/blkid.tab
- # <device DEVNO="0x0b00" TIME="1481737655.543841"
- # UUID="112D211272645f72" LABEL="rd_rdfe_stable.161212-1209"
- # TYPE="udf">/dev/sr0</device>
- #
- is_azure_chassis && return $DS_FOUND
- check_seed_dir azure ovf-env.xml && return ${DS_FOUND}
- [ "${DI_VIRT}" = "microsoft" ] || return ${DS_NOT_FOUND}
- has_fs_with_label "rd_rdfe_*" && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- dscheck_Bigstep() {
- # bigstep is activated by presense of seed file 'url'
- [ -f "${PATH_VAR_LIB_CLOUD}/data/seed/bigstep/url" ] &&
- return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- ec2_read_strict_setting() {
- # the 'strict_id' setting for Ec2 controls behavior when
- # the platform does not identify itself directly as Ec2.
- # order of precedence is:
- # 1. builtin setting here cloud-init/ds-identify builtin
- # 2. ds-identify config
- # 3. system config (/etc/cloud/cloud.cfg.d/*Ec2*.cfg)
- # 4. kernel command line (undocumented)
- # 5. user-data or vendor-data (not available here)
- local default="$1" key="ci.datasource.ec2.strict_id" val=""
- # 4. kernel command line
- case " ${DI_KERNEL_CMDLINE} " in
- *\ $key=*\ )
- val=${DI_KERNEL_CMDLINE##*$key=}
- val=${val%% *};
- _RET=${val:-$default}
- return 0
- esac
- # 3. look for the key 'strict_id' (datasource/Ec2/strict_id)
- # only in cloud.cfg or cloud.cfg.d/EC2.cfg (case insensitive)
- local cfg="${PATH_ETC_CI_CFG}" cfg_d="${PATH_ETC_CI_CFG_D}"
- if check_config strict_id "$cfg" "$cfg_d/*[Ee][Cc]2*.cfg"; then
- debug 2 "${_RET_fname} set strict_id to $_RET"
- return 0
- fi
- # 2. ds-identify config (datasource.ec2.strict)
- local config="${PATH_DI_CONFIG}"
- if [ -f "$config" ]; then
- if _read_config "$key" < "$config"; then
- _RET=${_RET:-$default}
- return 0
- fi
- fi
- # 1. Default
- _RET=$default
- return 0
- }
- ec2_identify_platform() {
- local default="$1"
- local serial="${DI_DMI_PRODUCT_SERIAL}"
- case "$serial" in
- *.brightbox.com) _RET="Brightbox"; return 0;;
- esac
- local asset_tag="${DI_DMI_CHASSIS_ASSET_TAG}"
- case "$asset_tag" in
- *.zstack.io) _RET="ZStack"; return 0;;
- esac
- local vendor="${DI_DMI_SYS_VENDOR}"
- case "$vendor" in
- e24cloud) _RET="E24cloud"; return 0;;
- esac
- # AWS http://docs.aws.amazon.com/AWSEC2/
- # latest/UserGuide/identify_ec2_instances.html
- local uuid="" hvuuid="${PATH_SYS_HYPERVISOR}/uuid"
- # if the (basically) xen specific /sys/hypervisor/uuid starts with 'ec2'
- if [ -r "$hvuuid" ] && read uuid < "$hvuuid" &&
- [ "${uuid#ec2}" != "$uuid" ]; then
- _RET="AWS"
- return 0
- fi
- # product uuid and product serial start with case insensitive
- local uuid="${DI_DMI_PRODUCT_UUID}"
- case "$uuid:$serial" in
- [Ee][Cc]2*:[Ee][Cc]2*)
- # both start with ec2, now check for case insenstive equal
- nocase_equal "$uuid" "$serial" &&
- { _RET="AWS"; return 0; };;
- esac
- _RET="$default"
- return 0;
- }
- dscheck_Ec2() {
- check_seed_dir "ec2" meta-data user-data && return ${DS_FOUND}
- is_container && return ${DS_NOT_FOUND}
- local unknown="Unknown" platform=""
- if ec2_identify_platform "$unknown"; then
- platform="$_RET"
- else
- warn "Failed to identify ec2 platform. Using '$unknown'."
- platform=$unknown
- fi
- debug 1 "ec2 platform is '$platform'."
- if [ "$platform" != "$unknown" ]; then
- return $DS_FOUND
- fi
- local default="${DI_EC2_STRICT_ID_DEFAULT}"
- if ec2_read_strict_setting "$default"; then
- strict="$_RET"
- else
- debug 1 "ec2_read_strict returned non-zero: $?. using '$default'."
- strict="$default"
- fi
- local key="datasource/Ec2/strict_id"
- case "$strict" in
- true|false|warn|warn,[0-9]*) :;;
- *)
- warn "$key was set to invalid '$strict'. using '$default'"
- strict="$default";;
- esac
- _RET_excfg="datasource: {Ec2: {strict_id: \"$strict\"}}"
- if [ "$strict" = "true" ]; then
- return $DS_NOT_FOUND
- else
- return $DS_MAYBE
- fi
- }
- dscheck_GCE() {
- if dmi_product_name_matches "Google Compute Engine"; then
- return ${DS_FOUND}
- fi
- # product name is not guaranteed (LP: #1674861)
- if dmi_product_serial_matches "GoogleCloud-*"; then
- return ${DS_FOUND}
- fi
- return ${DS_NOT_FOUND}
- }
- dscheck_OpenStack() {
- # the openstack metadata http service
- # if there is a config drive, then do not check metadata
- # FIXME: if config drive not in the search list, then we should not
- # do this check.
- check_configdrive_v2
- if [ $? -eq ${DS_FOUND} ]; then
- return ${DS_NOT_FOUND}
- fi
- local nova="OpenStack Nova" compute="OpenStack Compute"
- if dmi_product_name_matches "$nova"; then
- return ${DS_FOUND}
- fi
- if dmi_product_name_matches "$compute"; then
- # RDO installed nova (LP: #1675349).
- return ${DS_FOUND}
- fi
- if [ "${DI_PID_1_PRODUCT_NAME}" = "$nova" ]; then
- return ${DS_FOUND}
- fi
- if dmi_chassis_asset_tag_matches "OpenTelekomCloud"; then
- return ${DS_FOUND}
- fi
- # LP: #1669875 : allow identification of OpenStack by asset tag
- if dmi_chassis_asset_tag_matches "$nova"; then
- return ${DS_FOUND}
- fi
- if dmi_chassis_asset_tag_matches "$compute"; then
- return ${DS_FOUND}
- fi
- # LP: #1715241 : arch other than intel are not identified properly.
- case "$DI_UNAME_MACHINE" in
- i?86|x86_64) :;;
- *) return ${DS_MAYBE};;
- esac
- return ${DS_NOT_FOUND}
- }
- dscheck_AliYun() {
- check_seed_dir "AliYun" meta-data user-data && return ${DS_FOUND}
- if dmi_product_name_matches "Alibaba Cloud ECS"; then
- return $DS_FOUND
- fi
- return $DS_NOT_FOUND
- }
- dscheck_AltCloud() {
- # ctype: either the dmi product name, or contents of
- # /etc/sysconfig/cloud-info
- # if ctype == "vsphere"
- # device = device with label 'CDROM'
- # elif ctype == "rhev"
- # device = /dev/floppy
- # then, filesystem on that device must have
- # user-data.txt or deltacloud-user-data.txt
- local ctype="" dev=""
- local match_rhev="[Rr][Hh][Ee][Vv]"
- local match_vsphere="[Vv][Ss][Pp][Hh][Ee][Rr][Ee]"
- local cinfo="${PATH_ROOT}/etc/sysconfig/cloud-info"
- if [ -f "$cinfo" ]; then
- read ctype < "$cinfo"
- else
- ctype="${DI_DMI_PRODUCT_NAME}"
- fi
- case "$ctype" in
- ${match_rhev})
- probe_floppy || return ${DS_NOT_FOUND}
- dev="/dev/floppy"
- ;;
- ${match_vsphere})
- block_dev_with_label CDROM || return ${DS_NOT_FOUND}
- dev="$_RET"
- ;;
- *) return ${DS_NOT_FOUND};;
- esac
- # FIXME: need to check $dev for user-data.txt or deltacloud-user-data.txt
- : "$dev"
- return $DS_MAYBE
- }
- dscheck_SmartOS() {
- # joyent cloud has two virt types: kvm and container
- # on kvm, product name on joyent public cloud shows 'SmartDC HVM'
- # on the container platform, uname's version has: BrandZ virtual linux
- # for container, we also verify that the socketfile exists to protect
- # against embedded containers (lxd running on brandz)
- local smartdc_kver="BrandZ virtual linux"
- local metadata_sockfile="${PATH_ROOT}/native/.zonecontrol/metadata.sock"
- dmi_product_name_matches "SmartDC*" && return $DS_FOUND
- [ "${DI_UNAME_KERNEL_VERSION}" = "${smartdc_kver}" ] &&
- [ -e "${metadata_sockfile}" ] &&
- return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- dscheck_None() {
- return ${DS_NOT_FOUND}
- }
- dscheck_Scaleway() {
- if [ "${DI_DMI_SYS_VENDOR}" = "Scaleway" ]; then
- return $DS_FOUND
- fi
- case " ${DI_KERNEL_CMDLINE} " in
- *\ scaleway\ *) return ${DS_FOUND};;
- esac
- if [ -f "${PATH_ROOT}/var/run/scaleway" ]; then
- return ${DS_FOUND}
- fi
- return ${DS_NOT_FOUND}
- }
- dscheck_Hetzner() {
- dmi_sys_vendor_is Hetzner && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- dscheck_Oracle() {
- local asset_tag="OracleCloud.com"
- dmi_chassis_asset_tag_matches "${asset_tag}" && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- is_ibm_provisioning() {
- local pcfg="${PATH_ROOT}/root/provisioningConfiguration.cfg"
- local logf="${PATH_ROOT}/root/swinstall.log"
- local is_prov=false msg="config '$pcfg' did not exist."
- if [ -f "$pcfg" ]; then
- msg="config '$pcfg' exists."
- is_prov=true
- if [ -f "$logf" ]; then
- if [ "$logf" -nt "$PATH_PROC_1_ENVIRON" ]; then
- msg="$msg log '$logf' from current boot."
- else
- is_prov=false
- msg="$msg log '$logf' from previous boot."
- fi
- else
- msg="$msg log '$logf' did not exist."
- fi
- fi
- debug 2 "ibm_provisioning=$is_prov: $msg"
- [ "$is_prov" = "true" ]
- }
- is_ibm_cloud() {
- cached "${_IS_IBM_CLOUD}" && return ${_IS_IBM_CLOUD}
- local ret=1
- if [ "$DI_VIRT" = "xen" ]; then
- if is_ibm_provisioning; then
- ret=0
- elif has_fs_with_label METADATA metadata; then
- ret=0
- elif has_fs_with_uuid 9796-932E &&
- has_fs_with_label CONFIG-2 config-2; then
- ret=0
- fi
- fi
- _IS_IBM_CLOUD=$ret
- return $ret
- }
- dscheck_IBMCloud() {
- if is_ibm_provisioning; then
- debug 1 "cloud-init disabled during provisioning on IBMCloud"
- return ${DS_NOT_FOUND}
- fi
- is_ibm_cloud && return ${DS_FOUND}
- return ${DS_NOT_FOUND}
- }
- collect_info() {
- read_virt
- read_pid1_product_name
- read_kernel_cmdline
- read_uname_info
- read_config
- read_datasource_list
- read_dmi_sys_vendor
- read_dmi_chassis_asset_tag
- read_dmi_product_name
- read_dmi_product_serial
- read_dmi_product_uuid
- read_fs_info
- }
- print_info() {
- collect_info
- _print_info
- }
- _print_info() {
- local n="" v="" vars=""
- vars="DMI_PRODUCT_NAME DMI_SYS_VENDOR DMI_PRODUCT_SERIAL"
- vars="$vars DMI_PRODUCT_UUID PID_1_PRODUCT_NAME DMI_CHASSIS_ASSET_TAG"
- vars="$vars FS_LABELS ISO9660_DEVS KERNEL_CMDLINE VIRT"
- vars="$vars UNAME_KERNEL_NAME UNAME_KERNEL_RELEASE UNAME_KERNEL_VERSION"
- vars="$vars UNAME_MACHINE UNAME_NODENAME UNAME_OPERATING_SYSTEM"
- vars="$vars DSNAME DSLIST"
- vars="$vars MODE ON_FOUND ON_MAYBE ON_NOTFOUND"
- for v in ${vars}; do
- eval n='${DI_'"$v"'}'
- echo "$v=$n"
- done
- echo "pid=$$ ppid=$PPID"
- is_container && echo "is_container=true" || echo "is_container=false"
- }
- write_result() {
- local runcfg="${PATH_RUN_CI_CFG}" ret="" line="" pre=""
- {
- if [ "$DI_MODE" = "report" ]; then
- echo "di_report:"
- pre=" "
- fi
- for line in "$@"; do
- echo "${pre}$line";
- done
- } > "$runcfg"
- ret=$?
- [ $ret -eq 0 ] || {
- error "failed to write to ${runcfg}"
- return $ret
- }
- return 0
- }
- record_notfound() {
- # in report mode, report nothing was found.
- # if not report mode: only report the negative result.
- # reporting an empty list would mean cloud-init would not search
- # any datasources.
- if [ "$DI_MODE" = "report" ]; then
- found --
- elif [ "$DI_MODE" = "search" ]; then
- local msg="# reporting not found result. notfound=${DI_ON_NOTFOUND}."
- local DI_MODE="report"
- found -- "$msg"
- fi
- }
- found() {
- # found(ds1, [ds2 ...], [-- [extra lines]])
- local list="" ds=""
- while [ $# -ne 0 ]; do
- if [ "$1" = "--" ]; then
- shift
- break
- fi
- list="${list:+${list}, }$1"
- shift
- done
- if [ $# -eq 1 ] && [ -z "$1" ]; then
- # do not pass an empty line through.
- shift
- fi
- # if None is not already in the list, then add it last.
- case " $list " in
- *\ None,\ *|*\ None\ ) :;;
- *) list=${list:+${list}, None};;
- esac
- write_result "datasource_list: [ $list ]" "$@"
- return
- }
- trim() {
- # shellcheck disable=2048,2086
- set -- $*
- _RET="$*"
- }
- unquote() {
- # remove quotes from quoted value
- local quote='"' tick="'"
- local val="$1"
- case "$val" in
- ${quote}*${quote}|${tick}*${tick})
- val=${val#?}; val=${val%?};;
- esac
- _RET="$val"
- }
- _read_config() {
- # reads config from stdin,
- # if no parameters are set, modifies _rc scoped environment vars.
- # if keyname is provided, then returns found value of that key.
- local keyname="${1:-_unset}"
- local line="" hash="#" key="" val=""
- while read line; do
- line=${line%%${hash}*}
- key="${line%%:*}"
- # no : in the line.
- [ "$key" = "$line" ] && continue
- trim "$key"
- key=${_RET}
- [ "$keyname" != "_unset" ] && [ "$keyname" != "$key" ] &&
- continue
- val="${line#*:}"
- trim "$val"
- unquote "${_RET}"
- val=${_RET}
- if [ "$keyname" = "$key" ]; then
- _RET="$val"
- return 0
- fi
- case "$key" in
- datasource) _rc_dsname="$val";;
- policy) _rc_policy="$val";;
- esac
- done
- if [ "$keyname" = "_unset" ]; then
- return 1
- fi
- _RET=""
- return 0
- }
- parse_warn() {
- echo "WARN: invalid value '$2' for key '$1'. Using $1=$3." 1>&2
- }
- parse_def_policy() {
- local _rc_mode="" _rc_report="" _rc_found="" _rc_maybe="" _rc_notfound=""
- local ret=""
- parse_policy "$@"
- ret=$?
- _def_mode=$_rc_mode
- _def_report=$_rc_report
- _def_found=$_rc_found
- _def_maybe=$_rc_maybe
- _def_notfound=$_rc_notfound
- return $ret
- }
- parse_policy() {
- # parse_policy(policy, default)
- # parse a policy string. sets
- # _rc_mode (enabled|disabled|search|report)
- # _rc_report true|false
- # _rc_found first|all
- # _rc_maybe all|none
- # _rc_notfound enabled|disabled
- local def=""
- case "$DI_UNAME_MACHINE" in
- # these have dmi data
- i?86|x86_64) def=${DI_DEFAULT_POLICY};;
- # aarch64 has dmi, but not currently used (LP: #1663304)
- aarch64) def=${DI_DEFAULT_POLICY_NO_DMI};;
- *) def=${DI_DEFAULT_POLICY_NO_DMI};;
- esac
- local policy="$1"
- local _def_mode="" _def_report="" _def_found="" _def_maybe=""
- local _def_notfound=""
- if [ $# -eq 1 ] || [ "$2" != "-" ]; then
- def=${2:-${def}}
- parse_def_policy "$def" -
- fi
- local mode="" report="" found="" maybe="" notfound=""
- local oifs="$IFS" tok="" val=""
- # shellcheck disable=2086
- { IFS=","; set -- $policy; IFS="$oifs"; }
- for tok in "$@"; do
- val=${tok#*=}
- case "$tok" in
- $DI_ENABLED|$DI_DISABLED|search|report) mode=$tok;;
- found=all|found=first) found=$val;;
- maybe=all|maybe=none) maybe=$val;;
- notfound=$DI_ENABLED|notfound=$DI_DISABLED) notfound=$val;;
- found=*)
- parse_warn found "$val" "${_def_found}"
- found=${_def_found};;
- maybe=*)
- parse_warn maybe "$val" "${_def_maybe}"
- maybe=${_def_maybe};;
- notfound=*)
- parse_warn notfound "$val" "${_def_notfound}"
- notfound=${_def_notfound};;
- esac
- done
- report=${report:-${_def_report:-false}}
- _rc_report=${report}
- _rc_mode=${mode:-${_def_mode}}
- _rc_found=${found:-${_def_found}}
- _rc_maybe=${maybe:-${_def_maybe}}
- _rc_notfound=${notfound:-${_def_notfound}}
- }
- read_config() {
- local config="${PATH_DI_CONFIG}"
- local _rc_dsname="" _rc_policy="" ret=""
- if [ -f "$config" ]; then
- _read_config < "$config"
- ret=$?
- elif [ -e "$config" ]; then
- error "$config exists but is not a file!"
- ret=1
- fi
- local tok="" key="" val=""
- for tok in ${DI_KERNEL_CMDLINE}; do
- key=${tok%%=*}
- val=${tok#*=}
- case "$key" in
- ci.ds) _rc_dsname="$val";;
- ci.datasource) _rc_dsname="$val";;
- ci.di.policy) _rc_policy="$val";;
- esac
- done
- local _rc_mode _rc_report _rc_found _rc_maybe _rc_notfound
- parse_policy "${_rc_policy}"
- debug 1 "policy loaded: mode=${_rc_mode} report=${_rc_report}" \
- "found=${_rc_found} maybe=${_rc_maybe} notfound=${_rc_notfound}"
- DI_MODE=${_rc_mode}
- DI_ON_FOUND=${_rc_found}
- DI_ON_MAYBE=${_rc_maybe}
- DI_ON_NOTFOUND=${_rc_notfound}
- DI_DSNAME="${_rc_dsname}"
- return $ret
- }
- manual_clean_and_existing() {
- [ -f "${PATH_VAR_LIB_CLOUD}/instance/manual-clean" ]
- }
- read_uptime() {
- local up _
- _RET="${UNAVAILABLE}"
- [ -f "$PATH_PROC_UPTIME" ] && read up _ < "$PATH_PROC_UPTIME" &&
- _RET="$up"
- return
- }
- _main() {
- local dscheck_fn="" ret_dis=1 ret_en=0
- read_uptime
- debug 1 "[up ${_RET}s]" "ds-identify $*"
- collect_info
- if [ "$DI_LOG" = "stderr" ]; then
- _print_info 1>&2
- else
- _print_info >> "$DI_LOG"
- fi
- case "$DI_MODE" in
- $DI_DISABLED)
- debug 1 "mode=$DI_DISABLED. returning $ret_dis"
- return $ret_dis
- ;;
- $DI_ENABLED)
- debug 1 "mode=$DI_ENABLED. returning $ret_en"
- return $ret_en;;
- search|report) :;;
- esac
- if [ -n "${DI_DSNAME}" ]; then
- debug 1 "datasource '$DI_DSNAME' specified."
- found "$DI_DSNAME"
- return
- fi
- if manual_clean_and_existing; then
- debug 1 "manual_cache_clean enabled. Not writing datasource_list."
- write_result "# manual_cache_clean."
- return
- fi
- # shellcheck disable=2086
- set -- $DI_DSLIST
- # if there is only a single entry in $DI_DSLIST
- if [ $# -eq 1 ] || [ $# -eq 2 -a "$2" = "None" ] ; then
- debug 1 "single entry in datasource_list ($DI_DSLIST) use that."
- found "$@"
- return
- fi
- local found="" ret="" ds="" maybe="" _RET_excfg=""
- local exfound_cfg="" exmaybe_cfg=""
- for ds in ${DI_DSLIST}; do
- dscheck_fn="dscheck_${ds}"
- debug 2 "Checking for datasource '$ds' via '$dscheck_fn'"
- if ! type "$dscheck_fn" >/dev/null 2>&1; then
- warn "No check method '$dscheck_fn' for datasource '$ds'"
- continue
- fi
- _RET_excfg=""
- $dscheck_fn
- ret="$?"
- case "$ret" in
- $DS_FOUND)
- debug 1 "check for '$ds' returned found";
- exfound_cfg="${exfound_cfg:+${exfound_cfg}${CR}}${_RET_excfg}"
- found="${found} $ds";;
- $DS_MAYBE)
- debug 1 "check for '$ds' returned maybe";
- exmaybe_cfg="${exmaybe_cfg:+${exmaybe_cfg}${CR}}${_RET_excfg}"
- maybe="${maybe} $ds";;
- *) debug 2 "check for '$ds' returned not-found[$ret]";;
- esac
- done
- debug 2 "found=${found# } maybe=${maybe# }"
- # shellcheck disable=2086
- set -- $found
- if [ $# -ne 0 ]; then
- if [ $# -eq 1 ]; then
- debug 1 "Found single datasource: $1"
- else
- # found=all
- debug 1 "Found $# datasources found=${DI_ON_FOUND}: $*"
- if [ "${DI_ON_FOUND}" = "first" ]; then
- set -- "$1"
- fi
- fi
- found "$@" -- "${exfound_cfg}"
- return
- fi
- # shellcheck disable=2086
- set -- $maybe
- if [ $# -ne 0 -a "${DI_ON_MAYBE}" != "none" ]; then
- debug 1 "$# datasources returned maybe: $*"
- found "$@" -- "${exmaybe_cfg}"
- return
- fi
- # record the empty result.
- record_notfound
- local basemsg="No ds found [mode=$DI_MODE, notfound=$DI_ON_NOTFOUND]."
- local msg="" ret=3
- case "$DI_MODE:$DI_ON_NOTFOUND" in
- report:$DI_DISABLED)
- msg="$basemsg Would disable cloud-init [$ret_dis]"
- ret=$ret_en;;
- report:$DI_ENABLED)
- msg="$basemsg Would enable cloud-init [$ret_en]"
- ret=$ret_en;;
- search:$DI_DISABLED)
- msg="$basemsg Disabled cloud-init [$ret_dis]"
- ret=$ret_dis;;
- search:$DI_ENABLED)
- msg="$basemsg Enabled cloud-init [$ret_en]"
- ret=$ret_en;;
- *) error "Unexpected result";;
- esac
- debug 1 "$msg"
- return "$ret"
- }
- main() {
- local ret=""
- ensure_sane_path
- [ -d "$PATH_RUN_CI" ] || mkdir -p "$PATH_RUN_CI"
- if [ "${1:+$1}" != "--force" ] && [ -f "$PATH_RUN_CI_CFG" ] &&
- [ -f "$PATH_RUN_DI_RESULT" ]; then
- if read ret < "$PATH_RUN_DI_RESULT"; then
- if [ "$ret" = "0" ] || [ "$ret" = "1" ]; then
- debug 2 "used cached result $ret. pass --force to re-run."
- return "$ret";
- fi
- debug 1 "previous run returned unexpected '$ret'. Re-running."
- else
- error "failed to read result from $PATH_RUN_DI_RESULT!"
- fi
- fi
- _main "$@"
- ret=$?
- echo "$ret" > "$PATH_RUN_DI_RESULT"
- read_uptime
- debug 1 "[up ${_RET}s]" "returning $ret"
- return "$ret"
- }
- noop() {
- :
- }
- case "${DI_MAIN}" in
- main|print_info|noop) "${DI_MAIN}" "$@";;
- *) error "unexpected value for DI_MAIN"; exit 1;;
- esac
- # vi: syntax=sh ts=4 expandtab
|