/usr/share/pyshared/landscape/broker/ping.py is in landscape-common 12.04.3-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | """
Implementation of a lightweight exchange-triggering mechanism via
small HTTP requests asking if we should do a full exchange.
"""
import urllib
from logging import info
from twisted.python.failure import Failure
from twisted.internet import defer
from landscape.lib.bpickle import loads
from landscape.lib.fetch import fetch
from landscape.lib.log import log_failure
class PingClient(object):
"""An HTTP client which asks: Are there messages for computer X?
@param url: The URL to ask the question to.
@type identity: L{landscape.broker.registration.Identity}
@param identity: This client's identity.
@param get_page: The method to use to retrieve content. If not specified,
landscape.lib.fetch.fetch is used.
"""
def __init__(self, reactor, url, identity, get_page=None):
if get_page is None:
get_page = fetch
self._reactor = reactor
self._identity = identity
self.get_page = get_page
self.url = url
def ping(self):
"""Ask the question.
Hits the URL previously specified with the insecure_id gotten
from the identity.
@return: A deferred resulting in True if there are messages
and False otherwise.
"""
insecure_id = self._identity.insecure_id
if insecure_id is not None:
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = urllib.urlencode({"insecure_id": insecure_id})
page_deferred = defer.Deferred()
def errback(type, value, tb):
page_deferred.errback(Failure(value, type, tb))
self._reactor.call_in_thread(page_deferred.callback, errback,
self.get_page, self.url,
post=True, data=data,
headers=headers)
page_deferred.addCallback(self._got_result)
return page_deferred
return defer.succeed(False)
def _got_result(self, webtext):
"""
Given a response that came from a ping server, return True if
the response indicates that their are messages waiting for
this computer, False otherwise.
"""
if loads(webtext) == {"messages": True}:
return True
class Pinger(object):
"""
A plugin which pings the Landscape server with HTTP requests to
see if a full exchange should be initiated.
@param reactor: The reactor to schedule calls with
@param url: The URL to ping
@param interval: How often to send the pings
@param exchanger: The L{landscape.broker.exchange.MessageExchange} to
trigger exchanges with.
"""
def __init__(self, reactor, url, identity, exchanger,
interval=30, ping_client_factory=PingClient):
self._url = url
self._interval = interval
self._identity = identity
self._reactor = reactor
self._exchanger = exchanger
self._call_id = None
self._ping_client = None
self.ping_client_factory = ping_client_factory
reactor.call_on("message", self._handle_set_intervals)
def get_url(self):
return self._url
def set_url(self, url):
self._url = url
if self._ping_client is not None:
self._ping_client.url = url
def get_interval(self):
return self._interval
def start(self):
"""Start pinging."""
self._ping_client = self.ping_client_factory(
self._reactor, self._url, self._identity)
self._call_id = self._reactor.call_every(self._interval, self.ping)
def ping(self):
"""Perform a ping; if there are messages, fire an exchange."""
ping_deferred = self._ping_client.ping()
ping_deferred.addCallback(self._got_result)
ping_deferred.addErrback(self._got_error)
def _got_result(self, exchange):
if exchange:
info("Ping indicates message available. "
"Scheduling an urgent exchange.")
self._exchanger.schedule_exchange(urgent=True)
def _got_error(self, failure):
log_failure(failure,
"Error contacting ping server at %s" %
(self._ping_client.url,))
def _handle_set_intervals(self, message):
if message["type"] == "set-intervals" and "ping" in message:
self._interval = message["ping"]
info("Ping interval set to %d seconds." % self._interval)
if self._call_id is not None:
self._reactor.cancel_call(self._call_id)
self._call_id = self._reactor.call_every(self._interval, self.ping)
class FakePinger(object):
def __init__(self, *args, **kwargs):
pass
def start(self):
pass
|