diff -Nru ubuntu-image-1.5+18.04ubuntu1/debian/changelog ubuntu-image-1.6+18.04ubuntu1/debian/changelog --- ubuntu-image-1.5+18.04ubuntu1/debian/changelog 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/debian/changelog 2018-12-14 16:08:09.000000000 +0000 @@ -1,3 +1,13 @@ +ubuntu-image (1.6+18.04ubuntu1) bionic; urgency=medium + + * Do not copy-over /etc/cloud to the rootfs if it's empty. This can cause + base snaps that define the writable-path as 'persistent' and 'transition' + to not be able to provide default configuration. (LP:1808554) + * Fix --with-proposed handling to properly pass PROPOSED to live-build. + * SRU tracking number LP: #1808564 + + -- Ɓukasz 'sil2100' Zemczak Fri, 14 Dec 2018 17:08:09 +0100 + ubuntu-image (1.5+18.04ubuntu1) bionic; urgency=medium [ Alfonso Sanchez-Beato (email Canonical) ] diff -Nru ubuntu-image-1.5+18.04ubuntu1/snapcraft.yaml ubuntu-image-1.6+18.04ubuntu1/snapcraft.yaml --- ubuntu-image-1.5+18.04ubuntu1/snapcraft.yaml 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/snapcraft.yaml 2018-12-14 16:08:09.000000000 +0000 @@ -2,7 +2,7 @@ summary: Create Ubuntu images description: | Use this tool to create Ubuntu images. -version: 1.5+snap1 +version: 1.6+snap1 grade: stable confinement: classic diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/assertion_builder.py ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/assertion_builder.py --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/assertion_builder.py 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/assertion_builder.py 2018-12-14 16:08:09.000000000 +0000 @@ -39,6 +39,13 @@ if subdir != 'boot': shutil.move(os.path.join(src, subdir), os.path.join(dst, subdir)) + etc_cloud = os.path.join(dst, 'etc', 'cloud') + if os.path.isdir(etc_cloud) and not os.listdir(etc_cloud): + # The snap --prepare-image command creates /etc/cloud even if + # it's empty. We don't want to copy it over into the final rootfs + # in that case as it can cause issues when base snaps want to ship + # default configuration there. + os.rmdir(etc_cloud) if self.cloud_init is not None: # LP: #1633232 - Only write out meta-data when the --cloud-init # parameter is given. diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/classic_builder.py ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/classic_builder.py --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/classic_builder.py 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/classic_builder.py 2018-12-14 16:08:09.000000000 +0000 @@ -60,8 +60,8 @@ env['SUBPROJECT'] = self.args.subproject if self.args.subarch is not None: env['SUBARCH'] = self.args.subarch - if self.args.with_proposed is not None: - env['PROPOSED'] = self.args.with_proposed + if self.args.with_proposed: + env['PROPOSED'] = '1' if self.args.extra_ppas is not None: env['EXTRA_PPAS'] = ' '.join(self.args.extra_ppas) # Only generate a single rootfs tree for classic images. diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/tests/test_builder.py ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/tests/test_builder.py --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/tests/test_builder.py 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/tests/test_builder.py 2018-12-14 16:08:09.000000000 +0000 @@ -245,6 +245,74 @@ boot = os.path.join(state.rootfs, 'boot') self.assertFalse(os.path.exists(boot)) + def test_populate_rootfs_contents_remove_empty_etc_cloud(self): + with ExitStack() as resources: + args = SimpleNamespace( + channel='edge', + cloud_init=None, + extra_snaps=None, + model_assertion=self.model_assertion, + output=None, + output_dir=None, + workdir=None, + hooks_directory=[], + ) + state = resources.enter_context(XXXModelAssertionBuilder(args)) + # Fake some state expected by the method under test. + state.unpackdir = resources.enter_context(TemporaryDirectory()) + image_dir = os.path.join(state.unpackdir, 'image') + os.makedirs(os.path.join(image_dir, 'etc', 'cloud')) + with open(os.path.join(image_dir, 'etc', + 'sentinel.dat'), 'wb') as fp: + fp.write(b'x' * 25) + state.rootfs = resources.enter_context(TemporaryDirectory()) + system_data = os.path.join(state.rootfs, 'system-data') + os.makedirs(system_data) + # Jump right to the state method we're trying to test. + state._next.pop() + state._next.append(state.populate_rootfs_contents) + next(state) + # Make sure the empty /etc/cloud has not been copied, but all other + # etc contents did. + etc_cloud = os.path.join( + state.rootfs, 'system-data', 'etc', 'cloud') + self.assertFalse(os.path.exists(etc_cloud)) + etc_sentinel = os.path.join( + state.rootfs, 'system-data', 'etc', 'sentinel.dat') + self.assertTrue(os.path.exists(etc_sentinel)) + + def test_populate_rootfs_contents_keep_nonempty_etc_cloud(self): + with ExitStack() as resources: + args = SimpleNamespace( + channel='edge', + cloud_init=None, + extra_snaps=None, + model_assertion=self.model_assertion, + output=None, + output_dir=None, + workdir=None, + hooks_directory=[], + ) + state = resources.enter_context(XXXModelAssertionBuilder(args)) + # Fake some state expected by the method under test. + state.unpackdir = resources.enter_context(TemporaryDirectory()) + image_dir = os.path.join(state.unpackdir, 'image') + src_cloud = os.path.join(image_dir, 'etc', 'cloud') + os.makedirs(src_cloud) + with open(os.path.join(src_cloud, 'sentinel.dat'), 'wb') as fp: + fp.write(b'x' * 25) + state.rootfs = resources.enter_context(TemporaryDirectory()) + system_data = os.path.join(state.rootfs, 'system-data') + os.makedirs(system_data) + # Jump right to the state method we're trying to test. + state._next.pop() + state._next.append(state.populate_rootfs_contents) + next(state) + # Make sure the non-empty /etc/cloud directory got carried over. + etc_sentinel = os.path.join( + state.rootfs, 'system-data', 'etc', 'cloud', 'sentinel.dat') + self.assertTrue(os.path.exists(etc_sentinel)) + def test_bootloader_options_uboot(self): # This test provides coverage for populate_bootfs_contents() when the # uboot bootloader is used. The live gadget snap (only tested when we diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/tests/test_classic_builder.py ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/tests/test_classic_builder.py --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/tests/test_classic_builder.py 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/tests/test_classic_builder.py 2018-12-14 16:08:09.000000000 +0000 @@ -921,7 +921,7 @@ } for arg, env in argstoenv.items(): kwargs = dict(kwargs_skel) - kwargs[arg] = 'test' + kwargs[arg] = 'test' if arg != 'with_proposed' else True args = SimpleNamespace(**kwargs) # Jump right to the method under test. state = resources.enter_context(XXXClassicBuilder(args)) @@ -933,7 +933,9 @@ self.assertEqual(len(mock.call_args_list), 1) posargs, kwargs = mock.call_args_list[0] self.assertIn(env, posargs[1]) - self.assertEqual(posargs[1][env], 'test') + self.assertEqual( + posargs[1][env], + 'test' if arg != 'with_proposed' else '1') # The extra_ppas argument is actually a list, so it needs a # separate test-case. outputtoinput = { diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/version.txt ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/version.txt --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image/version.txt 2018-10-02 15:07:58.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image/version.txt 2018-12-14 16:08:09.000000000 +0000 @@ -1 +1 @@ -1.5+18.04ubuntu1 +1.6+18.04ubuntu1 diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/dependency_links.txt ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/dependency_links.txt --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/dependency_links.txt 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/dependency_links.txt 2018-12-14 16:00:15.000000000 +0000 @@ -0,0 +1 @@ + diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/entry_points.txt ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/entry_points.txt --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/entry_points.txt 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/entry_points.txt 2018-12-14 16:00:15.000000000 +0000 @@ -0,0 +1,3 @@ +[flake8.extension] +B4 = ubuntu_image.testing.flake8:ImportOrder + diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/PKG-INFO ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/PKG-INFO --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/PKG-INFO 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/PKG-INFO 2018-12-14 16:00:15.000000000 +0000 @@ -0,0 +1,21 @@ +Metadata-Version: 1.1 +Name: ubuntu-image +Version: 1.5+19.04ubuntu3 +Summary: Construct snappy images out of a model assertion +Home-page: https://github.com/CanonicalLtd/ubuntu-image +Author: UNKNOWN +Author-email: snapcraft@lists.ubuntu.com +License: GPLv3 +Description: UNKNOWN +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Topic :: Software Development :: Build Tools +Classifier: Topic :: System :: Software Distribution diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/requires.txt ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/requires.txt --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/requires.txt 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/requires.txt 2018-12-14 16:00:15.000000000 +0000 @@ -0,0 +1,3 @@ +attrs +pyyaml +voluptuous diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/SOURCES.txt ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/SOURCES.txt --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/SOURCES.txt 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/SOURCES.txt 2018-12-14 16:00:15.000000000 +0000 @@ -0,0 +1,49 @@ +.requirements.txt +MANIFEST.in +README.rst +devel-coverage.ini +release.py +setup.py +tox.ini +ubuntu-image +ubuntu-image.rst +xenial-coverage.ini +demo/boot/README.rst +demo/multivol/README.rst +demo/multivol/gadget/hello.txt +demo/multivol/gadget/notes.txt +demo/multivol/gadget/world.txt +docs/notes.rst +ubuntu_image/__init__.py +ubuntu_image/__main__.py +ubuntu_image/assertion_builder.py +ubuntu_image/classic_builder.py +ubuntu_image/common_builder.py +ubuntu_image/helpers.py +ubuntu_image/hooks.py +ubuntu_image/i18n.py +ubuntu_image/image.py +ubuntu_image/parser.py +ubuntu_image/state.py +ubuntu_image/version.txt +ubuntu_image.egg-info/PKG-INFO +ubuntu_image.egg-info/SOURCES.txt +ubuntu_image.egg-info/dependency_links.txt +ubuntu_image.egg-info/entry_points.txt +ubuntu_image.egg-info/requires.txt +ubuntu_image.egg-info/top_level.txt +ubuntu_image/testing/__init__.py +ubuntu_image/testing/flake8.py +ubuntu_image/testing/helpers.py +ubuntu_image/testing/nose.py +ubuntu_image/tests/__init__.py +ubuntu_image/tests/test_builder.py +ubuntu_image/tests/test_classic_builder.py +ubuntu_image/tests/test_helpers.py +ubuntu_image/tests/test_hooks.py +ubuntu_image/tests/test_image.py +ubuntu_image/tests/test_main.py +ubuntu_image/tests/test_parser.py +ubuntu_image/tests/test_state.py +ubuntu_image/tests/test_stub.py +ubuntu_image/tests/data/__init__.py \ No newline at end of file diff -Nru ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/top_level.txt ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/top_level.txt --- ubuntu-image-1.5+18.04ubuntu1/ubuntu_image.egg-info/top_level.txt 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-image-1.6+18.04ubuntu1/ubuntu_image.egg-info/top_level.txt 2018-12-14 16:00:15.000000000 +0000 @@ -0,0 +1 @@ +ubuntu_image