def test_asks_region_for_monitoring_state(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateInterfaces, region.GetDiscoveryState ) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed("rpc") reactor = Clock() service = RackNetworksMonitoringService( rpc_service, reactor, enable_monitoring=False, enable_beaconing=False, ) protocol.GetDiscoveryState.return_value = {"interfaces": {}} # Put something in the cache. This tells recordInterfaces that refresh # has already run but the interfaces have changed thus they need to be # updated. service._recorded = {} yield service.startService() yield maybeDeferred(service.getDiscoveryState) yield service.stopService() self.assertThat( protocol.GetDiscoveryState, MockCalledOnceWith( protocol, system_id=rpc_service.getClient().localIdent ), )
def test_runs_refresh_first_time(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop(region.RequestRackRefresh) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False, ) yield maybeDeferred(service.startService) # By stopping the interface_monitor first, we assure that the loop # happens at least once before the service stops completely. yield maybeDeferred(service.interface_monitor.stopService) yield maybeDeferred(service.stopService) self.assertThat( protocol.RequestRackRefresh, MockCalledOnceWith( protocol, system_id=rpc_service.getClient().localIdent ), )
def test_reports_interfaces_to_region(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop(region.UpdateInterfaces) self.addCleanup((yield connecting)) interfaces = { "eth0": { "type": "physical", "mac_address": factory.make_mac_address(), "parents": [], "links": [], "enabled": True, } } rpc_service = services.getServiceNamed('rpc') service = RackNetworksMonitoringService(rpc_service, Clock(), enable_monitoring=False) service.getInterfaces = lambda: succeed(interfaces) # Put something in the cache. This tells recordInterfaces that refresh # has already run but the interfaces have changed thus they need to be # updated. service._recorded = {} service.startService() yield service.stopService() self.assertThat( protocol.UpdateInterfaces, MockCalledOnceWith(protocol, system_id=rpc_service.getClient().localIdent, interfaces=interfaces))
def test_reports_mdns_to_region(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateInterfaces, region.ReportMDNSEntries ) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False, ) mdns = [ { "interface": "eth0", "hostname": "boggle.example.com", "address": factory.make_ip_address(), } ] yield service.reportMDNSEntries(mdns) self.assertThat( protocol.ReportMDNSEntries, MockCalledOnceWith( protocol, system_id=rpc_service.getClient().localIdent, mdns=mdns, ), )
def test_reports_interfaces_with_hints_if_beaconing_enabled(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop(region.UpdateInterfaces) # Don't actually wait for beaconing to complete. pause_mock = self.patch(services_module, "pause") queue_mcast_mock = self.patch( services_module.BeaconingSocketProtocol, "queueMulticastBeaconing" ) self.addCleanup((yield connecting)) interfaces = { "eth0": { "type": "physical", "mac_address": factory.make_mac_address(), "parents": [], "links": [], "enabled": True, } } rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=True, ) service.getInterfaces = lambda: succeed(interfaces) # Put something in the cache. This tells recordInterfaces that refresh # has already run but the interfaces have changed thus they need to be # updated. service._recorded = {} service.startService() yield service.stopService() self.assertThat( protocol.UpdateInterfaces, MockCalledOnceWith( protocol, system_id=rpc_service.getClient().localIdent, interfaces=interfaces, topology_hints=[], ), ) # The service should have sent out beacons, waited three seconds, # solicited for more beacons, then waited another three seconds before # deciding that beaconing is complete. self.assertThat(pause_mock, MockCallsMatch(call(3.0), call(3.0))) self.assertThat( queue_mcast_mock, MockCallsMatch( # Called when the service starts. call(solicitation=True), # Called three seconds later. call(solicitation=True), # Not called again when the service shuts down. ), )
def test_get_refresh_details_not_running(self): yield self.create_fake_rpc_service() rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False, ) service.running = 0 details = yield service.getRefreshDetails() self.assertEqual((None, None, None), details)
def test_reports_neighbours_to_region(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateInterfaces, region.ReportNeighbours) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed('rpc') service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False) neighbours = [{"ip": factory.make_ip_address()}] yield service.reportNeighbours(neighbours) self.assertThat( protocol.ReportNeighbours, MockCalledOnceWith( protocol, system_id=rpc_service.getClient().localIdent, neighbours=neighbours))
def test_reports_interfaces_to_region(self): def refresh( system_id, consumer_key, token_key, token_secret, maas_url=None, post_process_hook=None, ): self.assertEqual("", system_id) self.assertEqual(self.metadata_creds["consumer_key"], consumer_key) self.assertEqual(self.metadata_creds["token_key"], token_key) self.assertEqual(self.metadata_creds["token_secret"], token_secret) self.assertEqual("http://localhost/MAAS", maas_url) yield self.create_fake_rpc_service() self.mock_refresh.side_effect = refresh interfaces = { "eth0": { "type": "physical", "mac_address": factory.make_mac_address(), "parents": [], "links": [], "enabled": True, } } update_interfaces_deferred = Deferred() rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False, update_interfaces_deferred=update_interfaces_deferred, ) service.getInterfaces = lambda: succeed(interfaces) # Put something in the cache. This tells recordInterfaces that refresh # has already run but the interfaces have changed thus they need to be # updated. service._recorded = {} service.startService() yield update_interfaces_deferred yield service.stopService() self.assertEquals(1, self.mock_refresh.call_count)
def test_reports_interfaces_with_hints_if_beaconing_enabled(self): yield self.create_fake_rpc_service() # Don't actually wait for beaconing to complete. pause_mock = self.patch(services_module, "pause") queue_mcast_mock = self.patch( services_module.BeaconingSocketProtocol, "queueMulticastBeaconing" ) interfaces = { "eth0": { "type": "physical", "mac_address": factory.make_mac_address(), "parents": [], "links": [], "enabled": True, } } rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=True, ) service.getInterfaces = lambda: succeed(interfaces) service.startService() # By stopping the interface_monitor first, we assure that the loop # happens at least once before the service stops completely. yield maybeDeferred(service.interface_monitor.stopService) yield service.stopService() # The service should have sent out beacons, waited three seconds, # solicited for more beacons, then waited another three seconds before # deciding that beaconing is complete. self.assertThat(pause_mock, MockCallsMatch(call(3.0), call(3.0))) self.assertThat( queue_mcast_mock, MockCallsMatch( # Called when the service starts. call(solicitation=True), # Called three seconds later. call(solicitation=True), # Not called again when the service shuts down. ), )
def test_runs_refresh_first_time(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop(region.RequestRackRefresh) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed('rpc') service = RackNetworksMonitoringService(rpc_service, Clock(), enable_monitoring=False) yield service.startService() yield service.stopService() self.assertThat( protocol.RequestRackRefresh, MockCalledOnceWith(protocol, system_id=rpc_service.getClient().localIdent))
def test_get_refresh_details_running(self): yield self.create_fake_rpc_service() rpc_service = services.getServiceNamed("rpc") service = RackNetworksMonitoringService( rpc_service, Clock(), enable_monitoring=False, enable_beaconing=False, ) service.running = 1 self.metadata_creds.update({ "consumer_key": "my-key", "token_key": "my-token", "token_secret": "my-secret", }) details = yield service.getRefreshDetails() self.assertEqual(("http://localhost/MAAS", "", self.metadata_creds), details)
def test_requests_beaconing_when_timer_fires(self): fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) protocol, connecting = fixture.makeEventLoop( region.UpdateInterfaces, region.GetDiscoveryState) self.addCleanup((yield connecting)) rpc_service = services.getServiceNamed('rpc') reactor = Clock() service = RackNetworksMonitoringService( rpc_service, reactor, enable_monitoring=False, enable_beaconing=True) service.beaconing_protocol = Mock() service.beaconing_protocol.queueMulticastBeaconing = Mock() service.getInterfaces = lambda: succeed({}) service._recorded = {} service.startService() yield service.stopService() self.assertThat( service.beaconing_protocol.queueMulticastBeaconing, MockCallsMatch(call()))
def connected(teardown): test.addCleanup(teardown) return services.getServiceNamed("rpc"), protocol
def render_GET(self, request): # Be sure that the TFTP endpoint is running. try: tftp = services.getServiceNamed("tftp") except KeyError: # TFTP service is not installed cannot handle a boot request. request.setResponseCode(503) return b"HTTP boot service not ready." # Extract the local servers IP/port of the request. localHost = request.getHeader("X-Server-Addr") try: localPort = int(request.getHeader("X-Server-Port")) except (TypeError, ValueError): localPort = 0 # Extract the original clients IP/port of the request. remoteHost = request.getHeader("X-Forwarded-For") try: remotePort = int(request.getHeader("X-Forwarded-Port")) except (TypeError, ValueError): remotePort = 0 # localHost and remoteHost are required headers. if not localHost or not remoteHost: request.setResponseCode(400) return b"Missing X-Server-Addr and X-Forwarded-For HTTP headers." def handleFailure(failure): if failure.check(AccessViolation): request.setResponseCode(403) request.write(b"") elif failure.check(FileNotFound): request.setResponseCode(404) request.write(b"") else: log.err(failure, "Failed to handle boot HTTP request.") request.setResponseCode(500) request.write(str(failure.value).encode("utf-8")) request.finish() def writeResponse(reader): # Some readers from `tftp` do not provide a way to get the size # of the generated content. Only set `Content-Length` when size # can be determined for the response. if hasattr(reader, "size"): request.setHeader(b"Content-Length", reader.size) # The readers from `tftp` use `finish` instead of `close`, but # `NoRangeStaticProducer` expects `close` instead of `finish`. Map # `finish` to `close` so the file handlers are cleaned up. reader.close = reader.finish # Produce the result without allowing range. This producer will # call `close` on the reader and `finish` on the request when done. producer = NoRangeStaticProducer(request, reader) producer.start() path = b"/".join(request.postpath) d = context.call( { "local": (localHost, localPort), "remote": (remoteHost, remotePort), }, tftp.backend.get_reader, path, skip_logging=True, ) d.addCallback(writeResponse) d.addErrback(handleFailure) d.addErrback(log.err, "Failed to handle boot HTTP request.") # Log the HTTP request to rackd.log and push that event to the # region controller. log_path = path.decode("utf-8") log.info( "{path} requested by {remoteHost}", path=log_path, remoteHost=remoteHost, ) d = deferLater( reactor, 0, send_node_event_ip_address, event_type=EVENT_TYPES.NODE_HTTP_REQUEST, ip_address=remoteHost, description=log_path, ) d.addErrback(log.err, "Logging HTTP request failed.") # Response is handled in the defer. return NOT_DONE_YET