~free.ekanayaka/landscape-client/intrepid-proposed

« back to all changes in this revision

Viewing changes to landscape/package/reporter.py

  • Committer: Free Ekanayaka
  • Date: 2009-12-16 11:08:04 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: free.ekanayaka@canonical.com-20091216110804-ezpxnyfxruuc5vm5
* 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
102
122
                logging.warning("Couldn't download hash=>id database: %s" %
103
123
                                str(exception))
104
124
 
105
 
            result = fetch_async(url)
 
125
            result = fetch_async(url,
 
126
                                 cainfo=self._config.get("ssl_public_key"))
106
127
            result.addCallback(fetch_ok)
107
128
            result.addErrback(fetch_error)
108
129
 
134
155
 
135
156
        @return: a deferred returning (out, err, code)
136
157
        """
 
158
        if self._config.force_smart_update:
 
159
            args = ()
 
160
        else:
 
161
            args = ("--after", "%d" % self.smart_update_interval)
137
162
        result = getProcessOutputAndValue(self.smart_update_filename,
138
 
                                          args=("--after", "%d" %
139
 
                                                self.smart_update_interval))
 
163
                                          args=args)
140
164
 
141
165
        def callback((out, err, code)):
142
166
            # smart-update --after N will exit with error code 1 when it
166
190
 
167
191
    def _handle_package_ids(self, message):
168
192
        unknown_hashes = []
169
 
        request_id = message["request-id"]
170
193
 
171
194
        try:
172
195
            request = self._store.get_hash_id_request(message["request-id"])
215
238
        # This problem would happen for example when switching the client from
216
239
        # one Landscape server to another, because the uuid-changed event would
217
240
        # cause a resynchronize task to be created by the monitor. See #417122.
218
 
        #
219
 
        #self._store.clear_hash_id_requests()
220
241
 
221
242
        return succeed(None)
222
243
 
327
348
        request = self._store.add_hash_id_request(unknown_hashes)
328
349
        message["request-id"] = request.id
329
350
        result = self._broker.send_message(message, True)
 
351
 
330
352
        def set_message_id(message_id):
331
353
            request.message_id = message_id
 
354
 
332
355
        def send_message_failed(failure):
333
356
            request.remove()
334
357
            return failure
 
358
 
335
359
        return result.addCallbacks(set_message_id, send_message_failed)
336
360
 
337
361
    def detect_changes(self):
341
365
 
342
366
        - are now installed, and were not;
343
367
        - are now available, and were not;
 
368
        - are now locked, and were not;
344
369
        - were previously available but are not anymore;
345
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;
346
377
 
347
378
        In all cases, the server is notified of the new situation
348
379
        with a "packages" message.
352
383
        old_installed = set(self._store.get_installed())
353
384
        old_available = set(self._store.get_available())
354
385
        old_upgrades = set(self._store.get_available_upgrades())
 
386
        old_locked = set(self._store.get_locked())
355
387
 
356
388
        current_installed = set()
357
389
        current_available = set()
358
390
        current_upgrades = set()
 
391
        current_locked = set()
359
392
 
360
393
        for package in self._facade.get_packages():
361
394
            hash = self._facade.get_package_hash(package)
386
419
                        continue
387
420
                    break
388
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
 
389
428
        new_installed = current_installed - old_installed
390
429
        new_available = current_available - old_available
391
430
        new_upgrades = current_upgrades - old_upgrades
 
431
        new_locked = current_locked - old_locked
392
432
 
393
433
        not_installed = old_installed - current_installed
394
434
        not_available = old_available - current_available
395
435
        not_upgrades = old_upgrades - current_upgrades
 
436
        not_locked = old_locked - current_locked
396
437
 
397
438
        message = {}
398
439
        if new_installed:
404
445
        if new_upgrades:
405
446
            message["available-upgrades"] = \
406
447
                list(sequence_to_ranges(sorted(new_upgrades)))
 
448
        if new_locked:
 
449
            message["locked"] = \
 
450
                list(sequence_to_ranges(sorted(new_locked)))
407
451
 
408
452
        if not_installed:
409
453
            message["not-installed"] = \
414
458
        if not_upgrades:
415
459
            message["not-available-upgrades"] = \
416
460
                list(sequence_to_ranges(sorted(not_upgrades)))
 
461
        if not_locked:
 
462
            message["not-locked"] = \
 
463
                list(sequence_to_ranges(sorted(not_locked)))
417
464
 
418
465
        if not message:
419
466
            result = succeed(None)
424
471
 
425
472
            logging.info("Queuing message with changes in known packages: "
426
473
                         "%d installed, %d available, %d available upgrades, "
427
 
                         "%d not installed, %d not available, %d not "
428
 
                         "available upgrades."
 
474
                         "%d locked, %d not installed, %d not available, "
 
475
                         "%d not available upgrades, %d not locked."
429
476
                         % (len(new_installed), len(new_available),
430
 
                            len(new_upgrades), len(not_installed),
431
 
                            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)))
432
480
 
433
481
        def update_currently_known(result):
434
482
            if new_installed:
437
485
                self._store.remove_installed(not_installed)
438
486
            if new_available:
439
487
                self._store.add_available(new_available)
 
488
            if new_locked:
 
489
                self._store.add_locked(new_locked)
440
490
            if not_available:
441
491
                self._store.remove_available(not_available)
442
492
            if new_upgrades:
443
493
                self._store.add_available_upgrades(new_upgrades)
444
494
            if not_upgrades:
445
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)
446
542
 
447
543
        result.addCallback(update_currently_known)
448
544