~free.ekanayaka/landscape-client/karmic-1.5.4-0ubuntu0.9.10.0

« back to all changes in this revision

Viewing changes to landscape/package/reporter.py

  • Committer: Bazaar Package Importer
  • Author(s): Free Ekanayaka
  • Date: 2009-12-16 10:50:05 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20091216105005-bmki8i2of1dmcdkc
Tags: 1.4.0-0ubuntu0.9.10.0
* New upstream release (LP: #497351)

* Bug fixes:
  - Fix landscape daemons fail to start when too many groups are
    available (LP: #456124)
  - Fix landscape programs wake up far too much. (LP: #340843)
  - Fix Package manager fails with 'no such table: task' (LP #465846)
  - Fix test suite leaving temporary files around (LP #476418)
  - Fix the 1hr long wait for user data to be uploaded following a
    resynchronisation (LP #369000)

* Add support for Ubuntu release upgrades:
  - Add helper function to fetch many files at once (LP: #450629)
  - Handle release-upgrade messages in the packagemanager
    plugin (LP: #455217)
  - Add a release-upgrader task handler (LP: #462543)
  - Support upgrade-tool environment variables (LP: #463321)

* Add initial support for Smart package locking:
  - Detect and report changes about Smart package locks (#488108)

* Packaging fixes:
  - Turn unnecessary Pre-Depends on python-gobject into a regular Depends
  - If it's empty, remove /etc/landscape upon purge

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
from landscape.lib.twisted_util import gather_results
12
12
from landscape.lib.fetch import fetch_async
13
13
 
14
 
from landscape.package.taskhandler import PackageTaskHandler, run_task_handler
 
14
from landscape.package.taskhandler import (
 
15
    PackageTaskHandlerConfiguration, PackageTaskHandler, run_task_handler)
15
16
from landscape.package.store import UnknownHashIDRequest
16
17
 
17
18
 
19
20
MAX_UNKNOWN_HASHES_PER_REQUEST = 500
20
21
 
21
22
 
 
23
class PackageReporterConfiguration(PackageTaskHandlerConfiguration):
 
24
    """Specialized configuration for the Landscape package-reporter."""
 
25
 
 
26
    def make_parser(self):
 
27
        """
 
28
        Specialize L{Configuration.make_parser}, adding options
 
29
        reporter-specific options.
 
30
        """
 
31
        parser = super(PackageReporterConfiguration, self).make_parser()
 
32
        parser.add_option("--force-smart-update", default=False,
 
33
                          action="store_true",
 
34
                          help="Force running smart-update.")
 
35
        return parser
 
36
 
 
37
 
22
38
class PackageReporter(PackageTaskHandler):
23
39
    """Report information about the system packages.
24
40
 
26
42
    @cvar smart_update_interval: Time interval in minutes to pass to
27
43
        the C{--after} command line option of C{smart-update}.
28
44
    """
 
45
    config_factory = PackageReporterConfiguration
 
46
 
29
47
    queue_name = "reporter"
 
48
 
30
49
    smart_update_interval = 60
31
50
    smart_update_filename = "/usr/lib/landscape/smart-update"
32
51
 
54
73
 
55
74
        # Finally, verify if we have anything new to report to the server.
56
75
        result.addCallback(lambda x: self.detect_changes())
 
76
        result.addCallback(lambda x: self.detect_package_locks_changes())
57
77
 
58
78
        result.callback(None)
59
79
        return result
135
155
 
136
156
        @return: a deferred returning (out, err, code)
137
157
        """
 
158
        if self._config.force_smart_update:
 
159
            args = ()
 
160
        else:
 
161
            args = ("--after", "%d" % self.smart_update_interval)
138
162
        result = getProcessOutputAndValue(self.smart_update_filename,
139
 
                                          args=("--after", "%d" %
140
 
                                                self.smart_update_interval))
 
163
                                          args=args)
141
164
 
142
165
        def callback((out, err, code)):
143
166
            # smart-update --after N will exit with error code 1 when it
167
190
 
168
191
    def _handle_package_ids(self, message):
169
192
        unknown_hashes = []
170
 
        request_id = message["request-id"]
171
193
 
172
194
        try:
173
195
            request = self._store.get_hash_id_request(message["request-id"])
216
238
        # This problem would happen for example when switching the client from
217
239
        # one Landscape server to another, because the uuid-changed event would
218
240
        # cause a resynchronize task to be created by the monitor. See #417122.
219
 
        #
220
 
        #self._store.clear_hash_id_requests()
221
241
 
222
242
        return succeed(None)
223
243
 
328
348
        request = self._store.add_hash_id_request(unknown_hashes)
329
349
        message["request-id"] = request.id
330
350
        result = self._broker.send_message(message, True)
 
351
 
331
352
        def set_message_id(message_id):
332
353
            request.message_id = message_id
 
354
 
333
355
        def send_message_failed(failure):
334
356
            request.remove()
335
357
            return failure
 
358
 
336
359
        return result.addCallbacks(set_message_id, send_message_failed)
337
360
 
338
361
    def detect_changes(self):
342
365
 
343
366
        - are now installed, and were not;
344
367
        - are now available, and were not;
 
368
        - are now locked, and were not;
345
369
        - were previously available but are not anymore;
346
370
        - were previously installed but are not anymore;
 
371
        - were previously locked but are not anymore;
 
372
 
 
373
        Additionally it will report package locks that:
 
374
 
 
375
        - are now set, and were not;
 
376
        - were previously set but are not anymore;
347
377
 
348
378
        In all cases, the server is notified of the new situation
349
379
        with a "packages" message.
353
383
        old_installed = set(self._store.get_installed())
354
384
        old_available = set(self._store.get_available())
355
385
        old_upgrades = set(self._store.get_available_upgrades())
 
386
        old_locked = set(self._store.get_locked())
356
387
 
357
388
        current_installed = set()
358
389
        current_available = set()
359
390
        current_upgrades = set()
 
391
        current_locked = set()
360
392
 
361
393
        for package in self._facade.get_packages():
362
394
            hash = self._facade.get_package_hash(package)
387
419
                        continue
388
420
                    break
389
421
 
 
422
        for package in self._facade.get_locked_packages():
 
423
            hash = self._facade.get_package_hash(package)
 
424
            id = self._store.get_hash_id(hash)
 
425
            if id is not None:
 
426
                current_locked.add(id)
 
427
 
390
428
        new_installed = current_installed - old_installed
391
429
        new_available = current_available - old_available
392
430
        new_upgrades = current_upgrades - old_upgrades
 
431
        new_locked = current_locked - old_locked
393
432
 
394
433
        not_installed = old_installed - current_installed
395
434
        not_available = old_available - current_available
396
435
        not_upgrades = old_upgrades - current_upgrades
 
436
        not_locked = old_locked - current_locked
397
437
 
398
438
        message = {}
399
439
        if new_installed:
405
445
        if new_upgrades:
406
446
            message["available-upgrades"] = \
407
447
                list(sequence_to_ranges(sorted(new_upgrades)))
 
448
        if new_locked:
 
449
            message["locked"] = \
 
450
                list(sequence_to_ranges(sorted(new_locked)))
408
451
 
409
452
        if not_installed:
410
453
            message["not-installed"] = \
415
458
        if not_upgrades:
416
459
            message["not-available-upgrades"] = \
417
460
                list(sequence_to_ranges(sorted(not_upgrades)))
 
461
        if not_locked:
 
462
            message["not-locked"] = \
 
463
                list(sequence_to_ranges(sorted(not_locked)))
418
464
 
419
465
        if not message:
420
466
            result = succeed(None)
425
471
 
426
472
            logging.info("Queuing message with changes in known packages: "
427
473
                         "%d installed, %d available, %d available upgrades, "
428
 
                         "%d not installed, %d not available, %d not "
429
 
                         "available upgrades."
 
474
                         "%d locked, %d not installed, %d not available, "
 
475
                         "%d not available upgrades, %d not locked."
430
476
                         % (len(new_installed), len(new_available),
431
 
                            len(new_upgrades), len(not_installed),
432
 
                            len(not_available), len(not_upgrades)))
 
477
                            len(new_upgrades), len(new_locked),
 
478
                            len(not_installed), len(not_available),
 
479
                            len(not_upgrades), len(not_locked)))
433
480
 
434
481
        def update_currently_known(result):
435
482
            if new_installed:
438
485
                self._store.remove_installed(not_installed)
439
486
            if new_available:
440
487
                self._store.add_available(new_available)
 
488
            if new_locked:
 
489
                self._store.add_locked(new_locked)
441
490
            if not_available:
442
491
                self._store.remove_available(not_available)
443
492
            if new_upgrades:
444
493
                self._store.add_available_upgrades(new_upgrades)
445
494
            if not_upgrades:
446
495
                self._store.remove_available_upgrades(not_upgrades)
 
496
            if not_locked:
 
497
                self._store.remove_locked(not_locked)
 
498
 
 
499
        result.addCallback(update_currently_known)
 
500
 
 
501
        return result
 
502
 
 
503
    def detect_package_locks_changes(self):
 
504
        """Detect changes in known package locks.
 
505
 
 
506
        This method will verify if there are package locks that:
 
507
 
 
508
        - are now set, and were not;
 
509
        - were previously set but are not anymore;
 
510
 
 
511
        In all cases, the server is notified of the new situation
 
512
        with a "packages" message.
 
513
        """
 
514
        old_package_locks = set(self._store.get_package_locks())
 
515
        current_package_locks = set(self._facade.get_package_locks())
 
516
 
 
517
        set_package_locks = current_package_locks - old_package_locks
 
518
        unset_package_locks = old_package_locks - current_package_locks
 
519
 
 
520
        message = {}
 
521
        if set_package_locks:
 
522
            message["created"] = sorted(set_package_locks)
 
523
        if unset_package_locks:
 
524
            message["deleted"] = sorted(unset_package_locks)
 
525
 
 
526
        if not message:
 
527
            result = succeed(None)
 
528
        else:
 
529
            message["type"] = "package-locks"
 
530
 
 
531
            result = self._broker.send_message(message, True)
 
532
 
 
533
            logging.info("Queuing message with changes in known package locks:"
 
534
                         " %d created, %d deleted." %
 
535
                         (len(set_package_locks), len(unset_package_locks)))
 
536
 
 
537
        def update_currently_known(result):
 
538
            if set_package_locks:
 
539
                self._store.add_package_locks(set_package_locks)
 
540
            if unset_package_locks:
 
541
                self._store.remove_package_locks(unset_package_locks)
447
542
 
448
543
        result.addCallback(update_currently_known)
449
544