7
from twisted.internet.defer import succeed, fail
9
from landscape.package.reporter import find_reporter_command
10
from landscape.package.taskhandler import PackageTaskHandler, run_task_handler
15
DEPENDENCY_ERROR_RESULT = 101
17
UNKNOWN_PACKAGE_DATA_TIMEOUT = 24 * 60 * 60
20
class UnknownPackageData(Exception):
21
"""Raised when an ID or a hash isn't known."""
24
class PackageChanger(PackageTaskHandler):
26
queue_name = "changer"
29
task1 = self._store.get_next_task(self.queue_name)
30
result = super(PackageChanger, self).run()
32
task2 = self._store.get_next_task(self.queue_name)
33
if task1 and task1.id != (task2 and task2.id):
35
os.setuid(pwd.getpwnam("landscape").pw_uid)
36
os.system(find_reporter_command())
37
return result.addCallback(finished)
39
def handle_tasks(self):
40
result = super(PackageChanger, self).handle_tasks()
41
return result.addErrback(self._warn_about_unknown_data)
43
def handle_task(self, task):
45
if message["type"] == "change-packages":
46
result = self._handle_change_packages(message)
47
return result.addErrback(self._check_expired_unknown_data, task)
49
def _warn_about_unknown_data(self, failure):
50
failure.trap(UnknownPackageData)
51
logging.warning("Package data not yet synchronized with server (%r)" %
52
failure.value.args[0])
54
def _check_expired_unknown_data(self, failure, task):
55
failure.trap(UnknownPackageData)
56
if task.timestamp < time.time() - UNKNOWN_PACKAGE_DATA_TIMEOUT:
57
self._warn_about_unknown_data(failure)
58
message = {"type": "change-packages-result",
59
"operation-id": task.data["operation-id"],
60
"result-code": ERROR_RESULT,
61
"result-text": "Package data has changed. "
62
"Please retry the operation."}
63
return self._broker.send_message(message)
67
def _handle_change_packages(self, message):
68
self.ensure_channels_reloaded()
70
self._facade.reset_marks()
72
if message.get("upgrade-all"):
73
for package in self._facade.get_packages():
75
self._facade.mark_upgrade(package)
77
for field, mark_func in [("install", self._facade.mark_install),
78
("remove", self._facade.mark_remove)]:
79
for id in message.get(field, ()):
80
hash = self._store.get_id_hash(id)
82
return fail(UnknownPackageData(id))
83
package = self._facade.get_package_by_hash(hash)
85
return fail(UnknownPackageData(hash))
88
message = {"type": "change-packages-result",
89
"operation-id": message.get("operation-id")}
91
# Delay importing these so that we don't import Smart unless
93
from landscape.package.facade import (
94
DependencyError, TransactionError, SmartError)
98
result = self._facade.perform_changes()
99
except (TransactionError, SmartError), exception:
100
result_code = ERROR_RESULT
101
result = exception.args[0]
102
except DependencyError, exception:
103
result_code = DEPENDENCY_ERROR_RESULT
106
for package in exception.packages:
107
hash = self._facade.get_package_hash(package)
108
id = self._store.get_hash_id(hash)
110
# Will have to wait until the server lets us know about
112
return fail(UnknownPackageData(hash))
113
if package.installed:
114
# Package currently installed. Must remove it.
117
# Package currently available. Must install it.
121
message["must-install"] = installs
124
message["must-remove"] = removals
126
result_code = SUCCESS_RESULT
128
message["result-code"] = result_code
129
if result is not None:
130
message["result-text"] = result
132
logging.info("Queuing message with change package results to "
133
"exchange urgently.")
134
return self._broker.send_message(message, True)
138
if os.getpgrp() != os.getpid():
140
return run_task_handler(PackageChanger, args)
143
def find_changer_command():
144
dirname = os.path.dirname(os.path.abspath(sys.argv[0]))
145
return os.path.join(dirname, "landscape-package-changer")