Merge lp:~bjornt/landscape-client/apt-upgrade-all-packages into lp:~landscape/landscape-client/trunk

Proposed by Björn Tillenius
Status: Merged
Approved by: Alberto Donato
Approved revision: 435
Merged at revision: 432
Proposed branch: lp:~bjornt/landscape-client/apt-upgrade-all-packages
Merge into: lp:~landscape/landscape-client/trunk
Diff against target: 273 lines (+81/-39)
3 files modified
landscape/package/changer.py (+1/-3)
landscape/package/facade.py (+14/-15)
landscape/package/tests/test_facade.py (+66/-21)
To merge this branch: bzr merge lp:~bjornt/landscape-client/apt-upgrade-all-packages
Reviewer Review Type Date Requested Status
Alberto Donato (community) Approve
Free Ekanayaka (community) Approve
Review via email: mp+88688@code.launchpad.net

Description of the change

Ask Apt to upgrade the whole system, rather than marking each package
for upgrade when the server requests a general system upgrade. This
makes the system upgrade holds for dependencies.

I'm making a dist-upgrade, because the existing tests require it. It's
easy to change, if we want a normal apt-get upgrade.

To post a comment you must log in.
Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

I believe we don't want dist-upgrade, as it can have quite disruptive effects like removing packages, or replacing postgres-8 with postgres-9 (in principle).

Also I didn't look at the code very in depth, but will this have really the same behavior as before? The important thing is to go back to the server if there are package changes that haven't been explicitly requested by the server (with install/remove messages) and that are not allowed by the auto-apply policy in effect.

review: Needs Information
435. By Björn Tillenius

Merge trunk, resolve conflicts.

Revision history for this message
Björn Tillenius (bjornt) wrote :

We can change it to use upgrade instead of dist-upgrade. However, I do think that the current Smart behavior is like dist-upgrade. I will do some testing to confirm, it's easy to change in another branch.

And yes, it will tell the changes to the server. cache.upgrade() doesn't upgrade the packages. You have to call cache.commit() for the changes to take place. But since the changes aren't in _package_installs/_package_removals, a DependencyError is raised before the commit.

Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

Thanks for explaining Bjorn, there's even a test raising DependencyError indeed.

So I guess the current Smart behavior is like dist-ugprade because we use PolicyUpgrade? I don't know the details of that, it might indeed be similar to dist-upgrade. However, dist-upgrade is really meant for cross-release upgrades ("distribution upgrades") not for regular updates, and we have separate machinery for release upgrades, so I'd really advocate for a plain apt-get upgrade.

Looks great, +1!

review: Approve
Revision history for this message
Alberto Donato (ack) wrote :

looks good! +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'landscape/package/changer.py'
--- landscape/package/changer.py 2011-12-13 10:29:04 +0000
+++ landscape/package/changer.py 2012-01-16 15:12:26 +0000
@@ -169,9 +169,7 @@
169 self._facade.reset_marks()169 self._facade.reset_marks()
170170
171 if upgrade:171 if upgrade:
172 for package in self._facade.get_packages():172 self._facade.mark_global_upgrade()
173 if self._facade.is_package_installed(package):
174 self._facade.mark_upgrade(package)
175173
176 for ids, mark_func in [(install, self._facade.mark_install),174 for ids, mark_func in [(install, self._facade.mark_install),
177 (remove, self._facade.mark_remove)]:175 (remove, self._facade.mark_remove)]:
178176
=== modified file 'landscape/package/facade.py'
--- landscape/package/facade.py 2012-01-13 09:37:40 +0000
+++ landscape/package/facade.py 2012-01-16 15:12:26 +0000
@@ -90,7 +90,7 @@
90 self._pkg2hash = {}90 self._pkg2hash = {}
91 self._hash2pkg = {}91 self._hash2pkg = {}
92 self._package_installs = []92 self._package_installs = []
93 self._package_upgrades = []93 self._global_upgrade = False
94 self._package_removals = []94 self._package_removals = []
95 self.refetch_package_index = False95 self.refetch_package_index = False
9696
@@ -363,7 +363,7 @@
363 held_package_names = set()363 held_package_names = set()
364 package_changes = self._package_installs[:]364 package_changes = self._package_installs[:]
365 package_changes.extend(self._package_removals)365 package_changes.extend(self._package_removals)
366 if not package_changes and not self._package_upgrades:366 if not package_changes and not self._global_upgrade:
367 return None367 return None
368 fixer = apt_pkg.ProblemResolver(self._cache._depcache)368 fixer = apt_pkg.ProblemResolver(self._cache._depcache)
369 for version in self._package_installs:369 for version in self._package_installs:
@@ -377,14 +377,8 @@
377 # been True.377 # been True.
378 fixer.clear(version.package._pkg)378 fixer.clear(version.package._pkg)
379 fixer.protect(version.package._pkg)379 fixer.protect(version.package._pkg)
380 for version in self._package_upgrades:380 if self._global_upgrade:
381 if self._is_package_held(version.package):381 self._cache.upgrade(dist_upgrade=True)
382 continue
383 version.package.mark_install(
384 auto_fix=False,
385 from_user=not version.package.is_auto_installed)
386 fixer.clear(version.package._pkg)
387 fixer.protect(version.package._pkg)
388 for version in self._package_removals:382 for version in self._package_removals:
389 if self._is_package_held(version.package):383 if self._is_package_held(version.package):
390 held_package_names.add(version.package.name)384 held_package_names.add(version.package.name)
@@ -448,17 +442,16 @@
448 def reset_marks(self):442 def reset_marks(self):
449 """Clear the pending package operations."""443 """Clear the pending package operations."""
450 del self._package_installs[:]444 del self._package_installs[:]
451 del self._package_upgrades[:]
452 del self._package_removals[:]445 del self._package_removals[:]
446 self._global_upgrade = False
453447
454 def mark_install(self, version):448 def mark_install(self, version):
455 """Mark the package for installation."""449 """Mark the package for installation."""
456 self._package_installs.append(version)450 self._package_installs.append(version)
457451
458 def mark_upgrade(self, version):452 def mark_global_upgrade(self):
459 """Mark the package for upgrade."""453 """Upgrade all installed packages."""
460 if version.package.candidate != version:454 self._global_upgrade = True
461 self._package_upgrades.append(version)
462455
463 def mark_remove(self, version):456 def mark_remove(self, version):
464 """Mark the package for removal."""457 """Mark the package for removal."""
@@ -626,6 +619,12 @@
626 def mark_upgrade(self, pkg):619 def mark_upgrade(self, pkg):
627 self._marks[pkg] = UPGRADE620 self._marks[pkg] = UPGRADE
628621
622 def mark_global_upgrade(self):
623 """Upgrade all installed packages."""
624 for package in self.get_packages():
625 if self.is_package_installed(package):
626 self.mark_upgrade(package)
627
629 def reset_marks(self):628 def reset_marks(self):
630 self._marks.clear()629 self._marks.clear()
631630
632631
=== modified file 'landscape/package/tests/test_facade.py'
--- landscape/package/tests/test_facade.py 2012-01-16 14:12:40 +0000
+++ landscape/package/tests/test_facade.py 2012-01-16 15:12:26 +0000
@@ -905,14 +905,13 @@
905 self.facade.reload_channels()905 self.facade.reload_channels()
906 foo = self.facade.get_packages_by_name("foo")[0]906 foo = self.facade.get_packages_by_name("foo")[0]
907 self.facade.mark_install(foo)907 self.facade.mark_install(foo)
908 bar_10 = sorted(self.facade.get_packages_by_name("bar"))[0]908 self.facade.mark_global_upgrade()
909 self.facade.mark_upgrade(bar_10)
910 [baz] = self.facade.get_packages_by_name("baz")909 [baz] = self.facade.get_packages_by_name("baz")
911 self.facade.mark_remove(baz)910 self.facade.mark_remove(baz)
912 self.facade.reset_marks()911 self.facade.reset_marks()
913 self.assertEqual(self.facade._package_installs, [])912 self.assertEqual(self.facade._package_installs, [])
914 self.assertEqual(self.facade._package_upgrades, [])
915 self.assertEqual(self.facade._package_removals, [])913 self.assertEqual(self.facade._package_removals, [])
914 self.assertFalse(self.facade._global_upgrade)
916 self.assertEqual(self.facade.perform_changes(), None)915 self.assertEqual(self.facade.perform_changes(), None)
917916
918 def test_wb_mark_install_adds_to_list(self):917 def test_wb_mark_install_adds_to_list(self):
@@ -930,10 +929,10 @@
930 install = self.facade._package_installs[0]929 install = self.facade._package_installs[0]
931 self.assertEqual("minimal", install.package.name)930 self.assertEqual("minimal", install.package.name)
932931
933 def test_wb_mark_upgrade_adds_to_list(self):932 def test_wb_mark_global_upgrade_sets_variable(self):
934 """933 """
935 C{mark_upgrade} adds the package to the list of packages to be934 C{mark_global_upgrade} sets a variable, so that the actual
936 upgraded.935 upgrade happens in C{perform_changes}.
937 """936 """
938 deb_dir = self.makeDir()937 deb_dir = self.makeDir()
939 self._add_system_package("foo", version="1.0")938 self._add_system_package("foo", version="1.0")
@@ -941,8 +940,9 @@
941 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")940 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")
942 self.facade.reload_channels()941 self.facade.reload_channels()
943 foo_10 = sorted(self.facade.get_packages_by_name("foo"))[0]942 foo_10 = sorted(self.facade.get_packages_by_name("foo"))[0]
944 self.facade.mark_upgrade(foo_10)943 self.facade.mark_global_upgrade()
945 self.assertEqual([foo_10], self.facade._package_upgrades)944 self.assertTrue(self.facade._global_upgrade)
945 self.assertEqual(foo_10, foo_10.package.installed)
946946
947 def test_wb_mark_remove_adds_to_list(self):947 def test_wb_mark_remove_adds_to_list(self):
948 """948 """
@@ -1062,7 +1062,27 @@
1062 ("single-arch", "2.0")],1062 ("single-arch", "2.0")],
1063 sorted(changes))1063 sorted(changes))
10641064
1065 def test_mark_upgrade_candidate_version(self):1065 def test_mark_global_upgrade(self):
1066 """
1067 C{mark_global_upgrade} upgrades all packages that can be
1068 upgraded. It makes C{perform_changes} raise a C{DependencyError}
1069 with the required changes, so that the user can review the
1070 changes and approve them.
1071 """
1072 deb_dir = self.makeDir()
1073 self._add_system_package("foo", version="1.0")
1074 self._add_system_package("bar")
1075 self._add_package_to_deb_dir(deb_dir, "foo", version="2.0")
1076 self._add_package_to_deb_dir(deb_dir, "baz")
1077 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")
1078 self.facade.reload_channels()
1079 foo2 = sorted(self.facade.get_packages_by_name("foo"))[1]
1080 self.facade.mark_global_upgrade()
1081 exception = self.assertRaises(
1082 DependencyError, self.facade.perform_changes)
1083 self.assertEqual([foo2], exception.packages)
1084
1085 def test_mark_global_upgrade_candidate_version(self):
1066 """1086 """
1067 If more than one version is available, the package will be1087 If more than one version is available, the package will be
1068 upgraded to the candidate version. Since the user didn't request1088 upgraded to the candidate version. Since the user didn't request
@@ -1077,16 +1097,16 @@
1077 self.facade.reload_channels()1097 self.facade.reload_channels()
1078 foo1, foo2, foo3 = sorted(self.facade.get_packages_by_name("foo"))1098 foo1, foo2, foo3 = sorted(self.facade.get_packages_by_name("foo"))
1079 self.assertEqual(foo3, foo1.package.candidate)1099 self.assertEqual(foo3, foo1.package.candidate)
1080 self.facade.mark_upgrade(foo1)1100 self.facade.mark_global_upgrade()
1081 exception = self.assertRaises(1101 exception = self.assertRaises(
1082 DependencyError, self.facade.perform_changes)1102 DependencyError, self.facade.perform_changes)
1083 self.assertEqual([foo3], exception.packages)1103 self.assertEqual([foo3], exception.packages)
10841104
1085 def test_mark_upgrade_no_upgrade(self):1105 def test_mark_global_upgrade_no_upgrade(self):
1086 """1106 """
1087 If the candidate version of a package is already installed,1107 If the candidate version of a package is already installed,
1088 mark_upgrade() won't request an upgrade to be made. I.e.1108 C{mark_global_upgrade()} won't request an upgrade to be made. I.e.
1089 perform_changes() won't do anything.1109 C{perform_changes()} won't do anything.
1090 """1110 """
1091 deb_dir = self.makeDir()1111 deb_dir = self.makeDir()
1092 self._add_system_package("foo", version="3.0")1112 self._add_system_package("foo", version="3.0")
@@ -1096,10 +1116,10 @@
1096 self.facade.reload_channels()1116 self.facade.reload_channels()
1097 foo3 = sorted(self.facade.get_packages_by_name("foo"))[-1]1117 foo3 = sorted(self.facade.get_packages_by_name("foo"))[-1]
1098 self.assertEqual(foo3, foo3.package.candidate)1118 self.assertEqual(foo3, foo3.package.candidate)
1099 self.facade.mark_upgrade(foo3)1119 self.facade.mark_global_upgrade()
1100 self.assertEqual(None, self.facade.perform_changes())1120 self.assertEqual(None, self.facade.perform_changes())
11011121
1102 def test_mark_upgrade_preserves_auto(self):1122 def test_mark_global_upgrade_preserves_auto(self):
1103 """1123 """
1104 Upgrading a package will retain its auto-install status.1124 Upgrading a package will retain its auto-install status.
1105 """1125 """
@@ -1114,8 +1134,7 @@
1114 noauto1, noauto2 = sorted(self.facade.get_packages_by_name("noauto"))1134 noauto1, noauto2 = sorted(self.facade.get_packages_by_name("noauto"))
1115 auto1.package.mark_auto(True)1135 auto1.package.mark_auto(True)
1116 noauto1.package.mark_auto(False)1136 noauto1.package.mark_auto(False)
1117 self.facade.mark_upgrade(auto1)1137 self.facade.mark_global_upgrade()
1118 self.facade.mark_upgrade(noauto1)
1119 self.assertRaises(DependencyError, self.facade.perform_changes)1138 self.assertRaises(DependencyError, self.facade.perform_changes)
1120 self.assertTrue(auto2.package.is_auto_installed)1139 self.assertTrue(auto2.package.is_auto_installed)
1121 self.assertFalse(noauto2.package.is_auto_installed)1140 self.assertFalse(noauto2.package.is_auto_installed)
@@ -1211,7 +1230,7 @@
1211 error = self.assertRaises(DependencyError, self.facade.perform_changes)1230 error = self.assertRaises(DependencyError, self.facade.perform_changes)
1212 self.assertEqual([bar], error.packages)1231 self.assertEqual([bar], error.packages)
12131232
1214 def test_mark_upgrade_dependency_error(self):1233 def test_mark_global_upgrade_dependency_error(self):
1215 """1234 """
1216 If a package is marked for upgrade, a DependencyError will be1235 If a package is marked for upgrade, a DependencyError will be
1217 raised, indicating which version of the package will be1236 raised, indicating which version of the package will be
@@ -1226,7 +1245,7 @@
1226 self.facade.reload_channels()1245 self.facade.reload_channels()
1227 foo_10, foo_15 = sorted(self.facade.get_packages_by_name("foo"))1246 foo_10, foo_15 = sorted(self.facade.get_packages_by_name("foo"))
1228 [bar] = self.facade.get_packages_by_name("bar")1247 [bar] = self.facade.get_packages_by_name("bar")
1229 self.facade.mark_upgrade(foo_10)1248 self.facade.mark_global_upgrade()
1230 error = self.assertRaises(DependencyError, self.facade.perform_changes)1249 error = self.assertRaises(DependencyError, self.facade.perform_changes)
1231 self.assertEqual(1250 self.assertEqual(
1232 sorted([bar, foo_15], key=self.version_sortkey),1251 sorted([bar, foo_15], key=self.version_sortkey),
@@ -1266,7 +1285,7 @@
1266 "Can't perform the changes, since the following packages" +1285 "Can't perform the changes, since the following packages" +
1267 " are held: bar, foo", error.args[0])1286 " are held: bar, foo", error.args[0])
12681287
1269 def test_mark_upgrade_held_packages(self):1288 def test_mark_global_upgrade_held_packages(self):
1270 """1289 """
1271 If a package that is on hold is marked for upgrade,1290 If a package that is on hold is marked for upgrade,
1272 C{perform_changes} won't request to install a newer version of1291 C{perform_changes} won't request to install a newer version of
@@ -1280,10 +1299,36 @@
1280 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")1299 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")
1281 self.facade.reload_channels()1300 self.facade.reload_channels()
1282 [foo_10, foo_15] = sorted(self.facade.get_packages_by_name("foo"))1301 [foo_10, foo_15] = sorted(self.facade.get_packages_by_name("foo"))
1283 self.facade.mark_upgrade(foo_10)1302 self.facade.mark_global_upgrade()
1284 self.assertEqual(None, self.facade.perform_changes())1303 self.assertEqual(None, self.facade.perform_changes())
1285 self.assertEqual(foo_10, foo_15.package.installed)1304 self.assertEqual(foo_10, foo_15.package.installed)
12861305
1306 def test_mark_global_upgrade_held_dependencies(self):
1307 """
1308 If a package that can be upgraded, but that package depends on a
1309 newer version of a held package, the first package won't be
1310 marked as requiring upgrade.
1311 """
1312 self._add_system_package(
1313 "foo", version="1.0",
1314 control_fields={"Status": "hold ok installed"})
1315 self._add_system_package(
1316 "bar", version="1.0",
1317 control_fields={"Depends": "foo"})
1318 deb_dir = self.makeDir()
1319 self._add_package_to_deb_dir(deb_dir, "foo", version="2.0")
1320 self._add_package_to_deb_dir(
1321 deb_dir, "bar", version="2.0",
1322 control_fields={"Depends": "foo (>> 1.0)"})
1323 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")
1324 self.facade.reload_channels()
1325 [foo_1, foo_2] = sorted(self.facade.get_packages_by_name("foo"))
1326 [bar_1, bar_2] = sorted(self.facade.get_packages_by_name("bar"))
1327 self.facade.mark_global_upgrade()
1328 self.assertEqual(None, self.facade.perform_changes())
1329 self.assertEqual(foo_1, foo_2.package.installed)
1330 self.assertEqual(bar_1, bar_2.package.installed)
1331
1287 def test_get_locked_packages_simple(self):1332 def test_get_locked_packages_simple(self):
1288 """1333 """
1289 C{get_locked_packages} returns all packages that are marked as1334 C{get_locked_packages} returns all packages that are marked as

Subscribers

People subscribed via source and target branches

to all changes: