diff --git a/lib/cli.py b/lib/cli.py
index 021591f6a43882307ea5e9a5614ae3e07115fdbf..50f5363cb99e1a7ece028df3245bf67793647905 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -118,6 +118,7 @@ __all__ = [
   "REBOOT_TYPE_OPT",
   "REMOVE_INSTANCE_OPT",
   "REMOVE_UIDS_OPT",
+  "ROMAN_OPT",
   "SECONDARY_IP_OPT",
   "SELECT_OS_OPT",
   "SEP_OPT",
@@ -977,6 +978,12 @@ REMOVE_UIDS_OPT = cli_option("--remove-uids", default=None,
                                    " ranges separated by commas, to be"
                                    " removed from the user-id pool"))
 
+ROMAN_OPT = cli_option("--roman",
+                       dest="roman_integers", default=False,
+                       action="store_true",
+                       help="Use roman numbers for positive integers")
+
+
 
 def _ParseArgs(argv, commands, aliases):
   """Parser for the command line arguments.
diff --git a/lib/compat.py b/lib/compat.py
index db3ae2874cf955c78af59c4408dbb5ad42bf0a09..51ff904ca8968d8bd3607111fa309f911d3bb128 100644
--- a/lib/compat.py
+++ b/lib/compat.py
@@ -30,6 +30,11 @@ try:
 except ImportError:
   functools = None
 
+try:
+  import roman
+except ImportError:
+  roman = None
+
 
 # compat.md5_hash and compat.sha1_hash can be called to generate and md5 and a
 # sha1 hashing modules, under python 2.4, 2.5 and 2.6, even though some changes
@@ -101,6 +106,29 @@ def _partial(func, *args, **keywords): # pylint: disable-msg=W0622
   return newfunc
 
 
+def TryToRoman(val, convert=True):
+  """Try to convert a value to roman numerals
+
+  If the roman module could be loaded convert the given value to a roman
+  numeral. Gracefully fail back to leaving the value untouched.
+
+  @type val: integer
+  @param val: value to convert
+  @type convert: boolean
+  @param convert: if False, don't try conversion at all
+  @rtype: string or typeof(val)
+  @return: roman numeral for val, or val if conversion didn't succeed
+
+  """
+  if roman is not None and convert:
+    try:
+      return roman.toRoman(val)
+    except roman.RomanError:
+      return val
+  else:
+    return val
+
+
 if functools is None:
   partial = _partial
 else:
diff --git a/lib/constants.py b/lib/constants.py
index a6cdcd6b775159ca0841221908538d59a685fb7b..3dd8875975d03469304d88386097bfb59e5a1457 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -490,6 +490,8 @@ HV_USB_MOUSE = "usb_mouse"
 HV_DEVICE_MODEL = "device_model"
 HV_INIT_SCRIPT = "init_script"
 HV_MIGRATION_PORT = "migration_port"
+HV_MIGRATION_BANDWIDTH = "migration_bandwidth"
+HV_MIGRATION_DOWNTIME = "migration_downtime"
 HV_USE_LOCALTIME = "use_localtime"
 HV_DISK_CACHE = "disk_cache"
 HV_SECURITY_MODEL = "security_model"
@@ -522,6 +524,8 @@ HVS_PARAMETER_TYPES = {
   HV_DEVICE_MODEL: VTYPE_STRING,
   HV_INIT_SCRIPT: VTYPE_STRING,
   HV_MIGRATION_PORT: VTYPE_INT,
+  HV_MIGRATION_BANDWIDTH: VTYPE_INT,
+  HV_MIGRATION_DOWNTIME: VTYPE_INT,
   HV_USE_LOCALTIME: VTYPE_BOOL,
   HV_DISK_CACHE: VTYPE_STRING,
   HV_SECURITY_MODEL: VTYPE_STRING,
@@ -791,6 +795,8 @@ HVC_DEFAULTS = {
     HV_DISK_TYPE: HT_DISK_PARAVIRTUAL,
     HV_USB_MOUSE: '',
     HV_MIGRATION_PORT: 8102,
+    HV_MIGRATION_BANDWIDTH: 32, # MiB/s
+    HV_MIGRATION_DOWNTIME: 30,  # ms
     HV_USE_LOCALTIME: False,
     HV_DISK_CACHE: HT_CACHE_DEFAULT,
     HV_SECURITY_MODEL: HT_SM_NONE,
@@ -808,6 +814,7 @@ HVC_DEFAULTS = {
 
 HVC_GLOBALS = frozenset([
   HV_MIGRATION_PORT,
+  HV_MIGRATION_BANDWIDTH,
   ])
 
 BEC_DEFAULTS = {
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index a962a0b6d89bf5952cbb2a8032d92588e2232c9b..6edc5362cbb3492464b2dc5156a6d5091d7f004f 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -88,6 +88,8 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     constants.HV_USB_MOUSE:
       hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
     constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
+    constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
+    constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
     constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
     constants.HV_DISK_CACHE:
       hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
@@ -854,6 +856,14 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     if not live:
       self._CallMonitorCommand(instance_name, 'stop')
 
+    migrate_command = ('migrate_set_speed %dm' %
+        instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
+    self._CallMonitorCommand(instance_name, migrate_command)
+
+    migrate_command = ('migrate_set_downtime %dms' %
+        instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
+    self._CallMonitorCommand(instance_name, migrate_command)
+
     migrate_command = 'migrate -d tcp:%s:%s' % (target, port)
     self._CallMonitorCommand(instance_name, migrate_command)
 
diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py
index a281e6a9b41d9434162a10847bfe010494b2e8f7..77f98b0798b4d43445ca50f17fcedd01d60ee7c9 100644
--- a/lib/hypervisor/hv_xen.py
+++ b/lib/hypervisor/hv_xen.py
@@ -213,6 +213,10 @@ class XenHypervisor(hv_base.BaseHypervisor):
     """
     ini_info = self.GetInstanceInfo(instance.name)
 
+    if ini_info is None:
+      raise errors.HypervisorError("Failed to reboot instance %s,"
+                                   " not running" % instance.name)
+
     result = utils.RunCmd(["xm", "reboot", instance.name])
     if result.failed:
       raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
@@ -223,7 +227,8 @@ class XenHypervisor(hv_base.BaseHypervisor):
       new_info = self.GetInstanceInfo(instance.name)
 
       # check if the domain ID has changed or the run time has decreased
-      if new_info[1] != ini_info[1] or new_info[5] < ini_info[5]:
+      if (new_info is not None and
+          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
         return
 
       raise utils.RetryAgain()
diff --git a/lib/jqueue.py b/lib/jqueue.py
index 62a5f4a5d0c13a6a4773a51ee48bbd918fa3992a..9e5d83663e04e35ef8432a9620e7f791c4f33417 100644
--- a/lib/jqueue.py
+++ b/lib/jqueue.py
@@ -77,11 +77,12 @@ class _QueuedOpCode(object):
   @ivar status: the current status
   @ivar result: the result of the LU execution
   @ivar start_timestamp: timestamp for the start of the execution
+  @ivar exec_timestamp: timestamp for the actual LU Exec() function invocation
   @ivar stop_timestamp: timestamp for the end of the execution
 
   """
   __slots__ = ["input", "status", "result", "log",
-               "start_timestamp", "end_timestamp",
+               "start_timestamp", "exec_timestamp", "end_timestamp",
                "__weakref__"]
 
   def __init__(self, op):
@@ -96,6 +97,7 @@ class _QueuedOpCode(object):
     self.result = None
     self.log = []
     self.start_timestamp = None
+    self.exec_timestamp = None
     self.end_timestamp = None
 
   @classmethod
@@ -114,6 +116,7 @@ class _QueuedOpCode(object):
     obj.result = state["result"]
     obj.log = state["log"]
     obj.start_timestamp = state.get("start_timestamp", None)
+    obj.exec_timestamp = state.get("exec_timestamp", None)
     obj.end_timestamp = state.get("end_timestamp", None)
     return obj
 
@@ -130,6 +133,7 @@ class _QueuedOpCode(object):
       "result": self.result,
       "log": self.log,
       "start_timestamp": self.start_timestamp,
+      "exec_timestamp": self.exec_timestamp,
       "end_timestamp": self.end_timestamp,
       }
 
@@ -385,6 +389,7 @@ class _OpExecCallbacks(mcpu.OpExecCbBase):
         raise CancelJob()
 
       self._op.status = constants.OP_STATUS_RUNNING
+      self._op.exec_timestamp = TimeStampNow()
     finally:
       self._queue.release()
 
@@ -1383,6 +1388,8 @@ class JobQueue(object):
         row.append([op.log for op in job.ops])
       elif fname == "opstart":
         row.append([op.start_timestamp for op in job.ops])
+      elif fname == "opexec":
+        row.append([op.exec_timestamp for op in job.ops])
       elif fname == "opend":
         row.append([op.end_timestamp for op in job.ops])
       elif fname == "received_ts":
diff --git a/lib/rapi/client.py b/lib/rapi/client.py
index e1513aa9ac54d871a848dad3ded01d2e0b68b3e2..49affb2e6c7190d0f0c87d08a9c81d9858a2e79d 100644
--- a/lib/rapi/client.py
+++ b/lib/rapi/client.py
@@ -421,6 +421,8 @@ class GanetiRapiClient(object):
       raise CertificateError("SSL issue: %s (%r)" % (err, err))
     except urllib2.HTTPError, err:
       raise GanetiApiError(str(err), code=err.code)
+    except urllib2.URLError, err:
+      raise GanetiApiError(str(err))
 
     if encoded_response_content:
       response_content = simplejson.loads(encoded_response_content)
diff --git a/lib/uidpool.py b/lib/uidpool.py
index aba5febe605790275712e2ddee336b724e66ad15..9be7381cc90435d44c7b648a6fcd46d73fb46759 100644
--- a/lib/uidpool.py
+++ b/lib/uidpool.py
@@ -36,6 +36,7 @@ import random
 
 from ganeti import errors
 from ganeti import constants
+from ganeti import compat
 from ganeti import utils
 
 
@@ -114,16 +115,17 @@ def RemoveFromUidPool(uid_pool, remove_uids):
     uid_pool.remove(uid_range)
 
 
-def _FormatUidRange(lower, higher):
+def _FormatUidRange(lower, higher, roman=False):
   """Convert a user-id range definition into a string.
 
   """
   if lower == higher:
-    return str(lower)
-  return "%s-%s" % (lower, higher)
+    return str(compat.TryToRoman(lower, convert=roman))
+  return "%s-%s" % (compat.TryToRoman(lower, convert=roman),
+                    compat.TryToRoman(higher, convert=roman))
 
 
-def FormatUidPool(uid_pool, separator=None):
+def FormatUidPool(uid_pool, separator=None, roman=False):
   """Convert the internal representation of the user-id pool into a string.
 
   The output format is also accepted by ParseUidPool()
@@ -136,7 +138,7 @@ def FormatUidPool(uid_pool, separator=None):
   """
   if separator is None:
     separator = ", "
-  return separator.join([_FormatUidRange(lower, higher)
+  return separator.join([_FormatUidRange(lower, higher, roman=roman)
                          for lower, higher in uid_pool])
 
 
diff --git a/lib/utils.py b/lib/utils.py
index df14049d43732d5d3a5dec5c5d9cc4bf8029f866..11f20772297f1b189964a3f3319fe6bf4261f261 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -1699,6 +1699,11 @@ def EnsureDirs(dirs):
       if err.errno != errno.EEXIST:
         raise errors.GenericError("Cannot create needed directory"
                                   " '%s': %s" % (dir_name, err))
+    try:
+      os.chmod(dir_name, dir_mode)
+    except EnvironmentError, err:
+      raise errors.GenericError("Cannot change directory permissions on"
+                                " '%s': %s" % (dir_name, err))
     if not os.path.isdir(dir_name):
       raise errors.GenericError("%s is not a directory" % dir_name)
 
diff --git a/man/gnt-cluster.sgml b/man/gnt-cluster.sgml
index d74c136d52f2aa970ba6085c07dceda101f2c71b..5044ae227f5fccadde6f024afd83c5b24238cb32 100644
--- a/man/gnt-cluster.sgml
+++ b/man/gnt-cluster.sgml
@@ -202,12 +202,20 @@
 
       <cmdsynopsis>
         <command>info</command>
+        <arg>--roman</arg>
       </cmdsynopsis>
 
       <para>
         Shows runtime cluster information: cluster name, architecture
         (32 or 64 bit), master node, node list and instance list.
       </para>
+
+      <para>
+        Passing the <option>--roman</option> option gnt-cluster info will try
+        to print its integer fields in a latin friendly way. This allows
+        further diffusion of Ganeti among ancient cultures.
+      </para>
+
     </refsect2>
 
     <refsect2>
@@ -419,6 +427,21 @@
               </para>
             </listitem>
           </varlistentry>
+          <varlistentry>
+            <term>migration_bandwidth</term>
+            <listitem>
+              <simpara>Valid for the KVM hypervisor.</simpara>
+
+              <para>
+                This option specifies the maximum bandwidth that KVM will
+                use for instance live migrations. The value is in MiB/s.
+              </para>
+
+              <simpara>This option is only effective with kvm versions >= 78
+              and qemu-kvm versions >= 0.10.0.
+              </simpara>
+            </listitem>
+          </varlistentry>
         </variablelist>
 
       </para>
diff --git a/man/gnt-instance.sgml b/man/gnt-instance.sgml
index 3d3563fc4075d20817b5d194d0e9d719a5b3688c..9e10af9917858ce736df2593605185935e556a28 100644
--- a/man/gnt-instance.sgml
+++ b/man/gnt-instance.sgml
@@ -673,6 +673,23 @@
                 </para>
 
                 <simpara>It is set to <quote>false</quote> by default.</simpara>
+              </listitem>
+            </varlistentry>
+
+            <varlistentry>
+              <term>migration_downtime</term>
+              <listitem>
+                <simpara>Valid for the KVM hypervisor.</simpara>
+
+                <simpara>The maximum amount of time (in ms) a KVM instance is
+                allowed to be frozen during a live migration, in order to copy
+                dirty memory pages. Default value is 30ms, but you may need to
+                increase this value for busy instances.
+                </simpara>
+
+                <simpara>This option is only effective with kvm versions >= 87
+                and qemu-kvm versions >= 0.11.0.
+                </simpara>
 
               </listitem>
             </varlistentry>
@@ -1016,6 +1033,7 @@ instance5: 11225
           <arg>--no-headers</arg>
           <arg>--separator=<replaceable>SEPARATOR</replaceable></arg>
           <arg>-o <replaceable>[+]FIELD,...</replaceable></arg>
+          <arg>--roman</arg>
           <arg rep="repeat">instance</arg>
         </cmdsynopsis>
 
@@ -1032,6 +1050,11 @@ instance5: 11225
           the output fields. Both these options are to help scripting.
         </para>
 
+        <para>
+          The <option>--roman</option> option allows latin people to better
+          understand the cluster instances' status.
+        </para>
+
         <para>
           The <option>-o</option> option takes a comma-separated list
           of output fields. The available fields and their meaning
@@ -1390,6 +1413,7 @@ instance5: 11225
             <arg>-s</arg>
             <arg>--static</arg>
           </group>
+          <arg>--roman</arg>
           <group choice="req">
             <arg>--all</arg>
             <arg rep="repeat"><replaceable>instance</replaceable></arg>
@@ -1413,6 +1437,13 @@ instance5: 11225
           Use the <option>--all</option> to get info about all instances,
           rather than explicitly passing the ones you're interested in.
         </para>
+
+        <para>
+          The <option>--roman</option> option can be used to cause envy among
+          people who like ancient cultures, but are stuck with non-latin-friendly
+          cluster virtualization technologies.
+        </para>
+
       </refsect3>
 
       <refsect3>
diff --git a/man/gnt-job.sgml b/man/gnt-job.sgml
index 35d3c547ac23a2f49cbf959006fca2a6ca44a06e..df778d6c63449da8834739cdda8c99b6423bacb9 100644
--- a/man/gnt-job.sgml
+++ b/man/gnt-job.sgml
@@ -210,7 +210,15 @@
           <varlistentry>
             <term>opstart</term>
             <listitem>
-              <simpara>the list of opcode start times</simpara>
+              <simpara>the list of opcode start times (before
+              acquiring locks)</simpara>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>opexec</term>
+            <listitem>
+              <simpara>the list of opcode execution start times (after
+              acquiring any necessary locks)</simpara>
             </listitem>
           </varlistentry>
           <varlistentry>
diff --git a/man/gnt-node.sgml b/man/gnt-node.sgml
index eb76deb4520a9a636fc73e48f11ce6de9db4a89a..22b89a048ef437f63bd78e1a6d54a4dbb99732b5 100644
--- a/man/gnt-node.sgml
+++ b/man/gnt-node.sgml
@@ -253,6 +253,8 @@
         <arg>--units=<replaceable>UNITS</replaceable></arg>
         <arg>-o <replaceable>[+]FIELD,...</replaceable></arg>
         <sbr>
+        <arg>--roman</arg>
+        <sbr>
         <arg rep="repeat">node</arg>
       </cmdsynopsis>
 
@@ -285,6 +287,12 @@
         cluster (but this might stall the query for a long time).
       </para>
 
+      <para>
+        Passing the <option>--roman</option> option gnt-node list will try to
+        output some of its fields in a latin-friendly way. This is not the
+        default for backwards compatibility.
+      </para>
+
       <para>
         The <option>-o</option> option takes a comma-separated list of
         output fields. The available fields and their meaning are:
diff --git a/scripts/gnt-cluster b/scripts/gnt-cluster
index 4bde5b91f3affb1ce78b368e5499173d473c013c..bf160cdb0f0fd1c940be489c6bc8eb3591f16fcb 100755
--- a/scripts/gnt-cluster
+++ b/scripts/gnt-cluster
@@ -216,7 +216,7 @@ def ShowClusterMaster(opts, args):
   return 0
 
 
-def _PrintGroupedParams(paramsdict, level=1):
+def _PrintGroupedParams(paramsdict, level=1, roman=False):
   """Print Grouped parameters (be, nic, disk) by group.
 
   @type paramsdict: dict of dicts
@@ -229,7 +229,9 @@ def _PrintGroupedParams(paramsdict, level=1):
   for item, val in sorted(paramsdict.items()):
     if isinstance(val, dict):
       ToStdout("%s- %s:", indent, item)
-      _PrintGroupedParams(val, level=level + 1)
+      _PrintGroupedParams(val, level=level + 1, roman=roman)
+    elif roman and isinstance(val, int):
+      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
     else:
       ToStdout("%s  %s: %s", indent, item, val)
 
@@ -276,19 +278,23 @@ def ShowClusterConfig(opts, args):
   _PrintGroupedParams(result["os_hvp"])
 
   ToStdout("Cluster parameters:")
-  ToStdout("  - candidate pool size: %s", result["candidate_pool_size"])
+  ToStdout("  - candidate pool size: %s",
+            compat.TryToRoman(result["candidate_pool_size"],
+                              convert=opts.roman_integers))
   ToStdout("  - master netdev: %s", result["master_netdev"])
   ToStdout("  - lvm volume group: %s", result["volume_group_name"])
   ToStdout("  - file storage path: %s", result["file_storage_dir"])
   ToStdout("  - maintenance of node health: %s",
            result["maintain_node_health"])
-  ToStdout("  - uid pool: %s", uidpool.FormatUidPool(result["uid_pool"]))
+  ToStdout("  - uid pool: %s",
+            uidpool.FormatUidPool(result["uid_pool"],
+                                  roman=opts.roman_integers))
 
   ToStdout("Default instance parameters:")
-  _PrintGroupedParams(result["beparams"])
+  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
 
   ToStdout("Default nic parameters:")
-  _PrintGroupedParams(result["nicparams"])
+  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
 
   return 0
 
@@ -817,8 +823,8 @@ commands = {
     [NODE_LIST_OPT],
     "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
   'info': (
-    ShowClusterConfig, ARGS_NONE, [],
-    "", "Show cluster configuration"),
+    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
+    "[--roman]", "Show cluster configuration"),
   'list-tags': (
     ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
   'add-tags': (
diff --git a/scripts/gnt-instance b/scripts/gnt-instance
index 250b11f4c6d864bc6ba350221618ca9790635524..710fb4dab635fcd304214134a720302b8c293e9a 100755
--- a/scripts/gnt-instance
+++ b/scripts/gnt-instance
@@ -34,6 +34,7 @@ from cStringIO import StringIO
 from ganeti.cli import *
 from ganeti import opcodes
 from ganeti import constants
+from ganeti import compat
 from ganeti import utils
 from ganeti import errors
 
@@ -323,6 +324,8 @@ def ListInstances(opts, args):
         val = ",".join(str(item) for item in val)
       elif val is None:
         val = "-"
+      if opts.roman_integers and isinstance(val, int):
+        val = compat.TryToRoman(val)
       row[idx] = str(val)
 
   data = GenerateTable(separator=opts.separator, headers=headers,
@@ -941,16 +944,18 @@ def ConnectToInstanceConsole(opts, args):
       os._exit(1) # pylint: disable-msg=W0212
 
 
-def _FormatLogicalID(dev_type, logical_id):
+def _FormatLogicalID(dev_type, logical_id, roman):
   """Formats the logical_id of a disk.
 
   """
   if dev_type == constants.LD_DRBD8:
     node_a, node_b, port, minor_a, minor_b, key = logical_id
     data = [
-      ("nodeA", "%s, minor=%s" % (node_a, minor_a)),
-      ("nodeB", "%s, minor=%s" % (node_b, minor_b)),
-      ("port", port),
+      ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a,
+                                                            convert=roman))),
+      ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b,
+                                                            convert=roman))),
+      ("port", compat.TryToRoman(port, convert=roman)),
       ("auth key", key),
       ]
   elif dev_type == constants.LD_LV:
@@ -962,7 +967,7 @@ def _FormatLogicalID(dev_type, logical_id):
   return data
 
 
-def _FormatBlockDevInfo(idx, top_level, dev, static):
+def _FormatBlockDevInfo(idx, top_level, dev, static, roman):
   """Show block device information.
 
   This is only used by L{ShowInstanceConfig}, but it's too big to be
@@ -977,6 +982,8 @@ def _FormatBlockDevInfo(idx, top_level, dev, static):
   @type static: boolean
   @param static: wheter the device information doesn't contain
       runtime information but only static data
+  @type roman: boolean
+  @param roman: whether to try to use roman integers
   @return: a list of either strings, tuples or lists
       (which should be formatted at a higher indent level)
 
@@ -998,19 +1005,19 @@ def _FormatBlockDevInfo(idx, top_level, dev, static):
     if major is None:
       major_string = "N/A"
     else:
-      major_string = str(major)
+      major_string = str(compat.TryToRoman(major, convert=roman))
 
     if minor is None:
       minor_string = "N/A"
     else:
-      minor_string = str(minor)
+      minor_string = str(compat.TryToRoman(minor, convert=roman))
 
     txt += ("%s (%s:%s)" % (path, major_string, minor_string))
     if dtype in (constants.LD_DRBD8, ):
       if syncp is not None:
         sync_text = "*RECOVERING* %5.2f%%," % syncp
         if estt:
-          sync_text += " ETA %ds" % estt
+          sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman)
         else:
           sync_text += " ETA unknown"
       else:
@@ -1039,9 +1046,9 @@ def _FormatBlockDevInfo(idx, top_level, dev, static):
     if dev["iv_name"] is not None:
       txt = dev["iv_name"]
     else:
-      txt = "disk %d" % idx
+      txt = "disk %s" % compat.TryToRoman(idx, convert=roman)
   else:
-    txt = "child %d" % idx
+    txt = "child %s" % compat.TryToRoman(idx, convert=roman)
   if isinstance(dev["size"], int):
     nice_size = utils.FormatUnit(dev["size"], "h")
   else:
@@ -1052,7 +1059,7 @@ def _FormatBlockDevInfo(idx, top_level, dev, static):
     data.append(("access mode", dev["mode"]))
   if dev["logical_id"] is not None:
     try:
-      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"])
+      l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"], roman)
     except ValueError:
       l_id = [str(dev["logical_id"])]
     if len(l_id) == 1:
@@ -1070,7 +1077,7 @@ def _FormatBlockDevInfo(idx, top_level, dev, static):
   if dev["children"]:
     data.append("child devices:")
     for c_idx, child in enumerate(dev["children"]):
-      data.append(_FormatBlockDevInfo(c_idx, False, child, static))
+      data.append(_FormatBlockDevInfo(c_idx, False, child, static, roman))
   d1.append(data)
   return d1
 
@@ -1137,7 +1144,9 @@ def ShowInstanceConfig(opts, args):
     instance = result[instance_name]
     buf.write("Instance name: %s\n" % instance["name"])
     buf.write("UUID: %s\n" % instance["uuid"])
-    buf.write("Serial number: %s\n" % instance["serial_no"])
+    buf.write("Serial number: %s\n" %
+              compat.TryToRoman(instance["serial_no"],
+                                convert=opts.roman_integers))
     buf.write("Creation time: %s\n" % utils.FormatTime(instance["ctime"]))
     buf.write("Modification time: %s\n" % utils.FormatTime(instance["mtime"]))
     buf.write("State: configured to be %s" % instance["config_state"])
@@ -1151,7 +1160,9 @@ def ShowInstanceConfig(opts, args):
     buf.write("    - secondaries: %s\n" % utils.CommaJoin(instance["snodes"]))
     buf.write("  Operating system: %s\n" % instance["os"])
     if instance.has_key("network_port"):
-      buf.write("  Allocated network port: %s\n" % instance["network_port"])
+      buf.write("  Allocated network port: %s\n" %
+                compat.TryToRoman(instance["network_port"],
+                                  convert=opts.roman_integers))
     buf.write("  Hypervisor: %s\n" % instance["hypervisor"])
 
     # custom VNC console information
@@ -1181,10 +1192,12 @@ def ShowInstanceConfig(opts, args):
         val = "default (%s)" % instance["hv_actual"][key]
       buf.write("    - %s: %s\n" % (key, val))
     buf.write("  Hardware:\n")
-    buf.write("    - VCPUs: %d\n" %
-              instance["be_actual"][constants.BE_VCPUS])
-    buf.write("    - memory: %dMiB\n" %
-              instance["be_actual"][constants.BE_MEMORY])
+    buf.write("    - VCPUs: %s\n" %
+              compat.TryToRoman(instance["be_actual"][constants.BE_VCPUS],
+                                convert=opts.roman_integers))
+    buf.write("    - memory: %sMiB\n" %
+              compat.TryToRoman(instance["be_actual"][constants.BE_MEMORY],
+                                convert=opts.roman_integers))
     buf.write("    - NICs:\n")
     for idx, (ip, mac, mode, link) in enumerate(instance["nics"]):
       buf.write("      - nic/%d: MAC: %s, IP: %s, mode: %s, link: %s\n" %
@@ -1192,7 +1205,8 @@ def ShowInstanceConfig(opts, args):
     buf.write("  Disks:\n")
 
     for idx, device in enumerate(instance["disks"]):
-      _FormatList(buf, _FormatBlockDevInfo(idx, True, device, opts.static), 2)
+      _FormatList(buf, _FormatBlockDevInfo(idx, True, device, opts.static,
+                  opts.roman_integers), 2)
 
   ToStdout(buf.getvalue().rstrip('\n'))
   return retcode
@@ -1379,12 +1393,12 @@ commands = {
     " (only for instances of type file and lv)"),
   'info': (
     ShowInstanceConfig, ARGS_MANY_INSTANCES,
-    [STATIC_OPT, ALL_OPT],
+    [STATIC_OPT, ALL_OPT, ROMAN_OPT],
     "[-s] {--all | <instance>...}",
     "Show information on the specified instance(s)"),
   'list': (
     ListInstances, ARGS_MANY_INSTANCES,
-    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT],
+    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT, ROMAN_OPT],
     "[<instance>...]",
     "Lists the instances and their status. The available fields are"
     " (see the man page for details): status, oper_state, oper_ram,"
diff --git a/scripts/gnt-job b/scripts/gnt-job
index 2e63cf6de2c91eebc74199a2eeaeae8f6b48f4cf..b2b9b11d6eebf8711f18716fc7b613c4a8079ff5 100755
--- a/scripts/gnt-job
+++ b/scripts/gnt-job
@@ -80,6 +80,7 @@ def ListJobs(opts, args):
       "oplog": "OpCode_log",
       "summary": "Summary",
       "opstart": "OpCode_start",
+      "opexec": "OpCode_exec",
       "opend": "OpCode_end",
       "start_ts": "Start",
       "end_ts": "End",
@@ -106,7 +107,7 @@ def ListJobs(opts, args):
         val = ",".join(val)
       elif field in ("start_ts", "end_ts", "received_ts"):
         val = FormatTimestamp(val)
-      elif field in ("opstart", "opend"):
+      elif field in ("opstart", "opexec", "opend"):
         val = [FormatTimestamp(entry) for entry in val]
       elif field == "lock_status" and not val:
         val = "-"
@@ -212,7 +213,7 @@ def ShowJobs(opts, args):
 
   selected_fields = [
     "id", "status", "ops", "opresult", "opstatus", "oplog",
-    "opstart", "opend", "received_ts", "start_ts", "end_ts",
+    "opstart", "opexec", "opend", "received_ts", "start_ts", "end_ts",
     ]
 
   result = GetClient().QueryJobs(args, selected_fields)
@@ -235,7 +236,7 @@ def ShowJobs(opts, args):
       continue
 
     (job_id, status, ops, opresult, opstatus, oplog,
-     opstart, opend, recv_ts, start_ts, end_ts) = entry
+     opstart, opexec, opend, recv_ts, start_ts, end_ts) = entry
     format(0, "Job ID: %s" % job_id)
     if status in _USER_JOB_STATUS:
       status = _USER_JOB_STATUS[status]
@@ -275,14 +276,18 @@ def ShowJobs(opts, args):
     else:
       format(1, "Total processing time: N/A")
     format(1, "Opcodes:")
-    for (opcode, result, status, log, s_ts, e_ts) in \
-            zip(ops, opresult, opstatus, oplog, opstart, opend):
+    for (opcode, result, status, log, s_ts, x_ts, e_ts) in \
+            zip(ops, opresult, opstatus, oplog, opstart, opexec, opend):
       format(2, "%s" % opcode["OP_ID"])
       format(3, "Status: %s" % status)
       if isinstance(s_ts, (tuple, list)):
         format(3, "Processing start: %s" % FormatTimestamp(s_ts))
       else:
         format(3, "No processing start time")
+      if isinstance(x_ts, (tuple, list)):
+        format(3, "Execution start:  %s" % FormatTimestamp(x_ts))
+      else:
+        format(3, "No execution start time")
       if isinstance(e_ts, (tuple, list)):
         format(3, "Processing end:   %s" % FormatTimestamp(e_ts))
       else:
diff --git a/scripts/gnt-node b/scripts/gnt-node
index 61c4f271488fd78b93495a6b5f8ed5eaf9371099..9e96248ee385888990c4d7d1838a1f04b690d34d 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -32,6 +32,7 @@ from ganeti.cli import *
 from ganeti import opcodes
 from ganeti import utils
 from ganeti import constants
+from ganeti import compat
 from ganeti import errors
 from ganeti import bootstrap
 
@@ -223,6 +224,8 @@ def ListNodes(opts, args):
         val = utils.FormatTime(val)
       elif val is None:
         val = "?"
+      elif opts.roman_integers and isinstance(val, int):
+        val = compat.TryToRoman(val)
       row[idx] = str(val)
 
   data = GenerateTable(separator=opts.separator, headers=headers,
@@ -662,7 +665,7 @@ commands = {
     "[<node_name>...]", "Show information about the node(s)"),
   'list': (
     ListNodes, ARGS_MANY_NODES,
-    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT],
+    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT, ROMAN_OPT],
     "[nodes...]",
     "Lists the nodes in the cluster. The available fields are (see the man"
     " page for details): %s. The default field list is (in order): %s." %
diff --git a/test/ganeti.compat_unittest.py b/test/ganeti.compat_unittest.py
index 19f82b7a8f26b8d225aea2c3dc8364afcc630719..dbe9940e71403666d44c1d7f94f216a50b01172b 100755
--- a/test/ganeti.compat_unittest.py
+++ b/test/ganeti.compat_unittest.py
@@ -58,5 +58,26 @@ class TestPartial(testutils.GanetiTestCase):
                            (("Foo", ), {"xyz": 999,}))
 
 
+class TestTryToRoman(testutils.GanetiTestCase):
+  """test the compat.TryToRoman function"""
+
+  def testAFewIntegers(self):
+    self.assertEquals(compat.TryToRoman(0), 0)
+    self.assertEquals(compat.TryToRoman(1), "I")
+    self.assertEquals(compat.TryToRoman(4), "IV")
+    self.assertEquals(compat.TryToRoman(5), "V")
+
+  def testStrings(self):
+    self.assertEquals(compat.TryToRoman("astring"), "astring")
+    self.assertEquals(compat.TryToRoman("5"), "5")
+
+  def testDontConvert(self):
+    self.assertEquals(compat.TryToRoman(0, convert=False), 0)
+    self.assertEquals(compat.TryToRoman(1, convert=False), 1)
+    self.assertEquals(compat.TryToRoman(7, convert=False), 7)
+    self.assertEquals(compat.TryToRoman("astring", convert=False), "astring")
+    self.assertEquals(compat.TryToRoman("19", convert=False), "19")
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index b329ad7214f766e774041c812d343b35dcc25198..dee83b0d84764a9cd307a523c0430faec5e76813 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -2245,5 +2245,26 @@ class TestIgnoreSignals(unittest.TestCase):
     self.assertEquals(utils.IgnoreSignals(self._Return, 33), 33)
 
 
+class TestEnsureDirs(unittest.TestCase):
+  """Tests for EnsureDirs"""
+
+  def setUp(self):
+    self.dir = tempfile.mkdtemp()
+    self.old_umask = os.umask(0777)
+
+  def testEnsureDirs(self):
+    utils.EnsureDirs([
+        (utils.PathJoin(self.dir, "foo"), 0777),
+        (utils.PathJoin(self.dir, "bar"), 0000),
+        ])
+    self.assertEquals(os.stat(utils.PathJoin(self.dir, "foo"))[0] & 0777, 0777)
+    self.assertEquals(os.stat(utils.PathJoin(self.dir, "bar"))[0] & 0777, 0000)
+
+  def tearDown(self):
+    os.rmdir(utils.PathJoin(self.dir, "foo"))
+    os.rmdir(utils.PathJoin(self.dir, "bar"))
+    os.rmdir(self.dir)
+    os.umask(self.old_umask)
+
 if __name__ == '__main__':
   testutils.GanetiTestProgram()