diff --git a/etc/fuel-agent/fuel-agent.conf.sample b/etc/fuel-agent/fuel-agent.conf.sample index c2caee76..61f11131 100644 --- a/etc/fuel-agent/fuel-agent.conf.sample +++ b/etc/fuel-agent/fuel-agent.conf.sample @@ -214,3 +214,4 @@ log_file=/var/log/fuel-agent.log # Default password for root user # (string value) default_root_password=r00tme +use_configdrive=false \ No newline at end of file diff --git a/fuel_agent/manager.py b/fuel_agent/manager.py index f6a87713..87fed991 100644 --- a/fuel_agent/manager.py +++ b/fuel_agent/manager.py @@ -131,6 +131,11 @@ opts = [ default=True, help='Create configdrive file, use pre-builded if set to False' ), + cfg.BoolOpt( + 'use_configdrive', + default=True, + help='Use separate partition for cloudinit configuration' + ), cfg.BoolOpt( 'fix_udev_net_rules', default=True, @@ -363,15 +368,7 @@ class Manager(object): fu.umount_fs(mount_point) os.rmdir(mount_point) - def _prepare_configdrive_files(self): - # see data sources part of cloud-init documentation - # for directory structure - cd_root = tempfile.mkdtemp(dir=CONF.tmp_path) - cd_latest = os.path.join(cd_root, 'openstack', 'latest') - md_output_path = os.path.join(cd_latest, 'meta_data.json') - ud_output_path = os.path.join(cd_latest, 'user_data') - os.makedirs(cd_latest) - + def _generate_cloudinit_config(self, metadata, userdata): cc_output_path = os.path.join(CONF.tmp_path, 'cloud_config.txt') bh_output_path = os.path.join(CONF.tmp_path, 'boothook.txt') @@ -392,13 +389,23 @@ class Manager(object): tmpl_dir, self.driver.configdrive_scheme.template_names('meta_data_json'), self.driver.configdrive_scheme.template_data(), - md_output_path + metadata ) utils.execute( - 'write-mime-multipart', '--output=%s' % ud_output_path, + 'write-mime-multipart', '--output=%s' % userdata, '%s:text/cloud-boothook' % bh_output_path, '%s:text/cloud-config' % cc_output_path) + + def _prepare_configdrive_files(self): + # see data sources part of cloud-init documentation + # for directory structure + cd_root = tempfile.mkdtemp(dir=CONF.tmp_path) + cd_latest = os.path.join(cd_root, 'openstack', 'latest') + md_output_path = os.path.join(cd_latest, 'meta_data.json') + ud_output_path = os.path.join(cd_latest, 'user_data') + os.makedirs(cd_latest) + self._generate_cloudinit_config(md_output_path, ud_output_path) return [os.path.join(cd_root, 'openstack')] def do_configdrive(self): @@ -430,6 +437,23 @@ class Manager(object): md5=md5, ) + def _prepare_cloudinit_config_files(self, target_dir): + # see data sources part of cloud-init documentation + # for directory structure + md_output_path = os.path.join(target_dir, 'meta-data') + ud_output_path = os.path.join(target_dir, 'user-data') + os.makedirs(target_dir) + self._generate_cloudinit_config(md_output_path, ud_output_path) + + def inject_cloudinit_config(self): + root_fs = self.driver.partition_scheme.fs_by_mount('/') + root = fu.mount_fs_temp(root_fs.type, str(root_fs.device)) + try: + self._prepare_cloudinit_config_files( + os.path.join(root, 'var/lib/cloud/seed/nocloud')) + finally: + fu.umount_fs(root) + def do_copyimage(self): LOG.debug('--- Copying images (do_copyimage) ---') for image in self.driver.image_scheme.images: @@ -488,6 +512,8 @@ class Manager(object): LOG.debug('Extending %s %s' % (image.format, image.target_device)) fu.extend_fs(image.format, image.target_device) + if not CONF.use_configdrive: + self.inject_cloudinit_config() self.move_files_to_their_places() def move_files_to_their_places(self, remove_src=True): @@ -968,7 +994,8 @@ class Manager(object): def do_provisioning(self): LOG.debug('--- Provisioning (do_provisioning) ---') self.do_partitioning() - self.do_configdrive() + if CONF.use_configdrive: + self.do_configdrive() self.do_copyimage() self.do_bootloader() LOG.debug('--- Provisioning END (do_provisioning) ---') diff --git a/fuel_agent/tests/test_manager.py b/fuel_agent/tests/test_manager.py index 0d142a90..910a42ec 100644 --- a/fuel_agent/tests/test_manager.py +++ b/fuel_agent/tests/test_manager.py @@ -538,6 +538,42 @@ class TestManager(unittest2.TestCase): '%s/%s:text/cloud-boothook' % (CONF.tmp_path, 'boothook.txt'), '%s/%s:text/cloud-config' % (CONF.tmp_path, 'cloud_config.txt')) + @mock.patch('os.makedirs') + @mock.patch.object(utils, 'execute') + @mock.patch.object(utils, 'render_and_save') + def test_prepare_cloudinit_config(self, mock_u_ras, mock_u_e, + mock_makedirs): + self.mgr._prepare_cloudinit_config_files( + '/var/lib/cloud/seed/nocloud') + mock_makedirs.assert_called_once_with('/var/lib/cloud/seed/nocloud') + + mock_u_ras_expected_calls = [ + mock.call(CONF.nc_template_path, + ['cloud_config_pro_fi-le.jinja2', + 'cloud_config_pro.jinja2', + 'cloud_config_pro_fi.jinja2', + 'cloud_config.jinja2'], + mock.ANY, '%s/%s' % (CONF.tmp_path, 'cloud_config.txt')), + mock.call(CONF.nc_template_path, + ['boothook_pro_fi-le.jinja2', + 'boothook_pro.jinja2', + 'boothook_pro_fi.jinja2', + 'boothook.jinja2'], + mock.ANY, '%s/%s' % (CONF.tmp_path, 'boothook.txt')), + mock.call(CONF.nc_template_path, + ['meta_data_json_pro_fi-le.jinja2', + 'meta_data_json_pro.jinja2', + 'meta_data_json_pro_fi.jinja2', + 'meta_data_json.jinja2'], + mock.ANY, '/var/lib/cloud/seed/nocloud/meta-data')] + self.assertEqual(mock_u_ras_expected_calls, mock_u_ras.call_args_list) + + mock_u_e.assert_called_once_with( + 'write-mime-multipart', + '--output=/var/lib/cloud/seed/nocloud/user-data', + '%s/%s:text/cloud-boothook' % (CONF.tmp_path, 'boothook.txt'), + '%s/%s:text/cloud-config' % (CONF.tmp_path, 'cloud_config.txt')) + @mock.patch('fuel_agent.manager.fu', create=True) @mock.patch('os.path.isdir') @mock.patch('os.rmdir') @@ -670,6 +706,14 @@ class TestManager(unittest2.TestCase): self.assertEqual(mock_fu_ef_expected_calls, mock_fu_ef.call_args_list) self.assertTrue(mock_mfttp.called) + @mock.patch('fuel_agent.manager.Manager.inject_cloudinit_config') + @mock.patch('fuel_agent.manager.Manager.move_files_to_their_places') + @mock.patch('fuel_agent.manager.CONF.use_configdrive', False) + def test_cloudconfig_iinjection(self, mock_mfttp, mock_icc): + with mock.patch.object(self.mgr.driver.image_scheme, 'images', []): + self.mgr.do_copyimage() + mock_icc.assert_called_once_with() + @mock.patch.object(fu, 'get_fs_type') @mock.patch.object(manager.os.path, 'exists') @mock.patch.object(hu, 'is_block_device')