[ostree] Add infrastructure for automatic kernel updates



commit a97bcc68d71115a45bc3f1346214181b7937d28a
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Tue Aug 14 00:11:50 2012 +0200

    Add infrastructure for automatic kernel updates
    
    If the distribution supports running arbitrary scripts at kernel
    updates, we can hook into it and update the ostree side of things
    automatically.

 Makefile-ostadmin.am                 |   13 ++
 configure.ac                         |    8 +
 src/ostadmin/15_ostree               |   66 ---------
 src/ostadmin/grub2/15_ostree         |  253 ++++++++++++++++++++++++++++++++++
 src/ostadmin/kernel/15_ostree_remove |   11 ++
 src/ostadmin/kernel/15_ostree_update |   10 ++
 6 files changed, 295 insertions(+), 66 deletions(-)
---
diff --git a/Makefile-ostadmin.am b/Makefile-ostadmin.am
index df22f8b..76df1cb 100644
--- a/Makefile-ostadmin.am
+++ b/Makefile-ostadmin.am
@@ -28,3 +28,16 @@ ostadmin_SOURCES = src/ostadmin/main.c \
 
 ostadmin_CFLAGS =  $(AM_CFLAGS) -I$(srcdir)/src/libgsystem -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -I$(srcdir)/src/ostadmin -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS)
 ostadmin_LDADD = libgsystem.la libotutil.la libostree.la $(OT_INTERNAL_GIO_UNIX_LIBS)
+
+if ENABLE_KERNEL_UPDATES
+
+grub2dir = $(sysconfdir)/grub.d
+grub2_SCRIPTS = src/ostadmin/grub2/15_ostree
+
+kernelpostinstdir = $(sysconfdir)/kernel/postinst.d
+kernelpostinst_SCRIPTS = src/ostadmin/kernel/15_ostree_update
+
+kernelprermdir = $(sysconfdir)/kernel/prerm.d
+kernelprerm_SCRIPTS = src/ostadmin/kernel/15_ostree_remove
+
+endif
diff --git a/configure.ac b/configure.ac
index 081d8af..6f32df3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,6 +97,13 @@ AS_IF([ test x$with_libarchive != xno ], [
 ])
 AM_CONDITIONAL(USE_LIBARCHIVE, test $with_libarchive != no)
 
+AC_ARG_ENABLE(kernel-updates,
+              AS_HELP_STRING([--enable-kernel-updates],
+	      [Install configuration scripts to handle kernel updates
+	       in the host system]), ,
+	      enable_kernel_updates=yes)
+AM_CONDITIONAL(ENABLE_KERNEL_UPDATES, test $enable_kernel_updates != no)
+
 AC_CONFIG_FILES([
 Makefile
 embedded-dependencies/Makefile
@@ -111,4 +118,5 @@ echo "
     embedded dependencies: $enable_embedded_dependencies
     libsoup (retrieve remote HTTP repositories): $with_soup
     libarchive (parse tar files directly): $with_libarchive
+    kernel updates integration: $enable_kernel_updates
 "
diff --git a/src/ostadmin/grub2/15_ostree b/src/ostadmin/grub2/15_ostree
new file mode 100755
index 0000000..6f9d51b
--- /dev/null
+++ b/src/ostadmin/grub2/15_ostree
@@ -0,0 +1,253 @@
+#! /bin/sh
+set -e
+
+# grub-mkconfig helper script.
+# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
+#
+# GRUB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GRUB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+
+prefix="/usr"
+exec_prefix="/usr"
+datarootdir="${prefix}/share"
+
+. "/usr/share/grub/grub-mkconfig_lib"
+
+export TEXTDOMAIN=grub
+export TEXTDOMAINDIR="${datarootdir}/locale"
+
+CLASS="--class gnu-linux --class gnu --class os --class ostree"
+OS="GNOME OS (Ostree)"
+
+# loop-AES arranges things so that /dev/loop/X can be our root device, but
+# the initrds that Linux uses don't like that.
+case ${GRUB_DEVICE} in
+  /dev/loop/*|/dev/loop[0-9])
+    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
+  ;;
+esac
+
+if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
+    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
+    || uses_abstraction "${GRUB_DEVICE}" lvm; then
+  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
+else
+  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
+fi
+
+GRUBFS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`"
+
+if [ x"$GRUBFS" = x ]; then
+    GRUBFS="$(stat -f --printf=%T / || true)"
+fi
+
+case x"$GRUBFS" in
+    xbtrfs)
+	rootsubvol="`make_system_path_relative_to_its_root /`"
+	rootsubvol="${rootsubvol#/}"
+	if [ "x${rootsubvol}" != x ]; then
+	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
+	fi;;
+    xzfs)
+	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
+	bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`"
+	LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs}"
+	;;
+esac
+
+title_correction_code=
+
+linux_entry ()
+{
+  os="$1"
+  version="$2"
+  type="$3"
+  args="$4"
+
+  if [ -z "$boot_device_id" ]; then
+      boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+  fi
+  if [ x$type != xsimple ] ; then
+      case $type in
+	  recovery)
+	      title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
+	  *)
+	      title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+      esac
+      if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
+	  replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
+	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
+	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
+	  grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
+      fi
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+  else
+      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+  fi      
+  if [ x$type != xrecovery ] ; then
+      save_default_entry | sed -e "s/^/\t/"
+  fi
+
+  # Use ELILO's generic "efifb" when it's known to be available.
+  # FIXME: We need an interface to select vesafb in case efifb can't be used.
+  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
+      echo "	load_video" | sed "s/^/$submenu_indentation/"
+      if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \
+	  && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
+	  echo "	set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
+      fi
+  else
+      if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
+	  echo "	load_video" | sed "s/^/$submenu_indentation/"
+      fi
+      echo "	set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
+  fi
+
+  echo "	insmod gzio" | sed "s/^/$submenu_indentation/"
+
+  if [ x$dirname = x/ ]; then
+    if [ -z "${prepare_root_cache}" ]; then
+      prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/")"
+    fi
+    printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
+  else
+    if [ -z "${prepare_boot_cache}" ]; then
+      prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
+    fi
+    printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+  fi
+  message="$(gettext_printf "Loading Linux %s ..." ${version})"
+  sed "s/^/$submenu_indentation/" << EOF
+	echo	'$message'
+	linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
+EOF
+  if test -n "${initrd}" ; then
+    # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+    message="$(gettext_printf "Loading initial ramdisk ...")"
+    sed "s/^/$submenu_indentation/" << EOF
+	echo	'$message'
+	initrd	${rel_dirname}/${initrd}
+EOF
+  fi
+  sed "s/^/$submenu_indentation/" << EOF
+}
+EOF
+}
+
+machine=`uname -m`
+case "x$machine" in
+    xi?86 | xx86_64)
+	list=`for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do
+                  if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+              done` ;;
+    *) 
+	list=`for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do
+                  if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+	     done` ;;
+esac
+
+case "$machine" in
+    i?86) GENKERNEL_ARCH="x86" ;;
+    mips|mips64) GENKERNEL_ARCH="mips" ;;
+    mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
+    arm*) GENKERNEL_ARCH="arm" ;;
+    *) GENKERNEL_ARCH="$machine" ;;
+esac
+
+prepare_boot_cache=
+prepare_root_cache=
+boot_device_id=
+title_correction_code=
+
+# Extra indentation to add to menu entries in a submenu. We're not in a submenu
+# yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
+submenu_indentation=""
+
+is_first_entry=true
+while [ "x$list" != "x" ] ; do
+  linux=`version_find_latest $list`
+  gettext_printf "Found linux image: %s\n" "$linux" >&2
+  basename=`basename $linux`
+  dirname=`dirname $linux`
+  rel_dirname=`make_system_path_relative_to_its_root $dirname`
+  version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
+  alt_version=`echo $version | sed -e "s,\.old$,,g"`
+  linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
+
+  initrd=
+  config=
+  initramfs=
+
+  for i in "initrd.img-ostree-${version}" "initrd-ostree-${version}.img" "initrd-ostree-${version}.gz" \
+	   "initrd-ostree-${version}" "initramfs-ostree-${version}.img" \
+	   "initrd.img-ostree-${alt_version}" "initrd-ostree-${alt_version}.img" \
+	   "initrd-ostree-${alt_version}" "initramfs-ostree-${alt_version}.img"; do
+    if test -e "${dirname}/${i}" ; then
+      initrd="$i"
+      break
+    fi
+  done
+
+  config=
+  for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
+    if test -e "${i}" ; then
+      config="${i}"
+      break
+    fi
+  done
+
+  initramfs=
+  if test -n "${config}" ; then
+      initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"`
+  fi
+
+  if test -n "${initrd}" ; then
+    gettext_printf "Found initrd image: %s\n" "${dirname}/${initrd}" >&2
+  elif test -z "${initramfs}" ; then
+    # ostree can't work without initrd
+    gettext_printf "Skipping version %s (missing initrd)\n" "${version}" >&2
+    list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
+    continue
+  fi
+
+  if [ "x$is_first_entry" = xtrue ]; then
+    linux_entry "${OS}" "${version}" simple \
+    "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ostree=${GRUB_OSTREE_REVISION}"
+
+    submenu_indentation="\t"
+    
+    if [ -z "$boot_device_id" ]; then
+	boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+    fi
+    # TRANSLATORS: %s is replaced with an OS name
+    echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {"
+  fi
+
+  linux_entry "${OS}" "${version}" advanced \
+              "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ostree=${GRUB_OSTREE_REVISION}"
+  if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+    linux_entry "${OS}" "${version}" recovery \
+                "single ${GRUB_CMDLINE_LINUX} ostree=${GRUB_OSTREE_REVISION}"
+  fi
+
+  list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
+  is_first_entry=false
+done
+
+# If at least one kernel was found, then we need to
+# add a closing '}' for the submenu command.
+if [ x"$is_first_entry" != xtrue ]; then
+  echo '}'
+fi
+
+echo "$title_correction_code"
diff --git a/src/ostadmin/kernel/15_ostree_remove b/src/ostadmin/kernel/15_ostree_remove
new file mode 100755
index 0000000..53b2a6e
--- /dev/null
+++ b/src/ostadmin/kernel/15_ostree_remove
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+version=$1
+
+if [ -z "$version" ]; then
+    echo "$0: kernel version required"
+    exit 1
+fi
+
+rm -fR "/ostree/modules/${version}"
+rm -fR "/boot/initramfs-ostree-${version}.img"
diff --git a/src/ostadmin/kernel/15_ostree_update b/src/ostadmin/kernel/15_ostree_update
new file mode 100755
index 0000000..4cdac1c
--- /dev/null
+++ b/src/ostadmin/kernel/15_ostree_update
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+version=$1
+
+if [ -z "$version" ]; then
+    echo "$0: kernel version required"
+    exit 1
+fi
+
+ostadmin update-kernel current/ ${version}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]