~ahasenack/landscape-client/landscape-client-1.5.5-0ubuntu0.9.04.0

« back to all changes in this revision

Viewing changes to landscape/package/changer.py

  • Committer: Bazaar Package Importer
  • Author(s): Rick Clark
  • Date: 2008-09-08 16:35:57 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080908163557-l3ixzj5dxz37wnw2
Tags: 1.0.18-0ubuntu1
New upstream release 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import logging
 
2
import time
 
3
import sys
 
4
import os
 
5
import pwd
 
6
 
 
7
from twisted.internet.defer import succeed, fail
 
8
 
 
9
from landscape.package.reporter import find_reporter_command
 
10
from landscape.package.taskhandler import PackageTaskHandler, run_task_handler
 
11
 
 
12
 
 
13
SUCCESS_RESULT = 1
 
14
ERROR_RESULT = 100
 
15
DEPENDENCY_ERROR_RESULT = 101
 
16
 
 
17
UNKNOWN_PACKAGE_DATA_TIMEOUT = 24 * 60 * 60
 
18
 
 
19
 
 
20
class UnknownPackageData(Exception):
 
21
    """Raised when an ID or a hash isn't known."""
 
22
 
 
23
 
 
24
class PackageChanger(PackageTaskHandler):
 
25
 
 
26
    queue_name = "changer"
 
27
 
 
28
    def run(self):
 
29
        task1 = self._store.get_next_task(self.queue_name)
 
30
        result = super(PackageChanger, self).run()
 
31
        def finished(result):
 
32
            task2 = self._store.get_next_task(self.queue_name)
 
33
            if task1 and task1.id != (task2 and task2.id):
 
34
                if os.getuid() == 0:
 
35
                    os.setuid(pwd.getpwnam("landscape").pw_uid)
 
36
                os.system(find_reporter_command())
 
37
        return result.addCallback(finished)
 
38
 
 
39
    def handle_tasks(self):
 
40
        result = super(PackageChanger, self).handle_tasks()
 
41
        return result.addErrback(self._warn_about_unknown_data)
 
42
 
 
43
    def handle_task(self, task):
 
44
        message = task.data
 
45
        if message["type"] == "change-packages":
 
46
            result = self._handle_change_packages(message)
 
47
            return result.addErrback(self._check_expired_unknown_data, task)
 
48
 
 
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])
 
53
 
 
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)
 
64
        else:
 
65
            return failure
 
66
 
 
67
    def _handle_change_packages(self, message):
 
68
        self.ensure_channels_reloaded()
 
69
 
 
70
        self._facade.reset_marks()
 
71
 
 
72
        if message.get("upgrade-all"):
 
73
            for package in self._facade.get_packages():
 
74
                if package.installed:
 
75
                    self._facade.mark_upgrade(package)
 
76
 
 
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)
 
81
                if hash is None:
 
82
                    return fail(UnknownPackageData(id))
 
83
                package = self._facade.get_package_by_hash(hash)
 
84
                if package is None:
 
85
                    return fail(UnknownPackageData(hash))
 
86
                mark_func(package)
 
87
 
 
88
        message = {"type": "change-packages-result",
 
89
                   "operation-id": message.get("operation-id")}
 
90
 
 
91
        # Delay importing these so that we don't import Smart unless
 
92
        # we really need to.
 
93
        from landscape.package.facade import (
 
94
            DependencyError, TransactionError, SmartError)
 
95
 
 
96
        result = None
 
97
        try:
 
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
 
104
            installs = []
 
105
            removals = []
 
106
            for package in exception.packages:
 
107
                hash = self._facade.get_package_hash(package)
 
108
                id = self._store.get_hash_id(hash)
 
109
                if id is None:
 
110
                    # Will have to wait until the server lets us know about
 
111
                    # this id.
 
112
                    return fail(UnknownPackageData(hash))
 
113
                if package.installed:
 
114
                    # Package currently installed. Must remove it.
 
115
                    removals.append(id)
 
116
                else:
 
117
                    # Package currently available. Must install it.
 
118
                    installs.append(id)
 
119
            if installs:
 
120
                installs.sort()
 
121
                message["must-install"] = installs
 
122
            if removals:
 
123
                removals.sort()
 
124
                message["must-remove"] = removals
 
125
        else:
 
126
            result_code = SUCCESS_RESULT
 
127
 
 
128
        message["result-code"] = result_code
 
129
        if result is not None:
 
130
            message["result-text"] = result
 
131
 
 
132
        logging.info("Queuing message with change package results to "
 
133
                     "exchange urgently.")
 
134
        return self._broker.send_message(message, True)
 
135
 
 
136
 
 
137
def main(args):
 
138
    if os.getpgrp() != os.getpid():
 
139
        os.setsid()
 
140
    return run_task_handler(PackageChanger, args)
 
141
 
 
142
 
 
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")