From 7dc01fbe7969c54a8b839fb5d18a95471a687358 Mon Sep 17 00:00:00 2001
From: Lucas Alvares Gomes <lucasagomes@gmail.com>
Date: Tue, 1 Apr 2014 10:02:03 +0100
Subject: [PATCH] Replace sfdisk with parted

Replace the current sfdisk which is broken with parted. This patch is
a short-term fix for the Icehouse RC1 release.

Closes-Bug: #1297925
Change-Id: I0c3763db0e29f58b33e998d1f7efb23337604960
---
 etc/ironic/rootwrap.d/ironic-utils.filters |  2 +-
 ironic/drivers/modules/deploy_utils.py     | 30 ++++++++++--------
 ironic/tests/drivers/test_deploy_utils.py  | 36 ++++++++++++++++++++++
 3 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/etc/ironic/rootwrap.d/ironic-utils.filters b/etc/ironic/rootwrap.d/ironic-utils.filters
index ab60e7a1fd..0ee273b1e4 100644
--- a/etc/ironic/rootwrap.d/ironic-utils.filters
+++ b/etc/ironic/rootwrap.d/ironic-utils.filters
@@ -4,7 +4,7 @@
 [Filters]
 # ironic/drivers/modules/deploy_utils.py
 iscsiadm: CommandFilter, iscsiadm, root
-sfdisk: CommandFilter, sfdisk, root
+parted: CommandFilter, parted, root
 dd: CommandFilter, dd, root
 blkid: CommandFilter, blkid, root
 
diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py
index 4cae95b47a..bad6458477 100644
--- a/ironic/drivers/modules/deploy_utils.py
+++ b/ironic/drivers/modules/deploy_utils.py
@@ -80,21 +80,25 @@ def delete_iscsi(portal_address, portal_port, target_iqn):
 
 def make_partitions(dev, root_mb, swap_mb, ephemeral_mb):
     """Create partitions for root and swap on a disk device."""
-    # Lead in with 1MB to allow room for the partition table itself, otherwise
-    # the way sfdisk adjusts doesn't shift the partition up to compensate, and
-    # we lose the space.
-    # http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/raring/util-linux/
-    # raring/view/head:/fdisk/sfdisk.c#L1940
+    cmd = []
+
+    def add_partition(start, size, fs_type=''):
+        end = start + size
+        cmd.extend(['mkpart', 'primary', fs_type, str(start), str(end)])
+        return end
+
+    offset = 1
     if ephemeral_mb:
-        stdin_command = ('1,%d,83;\n,%d,82;\n,%d,83;\n0,0;\n' %
-                (ephemeral_mb, swap_mb, root_mb))
+        offset = add_partition(offset, ephemeral_mb)
+        offset = add_partition(offset, swap_mb, fs_type='linux-swap')
+        offset = add_partition(offset, root_mb)
     else:
-        stdin_command = ('1,%d,83;\n,%d,82;\n0,0;\n0,0;\n' %
-                (root_mb, swap_mb))
-    utils.execute('sfdisk', '-uM', dev, process_input=stdin_command,
-            run_as_root=True,
-            attempts=3,
-            check_exit_code=[0])
+        offset = add_partition(offset, root_mb)
+        offset = add_partition(offset, swap_mb, fs_type='linux-swap')
+
+    utils.execute('parted', '-a', 'optimal', '-s', dev, '--', 'mklabel',
+                  'msdos', 'unit', 'MiB', *cmd, run_as_root=True, attempts=3,
+                  check_exit_code=[0])
     # avoid "device is busy"
     time.sleep(3)
 
diff --git a/ironic/tests/drivers/test_deploy_utils.py b/ironic/tests/drivers/test_deploy_utils.py
index ed1ea75791..d81ba8e29a 100644
--- a/ironic/tests/drivers/test_deploy_utils.py
+++ b/ironic/tests/drivers/test_deploy_utils.py
@@ -20,6 +20,7 @@ import os
 import tempfile
 
 from ironic.common import exception
+from ironic.common import utils as common_utils
 from ironic.drivers.modules import deploy_utils as utils
 from ironic.tests import base as tests_base
 
@@ -400,3 +401,38 @@ class WorkOnDiskTestCase(tests_base.TestCase):
         self.assertEqual(self.mock_ibd.call_args_list, calls)
         self.mock_mp.assert_called_once_with(self.dev, self.root_mb,
                                              self.swap_mb, ephemeral_mb)
+
+
+@mock.patch.object(common_utils, 'execute')
+class MakePartitionsTestCase(tests_base.TestCase):
+
+    def setUp(self):
+        super(MakePartitionsTestCase, self).setUp()
+        self.dev = 'fake-dev'
+        self.root_mb = 1024
+        self.swap_mb = 512
+        self.ephemeral_mb = 0
+        self.parted_static_cmd = ['parted', '-a', 'optimal', '-s', self.dev,
+                                  '--', 'mklabel', 'msdos', 'unit', 'MiB']
+
+    def test_make_partitions(self, mock_exc):
+        expected_mkpart = ['mkpart', 'primary', '', '1', '1025',
+                           'mkpart', 'primary', 'linux-swap', '1025', '1537']
+        cmd = self.parted_static_cmd + expected_mkpart
+        utils.make_partitions(self.dev, self.root_mb, self.swap_mb,
+                              self.ephemeral_mb)
+        mock_exc.assert_called_once_with(*cmd,
+                                         run_as_root=True, attempts=3,
+                                         check_exit_code=[0])
+
+    def test_make_partitions_with_ephemeral(self, mock_exc):
+        self.ephemeral_mb = 2048
+        expected_mkpart = ['mkpart', 'primary', '', '1', '2049',
+                           'mkpart', 'primary', 'linux-swap', '2049', '2561',
+                           'mkpart', 'primary', '', '2561', '3585']
+        cmd = self.parted_static_cmd + expected_mkpart
+        utils.make_partitions(self.dev, self.root_mb, self.swap_mb,
+                              self.ephemeral_mb)
+        mock_exc.assert_called_once_with(*cmd,
+                                         run_as_root=True, attempts=3,
+                                         check_exit_code=[0])