4
5
from twisted.internet.defer import Deferred, succeed
6
from landscape.lib.dbus_util import get_bus
7
7
from landscape.lib.lock import lock_path, LockError
8
8
from landscape.lib.log import log_failure
9
from landscape.lib.command import run_command, CommandError
9
from landscape.lib.lsb_release import LSB_RELEASE_FILENAME, parse_lsb_release
10
10
from landscape.deployment import Configuration, init_logging
11
11
from landscape.package.store import PackageStore, InvalidHashIdDb
12
12
from landscape.broker.remote import RemoteBroker
15
class PackageTaskHandlerConfiguration(Configuration):
16
"""Specialized configuration for L{PackageTaskHandler}s."""
19
def package_directory(self):
20
"""Get the path to the package directory."""
21
return os.path.join(self.data_path, "package")
24
def store_filename(self):
25
"""Get the path to the SQlite file for the L{PackageStore}."""
26
return os.path.join(self.package_directory, "database")
29
def hash_id_directory(self):
30
"""Get the path to the directory holding the stock hash-id stores."""
31
return os.path.join(self.package_directory, "hash-id")
34
class LazyRemoteBroker(object):
35
"""Wrapper class around L{RemoteBroker} providing lazy initialization.
37
This class is a wrapper around a regular L{RemoteBroker}. It creates
38
the remote broker object only when one of its attributes is first accessed.
40
@note: This behaviour is needed in particular by the ReleaseUpgrader and
41
the PackageChanger, because if the they connect early and DBus gets
42
upgraded while they run, they might crash or not be able to communicate
43
with the broker due to bugs in DBus.
46
def __init__(self, bus):
50
def __getattr__(self, name):
52
from landscape.lib.dbus_util import get_bus
53
self._remote = RemoteBroker(get_bus(self._bus))
54
return getattr(self._remote, name)
15
57
class PackageTaskHandler(object):
59
config_factory = PackageTaskHandlerConfiguration
17
61
queue_name = "default"
62
lsb_release_filename = LSB_RELEASE_FILENAME
19
64
def __init__(self, package_store, package_facade, remote_broker, config):
20
65
self._store = package_store
33
77
return self.handle_tasks()
35
79
def handle_tasks(self):
37
self._handle_next_task(None, deferred)
80
return self._handle_next_task(None)
40
def _handle_next_task(self, result, deferred, last_task=None):
82
def _handle_next_task(self, result, last_task=None):
41
83
if last_task is not None:
42
84
# Last task succeeded. We can safely kill it now.
48
90
# We have another task. Let's handle it.
49
91
result = self.handle_task(task)
50
result.addCallback(self._handle_next_task, deferred, task)
51
result.addErrback(deferred.errback)
92
result.addCallback(self._handle_next_task, task)
54
96
# No more tasks! We're done!
55
deferred.callback(None)
57
99
def handle_task(self, task):
58
100
return succeed(None)
107
# XXX replace this with a L{SmartFacade} method
108
codename = run_command("lsb_release -cs")
109
except CommandError, error:
149
lsb_release_info = parse_lsb_release(self.lsb_release_filename)
150
except IOError, error:
110
151
logging.warning(warning % str(error))
154
codename = lsb_release_info["code-name"]
156
logging.warning(warning % "missing code-name key in %s" %
157
self.lsb_release_filename)
113
160
arch = self._facade.get_arch()
118
165
logging.warning(warning % "unknown dpkg architecture")
121
package_directory = os.path.join(self._config.data_path, "package")
122
hash_id_db_directory = os.path.join(package_directory, "hash-id")
124
return os.path.join(hash_id_db_directory,
125
"%s_%s_%s" % (server_uuid,
168
return os.path.join(self._config.hash_id_directory,
169
"%s_%s_%s" % (server_uuid, codename, arch))
129
171
result = self._broker.get_server_uuid()
130
172
result.addCallback(got_server_uuid)
140
182
if reactor is None:
141
183
from twisted.internet import reactor
143
program_name = cls.queue_name
145
config = Configuration()
185
config = cls.config_factory()
146
186
config.load(args)
148
package_directory = os.path.join(config.data_path, "package")
149
hash_id_directory = os.path.join(package_directory, "hash-id")
150
for directory in [package_directory, hash_id_directory]:
188
for directory in [config.package_directory, config.hash_id_directory]:
151
189
if not os.path.isdir(directory):
152
190
os.mkdir(directory)
154
lock_filename = os.path.join(package_directory, program_name + ".lock")
192
program_name = cls.queue_name
193
lock_filename = os.path.join(config.package_directory,
194
program_name + ".lock")
156
196
lock_path(lock_filename)
157
197
except LockError:
164
init_logging(config, "package-" + program_name)
166
store_filename = os.path.join(package_directory, "database")
204
words = re.findall("[A-Z][a-z]+", cls.__name__)
205
init_logging(config, "-".join(word.lower() for word in words))
168
207
# Setup our umask for Smart to use, this needs to setup file permissions to
173
212
# import Smart unless we need to.
174
213
from landscape.package.facade import SmartFacade
176
package_store = PackageStore(store_filename)
215
package_store = PackageStore(config.store_filename)
177
216
package_facade = SmartFacade()
178
remote = RemoteBroker(get_bus(config.bus))
217
remote = LazyRemoteBroker(config.bus)
180
219
handler = cls(package_store, package_facade, remote, config)
182
221
def got_err(failure):
183
222
log_failure(failure)
185
result = handler.run()
225
result.addCallback(lambda ignored: handler.run())
186
226
result.addErrback(got_err)
187
227
result.addBoth(lambda ignored: reactor.callLater(0, reactor.stop))
228
reactor.callWhenRunning(lambda: result.callback(None))