1
0
mirror of https://github.com/gryf/openstack.git synced 2025-12-17 03:20:25 +01:00
Files
openstack/ironic-lib/0007-System-installation-implementation.patch
2018-03-23 16:40:32 +01:00

218 lines
9.0 KiB
Diff

From be717da52b717b9a59f947e3ade2be5423d401a4 Mon Sep 17 00:00:00 2001
From: "Grzegorz Grasza (xek)" <grzegorz.grasza@intel.com>
Date: Fri, 19 Jan 2018 13:29:30 +0100
Subject: [PATCH 07/11] System installation implementation
Co-Authored-By: Grzegorz Grasza <grzegorz.grasza@intel.com>
---
ironic_lib/system_installer/systemsetup.py | 93 ++++++++++++++++++++++++++++++
ironic_lib/tests/test_systemsetup.py | 90 +++++++++++++++++++++++++++++
2 files changed, 183 insertions(+)
create mode 100644 ironic_lib/tests/test_systemsetup.py
diff --git a/ironic_lib/system_installer/systemsetup.py b/ironic_lib/system_installer/systemsetup.py
index e03c5b4..fa303e6 100644
--- a/ironic_lib/system_installer/systemsetup.py
+++ b/ironic_lib/system_installer/systemsetup.py
@@ -13,8 +13,101 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
+
+from ironic_lib import utils
+from oslo_log import log
+
+from ironic_lib.system_installer import exceptions
from ironic_lib.system_installer.filesystemsetup import FilesystemSetup
+LOG = log.getLogger()
+
class SystemSetup(FilesystemSetup):
"""Basic disk formatting implementation"""
+
+ def validate_env(self):
+ if not self._cmd_exists('guestmount'):
+ raise exceptions.EnvError('guestmount command not available')
+
+ def setup_disks(self, devices, image_path):
+ fstab = []
+ for disk_name, disk in sorted(
+ self.conf.items(), key=lambda x: x[1].get('mountpoint', 'z')):
+ if 'mountpoint' in disk and not disk.get('preserve', False):
+ mountpoint = disk['mountpoint']
+ device = devices.get(disk_name, disk_name)
+ try:
+ os.makedirs('/next' + mountpoint)
+ except OSError as e:
+ if e.errno != os.errno.EEXIST:
+ raise
+ out, err = utils.execute('mount', device, '/next' + mountpoint)
+ LOG.debug("mount stdout: %s", out)
+ LOG.debug("mount stderr: %s", err)
+ fstab.append(self._generate_fstab_line(
+ device, disk.get('mountpoint'), disk.get('fstype', 'xfs'),
+ disk.get('mountopts')))
+ self._copy_files(image_path)
+ for m in ['/dev', '/dev/pts', '/proc', '/sys', '/run']:
+ utils.execute('mount', '-B', m, '/next' + m)
+ self._write_fstab(fstab)
+ partition_label = self.get_boot_partition()
+ return self._install_bootloader(devices.get(partition_label,
+ partition_label))
+
+ def _generate_fstab_line(self, device, mountpoint, fstype, mountopts):
+ if not mountpoint and fstype != 'swap':
+ return ''
+ uuid = self._get_uuid(device)
+ opts = 'defaults'
+ dump = '0'
+ pas = '2'
+ if fstype == 'vfat':
+ opts = 'umask=0077'
+ if mountpoint in ['/', '/boot']:
+ pas = '1'
+ elif fstype == 'swap':
+ opts = 'sw'
+ pas = '0'
+ mountpoint = 'none'
+ return 'UUID=' + '\t'.join(
+ [uuid, mountpoint, fstype, mountopts or opts, dump, pas]) + '\n'
+
+ def _copy_files(self, image_path):
+ try:
+ os.mkdir('/image')
+ except OSError as e:
+ if e.errno != os.errno.EEXIST:
+ raise
+ utils.execute('guestmount', '-a', image_path, '-i', '--ro', '/image')
+ utils.execute('cp', '-a', '/image/.', '/next/')
+ utils.execute('umount', '-R', '/image')
+
+ def _write_fstab(self, fstab_list):
+ if ''.join(fstab_list).strip():
+ with open('/next/etc/fstab', 'w') as fstab:
+ fstab.write('# generated by disk_partitioner.py\n')
+ fstab.writelines(fstab_list)
+
+ def _install_bootloader(self, device):
+ device = device.rstrip('1234567890') # install to MBR
+ if os.path.isfile('/next/usr/sbin/grub-install'):
+ grub = 'grub'
+ elif os.path.isfile('/next/usr/sbin/grub2-install'):
+ grub = 'grub2'
+ else:
+ raise exceptions.EnvError('grub command not available on image')
+ utils.execute('chroot /next /usr/sbin/{}-mkconfig'
+ ' -o /boot/{}/grub.cfg'.format(grub, grub), shell=True)
+ utils.execute('chroot /next /usr/sbin/{}-install --recheck {}'.format(
+ grub, device), shell=True)
+ utils.execute('sync')
+ utils.execute('umount', '-R', '/next')
+ return device
+
+ @staticmethod
+ def _get_uuid(device):
+ out, _ = utils.execute('blkid -o value -s UUID ' + device, shell=True)
+ return out.strip()
diff --git a/ironic_lib/tests/test_systemsetup.py b/ironic_lib/tests/test_systemsetup.py
new file mode 100644
index 0000000..0e127f5
--- /dev/null
+++ b/ironic_lib/tests/test_systemsetup.py
@@ -0,0 +1,90 @@
+# Copyright (c) 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+
+import mock
+
+from ironic_lib.system_installer import exceptions
+from ironic_lib.system_installer import systemsetup
+
+
+class SystemSetupTestCase(unittest.TestCase):
+
+ @mock.patch.object(systemsetup.SystemSetup, '_cmd_exists')
+ def test_validate_env_fail(self, cmd):
+ system_setup = systemsetup.SystemSetup({'filesystems': {}})
+ cmd.return_value = False
+ with self.assertRaises(exceptions.EnvError):
+ system_setup.validate_env()
+
+ @mock.patch('ironic_lib.system_installer.systemsetup.open')
+ @mock.patch('ironic_lib.utils.execute')
+ @mock.patch.object(systemsetup.SystemSetup, '_get_uuid')
+ @mock.patch('os.path.isfile')
+ @mock.patch('os.mkdir')
+ def test_setup_disks(self, mkdir, is_file, uuid, exe_mock, mock_open):
+ uuid.return_value = 'test_uuid'
+ exe_mock.return_value = 'grub-install (GRUB) 2.02~beta3-4ubuntu2.2', 0
+
+ system_setup = systemsetup.SystemSetup(
+ {'filesystems': {'boot': {'mountpoint': '/boot',
+ 'mountopts': 'foo',
+ 'fstype': 'ext2'},
+ 'root': {'mountpoint': '/',
+ 'fstype': 'ext4'},
+ 'home': {'mountpoint': '/home'}}})
+ system_setup.setup_disks({}, 'test_image')
+ exe_mock.assert_any_call('mount', 'boot', '/next/boot')
+ file_handle = mock_open.return_value.__enter__.return_value
+ file_handle.writelines.assert_called_with(
+ ['UUID=test_uuid\t/\text4\tdefaults\t0\t1\n',
+ 'UUID=test_uuid\t/boot\text2\tfoo\t0\t1\n',
+ 'UUID=test_uuid\t/home\txfs\tdefaults\t0\t2\n'])
+
+ @mock.patch.object(systemsetup.SystemSetup, '_install_bootloader')
+ @mock.patch.object(systemsetup.SystemSetup, '_copy_files')
+ @mock.patch('ironic_lib.system_installer.systemsetup.open')
+ @mock.patch('ironic_lib.utils.execute')
+ @mock.patch.object(systemsetup.SystemSetup, '_get_uuid')
+ @mock.patch('os.path.isfile')
+ @mock.patch('os.mkdir')
+ def test_setup_disks_preserve_true(self, mkdir, is_file,
+ uuid, exe_mock, mock_open,
+ copy, bootloader):
+ uuid.return_value = 'test_uuid'
+ exe_mock.return_value = 'grub-install (GRUB) 2.02~beta3-4ubuntu2.2', 0
+
+ system_setup = systemsetup.SystemSetup(
+ {'filesystems': {'boot': {'mountpoint': '/boot',
+ 'mountopts': 'foo',
+ 'fstype': 'ext2'},
+ 'home': {'mountpoint': '/home',
+ 'preserve': 1}}})
+ system_setup.setup_disks({}, 'test_image')
+ exe_mock.assert_any_call('mount', 'boot', '/next/boot')
+ exe_mock.assert_any_call('mount', '-B', '/dev', '/next' + '/dev')
+ exe_mock.assert_any_call('mount', '-B', '/dev/pts',
+ '/next' + '/dev/pts')
+ exe_mock.assert_any_call('mount', '-B', '/proc', '/next' + '/proc')
+ exe_mock.assert_any_call('mount', '-B', '/sys', '/next' + '/sys')
+ exe_mock.assert_any_call('mount', '-B', '/run', '/next' + '/run')
+
+ assert exe_mock.call_count == 6
+
+ file_handle = mock_open.return_value.__enter__.return_value
+ file_handle.writelines.assert_called_with(
+ ['UUID=test_uuid\t/boot\text2\tfoo\t0\t1\n',
+ 'UUID=test_uuid\t/home\txfs\tdefaults\t0\t2\n'])
--
2.14.1