Merge lp:~ericsnowcurrently/landscape-client/fix-test-race-sys-argv into lp:~landscape/landscape-client/trunk

Proposed by Eric Snow
Status: Merged
Approved by: Eric Snow
Approved revision: 997
Merged at revision: 1002
Proposed branch: lp:~ericsnowcurrently/landscape-client/fix-test-race-sys-argv
Merge into: lp:~landscape/landscape-client/trunk
Diff against target: 1291 lines (+304/-257)
20 files modified
landscape/deployment.py (+16/-0)
landscape/lib/bpickle.py (+0/-1)
landscape/lib/tests/test_process.py (+2/-1)
landscape/manager/aptsources.py (+1/-1)
landscape/manager/packagemanager.py (+4/-5)
landscape/manager/tests/test_aptsources.py (+2/-2)
landscape/manager/tests/test_packagemanager.py (+40/-38)
landscape/monitor/packagemonitor.py (+4/-1)
landscape/monitor/tests/test_packagemonitor.py (+20/-34)
landscape/monitor/tests/test_processorinfo.py (+3/-3)
landscape/package/changer.py (+12/-10)
landscape/package/releaseupgrader.py (+7/-11)
landscape/package/reporter.py (+4/-4)
landscape/package/tests/test_changer.py (+35/-40)
landscape/package/tests/test_releaseupgrader.py (+15/-23)
landscape/package/tests/test_reporter.py (+13/-14)
landscape/tests/helpers.py (+12/-0)
landscape/tests/test_deployment.py (+37/-1)
landscape/tests/test_watchdog.py (+73/-66)
landscape/watchdog.py (+4/-2)
To merge this branch: bzr merge lp:~ericsnowcurrently/landscape-client/fix-test-race-sys-argv
Reviewer Review Type Date Requested Status
🤖 Landscape Builder test results Approve
Free Ekanayaka (community) Approve
Simon Poirier (community) Approve
Review via email: mp+321391@code.launchpad.net

Commit message

his patch fixes a race condition in tests involving sys.argv.

Under certain load conditions there is a collision on patched-out
sys.argv. To resolve this, we switch to using the config to store the
bindir that should be used (rather than extrapolating from sys.argv[0]).

Description of the change

This patch fixes a race condition in tests involving sys.argv.

Under certain load conditions there is a collision on patched-out
sys.argv. To resolve this, we switch to using the config to store the
bindir that should be used (rather than extrapolating from sys.argv[0]).

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make ci-check
Result: Fail
Revno: 992
Branch: lp:~ericsnowcurrently/landscape-client/fix-test-race-sys-argv
Jenkins: https://ci.lscape.net/job/latch-test-xenial/3818/

review: Needs Fixing (test results)
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :
review: Approve (test results)
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :
review: Approve (test results)
Revision history for this message
Simon Poirier (simpoir) wrote :

+1 looks good. few nitpicks.

review: Approve
Revision history for this message
Eric Snow (ericsnowcurrently) :
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :
review: Approve (test results)
Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

+1

review: Approve
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Attempt to merge into lp:landscape-client failed due to conflicts:

text conflict in landscape/manager/packagemanager.py
text conflict in landscape/watchdog.py

997. By Eric Snow

Merge from trunk.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :
review: Approve (test results)
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :
review: Approve (test results)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'landscape/deployment.py'
2--- landscape/deployment.py 2017-01-09 16:38:21 +0000
3+++ landscape/deployment.py 2017-04-05 14:19:44 +0000
4@@ -1,4 +1,5 @@
5 import os
6+import os.path
7 import sys
8
9 from configobj import ConfigObj, ConfigObjError
10@@ -432,3 +433,18 @@
11 upgrade_manager.initialize(persist)
12 persist.save(service.persist_filename)
13 return persist
14+
15+
16+def get_bindir(config=None):
17+ """Return the directory path where the client binaries are.
18+
19+ If the config is None, it doesn't have a "bindir" attribute, or its
20+ value is None, then sys.argv[0] is returned.
21+ """
22+ try:
23+ bindir = config.bindir
24+ except AttributeError: # ...also the result if config is None.
25+ bindir = None
26+ if bindir is None:
27+ bindir = os.path.dirname(os.path.abspath(sys.argv[0]))
28+ return bindir
29
30=== modified file 'landscape/lib/bpickle.py'
31--- landscape/lib/bpickle.py 2017-04-03 08:15:02 +0000
32+++ landscape/lib/bpickle.py 2017-04-05 14:19:44 +0000
33@@ -210,4 +210,3 @@
34 dumps_table.update({
35 str: dumps_unicode,
36 })
37-
38
39=== modified file 'landscape/lib/tests/test_process.py'
40--- landscape/lib/tests/test_process.py 2017-03-29 09:15:01 +0000
41+++ landscape/lib/tests/test_process.py 2017-04-05 14:19:44 +0000
42@@ -43,7 +43,8 @@
43 @mock.patch("landscape.lib.process.detect_jiffies", return_value=1)
44 @mock.patch("os.listdir")
45 @mock.patch("landscape.monitor.computeruptime.get_uptime")
46- def test_missing_process_race(self, get_uptime_mock, list_dir_mock, jiffies_mock):
47+ def test_missing_process_race(self, get_uptime_mock, list_dir_mock,
48+ jiffies_mock):
49 """
50 We use os.listdir("/proc") to get the list of active processes, if a
51 process ends before we attempt to read the process' information, then
52
53=== modified file 'landscape/manager/aptsources.py'
54--- landscape/manager/aptsources.py 2017-03-28 14:09:52 +0000
55+++ landscape/manager/aptsources.py 2017-04-05 14:19:44 +0000
56@@ -135,7 +135,7 @@
57
58 def _run_reporter(self):
59 """Once the repositories are modified, trigger a reporter run."""
60- reporter = find_reporter_command()
61+ reporter = find_reporter_command(self.registry.config)
62
63 # Force an apt-update run, because the sources.list has changed
64 args = ["--force-apt-update"]
65
66=== modified file 'landscape/manager/packagemanager.py'
67--- landscape/manager/packagemanager.py 2017-04-04 08:50:05 +0000
68+++ landscape/manager/packagemanager.py 2017-04-05 14:19:44 +0000
69@@ -69,13 +69,12 @@
70 if self.config.config:
71 args.extend(["-c", self.config.config])
72 if self._package_store.get_next_task(cls.queue_name):
73+ command = cls.find_command(self.config)
74+ environ = encode_values(os.environ)
75 # path is set to None so that getProcessOutput does not
76 # chdir to "." see bug #211373
77- environ = encode_values(os.environ)
78- result = getProcessOutput(cls.find_command(),
79- args=args, env=environ,
80- errortoo=1,
81- path=None)
82+ result = getProcessOutput(
83+ command, args=args, env=environ, errortoo=1, path=None)
84 result.addCallback(self._got_output, cls)
85 else:
86 result = succeed(None)
87
88=== modified file 'landscape/manager/tests/test_aptsources.py'
89--- landscape/manager/tests/test_aptsources.py 2017-04-05 07:25:48 +0000
90+++ landscape/manager/tests/test_aptsources.py 2017-04-05 14:19:44 +0000
91@@ -3,7 +3,6 @@
92 import mock
93
94 from twisted.internet.defer import Deferred, succeed
95-from twisted.python.compat import _PY3
96
97 from landscape.manager.aptsources import AptSources
98 from landscape.manager.plugin import SUCCEEDED, FAILED
99@@ -469,7 +468,8 @@
100 deferred = Deferred()
101
102 def _run_process(command, args, env={}, path=None, uid=None, gid=None):
103- self.assertEqual(find_reporter_command(), command)
104+ self.assertEqual(
105+ find_reporter_command(self.manager.config), command)
106 self.assertEqual(["--force-apt-update", "--config=%s" %
107 self.manager.config.config], args)
108 deferred.callback(("ok", "", 0))
109
110=== modified file 'landscape/manager/tests/test_packagemanager.py'
111--- landscape/manager/tests/test_packagemanager.py 2017-01-09 14:29:54 +0000
112+++ landscape/manager/tests/test_packagemanager.py 2017-04-05 14:19:44 +0000
113@@ -1,5 +1,6 @@
114 import mock
115 import os
116+import os.path
117
118 from twisted.internet.defer import Deferred
119
120@@ -20,6 +21,7 @@
121 def setUp(self):
122 """Initialize test helpers and create a sample package store."""
123 super(PackageManagerTest, self).setUp()
124+ self.config = self.broker_service.config
125 self.package_store = PackageStore(os.path.join(self.data_path,
126 "package/database"))
127 self.package_manager = PackageManager()
128@@ -29,8 +31,7 @@
129 If the package sqlite database file doesn't exist yet, it is created
130 upon message handling.
131 """
132- filename = os.path.join(self.broker_service.config.data_path,
133- "package/database")
134+ filename = os.path.join(self.config.data_path, "package/database")
135 os.unlink(filename)
136 self.assertFalse(os.path.isfile(filename))
137
138@@ -179,21 +180,21 @@
139 self.package_manager.spawn_handler.assert_called_once_with(
140 ReleaseUpgrader)
141
142- @mock.patch("landscape.package.changer.find_changer_command")
143- def test_spawn_changer(self, find_command_mock):
144+ def test_spawn_changer(self):
145 """
146 The L{PackageManager.spawn_handler} method executes the correct command
147 when passed the L{PackageChanger} class as argument.
148 """
149- command = self.makeFile("#!/bin/sh\necho 'I am the changer!' >&2\n")
150- os.chmod(command, 0o755)
151- find_command_mock.return_value = command
152+ command = self.write_script(
153+ self.config,
154+ "landscape-package-changer",
155+ "#!/bin/sh\necho 'I am the changer!' >&2\n")
156+ self.manager.config = self.config
157
158 self.package_store.add_task("changer", "Do something!")
159
160 self.manager.add(self.package_manager)
161 result = self.package_manager.spawn_handler(PackageChanger)
162- find_command_mock.assert_called_once_with()
163
164 def got_result(result):
165 log = self.logfile.getvalue()
166@@ -202,21 +203,20 @@
167
168 return result.addCallback(got_result)
169
170- @mock.patch(
171- "landscape.package.releaseupgrader.find_release_upgrader_command")
172- def test_spawn_release_upgrader(self, find_command_mock):
173+ def test_spawn_release_upgrader(self):
174 """
175 The L{PackageManager.spawn_handler} method executes the correct command
176 when passed the L{ReleaseUpgrader} class as argument.
177 """
178- command = self.makeFile("#!/bin/sh\necho 'I am the upgrader!' >&2\n")
179- os.chmod(command, 0o755)
180- find_command_mock.return_value = command
181+ command = self.write_script(
182+ self.config,
183+ "landscape-release-upgrader",
184+ "#!/bin/sh\necho 'I am the upgrader!' >&2\n")
185+ self.manager.config = self.config
186
187 self.package_store.add_task("release-upgrader", "Do something!")
188 self.manager.add(self.package_manager)
189 result = self.package_manager.spawn_handler(ReleaseUpgrader)
190- find_command_mock.assert_called_once_with()
191
192 def got_result(result):
193 log = self.logfile.getvalue()
194@@ -225,15 +225,17 @@
195
196 return result.addCallback(got_result)
197
198- @mock.patch("landscape.package.changer.find_changer_command")
199- def test_spawn_handler_without_output(self, find_command_mock):
200- find_command_mock.return_value = "/bin/true"
201+ def test_spawn_handler_without_output(self):
202+ self.write_script(
203+ self.config,
204+ "landscape-package-changer",
205+ "#!/bin/sh\n/bin/true")
206+ self.manager.config = self.config
207
208 self.package_store.add_task("changer", "Do something!")
209
210 self.manager.add(self.package_manager)
211 result = self.package_manager.spawn_handler(PackageChanger)
212- find_command_mock.assert_called_once_with()
213
214 def got_result(result):
215 log = self.logfile.getvalue()
216@@ -241,18 +243,18 @@
217
218 return result.addCallback(got_result)
219
220- @mock.patch("landscape.package.changer.find_changer_command")
221- def test_spawn_handler_copies_environment(self, find_command_mock):
222- command = self.makeFile("#!/bin/sh\necho VAR: $VAR\n")
223- os.chmod(command, 0o755)
224- find_command_mock.return_value = command
225+ def test_spawn_handler_copies_environment(self):
226+ command = self.write_script(
227+ self.config,
228+ "landscape-package-changer",
229+ "#!/bin/sh\necho VAR: $VAR\n")
230+ self.manager.config = self.config
231
232 self.manager.add(self.package_manager)
233 self.package_store.add_task("changer", "Do something!")
234
235 os.environ["VAR"] = "HI!"
236 result = self.package_manager.spawn_handler(PackageChanger)
237- find_command_mock.assert_called_once_with()
238
239 def got_result(result):
240 log = self.logfile.getvalue()
241@@ -261,16 +263,16 @@
242
243 return result.addCallback(got_result)
244
245- @mock.patch("landscape.package.changer.find_changer_command")
246- def test_spawn_handler_passes_quiet_option(self, find_command_mock):
247- command = self.makeFile("#!/bin/sh\necho OPTIONS: $@\n")
248- os.chmod(command, 0o755)
249- find_command_mock.return_value = command
250+ def test_spawn_handler_passes_quiet_option(self):
251+ command = self.write_script(
252+ self.config,
253+ "landscape-package-changer",
254+ "#!/bin/sh\necho OPTIONS: $@\n")
255+ self.manager.config = self.config
256
257 self.manager.add(self.package_manager)
258 self.package_store.add_task("changer", "Do something!")
259 result = self.package_manager.spawn_handler(PackageChanger)
260- find_command_mock.assert_called_once_with()
261
262 def got_result(result):
263 log = self.logfile.getvalue()
264@@ -292,22 +294,22 @@
265
266 return result.addCallback(got_result)
267
268- @mock.patch("landscape.package.changer.find_changer_command")
269- def test_spawn_handler_doesnt_chdir(self, find_command_mock):
270- command = self.makeFile("#!/bin/sh\necho RUN\n")
271- os.chmod(command, 0o755)
272+ def test_spawn_handler_doesnt_chdir(self):
273+ self.write_script(
274+ self.config,
275+ "landscape-package-changer",
276+ "#!/bin/sh\necho RUN\n")
277+ self.manager.config = self.config
278+
279 cwd = os.getcwd()
280 self.addCleanup(os.chdir, cwd)
281 dir = self.makeDir()
282 os.chdir(dir)
283 os.chmod(dir, 0)
284
285- find_command_mock.return_value = command
286-
287 self.manager.add(self.package_manager)
288 self.package_store.add_task("changer", "Do something!")
289 result = self.package_manager.spawn_handler(PackageChanger)
290- find_command_mock.assert_called_once_with()
291
292 def got_result(result):
293 log = self.logfile.getvalue()
294
295=== modified file 'landscape/monitor/packagemonitor.py'
296--- landscape/monitor/packagemonitor.py 2017-04-04 08:50:05 +0000
297+++ landscape/monitor/packagemonitor.py 2017-04-05 14:19:44 +0000
298@@ -14,13 +14,14 @@
299 run_interval = 1800
300 scope = "package"
301
302+ _reporter_command = None
303+
304 def __init__(self, package_store_filename=None):
305 super(PackageMonitor, self).__init__()
306 if package_store_filename:
307 self._package_store = PackageStore(package_store_filename)
308 else:
309 self._package_store = None
310- self._reporter_command = find_reporter_command()
311
312 def register(self, registry):
313 self.config = registry.config
314@@ -117,6 +118,8 @@
315 else:
316 env["FAKE_GLOBAL_PACKAGE_STORE"] = "1"
317
318+ if self._reporter_command is None:
319+ self._reporter_command = find_reporter_command(self.config)
320 # path is set to None so that getProcessOutput does not
321 # chdir to "." see bug #211373
322 env = encode_values(env)
323
324=== modified file 'landscape/monitor/tests/test_packagemonitor.py'
325--- landscape/monitor/tests/test_packagemonitor.py 2017-03-30 07:57:04 +0000
326+++ landscape/monitor/tests/test_packagemonitor.py 2017-04-05 14:19:44 +0000
327@@ -129,12 +129,10 @@
328 self.assertEqual(task.data, message)
329
330 def test_spawn_reporter(self):
331- command = self.makeFile("#!/bin/sh\necho 'I am the reporter!' >&2\n")
332- os.chmod(command, 0o755)
333- find_command_mock_patcher = mock.patch(
334- "landscape.monitor.packagemonitor.find_reporter_command",
335- return_value=command)
336- find_command_mock_patcher.start()
337+ command = self.write_script(
338+ self.config,
339+ "landscape-package-reporter",
340+ "#!/bin/sh\necho 'I am the reporter!' >&2\n")
341
342 package_monitor = PackageMonitor(self.package_store_filename)
343 self.monitor.add(package_monitor)
344@@ -144,15 +142,14 @@
345 log = self.logfile.getvalue()
346 self.assertIn("I am the reporter!", log)
347 self.assertNotIn(command, log)
348- find_command_mock_patcher.stop()
349
350 return result.addCallback(got_result)
351
352 def test_spawn_reporter_without_output(self):
353- find_command_mock_patcher = mock.patch(
354- "landscape.monitor.packagemonitor.find_reporter_command",
355- return_value="/bin/true")
356- find_command_mock_patcher.start()
357+ self.write_script(
358+ self.config,
359+ "landscape-package-reporter",
360+ "#!/bin/sh\n/bin/true")
361
362 package_monitor = PackageMonitor(self.package_store_filename)
363 self.monitor.add(package_monitor)
364@@ -161,17 +158,14 @@
365 def got_result(result):
366 log = self.logfile.getvalue()
367 self.assertNotIn("reporter output", log)
368- find_command_mock_patcher.stop()
369
370 return result.addCallback(got_result)
371
372 def test_spawn_reporter_copies_environment(self):
373- command = self.makeFile("#!/bin/sh\necho VAR: $VAR\n")
374- os.chmod(command, 0o755)
375- find_command_mock_patcher = mock.patch(
376- "landscape.monitor.packagemonitor.find_reporter_command",
377- return_value=command)
378- find_command_mock_patcher.start()
379+ command = self.write_script(
380+ self.config,
381+ "landscape-package-reporter",
382+ "#!/bin/sh\necho VAR: $VAR\n")
383
384 package_monitor = PackageMonitor(self.package_store_filename)
385 self.monitor.add(package_monitor)
386@@ -184,17 +178,14 @@
387 log = self.logfile.getvalue()
388 self.assertIn("VAR: HI!", log)
389 self.assertNotIn(command, log)
390- find_command_mock_patcher.stop()
391
392 return result.addCallback(got_result)
393
394 def test_spawn_reporter_passes_quiet_option(self):
395- command = self.makeFile("#!/bin/sh\necho OPTIONS: $@\n")
396- os.chmod(command, 0o755)
397- find_command_mock_patcher = mock.patch(
398- "landscape.monitor.packagemonitor.find_reporter_command",
399- return_value=command)
400- find_command_mock_patcher.start()
401+ command = self.write_script(
402+ self.config,
403+ "landscape-package-reporter",
404+ "#!/bin/sh\necho OPTIONS: $@\n")
405
406 package_monitor = PackageMonitor(self.package_store_filename)
407 self.monitor.add(package_monitor)
408@@ -205,7 +196,6 @@
409 log = self.logfile.getvalue()
410 self.assertIn("OPTIONS: --quiet", log)
411 self.assertNotIn(command, log)
412- find_command_mock_patcher.stop()
413
414 return result.addCallback(got_result)
415
416@@ -276,19 +266,16 @@
417 self.assertSingleReporterTask(task.data, task.id)
418
419 def test_spawn_reporter_doesnt_chdir(self):
420- command = self.makeFile("#!/bin/sh\necho RUN\n")
421- os.chmod(command, 0o755)
422+ self.write_script(
423+ self.config,
424+ "landscape-package-reporter",
425+ "#!/bin/sh\necho RUN\n")
426 cwd = os.getcwd()
427 self.addCleanup(os.chdir, cwd)
428 dir = self.makeDir()
429 os.chdir(dir)
430 os.chmod(dir, 0)
431
432- find_command_mock_patcher = mock.patch(
433- "landscape.monitor.packagemonitor.find_reporter_command",
434- return_value=command)
435- find_command_mock_patcher.start()
436-
437 package_monitor = PackageMonitor(self.package_store_filename)
438 self.monitor.add(package_monitor)
439
440@@ -299,7 +286,6 @@
441 self.assertIn("RUN", log)
442 # restore permissions to the dir so tearDown can clean it up
443 os.chmod(dir, 0o766)
444- find_command_mock_patcher.stop()
445
446 return result.addCallback(got_result)
447
448
449=== modified file 'landscape/monitor/tests/test_processorinfo.py'
450--- landscape/monitor/tests/test_processorinfo.py 2017-03-30 08:53:45 +0000
451+++ landscape/monitor/tests/test_processorinfo.py 2017-04-05 14:19:44 +0000
452@@ -389,7 +389,7 @@
453 processor 1: version = FF, identification = 018F67, machine = 2964
454 processor 2: version = FF, identification = 018F67, machine = 2964
455 processor 3: version = FF, identification = 018F67, machine = 2964
456-""" # noqa
457+""" # noqa
458
459 def test_read_sample_s390x_data(self):
460 """Ensure the plugin can parse /proc/cpuinfo from an IBM zSeries machine."""
461@@ -455,7 +455,7 @@
462 address sizes : 40 bits physical, 48 bits virtual
463 power management: ts fid vid ttp
464
465-"""
466+""" # noqa
467
468 UP_PENTIUM_M = """
469 processor : 0
470@@ -477,7 +477,7 @@
471 flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss tm pbe nx est tm2
472 bogomips : 1198.25
473
474-"""
475+""" # noqa
476
477 def setUp(self):
478 LandscapeTest.setUp(self)
479
480=== modified file 'landscape/package/changer.py'
481--- landscape/package/changer.py 2017-03-13 15:15:46 +0000
482+++ landscape/package/changer.py 2017-04-05 14:19:44 +0000
483@@ -1,7 +1,6 @@
484 import logging
485 import base64
486 import time
487-import sys
488 import os
489 import pwd
490 import grp
491@@ -14,6 +13,7 @@
492 POLICY_STRICT, POLICY_ALLOW_INSTALLS, POLICY_ALLOW_ALL_CHANGES,
493 UNKNOWN_PACKAGE_DATA_TIMEOUT)
494
495+from landscape.deployment import get_bindir
496 from landscape.lib.fs import create_binary_file
497 from landscape.lib.log import log_failure
498 from landscape.package.reporter import find_reporter_command
499@@ -101,7 +101,7 @@
500 if os.getuid() == 0:
501 os.setgid(grp.getgrnam("landscape").gr_gid)
502 os.setuid(pwd.getpwnam("landscape").pw_uid)
503- command = find_reporter_command()
504+ command = find_reporter_command(self._config)
505 if self._config.config is not None:
506 command += " -c %s" % self._config.config
507 os.system(command)
508@@ -374,14 +374,16 @@
509 "result-code": 1}
510 return self._broker.send_message(response, self._session_id, True)
511
512- @staticmethod
513- def find_command():
514- return find_changer_command()
515-
516-
517-def find_changer_command():
518- dirname = os.path.dirname(os.path.abspath(sys.argv[0]))
519- return os.path.join(dirname, "landscape-package-changer")
520+ @classmethod
521+ def find_command(cls, config=None):
522+ """Return the path to the package-changer script.
523+
524+ The script's directory is derived from the provided config.
525+ If that is None or doesn't have a "bindir" then directory of
526+ sys.argv[0] is returned.
527+ """
528+ bindir = get_bindir(config)
529+ return os.path.join(bindir, "landscape-package-changer")
530
531
532 def main(args):
533
534=== modified file 'landscape/package/releaseupgrader.py'
535--- landscape/package/releaseupgrader.py 2017-03-22 09:29:17 +0000
536+++ landscape/package/releaseupgrader.py 2017-04-05 14:19:44 +0000
537@@ -4,11 +4,11 @@
538 import os
539 import pwd
540 import shutil
541-import sys
542 import tarfile
543
544 from twisted.internet.defer import succeed
545
546+from landscape.deployment import get_bindir
547 from landscape.lib.fetch import url_to_filename, fetch_to_files
548 from landscape.lib.lsb_release import parse_lsb_release, LSB_RELEASE_FILENAME
549 from landscape.lib.gpg import gpg_verify
550@@ -252,7 +252,7 @@
551 uid = None
552 gid = None
553
554- reporter = find_reporter_command()
555+ reporter = find_reporter_command(self._config)
556
557 # Force an apt-update run, because the sources.list has changed
558 args = ["--force-apt-update"]
559@@ -274,9 +274,11 @@
560
561 return self._send_message(message)
562
563- @staticmethod
564- def find_command():
565- return find_release_upgrader_command()
566+ @classmethod
567+ def find_command(cls, config=None):
568+ """Return the path to the landscape-release-upgrader script."""
569+ bindir = get_bindir(config)
570+ return os.path.join(bindir, "landscape-release-upgrader")
571
572 def _send_message(self, message):
573 """Acquire a session ID and send the given message."""
574@@ -289,12 +291,6 @@
575 return deferred
576
577
578-def find_release_upgrader_command():
579- """Return the path to the landscape-release-upgrader script."""
580- dirname = os.path.dirname(os.path.abspath(sys.argv[0]))
581- return os.path.join(dirname, "landscape-release-upgrader")
582-
583-
584 def main(args):
585 if os.getpgrp() != os.getpid():
586 os.setsid()
587
588=== modified file 'landscape/package/reporter.py'
589--- landscape/package/reporter.py 2017-03-21 17:00:34 +0000
590+++ landscape/package/reporter.py 2017-04-05 14:19:44 +0000
591@@ -5,7 +5,6 @@
592
593 import logging
594 import time
595-import sys
596 import os
597 import glob
598 import apt_pkg
599@@ -13,6 +12,7 @@
600 from twisted.internet.defer import (
601 Deferred, succeed, inlineCallbacks, returnValue)
602
603+from landscape.deployment import get_bindir
604 from landscape.lib import bpickle
605 from landscape.lib.sequenceranges import sequence_to_ranges
606 from landscape.lib.twisted_util import gather_results, spawn_process
607@@ -751,6 +751,6 @@
608 return run_task_handler(PackageReporter, args)
609
610
611-def find_reporter_command():
612- dirname = os.path.dirname(os.path.abspath(sys.argv[0]))
613- return os.path.join(dirname, "landscape-package-reporter")
614+def find_reporter_command(config=None):
615+ bindir = get_bindir(config)
616+ return os.path.join(bindir, "landscape-package-reporter")
617
618=== modified file 'landscape/package/tests/test_changer.py'
619--- landscape/package/tests/test_changer.py 2017-03-21 18:03:57 +0000
620+++ landscape/package/tests/test_changer.py 2017-04-05 14:19:44 +0000
621@@ -12,7 +12,7 @@
622
623 from landscape.lib.fs import create_text_file, read_text_file, touch_file
624 from landscape.package.changer import (
625- PackageChanger, main, find_changer_command, UNKNOWN_PACKAGE_DATA_TIMEOUT,
626+ PackageChanger, main, UNKNOWN_PACKAGE_DATA_TIMEOUT,
627 SUCCESS_RESULT, DEPENDENCY_ERROR_RESULT, POLICY_ALLOW_INSTALLS,
628 POLICY_ALLOW_ALL_CHANGES, ERROR_RESULT)
629 from landscape.package.store import PackageStore
630@@ -662,15 +662,14 @@
631
632 @patch("os.system")
633 def test_spawn_reporter_after_running(self, system_mock):
634- with patch("landscape.package.changer.find_reporter_command",
635- return_value="/fake/bin/landscape-package-reporter"):
636- # Add a task that will do nothing besides producing an
637- # answer. The reporter is only spawned if at least one
638- # task was handled.
639- self.store.add_task("changer", {"type": "change-packages",
640- "operation-id": 123})
641+ self.config.bindir = "/fake/bin"
642+ # Add a task that will do nothing besides producing an
643+ # answer. The reporter is only spawned if at least one
644+ # task was handled.
645+ self.store.add_task("changer", {"type": "change-packages",
646+ "operation-id": 123})
647
648- self.successResultOf(self.changer.run())
649+ self.successResultOf(self.changer.run())
650
651 system_mock.assert_called_once_with(
652 "/fake/bin/landscape-package-reporter")
653@@ -679,15 +678,14 @@
654 def test_spawn_reporter_after_running_with_config(self, system_mock):
655 """The changer passes the config to the reporter when running it."""
656 self.config.config = "test.conf"
657+ self.config.bindir = "/fake/bin"
658
659- with patch("landscape.package.changer.find_reporter_command",
660- return_value="/fake/bin/landscape-package-reporter"):
661- # Add a task that will do nothing besides producing an
662- # answer. The reporter is only spawned if at least one
663- # task was handled.
664- self.store.add_task("changer", {"type": "change-packages",
665- "operation-id": 123})
666- self.successResultOf(self.changer.run())
667+ # Add a task that will do nothing besides producing an
668+ # answer. The reporter is only spawned if at least one
669+ # task was handled.
670+ self.store.add_task("changer", {"type": "change-packages",
671+ "operation-id": 123})
672+ self.successResultOf(self.changer.run())
673
674 system_mock.assert_called_once_with(
675 "/fake/bin/landscape-package-reporter -c test.conf")
676@@ -703,6 +701,7 @@
677 to report the recent changes. If we're running as root, we want to
678 change to the "landscape" user and "landscape" group.
679 """
680+ self.config.bindir = "/fake/bin"
681
682 class FakeGroup(object):
683 gr_gid = 199
684@@ -713,15 +712,12 @@
685 # We are running as root
686 with patch("grp.getgrnam", return_value=FakeGroup()) as grnam_mock:
687 with patch("pwd.getpwnam", return_value=FakeUser()) as pwnam_mock:
688- with patch(
689- "landscape.package.changer.find_reporter_command",
690- return_value="/fake/bin/landscape-package-reporter"):
691- # Add a task that will do nothing besides producing an
692- # answer. The reporter is only spawned if at least
693- # one task was handled.
694- self.store.add_task("changer", {"type": "change-packages",
695- "operation-id": 123})
696- self.successResultOf(self.changer.run())
697+ # Add a task that will do nothing besides producing an
698+ # answer. The reporter is only spawned if at least
699+ # one task was handled.
700+ self.store.add_task("changer", {"type": "change-packages",
701+ "operation-id": 123})
702+ self.successResultOf(self.changer.run())
703
704 grnam_mock.assert_called_once_with("landscape")
705 setgid_mock.assert_called_once_with(199)
706@@ -778,20 +774,19 @@
707 pgrp.assert_called_once_with()
708 task.assert_called_once_with(PackageChanger, ["ARGS"])
709
710- def test_find_changer_command(self):
711- dirname = self.makeDir()
712- filename = self.makeFile("", dirname=dirname,
713- basename="landscape-package-changer")
714-
715- saved_argv = sys.argv
716- try:
717- sys.argv = [os.path.join(dirname, "landscape-monitor")]
718-
719- command = find_changer_command()
720-
721- self.assertEqual(command, filename)
722- finally:
723- sys.argv = saved_argv
724+ def test_find_command_with_bindir(self):
725+ self.config.bindir = "/spam/eggs"
726+ command = PackageChanger.find_command(self.config)
727+
728+ self.assertEqual("/spam/eggs/landscape-package-changer", command)
729+
730+ def test_find_command_default(self):
731+ expected = os.path.join(
732+ os.path.dirname(os.path.abspath(sys.argv[0])),
733+ "landscape-package-changer")
734+ command = PackageChanger.find_command()
735+
736+ self.assertEqual(expected, command)
737
738 def test_transaction_error_with_unicode_data(self):
739 self.store.set_hash_ids({HASH1: 1})
740
741=== modified file 'landscape/package/tests/test_releaseupgrader.py'
742--- landscape/package/tests/test_releaseupgrader.py 2017-03-23 07:43:57 +0000
743+++ landscape/package/tests/test_releaseupgrader.py 2017-04-05 14:19:44 +0000
744@@ -502,20 +502,20 @@
745 packages.
746 """
747 upgrade_tool_directory = self.config.upgrade_tool_directory
748- open(os.path.join(upgrade_tool_directory, "somefile"), "w").close()
749+ with open(os.path.join(upgrade_tool_directory, "somefile"), "w"):
750+ pass
751 os.mkdir(os.path.join(upgrade_tool_directory, "somedir"))
752
753- reporter_filename = self.makeFile("#!/bin/sh\n"
754- "echo $@\n"
755- "echo $(pwd)\n")
756- os.chmod(reporter_filename, 0o755)
757+ self.write_script(
758+ self.config,
759+ "landscape-package-reporter",
760+ "#!/bin/sh\n"
761+ "echo $@\n"
762+ "echo $(pwd)\n")
763
764 deferred = Deferred()
765
766- @mock.patch("landscape.package.releaseupgrader.find_reporter_command")
767- def do_test(find_reporter_mock):
768-
769- find_reporter_mock.return_value = reporter_filename
770+ def do_test():
771 result = self.upgrader.finish()
772
773 def check_result(args):
774@@ -526,7 +526,6 @@
775 b"--force-apt-update\n%s\n" % os.getcwd().encode("utf-8"))
776 self.assertEqual(err, b"")
777 self.assertEqual(code, 0)
778- find_reporter_mock.assert_called_once_with()
779
780 result.addCallback(check_result)
781 result.chainDeferred(deferred)
782@@ -537,11 +536,7 @@
783 @mock.patch("grp.getgrnam")
784 @mock.patch("pwd.getpwnam")
785 @mock.patch("os.getuid", return_value=0)
786- @mock.patch("landscape.package.releaseupgrader.find_reporter_command",
787- return_value="reporter")
788- def test_finish_as_root(
789- self, find_reporter_mock, getuid_mock, getpwnam_mock,
790- getgrnam_mock):
791+ def test_finish_as_root(self, getuid_mock, getpwnam_mock, getgrnam_mock):
792 """
793 If the release-upgrader process is run as root, as it alwyas should,
794 the L{ReleaseUpgrader.finish} method spawns the package-reporter with
795@@ -573,7 +568,6 @@
796 reactor.spawnProcess = saved_spawn_process
797 self.assertEqual(spawn_process_calls, [True])
798
799- find_reporter_mock.assert_called_once_with()
800 getuid_mock.assert_called_once_with()
801 getpwnam_mock.assert_called_once_with("landscape")
802 getgrnam_mock.assert_called_once_with("landscape")
803@@ -583,16 +577,15 @@
804 The L{ReleaseUpgrader.finish} method passes over to the reporter the
805 configuration file the release-upgrader was called with.
806 """
807- reporter_filename = self.makeFile("#!/bin/sh\necho $@\n")
808- os.chmod(reporter_filename, 0o755)
809+ self.write_script(
810+ self.config,
811+ "landscape-package-reporter",
812+ "#!/bin/sh\necho $@\n")
813 self.config.config = "/some/config"
814
815 deferred = Deferred()
816
817- @mock.patch("landscape.package.releaseupgrader.find_reporter_command")
818- def do_test(find_reporter_mock):
819-
820- find_reporter_mock.return_value = reporter_filename
821+ def do_test():
822 result = self.upgrader.finish()
823
824 def check_result(args):
825@@ -601,7 +594,6 @@
826 b"--config=/some/config\n")
827 self.assertEqual(err, b"")
828 self.assertEqual(code, 0)
829- find_reporter_mock.assert_called_once_with()
830
831 result.addCallback(check_result)
832 result.chainDeferred(deferred)
833
834=== modified file 'landscape/package/tests/test_reporter.py'
835--- landscape/package/tests/test_reporter.py 2017-03-21 17:00:34 +0000
836+++ landscape/package/tests/test_reporter.py 2017-04-05 14:19:44 +0000
837@@ -1116,20 +1116,19 @@
838 self.assertEqual("RESULT", main(["ARGS"]))
839 m.assert_called_once_with(PackageReporter, ["ARGS"])
840
841- def test_find_reporter_command(self):
842- dirname = self.makeDir()
843- filename = self.makeFile("", dirname=dirname,
844- basename="landscape-package-reporter")
845-
846- saved_argv = sys.argv
847- try:
848- sys.argv = [os.path.join(dirname, "landscape-monitor")]
849-
850- command = find_reporter_command()
851-
852- self.assertEqual(command, filename)
853- finally:
854- sys.argv = saved_argv
855+ def test_find_reporter_command_with_bindir(self):
856+ self.config.bindir = "/spam/eggs"
857+ command = find_reporter_command(self.config)
858+
859+ self.assertEqual("/spam/eggs/landscape-package-reporter", command)
860+
861+ def test_find_reporter_command_default(self):
862+ expected = os.path.join(
863+ os.path.dirname(os.path.abspath(sys.argv[0])),
864+ "landscape-package-reporter")
865+ command = find_reporter_command()
866+
867+ self.assertEqual(expected, command)
868
869 def test_resynchronize(self):
870 """
871
872=== modified file 'landscape/tests/helpers.py'
873--- landscape/tests/helpers.py 2017-03-27 06:26:21 +0000
874+++ landscape/tests/helpers.py 2017-04-05 14:19:44 +0000
875@@ -276,6 +276,18 @@
876 self.addCleanup(self._clean_file, path)
877 return path
878
879+ def write_script(self, config, name, content, bindir=None):
880+ """Return the path to the script after writing it to a temp dir."""
881+ if bindir is None:
882+ bindir = self.makeDir()
883+ config.bindir = bindir
884+ filename = self.makeFile(
885+ content,
886+ dirname=bindir,
887+ basename=name)
888+ os.chmod(filename, 0o755)
889+ return filename
890+
891
892 class LandscapeIsolatedTest(LandscapeTest):
893 """TestCase that also runs all test methods in a subprocess."""
894
895=== modified file 'landscape/tests/test_deployment.py'
896--- landscape/tests/test_deployment.py 2017-03-13 15:38:09 +0000
897+++ landscape/tests/test_deployment.py 2017-04-05 14:19:44 +0000
898@@ -2,12 +2,14 @@
899 from textwrap import dedent
900 import mock
901 import os
902+import os.path
903+import sys
904
905 from landscape.compat import StringIO
906 from landscape.lib.fs import read_text_file, create_text_file
907
908 from landscape.deployment import (
909- BaseConfiguration, Configuration, get_versioned_persist)
910+ BaseConfiguration, Configuration, get_versioned_persist, get_bindir)
911 from landscape.manager.config import ManagerConfiguration
912
913 from landscape.tests.helpers import LandscapeTest, LogKeeperHelper
914@@ -711,3 +713,37 @@
915 {"monitor": mock_monitor}):
916 persist = get_versioned_persist(FakeService())
917 mock_monitor.apply.assert_called_with(persist)
918+
919+
920+class GetBindirTest(LandscapeTest):
921+
922+ BIN_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
923+
924+ def test_config_has_valid_bindir(self):
925+ """get_bindir() returns the directory name found in the config."""
926+ cfg = Configuration()
927+ cfg.bindir = "/spam/eggs"
928+ bindir = get_bindir(cfg)
929+
930+ self.assertEqual("/spam/eggs", bindir)
931+
932+ def test_config_has_None_bindir(self):
933+ """get_bindir() """
934+ cfg = Configuration()
935+ cfg.bindir = None
936+ bindir = get_bindir(cfg)
937+
938+ self.assertEqual(self.BIN_DIR, bindir)
939+
940+ def test_config_has_no_bindir(self):
941+ """get_bindir() """
942+ cfg = object()
943+ bindir = get_bindir(cfg)
944+
945+ self.assertEqual(self.BIN_DIR, bindir)
946+
947+ def test_config_is_None(self):
948+ """get_bindir() """
949+ bindir = get_bindir(None)
950+
951+ self.assertEqual(self.BIN_DIR, bindir)
952
953=== modified file 'landscape/tests/test_watchdog.py'
954--- landscape/tests/test_watchdog.py 2017-04-04 08:50:05 +0000
955+++ landscape/tests/test_watchdog.py 2017-04-05 14:19:44 +0000
956@@ -517,12 +517,10 @@
957
958 connector_factory = RemoteStubBrokerConnector
959
960+ EXEC_NAME = "landscape-broker"
961+
962 def setUp(self):
963 super(DaemonTestBase, self).setUp()
964- self.exec_dir = self.makeDir()
965- self.exec_name = os.path.join(self.exec_dir, "landscape-broker")
966- self.saved_argv = sys.argv
967- sys.argv = [os.path.join(self.exec_dir, "arv0_execname")]
968
969 if hasattr(self, "broker_service"):
970 # DaemonBrokerTest
971@@ -539,7 +537,6 @@
972 self.daemon = self.get_daemon()
973
974 def tearDown(self):
975- sys.argv = self.saved_argv
976 if hasattr(self, "broker_service"):
977 # DaemonBrokerTest
978 self.broker_service.stopService()
979@@ -552,7 +549,7 @@
980 else:
981 MyDaemon = Daemon
982 daemon = MyDaemon(self.connector, **kwargs)
983- daemon.program = os.path.basename(self.exec_name)
984+ daemon.program = self.EXEC_NAME
985 daemon.factor = 0.01
986 return daemon
987
988@@ -564,25 +561,39 @@
989 self._mtime = os.path.getmtime(filename)
990 self._filename = filename
991
992- def wait(self):
993+ def wait(self, timeout=60):
994+ if timeout:
995+ end = time.time() + timeout
996 while self._mtime == os.path.getmtime(self._filename):
997 time.sleep(0.1)
998+ if timeout and time.time() > end:
999+ raise RuntimeError(
1000+ "timed out after {} seconds".format(timeout))
1001
1002
1003 class DaemonTest(DaemonTestBase):
1004
1005+ def _write_script(self, content):
1006+ filename = self.write_script(self.config, self.EXEC_NAME, content)
1007+ self.daemon.BIN_DIR = self.config.bindir
1008+ return filename
1009+
1010 def test_find_executable_works(self):
1011- self.makeFile("I'm the broker.", path=self.exec_name)
1012- self.assertEqual(self.daemon.find_executable(), self.exec_name)
1013+ expected = self._write_script("I'm the broker.")
1014+ command = self.daemon.find_executable()
1015+
1016+ self.assertEqual(expected, command)
1017
1018 def test_find_executable_cant_find_file(self):
1019- self.assertRaises(ExecutableNotFoundError, self.daemon.find_executable)
1020+ self.daemon.BIN_DIR = "/fake/bin"
1021+
1022+ with self.assertRaises(ExecutableNotFoundError):
1023+ self.daemon.find_executable()
1024
1025 def test_start_process(self):
1026 output_filename = self.makeFile("NOT RUN")
1027- self.makeFile('#!/bin/sh\necho "RUN $@" > %s' % output_filename,
1028- path=self.exec_name)
1029- os.chmod(self.exec_name, 0o755)
1030+ self._write_script(
1031+ '#!/bin/sh\necho "RUN $@" > %s' % output_filename)
1032
1033 waiter = FileChangeWaiter(output_filename)
1034
1035@@ -597,16 +608,16 @@
1036
1037 def test_start_process_with_verbose(self):
1038 output_filename = self.makeFile("NOT RUN")
1039- self.makeFile('#!/bin/sh\necho "RUN $@" > %s' % output_filename,
1040- path=self.exec_name)
1041- os.chmod(self.exec_name, 0o755)
1042+ self._write_script(
1043+ '#!/bin/sh\necho "RUN $@" > %s' % output_filename)
1044
1045 waiter = FileChangeWaiter(output_filename)
1046
1047 daemon = self.get_daemon(verbose=True)
1048+ daemon.BIN_DIR = self.config.bindir
1049 daemon.start()
1050
1051- waiter.wait()
1052+ waiter.wait(timeout=10)
1053
1054 self.assertEqual(open(output_filename).read(),
1055 "RUN --ignore-sigint\n")
1056@@ -616,15 +627,14 @@
1057 def test_kill_process_with_sigterm(self):
1058 """The stop() method sends SIGTERM to the subprocess."""
1059 output_filename = self.makeFile("NOT RUN")
1060- self.makeFile("#!%s\n"
1061- "import time\n"
1062- "file = open(%r, 'w')\n"
1063- "file.write('RUN')\n"
1064- "file.close()\n"
1065- "time.sleep(1000)\n"
1066- % (sys.executable, output_filename),
1067- path=self.exec_name)
1068- os.chmod(self.exec_name, 0o755)
1069+ self._write_script(
1070+ ("#!%s\n"
1071+ "import time\n"
1072+ "file = open(%r, 'w')\n"
1073+ "file.write('RUN')\n"
1074+ "file.close()\n"
1075+ "time.sleep(1000)\n"
1076+ ) % (sys.executable, output_filename))
1077
1078 waiter = FileChangeWaiter(output_filename)
1079 self.daemon.start()
1080@@ -639,16 +649,15 @@
1081 some time after the SIGTERM was issued and didn't work.
1082 """
1083 output_filename = self.makeFile("NOT RUN")
1084- self.makeFile("#!%s\n"
1085- "import signal, os\n"
1086- "signal.signal(signal.SIGTERM, signal.SIG_IGN)\n"
1087- "file = open(%r, 'w')\n"
1088- "file.write('RUN')\n"
1089- "file.close()\n"
1090- "os.kill(os.getpid(), signal.SIGSTOP)\n"
1091- % (sys.executable, output_filename),
1092- path=self.exec_name)
1093- os.chmod(self.exec_name, 0o755)
1094+ self._write_script(
1095+ ("#!%s\n"
1096+ "import signal, os\n"
1097+ "signal.signal(signal.SIGTERM, signal.SIG_IGN)\n"
1098+ "file = open(%r, 'w')\n"
1099+ "file.write('RUN')\n"
1100+ "file.close()\n"
1101+ "os.kill(os.getpid(), signal.SIGSTOP)\n"
1102+ ) % (sys.executable, output_filename))
1103
1104 self.addCleanup(setattr, landscape.watchdog, "SIGKILL_DELAY",
1105 landscape.watchdog.SIGKILL_DELAY)
1106@@ -666,9 +675,8 @@
1107 died.
1108 """
1109 output_filename = self.makeFile("NOT RUN")
1110- self.makeFile('#!/bin/sh\necho "RUN" > %s' % output_filename,
1111- path=self.exec_name)
1112- os.chmod(self.exec_name, 0o755)
1113+ self._write_script(
1114+ '#!/bin/sh\necho "RUN" > %s' % output_filename)
1115
1116 self.daemon.start()
1117
1118@@ -682,9 +690,8 @@
1119 certain amount of time, just like C{wait}.
1120 """
1121 output_filename = self.makeFile("NOT RUN")
1122- self.makeFile('#!/bin/sh\necho "RUN" > %s' % output_filename,
1123- path=self.exec_name)
1124- os.chmod(self.exec_name, 0o755)
1125+ self._write_script(
1126+ '#!/bin/sh\necho "RUN" > %s' % output_filename)
1127
1128 self.daemon.start()
1129
1130@@ -695,7 +702,8 @@
1131 def test_wait_or_die_terminates(self):
1132 """wait_or_die eventually terminates the process."""
1133 output_filename = self.makeFile("NOT RUN")
1134- self.makeFile("""\
1135+ self._write_script(
1136+ """\
1137 #!%(exe)s
1138 import time
1139 import signal
1140@@ -708,10 +716,7 @@
1141 file.close()
1142 signal.signal(signal.SIGTERM, term)
1143 time.sleep(999)
1144- """
1145- % {"exe": sys.executable, "out": output_filename},
1146- path=self.exec_name)
1147- os.chmod(self.exec_name, 0o755)
1148+ """ % {"exe": sys.executable, "out": output_filename})
1149
1150 self.addCleanup(setattr, landscape.watchdog, "GRACEFUL_WAIT_PERIOD",
1151 landscape.watchdog.GRACEFUL_WAIT_PERIOD)
1152@@ -728,16 +733,15 @@
1153 and terminating don't work.
1154 """
1155 output_filename = self.makeFile("NOT RUN")
1156- self.makeFile("#!%s\n"
1157- "import signal, os\n"
1158- "signal.signal(signal.SIGTERM, signal.SIG_IGN)\n"
1159- "file = open(%r, 'w')\n"
1160- "file.write('RUN')\n"
1161- "file.close()\n"
1162- "os.kill(os.getpid(), signal.SIGSTOP)\n"
1163- % (sys.executable, output_filename),
1164- path=self.exec_name)
1165- os.chmod(self.exec_name, 0o755)
1166+ self._write_script(
1167+ ("#!%s\n"
1168+ "import signal, os\n"
1169+ "signal.signal(signal.SIGTERM, signal.SIG_IGN)\n"
1170+ "file = open(%r, 'w')\n"
1171+ "file.write('RUN')\n"
1172+ "file.close()\n"
1173+ "os.kill(os.getpid(), signal.SIGSTOP)\n"
1174+ ) % (sys.executable, output_filename))
1175
1176 self.addCleanup(setattr, landscape.watchdog, "SIGKILL_DELAY",
1177 landscape.watchdog.SIGKILL_DELAY)
1178@@ -789,9 +793,8 @@
1179
1180 output_filename = self.makeFile("NOT RUN")
1181
1182- self.makeFile("#!/bin/sh\necho RUN >> %s" % output_filename,
1183- path=self.exec_name)
1184- os.chmod(self.exec_name, 0o755)
1185+ self._write_script(
1186+ "#!/bin/sh\necho RUN >> %s" % output_filename)
1187
1188 def got_result(result):
1189 self.assertEqual(len(list(open(output_filename))),
1190@@ -813,6 +816,7 @@
1191 reactor.callLater(1, result.callback, None)
1192
1193 daemon = self.get_daemon(reactor=reactor)
1194+ daemon.BIN_DIR = self.config.bindir
1195 daemon.start()
1196
1197 return result
1198@@ -832,9 +836,8 @@
1199
1200 output_filename = self.makeFile("NOT RUN")
1201
1202- self.makeFile("#!/bin/sh\necho RUN >> %s" % output_filename,
1203- path=self.exec_name)
1204- os.chmod(self.exec_name, 0o755)
1205+ self._write_script(
1206+ "#!/bin/sh\necho RUN >> %s" % output_filename)
1207
1208 def got_result(result):
1209 # Pay attention to the +1 bellow. It's the reason for this test.
1210@@ -866,6 +869,7 @@
1211 # It's important to call start() shortly after the mocking above,
1212 # as we don't want anyone else getting the fake time.
1213 daemon = self.get_daemon(reactor=reactor)
1214+ daemon.BIN_DIR = self.config.bindir
1215 daemon.start()
1216
1217 def mock_reactor_stop():
1218@@ -891,7 +895,7 @@
1219 the username of the daemon. It also specifies the gid as the primary
1220 group of that user.
1221 """
1222- self.makeFile("", path=self.exec_name)
1223+ self._write_script("#!/bin/sh")
1224
1225 class getpwnam_result:
1226 pw_uid = 123
1227@@ -903,6 +907,7 @@
1228 reactor = mock.Mock()
1229
1230 daemon = self.get_daemon(reactor=reactor)
1231+ daemon.BIN_DIR = self.config.bindir
1232 daemon.start()
1233
1234 getuid.assert_called_with()
1235@@ -926,10 +931,11 @@
1236 If the watchdog is not running as root, no uid or gid switching will
1237 occur.
1238 """
1239- self.makeFile("", path=self.exec_name)
1240+ self._write_script("#!/bin/sh")
1241
1242 reactor = mock.Mock()
1243 daemon = self.get_daemon(reactor=reactor)
1244+ daemon.BIN_DIR = self.config.bindir
1245 daemon.start()
1246
1247 reactor.spawnProcess.assert_called_with(
1248@@ -943,10 +949,11 @@
1249 If the daemon is specified to run as root, and the watchdog is running
1250 as root, no uid or gid switching will occur.
1251 """
1252- self.makeFile("", path=self.exec_name)
1253+ self._write_script("#!/bin/sh")
1254 reactor = mock.Mock()
1255
1256 daemon = self.get_daemon(reactor=reactor, username="root")
1257+ daemon.BIN_DIR = self.config.bindir
1258 daemon.start()
1259
1260 reactor.spawnProcess.assert_called_with(
1261
1262=== modified file 'landscape/watchdog.py'
1263--- landscape/watchdog.py 2017-04-05 11:55:26 +0000
1264+++ landscape/watchdog.py 2017-04-05 14:19:44 +0000
1265@@ -22,7 +22,7 @@
1266 from twisted.application.service import Service, Application
1267 from twisted.application.app import startApplication
1268
1269-from landscape.deployment import init_logging, Configuration
1270+from landscape.deployment import init_logging, Configuration, get_bindir
1271 from landscape.lib.encoding import encode_values
1272 from landscape.lib.twisted_util import gather_results
1273 from landscape.lib.log import log_failure
1274@@ -76,6 +76,8 @@
1275 factor = 1.1
1276 options = None
1277
1278+ BIN_DIR = None
1279+
1280 def __init__(self, connector, reactor=reactor, verbose=False,
1281 config=None):
1282 self._connector = connector
1283@@ -115,7 +117,7 @@
1284 If the executable can't be found, L{ExecutableNotFoundError} will be
1285 raised.
1286 """
1287- dirname = os.path.dirname(os.path.abspath(sys.argv[0]))
1288+ dirname = self.BIN_DIR or get_bindir()
1289 executable = os.path.join(dirname, self.program)
1290 if not os.path.exists(executable):
1291 raise ExecutableNotFoundError("%s doesn't exist" % (executable,))

Subscribers

People subscribed via source and target branches

to all changes: