Beispiel #1
0
    def _makeTFTPService(self, tftp_root, tftp_port, rpc_service):
        """Create the dynamic TFTP service."""
        from provisioningserver.rackdservices.tftp import TFTPService
        tftp_service = TFTPService(resource_root=tftp_root,
                                   port=tftp_port,
                                   client_service=rpc_service)
        tftp_service.setName("tftp")

        # *** EXPERIMENTAL ***
        # https://code.launchpad.net/~allenap/maas/tftp-offload/+merge/312146
        # If the TFTP port has been set to zero, use the experimental offload
        # service. Otherwise stick to the normal in-process TFTP service.
        if tftp_port == 0:
            from provisioningserver.path import get_data_path
            from provisioningserver.rackdservices import tftp_offload
            from twisted.internet.endpoints import UNIXServerEndpoint
            tftp_offload_socket = get_data_path(
                "/var/lib/maas/tftp-offload.sock")
            tftp_offload_endpoint = UNIXServerEndpoint(reactor,
                                                       tftp_offload_socket,
                                                       wantPID=False)
            tftp_offload_service = tftp_offload.TFTPOffloadService(
                reactor, tftp_offload_endpoint, tftp_service.backend)
            tftp_offload_service.setName("tftp-offload")
            return tftp_offload_service
        # *** /EXPERIMENTAL ***

        return tftp_service
Beispiel #2
0
    def test_tftp_service_does_not_bind_to_link_local_addresses(self):
        # Initial set of interfaces to bind to.
        ipv4_test_net_3 = IPNetwork("203.0.113.0/24")  # RFC 5737
        normal_addresses = {
            factory.pick_ip_in_network(ipv4_test_net_3),
            factory.make_ipv6_address(),
        }
        link_local_addresses = {
            factory.pick_ip_in_network(IPV4_LINK_LOCAL),
            factory.pick_ip_in_network(IPV6_LINK_LOCAL),
        }
        self.patch(
            tftp_module,
            "get_all_interface_addresses",
            lambda: normal_addresses | link_local_addresses,
        )

        tftp_service = TFTPService(
            resource_root=self.make_dir(),
            client_service=Mock(),
            port=factory.pick_port(),
        )
        tftp_service.updateServers()

        # Only the "normal" addresses have been used.
        self.assertEqual(
            normal_addresses,
            {server.name for server in tftp_service.getServers()},
        )
Beispiel #3
0
    def test_tftp_service_rebinds_on_HUP(self):
        # Initial set of interfaces to bind to.
        interfaces = {"1.1.1.1", "2.2.2.2"}
        self.patch(
            tftp_module, "get_all_interface_addresses", lambda: interfaces
        )

        tftp_service = TFTPService(
            resource_root=self.make_dir(),
            client_service=Mock(),
            port=factory.pick_port(),
        )
        tftp_service.updateServers()

        # The child services of tftp_services are named after the
        # interface they bind to.
        self.assertEqual(
            interfaces, {server.name for server in tftp_service.getServers()}
        )

        # Update the set of interfaces to bind to.
        interfaces.add("3.3.3.3")
        interfaces.remove("1.1.1.1")

        # Ask the TFTP service to update its set of servers.
        tftp_service.updateServers()

        # We're in the reactor thread but we want to move the reactor
        # forwards, hence we need to get all explicit about it.
        reactor.runUntilCurrent()

        # The interfaces now bound match the updated interfaces set.
        self.assertEqual(
            interfaces, {server.name for server in tftp_service.getServers()}
        )
Beispiel #4
0
 def test_tftp_service(self):
     # A TFTP service is configured and added to the top-level service.
     interfaces = [factory.make_ipv4_address(), factory.make_ipv6_address()]
     self.patch(
         tftp_module, "get_all_interface_addresses", lambda: interfaces
     )
     example_root = self.make_dir()
     example_client_service = Mock()
     example_port = factory.pick_port()
     tftp_service = TFTPService(
         resource_root=example_root,
         client_service=example_client_service,
         port=example_port,
     )
     tftp_service.updateServers()
     # The "tftp" service is a multi-service containing UDP servers for
     # each interface defined by get_all_interface_addresses().
     self.assertIsInstance(tftp_service, MultiService)
     # There's also a TimerService that updates the servers every 45s.
     self.assertThat(
         tftp_service.refresher,
         MatchesStructure.byEquality(
             step=45,
             parent=tftp_service,
             name="refresher",
             call=(tftp_service.updateServers, (), {}),
         ),
     )
     expected_backend = MatchesAll(
         IsInstance(TFTPBackend),
         AfterPreprocessing(
             lambda backend: backend.base.path, Equals(example_root)
         ),
         AfterPreprocessing(
             lambda backend: backend.client_service,
             Equals(example_client_service),
         ),
     )
     expected_protocol = MatchesAll(
         IsInstance(TFTP),
         AfterPreprocessing(
             lambda protocol: protocol.backend, expected_backend
         ),
     )
     expected_server = MatchesAll(
         IsInstance(internet.UDPServer),
         AfterPreprocessing(lambda service: len(service.args), Equals(2)),
         AfterPreprocessing(
             lambda service: service.args[0], Equals(example_port)  # port
         ),
         AfterPreprocessing(
             lambda service: service.args[1], expected_protocol  # protocol
         ),
     )
     self.assertThat(tftp_service.getServers(), AllMatch(expected_server))
     # Only the interface used for each service differs.
     self.assertItemsEqual(
         [svc.kwargs for svc in tftp_service.getServers()],
         [{"interface": interface} for interface in interfaces],
     )