[gnome-ostree] qa: Extract out guestfish helper code, various fixes to deploy/grub config



commit a660ce929196bd42c6c665b1d4960cbb5d8c1d79
Author: Colin Walters <walters verbum org>
Date:   Wed Jan 9 18:57:36 2013 -0500

    qa: Extract out guestfish helper code, various fixes to deploy/grub config

 Makefile-ostbuild.am                       |    1 +
 src/ostbuild/js/builtins/qa_make_disk.js   |   12 ++--
 src/ostbuild/js/builtins/qa_pull_deploy.js |   79 ++++++++++++++++------------
 src/ostbuild/js/guestfish.js               |   62 ++++++++++++++++++++++
 4 files changed, 114 insertions(+), 40 deletions(-)
---
diff --git a/Makefile-ostbuild.am b/Makefile-ostbuild.am
index 9740386..90f9979 100644
--- a/Makefile-ostbuild.am
+++ b/Makefile-ostbuild.am
@@ -45,6 +45,7 @@ jsostbuild_DATA= \
 	src/ostbuild/js/jsondb.js \
 	src/ostbuild/js/jsonutil.js \
 	src/ostbuild/js/main.js \
+	src/ostbuild/js/guestfish.js \
 	src/ostbuild/js/params.js \
 	src/ostbuild/js/procutil.js \
 	src/ostbuild/js/snapshot.js \
diff --git a/src/ostbuild/js/builtins/qa_make_disk.js b/src/ostbuild/js/builtins/qa_make_disk.js
index f6ca0fc..b125505 100644
--- a/src/ostbuild/js/builtins/qa_make_disk.js
+++ b/src/ostbuild/js/builtins/qa_make_disk.js
@@ -25,6 +25,7 @@ const GSystem = imports.gi.GSystem;
 
 const ArgParse = imports.argparse;
 const ProcUtil = imports.procutil;
+const GuestFish = imports.guestfish;
 
 const loop = GLib.MainLoop.new(null, true);
 
@@ -51,13 +52,12 @@ const QaMakeDisk = new Lang.Class({
         let guestfishProcess;
         
         ProcUtil.runSync(['qemu-img', 'create', tmppath.get_path(), '' + sizeMb + 'M'], cancellable);
-        let lines = ProcUtil.runProcWithInputSyncGetLines(['guestfish', '-a', tmppath.get_path()], 
-                                                          cancellable,
-                                                          'launch\n\
+        let makeDiskCmd = 'launch\n\
 part-init /dev/vda mbr\n\
 blockdev-getsize64 /dev/vda\n\
-blockdev-getss /dev/vda\n');
-                                                 
+blockdev-getss /dev/vda\n';
+        let gf = new GuestFish.GuestFish(tmppath, true);
+        let lines = gf.run(makeDiskCmd, cancellable, {partitionOpts: [], readWrite: true});
         if (lines.length != 2)
             throw new Error("guestfish returned unexpected output lines (" + lines.length + ", expected 2");
         let diskBytesize = parseInt(lines[0]);
@@ -86,7 +86,7 @@ mkdir /boot\n\
     swapOffset, rootOffset - 1,
     rootOffset, endOffset - 1]);
         print("partition config: ", partconfig);
-        lines = ProcUtil.runProcWithInputSyncGetLines(['guestfish', '-a', tmppath.get_path()], cancellable, partconfig);
+        lines = gf.run(partconfig, cancellable, {partitionOpts: [], readWrite: true});
         GSystem.file_rename(tmppath, path, cancellable);
         print("Created: " + path.get_path());
     }
diff --git a/src/ostbuild/js/builtins/qa_pull_deploy.js b/src/ostbuild/js/builtins/qa_pull_deploy.js
index 9bf872f..353ae7d 100644
--- a/src/ostbuild/js/builtins/qa_pull_deploy.js
+++ b/src/ostbuild/js/builtins/qa_pull_deploy.js
@@ -25,6 +25,7 @@ const GSystem = imports.gi.GSystem;
 
 const ArgParse = imports.argparse;
 const ProcUtil = imports.procutil;
+const GuestFish = imports.guestfish;
 
 const loop = GLib.MainLoop.new(null, true);
 
@@ -35,14 +36,17 @@ const QaPullDeploy = new Lang.Class({
         let deployBootdir = mntdir.resolve_relative_path('ostree/deploy/' + osname + '/current/boot');
         let d = deployBootdir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
 	      let finfo;
-	      while ((finfo = d.next_file(cancellable)) != null) {
-	          let child = deployBootdir.get_child(finfo.get_name());
-	          if (child.get_basename().indexOf('vmlinuz-') == 0) {
-                return child;
+        try {
+	          while ((finfo = d.next_file(cancellable)) != null) {
+	              let child = deployBootdir.get_child(finfo.get_name());
+	              if (child.get_basename().indexOf('vmlinuz-') == 0) {
+                    return child;
+                }
             }
+            throw new Error("Couldn't find vmlinuz- in " + deployBootdir.get_path());
+        } finally {
+            d.close(null);
         }
-        d.close(cancellable);
-        throw new Error("Couldn't find vmlinuz- in " + deployBootdir.get_path());
     },
 
     _parseKernelRelease: function(kernelPath) {
@@ -62,17 +66,6 @@ const QaPullDeploy = new Lang.Class({
         return path;
     },
 
-    // https://bugzilla.redhat.com/show_bug.cgi?id=892834
-    // Also; we have to recreate it as a directory, then
-    // delete that again to avoid further fuse/guestfs bugs.
-    _workaroundGuestfsFuseBug: function(symlinkPath, cancellable) {
-        GSystem.shutil_rm_rf(symlinkPath, cancellable);
-        GSystem.file_ensure_directory(symlinkPath, true, cancellable);
-        let dummyFile = symlinkPath.get_child('dummy');
-        dummyFile.replace_contents('hello world', null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, cancellable);
-        GSystem.shutil_rm_rf(symlinkPath, cancellable);
-    },
-
     execute: function(argv) {
         let cancellable = null;
         let parser = new ArgParse.ArgumentParser("Generate a disk image");
@@ -120,19 +113,24 @@ const QaPullDeploy = new Lang.Class({
                 ProcUtil.runSync(adminCmd.concat(['init-fs', mntdir.get_path()]), cancellable,
                                  {logInitiation: true, env: adminEnv});
             }
-            ProcUtil.runSync(adminCmd.concat(['os-init', args.osname]), cancellable,
-                             {logInitiation: true, env: adminEnv});
+
+            // *** NOTE ***
+            // Here we blow away any current deployment.  This is pretty lame, but it
+            // avoids us triggering a variety of guestfs/FUSE bugs =(
+            // See: https://bugzilla.redhat.com/show_bug.cgi?id=892834
+            //
+            // But regardless, it's probably useful if every
+            // deployment starts clean, and callers can use libguestfs
+            // to crack the FS open afterwards and modify config files
+            // or the like.
+            GSystem.shutil_rm_rf(ostree_osdir, cancellable);
+
             ProcUtil.runSync(adminCmd.concat(['os-init', args.osname]), cancellable,
                              {logInitiation: true, env: adminEnv});
             ProcUtil.runSync(['ostree', '--repo=' + ostreedir.get_child('repo').get_path(),
                               'pull-local', args.srcrepo, args.target], cancellable,
                              {logInitiation: true, env: adminEnv});
 
-            let currentDeployLink = ostree_osdir.get_child('current');
-            let currentEtcDeployLink = ostree_osdir.get_child('current-etc');
-            this._workaroundGuestfsFuseBug(currentDeployLink, cancellable);
-            this._workaroundGuestfsFuseBug(currentEtcDeployLink, cancellable);
-            
             ProcUtil.runSync(adminCmd.concat(['deploy', '--no-kernel', args.osname, args.target]), cancellable,
                              {logInitiation: true, env: adminEnv});
             ProcUtil.runSync(adminCmd.concat(['update-kernel', '--no-bootloader', args.osname]), cancellable,
@@ -162,10 +160,10 @@ LABEL=gnostree-swap swap swap defaults 0 0\n';
             let grubConfPath = grubDir.get_child('grub.conf');
             let grubConf = Format.vprintf('default=0\n\
 timeout=5\n\
-title GNOME-OSTree\n\
+title %s\n\
         root (hd0,0)\n\
-        kernel /%s root=LABEL=gnostree-root\n\
-        initrd /%s\n', [bootRelativeKernelPath, bootRelativeInitramfsPath]);
+        kernel /%s root=LABEL=gnostree-root ostree=%s/current\n\
+        initrd /%s\n', [args.osname, bootRelativeKernelPath, args.osname, bootRelativeInitramfsPath]);
             grubConfPath.replace_contents(grubConf, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, cancellable);
         } finally {
             if (guestmountPidFile.query_exists(null)) {
@@ -181,8 +179,23 @@ title GNOME-OSTree\n\
                         } catch (e) {
                             if (!(e.origError && e.origError.domain == GLib.spawn_exit_error_quark()))
                                 throw e;
-                            else
+                            else {
+                                let proc = GSystem.Subprocess.new_simple_argv(['fuser', '-m', mntdir.get_path()],
+                                                                              GSystem.SubprocessStreamDisposition.INHERIT,
+                                                                              GSystem.SubprocessStreamDisposition.INHERIT,
+                                                                              cancellable);
+                                proc.init(cancellable);
+                                proc.wait_sync(cancellable);
+                                let creds = new Gio.Credentials();
+                                proc = GSystem.Subprocess.new_simple_argv(['ls', '-al', '/proc/' + creds.get_unix_pid() + '/fd'],
+                                                                          GSystem.SubprocessStreamDisposition.INHERIT,
+                                                                          GSystem.SubprocessStreamDisposition.INHERIT,
+                                                                          cancellable);
+                                proc.init(cancellable);
+                                proc.wait_sync(cancellable);
+                                                                              
                                 GLib.usleep(GLib.USEC_PER_SEC);
+                            }
                         }
                     }
                     let pid = parseInt(pidStr);
@@ -205,12 +218,10 @@ title GNOME-OSTree\n\
             }
         }
 
-        let grubInstallCmds = 'grub-install / /dev/vda\n';
-        let lines = ProcUtil.runProcWithInputSyncGetLines(['guestfish', '-a', args.diskpath,
-                                                           '-m', '/dev/sda3',
-                                                           '-m', '/dev/sda1:/boot'],
-                                                          cancellable, grubInstallCmds);
-        
+        let gf = new GuestFish.GuestFish(diskpath, true);
+        gf.run('grub-install / /dev/vda\n', cancellable,
+               {partitionOpts: ['-m', '/dev/sda3', '-m', '/dev/sda1:/boot'],
+                readWrite: true});
         print("Complete!");
     }
 });
diff --git a/src/ostbuild/js/guestfish.js b/src/ostbuild/js/guestfish.js
new file mode 100644
index 0000000..bd3a29e
--- /dev/null
+++ b/src/ostbuild/js/guestfish.js
@@ -0,0 +1,62 @@
+// Copyright (C) 2012,2013 Colin Walters <walters verbum org>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const Lang = imports.lang;
+
+const GSystem = imports.gi.GSystem;
+const Params = imports.params;
+const ProcUtil = imports.procutil;
+
+const GuestFish = new Lang.Class({
+    Name: 'GuestFish',
+
+    _init: function(diskpath, useLockFile) {
+	this._diskpath = diskpath;
+	if (useLockFile) {
+	    let lockfilePath = diskpath.get_parent().get_child(diskpath.get_basename() + '.guestfish-lock');
+	    this._lockfilePath = lockfilePath;
+	} else {
+	    this._lockfilePath = null;
+	}
+    },
+    
+    run: function(input, cancellable, params) {
+	params = Params.parse(params, {partitionOpts: ['-i'],
+				       readWrite: false});
+	
+	try {
+	    let guestfishArgv = ['guestfish', '-a', this._diskpath.get_path()];
+	    if (params.readWrite)
+		guestfishArgv.push('--rw');
+	    else
+		guestfishArgv.push('--ro');
+	    guestfishArgv.push.apply(guestfishArgv, params.partitionOpts);
+
+	    let stream = this._lockfilePath.create(Gio.FileCreateFlags.NONE, cancellable);
+	    stream.close(cancellable);
+	    
+	    return ProcUtil.runProcWithInputSyncGetLines(guestfishArgv, cancellable, input);
+	} finally {
+	    if (this._lockfilePath != null) {
+		GSystem.file_unlink(this._lockfilePath, cancellable);
+	    }
+	}
+    }
+});
+



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