summaryrefslogtreecommitdiff
path: root/debian/cloud-init.postinst
diff options
context:
space:
mode:
Diffstat (limited to 'debian/cloud-init.postinst')
-rw-r--r--debian/cloud-init.postinst264
1 files changed, 264 insertions, 0 deletions
diff --git a/debian/cloud-init.postinst b/debian/cloud-init.postinst
new file mode 100644
index 00000000..a36fb248
--- /dev/null
+++ b/debian/cloud-init.postinst
@@ -0,0 +1,264 @@
+#!/bin/sh -e
+
+. /usr/share/debconf/confmodule
+
+set -f # disable pathname expansion
+db_capb escape # to support carriage return / multi-line values
+
+update_cfg() {
+ # takes filename, header, new object (in yaml), optionally 'remover'
+ # and merges new into existing object in filename, and then updates file
+ # remover a string that means "delete existing entry"
+ python3 -c '
+import sys, yaml
+
+def update(src, cand):
+ if not (isinstance(src, dict) and isinstance(cand, dict)):
+ return cand
+ for k, v in cand.items():
+ # if the candidate has _ as value, delete source
+ if v == REMOVER:
+ if k in src:
+ del src[k]
+ continue
+ if k not in src:
+ src[k] = v
+ else:
+ src[k] = update(src[k], v)
+ return src
+
+(fname, header, newyaml) = sys.argv[1:4]
+REMOVER = object
+if len(sys.argv) == 5:
+ REMOVER = sys.argv[4]
+newcfg = yaml.load(newyaml)
+
+with open(fname, "r") as fp:
+ cfg = yaml.load(fp)
+if not cfg: cfg = {}
+
+cfg = update(cfg, newcfg)
+
+with open(fname, "w") as fp:
+ fp.write(header + "\n")
+ fp.write(yaml.dump(cfg))' "$@"
+}
+
+handle_preseed_maas() {
+ local cfg_file="/etc/cloud/cloud.cfg.d/90_dpkg_maas.cfg"
+ local md_url="" creds_all="" c_key="" t_key="" t_sec="" c_sec="";
+
+ db_get "cloud-init/maas-metadata-url" && md_url="$RET" || :
+ db_get "cloud-init/maas-metadata-credentials" && creds_all="$RET" || :
+
+ # nothing to do
+ [ -n "$md_url" -o -n "$creds_all" ] || return 0
+
+ # change a url query string format into : delimited
+ if [ -n "$creds_all" -a "${creds_all#*&}" != "${creds_all}" ]; then
+ # the command here ends up looking like:
+ # python3 -c '...' 'oauth_consumer_key=v1&oauth_token_key=v2...' \
+ # oauth_consumer_key oauth_token_key oauth_token_secret
+ creds_all=$(python3 -c 'from six.moves.urllib.parse import parse_qs;
+import sys;
+keys = parse_qs(sys.argv[1])
+for k in sys.argv[2:]:
+ sys.stdout.write("%s:" % keys.get(k,[""])[0])' "$creds_all" \
+ oauth_consumer_key oauth_token_key oauth_token_secret
+)
+ fi
+
+ # now, if non-empty creds_all is: consumer_key:token_key:token_secret
+ if [ -n "$creds_all" ]; then
+ OIFS="$IFS"; IFS=:; set -- $creds_all; IFS="$OIFS"
+ c_key=$1; t_key=$2; t_sec=$3
+ fi
+
+ if [ "$md_url" = "_" -a "${c_key}:${t_key}:${t_sec}" = "_:_:_" ]; then
+ # if all these values were '_', the delete value, just delete the file.
+ rm -f "$cfg_file"
+ else
+ local header="# written by cloud-init debian package per preseed entries
+# cloud-init/{maas-metadata-url,/maas-metadata-credentials}"
+
+ local pair="" k="" v="" pload="" orig_umask=""
+ for pair in "metadata_url:$md_url" "consumer_key:${c_key}" \
+ "token_key:${t_key}" "token_secret:$t_sec"; do
+ k=${pair%%:*}
+ v=${pair#${k}:}
+ [ -n "$v" ] && pload="${pload} $k: \"$v\","
+ done
+
+ # '_' would indicate "delete", otherwise, existing entries are left
+ orig_umask=$(umask)
+ umask 066
+ : >> "$cfg_file" && chmod 600 "$cfg_file"
+ update_cfg "$cfg_file" "$header" "datasource: { MAAS: { ${pload%,} } }" _
+ umask ${orig_umask}
+ fi
+
+ # now clear the database of the values, as they've been consumed
+ db_unregister "cloud-init/maas-metadata-url" || :
+ db_unregister "cloud-init/maas-metadata-credentials" || :
+}
+
+handle_preseed_local_cloud_config() {
+ local ccfg="" debconf_name="cloud-init/local-cloud-config"
+ local cfg_file="/etc/cloud/cloud.cfg.d/90_dpkg_local_cloud_config.cfg"
+ local header="# written by cloud-init debian package per preseed entry
+# $debconf_name"
+
+ db_get "${debconf_name}" && ccfg="$RET" || :
+
+ if [ "$ccfg" = "_" ]; then
+ rm -f "$cfg_file"
+ elif [ -n "$ccfg" ]; then
+ { echo "$header"; echo "$ccfg"; } > "$cfg_file"
+ fi
+ db_unregister "${debconf_name}" || :
+}
+
+fix_1336855() {
+ ### Begin fix for LP: 1336855
+ # fix issue where cloud-init misidentifies the location of grub and
+ # where grub misidentifies the location of the device
+
+ # if cloud-init's grub module did not run, then it did not break anything.
+ [ -f /var/lib/cloud/instance/sem/config_grub_dpkg ] || return 0
+
+ # This bug only happened on /dev/xvda devices
+ [ -b /dev/xvda ] || return 0
+
+ # we can't fix the system without /proc/cmdline
+ [ -r /proc/cmdline ] || return 0
+
+ # Don't do anything unless we have grub
+ [ -x /usr/sbin/grub-install ] || return 0
+
+ # First, identify the kernel device for the parent.
+ for parm in $(cat /proc/cmdline); do
+ dev=$(echo $parm | awk -F\= '{print$NF}')
+ case $parm in
+ root=UUID*) [ -d /dev/disk/by-uuid ] &&
+ root_dev=$(readlink -f /dev/disk/by-uuid/$dev);;
+ root=LABEL*) [ -d /dev/disk/by-label ] &&
+ root_dev=$(readlink -f /dev/disk/by-label/$dev);;
+ root=/dev*) [ -d /dev ] &&
+ root_dev=$(readlink -f $dev);;
+ esac
+ [ -n "$root_dev" ] && break
+ done
+
+ # Don't continue if we don't have a root directive
+ [ -z "$root_dev" ] && return 0
+
+ # Only deal with simple, cloud-based devices
+ case $root_dev in
+ /dev/vda*|/dev/xvda*|/dev/sda*) ;;
+ *) return 0;;
+ esac
+
+ # Make sure that we are not chrooted.
+ [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ] && return 0
+
+ # Check if we are in a container, i.e. LXC
+ if systemd-detect-virt --quiet --container || lxc-is-container 2>/dev/null; then
+ return 0
+ fi
+
+ # Find out where grub thinks the root device is. Only continue if
+ # grub postinst would install/reinstall grub
+ db_get grub-pc/install_devices && grub_cfg_dev=${RET} || return 0
+ db_get grub-pc/install_devices_empty && grub_dev_empty=${RET} || return 0
+
+ # Find out the parent device for the root device.
+ # example output: sda/sda1
+ block_path=$(udevadm info -q path -n $root_dev | awk '-Fblock/' '{print$NF}')
+
+ # Extract the parent device name. This works where the device is a block device
+ # example output: /dev/sda
+ parent_dev=$(echo $block_path | awk '-F/' '$1 { if ( $1 ) {print"/dev/"$1}}')
+ [ -b "${parent_dev}" ] || return 0
+
+ # Do nothing if the device that the grub postinst would install is already used
+ [ "$grub_cfg_dev" = "$parent_dev" -o "$grub_cfg_dev" = "$root_dev" ] && return 0
+
+ # If we get here, do the installation
+ echo "Reconfiguring grub install device due to mismatch (LP: #1336855)"
+ echo " Grub should use $parent_dev but is configured for $grub_cfg_dev"
+ db_set grub-pc/install_devices "$parent_dev"
+ grub-install $parent_dev &&
+ echo "Reinstalled grub" ||
+ echo "WARNING! Unable to fix grub device mismatch. You may be broken."
+
+}
+
+cleanup_lp1552999() {
+ local oldver="$1" last_bad_ver="0.7.7~bzr1178"
+ dpkg --compare-versions "$oldver" le "$last_bad_ver" || return 0
+ local edir="/etc/systemd/system/multi-user.target.wants"
+ rm -f "$edir/cloud-config.service" "$edir/cloud-final.service" \
+ "$edir/cloud-init-local.service" "$edir/cloud-init.service"
+}
+
+disable_network_config_on_upgrade() {
+ local oldver="$1" last_without_net="0.7.7~bzr1182-0ubuntu1"
+ if [ ! -f /var/lib/cloud/instance/obj.pkl ]; then
+ # this is a fresh system not one that has been booted.
+ return 0
+ fi
+ if dpkg --compare-versions "$oldver" le "$last_without_net"; then
+ echo "dpkg upgrade from $oldver" > /var/lib/cloud/data/upgraded-network
+ fi
+}
+
+if [ "$1" = "configure" ]; then
+ # disable ureadahead (LP: #499520)
+ dpkg-divert --package cloud-init --rename --divert \
+ /etc/init/ureadahead.conf.disabled --add /etc/init/ureadahead.conf
+ if db_get cloud-init/datasources; then
+ values="$RET"
+ if [ "${values#*MaaS}" != "${values}" ]; then
+ # if db had old MAAS spelling, fix it.
+ values=$(echo "$values" | sed 's,MaaS,MAAS,g')
+ db_set cloud-init/datasources "$values"
+ fi
+ cat > /etc/cloud/cloud.cfg.d/90_dpkg.cfg <<EOF
+# to update this file, run dpkg-reconfigure cloud-init
+datasource_list: [ $values ]
+EOF
+ fi
+
+ # we want to affect apt_pipelining on install, not wait for
+ # cloud-init to run it on next boot.
+ pipeline_f="/etc/apt/apt.conf.d/90cloud-init-pipelining"
+ if [ -f /var/lib/cloud/instance/obj.pkl ]; then
+ cloud-init single --name apt-pipelining --frequency once >/dev/null 2>&1 ||
+ echo "Warning: failed to setup apt-pipelining" 1>&2
+ elif [ ! -f "$pipeline_f" ]; then
+ # there was no cloud available, so populate it ourselves.
+ cat > "$pipeline_f" <<EOF
+//Written by cloud-init per 'apt_pipelining'
+Acquire::http::Pipeline-Depth "0";
+EOF
+ fi
+
+ # if there are maas settings pre-seeded apply them
+ handle_preseed_maas
+
+ # if there is generic cloud-config preseed, apply them
+ handle_preseed_local_cloud_config
+
+ # fix issue where cloud-init misidentifies the location of grub
+ fix_1336855
+
+ # make upgrades disable network changes by cloud-init
+ disable_network_config_on_upgrade "$2"
+fi
+
+#DEBHELPER#
+
+if [ "$1" = "configure" ]; then
+ oldver="$2"
+ cleanup_lp1552999 "$oldver"
+fi