From c30683e98254e694f1171e5dcdf8c0ef85021bb0 Mon Sep 17 00:00:00 2001 From: Ben Howard Date: Thu, 26 Sep 2013 08:18:29 -0600 Subject: Added support for formating the ephemeral disk on Windows Azure. --- cloudinit/sources/DataSourceAzure.py | 27 ++++++++++++++-- doc/examples/cloud-config-disk-setup.txt | 8 ++--- tests/unittests/test_datasource/test_azure.py | 45 +++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index a77c3d9a..3f96a0a5 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -44,8 +44,17 @@ BUILTIN_DS_CONFIG = { 'policy': True, 'command': BOUNCE_COMMAND, 'hostname_command': 'hostname', - } + }, + 'ephemeral_disk': '/dev/sdb1', + 'disk_setup': { + 'ephemeral0': {'table_type': 'mbr', + 'layout': True, + 'overwrite': False} + }, + 'fs_setup': [{'filesystem': 'ext4', 'device': '/dev/sdb', + 'partition': 'auto'}], } + DS_CFG_PATH = ['datasource', DS_NAME] @@ -111,11 +120,22 @@ class DataSourceAzureNet(sources.DataSource): if seed: self.metadata['random_seed'] = seed + # now update ds_cfg to reflect contents pass in config usercfg = util.get_cfg_by_path(self.cfg, DS_CFG_PATH, {}) self.ds_cfg = util.mergemanydict([usercfg, self.ds_cfg]) mycfg = self.ds_cfg + # Put the disk format elements into the config object + if 'disk_setup' in mycfg: + self.cfg['disk_setup'] = mycfg['disk_setup'] + + if 'fs_setup' in mycfg: + self.cfg['fs_setup'] = mycfg['fs_setup'] + + if 'ephemeral_disk' in mycfg: + self.cfg['ephemeral_disk'] = mycfg['ephemeral_disk'] + # walinux agent writes files world readable, but expects # the directory to be protected. write_files(mycfg['data_dir'], files, dirmode=0700) @@ -161,9 +181,12 @@ class DataSourceAzureNet(sources.DataSource): pubkeys = pubkeys_from_crt_files(fp_files) self.metadata['public-keys'] = pubkeys - return True + def device_name_to_device(self, name): + if 'ephemeral0' in name and 'ephemeral_disk' in self.cfg: + return self.cfg['ephemeral_disk'] + def get_config_obj(self): return self.cfg diff --git a/doc/examples/cloud-config-disk-setup.txt b/doc/examples/cloud-config-disk-setup.txt index db2c52a7..0ca65fd0 100644 --- a/doc/examples/cloud-config-disk-setup.txt +++ b/doc/examples/cloud-config-disk-setup.txt @@ -19,8 +19,8 @@ Default disk definitions for AWS Default disk definitions for Windows Azure ------------------------------------------ -(Not implemented yet due to conflict with WALinuxAgent in Ubuntu) +ephemeral_disk: /dev/sdb1 disk_setup: /dev/sdb: type: mbr @@ -29,15 +29,15 @@ disk_setup: fs_setup: - label: ephemeral0 - filesystem: ext3 + filesystem: ext4 device: ephemeral0 - partition: any + partition: auto Default disk definitions for SmartOS ------------------------------------ -ephemeral_disk: /dev/vdb +ephemeral_disk: /dev/vdb1 disk_setup: /dev/vdb: type: mbr diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py index 1ca6a79d..aa37337c 100644 --- a/tests/unittests/test_datasource/test_azure.py +++ b/tests/unittests/test_datasource/test_azure.py @@ -290,6 +290,51 @@ class TestAzureDataSource(MockerTestCase): self.assertEqual(data.get('apply_hostname_bounce', "N/A"), "N/A") + def test_default_ephemeral(self): + # make sure the ephemeral device works + odata = {} + data = {'ovfcontent': construct_valid_ovf_env(data=odata), + 'sys_cfg': {}} + + dsrc = self._get_ds(data) + ret = dsrc.get_data() + self.assertTrue(ret) + cfg = dsrc.get_config_obj() + + self.assertEquals(dsrc.device_name_to_device("ephemeral0"), + "/dev/sdb1") + assert 'disk_setup' in cfg + assert 'fs_setup' in cfg + self.assertIsInstance(cfg['disk_setup'], dict) + self.assertIsInstance(cfg['fs_setup'], list) + + def test_overriden_ephemeral(self): + # Make sure that the merge happens correctly + dscfg = {'ephemeral_disk': '/dev/sdc', + 'disk_setup': {'/dev/sdc': {'something': '...'}, + 'ephemeral0': False, + }, + 'fs_setup': [{'label': 'something'}]} + odata = {'HostName': "myhost", 'UserName': "myuser", + 'dscfg': {'text': yaml.dump(dscfg), 'encoding': 'plain'}} + data = {'ovfcontent': construct_valid_ovf_env(data=odata), + 'sys_cfg': {}} + + dsrc = self._get_ds(data) + ret = dsrc.get_data() + cfg = dsrc.get_config_obj() + self.assertTrue(ret) + self.assertTrue(cfg) + self.assertEquals(dsrc.device_name_to_device("ephemeral0"), + "/dev/sdc") + assert 'disk_setup' in cfg + assert 'fs_setup' in cfg + self.assertIsInstance(cfg['disk_setup'], dict) + self.assertIsInstance(cfg['fs_setup'], list) + assert 'ephemeral0' in cfg['disk_setup'] + assert '/dev/sdc' in cfg['disk_setup'] + self.assertFalse(cfg['disk_setup']['ephemeral0']) + class TestReadAzureOvf(MockerTestCase): def test_invalid_xml_raises_non_azure_ds(self): -- cgit v1.2.1 From 22e3686ee67a06d5063c7a5203dd5d20b7b43a99 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 26 Sep 2013 10:56:23 -0400 Subject: fix pep8 --- cloudinit/sources/DataSourceAzure.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index 3f96a0a5..ef3f073a 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -120,7 +120,6 @@ class DataSourceAzureNet(sources.DataSource): if seed: self.metadata['random_seed'] = seed - # now update ds_cfg to reflect contents pass in config usercfg = util.get_cfg_by_path(self.cfg, DS_CFG_PATH, {}) self.ds_cfg = util.mergemanydict([usercfg, self.ds_cfg]) -- cgit v1.2.1 From f39684743bae09fa8d4c6b5b014e1f05e9fbe30d Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 26 Sep 2013 11:07:09 -0400 Subject: add entry to ChangeLog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 8222e2b7..880ace21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ - small fix for OVF datasource for iso transport on non-iso9660 filesystem - determine if upstart version is suitable for 'initctl reload-configuration' (LP: #1124384). If so, then invoke it. + supports setting up instance-store disk with partition table and filesystem. - add Azure datasource. - add support for SuSE / SLES [Juerg Haefliger] - add a trailing carriage return to chpasswd input, which reportedly -- cgit v1.2.1 From 529ffb443d523fb9df7cb9f0a6c65151a930f625 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 26 Sep 2013 11:46:54 -0400 Subject: re-work 'ephemeral_disk' and location of builtin config Previously we had this 'ephemeral_disk' entry in the datasource config for Azure, and then we also copied some entries into the .cfg for that datasource from the datasource config. Ie, datasource['Azure']['disk_setup'] would be oddly copied into the .cfg object that was returned by 'get_config_obj' Now, instead, we have a BUILTIN_CLOUD_CONFIG, which has those same values in it. The other change here is that 'ephemeral_disk' now has no meaning. Instead, we add a populated-by-default entry 'disk_aliases' to the BUILTIN_DS_CFG, and then just return entries in it for 'device_name_to_device' --- cloudinit/sources/DataSourceAzure.py | 24 ++++++++---------------- cloudinit/sources/DataSourceSmartOS.py | 12 ++++++------ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index ef3f073a..f7ca9eb6 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -45,7 +45,10 @@ BUILTIN_DS_CONFIG = { 'command': BOUNCE_COMMAND, 'hostname_command': 'hostname', }, - 'ephemeral_disk': '/dev/sdb1', + 'disk_aliases': {'ephemeral0': '/dev/sdb1'}, +} + +BUILTIN_CLOUD_CONFIG = { 'disk_setup': { 'ephemeral0': {'table_type': 'mbr', 'layout': True, @@ -103,7 +106,7 @@ class DataSourceAzureNet(sources.DataSource): (md, self.userdata_raw, cfg, files) = ret self.seed = cdev self.metadata = util.mergemanydict([md, DEFAULT_METADATA]) - self.cfg = cfg + self.cfg = util.mergemanydict([cfg, BUILTIN_CLOUD_CONFIG]) found = cdev LOG.debug("found datasource in %s", cdev) @@ -121,20 +124,10 @@ class DataSourceAzureNet(sources.DataSource): self.metadata['random_seed'] = seed # now update ds_cfg to reflect contents pass in config - usercfg = util.get_cfg_by_path(self.cfg, DS_CFG_PATH, {}) - self.ds_cfg = util.mergemanydict([usercfg, self.ds_cfg]) + user_ds_cfg = util.get_cfg_by_path(self.cfg, DS_CFG_PATH, {}) + self.ds_cfg = util.mergemanydict([user_ds_cfg, self.ds_cfg]) mycfg = self.ds_cfg - # Put the disk format elements into the config object - if 'disk_setup' in mycfg: - self.cfg['disk_setup'] = mycfg['disk_setup'] - - if 'fs_setup' in mycfg: - self.cfg['fs_setup'] = mycfg['fs_setup'] - - if 'ephemeral_disk' in mycfg: - self.cfg['ephemeral_disk'] = mycfg['ephemeral_disk'] - # walinux agent writes files world readable, but expects # the directory to be protected. write_files(mycfg['data_dir'], files, dirmode=0700) @@ -183,8 +176,7 @@ class DataSourceAzureNet(sources.DataSource): return True def device_name_to_device(self, name): - if 'ephemeral0' in name and 'ephemeral_disk' in self.cfg: - return self.cfg['ephemeral_disk'] + return self.ds_cfg['disk_aliases'].get(name) def get_config_obj(self): return self.cfg diff --git a/cloudinit/sources/DataSourceSmartOS.py b/cloudinit/sources/DataSourceSmartOS.py index da1eec79..050325fa 100644 --- a/cloudinit/sources/DataSourceSmartOS.py +++ b/cloudinit/sources/DataSourceSmartOS.py @@ -72,7 +72,10 @@ BUILTIN_DS_CONFIG = { 'iptables_disable'], 'base64_keys': [], 'base64_all': False, - 'ephemeral_disk': '/dev/vdb', + 'disk_aliases': {'ephemeral0': '/dev/vdb'}, +} + +BUILTIN_CLOUD_CONFIG = { 'disk_setup': { 'ephemeral0': {'table_type': 'mbr', 'layout': True, @@ -94,9 +97,7 @@ class DataSourceSmartOS(sources.DataSource): BUILTIN_DS_CONFIG]) self.metadata = {} - self.cfg = {} - self.cfg['disk_setup'] = self.ds_cfg.get('disk_setup') - self.cfg['fs_setup'] = self.ds_cfg.get('fs_setup') + self.cfg = BUILTIN_CLOUD_CONFIG self.seed = self.ds_cfg.get("serial_device") self.seed_timeout = self.ds_cfg.get("serial_timeout") @@ -154,8 +155,7 @@ class DataSourceSmartOS(sources.DataSource): return True def device_name_to_device(self, name): - if 'ephemeral0' in name: - return self.ds_cfg['ephemeral_disk'] + return self.ds_cfg['disk_aliases'].get(name) def get_config_obj(self): return self.cfg -- cgit v1.2.1 From 894e7d38e1b4f0b18dc36bbe147098b7137840c1 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 12:26:25 -0400 Subject: fix tests small other changes Also * cloudinit/sources/DataSourceAzure.py: invalid xml in a file called 'ovfenv.xml' should raise BrokenAzureDatasource rather than NonAzureDataSource * cloudinit/sources/DataSourceSmartOS.py: cloudinit/sources/DataSourceAzure.py use 'ephemeral0' as the device name in builtin fs_setup * tests/unittests/test_datasource/test_azure.py: * always patch 'list_possible_azure_ds_devs' as it calls find_devs_with which calls blkid, and dramatically was slowing down tests on my system. * test_user_cfg_set_agent_command_plain: fix this test to not depend on specific format of yaml.dumps(). * test_userdata_arrives: add a test that user-data makes it through --- cloudinit/sources/DataSourceAzure.py | 4 +- cloudinit/sources/DataSourceSmartOS.py | 2 +- tests/unittests/test_datasource/test_azure.py | 51 ++++++++++++++----------- tests/unittests/test_datasource/test_smartos.py | 28 +++++++------- 4 files changed, 44 insertions(+), 41 deletions(-) diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index f7ca9eb6..a9680d79 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -54,7 +54,7 @@ BUILTIN_CLOUD_CONFIG = { 'layout': True, 'overwrite': False} }, - 'fs_setup': [{'filesystem': 'ext4', 'device': '/dev/sdb', + 'fs_setup': [{'filesystem': 'ext4', 'device': 'ephemeral0', 'partition': 'auto'}], } @@ -363,7 +363,7 @@ def read_azure_ovf(contents): try: dom = minidom.parseString(contents) except Exception as e: - raise NonAzureDataSource("invalid xml: %s" % e) + raise BrokenAzureDataSource("invalid xml: %s" % e) results = find_child(dom.documentElement, lambda n: n.localName == "ProvisioningSection") diff --git a/cloudinit/sources/DataSourceSmartOS.py b/cloudinit/sources/DataSourceSmartOS.py index 050325fa..fa26633a 100644 --- a/cloudinit/sources/DataSourceSmartOS.py +++ b/cloudinit/sources/DataSourceSmartOS.py @@ -82,7 +82,7 @@ BUILTIN_CLOUD_CONFIG = { 'overwrite': False} }, 'fs_setup': [{'label': 'ephemeral0', 'filesystem': 'ext3', - 'device': '/dev/xvdb', 'partition': 'auto'}], + 'device': 'ephemeral0', 'partition': 'auto'}], } diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py index aa37337c..3bcc9520 100644 --- a/tests/unittests/test_datasource/test_azure.py +++ b/tests/unittests/test_datasource/test_azure.py @@ -120,8 +120,7 @@ class TestAzureDataSource(MockerTestCase): mod = DataSourceAzure - if data.get('dsdevs'): - self.apply_patches([(mod, 'list_possible_azure_ds_devs', dsdevs)]) + self.apply_patches([(mod, 'list_possible_azure_ds_devs', dsdevs)]) self.apply_patches([(mod, 'invoke_agent', _invoke_agent), (mod, 'write_files', _write_files), @@ -154,9 +153,12 @@ class TestAzureDataSource(MockerTestCase): def test_user_cfg_set_agent_command_plain(self): # set dscfg in via plaintext - cfg = {'agent_command': "my_command"} + # we must have friendly-to-xml formatted plaintext in yaml_cfg + # not all plaintext is expected to work. + yaml_cfg = "{agent_command: my_command}\n" + cfg = yaml.safe_load(yaml_cfg) odata = {'HostName': "myhost", 'UserName': "myuser", - 'dscfg': {'text': yaml.dump(cfg), 'encoding': 'plain'}} + 'dscfg': {'text': yaml_cfg, 'encoding': 'plain'}} data = {'ovfcontent': construct_valid_ovf_env(data=odata)} dsrc = self._get_ds(data) @@ -308,38 +310,41 @@ class TestAzureDataSource(MockerTestCase): self.assertIsInstance(cfg['disk_setup'], dict) self.assertIsInstance(cfg['fs_setup'], list) - def test_overriden_ephemeral(self): - # Make sure that the merge happens correctly - dscfg = {'ephemeral_disk': '/dev/sdc', - 'disk_setup': {'/dev/sdc': {'something': '...'}, - 'ephemeral0': False, - }, - 'fs_setup': [{'label': 'something'}]} + def test_provide_disk_aliases(self): + # Make sure that user can affect disk aliases + dscfg = {'disk_aliases': {'ephemeral0': '/dev/sdc'}} odata = {'HostName': "myhost", 'UserName': "myuser", - 'dscfg': {'text': yaml.dump(dscfg), 'encoding': 'plain'}} - data = {'ovfcontent': construct_valid_ovf_env(data=odata), - 'sys_cfg': {}} + 'dscfg': {'text': base64.b64encode(yaml.dump(dscfg)), + 'encoding': 'base64'}} + usercfg = {'disk_setup': {'/dev/sdc': {'something': '...'}, + 'ephemeral0': False}} + userdata = '#cloud-config' + yaml.dump(usercfg) + "\n" + + ovfcontent = construct_valid_ovf_env(data=odata, userdata=userdata) + data = {'ovfcontent': ovfcontent, 'sys_cfg': {}} dsrc = self._get_ds(data) ret = dsrc.get_data() - cfg = dsrc.get_config_obj() self.assertTrue(ret) + cfg = dsrc.get_config_obj() self.assertTrue(cfg) self.assertEquals(dsrc.device_name_to_device("ephemeral0"), "/dev/sdc") - assert 'disk_setup' in cfg - assert 'fs_setup' in cfg - self.assertIsInstance(cfg['disk_setup'], dict) - self.assertIsInstance(cfg['fs_setup'], list) - assert 'ephemeral0' in cfg['disk_setup'] - assert '/dev/sdc' in cfg['disk_setup'] - self.assertFalse(cfg['disk_setup']['ephemeral0']) + + def test_userdata_arrives(self): + userdata = "This is my user-data" + xml = construct_valid_ovf_env(data={}, userdata=userdata) + data = {'ovfcontent': xml} + dsrc = self._get_ds(data) + dsrc.get_data() + + self.assertEqual(userdata, dsrc.userdata_raw) class TestReadAzureOvf(MockerTestCase): def test_invalid_xml_raises_non_azure_ds(self): invalid_xml = "" + construct_valid_ovf_env(data={}) - self.assertRaises(DataSourceAzure.NonAzureDataSource, + self.assertRaises(DataSourceAzure.BrokenAzureDataSource, DataSourceAzure.read_azure_ovf, invalid_xml) def test_load_with_pubkeys(self): diff --git a/tests/unittests/test_datasource/test_smartos.py b/tests/unittests/test_datasource/test_smartos.py index 56fe811e..956767d8 100644 --- a/tests/unittests/test_datasource/test_smartos.py +++ b/tests/unittests/test_datasource/test_smartos.py @@ -79,7 +79,6 @@ class MockSerial(object): if self.last in self.mockdata: if not self.mocked_out: self.mocked_out = [x for x in self._format_out()] - print self.mocked_out if len(self.mocked_out) > self.count: self.count += 1 @@ -275,26 +274,25 @@ class TestSmartOSDataSource(MockerTestCase): self.assertIsInstance(cfg['disk_setup'], dict) self.assertIsInstance(cfg['fs_setup'], list) - def test_override_builtin_ds(self): + def test_override_disk_aliases(self): # Test to make sure that the built-in DS is overriden - data = {} - data['disk_setup'] = {'test_dev': {}} - data['fs_setup'] = [{'label': 'test_dev'}] - data['serial_device'] = '/dev/ttyS2' - dsrc = self._get_ds(ds_cfg=data) - cfg = dsrc.get_config_obj() + builtin = DataSourceSmartOS.BUILTIN_DS_CONFIG + + mydscfg = {'disk_aliases': {'FOO': '/dev/bar'}} + # expect that these values are in builtin, or this is pointless + for k in mydscfg: + self.assertIn(k, builtin) + + dsrc = self._get_ds(ds_cfg=mydscfg) ret = dsrc.get_data() self.assertTrue(ret) - assert 'disk_setup' in cfg - assert 'fs_setup' in cfg - self.assertIsInstance(cfg['disk_setup'], dict) - self.assertIsInstance(cfg['fs_setup'], list) - assert 'test_dev' in cfg['disk_setup'] - assert 'test_dev' in cfg['fs_setup'][0]['label'] + self.assertEqual(mydscfg['disk_aliases']['FOO'], + dsrc.ds_cfg['disk_aliases']['FOO']) - self.assertEquals(data['serial_device'], dsrc.seed) + self.assertEqual(dsrc.device_name_to_device('FOO'), + mydscfg['disk_aliases']['FOO']) def apply_patches(patches): -- cgit v1.2.1 From d3aba30c0a257b684acc869ac146f30cc985c4d4 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 12:52:45 -0400 Subject: fix doc for smartos --- doc/sources/smartos/README.rst | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/doc/sources/smartos/README.rst b/doc/sources/smartos/README.rst index e2d3312e..8b63e520 100644 --- a/doc/sources/smartos/README.rst +++ b/doc/sources/smartos/README.rst @@ -73,15 +73,21 @@ or not to base64 decode something: (i.e. /etc/cloud/cloud.cfg.d) that sets which values should not be base64 decoded. -ephemeral_disk: +disk_aliases and ephemeral disk: --------------- - -In order to instruct Cloud-init which disk to auto-mount. By default, -SmartOS only supports a single ephemeral disk. - -The default SmartOS configuration will prepare the ephemeral disk and format -it for you. SmartOS does not, by default, prepare the ephemeral disk for you. - -If you change ephemeral_disk, you should also consider changing -the default disk formatting parameters. See -doc/examples/cloud-config-disk-setup.txt for information on using this. +By default, SmartOS only supports a single ephemeral disk. That disk is +completely empty (un-partitioned with no filesystem). + +The SmartOS datasource has built-in cloud-config which instructs the +'disk_setup' module to partition and format the ephemeral disk. + +You can control the disk_setup then in 2 ways: + 1. through the datasource config, you can change the 'alias' of + ephermeral0 to reference another device. The default is: + 'disk_aliases': {'ephemeral0': '/dev/vdb'}, + Which means anywhere disk_setup sees a device named 'ephemeral0' + then /dev/vdb will be substituted. + 2. you can provide disk_setup or fs_setup data in user-data to overwrite + the datasource's built-in values. + +See doc/examples/cloud-config-disk-setup.txt for information on disk_setup. -- cgit v1.2.1 From ad9abea158c2001770a88c9911fe03f2a02399e0 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 12:56:01 -0400 Subject: fix probably debug code that explicitly set 'partition' to 'any'. --- cloudinit/config/cc_disk_setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index fb404c5d..8b7581a7 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -576,10 +576,9 @@ def mkfs(cloud, fs_cfg): When 'cmd' is provided then no other parameter is required. """ - fs_cfg['partition'] = 'any' label = fs_cfg.get('label') device = fs_cfg.get('device') - partition = str(fs_cfg.get('partition')) + partition = str(fs_cfg.get('partition'), 'any') fs_type = fs_cfg.get('filesystem') fs_cmd = fs_cfg.get('cmd', []) fs_opts = fs_cfg.get('extra_opts', []) -- cgit v1.2.1 From ebb7da33895e72597db93e0fedea0fe204140d1b Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 12:58:50 -0400 Subject: update documentation --- doc/examples/cloud-config-disk-setup.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/examples/cloud-config-disk-setup.txt b/doc/examples/cloud-config-disk-setup.txt index 0ca65fd0..c108d924 100644 --- a/doc/examples/cloud-config-disk-setup.txt +++ b/doc/examples/cloud-config-disk-setup.txt @@ -20,9 +20,9 @@ Default disk definitions for AWS Default disk definitions for Windows Azure ------------------------------------------ -ephemeral_disk: /dev/sdb1 +device_aliases: {'ephemeral0': '/dev/sdb'} disk_setup: - /dev/sdb: + ephemeral0: type: mbr layout: True overwrite: False @@ -37,9 +37,9 @@ fs_setup: Default disk definitions for SmartOS ------------------------------------ -ephemeral_disk: /dev/vdb1 +device_aliases: {'ephemeral0': '/dev/sdb'} disk_setup: - /dev/vdb: + ephemeral0: type: mbr layout: True overwrite: False @@ -47,8 +47,8 @@ disk_setup: fs_setup: - label: ephemeral0 filesystem: ext3 - device: /dev/vdb - partition: 1 + device: ephemeral0 + partition: auto Cavaut for SmartOS: if ephemeral disk is not defined, then the disk will not be automatically added to the mounts. -- cgit v1.2.1 From 8d8cd21830f146cc5d25ca07834ca9398e4345db Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 13:00:35 -0400 Subject: azure data source 'ephemeral0' point to '/dev/sdb', not /dev/sdb1 in general block device mappings should be to block devices, not partitoins. --- cloudinit/sources/DataSourceAzure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index a9680d79..7ba6cea8 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -45,7 +45,7 @@ BUILTIN_DS_CONFIG = { 'command': BOUNCE_COMMAND, 'hostname_command': 'hostname', }, - 'disk_aliases': {'ephemeral0': '/dev/sdb1'}, + 'disk_aliases': {'ephemeral0': '/dev/sdb'}, } BUILTIN_CLOUD_CONFIG = { -- cgit v1.2.1 From f59a72f2e2f3c55ba6bc0e0f4887fd3d82b77a30 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 13:16:38 -0400 Subject: fix syntax error in last commit --- cloudinit/config/cc_disk_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index 8b7581a7..a170f81f 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -578,7 +578,7 @@ def mkfs(cloud, fs_cfg): """ label = fs_cfg.get('label') device = fs_cfg.get('device') - partition = str(fs_cfg.get('partition'), 'any') + partition = str(fs_cfg.get('partition', 'any')) fs_type = fs_cfg.get('filesystem') fs_cmd = fs_cfg.get('cmd', []) fs_opts = fs_cfg.get('extra_opts', []) -- cgit v1.2.1 From 9a4d0621de509291e7c4cb4e83742bbd12652d33 Mon Sep 17 00:00:00 2001 From: Ben Howard Date: Fri, 27 Sep 2013 11:35:36 -0600 Subject: Disable partitioning of ephemeral for SmartOS at request of Joyent --- cloudinit/sources/DataSourceSmartOS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinit/sources/DataSourceSmartOS.py b/cloudinit/sources/DataSourceSmartOS.py index fa26633a..93b8b50b 100644 --- a/cloudinit/sources/DataSourceSmartOS.py +++ b/cloudinit/sources/DataSourceSmartOS.py @@ -78,7 +78,7 @@ BUILTIN_DS_CONFIG = { BUILTIN_CLOUD_CONFIG = { 'disk_setup': { 'ephemeral0': {'table_type': 'mbr', - 'layout': True, + 'layout': False, 'overwrite': False} }, 'fs_setup': [{'label': 'ephemeral0', 'filesystem': 'ext3', -- cgit v1.2.1 From d7799040e194e6ef5c5cb5851e42dd1983c96199 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 15:45:56 -0400 Subject: update to get functional with any alias in a 'device' entry --- cloudinit/config/cc_disk_setup.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index a170f81f..85e184cb 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -513,9 +513,6 @@ def mkpart(device, cloud, definition): # Check if the default device is a partition or not LOG.debug("Checking against default devices") if _device and (_device != device): - if not is_device_valid(_device): - _device = _device[:-1] - if not is_device_valid(_device): raise Exception("Unable to find backing block device for %s" % \ device) @@ -586,7 +583,7 @@ def mkfs(cloud, fs_cfg): # This allows you to define the default ephemeral or swap LOG.debug("Checking %s against default devices" % device) - _device = is_default_device(label, cloud, fallback=device) + _device = is_default_device(device, cloud, fallback=device) if _device and (_device != device): if not is_device_valid(_device): raise Exception("Unable to find backing block device for %s" % \ -- cgit v1.2.1 From 395c9819966d97ef70d3dbfd5e2d47dba64af039 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 15:58:56 -0400 Subject: adjust aliases early rather than late. this adds 2 functions update_disk_setup_devices update_fs_setup_devices Which update the appropriate datatype, and translate the names. Translating early means we don't have to deal with updating in the mkfs or mkpart calls explicitly. These are more easily unit tested as they just take a dictionary of the expected type and a 'transformer' that should return a new name or None. --- cloudinit/config/cc_disk_setup.py | 79 ++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index 85e184cb..487a2582 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -41,6 +41,7 @@ def handle(_name, cfg, cloud, log, _args): """ disk_setup = cfg.get("disk_setup") if isinstance(disk_setup, dict): + update_disk_setup_devices(disk_setup, cloud.device_name_to_device) log.info("Partitioning disks.") for disk, definition in disk_setup.items(): if not isinstance(definition, dict): @@ -51,13 +52,13 @@ def handle(_name, cfg, cloud, log, _args): log.debug("Creating new partition table/disk") util.log_time(logfunc=LOG.debug, msg="Creating partition on %s" % disk, - func=mkpart, args=(disk, cloud, definition)) + func=mkpart, args=(disk, definition)) except Exception as e: util.logexc(LOG, "Failed partitioning operation\n%s" % e) fs_setup = cfg.get("fs_setup") if isinstance(fs_setup, list): - log.info("Creating file systems.") + update_fs_setup_devices(fs_setup, cloud.device_name_to_device) for definition in fs_setup: if not isinstance(definition, dict): log.warn("Invalid file system definition: %s" % definition) @@ -68,31 +69,48 @@ def handle(_name, cfg, cloud, log, _args): device = definition.get('device') util.log_time(logfunc=LOG.debug, msg="Creating fs for %s" % device, - func=mkfs, args=(cloud, definition)) + func=mkfs, args=(definition,)) except Exception as e: util.logexc(LOG, "Failed during filesystem operation\n%s" % e) -def is_default_device(name, cloud, fallback=None): - """ - Ask the cloud datasource if the 'name' maps to a default - device. If so, return that value, otherwise return 'name', or - fallback if so defined. - """ - - _dev = None - try: - _dev = cloud.device_name_to_device(name) - except Exception as e: - util.logexc(LOG, "Failed to find mapping for %s" % e) +def update_disk_setup_devices(disk_setup, tformer): + # update 'disk_setup' dictionary anywhere were a device may occur + # update it with the response from 'tformer' + for origname in disk_setup.keys(): + transformed = tformer(origname) + if transformed is None or transformed == origname: + continue + if transformed in disk_setup: + LOG.info("Replacing %s in disk_setup for translation of %s", + origname, transformed) + del disk_setup[transformed] + + disk_setup[transformed] = disk_setup[origname] + disk_setup[transformed]['_origname'] = origname + del disk_setup[origname] + LOG.debug("updated disk_setup device entry '%s' to '%s'", + origname, transformed) + + +def update_fs_setup_devices(disk_setup, tformer): + # update 'fs_setup' dictionary anywhere were a device may occur + # update it with the response from 'tformer' + for definition in disk_setup: + if not isinstance(definition, dict): + LOG.warn("entry in disk_setup not a dict: %s", definition) + continue - if _dev: - return _dev + origname = definition.get('device') + if origname is None: + continue - if fallback: - return fallback + transformed = tformer(origname) + if transformed is None or transformed == origname: + continue - return name + definition['_origname'] = origname + definition['device'] = transformed def value_splitter(values, start=None): @@ -488,12 +506,11 @@ def exec_mkpart(table_type, device, layout): return get_dyn_func("exec_mkpart_%s", table_type, device, layout) -def mkpart(device, cloud, definition): +def mkpart(device, definition): """ Creates the partition table. Parameters: - cloud: the cloud object definition: dictionary describing how to create the partition. The following are supported values in the dict: @@ -508,17 +525,9 @@ def mkpart(device, cloud, definition): overwrite = definition.get('overwrite', False) layout = definition.get('layout', False) table_type = definition.get('table_type', 'mbr') - _device = is_default_device(device, cloud) # Check if the default device is a partition or not LOG.debug("Checking against default devices") - if _device and (_device != device): - if not is_device_valid(_device): - raise Exception("Unable to find backing block device for %s" % \ - device) - else: - LOG.debug("Mapped %s to physical device %s" % (device, _device)) - device = _device if (isinstance(layout, bool) and not layout) or not layout: LOG.debug("Device is not to be partitioned, skipping") @@ -552,7 +561,7 @@ def mkpart(device, cloud, definition): LOG.debug("Partition table created for %s" % device) -def mkfs(cloud, fs_cfg): +def mkfs(fs_cfg): """ Create a file system on the device. @@ -583,14 +592,6 @@ def mkfs(cloud, fs_cfg): # This allows you to define the default ephemeral or swap LOG.debug("Checking %s against default devices" % device) - _device = is_default_device(device, cloud, fallback=device) - if _device and (_device != device): - if not is_device_valid(_device): - raise Exception("Unable to find backing block device for %s" % \ - device) - else: - LOG.debug("Mapped %s to physical device %s" % (device, _device)) - device = _device if not partition or partition.isdigit(): # Handle manual definition of partition -- cgit v1.2.1 From 387ed73726d20572912cedc7d8e98ce883390265 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 16:17:58 -0400 Subject: demote .info to .debug, add another debug --- cloudinit/config/cc_disk_setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index 487a2582..e64176ba 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -42,7 +42,7 @@ def handle(_name, cfg, cloud, log, _args): disk_setup = cfg.get("disk_setup") if isinstance(disk_setup, dict): update_disk_setup_devices(disk_setup, cloud.device_name_to_device) - log.info("Partitioning disks.") + log.debug("Partitioning disks: %s", str(disk_setup)) for disk, definition in disk_setup.items(): if not isinstance(definition, dict): log.warn("Invalid disk definition for %s" % disk) @@ -58,6 +58,7 @@ def handle(_name, cfg, cloud, log, _args): fs_setup = cfg.get("fs_setup") if isinstance(fs_setup, list): + log.debug("setting up filesystems: %s", str(fs_setup)) update_fs_setup_devices(fs_setup, cloud.device_name_to_device) for definition in fs_setup: if not isinstance(definition, dict): -- cgit v1.2.1 From 5151f08c61a996ada0917a23cbd1288fdaec8837 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 16:31:31 -0400 Subject: fix test to adjust for 'ephemeral0' being /dev/sdb --- tests/unittests/test_datasource/test_azure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py index 3bcc9520..86e2ed8c 100644 --- a/tests/unittests/test_datasource/test_azure.py +++ b/tests/unittests/test_datasource/test_azure.py @@ -304,7 +304,7 @@ class TestAzureDataSource(MockerTestCase): cfg = dsrc.get_config_obj() self.assertEquals(dsrc.device_name_to_device("ephemeral0"), - "/dev/sdb1") + "/dev/sdb") assert 'disk_setup' in cfg assert 'fs_setup' in cfg self.assertIsInstance(cfg['disk_setup'], dict) -- cgit v1.2.1 From 3f96e2809c29af300ffa78c9cbee401904c8defe Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 16:44:41 -0400 Subject: fix one bug --- cloudinit/config/cc_disk_setup.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index e64176ba..ebff6e62 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -650,13 +650,14 @@ def mkfs(fs_cfg): # Make sure the device is defined if not device: - LOG.critical("Device is not known: %s" % fs_cfg) + LOG.warn("Device is not known: %s", device) return # Check that we can create the FS - if not label or not fs_type: - LOG.debug("Command to create filesystem %s is bad. Skipping." % \ - label) + if not (fs_type or fs_cmd): + raise Exception("No way to create filesystem '%s'. fs_type or fs_cmd " + "must be set.", label) + # Create the commands if fs_cmd: -- cgit v1.2.1 From fa099e1a375fcefdc1cff7ac1c096ace4022ce1f Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 16:53:45 -0400 Subject: change LOG.debug('format' % var) to ('format', var) --- cloudinit/config/cc_disk_setup.py | 56 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index ebff6e62..74965899 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -238,8 +238,8 @@ def find_device_node(device, fs_type=None, label=None, valid_targets=None, for key, value in value_splitter(part): d[key.lower()] = value - if d['fstype'] == fs_type and \ - ((label_match and d['label'] == label) or not label_match): + if (d['fstype'] == fs_type and + ((label_match and d['label'] == label) or not label_match)): # If we find a matching device, we return that return ('/dev/%s' % d['name'], True) @@ -416,8 +416,8 @@ def get_partition_mbr_layout(size, layout): # Create a single partition return "0," - if (len(layout) == 0 and isinstance(layout, list)) or \ - not isinstance(layout, list): + if ((len(layout) == 0 and isinstance(layout, list)) or + not isinstance(layout, list)): raise Exception("Partition layout is invalid") last_part_num = len(layout) @@ -433,8 +433,7 @@ def get_partition_mbr_layout(size, layout): if isinstance(part, list): if len(part) != 2: - raise Exception("Partition was incorrectly defined: %s" % \ - part) + raise Exception("Partition was incorrectly defined: %s" % part) percent, part_type = part part_size = int((float(size) * (float(percent) / 100)) / 1024) @@ -535,9 +534,9 @@ def mkpart(device, definition): return # Device is not to be partitioned # This prevents you from overwriting the device - LOG.debug("Checking if device %s is a valid device" % device) + LOG.debug("Checking if device %s is a valid device", device) if not is_device_valid(device): - raise Exception("Device %s is not a disk device!" % device) + raise Exception("Device %s is not a disk device!", device) LOG.debug("Checking if device layout matches") if check_partition_layout(table_type, device, layout): @@ -556,10 +555,10 @@ def mkpart(device, definition): part_definition = get_partition_layout(table_type, device_size, layout) LOG.debug(" Layout is: %s" % part_definition) - LOG.debug("Creating partition table on %s" % device) + LOG.debug("Creating partition table on %s", device) exec_mkpart(table_type, device, part_definition) - LOG.debug("Partition table created for %s" % device) + LOG.debug("Partition table created for %s", device) def mkfs(fs_cfg): @@ -592,36 +591,36 @@ def mkfs(fs_cfg): overwrite = fs_cfg.get('overwrite', False) # This allows you to define the default ephemeral or swap - LOG.debug("Checking %s against default devices" % device) + LOG.debug("Checking %s against default devices", device) if not partition or partition.isdigit(): # Handle manual definition of partition if partition.isdigit(): device = "%s%s" % (device, partition) - LOG.debug("Manual request of partition %s for %s" % ( - partition, device)) + LOG.debug("Manual request of partition %s for %s", + partition, device) # Check to see if the fs already exists - LOG.debug("Checking device %s" % device) + LOG.debug("Checking device %s", device) check_label, check_fstype, _ = check_fs(device) - LOG.debug("Device %s has %s %s" % (device, check_label, check_fstype)) + LOG.debug("Device %s has %s %s", device, check_label, check_fstype) if check_label == label and check_fstype == fs_type: - LOG.debug("Existing file system found at %s" % device) + LOG.debug("Existing file system found at %s", device) if not overwrite: - LOG.warn("Device %s has required file system" % device) + LOG.debug("Device %s has required file system", device) return else: - LOG.warn("Destroying filesystem on %s" % device) + LOG.warn("Destroying filesystem on %s", device) else: - LOG.debug("Device %s is cleared for formating" % device) + LOG.debug("Device %s is cleared for formating", device) elif partition and str(partition).lower() in ('auto', 'any'): # For auto devices, we match if the filesystem does exist odevice = device - LOG.debug("Identifying device to create %s filesytem on" % label) + LOG.debug("Identifying device to create %s filesytem on", label) # any mean pick the first match on the device with matching fs_type label_match = True @@ -630,23 +629,22 @@ def mkfs(fs_cfg): device, reuse = find_device_node(device, fs_type=fs_type, label=label, label_match=label_match) - LOG.debug("Automatic device for %s identified as %s" % ( - odevice, device)) + LOG.debug("Automatic device for %s identified as %s", odevice, device) if reuse: LOG.debug("Found filesystem match, skipping formating.") return if not device: - LOG.debug("No device aviable that matches request.") - LOG.debug("Skipping fs creation for %s" % fs_cfg) + LOG.debug("No device aviable that matches request. " + "Skipping fs creation for %s", fs_cfg) return else: LOG.debug("Error in device identification handling.") return - LOG.debug("File system %s will be created on %s" % (label, device)) + LOG.debug("File system %s will be created on %s", label, device) # Make sure the device is defined if not device: @@ -658,7 +656,6 @@ def mkfs(fs_cfg): raise Exception("No way to create filesystem '%s'. fs_type or fs_cmd " "must be set.", label) - # Create the commands if fs_cmd: fs_cmd = fs_cfg['cmd'] % {'label': label, @@ -672,7 +669,8 @@ def mkfs(fs_cfg): mkfs_cmd = util.which("mk%s" % fs_type) if not mkfs_cmd: - LOG.critical("Unable to locate command to create filesystem.") + LOG.warn("Cannot create fstype '%s'. No mkfs.%s command", fs_type, + fs_type) return fs_cmd = [mkfs_cmd, device] @@ -684,8 +682,8 @@ def mkfs(fs_cfg): if fs_opts: fs_cmd.extend(fs_opts) - LOG.debug("Creating file system %s on %s" % (label, device)) - LOG.debug(" Using cmd: %s" % "".join(fs_cmd)) + LOG.debug("Creating file system %s on %s", label, device) + LOG.debug(" Using cmd: %s", "".join(fs_cmd)) try: util.subp(fs_cmd) except Exception as e: -- cgit v1.2.1 From 1d9e80555db86777264703e85624f054046389fe Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 17:08:40 -0400 Subject: find_device_node: treat label=None as label="" Since for a string there is no difference, we're just checking for this here. --- cloudinit/config/cc_disk_setup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index 74965899..d274f81a 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -214,6 +214,10 @@ def find_device_node(device, fs_type=None, label=None, valid_targets=None, Note: This works with GPT partition tables! """ + # label of None is same as no label + if label is None: + label = "" + if not valid_targets: valid_targets = ['disk', 'part'] -- cgit v1.2.1 From 9c5a96a4d86081041bc7cce831cfe0e502c42ecd Mon Sep 17 00:00:00 2001 From: Ben Howard Date: Fri, 27 Sep 2013 16:23:01 -0600 Subject: Updated the documentation on disk formating --- doc/examples/cloud-config-disk-setup.txt | 44 +++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/doc/examples/cloud-config-disk-setup.txt b/doc/examples/cloud-config-disk-setup.txt index 19698492..d3129058 100644 --- a/doc/examples/cloud-config-disk-setup.txt +++ b/doc/examples/cloud-config-disk-setup.txt @@ -188,13 +188,43 @@ Where: of the ephemeral storage layer. : The valid options are: - "auto": auto is a special in the sense that you are telling cloud-init - not to care whether there is a partition or not. Auto will put the - first partition that does not contain a file system already. In - the absence of a partition table, it will put it directly on the - disk. - - "none": Put the partition directly on the disk. + "auto|any": tell cloud-init not to care whether there is a partition + or not. Auto will use the first partition that does not contain a + file system already. In the absence of a partition table, it will + put it directly on the disk. + + "auto": If a file system that matches the specification in terms of + label, type and device, then cloud-init will skip the creation of + the file system. + + "any": If a file system that matches the file system type and device, + then cloud-init will skip the creation of the file system. + + Devices are selected based on first-detected, starting with partitions + and then the raw disk. Consider the following: + NAME FSTYPE LABEL + xvdb + ├─xvdb1 ext4 + ├─xvdb2 + ├─xvdb3 btrfs test + └─xvdb4 ext4 test + + If you ask for 'auto', label of 'test, and file system of 'ext4' + then cloud-init will select the 2nd partition, even though there + is a partition match at the 4th partition. + + If you ask for 'any' and a label of 'test', then cloud-init will + select the 1st partition. + + If you ask for 'auto' and don't define label, then cloud-init will + select the 1st partition. + + In general, if you have a specific partition configuration in mind, + you should define either the device or the partition number. 'auto' + and 'any' are specifically intended for formating ephemeral storage or + for simple schemes. + + "none": Put the file system directly on the device. : where NUM is the actual partition number. -- cgit v1.2.1 From ba7cc2b9fc5ff12b7eb613d1f1516fa35ec5ec03 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 27 Sep 2013 19:35:20 -0400 Subject: remove non-ascii chars --- doc/examples/cloud-config-disk-setup.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/examples/cloud-config-disk-setup.txt b/doc/examples/cloud-config-disk-setup.txt index d3129058..3fc47699 100644 --- a/doc/examples/cloud-config-disk-setup.txt +++ b/doc/examples/cloud-config-disk-setup.txt @@ -204,10 +204,10 @@ Where: and then the raw disk. Consider the following: NAME FSTYPE LABEL xvdb - ├─xvdb1 ext4 - ├─xvdb2 - ├─xvdb3 btrfs test - └─xvdb4 ext4 test + |-xvdb1 ext4 + |-xvdb2 + |-xvdb3 btrfs test + \-xvdb4 ext4 test If you ask for 'auto', label of 'test, and file system of 'ext4' then cloud-init will select the 2nd partition, even though there -- cgit v1.2.1