/usr/lib/python3/dist-packages/provisioningserver/pserv_services/lease_socket_service.py is in python3-maas-provisioningserver 2.0.0~beta3+bzr4941-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 | # Copyright 2014-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Twisted service recieves lease information from the MAAS dhcpd.sock."""
__all__ = [
"LeaseSocketService",
]
from collections import deque
import json
import os
from provisioningserver.logger import get_maas_logger
from provisioningserver.path import get_path
from provisioningserver.rpc.exceptions import NoConnectionsAvailable
from provisioningserver.rpc.region import UpdateLease
from provisioningserver.utils.twisted import (
pause,
retries,
)
from twisted.application.service import Service
from twisted.internet import (
reactor,
task,
)
from twisted.internet.defer import inlineCallbacks
from twisted.internet.protocol import DatagramProtocol
maaslog = get_maas_logger("lease_socket_service")
def get_socket_path():
"""Return path to dhcpd.sock."""
return os.path.join(get_path("/var/lib/maas"), "dhcpd.sock")
class LeaseSocketService(Service, DatagramProtocol):
"""Service for recieving lease information over MAAS dhcpd.sock."""
# None, or a Deferred that will fire when the processor exits.
done = None
def __init__(self, client_service, reactor):
self.client_service = client_service
self.reactor = reactor
self.address = get_socket_path()
self.notifications = deque()
self.processor = task.LoopingCall(
self.processNotifications, clock=self.reactor)
def startService(self):
"""Start the service."""
super(LeaseSocketService, self).startService()
# Listen for packets from the `dhcpd.sock`.
self.port = self.reactor.listenUNIXDatagram(self.address, self)
# Start the looping call to handle received notifications.
self.done = self.processor.start(0.1, now=False)
def stopService(self):
"""Stop the service."""
super(LeaseSocketService, self).stopService()
# Close the connection.
self.port.connectionLost()
del self.port
# Remove the socket on the filesystem.
os.remove(self.address)
# Stop the processor once it has flushed all data.
done, self.done = self.done, None
self.processor.stop()
return done
def datagramReceived(self, data, conn):
"""Received packet of information.
Packet should be JSON encode information about an updated lease.
The packet is converted from JSON then placed in a queue to be sent to
the region controller for processing.
"""
# If this fails to convert, twisted will handle this gracefully and
# not cause the reactor to crash.
notification = json.loads(data.decode("utf-8"))
# Place the notification into the list of notifications and the looping
# call will handle sending the notification to the region. This ensures
# that even if the connection is lost to the region that the queued
# notifications will still be sent.
self.notifications.append(notification)
def processNotifications(self, clock=reactor):
"""Process all notifications."""
def gen_notifications(notifications):
while len(notifications) != 0:
yield notifications.popleft()
return task.coiterate(
self.processNotification(notification, clock=clock)
for notification in gen_notifications(self.notifications))
@inlineCallbacks
def processNotification(self, notification, clock=reactor):
"""Send a notification to the region."""
client = None
for elapsed, remaining, wait in retries(30, 10, clock):
try:
client = self.client_service.getClient()
break
except NoConnectionsAvailable:
yield pause(wait, self.clock)
else:
maaslog.error(
"Can't send DHCP lease information, no RPC "
"connection to region.")
return
# Notification contains all the required data except for the cluster
# UUID. Add that into the notification and send the information to
# the region for processing.
notification["cluster_uuid"] = client.localIdent
yield client(UpdateLease, **notification)
|