Merge lp:~bjornt/landscape-client/apt-upgrade-all-packages into lp:~landscape/landscape-client/trunk
- apt-upgrade-all-packages
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alberto Donato (community) | Approve | ||
Free Ekanayaka (community) | Approve | ||
Review via email: mp+88688@code.launchpad.net |
Commit message
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.
Free Ekanayaka (free.ekanayaka) wrote : | # |
- 435. By Björn Tillenius
-
Merge trunk, resolve conflicts.
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_
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!
Preview Diff
1 | === modified file 'landscape/package/changer.py' | |||
2 | --- landscape/package/changer.py 2011-12-13 10:29:04 +0000 | |||
3 | +++ landscape/package/changer.py 2012-01-16 15:12:26 +0000 | |||
4 | @@ -169,9 +169,7 @@ | |||
5 | 169 | self._facade.reset_marks() | 169 | self._facade.reset_marks() |
6 | 170 | 170 | ||
7 | 171 | if upgrade: | 171 | if upgrade: |
11 | 172 | for package in self._facade.get_packages(): | 172 | self._facade.mark_global_upgrade() |
9 | 173 | if self._facade.is_package_installed(package): | ||
10 | 174 | self._facade.mark_upgrade(package) | ||
12 | 175 | 173 | ||
13 | 176 | for ids, mark_func in [(install, self._facade.mark_install), | 174 | for ids, mark_func in [(install, self._facade.mark_install), |
14 | 177 | (remove, self._facade.mark_remove)]: | 175 | (remove, self._facade.mark_remove)]: |
15 | 178 | 176 | ||
16 | === modified file 'landscape/package/facade.py' | |||
17 | --- landscape/package/facade.py 2012-01-13 09:37:40 +0000 | |||
18 | +++ landscape/package/facade.py 2012-01-16 15:12:26 +0000 | |||
19 | @@ -90,7 +90,7 @@ | |||
20 | 90 | self._pkg2hash = {} | 90 | self._pkg2hash = {} |
21 | 91 | self._hash2pkg = {} | 91 | self._hash2pkg = {} |
22 | 92 | self._package_installs = [] | 92 | self._package_installs = [] |
24 | 93 | self._package_upgrades = [] | 93 | self._global_upgrade = False |
25 | 94 | self._package_removals = [] | 94 | self._package_removals = [] |
26 | 95 | self.refetch_package_index = False | 95 | self.refetch_package_index = False |
27 | 96 | 96 | ||
28 | @@ -363,7 +363,7 @@ | |||
29 | 363 | held_package_names = set() | 363 | held_package_names = set() |
30 | 364 | package_changes = self._package_installs[:] | 364 | package_changes = self._package_installs[:] |
31 | 365 | package_changes.extend(self._package_removals) | 365 | package_changes.extend(self._package_removals) |
33 | 366 | if not package_changes and not self._package_upgrades: | 366 | if not package_changes and not self._global_upgrade: |
34 | 367 | return None | 367 | return None |
35 | 368 | fixer = apt_pkg.ProblemResolver(self._cache._depcache) | 368 | fixer = apt_pkg.ProblemResolver(self._cache._depcache) |
36 | 369 | for version in self._package_installs: | 369 | for version in self._package_installs: |
37 | @@ -377,14 +377,8 @@ | |||
38 | 377 | # been True. | 377 | # been True. |
39 | 378 | fixer.clear(version.package._pkg) | 378 | fixer.clear(version.package._pkg) |
40 | 379 | fixer.protect(version.package._pkg) | 379 | fixer.protect(version.package._pkg) |
49 | 380 | for version in self._package_upgrades: | 380 | if self._global_upgrade: |
50 | 381 | if self._is_package_held(version.package): | 381 | self._cache.upgrade(dist_upgrade=True) |
43 | 382 | continue | ||
44 | 383 | version.package.mark_install( | ||
45 | 384 | auto_fix=False, | ||
46 | 385 | from_user=not version.package.is_auto_installed) | ||
47 | 386 | fixer.clear(version.package._pkg) | ||
48 | 387 | fixer.protect(version.package._pkg) | ||
51 | 388 | for version in self._package_removals: | 382 | for version in self._package_removals: |
52 | 389 | if self._is_package_held(version.package): | 383 | if self._is_package_held(version.package): |
53 | 390 | held_package_names.add(version.package.name) | 384 | held_package_names.add(version.package.name) |
54 | @@ -448,17 +442,16 @@ | |||
55 | 448 | def reset_marks(self): | 442 | def reset_marks(self): |
56 | 449 | """Clear the pending package operations.""" | 443 | """Clear the pending package operations.""" |
57 | 450 | del self._package_installs[:] | 444 | del self._package_installs[:] |
58 | 451 | del self._package_upgrades[:] | ||
59 | 452 | del self._package_removals[:] | 445 | del self._package_removals[:] |
60 | 446 | self._global_upgrade = False | ||
61 | 453 | 447 | ||
62 | 454 | def mark_install(self, version): | 448 | def mark_install(self, version): |
63 | 455 | """Mark the package for installation.""" | 449 | """Mark the package for installation.""" |
64 | 456 | self._package_installs.append(version) | 450 | self._package_installs.append(version) |
65 | 457 | 451 | ||
70 | 458 | def mark_upgrade(self, version): | 452 | def mark_global_upgrade(self): |
71 | 459 | """Mark the package for upgrade.""" | 453 | """Upgrade all installed packages.""" |
72 | 460 | if version.package.candidate != version: | 454 | self._global_upgrade = True |
69 | 461 | self._package_upgrades.append(version) | ||
73 | 462 | 455 | ||
74 | 463 | def mark_remove(self, version): | 456 | def mark_remove(self, version): |
75 | 464 | """Mark the package for removal.""" | 457 | """Mark the package for removal.""" |
76 | @@ -626,6 +619,12 @@ | |||
77 | 626 | def mark_upgrade(self, pkg): | 619 | def mark_upgrade(self, pkg): |
78 | 627 | self._marks[pkg] = UPGRADE | 620 | self._marks[pkg] = UPGRADE |
79 | 628 | 621 | ||
80 | 622 | def mark_global_upgrade(self): | ||
81 | 623 | """Upgrade all installed packages.""" | ||
82 | 624 | for package in self.get_packages(): | ||
83 | 625 | if self.is_package_installed(package): | ||
84 | 626 | self.mark_upgrade(package) | ||
85 | 627 | |||
86 | 629 | def reset_marks(self): | 628 | def reset_marks(self): |
87 | 630 | self._marks.clear() | 629 | self._marks.clear() |
88 | 631 | 630 | ||
89 | 632 | 631 | ||
90 | === modified file 'landscape/package/tests/test_facade.py' | |||
91 | --- landscape/package/tests/test_facade.py 2012-01-16 14:12:40 +0000 | |||
92 | +++ landscape/package/tests/test_facade.py 2012-01-16 15:12:26 +0000 | |||
93 | @@ -905,14 +905,13 @@ | |||
94 | 905 | self.facade.reload_channels() | 905 | self.facade.reload_channels() |
95 | 906 | foo = self.facade.get_packages_by_name("foo")[0] | 906 | foo = self.facade.get_packages_by_name("foo")[0] |
96 | 907 | self.facade.mark_install(foo) | 907 | self.facade.mark_install(foo) |
99 | 908 | bar_10 = sorted(self.facade.get_packages_by_name("bar"))[0] | 908 | self.facade.mark_global_upgrade() |
98 | 909 | self.facade.mark_upgrade(bar_10) | ||
100 | 910 | [baz] = self.facade.get_packages_by_name("baz") | 909 | [baz] = self.facade.get_packages_by_name("baz") |
101 | 911 | self.facade.mark_remove(baz) | 910 | self.facade.mark_remove(baz) |
102 | 912 | self.facade.reset_marks() | 911 | self.facade.reset_marks() |
103 | 913 | self.assertEqual(self.facade._package_installs, []) | 912 | self.assertEqual(self.facade._package_installs, []) |
104 | 914 | self.assertEqual(self.facade._package_upgrades, []) | ||
105 | 915 | self.assertEqual(self.facade._package_removals, []) | 913 | self.assertEqual(self.facade._package_removals, []) |
106 | 914 | self.assertFalse(self.facade._global_upgrade) | ||
107 | 916 | self.assertEqual(self.facade.perform_changes(), None) | 915 | self.assertEqual(self.facade.perform_changes(), None) |
108 | 917 | 916 | ||
109 | 918 | def test_wb_mark_install_adds_to_list(self): | 917 | def test_wb_mark_install_adds_to_list(self): |
110 | @@ -930,10 +929,10 @@ | |||
111 | 930 | install = self.facade._package_installs[0] | 929 | install = self.facade._package_installs[0] |
112 | 931 | self.assertEqual("minimal", install.package.name) | 930 | self.assertEqual("minimal", install.package.name) |
113 | 932 | 931 | ||
115 | 933 | def test_wb_mark_upgrade_adds_to_list(self): | 932 | def test_wb_mark_global_upgrade_sets_variable(self): |
116 | 934 | """ | 933 | """ |
119 | 935 | C{mark_upgrade} adds the package to the list of packages to be | 934 | C{mark_global_upgrade} sets a variable, so that the actual |
120 | 936 | upgraded. | 935 | upgrade happens in C{perform_changes}. |
121 | 937 | """ | 936 | """ |
122 | 938 | deb_dir = self.makeDir() | 937 | deb_dir = self.makeDir() |
123 | 939 | self._add_system_package("foo", version="1.0") | 938 | self._add_system_package("foo", version="1.0") |
124 | @@ -941,8 +940,9 @@ | |||
125 | 941 | self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./") | 940 | self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./") |
126 | 942 | self.facade.reload_channels() | 941 | self.facade.reload_channels() |
127 | 943 | foo_10 = sorted(self.facade.get_packages_by_name("foo"))[0] | 942 | foo_10 = sorted(self.facade.get_packages_by_name("foo"))[0] |
130 | 944 | self.facade.mark_upgrade(foo_10) | 943 | self.facade.mark_global_upgrade() |
131 | 945 | self.assertEqual([foo_10], self.facade._package_upgrades) | 944 | self.assertTrue(self.facade._global_upgrade) |
132 | 945 | self.assertEqual(foo_10, foo_10.package.installed) | ||
133 | 946 | 946 | ||
134 | 947 | def test_wb_mark_remove_adds_to_list(self): | 947 | def test_wb_mark_remove_adds_to_list(self): |
135 | 948 | """ | 948 | """ |
136 | @@ -1062,7 +1062,27 @@ | |||
137 | 1062 | ("single-arch", "2.0")], | 1062 | ("single-arch", "2.0")], |
138 | 1063 | sorted(changes)) | 1063 | sorted(changes)) |
139 | 1064 | 1064 | ||
141 | 1065 | def test_mark_upgrade_candidate_version(self): | 1065 | def test_mark_global_upgrade(self): |
142 | 1066 | """ | ||
143 | 1067 | C{mark_global_upgrade} upgrades all packages that can be | ||
144 | 1068 | upgraded. It makes C{perform_changes} raise a C{DependencyError} | ||
145 | 1069 | with the required changes, so that the user can review the | ||
146 | 1070 | changes and approve them. | ||
147 | 1071 | """ | ||
148 | 1072 | deb_dir = self.makeDir() | ||
149 | 1073 | self._add_system_package("foo", version="1.0") | ||
150 | 1074 | self._add_system_package("bar") | ||
151 | 1075 | self._add_package_to_deb_dir(deb_dir, "foo", version="2.0") | ||
152 | 1076 | self._add_package_to_deb_dir(deb_dir, "baz") | ||
153 | 1077 | self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./") | ||
154 | 1078 | self.facade.reload_channels() | ||
155 | 1079 | foo2 = sorted(self.facade.get_packages_by_name("foo"))[1] | ||
156 | 1080 | self.facade.mark_global_upgrade() | ||
157 | 1081 | exception = self.assertRaises( | ||
158 | 1082 | DependencyError, self.facade.perform_changes) | ||
159 | 1083 | self.assertEqual([foo2], exception.packages) | ||
160 | 1084 | |||
161 | 1085 | def test_mark_global_upgrade_candidate_version(self): | ||
162 | 1066 | """ | 1086 | """ |
163 | 1067 | If more than one version is available, the package will be | 1087 | If more than one version is available, the package will be |
164 | 1068 | upgraded to the candidate version. Since the user didn't request | 1088 | upgraded to the candidate version. Since the user didn't request |
165 | @@ -1077,16 +1097,16 @@ | |||
166 | 1077 | self.facade.reload_channels() | 1097 | self.facade.reload_channels() |
167 | 1078 | foo1, foo2, foo3 = sorted(self.facade.get_packages_by_name("foo")) | 1098 | foo1, foo2, foo3 = sorted(self.facade.get_packages_by_name("foo")) |
168 | 1079 | self.assertEqual(foo3, foo1.package.candidate) | 1099 | self.assertEqual(foo3, foo1.package.candidate) |
170 | 1080 | self.facade.mark_upgrade(foo1) | 1100 | self.facade.mark_global_upgrade() |
171 | 1081 | exception = self.assertRaises( | 1101 | exception = self.assertRaises( |
172 | 1082 | DependencyError, self.facade.perform_changes) | 1102 | DependencyError, self.facade.perform_changes) |
173 | 1083 | self.assertEqual([foo3], exception.packages) | 1103 | self.assertEqual([foo3], exception.packages) |
174 | 1084 | 1104 | ||
176 | 1085 | def test_mark_upgrade_no_upgrade(self): | 1105 | def test_mark_global_upgrade_no_upgrade(self): |
177 | 1086 | """ | 1106 | """ |
178 | 1087 | If the candidate version of a package is already installed, | 1107 | If the candidate version of a package is already installed, |
181 | 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. |
182 | 1089 | perform_changes() won't do anything. | 1109 | C{perform_changes()} won't do anything. |
183 | 1090 | """ | 1110 | """ |
184 | 1091 | deb_dir = self.makeDir() | 1111 | deb_dir = self.makeDir() |
185 | 1092 | self._add_system_package("foo", version="3.0") | 1112 | self._add_system_package("foo", version="3.0") |
186 | @@ -1096,10 +1116,10 @@ | |||
187 | 1096 | self.facade.reload_channels() | 1116 | self.facade.reload_channels() |
188 | 1097 | foo3 = sorted(self.facade.get_packages_by_name("foo"))[-1] | 1117 | foo3 = sorted(self.facade.get_packages_by_name("foo"))[-1] |
189 | 1098 | self.assertEqual(foo3, foo3.package.candidate) | 1118 | self.assertEqual(foo3, foo3.package.candidate) |
191 | 1099 | self.facade.mark_upgrade(foo3) | 1119 | self.facade.mark_global_upgrade() |
192 | 1100 | self.assertEqual(None, self.facade.perform_changes()) | 1120 | self.assertEqual(None, self.facade.perform_changes()) |
193 | 1101 | 1121 | ||
195 | 1102 | def test_mark_upgrade_preserves_auto(self): | 1122 | def test_mark_global_upgrade_preserves_auto(self): |
196 | 1103 | """ | 1123 | """ |
197 | 1104 | Upgrading a package will retain its auto-install status. | 1124 | Upgrading a package will retain its auto-install status. |
198 | 1105 | """ | 1125 | """ |
199 | @@ -1114,8 +1134,7 @@ | |||
200 | 1114 | noauto1, noauto2 = sorted(self.facade.get_packages_by_name("noauto")) | 1134 | noauto1, noauto2 = sorted(self.facade.get_packages_by_name("noauto")) |
201 | 1115 | auto1.package.mark_auto(True) | 1135 | auto1.package.mark_auto(True) |
202 | 1116 | noauto1.package.mark_auto(False) | 1136 | noauto1.package.mark_auto(False) |
205 | 1117 | self.facade.mark_upgrade(auto1) | 1137 | self.facade.mark_global_upgrade() |
204 | 1118 | self.facade.mark_upgrade(noauto1) | ||
206 | 1119 | self.assertRaises(DependencyError, self.facade.perform_changes) | 1138 | self.assertRaises(DependencyError, self.facade.perform_changes) |
207 | 1120 | self.assertTrue(auto2.package.is_auto_installed) | 1139 | self.assertTrue(auto2.package.is_auto_installed) |
208 | 1121 | self.assertFalse(noauto2.package.is_auto_installed) | 1140 | self.assertFalse(noauto2.package.is_auto_installed) |
209 | @@ -1211,7 +1230,7 @@ | |||
210 | 1211 | error = self.assertRaises(DependencyError, self.facade.perform_changes) | 1230 | error = self.assertRaises(DependencyError, self.facade.perform_changes) |
211 | 1212 | self.assertEqual([bar], error.packages) | 1231 | self.assertEqual([bar], error.packages) |
212 | 1213 | 1232 | ||
214 | 1214 | def test_mark_upgrade_dependency_error(self): | 1233 | def test_mark_global_upgrade_dependency_error(self): |
215 | 1215 | """ | 1234 | """ |
216 | 1216 | If a package is marked for upgrade, a DependencyError will be | 1235 | If a package is marked for upgrade, a DependencyError will be |
217 | 1217 | raised, indicating which version of the package will be | 1236 | raised, indicating which version of the package will be |
218 | @@ -1226,7 +1245,7 @@ | |||
219 | 1226 | self.facade.reload_channels() | 1245 | self.facade.reload_channels() |
220 | 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")) |
221 | 1228 | [bar] = self.facade.get_packages_by_name("bar") | 1247 | [bar] = self.facade.get_packages_by_name("bar") |
223 | 1229 | self.facade.mark_upgrade(foo_10) | 1248 | self.facade.mark_global_upgrade() |
224 | 1230 | error = self.assertRaises(DependencyError, self.facade.perform_changes) | 1249 | error = self.assertRaises(DependencyError, self.facade.perform_changes) |
225 | 1231 | self.assertEqual( | 1250 | self.assertEqual( |
226 | 1232 | sorted([bar, foo_15], key=self.version_sortkey), | 1251 | sorted([bar, foo_15], key=self.version_sortkey), |
227 | @@ -1266,7 +1285,7 @@ | |||
228 | 1266 | "Can't perform the changes, since the following packages" + | 1285 | "Can't perform the changes, since the following packages" + |
229 | 1267 | " are held: bar, foo", error.args[0]) | 1286 | " are held: bar, foo", error.args[0]) |
230 | 1268 | 1287 | ||
232 | 1269 | def test_mark_upgrade_held_packages(self): | 1288 | def test_mark_global_upgrade_held_packages(self): |
233 | 1270 | """ | 1289 | """ |
234 | 1271 | If a package that is on hold is marked for upgrade, | 1290 | If a package that is on hold is marked for upgrade, |
235 | 1272 | C{perform_changes} won't request to install a newer version of | 1291 | C{perform_changes} won't request to install a newer version of |
236 | @@ -1280,10 +1299,36 @@ | |||
237 | 1280 | self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./") | 1299 | self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./") |
238 | 1281 | self.facade.reload_channels() | 1300 | self.facade.reload_channels() |
239 | 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")) |
241 | 1283 | self.facade.mark_upgrade(foo_10) | 1302 | self.facade.mark_global_upgrade() |
242 | 1284 | self.assertEqual(None, self.facade.perform_changes()) | 1303 | self.assertEqual(None, self.facade.perform_changes()) |
243 | 1285 | self.assertEqual(foo_10, foo_15.package.installed) | 1304 | self.assertEqual(foo_10, foo_15.package.installed) |
244 | 1286 | 1305 | ||
245 | 1306 | def test_mark_global_upgrade_held_dependencies(self): | ||
246 | 1307 | """ | ||
247 | 1308 | If a package that can be upgraded, but that package depends on a | ||
248 | 1309 | newer version of a held package, the first package won't be | ||
249 | 1310 | marked as requiring upgrade. | ||
250 | 1311 | """ | ||
251 | 1312 | self._add_system_package( | ||
252 | 1313 | "foo", version="1.0", | ||
253 | 1314 | control_fields={"Status": "hold ok installed"}) | ||
254 | 1315 | self._add_system_package( | ||
255 | 1316 | "bar", version="1.0", | ||
256 | 1317 | control_fields={"Depends": "foo"}) | ||
257 | 1318 | deb_dir = self.makeDir() | ||
258 | 1319 | self._add_package_to_deb_dir(deb_dir, "foo", version="2.0") | ||
259 | 1320 | self._add_package_to_deb_dir( | ||
260 | 1321 | deb_dir, "bar", version="2.0", | ||
261 | 1322 | control_fields={"Depends": "foo (>> 1.0)"}) | ||
262 | 1323 | self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./") | ||
263 | 1324 | self.facade.reload_channels() | ||
264 | 1325 | [foo_1, foo_2] = sorted(self.facade.get_packages_by_name("foo")) | ||
265 | 1326 | [bar_1, bar_2] = sorted(self.facade.get_packages_by_name("bar")) | ||
266 | 1327 | self.facade.mark_global_upgrade() | ||
267 | 1328 | self.assertEqual(None, self.facade.perform_changes()) | ||
268 | 1329 | self.assertEqual(foo_1, foo_2.package.installed) | ||
269 | 1330 | self.assertEqual(bar_1, bar_2.package.installed) | ||
270 | 1331 | |||
271 | 1287 | def test_get_locked_packages_simple(self): | 1332 | def test_get_locked_packages_simple(self): |
272 | 1288 | """ | 1333 | """ |
273 | 1289 | C{get_locked_packages} returns all packages that are marked as | 1334 | C{get_locked_packages} returns all packages that are marked as |
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.