[Libguestfs] [PATCH 2/3] inspection: Add support for CoreOS

Nikos Skalkotos skalkoto at grnet.gr
Fri May 29 09:24:58 UTC 2015


* Implement coreos distro
* Detect CoreOS images

Signed-off-by: Nikos Skalkotos <skalkoto at grnet.gr>
---
 generator/actions.ml   |  4 +++
 src/guestfs-internal.h |  3 +++
 src/inspect-fs-unix.c  | 69 +++++++++++++++++++++++++++++++++++++++++++++++---
 src/inspect-fs.c       | 21 +++++++++++++++
 src/inspect-icon.c     |  1 +
 src/inspect.c          | 62 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 157 insertions(+), 3 deletions(-)

diff --git a/generator/actions.ml b/generator/actions.ml
index e9374a3..e1b14ca 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -1073,6 +1073,10 @@ Cirros.
 
 =item \"debian\"
 
+CoreOS.
+
+=item \"coreos\"
+
 Debian.
 
 =item \"fedora\"
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index 01cbca7..1462673 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -551,6 +551,7 @@ enum inspect_os_distro {
   OS_DISTRO_ORACLE_LINUX,
   OS_DISTRO_FREEBSD,
   OS_DISTRO_NETBSD,
+  OS_DISTRO_COREOS,
 };
 
 enum inspect_os_package_format {
@@ -797,6 +798,8 @@ extern int guestfs_int_check_netbsd_root (guestfs_h *g, struct inspect_fs *fs);
 extern int guestfs_int_check_openbsd_root (guestfs_h *g, struct inspect_fs *fs);
 extern int guestfs_int_check_hurd_root (guestfs_h *g, struct inspect_fs *fs);
 extern int guestfs_int_check_minix_root (guestfs_h *g, struct inspect_fs *fs);
+extern int guestfs_int_check_coreos_root (guestfs_h *g, struct inspect_fs *fs);
+extern int guestfs_int_check_coreos_usr (guestfs_h *g, struct inspect_fs *fs);
 
 /* inspect-fs-windows.c */
 extern char *guestfs_int_case_sensitive_path_silently (guestfs_h *g, const char *);
diff --git a/src/inspect-fs-unix.c b/src/inspect-fs-unix.c
index 2abbf24..ff50b2a 100644
--- a/src/inspect-fs-unix.c
+++ b/src/inspect-fs-unix.c
@@ -160,11 +160,16 @@ parse_release_file (guestfs_h *g, struct inspect_fs *fs,
  *   DISTRIB_CODENAME=Henry_Farman
  *   DISTRIB_DESCRIPTION="Mandriva Linux 2010.1"
  * Mandriva also has a normal release file called /etc/mandriva-release.
+ *
+ * CoreOS has a /etc/lsb-release link to /usr/share/coreos/lsb-release containing:
+ *   DISTRIB_ID=CoreOS
+ *   DISTRIB_RELEASE=647.0.0
+ *   DISTRIB_CODENAME="Red Dog"
+ *   DISTRIB_DESCRIPTION="CoreOS 647.0.0"
  */
 static int
-parse_lsb_release (guestfs_h *g, struct inspect_fs *fs)
+parse_lsb_release (guestfs_h *g, struct inspect_fs *fs, const char *filename)
 {
-  const char *filename = "/etc/lsb-release";
   int64_t size;
   CLEANUP_FREE_STRING_LIST char **lines = NULL;
   size_t i;
@@ -208,6 +213,11 @@ parse_lsb_release (guestfs_h *g, struct inspect_fs *fs)
       fs->distro = OS_DISTRO_MAGEIA;
       r = 1;
     }
+    else if (fs->distro == 0 &&
+             STREQ (lines[i], "DISTRIB_ID=CoreOS")) {
+      fs->distro = OS_DISTRO_COREOS;
+      r = 1;
+    }
     else if (STRPREFIX (lines[i], "DISTRIB_RELEASE=")) {
       char *major, *minor;
       if (match2 (g, &lines[i][16], re_major_minor, &major, &minor)) {
@@ -338,7 +348,7 @@ guestfs_int_check_linux_root (guestfs_h *g, struct inspect_fs *fs)
 
   if (guestfs_is_file_opts (g, "/etc/lsb-release",
                             GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
-    r = parse_lsb_release (g, fs);
+    r = parse_lsb_release (g, fs, "/etc/lsb-release");
     if (r == -1)        /* error */
       return -1;
     if (r == 1)         /* ok - detected the release from this file */
@@ -795,6 +805,59 @@ guestfs_int_check_minix_root (guestfs_h *g, struct inspect_fs *fs)
   return 0;
 }
 
+/* The currently mounted device is a CoreOS root. From this partition we can
+ * only determine the hostname. All immutable OS files are under a separate
+ * read-only /usr partition.
+ */
+int
+guestfs_int_check_coreos_root (guestfs_h *g, struct inspect_fs *fs)
+{
+  fs->type = OS_TYPE_LINUX;
+  fs->distro = OS_DISTRO_COREOS;
+
+  /* Determine hostname. */
+  if (check_hostname_unix (g, fs) == -1)
+    return -1;
+
+  /* CoreOS does not contain /etc/fstab to determine the mount points.
+   * Associate this filesystem with the "/" mount point.
+   */
+  if (add_fstab_entry (g, fs, fs->mountable, "/") == -1)
+    return -1;
+
+  return 0;
+}
+
+/* The currently mounted device looks like a CoreOS /usr. In CoreOS
+ * the read-only /usr contains the OS version. The /etc/os-release is a
+ * link to /usr/share/coreos/os-release.
+ */
+int
+guestfs_int_check_coreos_usr (guestfs_h *g, struct inspect_fs *fs)
+{
+  int r;
+
+  fs->type = OS_TYPE_LINUX;
+  fs->distro = OS_DISTRO_COREOS;
+  if (guestfs_is_file_opts (g, "/share/coreos/lsb-release",
+                            GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
+    r = parse_lsb_release (g, fs, "/share/coreos/lsb-release");
+    if (r == -1)        /* error */
+      return -1;
+  }
+
+  /* Determine the architecture. */
+  check_architecture (g, fs);
+
+  /* CoreOS does not contain /etc/fstab to determine the mount points.
+   * Associate this filesystem with the "/usr" mount point.
+   */
+  if (add_fstab_entry (g, fs, fs->mountable, "/usr") == -1)
+    return -1;
+
+  return 0;
+}
+
 static void
 check_architecture (guestfs_h *g, struct inspect_fs *fs)
 {
diff --git a/src/inspect-fs.c b/src/inspect-fs.c
index 5f55f1d..64f904f 100644
--- a/src/inspect-fs.c
+++ b/src/inspect-fs.c
@@ -232,6 +232,17 @@ check_filesystem (guestfs_h *g, const char *mountable,
     if (guestfs_int_check_linux_root (g, fs) == -1)
       return -1;
   }
+  /* CoreOS root? */
+  else if (is_dir_etc &&
+           guestfs_is_dir (g, "/root") > 0 &&
+           guestfs_is_dir (g, "/home") > 0 &&
+           guestfs_is_dir (g, "/usr") > 0 &&
+           guestfs_is_file (g, "/etc/coreos/update.conf") > 0) {
+    fs->is_root = 1;
+    fs->format = OS_FORMAT_INSTALLED;
+    if (guestfs_int_check_coreos_root (g, fs) == -1)
+      return -1;
+  }
   /* Linux /usr/local? */
   else if (is_dir_etc &&
            is_dir_bin &&
@@ -246,6 +257,14 @@ check_filesystem (guestfs_h *g, const char *mountable,
            guestfs_is_dir (g, "/local") > 0 &&
            guestfs_is_file (g, "/etc/fstab") == 0)
     ;
+  /* CoreOS /usr? */
+  else if (is_dir_bin &&
+           is_dir_share &&
+           guestfs_is_dir (g, "/local") > 0 &&
+           guestfs_is_dir (g, "/share/coreos") > 0) {
+    if (guestfs_int_check_coreos_usr (g, fs) == -1)
+      return -1;
+  }
   /* Linux /var? */
   else if (guestfs_is_dir (g, "/log") > 0 &&
            guestfs_is_dir (g, "/run") > 0 &&
@@ -476,6 +495,7 @@ guestfs_int_check_package_format (guestfs_h *g, struct inspect_fs *fs)
 
   case OS_DISTRO_SLACKWARE:
   case OS_DISTRO_TTYLINUX:
+  case OS_DISTRO_COREOS:
   case OS_DISTRO_WINDOWS:
   case OS_DISTRO_BUILDROOT:
   case OS_DISTRO_CIRROS:
@@ -546,6 +566,7 @@ guestfs_int_check_package_management (guestfs_h *g, struct inspect_fs *fs)
 
   case OS_DISTRO_SLACKWARE:
   case OS_DISTRO_TTYLINUX:
+  case OS_DISTRO_COREOS:
   case OS_DISTRO_WINDOWS:
   case OS_DISTRO_BUILDROOT:
   case OS_DISTRO_CIRROS:
diff --git a/src/inspect-icon.c b/src/inspect-icon.c
index fb998c2..57b2ce3 100644
--- a/src/inspect-icon.c
+++ b/src/inspect-icon.c
@@ -169,6 +169,7 @@ guestfs_impl_inspect_get_icon (guestfs_h *g, const char *root, size_t *size_r,
       /* These are just to keep gcc warnings happy. */
     case OS_DISTRO_ARCHLINUX:
     case OS_DISTRO_BUILDROOT:
+    case OS_DISTRO_COREOS:
     case OS_DISTRO_FREEDOS:
     case OS_DISTRO_GENTOO:
     case OS_DISTRO_LINUX_MINT:
diff --git a/src/inspect.c b/src/inspect.c
index f528bf2..dd6a06f 100644
--- a/src/inspect.c
+++ b/src/inspect.c
@@ -42,6 +42,7 @@
 COMPILE_REGEXP (re_primary_partition, "^/dev/(?:h|s|v)d.[1234]$", 0)
 
 static void check_for_duplicated_bsd_root (guestfs_h *g);
+static int collect_coreos_inspection_info (guestfs_h *g);
 
 /* The main inspection code. */
 char **
@@ -70,6 +71,15 @@ guestfs_impl_inspect_os (guestfs_h *g)
     }
   }
 
+  /* The OS inspection information for CoreOS are gathered by inspecting
+   * multiple filesystems. Gather all the inspected information in the
+   * inspect_fs struct of the root filesystem.
+   */
+  if (collect_coreos_inspection_info (g)) {
+    guestfs_int_free_inspect_info (g);
+    return NULL;
+  }
+
   /* Check if the same filesystem was listed twice as root in g->fses.
    * This may happen for the *BSD root partition where an MBR partition
    * is a shadow of the real root partition probably /dev/sda5
@@ -87,6 +97,57 @@ guestfs_impl_inspect_os (guestfs_h *g)
   return ret;
 }
 
+/* Traverse through the filesystem list and find out if it contains the
+ * "/" and "/usr" filesystems of a CoreOS image. If this is the case,
+ * sum up all the collected information on the root fs.
+ */
+static int
+collect_coreos_inspection_info (guestfs_h *g)
+{
+  size_t i;
+  struct inspect_fs *root = NULL, *usr = NULL;
+
+  for (i = 0; i < g->nr_fses; ++i) {
+    struct inspect_fs *fs = &g->fses[i];
+
+    if (fs->distro == OS_DISTRO_COREOS && fs->is_root)
+      root = fs;
+  }
+
+  if (root == NULL)
+    return 0;
+
+  for (i = 0; i < g->nr_fses; ++i) {
+    struct inspect_fs *fs = &g->fses[i];
+
+    if (fs->distro != OS_DISTRO_COREOS || fs->is_root != 0)
+      continue;
+
+    /* CoreOS is designed to contain 2 /usr partitions (USR-A, USR-B):
+     * https://coreos.com/docs/sdk-distributors/sdk/disk-partitions/
+     * One is active and one passive. During the initial boot, the passive
+     * partition is empty and it gets filled up when an update is performed.
+     * Then, when the system reboots, the boot loader is instructed to boot
+     * from the passive partition. If both partitions are valid, we cannot
+     * determine which the active and which the passive is, unless we peep into
+     * the boot loader. As a workaround, we check the OS versions and pick the
+     * one with the higher version as active.
+     */
+    if (usr &&
+        (usr->major_version > fs->major_version ||
+         (usr->major_version == fs->major_version &&
+          usr->minor_version > fs->minor_version)))
+      continue;
+
+    usr = fs;
+  }
+
+  if (usr == NULL)
+    return 0;
+
+  return guestfs_int_merge_fs_inspections (g, root, usr);
+}
+
 /* On *BSD systems, sometimes /dev/sda[1234] is a shadow of the real root
  * filesystem that is probably /dev/sda5
  * (see: http://www.freebsd.org/doc/handbook/disk-organization.html)
@@ -201,6 +262,7 @@ guestfs_impl_inspect_get_distro (guestfs_h *g, const char *root)
   case OS_DISTRO_BUILDROOT: ret = safe_strdup (g, "buildroot"); break;
   case OS_DISTRO_CENTOS: ret = safe_strdup (g, "centos"); break;
   case OS_DISTRO_CIRROS: ret = safe_strdup (g, "cirros"); break;
+  case OS_DISTRO_COREOS: ret = safe_strdup (g, "coreos"); break;
   case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break;
   case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break;
   case OS_DISTRO_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
-- 
2.1.0




More information about the Libguestfs mailing list