Merge lp:~therve/landscape-client/lshw into lp:~landscape/landscape-client/trunk
- lshw
- Merge into trunk
Proposed by
Thomas Herve
Status: | Merged |
---|---|
Approved by: | Mike Milner |
Approved revision: | 417 |
Merged at revision: | 414 |
Proposed branch: | lp:~therve/landscape-client/lshw |
Merge into: | lp:~landscape/landscape-client/trunk |
Diff against target: |
1816 lines (+103/-1159) 41 files modified
README (+1/-10) dbus/landscape.conf (+0/-62) debian/control (+2/-3) debian/landscape-client.install (+0/-2) debian/landscape-client.postinst (+0/-11) debian/rules (+6/-9) landscape/broker/exchange.py (+1/-3) landscape/configuration.py (+0/-4) landscape/hal.py (+0/-52) landscape/lib/bpickle_dbus.py (+0/-63) landscape/lib/tests/test_bpickle_dbus.py (+0/-75) landscape/manager/config.py (+1/-1) landscape/manager/hardwareinfo.py (+27/-0) landscape/manager/tests/test_config.py (+2/-1) landscape/manager/tests/test_hardwareinfo.py (+29/-0) landscape/manager/tests/test_service.py (+3/-9) landscape/message_schemas.py (+5/-1) landscape/monitor/config.py (+4/-5) landscape/monitor/hardwareinventory.py (+0/-114) landscape/monitor/mountinfo.py (+2/-65) landscape/monitor/tests/test_hardwareinventory.py (+0/-273) landscape/monitor/tests/test_mountinfo.py (+0/-76) landscape/monitor/tests/test_service.py (+3/-9) landscape/package/releaseupgrader.py (+0/-21) landscape/package/tests/test_releaseupgrader.py (+0/-54) landscape/reactor.py (+2/-13) landscape/service.py (+0/-6) landscape/tests/test_configuration.py (+1/-1) landscape/tests/test_hal.py (+0/-87) landscape/tests/test_service.py (+0/-9) landscape/tests/test_textmessage.py (+2/-2) landscape/textmessage.py (+1/-2) landscape/watchdog.py (+7/-10) man/landscape-client.1 (+1/-6) man/landscape-client.txt (+0/-2) man/landscape-config.1 (+1/-6) man/landscape-config.txt (+0/-2) man/landscape-message.1 (+1/-5) man/landscape-message.txt (+0/-1) scripts/landscape-dbus-proxy (+0/-82) setup.py (+1/-2) |
To merge this branch: | bzr merge lp:~therve/landscape-client/lshw |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike Milner (community) | Approve | ||
Alberto Donato (community) | Approve | ||
Review via email: mp+84225@code.launchpad.net |
Commit message
Description of the change
The branch ought to be really small, but I removed the code for HAL support, and what was remaining of DBus.
The only part remaining is the old message schemas, but it needs to be removed on the server first.
To post a comment you must log in.
lp:~therve/landscape-client/lshw
updated
- 416. By Thomas Herve
-
Lints
lp:~therve/landscape-client/lshw
updated
- 417. By Thomas Herve
-
Fix man pages dates
Revision history for this message
Mike Milner (milner) wrote : | # |
Looks good - I love it when code goes away! +1
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'README' | |||
2 | --- README 2008-12-22 17:21:04 +0000 | |||
3 | +++ README 2011-12-02 09:56:24 +0000 | |||
4 | @@ -23,14 +23,6 @@ | |||
5 | 23 | 23 | ||
6 | 24 | == Developing == | 24 | == Developing == |
7 | 25 | 25 | ||
8 | 26 | To run the full test suite, you must have a dbus session bus | ||
9 | 27 | running. If you don't have one (for example, if you're running the | ||
10 | 28 | tests in an ssh session), run the following command: | ||
11 | 29 | |||
12 | 30 | export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --print-address=1 --session --fork` | ||
13 | 31 | |||
14 | 32 | Then your tests should pass. | ||
15 | 33 | |||
16 | 34 | When you want to test the landscape client manually without management | 26 | When you want to test the landscape client manually without management |
17 | 35 | features, you can simply run: | 27 | features, you can simply run: |
18 | 36 | 28 | ||
19 | @@ -39,8 +31,7 @@ | |||
20 | 39 | This defaults to the 'landscape-client.conf' configuration file. | 31 | This defaults to the 'landscape-client.conf' configuration file. |
21 | 40 | 32 | ||
22 | 41 | When you want to test management features manually, you'll need to run as root. | 33 | When you want to test management features manually, you'll need to run as root. |
25 | 42 | There's a configuration file 'root-client.conf' which specifies use of the | 34 | There's a configuration file 'root-client.conf'. |
24 | 43 | system bus. | ||
26 | 44 | 35 | ||
27 | 45 | $ sudo ./scripts/landscape-client -c root-client.conf | 36 | $ sudo ./scripts/landscape-client -c root-client.conf |
28 | 46 | 37 | ||
29 | 47 | 38 | ||
30 | === removed directory 'dbus' | |||
31 | === removed file 'dbus/landscape.conf' | |||
32 | --- dbus/landscape.conf 2010-06-10 13:30:58 +0000 | |||
33 | +++ dbus/landscape.conf 1970-01-01 00:00:00 +0000 | |||
34 | @@ -1,62 +0,0 @@ | |||
35 | 1 | <!DOCTYPE busconfig PUBLIC | ||
36 | 2 | "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" | ||
37 | 3 | "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> | ||
38 | 4 | <busconfig> | ||
39 | 5 | |||
40 | 6 | <policy user="landscape"> | ||
41 | 7 | <allow own="com.canonical.landscape.Broker" /> | ||
42 | 8 | <allow own="com.canonical.landscape.Monitor" /> | ||
43 | 9 | |||
44 | 10 | <allow send_destination="com.canonical.landscape.Broker" /> | ||
45 | 11 | <allow receive_sender="com.canonical.landscape.Broker" /> | ||
46 | 12 | |||
47 | 13 | <allow send_destination="com.canonical.landscape.Monitor" /> | ||
48 | 14 | <allow receive_sender="com.canonical.landscape.Monitor" /> | ||
49 | 15 | |||
50 | 16 | <allow send_destination="com.canonical.landscape.Manager" /> | ||
51 | 17 | <allow receive_sender="com.canonical.landscape.Manager" /> | ||
52 | 18 | |||
53 | 19 | <allow send_interface="org.freedesktop.Hal.Manager" /> | ||
54 | 20 | <allow send_interface="org.freedesktop.Hal.Device" /> | ||
55 | 21 | |||
56 | 22 | </policy> | ||
57 | 23 | |||
58 | 24 | <!-- this is a horrible hack --> | ||
59 | 25 | <policy user="haldaemon"> | ||
60 | 26 | |||
61 | 27 | <allow receive_sender="com.canonical.landscape.Manager" /> | ||
62 | 28 | <allow receive_sender="com.canonical.landscape.Monitor" /> | ||
63 | 29 | <allow receive_sender="com.canonical.landscape.Broker" /> | ||
64 | 30 | |||
65 | 31 | </policy> | ||
66 | 32 | |||
67 | 33 | <policy user="root"> | ||
68 | 34 | <allow own="com.canonical.landscape.Manager" /> | ||
69 | 35 | |||
70 | 36 | <allow send_destination="com.canonical.landscape.Broker" /> | ||
71 | 37 | <allow receive_sender="com.canonical.landscape.Broker" /> | ||
72 | 38 | |||
73 | 39 | <allow send_destination="com.canonical.landscape.Monitor" /> | ||
74 | 40 | <allow receive_sender="com.canonical.landscape.Monitor" /> | ||
75 | 41 | |||
76 | 42 | <allow send_destination="com.canonical.landscape.Manager" /> | ||
77 | 43 | <allow receive_sender="com.canonical.landscape.Manager" /> | ||
78 | 44 | </policy> | ||
79 | 45 | |||
80 | 46 | <policy context="default"> | ||
81 | 47 | <deny own="com.canonical.landscape.Broker" /> | ||
82 | 48 | <deny own="com.canonical.landscape.Monitor" /> | ||
83 | 49 | <deny own="com.canonical.landscape.Manager" /> | ||
84 | 50 | |||
85 | 51 | <deny send_destination="com.canonical.landscape.Broker" /> | ||
86 | 52 | <deny receive_sender="com.canonical.landscape.Broker" /> | ||
87 | 53 | |||
88 | 54 | <deny send_destination="com.canonical.landscape.Monitor" /> | ||
89 | 55 | <deny receive_sender="com.canonical.landscape.Monitor" /> | ||
90 | 56 | |||
91 | 57 | <deny send_destination="com.canonical.landscape.Manager" /> | ||
92 | 58 | <deny receive_sender="com.canonical.landscape.Manager" /> | ||
93 | 59 | |||
94 | 60 | </policy> | ||
95 | 61 | |||
96 | 62 | </busconfig> | ||
97 | 63 | 0 | ||
98 | === modified file 'debian/control' | |||
99 | --- debian/control 2011-01-31 11:04:34 +0000 | |||
100 | +++ debian/control 2011-12-02 09:56:24 +0000 | |||
101 | @@ -12,15 +12,14 @@ | |||
102 | 12 | Depends: ${python:Depends}, ${misc:Depends}, ${extra:Depends}, | 12 | Depends: ${python:Depends}, ${misc:Depends}, ${extra:Depends}, |
103 | 13 | python-gnupginterface, | 13 | python-gnupginterface, |
104 | 14 | python-twisted-core, | 14 | python-twisted-core, |
105 | 15 | python-gobject, | ||
106 | 16 | python-apt, | 15 | python-apt, |
107 | 17 | ca-certificates, | 16 | ca-certificates, |
108 | 18 | perl-modules, | ||
109 | 19 | python-gdbm, | 17 | python-gdbm, |
110 | 20 | lsb-release, | 18 | lsb-release, |
111 | 21 | lsb-base, | 19 | lsb-base, |
112 | 22 | adduser, | 20 | adduser, |
114 | 23 | bc | 21 | bc, |
115 | 22 | lshw | ||
116 | 24 | Suggests: ${extra:Suggests} | 23 | Suggests: ${extra:Suggests} |
117 | 25 | Replaces: landscape-client (<= 1.0.23-0ubuntu0.8.10) | 24 | Replaces: landscape-client (<= 1.0.23-0ubuntu0.8.10) |
118 | 26 | Description: The Landscape administration system client | 25 | Description: The Landscape administration system client |
119 | 27 | 26 | ||
120 | === modified file 'debian/landscape-client.install' | |||
121 | --- debian/landscape-client.install 2010-06-10 13:30:58 +0000 | |||
122 | +++ debian/landscape-client.install 2011-12-02 09:56:24 +0000 | |||
123 | @@ -8,7 +8,5 @@ | |||
124 | 8 | usr/bin/landscape-package-reporter | 8 | usr/bin/landscape-package-reporter |
125 | 9 | usr/bin/landscape-release-upgrader | 9 | usr/bin/landscape-release-upgrader |
126 | 10 | usr/bin/landscape-is-cloud-managed | 10 | usr/bin/landscape-is-cloud-managed |
127 | 11 | usr/bin/landscape-dbus-proxy | ||
128 | 12 | usr/share/landscape/cloud-default.conf | 11 | usr/share/landscape/cloud-default.conf |
129 | 13 | etc/dbus-1/system.d/landscape.conf | ||
130 | 14 | usr/lib/landscape | 12 | usr/lib/landscape |
131 | 15 | 13 | ||
132 | === modified file 'debian/landscape-client.postinst' | |||
133 | --- debian/landscape-client.postinst 2011-11-04 11:42:10 +0000 | |||
134 | +++ debian/landscape-client.postinst 2011-12-02 09:56:24 +0000 | |||
135 | @@ -123,17 +123,6 @@ | |||
136 | 123 | if [ -e $very_old_cron_job ]; then | 123 | if [ -e $very_old_cron_job ]; then |
137 | 124 | rm $very_old_cron_job | 124 | rm $very_old_cron_job |
138 | 125 | fi | 125 | fi |
139 | 126 | |||
140 | 127 | # Check if we're upgrading from a D-Bus version | ||
141 | 128 | if ! [ -z $2 ]; then | ||
142 | 129 | if dpkg --compare-versions $2 lt 1.5.1; then | ||
143 | 130 | # Launch a proxy service that will forward requests over DBus | ||
144 | 131 | # from the old package-changer to the new AMP-based broker. This | ||
145 | 132 | # is a one-off only needed for the DBus->AMP upgrade | ||
146 | 133 | start-stop-daemon -x /usr/bin/landscape-dbus-proxy -b -c landscape -u landscape -S | ||
147 | 134 | fi | ||
148 | 135 | fi | ||
149 | 136 | |||
150 | 137 | ;; | 126 | ;; |
151 | 138 | 127 | ||
152 | 139 | abort-upgrade|abort-remove|abort-deconfigure) | 128 | abort-upgrade|abort-remove|abort-deconfigure) |
153 | 140 | 129 | ||
154 | === modified file 'debian/rules' | |||
155 | --- debian/rules 2011-11-04 11:42:10 +0000 | |||
156 | +++ debian/rules 2011-12-02 09:56:24 +0000 | |||
157 | @@ -60,7 +60,6 @@ | |||
158 | 60 | install -D -o root -g root -m 644 debian/cloud-default.conf $(root_dir)/usr/share/landscape/cloud-default.conf | 60 | install -D -o root -g root -m 644 debian/cloud-default.conf $(root_dir)/usr/share/landscape/cloud-default.conf |
159 | 61 | install -D -o root -g root -m 755 smart-update/smart-update $(root_dir)/usr/lib/landscape/smart-update | 61 | install -D -o root -g root -m 755 smart-update/smart-update $(root_dir)/usr/lib/landscape/smart-update |
160 | 62 | install -D -o root -g root -m 755 apt-update/apt-update $(root_dir)/usr/lib/landscape/apt-update | 62 | install -D -o root -g root -m 755 apt-update/apt-update $(root_dir)/usr/lib/landscape/apt-update |
161 | 63 | install -D -o root -g root -m 644 dbus/landscape.conf $(root_dir)/etc/dbus-1/system.d/landscape.conf | ||
162 | 64 | 63 | ||
163 | 65 | binary-indep: | 64 | binary-indep: |
164 | 66 | # do nothing | 65 | # do nothing |
165 | @@ -84,24 +83,22 @@ | |||
166 | 84 | 83 | ||
167 | 85 | ifneq (,$(findstring $(dist_release),"dapper")) | 84 | ifneq (,$(findstring $(dist_release),"dapper")) |
168 | 86 | # We need python2.4-pysqlite2 and a non-buggy libcurl3-gnutls on dapper | 85 | # We need python2.4-pysqlite2 and a non-buggy libcurl3-gnutls on dapper |
171 | 87 | echo "extra:Depends=python2.4-pysqlite2, libcurl3-gnutls (>= 7.15.1-1ubuntu3), python-smartpm (>= 1.1.1~bzr20081010-0ubuntu1.6.06.0), python2.4-dbus" >> $(landscape_common_substvars) | 86 | echo "extra:Depends=python2.4-pysqlite2, libcurl3-gnutls (>= 7.15.1-1ubuntu3), python-smartpm (>= 1.1.1~bzr20081010-0ubuntu1.6.06.0)" >> $(landscape_common_substvars) |
172 | 88 | echo "extra:Depends=python2.4-pycurl, hal" >> $(landscape_client_substvars) | 87 | echo "extra:Depends=python2.4-pycurl" >> $(landscape_client_substvars) |
173 | 89 | endif | 88 | endif |
174 | 90 | ifneq (,$(findstring $(dist_release),"hardy")) | 89 | ifneq (,$(findstring $(dist_release),"hardy")) |
175 | 91 | # We want the smart 1.1.1 from the Landscape repository on hardy | 90 | # We want the smart 1.1.1 from the Landscape repository on hardy |
178 | 92 | echo "extra:Depends=python-smartpm (>= 1.1.1~bzr20081010-0ubuntu1.8.04.1), python-dbus" >> $(landscape_common_substvars) | 91 | echo "extra:Depends=python-smartpm (>= 1.1.1~bzr20081010-0ubuntu1.8.04.1)" >> $(landscape_common_substvars) |
179 | 93 | echo "extra:Depends=python-pycurl, hal" >> $(landscape_client_substvars) | 92 | echo "extra:Depends=python-pycurl" >> $(landscape_client_substvars) |
180 | 94 | endif | 93 | endif |
181 | 95 | ifneq (,$(filter $(dist_release),karmic lucid maverick)) | 94 | ifneq (,$(filter $(dist_release),karmic lucid maverick)) |
182 | 96 | # We want libpam-modules in karmic, and smart 1.2 | 95 | # We want libpam-modules in karmic, and smart 1.2 |
185 | 97 | echo "extra:Depends=libpam-modules (>= 1.0.1-9ubuntu3), python-smartpm (>= 1.2-4), python-dbus" >> $(landscape_common_substvars) | 96 | echo "extra:Depends=libpam-modules (>= 1.0.1-9ubuntu3), python-smartpm (>= 1.2-4)" >> $(landscape_common_substvars) |
186 | 98 | echo "extra:Depends=python-pycurl, hal" >> $(landscape_client_substvars) | 97 | echo "extra:Depends=python-pycurl" >> $(landscape_client_substvars) |
187 | 99 | endif | 98 | endif |
188 | 100 | ifeq (,$(filter $(dist_release),dapper hardy karmic lucid maverick)) | 99 | ifeq (,$(filter $(dist_release),dapper hardy karmic lucid maverick)) |
189 | 101 | # Starting natty, no more hal or dbus | ||
190 | 102 | echo "extra:Depends=libpam-modules (>= 1.0.1-9ubuntu3), python-smartpm (>= 1.2-4)" >> $(landscape_common_substvars) | 100 | echo "extra:Depends=libpam-modules (>= 1.0.1-9ubuntu3), python-smartpm (>= 1.2-4)" >> $(landscape_common_substvars) |
191 | 103 | echo "extra:Depends=python-pycurl, gir1.2-gudev-1.0 (>= 165-0ubuntu2)" >> $(landscape_client_substvars) | 101 | echo "extra:Depends=python-pycurl, gir1.2-gudev-1.0 (>= 165-0ubuntu2)" >> $(landscape_client_substvars) |
192 | 104 | echo "extra:Suggests=python-dbus, hal" >> $(landscape_client_substvars) | ||
193 | 105 | endif | 102 | endif |
194 | 106 | ifeq (,$(filter $(dist_release),dapper hardy karmic)) | 103 | ifeq (,$(filter $(dist_release),dapper hardy karmic)) |
195 | 107 | # The python-image-store-proxy package is needed for the eucalyptus plugin | 104 | # The python-image-store-proxy package is needed for the eucalyptus plugin |
196 | 108 | 105 | ||
197 | === modified file 'landscape/broker/exchange.py' | |||
198 | --- landscape/broker/exchange.py 2011-07-18 13:35:59 +0000 | |||
199 | +++ landscape/broker/exchange.py 2011-12-02 09:56:24 +0000 | |||
200 | @@ -422,9 +422,7 @@ | |||
201 | 422 | handler(message) | 422 | handler(message) |
202 | 423 | 423 | ||
203 | 424 | def register_client_accepted_message_type(self, type): | 424 | def register_client_accepted_message_type(self, type): |
207 | 425 | # stringify the type because it's a dbus.String. It should work | 425 | self._client_accepted_types.add(type) |
205 | 426 | # anyway, but this is just for sanity and less confusing logs. | ||
206 | 427 | self._client_accepted_types.add(str(type)) | ||
208 | 428 | 426 | ||
209 | 429 | def get_client_accepted_message_types(self): | 427 | def get_client_accepted_message_types(self): |
210 | 430 | return sorted(self._client_accepted_types) | 428 | return sorted(self._client_accepted_types) |
211 | 431 | 429 | ||
212 | === modified file 'landscape/configuration.py' | |||
213 | --- landscape/configuration.py 2011-11-11 12:34:57 +0000 | |||
214 | +++ landscape/configuration.py 2011-12-02 09:56:24 +0000 | |||
215 | @@ -541,10 +541,6 @@ | |||
216 | 541 | connector.disconnect() | 541 | connector.disconnect() |
217 | 542 | 542 | ||
218 | 543 | def catch_all(failure): | 543 | def catch_all(failure): |
219 | 544 | # We catch SecurityError here too, because on some DBUS configurations | ||
220 | 545 | # if you try to connect to a dbus name that doesn't have a listener, | ||
221 | 546 | # it'll try auto-starting the service, but then the StartServiceByName | ||
222 | 547 | # call can raise a SecurityError. | ||
223 | 548 | print_text(failure.getTraceback(), error=True) | 544 | print_text(failure.getTraceback(), error=True) |
224 | 549 | print_text("Unknown error occurred.", error=True) | 545 | print_text("Unknown error occurred.", error=True) |
225 | 550 | stop() | 546 | stop() |
226 | 551 | 547 | ||
227 | === removed file 'landscape/hal.py' | |||
228 | --- landscape/hal.py 2011-06-13 23:58:09 +0000 | |||
229 | +++ landscape/hal.py 1970-01-01 00:00:00 +0000 | |||
230 | @@ -1,52 +0,0 @@ | |||
231 | 1 | import logging | ||
232 | 2 | |||
233 | 3 | from dbus import Interface, SystemBus | ||
234 | 4 | from dbus.exceptions import DBusException | ||
235 | 5 | |||
236 | 6 | |||
237 | 7 | class HALManager(object): | ||
238 | 8 | |||
239 | 9 | def __init__(self, bus=None): | ||
240 | 10 | try: | ||
241 | 11 | self._bus = bus or SystemBus() | ||
242 | 12 | manager = self._bus.get_object("org.freedesktop.Hal", | ||
243 | 13 | "/org/freedesktop/Hal/Manager") | ||
244 | 14 | except DBusException: | ||
245 | 15 | logging.error("Couldn't to connect to Hal via DBus") | ||
246 | 16 | self._manager = None | ||
247 | 17 | else: | ||
248 | 18 | self._manager = Interface(manager, "org.freedesktop.Hal.Manager") | ||
249 | 19 | |||
250 | 20 | def get_devices(self): | ||
251 | 21 | """Returns a list of HAL devices. | ||
252 | 22 | |||
253 | 23 | @note: If it wasn't possible to connect to HAL over DBus, then an | ||
254 | 24 | empty list will be returned. This can happen if the HAL or DBus | ||
255 | 25 | services are not running. | ||
256 | 26 | """ | ||
257 | 27 | if not self._manager: | ||
258 | 28 | return [] | ||
259 | 29 | devices = [] | ||
260 | 30 | for udi in self._manager.GetAllDevices(): | ||
261 | 31 | device = self._bus.get_object("org.freedesktop.Hal", udi) | ||
262 | 32 | device = Interface(device, "org.freedesktop.Hal.Device") | ||
263 | 33 | device = HALDevice(device) | ||
264 | 34 | devices.append(device) | ||
265 | 35 | return devices | ||
266 | 36 | |||
267 | 37 | |||
268 | 38 | class HALDevice(object): | ||
269 | 39 | |||
270 | 40 | def __init__(self, device): | ||
271 | 41 | self._children = [] | ||
272 | 42 | self._device = device | ||
273 | 43 | self.properties = device.GetAllProperties() | ||
274 | 44 | self.udi = self.properties["info.udi"] | ||
275 | 45 | self.parent = None | ||
276 | 46 | |||
277 | 47 | def add_child(self, device): | ||
278 | 48 | self._children.append(device) | ||
279 | 49 | device.parent = self | ||
280 | 50 | |||
281 | 51 | def get_children(self): | ||
282 | 52 | return self._children | ||
283 | 53 | 0 | ||
284 | === removed file 'landscape/lib/bpickle_dbus.py' | |||
285 | --- landscape/lib/bpickle_dbus.py 2008-06-10 10:56:01 +0000 | |||
286 | +++ landscape/lib/bpickle_dbus.py 1970-01-01 00:00:00 +0000 | |||
287 | @@ -1,63 +0,0 @@ | |||
288 | 1 | """ | ||
289 | 2 | Different versions of the Python DBus bindings return different types | ||
290 | 3 | to represent integers, strings, lists, etc. Older versions return | ||
291 | 4 | builtin Python types: C{int}, C{str}, C{list}, etc. Newer versions | ||
292 | 5 | return DBus-specific wrappers: C{Int16}, C{String}, C{Array}, etc. | ||
293 | 6 | Failures occur when DBus types are used because bpickle doesn't know | ||
294 | 7 | that an C{Int16} is really an C{int} and that an C{Array} is really a | ||
295 | 8 | C{list}. | ||
296 | 9 | |||
297 | 10 | L{install} and L{uninstall} can install and remove extensions that | ||
298 | 11 | make bpickle work with DBus types. | ||
299 | 12 | """ | ||
300 | 13 | |||
301 | 14 | import dbus | ||
302 | 15 | |||
303 | 16 | from landscape.lib import bpickle | ||
304 | 17 | |||
305 | 18 | |||
306 | 19 | def install(): | ||
307 | 20 | """Install bpickle extensions for DBus types.""" | ||
308 | 21 | for type, function in get_dbus_types(): | ||
309 | 22 | bpickle.dumps_table[type] = function | ||
310 | 23 | |||
311 | 24 | |||
312 | 25 | def uninstall(): | ||
313 | 26 | """Uninstall bpickle extensions for DBus types.""" | ||
314 | 27 | for type, function in get_dbus_types(): | ||
315 | 28 | del bpickle.dumps_table[type] | ||
316 | 29 | |||
317 | 30 | |||
318 | 31 | def dumps_utf8string(obj): | ||
319 | 32 | """ | ||
320 | 33 | Convert the specified L{dbus.types.UTF8String} to bpickle's | ||
321 | 34 | representation for C{unicode} data. | ||
322 | 35 | """ | ||
323 | 36 | return "u%s:%s" % (len(obj), obj) | ||
324 | 37 | |||
325 | 38 | def dumps_double(obj): | ||
326 | 39 | """ | ||
327 | 40 | Convert a dbus.types.Double into a floating point representation. | ||
328 | 41 | """ | ||
329 | 42 | return "f%r;" % float(obj) | ||
330 | 43 | |||
331 | 44 | def get_dbus_types(): | ||
332 | 45 | """ | ||
333 | 46 | Generator yields C{(type, bpickle_function)} for available DBus | ||
334 | 47 | types. | ||
335 | 48 | """ | ||
336 | 49 | for (type_name, function) in [("Boolean", bpickle.dumps_bool), | ||
337 | 50 | ("Int16", bpickle.dumps_int), | ||
338 | 51 | ("UInt16", bpickle.dumps_int), | ||
339 | 52 | ("Int32", bpickle.dumps_int), | ||
340 | 53 | ("UInt32", bpickle.dumps_int), | ||
341 | 54 | ("Int64", bpickle.dumps_int), | ||
342 | 55 | ("UInt64", bpickle.dumps_int), | ||
343 | 56 | ("Double", dumps_double), | ||
344 | 57 | ("Array", bpickle.dumps_list), | ||
345 | 58 | ("Dictionary", bpickle.dumps_dict), | ||
346 | 59 | ("String", bpickle.dumps_unicode), | ||
347 | 60 | ("UTF8String", dumps_utf8string),]: | ||
348 | 61 | type = getattr(dbus.types, type_name, None) | ||
349 | 62 | if type is not None: | ||
350 | 63 | yield type, function | ||
351 | 64 | 0 | ||
352 | === removed file 'landscape/lib/tests/test_bpickle_dbus.py' | |||
353 | --- landscape/lib/tests/test_bpickle_dbus.py 2011-07-05 05:09:11 +0000 | |||
354 | +++ landscape/lib/tests/test_bpickle_dbus.py 1970-01-01 00:00:00 +0000 | |||
355 | @@ -1,75 +0,0 @@ | |||
356 | 1 | import unittest | ||
357 | 2 | |||
358 | 3 | from dbus.types import Double | ||
359 | 4 | |||
360 | 5 | from landscape.lib import bpickle | ||
361 | 6 | from landscape.lib.bpickle_dbus import install, uninstall, dumps_utf8string | ||
362 | 7 | |||
363 | 8 | |||
364 | 9 | original = dict(bpickle.dumps_table) | ||
365 | 10 | |||
366 | 11 | |||
367 | 12 | class DBusBPickleExtensionsTest(unittest.TestCase): | ||
368 | 13 | |||
369 | 14 | def tearDown(self): | ||
370 | 15 | # Mutate the original object back to the original version | ||
371 | 16 | # because rebinding it will cause bizarre failures. | ||
372 | 17 | bpickle.dumps_table.clear() | ||
373 | 18 | bpickle.dumps_table.update(original) | ||
374 | 19 | |||
375 | 20 | def test_install(self): | ||
376 | 21 | """ | ||
377 | 22 | Installing bpickle extensions for DBus types should add to the | ||
378 | 23 | existing table. Existing bpickle mappings shouldn't be | ||
379 | 24 | changed. | ||
380 | 25 | """ | ||
381 | 26 | install() | ||
382 | 27 | self.assertNotEquals(original, bpickle.dumps_table) | ||
383 | 28 | pre = set(original.iteritems()) | ||
384 | 29 | post = set(bpickle.dumps_table.iteritems()) | ||
385 | 30 | self.assertTrue(pre.issubset(post)) | ||
386 | 31 | |||
387 | 32 | def test_uninstall(self): | ||
388 | 33 | """ | ||
389 | 34 | Uninstalling bpickle extensions for DBus types should remove | ||
390 | 35 | whatever was added during installation. Extensions installed | ||
391 | 36 | by external components should not be affected by this | ||
392 | 37 | operation. | ||
393 | 38 | """ | ||
394 | 39 | install() | ||
395 | 40 | self.assertFalse(object in bpickle.dumps_table) | ||
396 | 41 | bpickle.dumps_table[object] = lambda obj: None | ||
397 | 42 | |||
398 | 43 | uninstall() | ||
399 | 44 | pre = set(original.iteritems()) | ||
400 | 45 | post = set(bpickle.dumps_table.iteritems()) | ||
401 | 46 | self.assertTrue(pre.issubset(post)) | ||
402 | 47 | self.assertTrue(object in bpickle.dumps_table) | ||
403 | 48 | self.assertTrue(len(original) + 1, len(bpickle.dumps_table)) | ||
404 | 49 | |||
405 | 50 | def test_dumps_utf8string(self): | ||
406 | 51 | """ | ||
407 | 52 | Dumping a L{dbus.types.UTF8String} should produce the same | ||
408 | 53 | bpickle output as would be produced for a C{unicode} value. | ||
409 | 54 | """ | ||
410 | 55 | try: | ||
411 | 56 | from dbus.types import UTF8String | ||
412 | 57 | |||
413 | 58 | value = UTF8String("") | ||
414 | 59 | self.assertEqual(dumps_utf8string(value), "u0:") | ||
415 | 60 | value = UTF8String("Charlie!") | ||
416 | 61 | self.assertEqual(dumps_utf8string(value), "u8:Charlie!") | ||
417 | 62 | except ImportError: | ||
418 | 63 | pass | ||
419 | 64 | |||
420 | 65 | def test_dumps_double(self): | ||
421 | 66 | """ | ||
422 | 67 | Dumping and restoring a L{dbus.types.Double} should result in the | ||
423 | 68 | same value. | ||
424 | 69 | """ | ||
425 | 70 | install() | ||
426 | 71 | try: | ||
427 | 72 | value = Double(480.0, variant_level=1) | ||
428 | 73 | except TypeError: | ||
429 | 74 | value = Double(480.0) | ||
430 | 75 | self.assertAlmostEquals(bpickle.loads(bpickle.dumps(value)), 480.0) | ||
431 | 76 | 0 | ||
432 | === modified file 'landscape/manager/config.py' | |||
433 | --- landscape/manager/config.py 2011-04-14 09:58:34 +0000 | |||
434 | +++ landscape/manager/config.py 2011-12-02 09:56:24 +0000 | |||
435 | @@ -5,7 +5,7 @@ | |||
436 | 5 | 5 | ||
437 | 6 | 6 | ||
438 | 7 | ALL_PLUGINS = ["ProcessKiller", "PackageManager", "UserManager", | 7 | ALL_PLUGINS = ["ProcessKiller", "PackageManager", "UserManager", |
440 | 8 | "ShutdownManager", "Eucalyptus", "AptSources"] | 8 | "ShutdownManager", "Eucalyptus", "AptSources", "HardwareInfo"] |
441 | 9 | 9 | ||
442 | 10 | 10 | ||
443 | 11 | class ManagerConfiguration(Configuration): | 11 | class ManagerConfiguration(Configuration): |
444 | 12 | 12 | ||
445 | === added file 'landscape/manager/hardwareinfo.py' | |||
446 | --- landscape/manager/hardwareinfo.py 1970-01-01 00:00:00 +0000 | |||
447 | +++ landscape/manager/hardwareinfo.py 2011-12-02 09:56:24 +0000 | |||
448 | @@ -0,0 +1,27 @@ | |||
449 | 1 | import os | ||
450 | 2 | |||
451 | 3 | from twisted.internet.utils import getProcessOutput | ||
452 | 4 | |||
453 | 5 | from landscape.manager.plugin import ManagerPlugin | ||
454 | 6 | |||
455 | 7 | |||
456 | 8 | class HardwareInfo(ManagerPlugin): | ||
457 | 9 | """A plugin to retrieve hardware information.""" | ||
458 | 10 | |||
459 | 11 | message_type = "hardware-info" | ||
460 | 12 | run_interval = 60 * 60 * 24 | ||
461 | 13 | run_immediately = True | ||
462 | 14 | command = "/usr/bin/lshw" | ||
463 | 15 | |||
464 | 16 | def run(self): | ||
465 | 17 | return self.registry.broker.call_if_accepted( | ||
466 | 18 | self.message_type, self.send_message) | ||
467 | 19 | |||
468 | 20 | def send_message(self): | ||
469 | 21 | result = getProcessOutput( | ||
470 | 22 | self.command, args=["-xml", "-quiet"], env=os.environ, path=None) | ||
471 | 23 | return result.addCallback(self._got_output) | ||
472 | 24 | |||
473 | 25 | def _got_output(self, output): | ||
474 | 26 | message = {"type": self.message_type, "data": output} | ||
475 | 27 | return self.registry.broker.send_message(message) | ||
476 | 0 | 28 | ||
477 | === modified file 'landscape/manager/tests/test_config.py' | |||
478 | --- landscape/manager/tests/test_config.py 2011-07-05 05:09:11 +0000 | |||
479 | +++ landscape/manager/tests/test_config.py 2011-12-02 09:56:24 +0000 | |||
480 | @@ -12,7 +12,8 @@ | |||
481 | 12 | def test_plugin_factories(self): | 12 | def test_plugin_factories(self): |
482 | 13 | """By default all plugins are enabled.""" | 13 | """By default all plugins are enabled.""" |
483 | 14 | self.assertEqual(["ProcessKiller", "PackageManager", "UserManager", | 14 | self.assertEqual(["ProcessKiller", "PackageManager", "UserManager", |
485 | 15 | "ShutdownManager", "Eucalyptus", "AptSources"], | 15 | "ShutdownManager", "Eucalyptus", "AptSources", |
486 | 16 | "HardwareInfo"], | ||
487 | 16 | ALL_PLUGINS) | 17 | ALL_PLUGINS) |
488 | 17 | self.assertEqual(ALL_PLUGINS, self.config.plugin_factories) | 18 | self.assertEqual(ALL_PLUGINS, self.config.plugin_factories) |
489 | 18 | 19 | ||
490 | 19 | 20 | ||
491 | === added file 'landscape/manager/tests/test_hardwareinfo.py' | |||
492 | --- landscape/manager/tests/test_hardwareinfo.py 1970-01-01 00:00:00 +0000 | |||
493 | +++ landscape/manager/tests/test_hardwareinfo.py 2011-12-02 09:56:24 +0000 | |||
494 | @@ -0,0 +1,29 @@ | |||
495 | 1 | from landscape.tests.helpers import LandscapeTest, ManagerHelper | ||
496 | 2 | |||
497 | 3 | from landscape.manager.hardwareinfo import HardwareInfo | ||
498 | 4 | |||
499 | 5 | |||
500 | 6 | class HardwareInfoTests(LandscapeTest): | ||
501 | 7 | helpers = [ManagerHelper] | ||
502 | 8 | |||
503 | 9 | def setUp(self): | ||
504 | 10 | super(HardwareInfoTests, self).setUp() | ||
505 | 11 | self.info = HardwareInfo() | ||
506 | 12 | self.info.command = "/bin/echo" | ||
507 | 13 | self.manager.add(self.info) | ||
508 | 14 | |||
509 | 15 | service = self.broker_service | ||
510 | 16 | service.message_store.set_accepted_types(["hardware-info"]) | ||
511 | 17 | |||
512 | 18 | def test_message(self): | ||
513 | 19 | """ | ||
514 | 20 | L{HardwareInfo} sends the output of its command when running. | ||
515 | 21 | """ | ||
516 | 22 | deferred = self.info.run() | ||
517 | 23 | |||
518 | 24 | def check(ignored): | ||
519 | 25 | self.assertMessages( | ||
520 | 26 | self.broker_service.message_store.get_pending_messages(), | ||
521 | 27 | [{"data": u"-xml -quiet\n", "type": "hardware-info"}]) | ||
522 | 28 | |||
523 | 29 | return deferred.addCallback(check) | ||
524 | 0 | 30 | ||
525 | === modified file 'landscape/manager/tests/test_service.py' | |||
526 | --- landscape/manager/tests/test_service.py 2011-07-05 05:09:11 +0000 | |||
527 | +++ landscape/manager/tests/test_service.py 2011-12-02 09:56:24 +0000 | |||
528 | @@ -1,4 +1,3 @@ | |||
529 | 1 | from landscape.tests.mocker import ANY | ||
530 | 2 | from landscape.tests.helpers import ( | 1 | from landscape.tests.helpers import ( |
531 | 3 | LandscapeTest, FakeBrokerServiceHelper) | 2 | LandscapeTest, FakeBrokerServiceHelper) |
532 | 4 | from landscape.reactor import FakeReactor | 3 | from landscape.reactor import FakeReactor |
533 | @@ -42,15 +41,10 @@ | |||
534 | 42 | The L{ManagerService.startService} method connects to the broker, | 41 | The L{ManagerService.startService} method connects to the broker, |
535 | 43 | starts the plugins and register the manager as broker client. | 42 | starts the plugins and register the manager as broker client. |
536 | 44 | """ | 43 | """ |
537 | 45 | # FIXME: don't actually run the real register method, because at the | ||
538 | 46 | # moment the UserManager plugin still depends on DBus. We can probably | ||
539 | 47 | # drop this mocking once the AMP migration is completed. | ||
540 | 48 | for plugin in self.service.plugins: | ||
541 | 49 | plugin.register = self.mocker.mock() | ||
542 | 50 | plugin.register(ANY) | ||
543 | 51 | self.mocker.replay() | ||
544 | 52 | |||
545 | 53 | def stop_service(ignored): | 44 | def stop_service(ignored): |
546 | 45 | for plugin in self.service.plugins: | ||
547 | 46 | if getattr(plugin, "stop", None) is not None: | ||
548 | 47 | plugin.stop() | ||
549 | 54 | [connector] = self.broker_service.broker.get_connectors() | 48 | [connector] = self.broker_service.broker.get_connectors() |
550 | 55 | connector.disconnect() | 49 | connector.disconnect() |
551 | 56 | self.service.stopService() | 50 | self.service.stopService() |
552 | 57 | 51 | ||
553 | === modified file 'landscape/message_schemas.py' | |||
554 | --- landscape/message_schemas.py 2011-11-11 12:30:53 +0000 | |||
555 | +++ landscape/message_schemas.py 2011-12-02 09:56:24 +0000 | |||
556 | @@ -99,6 +99,10 @@ | |||
557 | 99 | )}) | 99 | )}) |
558 | 100 | 100 | ||
559 | 101 | 101 | ||
560 | 102 | HARDWARE_INFO = Message("hardware-info", { | ||
561 | 103 | "data": utf8}) | ||
562 | 104 | |||
563 | 105 | |||
564 | 102 | LOAD_AVERAGE = Message("load-average", { | 106 | LOAD_AVERAGE = Message("load-average", { |
565 | 103 | "load-averages": List(Tuple(Int(), Float())), | 107 | "load-averages": List(Tuple(Int(), Float())), |
566 | 104 | }) | 108 | }) |
567 | @@ -392,7 +396,7 @@ | |||
568 | 392 | message_schemas = {} | 396 | message_schemas = {} |
569 | 393 | for schema in [ACTIVE_PROCESS_INFO, COMPUTER_UPTIME, CLIENT_UPTIME, | 397 | for schema in [ACTIVE_PROCESS_INFO, COMPUTER_UPTIME, CLIENT_UPTIME, |
570 | 394 | OPERATION_RESULT, COMPUTER_INFO, DISTRIBUTION_INFO, | 398 | OPERATION_RESULT, COMPUTER_INFO, DISTRIBUTION_INFO, |
572 | 395 | HARDWARE_INVENTORY, LOAD_AVERAGE, MEMORY_INFO, | 399 | HARDWARE_INVENTORY, HARDWARE_INFO, LOAD_AVERAGE, MEMORY_INFO, |
573 | 396 | RESYNCHRONIZE, MOUNT_ACTIVITY, MOUNT_INFO, FREE_SPACE, | 400 | RESYNCHRONIZE, MOUNT_ACTIVITY, MOUNT_INFO, FREE_SPACE, |
574 | 397 | REGISTER, REGISTER_CLOUD_VM, REGISTER_PROVISIONED_MACHINE, | 401 | REGISTER, REGISTER_CLOUD_VM, REGISTER_PROVISIONED_MACHINE, |
575 | 398 | TEMPERATURE, PROCESSOR_INFO, USERS, PACKAGES, PACKAGE_LOCKS, | 402 | TEMPERATURE, PROCESSOR_INFO, USERS, PACKAGES, PACKAGE_LOCKS, |
576 | 399 | 403 | ||
577 | === modified file 'landscape/monitor/config.py' | |||
578 | --- landscape/monitor/config.py 2010-05-04 17:23:45 +0000 | |||
579 | +++ landscape/monitor/config.py 2011-12-02 09:56:24 +0000 | |||
580 | @@ -1,11 +1,10 @@ | |||
581 | 1 | from landscape.deployment import Configuration | 1 | from landscape.deployment import Configuration |
582 | 2 | 2 | ||
583 | 3 | 3 | ||
589 | 4 | ALL_PLUGINS = ["ActiveProcessInfo", "ComputerInfo", "HardwareInventory", | 4 | ALL_PLUGINS = ["ActiveProcessInfo", "ComputerInfo", "LoadAverage", |
590 | 5 | "LoadAverage", "MemoryInfo", "MountInfo", "ProcessorInfo", | 5 | "MemoryInfo", "MountInfo", "ProcessorInfo", "Temperature", |
591 | 6 | "Temperature", "PackageMonitor", "UserMonitor", | 6 | "PackageMonitor", "UserMonitor", "RebootRequired", |
592 | 7 | "RebootRequired", "AptPreferences", "NetworkActivity", | 7 | "AptPreferences", "NetworkActivity", "NetworkDevice"] |
588 | 8 | "NetworkDevice"] | ||
593 | 9 | 8 | ||
594 | 10 | 9 | ||
595 | 11 | class MonitorConfiguration(Configuration): | 10 | class MonitorConfiguration(Configuration): |
596 | 12 | 11 | ||
597 | === removed file 'landscape/monitor/hardwareinventory.py' | |||
598 | --- landscape/monitor/hardwareinventory.py 2011-01-28 09:37:10 +0000 | |||
599 | +++ landscape/monitor/hardwareinventory.py 1970-01-01 00:00:00 +0000 | |||
600 | @@ -1,114 +0,0 @@ | |||
601 | 1 | import logging | ||
602 | 2 | |||
603 | 3 | from twisted.internet.defer import succeed | ||
604 | 4 | |||
605 | 5 | from landscape.lib.log import log_failure | ||
606 | 6 | |||
607 | 7 | from landscape.diff import diff | ||
608 | 8 | from landscape.monitor.plugin import MonitorPlugin | ||
609 | 9 | |||
610 | 10 | |||
611 | 11 | class HardwareInventory(MonitorPlugin): | ||
612 | 12 | |||
613 | 13 | persist_name = "hardware-inventory" | ||
614 | 14 | |||
615 | 15 | def __init__(self, hal_manager=None): | ||
616 | 16 | super(HardwareInventory, self).__init__() | ||
617 | 17 | self._persist_sets = [] | ||
618 | 18 | self._persist_removes = [] | ||
619 | 19 | self.enabled = True | ||
620 | 20 | try: | ||
621 | 21 | from landscape.hal import HALManager | ||
622 | 22 | except ImportError: | ||
623 | 23 | self.enabled = False | ||
624 | 24 | else: | ||
625 | 25 | self._hal_manager = hal_manager or HALManager() | ||
626 | 26 | |||
627 | 27 | def register(self, manager): | ||
628 | 28 | if not self.enabled: | ||
629 | 29 | return | ||
630 | 30 | super(HardwareInventory, self).register(manager) | ||
631 | 31 | self.call_on_accepted("hardware-inventory", self.exchange, True) | ||
632 | 32 | |||
633 | 33 | def send_message(self, urgent): | ||
634 | 34 | devices = self.create_message() | ||
635 | 35 | if devices: | ||
636 | 36 | message = {"type": "hardware-inventory", "devices": devices} | ||
637 | 37 | result = self.registry.broker.send_message(message, urgent=urgent) | ||
638 | 38 | result.addCallback(self.persist_data) | ||
639 | 39 | result.addErrback(log_failure) | ||
640 | 40 | logging.info("Queueing a message with hardware-inventory " | ||
641 | 41 | "information.") | ||
642 | 42 | else: | ||
643 | 43 | result = succeed(None) | ||
644 | 44 | return result | ||
645 | 45 | |||
646 | 46 | def exchange(self, urgent=False): | ||
647 | 47 | if not self.enabled: | ||
648 | 48 | return | ||
649 | 49 | return self.registry.broker.call_if_accepted("hardware-inventory", | ||
650 | 50 | self.send_message, urgent) | ||
651 | 51 | |||
652 | 52 | def persist_data(self, message_id): | ||
653 | 53 | for key, udi, value in self._persist_sets: | ||
654 | 54 | self._persist.set((key, udi), value) | ||
655 | 55 | for key in self._persist_removes: | ||
656 | 56 | self._persist.remove(key) | ||
657 | 57 | del self._persist_sets[:] | ||
658 | 58 | del self._persist_removes[:] | ||
659 | 59 | # This forces the registry to write the persistent store to disk | ||
660 | 60 | # This means that the persistent data reflects the state of the | ||
661 | 61 | # messages sent. | ||
662 | 62 | self.registry.flush() | ||
663 | 63 | |||
664 | 64 | def create_message(self): | ||
665 | 65 | # FIXME Using persist to keep track of changes here uses a | ||
666 | 66 | # fair amount of memory. On my machine a rough test seemed to | ||
667 | 67 | # indicate that memory usage grew by 1.3mb, about 12% of the | ||
668 | 68 | # overall process size. Look here to save memory. | ||
669 | 69 | del self._persist_sets[:] | ||
670 | 70 | del self._persist_removes[:] | ||
671 | 71 | devices = [] | ||
672 | 72 | previous_devices = self._persist.get("devices", {}) | ||
673 | 73 | current_devices = set() | ||
674 | 74 | |||
675 | 75 | for device in self._hal_manager.get_devices(): | ||
676 | 76 | previous_properties = previous_devices.get(device.udi) | ||
677 | 77 | if not previous_properties: | ||
678 | 78 | devices.append(("create", device.properties)) | ||
679 | 79 | elif previous_properties != device.properties: | ||
680 | 80 | creates, updates, deletes = diff(previous_properties, | ||
681 | 81 | device.properties) | ||
682 | 82 | devices.append(("update", device.udi, | ||
683 | 83 | creates, updates, deletes)) | ||
684 | 84 | current_devices.add(device.udi) | ||
685 | 85 | self._persist_sets.append( | ||
686 | 86 | ("devices", device.udi, device.properties)) | ||
687 | 87 | |||
688 | 88 | items_with_parents = {} | ||
689 | 89 | deleted_devices = set() | ||
690 | 90 | for udi, value in previous_devices.iteritems(): | ||
691 | 91 | if udi not in current_devices: | ||
692 | 92 | if "info.parent" in value: | ||
693 | 93 | items_with_parents[udi] = value["info.parent"] | ||
694 | 94 | deleted_devices.add(udi) | ||
695 | 95 | |||
696 | 96 | # We remove the deleted devices from our persistent store it's | ||
697 | 97 | # only the information we're sending to the server that we're | ||
698 | 98 | # compressing. | ||
699 | 99 | for udi in deleted_devices: | ||
700 | 100 | self._persist_removes.append(("devices", udi)) | ||
701 | 101 | |||
702 | 102 | # We can now flatten the list of devices we send to the server | ||
703 | 103 | # For each of the items_with_parents, if both the item and it's parent | ||
704 | 104 | # are in the deleted_devices set, then we can remove this item from the | ||
705 | 105 | # set. | ||
706 | 106 | minimal_deleted_devices = deleted_devices.copy() | ||
707 | 107 | for child, parent in items_with_parents.iteritems(): | ||
708 | 108 | if child in deleted_devices and parent in deleted_devices: | ||
709 | 109 | minimal_deleted_devices.remove(child) | ||
710 | 110 | # We now build the deleted devices message | ||
711 | 111 | for udi in minimal_deleted_devices: | ||
712 | 112 | devices.append(("delete", udi)) | ||
713 | 113 | |||
714 | 114 | return devices | ||
715 | 115 | 0 | ||
716 | === modified file 'landscape/monitor/mountinfo.py' | |||
717 | --- landscape/monitor/mountinfo.py 2011-04-08 09:01:42 +0000 | |||
718 | +++ landscape/monitor/mountinfo.py 2011-12-02 09:56:24 +0000 | |||
719 | @@ -15,7 +15,7 @@ | |||
720 | 15 | 15 | ||
721 | 16 | def __init__(self, interval=300, monitor_interval=60 * 60, | 16 | def __init__(self, interval=300, monitor_interval=60 * 60, |
722 | 17 | mounts_file="/proc/mounts", create_time=time.time, | 17 | mounts_file="/proc/mounts", create_time=time.time, |
724 | 18 | statvfs=None, hal_manager=None, mtab_file="/etc/mtab"): | 18 | statvfs=None, mtab_file="/etc/mtab"): |
725 | 19 | self.run_interval = interval | 19 | self.run_interval = interval |
726 | 20 | self._monitor_interval = monitor_interval | 20 | self._monitor_interval = monitor_interval |
727 | 21 | self._create_time = create_time | 21 | self._create_time = create_time |
728 | @@ -29,12 +29,6 @@ | |||
729 | 29 | self._mount_info = [] | 29 | self._mount_info = [] |
730 | 30 | self._mount_info_to_persist = None | 30 | self._mount_info_to_persist = None |
731 | 31 | try: | 31 | try: |
732 | 32 | from landscape.hal import HALManager | ||
733 | 33 | except ImportError: | ||
734 | 34 | self._hal_manager = hal_manager | ||
735 | 35 | else: | ||
736 | 36 | self._hal_manager = hal_manager or HALManager() | ||
737 | 37 | try: | ||
738 | 38 | from gi.repository import GUdev | 32 | from gi.repository import GUdev |
739 | 39 | except ImportError: | 33 | except ImportError: |
740 | 40 | self._gudev_client = None | 34 | self._gudev_client = None |
741 | @@ -122,9 +116,7 @@ | |||
742 | 122 | current_mount_points.add(mount_point) | 116 | current_mount_points.add(mount_point) |
743 | 123 | 117 | ||
744 | 124 | def _get_removable_devices(self): | 118 | def _get_removable_devices(self): |
748 | 125 | if self._hal_manager is not None: | 119 | if self._gudev_client is not None: |
746 | 126 | return self._get_hal_removable_devices() | ||
747 | 127 | elif self._gudev_client is not None: | ||
749 | 128 | return self._get_udev_removable_devices() | 120 | return self._get_udev_removable_devices() |
750 | 129 | else: | 121 | else: |
751 | 130 | return set() | 122 | return set() |
752 | @@ -138,61 +130,6 @@ | |||
753 | 138 | return False | 130 | return False |
754 | 139 | return is_removable() | 131 | return is_removable() |
755 | 140 | 132 | ||
756 | 141 | def _get_hal_removable_devices(self): | ||
757 | 142 | block_devices = {} # {udi: [device, ...]} | ||
758 | 143 | children = {} # {parent_udi: [child_udi, ...]} | ||
759 | 144 | removable = set() | ||
760 | 145 | |||
761 | 146 | # We walk the list of devices building up a dictionary of all removable | ||
762 | 147 | # devices, and a mapping of {UDI => [block devices]} | ||
763 | 148 | # We differentiate between devices that we definitely know are | ||
764 | 149 | # removable and devices that _may_ be removable, depending on their | ||
765 | 150 | # parent device, e.g. /dev/sdb1 isn't flagged as removable, but | ||
766 | 151 | # /dev/sdb may well be removable. | ||
767 | 152 | |||
768 | 153 | # Unfortunately, HAL doesn't guarantee the order of the devices | ||
769 | 154 | # returned from get_devices(), so we may not know that a parent device | ||
770 | 155 | # is removable when we find it's first child. | ||
771 | 156 | devices = self._hal_manager.get_devices() | ||
772 | 157 | for device in devices: | ||
773 | 158 | block_device = device.properties.get("block.device") | ||
774 | 159 | if block_device: | ||
775 | 160 | if device.properties.get("storage.removable"): | ||
776 | 161 | removable.add(device.udi) | ||
777 | 162 | |||
778 | 163 | try: | ||
779 | 164 | block_devices[device.udi].append(block_device) | ||
780 | 165 | except KeyError: | ||
781 | 166 | block_devices[device.udi] = [block_device] | ||
782 | 167 | |||
783 | 168 | parent_udi = device.properties.get("info.parent") | ||
784 | 169 | if parent_udi is not None: | ||
785 | 170 | try: | ||
786 | 171 | children[parent_udi].append(device.udi) | ||
787 | 172 | except KeyError: | ||
788 | 173 | children[parent_udi] = [device.udi] | ||
789 | 174 | |||
790 | 175 | # Propagate the removable flag from each node all the way to | ||
791 | 176 | # its leaf children. | ||
792 | 177 | updated = True | ||
793 | 178 | while updated: | ||
794 | 179 | updated = False | ||
795 | 180 | for parent_udi in children: | ||
796 | 181 | if parent_udi in removable: | ||
797 | 182 | for child_udi in children[parent_udi]: | ||
798 | 183 | if child_udi not in removable: | ||
799 | 184 | removable.add(child_udi) | ||
800 | 185 | updated = True | ||
801 | 186 | |||
802 | 187 | # We've now seen _all_ devices, and have the definitive list of | ||
803 | 188 | # removable UDIs, so we can now find all the removable devices in the | ||
804 | 189 | # system. | ||
805 | 190 | removable_devices = set() | ||
806 | 191 | for udi in removable: | ||
807 | 192 | removable_devices.update(block_devices[udi]) | ||
808 | 193 | |||
809 | 194 | return removable_devices | ||
810 | 195 | |||
811 | 196 | def _get_mount_info(self): | 133 | def _get_mount_info(self): |
812 | 197 | """Generator yields local mount points worth recording data for.""" | 134 | """Generator yields local mount points worth recording data for.""" |
813 | 198 | removable_devices = self._get_removable_devices() | 135 | removable_devices = self._get_removable_devices() |
814 | 199 | 136 | ||
815 | === removed file 'landscape/monitor/tests/test_hardwareinventory.py' | |||
816 | --- landscape/monitor/tests/test_hardwareinventory.py 2011-07-05 05:09:11 +0000 | |||
817 | +++ landscape/monitor/tests/test_hardwareinventory.py 1970-01-01 00:00:00 +0000 | |||
818 | @@ -1,273 +0,0 @@ | |||
819 | 1 | from twisted.internet.defer import fail, succeed | ||
820 | 2 | |||
821 | 3 | from landscape.monitor.hardwareinventory import HardwareInventory | ||
822 | 4 | from landscape.tests.test_hal import MockHALManager, MockRealHALDevice | ||
823 | 5 | from landscape.tests.helpers import LandscapeTest, MonitorHelper | ||
824 | 6 | from landscape.tests.mocker import ANY | ||
825 | 7 | from landscape.message_schemas import HARDWARE_INVENTORY | ||
826 | 8 | |||
827 | 9 | |||
828 | 10 | class HardwareInventoryTest(LandscapeTest): | ||
829 | 11 | |||
830 | 12 | helpers = [MonitorHelper] | ||
831 | 13 | |||
832 | 14 | def setUp(self): | ||
833 | 15 | super(HardwareInventoryTest, self).setUp() | ||
834 | 16 | self.mstore.set_accepted_types(["hardware-inventory"]) | ||
835 | 17 | devices = [MockRealHALDevice({u"info.udi": u"wubble", | ||
836 | 18 | u"info.product": u"Wubble"}), | ||
837 | 19 | MockRealHALDevice({u"info.udi": u"ooga", | ||
838 | 20 | u"info.product": u"Ooga"})] | ||
839 | 21 | self.hal_manager = MockHALManager(devices) | ||
840 | 22 | self.plugin = HardwareInventory(hal_manager=self.hal_manager) | ||
841 | 23 | self.monitor.add(self.plugin) | ||
842 | 24 | |||
843 | 25 | def assertSchema(self, devices): | ||
844 | 26 | full_message = {"type": "hardware-inventory", "devices": devices} | ||
845 | 27 | self.assertEqual(HARDWARE_INVENTORY.coerce(full_message), | ||
846 | 28 | full_message) | ||
847 | 29 | |||
848 | 30 | def test_hal_devices(self): | ||
849 | 31 | """ | ||
850 | 32 | The first time the plugin runs it should report information | ||
851 | 33 | about all HAL devices found on the system. Every UDI provided | ||
852 | 34 | by HAL should be present in the devices list as is from HAL. | ||
853 | 35 | """ | ||
854 | 36 | message = self.plugin.create_message() | ||
855 | 37 | actual_udis = [part[1][u"info.udi"] for part in message] | ||
856 | 38 | expected_udis = [device.udi for device | ||
857 | 39 | in self.hal_manager.get_devices()] | ||
858 | 40 | self.assertEqual(set(actual_udis), set(expected_udis)) | ||
859 | 41 | |||
860 | 42 | def test_first_message(self): | ||
861 | 43 | """ | ||
862 | 44 | The first time the plugin runs it should report information | ||
863 | 45 | about all HAL devices found on the system. All new devices | ||
864 | 46 | will be reported with 'create' actions. | ||
865 | 47 | """ | ||
866 | 48 | message = self.plugin.create_message() | ||
867 | 49 | actions = [part[0] for part in message] | ||
868 | 50 | self.assertEqual(set(actions), set(["create"])) | ||
869 | 51 | self.assertSchema(message) | ||
870 | 52 | |||
871 | 53 | def test_no_changes(self): | ||
872 | 54 | """ | ||
873 | 55 | Messages should not be created if hardware information is | ||
874 | 56 | unchanged since the last server exchange. | ||
875 | 57 | """ | ||
876 | 58 | self.plugin.exchange() | ||
877 | 59 | self.assertNotEquals(len(self.mstore.get_pending_messages()), 0) | ||
878 | 60 | |||
879 | 61 | messages = self.mstore.get_pending_messages() | ||
880 | 62 | self.plugin.exchange() | ||
881 | 63 | self.assertEqual(self.mstore.get_pending_messages(), messages) | ||
882 | 64 | |||
883 | 65 | def test_update(self): | ||
884 | 66 | """ | ||
885 | 67 | If a change is detected for a device that was previously | ||
886 | 68 | reported to the server, the changed device should be reported | ||
887 | 69 | with an 'update' action. Property changes are reported at a | ||
888 | 70 | key/value pair level. | ||
889 | 71 | """ | ||
890 | 72 | self.hal_manager.devices = [ | ||
891 | 73 | MockRealHALDevice({u"info.udi": u"wubble", | ||
892 | 74 | u"info.product": u"Wubble"})] | ||
893 | 75 | registry_mocker = self.mocker.replace(self.plugin.registry) | ||
894 | 76 | registry_mocker.flush() | ||
895 | 77 | self.mocker.count(2) | ||
896 | 78 | self.mocker.result(None) | ||
897 | 79 | self.mocker.replay() | ||
898 | 80 | message = self.plugin.create_message() | ||
899 | 81 | self.plugin.persist_data(None) | ||
900 | 82 | self.assertEqual(message, [("create", {u"info.udi": u"wubble", | ||
901 | 83 | u"info.product": u"Wubble"})]) | ||
902 | 84 | |||
903 | 85 | self.hal_manager.devices[0] = MockRealHALDevice( | ||
904 | 86 | {u"info.udi": u"wubble", u"info.product": u"Ooga"}) | ||
905 | 87 | message = self.plugin.create_message() | ||
906 | 88 | self.plugin.persist_data(None) | ||
907 | 89 | self.assertEqual(message, [("update", u"wubble", | ||
908 | 90 | {}, {u"info.product": u"Ooga"}, {})]) | ||
909 | 91 | self.assertSchema(message) | ||
910 | 92 | self.assertEqual(self.plugin.create_message(), []) | ||
911 | 93 | |||
912 | 94 | def test_update_list(self): | ||
913 | 95 | """ | ||
914 | 96 | An update should be sent to the server when a strlist device | ||
915 | 97 | property changes. No updates should be sent if a device is | ||
916 | 98 | unchanged. | ||
917 | 99 | """ | ||
918 | 100 | self.hal_manager.devices = [ | ||
919 | 101 | MockRealHALDevice({u"info.udi": u"wubble", | ||
920 | 102 | u"info.product": u"Wubble", | ||
921 | 103 | u"info.capabilities": [u"foo", u"bar"]})] | ||
922 | 104 | |||
923 | 105 | message = self.plugin.create_message() | ||
924 | 106 | self.plugin.persist_data(None) | ||
925 | 107 | self.assertEqual(message, [("create", | ||
926 | 108 | {u"info.udi": u"wubble", | ||
927 | 109 | u"info.product": u"Wubble", | ||
928 | 110 | u"info.capabilities": [u"foo", u"bar"]}), | ||
929 | 111 | ]) | ||
930 | 112 | |||
931 | 113 | self.assertSchema(message) | ||
932 | 114 | |||
933 | 115 | self.hal_manager.devices[0] = MockRealHALDevice( | ||
934 | 116 | {u"info.udi": u"wubble", u"info.product": u"Wubble", | ||
935 | 117 | u"info.capabilities": [u"foo"]}) | ||
936 | 118 | message = self.plugin.create_message() | ||
937 | 119 | self.plugin.persist_data(None) | ||
938 | 120 | self.assertEqual(message, [("update", u"wubble", | ||
939 | 121 | {}, {u"info.capabilities": [u"foo"]}, {}), | ||
940 | 122 | ]) | ||
941 | 123 | self.assertSchema(message) | ||
942 | 124 | |||
943 | 125 | self.assertEqual(self.plugin.create_message(), []) | ||
944 | 126 | |||
945 | 127 | def test_update_complex(self): | ||
946 | 128 | """ | ||
947 | 129 | The 'update' action reports property create, update and | ||
948 | 130 | delete changes. | ||
949 | 131 | """ | ||
950 | 132 | self.hal_manager.devices = [ | ||
951 | 133 | MockRealHALDevice({u"info.udi": u"wubble", | ||
952 | 134 | u"info.product": u"Wubble", | ||
953 | 135 | u"linux.acpi_type": 11})] | ||
954 | 136 | |||
955 | 137 | message = self.plugin.create_message() | ||
956 | 138 | self.plugin.persist_data(None) | ||
957 | 139 | self.assertEqual(message, [("create", {u"info.udi": u"wubble", | ||
958 | 140 | u"info.product": u"Wubble", | ||
959 | 141 | u"linux.acpi_type": 11})]) | ||
960 | 142 | |||
961 | 143 | self.hal_manager.devices[0] = MockRealHALDevice( | ||
962 | 144 | {u"info.udi": u"wubble", u"info.product": u"Ooga", | ||
963 | 145 | u"info.category": u"unittest"}) | ||
964 | 146 | message = self.plugin.create_message() | ||
965 | 147 | self.plugin.persist_data(None) | ||
966 | 148 | self.assertEqual(message, [("update", u"wubble", | ||
967 | 149 | {u"info.category": u"unittest"}, | ||
968 | 150 | {u"info.product": u"Ooga"}, | ||
969 | 151 | {u"linux.acpi_type": 11})]) | ||
970 | 152 | self.assertSchema(message) | ||
971 | 153 | |||
972 | 154 | self.assertEqual(self.plugin.create_message(), []) | ||
973 | 155 | |||
974 | 156 | def test_delete(self): | ||
975 | 157 | """ | ||
976 | 158 | If a device that was previously reported is no longer present | ||
977 | 159 | in a system a device entry should be created with a 'delete' | ||
978 | 160 | action. | ||
979 | 161 | """ | ||
980 | 162 | self.hal_manager.devices = [ | ||
981 | 163 | MockRealHALDevice({u"info.udi": u"wubble", | ||
982 | 164 | u"info.product": u"Wubble"}), | ||
983 | 165 | MockRealHALDevice({u"info.udi": u"ooga", | ||
984 | 166 | u"info.product": u"Ooga"})] | ||
985 | 167 | |||
986 | 168 | message = self.plugin.create_message() | ||
987 | 169 | self.plugin.persist_data(None) | ||
988 | 170 | self.assertEqual(message, [("create", {u"info.udi": u"wubble", | ||
989 | 171 | u"info.product": u"Wubble"}), | ||
990 | 172 | ("create", {u"info.udi": u"ooga", | ||
991 | 173 | u"info.product": u"Ooga"})]) | ||
992 | 174 | self.assertSchema(message) | ||
993 | 175 | |||
994 | 176 | self.hal_manager.devices.pop(1) | ||
995 | 177 | message = self.plugin.create_message() | ||
996 | 178 | self.plugin.persist_data(None) | ||
997 | 179 | self.assertEqual(message, [("delete", u"ooga")]) | ||
998 | 180 | self.assertSchema(message) | ||
999 | 181 | self.assertEqual(self.plugin.create_message(), []) | ||
1000 | 182 | |||
1001 | 183 | def test_minimal_delete(self): | ||
1002 | 184 | self.hal_manager.devices = [ | ||
1003 | 185 | MockRealHALDevice({u"info.udi": u"wubble", | ||
1004 | 186 | u"block.device": u"/dev/scd", | ||
1005 | 187 | u"storage.removable": True}), | ||
1006 | 188 | MockRealHALDevice({u"info.udi": u"wubble0", | ||
1007 | 189 | u"block.device": u"/dev/scd0", | ||
1008 | 190 | u"info.parent": u"wubble"}), | ||
1009 | 191 | MockRealHALDevice({u"info.udi": u"wubble1", | ||
1010 | 192 | u"block.device": u"/dev/scd1", | ||
1011 | 193 | u"info.parent": u"wubble"}), | ||
1012 | 194 | MockRealHALDevice({u"info.udi": u"wubble2", | ||
1013 | 195 | u"block.device": u"/dev/scd1", | ||
1014 | 196 | u"info.parent": u"wubble0"}), | ||
1015 | 197 | MockRealHALDevice({u"info.udi": u"wubble3", | ||
1016 | 198 | u"block.device": u"/dev/scd1", | ||
1017 | 199 | u"info.parent": u"wubble2"})] | ||
1018 | 200 | |||
1019 | 201 | message = self.plugin.create_message() | ||
1020 | 202 | self.plugin.persist_data(None) | ||
1021 | 203 | |||
1022 | 204 | del self.hal_manager.devices[:] | ||
1023 | 205 | |||
1024 | 206 | message = self.plugin.create_message() | ||
1025 | 207 | self.plugin.persist_data(None) | ||
1026 | 208 | |||
1027 | 209 | self.assertEqual(message, [("delete", u"wubble")]) | ||
1028 | 210 | self.assertEqual(self.plugin.create_message(), []) | ||
1029 | 211 | |||
1030 | 212 | def test_resynchronize(self): | ||
1031 | 213 | """ | ||
1032 | 214 | If a 'resynchronize' reactor event is fired, the plugin should | ||
1033 | 215 | send a message that contains all data as if the server has | ||
1034 | 216 | none. | ||
1035 | 217 | """ | ||
1036 | 218 | self.plugin.exchange() | ||
1037 | 219 | self.reactor.fire("resynchronize") | ||
1038 | 220 | self.plugin.exchange() | ||
1039 | 221 | |||
1040 | 222 | messages = self.mstore.get_pending_messages() | ||
1041 | 223 | self.assertEqual(len(messages), 2) | ||
1042 | 224 | self.assertEqual(messages[0]["devices"], messages[1]["devices"]) | ||
1043 | 225 | |||
1044 | 226 | def test_call_on_accepted(self): | ||
1045 | 227 | remote_broker_mock = self.mocker.replace(self.remote) | ||
1046 | 228 | remote_broker_mock.send_message(ANY, urgent=True) | ||
1047 | 229 | self.mocker.result(succeed(None)) | ||
1048 | 230 | self.mocker.replay() | ||
1049 | 231 | |||
1050 | 232 | self.reactor.fire(("message-type-acceptance-changed", | ||
1051 | 233 | "hardware-inventory"), | ||
1052 | 234 | True) | ||
1053 | 235 | |||
1054 | 236 | def test_no_message_if_not_accepted(self): | ||
1055 | 237 | """ | ||
1056 | 238 | Don't add any messages at all if the broker isn't currently | ||
1057 | 239 | accepting their type. | ||
1058 | 240 | """ | ||
1059 | 241 | self.mstore.set_accepted_types([]) | ||
1060 | 242 | self.reactor.advance(self.monitor.step_size * 2) | ||
1061 | 243 | self.monitor.exchange() | ||
1062 | 244 | |||
1063 | 245 | self.mstore.set_accepted_types(["hardware-inventory"]) | ||
1064 | 246 | self.assertMessages(list(self.mstore.get_pending_messages()), []) | ||
1065 | 247 | |||
1066 | 248 | def test_do_not_persist_changes_when_send_message_fails(self): | ||
1067 | 249 | """ | ||
1068 | 250 | When the plugin is run it persists data that it uses on | ||
1069 | 251 | subsequent checks to calculate the delta to send. It should | ||
1070 | 252 | only persist data when the broker confirms that the message | ||
1071 | 253 | sent by the plugin has been sent. | ||
1072 | 254 | """ | ||
1073 | 255 | |||
1074 | 256 | class MyException(Exception): | ||
1075 | 257 | pass | ||
1076 | 258 | |||
1077 | 259 | self.log_helper.ignore_errors(MyException) | ||
1078 | 260 | |||
1079 | 261 | broker_mock = self.mocker.replace(self.monitor.broker) | ||
1080 | 262 | broker_mock.send_message(ANY, urgent=ANY) | ||
1081 | 263 | self.mocker.result(fail(MyException())) | ||
1082 | 264 | self.mocker.replay() | ||
1083 | 265 | |||
1084 | 266 | message = self.plugin.create_message() | ||
1085 | 267 | |||
1086 | 268 | def assert_message(message_id): | ||
1087 | 269 | self.assertEqual(message, self.plugin.create_message()) | ||
1088 | 270 | |||
1089 | 271 | result = self.plugin.exchange() | ||
1090 | 272 | result.addCallback(assert_message) | ||
1091 | 273 | return result | ||
1092 | 274 | 0 | ||
1093 | === modified file 'landscape/monitor/tests/test_mountinfo.py' | |||
1094 | --- landscape/monitor/tests/test_mountinfo.py 2011-07-05 05:09:11 +0000 | |||
1095 | +++ landscape/monitor/tests/test_mountinfo.py 2011-12-02 09:56:24 +0000 | |||
1096 | @@ -3,7 +3,6 @@ | |||
1097 | 3 | from twisted.internet.defer import succeed | 3 | from twisted.internet.defer import succeed |
1098 | 4 | 4 | ||
1099 | 5 | from landscape.monitor.mountinfo import MountInfo | 5 | from landscape.monitor.mountinfo import MountInfo |
1100 | 6 | from landscape.tests.test_hal import MockHALManager, MockRealHALDevice | ||
1101 | 7 | from landscape.tests.helpers import LandscapeTest, mock_counter, MonitorHelper | 6 | from landscape.tests.helpers import LandscapeTest, mock_counter, MonitorHelper |
1102 | 8 | from landscape.tests.mocker import ANY | 7 | from landscape.tests.mocker import ANY |
1103 | 9 | 8 | ||
1104 | @@ -22,8 +21,6 @@ | |||
1105 | 22 | self.log_helper.ignore_errors("Typelib file for namespace") | 21 | self.log_helper.ignore_errors("Typelib file for namespace") |
1106 | 23 | 22 | ||
1107 | 24 | def get_mount_info(self, *args, **kwargs): | 23 | def get_mount_info(self, *args, **kwargs): |
1108 | 25 | hal_devices = kwargs.pop("hal_devices", []) | ||
1109 | 26 | kwargs["hal_manager"] = MockHALManager(hal_devices) | ||
1110 | 27 | if "statvfs" not in kwargs: | 24 | if "statvfs" not in kwargs: |
1111 | 28 | kwargs["statvfs"] = lambda path: (0,) * 10 | 25 | kwargs["statvfs"] = lambda path: (0,) * 10 |
1112 | 29 | return MountInfo(*args, **kwargs) | 26 | return MountInfo(*args, **kwargs) |
1113 | @@ -323,51 +320,8 @@ | |||
1114 | 323 | message = plugin.create_mount_info_message() | 320 | message = plugin.create_mount_info_message() |
1115 | 324 | self.assertEqual(message, None) | 321 | self.assertEqual(message, None) |
1116 | 325 | 322 | ||
1117 | 326 | def test_ignore_removable_partitions(self): | ||
1118 | 327 | """ | ||
1119 | 328 | Partitions on removable devices don't directly report | ||
1120 | 329 | storage.removable : True, but they do point to their parent and the | ||
1121 | 330 | parent will be marked removable if appropriate. | ||
1122 | 331 | """ | ||
1123 | 332 | devices = [MockRealHALDevice({"info.udi": "wubble", | ||
1124 | 333 | "block.device": "/dev/scd", | ||
1125 | 334 | "storage.removable": True}), | ||
1126 | 335 | MockRealHALDevice({"info.udi": "wubble0", | ||
1127 | 336 | "block.device": "/dev/scd0", | ||
1128 | 337 | "info.parent": "wubble"})] | ||
1129 | 338 | |||
1130 | 339 | filename = self.makeFile("""\ | ||
1131 | 340 | /dev/scd0 /media/Xerox_M750 iso9660 ro,nosuid,nodev,uid=1000,utf8 0 0 | ||
1132 | 341 | """) | ||
1133 | 342 | plugin = self.get_mount_info(mounts_file=filename, hal_devices=devices, | ||
1134 | 343 | mtab_file=filename) | ||
1135 | 344 | self.monitor.add(plugin) | ||
1136 | 345 | plugin.run() | ||
1137 | 346 | |||
1138 | 347 | message = plugin.create_mount_info_message() | ||
1139 | 348 | self.assertEqual(message, None) | ||
1140 | 349 | |||
1141 | 350 | def test_ignore_removable_devices(self): | 323 | def test_ignore_removable_devices(self): |
1142 | 351 | """ | 324 | """ |
1143 | 352 | The mount info plugin should only report data about | ||
1144 | 353 | non-removable devices. | ||
1145 | 354 | """ | ||
1146 | 355 | devices = [MockRealHALDevice({"info.udi": "wubble", | ||
1147 | 356 | "block.device": "/dev/scd0", | ||
1148 | 357 | "storage.removable": True})] | ||
1149 | 358 | filename = self.makeFile("""\ | ||
1150 | 359 | /dev/scd0 /media/Xerox_M750 iso9660 ro,nosuid,nodev,uid=1000,utf8 0 0 | ||
1151 | 360 | """) | ||
1152 | 361 | plugin = self.get_mount_info(mounts_file=filename, hal_devices=devices, | ||
1153 | 362 | mtab_file=filename) | ||
1154 | 363 | self.monitor.add(plugin) | ||
1155 | 364 | plugin.run() | ||
1156 | 365 | |||
1157 | 366 | message = plugin.create_mount_info_message() | ||
1158 | 367 | self.assertEqual(message, None) | ||
1159 | 368 | |||
1160 | 369 | def test_ignore_removable_devices_gudev(self): | ||
1161 | 370 | """ | ||
1162 | 371 | The mount info plugin uses gudev to retrieve removable information | 325 | The mount info plugin uses gudev to retrieve removable information |
1163 | 372 | about devices. | 326 | about devices. |
1164 | 373 | """ | 327 | """ |
1165 | @@ -376,7 +330,6 @@ | |||
1166 | 376 | """) | 330 | """) |
1167 | 377 | plugin = self.get_mount_info(mounts_file=filename, | 331 | plugin = self.get_mount_info(mounts_file=filename, |
1168 | 378 | mtab_file=filename) | 332 | mtab_file=filename) |
1169 | 379 | plugin._hal_manager = None | ||
1170 | 380 | 333 | ||
1171 | 381 | class MockDevice(object): | 334 | class MockDevice(object): |
1172 | 382 | def get_sysfs_attr_as_boolean(self, attr): | 335 | def get_sysfs_attr_as_boolean(self, attr): |
1173 | @@ -395,35 +348,6 @@ | |||
1174 | 395 | message = plugin.create_mount_info_message() | 348 | message = plugin.create_mount_info_message() |
1175 | 396 | self.assertEqual(message, None) | 349 | self.assertEqual(message, None) |
1176 | 397 | 350 | ||
1177 | 398 | def test_ignore_multiparented_removable_devices(self): | ||
1178 | 399 | """ | ||
1179 | 400 | Some removable devices might be the grand-children of a device that is | ||
1180 | 401 | marked as "storage.removable". | ||
1181 | 402 | """ | ||
1182 | 403 | devices = [MockRealHALDevice({"info.udi": "wubble", | ||
1183 | 404 | "block.device": "/dev/scd", | ||
1184 | 405 | "storage.removable": True}), | ||
1185 | 406 | MockRealHALDevice({"info.udi": "wubble0", | ||
1186 | 407 | "block.device": "/dev/scd0", | ||
1187 | 408 | "info.parent": "wubble"}), | ||
1188 | 409 | MockRealHALDevice({"info.udi": "wubble0a", | ||
1189 | 410 | "block.device": "/dev/scd0a", | ||
1190 | 411 | "info.parent": "wubble0"}), | ||
1191 | 412 | MockRealHALDevice({"info.udi": "wubble0b", | ||
1192 | 413 | "block.device": "/dev/scd0b", | ||
1193 | 414 | "info.parent": "wubble0"})] | ||
1194 | 415 | |||
1195 | 416 | filename = self.makeFile("""\ | ||
1196 | 417 | /dev/scd0a /media/Xerox_M750 iso9660 ro,nosuid,nodev,uid=1000,utf8 0 0 | ||
1197 | 418 | """) | ||
1198 | 419 | plugin = self.get_mount_info(mounts_file=filename, hal_devices=devices, | ||
1199 | 420 | mtab_file=filename) | ||
1200 | 421 | self.monitor.add(plugin) | ||
1201 | 422 | plugin.run() | ||
1202 | 423 | |||
1203 | 424 | message = plugin.create_mount_info_message() | ||
1204 | 425 | self.assertEqual(message, None) | ||
1205 | 426 | |||
1206 | 427 | def test_sample_free_space(self): | 351 | def test_sample_free_space(self): |
1207 | 428 | """Test collecting information about free space.""" | 352 | """Test collecting information about free space.""" |
1208 | 429 | def statvfs(path, multiplier=mock_counter(1).next): | 353 | def statvfs(path, multiplier=mock_counter(1).next): |
1209 | 430 | 354 | ||
1210 | === modified file 'landscape/monitor/tests/test_service.py' | |||
1211 | --- landscape/monitor/tests/test_service.py 2011-07-05 05:09:11 +0000 | |||
1212 | +++ landscape/monitor/tests/test_service.py 2011-12-02 09:56:24 +0000 | |||
1213 | @@ -1,4 +1,3 @@ | |||
1214 | 1 | from landscape.tests.mocker import ANY | ||
1215 | 2 | from landscape.tests.helpers import LandscapeTest, FakeBrokerServiceHelper | 1 | from landscape.tests.helpers import LandscapeTest, FakeBrokerServiceHelper |
1216 | 3 | from landscape.reactor import FakeReactor | 2 | from landscape.reactor import FakeReactor |
1217 | 4 | from landscape.monitor.config import MonitorConfiguration, ALL_PLUGINS | 3 | from landscape.monitor.config import MonitorConfiguration, ALL_PLUGINS |
1218 | @@ -46,15 +45,10 @@ | |||
1219 | 46 | starts the plugins and register the monitor as broker client. It also | 45 | starts the plugins and register the monitor as broker client. It also |
1220 | 47 | start listening on its own socket for incoming connections. | 46 | start listening on its own socket for incoming connections. |
1221 | 48 | """ | 47 | """ |
1222 | 49 | # FIXME: don't actually run the real register method, because at the | ||
1223 | 50 | # moment the UserMonitor plugin still depends on DBus. We can probably | ||
1224 | 51 | # drop this mocking once the AMP migration is completed. | ||
1225 | 52 | for plugin in self.service.plugins: | ||
1226 | 53 | plugin.register = self.mocker.mock() | ||
1227 | 54 | plugin.register(ANY) | ||
1228 | 55 | self.mocker.replay() | ||
1229 | 56 | |||
1230 | 57 | def stop_service(ignored): | 48 | def stop_service(ignored): |
1231 | 49 | for plugin in self.service.plugins: | ||
1232 | 50 | if getattr(plugin, "stop", None) is not None: | ||
1233 | 51 | plugin.stop() | ||
1234 | 58 | [connector] = self.broker_service.broker.get_connectors() | 52 | [connector] = self.broker_service.broker.get_connectors() |
1235 | 59 | connector.disconnect() | 53 | connector.disconnect() |
1236 | 60 | self.service.stopService() | 54 | self.service.stopService() |
1237 | 61 | 55 | ||
1238 | === modified file 'landscape/package/releaseupgrader.py' | |||
1239 | --- landscape/package/releaseupgrader.py 2011-07-06 12:34:11 +0000 | |||
1240 | +++ landscape/package/releaseupgrader.py 2011-12-02 09:56:24 +0000 | |||
1241 | @@ -188,32 +188,11 @@ | |||
1242 | 188 | config.add_section("NonInteractive") | 188 | config.add_section("NonInteractive") |
1243 | 189 | config.set("NonInteractive", "ForceOverwrite", "no") | 189 | config.set("NonInteractive", "ForceOverwrite", "no") |
1244 | 190 | 190 | ||
1245 | 191 | # Workaround for Bug #174148, which prevents dbus from restarting | ||
1246 | 192 | # after a dapper->hardy upgrade | ||
1247 | 193 | if not config.has_section("Distro"): | ||
1248 | 194 | config.add_section("Distro") | ||
1249 | 195 | if not config.has_option("Distro", "PostInstallScripts"): | ||
1250 | 196 | config.set("Distro", "PostInstallScripts", "./dbus.sh") | ||
1251 | 197 | else: | ||
1252 | 198 | scripts = config.get("Distro", "PostInstallScripts") | ||
1253 | 199 | scripts += ", ./dbus.sh" | ||
1254 | 200 | config.set("Distro", "PostInstallScripts", scripts) | ||
1255 | 201 | |||
1256 | 202 | # Write config changes to disk | 191 | # Write config changes to disk |
1257 | 203 | fd = open(config_filename, "w") | 192 | fd = open(config_filename, "w") |
1258 | 204 | config.write(fd) | 193 | config.write(fd) |
1259 | 205 | fd.close() | 194 | fd.close() |
1260 | 206 | 195 | ||
1261 | 207 | # Generate the post-install script that starts DBus | ||
1262 | 208 | dbus_sh_filename = os.path.join(upgrade_tool_directory, | ||
1263 | 209 | "dbus.sh") | ||
1264 | 210 | fd = open(dbus_sh_filename, "w") | ||
1265 | 211 | fd.write("#!/bin/sh\n" | ||
1266 | 212 | "/etc/init.d/dbus start\n" | ||
1267 | 213 | "sleep 10\n") | ||
1268 | 214 | fd.close() | ||
1269 | 215 | os.chmod(dbus_sh_filename, 0755) | ||
1270 | 216 | |||
1271 | 217 | # On some releases the upgrade-tool doesn't support the allow third | 196 | # On some releases the upgrade-tool doesn't support the allow third |
1272 | 218 | # party environment variable, so this trick is needed to make it | 197 | # party environment variable, so this trick is needed to make it |
1273 | 219 | # possible to upgrade against testing client packages from the | 198 | # possible to upgrade against testing client packages from the |
1274 | 220 | 199 | ||
1275 | === modified file 'landscape/package/tests/test_releaseupgrader.py' | |||
1276 | --- landscape/package/tests/test_releaseupgrader.py 2011-11-15 09:57:05 +0000 | |||
1277 | +++ landscape/package/tests/test_releaseupgrader.py 2011-12-02 09:56:24 +0000 | |||
1278 | @@ -245,60 +245,6 @@ | |||
1279 | 245 | result.addCallback(check_result) | 245 | result.addCallback(check_result) |
1280 | 246 | return result | 246 | return result |
1281 | 247 | 247 | ||
1282 | 248 | def test_tweak_sets_dbus_start_script(self): | ||
1283 | 249 | """ | ||
1284 | 250 | The L{ReleaseUpgrader.tweak} method adds to the upgrade-tool | ||
1285 | 251 | configuration a little script that starts dbus after the upgrade. | ||
1286 | 252 | """ | ||
1287 | 253 | config_filename = os.path.join(self.config.upgrade_tool_directory, | ||
1288 | 254 | "DistUpgrade.cfg.dapper") | ||
1289 | 255 | self.makeFile(path=config_filename, | ||
1290 | 256 | content="[Distro]\n" | ||
1291 | 257 | "PostInstallScripts=/foo.sh\n") | ||
1292 | 258 | |||
1293 | 259 | def check_result(ignored): | ||
1294 | 260 | config = ConfigParser.ConfigParser() | ||
1295 | 261 | config.read(config_filename) | ||
1296 | 262 | self.assertEqual(config.get("Distro", "PostInstallScripts"), | ||
1297 | 263 | "/foo.sh, ./dbus.sh") | ||
1298 | 264 | dbus_sh = os.path.join(self.config.upgrade_tool_directory, | ||
1299 | 265 | "dbus.sh") | ||
1300 | 266 | self.assertFileContent(dbus_sh, | ||
1301 | 267 | "#!/bin/sh\n" | ||
1302 | 268 | "/etc/init.d/dbus start\n" | ||
1303 | 269 | "sleep 10\n") | ||
1304 | 270 | |||
1305 | 271 | result = self.upgrader.tweak("dapper") | ||
1306 | 272 | result.addCallback(check_result) | ||
1307 | 273 | return result | ||
1308 | 274 | |||
1309 | 275 | def test_tweak_sets_dbus_start_script_with_no_post_install_scripts(self): | ||
1310 | 276 | """ | ||
1311 | 277 | The L{ReleaseUpgrader.tweak} method adds to the upgrade-tool | ||
1312 | 278 | configuration a little script that starts dbus after the upgrade. This | ||
1313 | 279 | works even when the config file doesn't have a PostInstallScripts entry | ||
1314 | 280 | yet. | ||
1315 | 281 | """ | ||
1316 | 282 | config_filename = os.path.join(self.config.upgrade_tool_directory, | ||
1317 | 283 | "DistUpgrade.cfg.dapper") | ||
1318 | 284 | self.makeFile(path=config_filename, content="") | ||
1319 | 285 | |||
1320 | 286 | def check_result(ignored): | ||
1321 | 287 | config = ConfigParser.ConfigParser() | ||
1322 | 288 | config.read(config_filename) | ||
1323 | 289 | self.assertEqual(config.get("Distro", "PostInstallScripts"), | ||
1324 | 290 | "./dbus.sh") | ||
1325 | 291 | dbus_sh = os.path.join(self.config.upgrade_tool_directory, | ||
1326 | 292 | "dbus.sh") | ||
1327 | 293 | self.assertFileContent(dbus_sh, | ||
1328 | 294 | "#!/bin/sh\n" | ||
1329 | 295 | "/etc/init.d/dbus start\n" | ||
1330 | 296 | "sleep 10\n") | ||
1331 | 297 | |||
1332 | 298 | result = self.upgrader.tweak("dapper") | ||
1333 | 299 | result.addCallback(check_result) | ||
1334 | 300 | return result | ||
1335 | 301 | |||
1336 | 302 | def test_default_logs_directory(self): | 248 | def test_default_logs_directory(self): |
1337 | 303 | """ | 249 | """ |
1338 | 304 | The default directory for the upgrade-tool logs is the system one. | 250 | The default directory for the upgrade-tool logs is the system one. |
1339 | 305 | 251 | ||
1340 | === modified file 'landscape/reactor.py' | |||
1341 | --- landscape/reactor.py 2011-07-21 23:55:47 +0000 | |||
1342 | +++ landscape/reactor.py 2011-12-02 09:56:24 +0000 | |||
1343 | @@ -16,10 +16,6 @@ | |||
1344 | 16 | """Raised when an invalid ID is used with reactor.cancel_call().""" | 16 | """Raised when an invalid ID is used with reactor.cancel_call().""" |
1345 | 17 | 17 | ||
1346 | 18 | 18 | ||
1347 | 19 | class CallHookError(Exception): | ||
1348 | 20 | """Raised when hooking on a reactor incorrectly.""" | ||
1349 | 21 | |||
1350 | 22 | |||
1351 | 23 | class EventID(object): | 19 | class EventID(object): |
1352 | 24 | """Unique identifier for an event handler. | 20 | """Unique identifier for an event handler. |
1353 | 25 | 21 | ||
1354 | @@ -147,13 +143,6 @@ | |||
1355 | 147 | except Exception, e: | 143 | except Exception, e: |
1356 | 148 | logging.exception(e) | 144 | logging.exception(e) |
1357 | 149 | 145 | ||
1358 | 150 | def _hook_threaded_callbacks(self): | ||
1359 | 151 | id = self.call_every(0.5, self._run_threaded_callbacks) | ||
1360 | 152 | self._run_threaded_callbacks_id = id | ||
1361 | 153 | |||
1362 | 154 | def _unhook_threaded_callbacks(self): | ||
1363 | 155 | self.cancel_call(self._run_threaded_callbacks_id) | ||
1364 | 156 | |||
1365 | 157 | 146 | ||
1366 | 158 | class UnixReactorMixin(object): | 147 | class UnixReactorMixin(object): |
1367 | 159 | 148 | ||
1368 | @@ -289,12 +278,12 @@ | |||
1369 | 289 | try: | 278 | try: |
1370 | 290 | # is it an IP address? | 279 | # is it an IP address? |
1371 | 291 | socket.inet_aton(hostname) | 280 | socket.inet_aton(hostname) |
1373 | 292 | except socket.error: # no | 281 | except socket.error: # no |
1374 | 293 | if hostname in self.hosts: | 282 | if hostname in self.hosts: |
1375 | 294 | return succeed(self.hosts[hostname]) | 283 | return succeed(self.hosts[hostname]) |
1376 | 295 | else: | 284 | else: |
1377 | 296 | return fail(DNSLookupError(hostname)) | 285 | return fail(DNSLookupError(hostname)) |
1379 | 297 | else: # yes | 286 | else: # yes |
1380 | 298 | return succeed(hostname) | 287 | return succeed(hostname) |
1381 | 299 | 288 | ||
1382 | 300 | 289 | ||
1383 | 301 | 290 | ||
1384 | === modified file 'landscape/service.py' | |||
1385 | --- landscape/service.py 2011-10-13 06:53:24 +0000 | |||
1386 | +++ landscape/service.py 2011-12-02 09:56:24 +0000 | |||
1387 | @@ -28,12 +28,6 @@ | |||
1388 | 28 | 28 | ||
1389 | 29 | def __init__(self, config): | 29 | def __init__(self, config): |
1390 | 30 | self.config = config | 30 | self.config = config |
1391 | 31 | try: | ||
1392 | 32 | from landscape.lib import bpickle_dbus | ||
1393 | 33 | except ImportError: | ||
1394 | 34 | pass | ||
1395 | 35 | else: | ||
1396 | 36 | bpickle_dbus.install() | ||
1397 | 37 | self.reactor = self.reactor_factory() | 31 | self.reactor = self.reactor_factory() |
1398 | 38 | if self.persist_filename: | 32 | if self.persist_filename: |
1399 | 39 | self.persist = get_versioned_persist(self) | 33 | self.persist = get_versioned_persist(self) |
1400 | 40 | 34 | ||
1401 | === modified file 'landscape/tests/test_configuration.py' | |||
1402 | --- landscape/tests/test_configuration.py 2011-11-14 17:28:04 +0000 | |||
1403 | +++ landscape/tests/test_configuration.py 2011-12-02 09:56:24 +0000 | |||
1404 | @@ -1856,7 +1856,7 @@ | |||
1405 | 1856 | 1856 | ||
1406 | 1857 | def test_register_bus_connection_failure_ok_no_register(self): | 1857 | def test_register_bus_connection_failure_ok_no_register(self): |
1407 | 1858 | """ | 1858 | """ |
1409 | 1859 | Exit code 0 will be returned if we can't contact Landscape via DBus and | 1859 | Exit code 0 will be returned if we can't contact Landscape and |
1410 | 1860 | --ok-no-register was passed. | 1860 | --ok-no-register was passed. |
1411 | 1861 | """ | 1861 | """ |
1412 | 1862 | print_text_mock = self.mocker.replace(print_text) | 1862 | print_text_mock = self.mocker.replace(print_text) |
1413 | 1863 | 1863 | ||
1414 | === removed file 'landscape/tests/test_hal.py' | |||
1415 | --- landscape/tests/test_hal.py 2011-07-05 05:09:11 +0000 | |||
1416 | +++ landscape/tests/test_hal.py 1970-01-01 00:00:00 +0000 | |||
1417 | @@ -1,87 +0,0 @@ | |||
1418 | 1 | from dbus import SystemBus, Interface | ||
1419 | 2 | from dbus.exceptions import DBusException | ||
1420 | 3 | |||
1421 | 4 | from landscape.hal import HALDevice, HALManager | ||
1422 | 5 | from landscape.tests.helpers import LandscapeTest | ||
1423 | 6 | |||
1424 | 7 | |||
1425 | 8 | class HALManagerTest(LandscapeTest): | ||
1426 | 9 | |||
1427 | 10 | def setUp(self): | ||
1428 | 11 | super(HALManagerTest, self).setUp() | ||
1429 | 12 | self.bus = SystemBus() | ||
1430 | 13 | |||
1431 | 14 | def test_get_devices(self): | ||
1432 | 15 | """ | ||
1433 | 16 | A HALManager can return a flat list of devices. All available | ||
1434 | 17 | devices should be included in the returned list. | ||
1435 | 18 | """ | ||
1436 | 19 | devices = HALManager().get_devices() | ||
1437 | 20 | manager = self.bus.get_object("org.freedesktop.Hal", | ||
1438 | 21 | "/org/freedesktop/Hal/Manager") | ||
1439 | 22 | manager = Interface(manager, "org.freedesktop.Hal.Manager") | ||
1440 | 23 | expected_devices = manager.GetAllDevices() | ||
1441 | 24 | actual_devices = [device.udi for device in devices] | ||
1442 | 25 | self.assertEqual(set(expected_devices), set(actual_devices)) | ||
1443 | 26 | |||
1444 | 27 | def test_get_devices_with_dbus_error(self): | ||
1445 | 28 | """ | ||
1446 | 29 | If the L{HALManager} fails connecting to HAL over D-Bus, then the | ||
1447 | 30 | L{HALManager.get_devices} method returns an empty list. | ||
1448 | 31 | """ | ||
1449 | 32 | self.log_helper.ignore_errors("Couldn't to connect to Hal via DBus") | ||
1450 | 33 | bus = self.mocker.mock() | ||
1451 | 34 | bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager") | ||
1452 | 35 | self.mocker.throw(DBusException()) | ||
1453 | 36 | self.mocker.replay() | ||
1454 | 37 | devices = HALManager(bus=bus).get_devices() | ||
1455 | 38 | self.assertEqual(devices, []) | ||
1456 | 39 | |||
1457 | 40 | def test_get_devices_with_no_server(self): | ||
1458 | 41 | """ | ||
1459 | 42 | If the L{HALManager} fails connecting to HAL over D-Bus, for example | ||
1460 | 43 | because the DBus server is not running at all, then the | ||
1461 | 44 | L{HALManager.get_devices} method returns an empty list. | ||
1462 | 45 | """ | ||
1463 | 46 | self.log_helper.ignore_errors("Couldn't to connect to Hal via DBus") | ||
1464 | 47 | bus_mock = self.mocker.replace("dbus.SystemBus") | ||
1465 | 48 | bus_mock() | ||
1466 | 49 | self.mocker.throw(DBusException()) | ||
1467 | 50 | self.mocker.replay() | ||
1468 | 51 | devices = HALManager().get_devices() | ||
1469 | 52 | self.assertEqual(devices, []) | ||
1470 | 53 | |||
1471 | 54 | |||
1472 | 55 | class MockHALManager(object): | ||
1473 | 56 | |||
1474 | 57 | def __init__(self, devices): | ||
1475 | 58 | self.devices = devices | ||
1476 | 59 | |||
1477 | 60 | def get_devices(self): | ||
1478 | 61 | return [HALDevice(device) for device in self.devices] | ||
1479 | 62 | |||
1480 | 63 | |||
1481 | 64 | class MockRealHALDevice(object): | ||
1482 | 65 | |||
1483 | 66 | def __init__(self, properties): | ||
1484 | 67 | self._properties = properties | ||
1485 | 68 | self.udi = properties.get("info.udi", "fake_udi") | ||
1486 | 69 | |||
1487 | 70 | def GetAllProperties(self): | ||
1488 | 71 | return self._properties | ||
1489 | 72 | |||
1490 | 73 | |||
1491 | 74 | class HALDeviceTest(LandscapeTest): | ||
1492 | 75 | |||
1493 | 76 | def test_init(self): | ||
1494 | 77 | device = HALDevice(MockRealHALDevice({"info.udi": "wubble"})) | ||
1495 | 78 | self.assertEqual(device.properties, {"info.udi": "wubble"}) | ||
1496 | 79 | self.assertEqual(device.udi, "wubble") | ||
1497 | 80 | self.assertEqual(device.parent, None) | ||
1498 | 81 | |||
1499 | 82 | def test_add_child(self): | ||
1500 | 83 | parent = HALDevice(MockRealHALDevice({"info.udi": "wubble"})) | ||
1501 | 84 | child = HALDevice(MockRealHALDevice({"info.udi": "ooga"})) | ||
1502 | 85 | parent.add_child(child) | ||
1503 | 86 | self.assertEqual(parent.get_children(), [child]) | ||
1504 | 87 | self.assertEqual(child.parent, parent) | ||
1505 | 88 | 0 | ||
1506 | === modified file 'landscape/tests/test_service.py' | |||
1507 | --- landscape/tests/test_service.py 2011-07-05 05:09:11 +0000 | |||
1508 | +++ landscape/tests/test_service.py 2011-12-02 09:56:24 +0000 | |||
1509 | @@ -56,15 +56,6 @@ | |||
1510 | 56 | service = TestService(self.config) | 56 | service = TestService(self.config) |
1511 | 57 | self.assertFalse(hasattr(service, "persist")) | 57 | self.assertFalse(hasattr(service, "persist")) |
1512 | 58 | 58 | ||
1513 | 59 | def test_install_bpickle_dbus(self): | ||
1514 | 60 | """ | ||
1515 | 61 | A L{LandscapeService} installs the DBus extensions of bpickle. | ||
1516 | 62 | """ | ||
1517 | 63 | dbus_mock = self.mocker.replace("landscape.lib.bpickle_dbus.install") | ||
1518 | 64 | dbus_mock() | ||
1519 | 65 | self.mocker.replay() | ||
1520 | 66 | TestService(self.config) | ||
1521 | 67 | |||
1522 | 68 | def test_usr1_rotates_logs(self): | 59 | def test_usr1_rotates_logs(self): |
1523 | 69 | """ | 60 | """ |
1524 | 70 | SIGUSR1 should cause logs to be reopened. | 61 | SIGUSR1 should cause logs to be reopened. |
1525 | 71 | 62 | ||
1526 | === modified file 'landscape/tests/test_textmessage.py' | |||
1527 | --- landscape/tests/test_textmessage.py 2011-07-05 05:09:11 +0000 | |||
1528 | +++ landscape/tests/test_textmessage.py 2011-12-02 09:56:24 +0000 | |||
1529 | @@ -13,8 +13,8 @@ | |||
1530 | 13 | 13 | ||
1531 | 14 | def test_send_message(self): | 14 | def test_send_message(self): |
1532 | 15 | """ | 15 | """ |
1535 | 16 | L{send_message} should send a message of type | 16 | L{send_message} should send a message of type C{text-message} to the |
1536 | 17 | C{text-message} to the landscape dbus messaging service. | 17 | landscape messaging service. |
1537 | 18 | """ | 18 | """ |
1538 | 19 | service = self.broker_service | 19 | service = self.broker_service |
1539 | 20 | service.message_store.set_accepted_types(["text-message"]) | 20 | service.message_store.set_accepted_types(["text-message"]) |
1540 | 21 | 21 | ||
1541 | === modified file 'landscape/textmessage.py' | |||
1542 | --- landscape/textmessage.py 2010-04-23 10:57:57 +0000 | |||
1543 | +++ landscape/textmessage.py 2011-12-02 09:56:24 +0000 | |||
1544 | @@ -1,7 +1,6 @@ | |||
1545 | 1 | """ | 1 | """ |
1546 | 2 | Support code for the C{landscape-message} utility, which sends a text | 2 | Support code for the C{landscape-message} utility, which sends a text |
1549 | 3 | message to the Landscape web UI via the landscape-client's dbus | 3 | message to the Landscape web UI via the landscape-client's messaging service. |
1548 | 4 | messaging service (see L{landscape.plugins.dbus_message}). | ||
1550 | 5 | """ | 4 | """ |
1551 | 6 | 5 | ||
1552 | 7 | import sys | 6 | import sys |
1553 | 8 | 7 | ||
1554 | === modified file 'landscape/watchdog.py' | |||
1555 | --- landscape/watchdog.py 2011-10-13 06:53:24 +0000 | |||
1556 | +++ landscape/watchdog.py 2011-12-02 09:56:24 +0000 | |||
1557 | @@ -57,8 +57,6 @@ | |||
1558 | 57 | @cvar program: The name of the executable program that will start this | 57 | @cvar program: The name of the executable program that will start this |
1559 | 58 | daemon. | 58 | daemon. |
1560 | 59 | @cvar username: The name of the user to switch to, by default. | 59 | @cvar username: The name of the user to switch to, by default. |
1561 | 60 | @cvar service: The DBus service name that the program will be expected to | ||
1562 | 61 | listen on. | ||
1563 | 62 | @cvar max_retries: The maximum number of retries before giving up when | 60 | @cvar max_retries: The maximum number of retries before giving up when |
1564 | 63 | trying to connect to the watched daemon. | 61 | trying to connect to the watched daemon. |
1565 | 64 | @cvar factor: The factor by which the delay between subsequent connection | 62 | @cvar factor: The factor by which the delay between subsequent connection |
1566 | @@ -173,8 +171,7 @@ | |||
1567 | 173 | 171 | ||
1568 | 174 | def is_running(self): | 172 | def is_running(self): |
1569 | 175 | # FIXME Error cases may not be handled in the best possible way | 173 | # FIXME Error cases may not be handled in the best possible way |
1572 | 176 | # here. We're basically return False if any error happens from the | 174 | # here. We're basically return False if any error happens. |
1571 | 177 | # dbus ping. | ||
1573 | 178 | return self._connect_and_call("ping") | 175 | return self._connect_and_call("ping") |
1574 | 179 | 176 | ||
1575 | 180 | def wait(self): | 177 | def wait(self): |
1576 | @@ -362,7 +359,7 @@ | |||
1577 | 362 | def start(self): | 359 | def start(self): |
1578 | 363 | """ | 360 | """ |
1579 | 364 | Start all daemons. The broker will be started first, and no other | 361 | Start all daemons. The broker will be started first, and no other |
1581 | 365 | daemons will be started before it is running and responding to DBUS | 362 | daemons will be started before it is running and responding to |
1582 | 366 | messages. | 363 | messages. |
1583 | 367 | 364 | ||
1584 | 368 | @return: A deferred which fires when all services have successfully | 365 | @return: A deferred which fires when all services have successfully |
1585 | @@ -463,11 +460,11 @@ | |||
1586 | 463 | 460 | ||
1587 | 464 | def daemonize(): | 461 | def daemonize(): |
1588 | 465 | # See http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC16 | 462 | # See http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC16 |
1591 | 466 | if os.fork(): # launch child and... | 463 | if os.fork(): # launch child and... |
1592 | 467 | os._exit(0) # kill off parent | 464 | os._exit(0) # kill off parent |
1593 | 468 | os.setsid() | 465 | os.setsid() |
1596 | 469 | if os.fork(): # launch child and... | 466 | if os.fork(): # launch child and... |
1597 | 470 | os._exit(0) # kill off parent again. | 467 | os._exit(0) # kill off parent again. |
1598 | 471 | # some argue that this umask should be 0, but that's annoying. | 468 | # some argue that this umask should be 0, but that's annoying. |
1599 | 472 | os.umask(077) | 469 | os.umask(077) |
1600 | 473 | null = os.open('/dev/null', os.O_RDWR) | 470 | null = os.open('/dev/null', os.O_RDWR) |
1601 | @@ -505,7 +502,7 @@ | |||
1602 | 505 | error("ERROR: The following daemons are already running: %s" | 502 | error("ERROR: The following daemons are already running: %s" |
1603 | 506 | % (", ".join(x.program for x in running_daemons))) | 503 | % (", ".join(x.program for x in running_daemons))) |
1604 | 507 | self.exit_code = 1 | 504 | self.exit_code = 1 |
1606 | 508 | reactor.crash() # so stopService isn't called. | 505 | reactor.crash() # so stopService isn't called. |
1607 | 509 | return | 506 | return |
1608 | 510 | self._daemonize() | 507 | self._daemonize() |
1609 | 511 | info("Watchdog watching for daemons.") | 508 | info("Watchdog watching for daemons.") |
1610 | 512 | 509 | ||
1611 | === modified file 'man/landscape-client.1' | |||
1612 | --- man/landscape-client.1 2010-01-18 17:26:36 +0000 | |||
1613 | +++ man/landscape-client.1 2011-12-02 09:56:24 +0000 | |||
1614 | @@ -1,5 +1,5 @@ | |||
1615 | 1 | .\"Text automatically generated by txt2man | 1 | .\"Text automatically generated by txt2man |
1617 | 2 | .TH landscape-client "18 January 2010" "" "" | 2 | .TH landscape-client 1 "02 December 2011" "" "" |
1618 | 3 | .SH NAME | 3 | .SH NAME |
1619 | 4 | \fBlandscape-client \fP- Landscape system client | 4 | \fBlandscape-client \fP- Landscape system client |
1620 | 5 | \fB | 5 | \fB |
1621 | @@ -35,11 +35,6 @@ | |||
1622 | 35 | \fIoptions\fP override settings from the file). | 35 | \fIoptions\fP override settings from the file). |
1623 | 36 | .TP | 36 | .TP |
1624 | 37 | .B | 37 | .B |
1625 | 38 | \fB--bus\fP=BUS | ||
1626 | 39 | Which DBUS bus to use. One of 'session' or | ||
1627 | 40 | 'system'. | ||
1628 | 41 | .TP | ||
1629 | 42 | .B | ||
1630 | 43 | \fB-d\fP PATH, \fB--data-path\fP=PATH | 38 | \fB-d\fP PATH, \fB--data-path\fP=PATH |
1631 | 44 | The directory to store data files in. | 39 | The directory to store data files in. |
1632 | 45 | .TP | 40 | .TP |
1633 | 46 | 41 | ||
1634 | === modified file 'man/landscape-client.txt' | |||
1635 | --- man/landscape-client.txt 2010-01-18 16:33:51 +0000 | |||
1636 | +++ man/landscape-client.txt 2011-12-02 09:56:24 +0000 | |||
1637 | @@ -17,8 +17,6 @@ | |||
1638 | 17 | -h, --help Show this help message and exit. | 17 | -h, --help Show this help message and exit. |
1639 | 18 | -c FILE, --config=FILE Use config from this file (any command line | 18 | -c FILE, --config=FILE Use config from this file (any command line |
1640 | 19 | options override settings from the file). | 19 | options override settings from the file). |
1641 | 20 | --bus=BUS Which DBUS bus to use. One of 'session' or | ||
1642 | 21 | 'system'. | ||
1643 | 22 | -d PATH, --data-path=PATH The directory to store data files in. | 20 | -d PATH, --data-path=PATH The directory to store data files in. |
1644 | 23 | -q, --quiet Do not log to the standard output. | 21 | -q, --quiet Do not log to the standard output. |
1645 | 24 | -l FILE, --log-dir=FILE The directory to write log files to. | 22 | -l FILE, --log-dir=FILE The directory to write log files to. |
1646 | 25 | 23 | ||
1647 | === modified file 'man/landscape-config.1' | |||
1648 | --- man/landscape-config.1 2010-01-18 17:26:36 +0000 | |||
1649 | +++ man/landscape-config.1 2011-12-02 09:56:24 +0000 | |||
1650 | @@ -1,5 +1,5 @@ | |||
1651 | 1 | .\"Text automatically generated by txt2man | 1 | .\"Text automatically generated by txt2man |
1653 | 2 | .TH landscape-config "18 January 2010" "" "" | 2 | .TH landscape-config 1 "02 December 2011" "" "" |
1654 | 3 | .SH NAME | 3 | .SH NAME |
1655 | 4 | \fBlandscape-config \fP- configure the Landscape management client | 4 | \fBlandscape-config \fP- configure the Landscape management client |
1656 | 5 | \fB | 5 | \fB |
1657 | @@ -46,11 +46,6 @@ | |||
1658 | 46 | '/etc/landscape/client.conf'). | 46 | '/etc/landscape/client.conf'). |
1659 | 47 | .TP | 47 | .TP |
1660 | 48 | .B | 48 | .B |
1661 | 49 | \fB--bus\fP=BUS | ||
1662 | 50 | Which DBUS bus to use. One of 'session' or 'system' | ||
1663 | 51 | (default: 'system'). | ||
1664 | 52 | .TP | ||
1665 | 53 | .B | ||
1666 | 54 | \fB-d\fP PATH, \fB--data-path\fP=PATH | 49 | \fB-d\fP PATH, \fB--data-path\fP=PATH |
1667 | 55 | The directory to store data files in (default: | 50 | The directory to store data files in (default: |
1668 | 56 | '/var/lib/landscape/client'). | 51 | '/var/lib/landscape/client'). |
1669 | 57 | 52 | ||
1670 | === modified file 'man/landscape-config.txt' | |||
1671 | --- man/landscape-config.txt 2010-01-18 17:20:34 +0000 | |||
1672 | +++ man/landscape-config.txt 2011-12-02 09:56:24 +0000 | |||
1673 | @@ -28,8 +28,6 @@ | |||
1674 | 28 | -c FILE, --config=FILE Use config from this file (any command line options | 28 | -c FILE, --config=FILE Use config from this file (any command line options |
1675 | 29 | override settings from the file) (default: | 29 | override settings from the file) (default: |
1676 | 30 | '/etc/landscape/client.conf'). | 30 | '/etc/landscape/client.conf'). |
1677 | 31 | --bus=BUS Which DBUS bus to use. One of 'session' or 'system' | ||
1678 | 32 | (default: 'system'). | ||
1679 | 33 | -d PATH, --data-path=PATH The directory to store data files in (default: | 31 | -d PATH, --data-path=PATH The directory to store data files in (default: |
1680 | 34 | '/var/lib/landscape/client'). | 32 | '/var/lib/landscape/client'). |
1681 | 35 | -q, --quiet Do not log to the standard output. | 33 | -q, --quiet Do not log to the standard output. |
1682 | 36 | 34 | ||
1683 | === modified file 'man/landscape-message.1' | |||
1684 | --- man/landscape-message.1 2010-01-18 17:26:36 +0000 | |||
1685 | +++ man/landscape-message.1 2011-12-02 09:56:24 +0000 | |||
1686 | @@ -1,5 +1,5 @@ | |||
1687 | 1 | .\"Text automatically generated by txt2man | 1 | .\"Text automatically generated by txt2man |
1689 | 2 | .TH landscape-message "18 January 2010" "" "" | 2 | .TH landscape-message 1 "02 December 2011" "" "" |
1690 | 3 | .SH NAME | 3 | .SH NAME |
1691 | 4 | \fBlandscape-message \fP- Send a message to the landscape web interface | 4 | \fBlandscape-message \fP- Send a message to the landscape web interface |
1692 | 5 | \fB | 5 | \fB |
1693 | @@ -31,10 +31,6 @@ | |||
1694 | 31 | .B | 31 | .B |
1695 | 32 | \fB-h\fP, \fB--help\fP | 32 | \fB-h\fP, \fB--help\fP |
1696 | 33 | Show this help message and exit. | 33 | Show this help message and exit. |
1697 | 34 | .TP | ||
1698 | 35 | .B | ||
1699 | 36 | \fB-b\fP BUS, \fB--bus\fP=BUS | ||
1700 | 37 | The DBUS bus to use to send the message. | ||
1701 | 38 | .SH EXAMPLES | 34 | .SH EXAMPLES |
1702 | 39 | 35 | ||
1703 | 40 | \fBlandscape-message\fP Hello administrator | 36 | \fBlandscape-message\fP Hello administrator |
1704 | 41 | 37 | ||
1705 | === modified file 'man/landscape-message.txt' | |||
1706 | --- man/landscape-message.txt 2010-01-18 16:33:51 +0000 | |||
1707 | +++ man/landscape-message.txt 2011-12-02 09:56:24 +0000 | |||
1708 | @@ -16,7 +16,6 @@ | |||
1709 | 16 | OPTIONS | 16 | OPTIONS |
1710 | 17 | --version Show program's version number and exit. | 17 | --version Show program's version number and exit. |
1711 | 18 | -h, --help Show this help message and exit. | 18 | -h, --help Show this help message and exit. |
1712 | 19 | -b BUS, --bus=BUS The DBUS bus to use to send the message. | ||
1713 | 20 | 19 | ||
1714 | 21 | EXAMPLES | 20 | EXAMPLES |
1715 | 22 | 21 | ||
1716 | 23 | 22 | ||
1717 | === removed file 'scripts/landscape-dbus-proxy' | |||
1718 | --- scripts/landscape-dbus-proxy 2011-06-13 23:58:09 +0000 | |||
1719 | +++ scripts/landscape-dbus-proxy 1970-01-01 00:00:00 +0000 | |||
1720 | @@ -1,82 +0,0 @@ | |||
1721 | 1 | #!/usr/bin/env python | ||
1722 | 2 | |||
1723 | 3 | import os | ||
1724 | 4 | import dbus | ||
1725 | 5 | import dbus.service | ||
1726 | 6 | import dbus.glib # This as side effects, don't remove it! | ||
1727 | 7 | |||
1728 | 8 | from dbus.service import Object, BusName, method | ||
1729 | 9 | |||
1730 | 10 | from twisted.internet import glib2reactor | ||
1731 | 11 | glib2reactor.install() | ||
1732 | 12 | from twisted.internet import reactor | ||
1733 | 13 | |||
1734 | 14 | from landscape.lib.bpickle import loads | ||
1735 | 15 | from landscape.lib.lock import lock_path, LockError | ||
1736 | 16 | from landscape.reactor import TwistedReactor | ||
1737 | 17 | from landscape.deployment import Configuration | ||
1738 | 18 | from landscape.broker.amp import RemoteBrokerConnector | ||
1739 | 19 | |||
1740 | 20 | |||
1741 | 21 | BUS_NAME = "com.canonical.landscape.Broker" | ||
1742 | 22 | OBJECT_PATH = "/com/canonical/landscape/Broker" | ||
1743 | 23 | |||
1744 | 24 | |||
1745 | 25 | def array_to_string(array): | ||
1746 | 26 | """Convert an L{Array} of L{Byte}s (or integers) to a Python str.""" | ||
1747 | 27 | result = [] | ||
1748 | 28 | for item in array: | ||
1749 | 29 | if item < 0: | ||
1750 | 30 | item = item + 256 | ||
1751 | 31 | result.append(chr(item)) | ||
1752 | 32 | return "".join(result) | ||
1753 | 33 | |||
1754 | 34 | |||
1755 | 35 | class BrokerDBusObject(Object): | ||
1756 | 36 | """A DBus-published object proxying L{RemoteBroker.send_message}. | ||
1757 | 37 | |||
1758 | 38 | It is used when upgrading from a DBus-based version of the Landscape client | ||
1759 | 39 | to the newer AMP-based one, for letting the old package-changer process | ||
1760 | 40 | performing the upgrade communicate with the new version of the client. | ||
1761 | 41 | """ | ||
1762 | 42 | |||
1763 | 43 | bus_name = BUS_NAME | ||
1764 | 44 | object_path = OBJECT_PATH | ||
1765 | 45 | |||
1766 | 46 | def __init__(self, config): | ||
1767 | 47 | super(BrokerDBusObject, self).__init__(BusName( | ||
1768 | 48 | self.bus_name, dbus.SystemBus()), object_path=self.object_path) | ||
1769 | 49 | self.config = config | ||
1770 | 50 | |||
1771 | 51 | @method(BUS_NAME) | ||
1772 | 52 | def send_message(self, message, urgent=True): | ||
1773 | 53 | """Queue the given message in the message exchange.""" | ||
1774 | 54 | message = loads(array_to_string(message)) | ||
1775 | 55 | |||
1776 | 56 | def cb_connected(broker): | ||
1777 | 57 | result = broker.send_message(message, urgent=True) | ||
1778 | 58 | return result.addCallback(cb_done) | ||
1779 | 59 | |||
1780 | 60 | def cb_done(ignored): | ||
1781 | 61 | return reactor.stop() | ||
1782 | 62 | |||
1783 | 63 | twisted_reactor = TwistedReactor() | ||
1784 | 64 | connector = RemoteBrokerConnector(twisted_reactor, self.config) | ||
1785 | 65 | connected = connector.connect() | ||
1786 | 66 | connected.addCallback(cb_connected) | ||
1787 | 67 | |||
1788 | 68 | |||
1789 | 69 | if __name__ == "__main__": | ||
1790 | 70 | config = Configuration() | ||
1791 | 71 | lock_dir = os.path.join(config.data_path, "package") | ||
1792 | 72 | if os.path.isdir(lock_dir): | ||
1793 | 73 | lock_filename = os.path.join(lock_dir, "changer.lock") | ||
1794 | 74 | try: | ||
1795 | 75 | lock_path(lock_filename) | ||
1796 | 76 | except LockError: | ||
1797 | 77 | # The package-changer is running, this means that we're upgrading from | ||
1798 | 78 | # a non-AMP version and that the upgrade is Landscape driven, so let's | ||
1799 | 79 | # expose the DBus broker proxy to give a chance to the package-changer | ||
1800 | 80 | # to send its result message. | ||
1801 | 81 | remote = BrokerDBusObject(config) | ||
1802 | 82 | reactor.run() | ||
1803 | 83 | 0 | ||
1804 | === modified file 'setup.py' | |||
1805 | --- setup.py 2010-06-10 13:30:58 +0000 | |||
1806 | +++ setup.py 2011-12-02 09:56:24 +0000 | |||
1807 | @@ -29,8 +29,7 @@ | |||
1808 | 29 | "scripts/landscape-package-reporter", | 29 | "scripts/landscape-package-reporter", |
1809 | 30 | "scripts/landscape-release-upgrader", | 30 | "scripts/landscape-release-upgrader", |
1810 | 31 | "scripts/landscape-sysinfo", | 31 | "scripts/landscape-sysinfo", |
1813 | 32 | "scripts/landscape-is-cloud-managed", | 32 | "scripts/landscape-is-cloud-managed"], |
1812 | 33 | "scripts/landscape-dbus-proxy"], | ||
1814 | 34 | ext_modules=[Extension("landscape.lib.initgroups", | 33 | ext_modules=[Extension("landscape.lib.initgroups", |
1815 | 35 | ["landscape/lib/initgroups.c"])] | 34 | ["landscape/lib/initgroups.c"])] |
1816 | 36 | ) | 35 | ) |
Looks good! +1