def test_rpc_info_from_running_ipc_master(self): # Run the IPC master, IPC worker, and RPC service so the endpoints # are updated in the database. region = factory.make_RegionController() self.useFixture(MAASIDFixture(region.system_id)) region.owner = factory.make_admin() region.save() # `workers` is only included so ipc-master will not actually get the # workers service because this test runs in all-in-one mode. self.useFixture( RegionEventLoopFixture( "ipc-master", "ipc-worker", "rpc", "workers" ) ) eventloop.start(master=True, all_in_one=True).wait(5) self.addCleanup(lambda: eventloop.reset().wait(5)) getServiceNamed = eventloop.services.getServiceNamed ipcMaster = getServiceNamed("ipc-master") @wait_for(5) @inlineCallbacks def wait_for_startup(): # Wait for the service to complete startup. yield ipcMaster.starting yield getServiceNamed("ipc-worker").starting yield getServiceNamed("rpc").starting # Force an update, because it's very hard to track when the # first iteration of the ipc-master service has completed. yield ipcMaster.update() wait_for_startup() response = self.client.get(reverse("rpc-info")) self.assertEqual("application/json", response["Content-Type"]) info = json.loads(response.content.decode("unicode_escape")) self.assertThat(info, KeysEqual("eventloops")) self.assertThat( info["eventloops"], MatchesDict( { # Each entry in the endpoints dict is a mapping from an # event loop to a list of (host, port) tuples. Each tuple is # a potential endpoint for connecting into that event loop. eventloop.loop.name: MatchesSetwise( *( MatchesListwise((Equals(addr), is_valid_port)) for addr, _ in ipcMaster._getListenAddresses(5240) ) ) } ), )
def test_rpc_info_when_rpc_advertise_startup_failed(self): self.useFixture(RegionEventLoopFixture("rpc", "rpc-advertise")) # Simulate a crash when the rpc-advertise service starts. self.simulateExceptionInAdvertiseService(factory.make_exception()) eventloop.start().wait(2.0) self.addCleanup(lambda: eventloop.reset().wait(5)) response = self.client.get(reverse('rpc-info')) self.assertEqual("application/json", response["Content-Type"]) info = json.loads(response.content.decode("unicode_escape")) self.assertEqual({"eventloops": None}, info)
def test_rpc_info_when_rpc_advertise_not_fully_started(self): self.useFixture(RegionEventLoopFixture("rpc", "rpc-advertise")) # Simulate a time-out when getting the advertising instance. self.simulateExceptionInAdvertiseService(CancelledError()) eventloop.start().wait(2.0) self.addCleanup(lambda: eventloop.reset().wait(5)) response = self.client.get(reverse('rpc-info')) self.assertEqual("application/json", response["Content-Type"]) info = json.loads(response.content.decode("unicode_escape")) self.assertEqual({"eventloops": None}, info)
def test_send_event_mac_address_logs_if_unknown_node(self): log = self.patch(events_module, 'log') name = factory.make_name('type_name') description = factory.make_name('description') level = random.randint(0, 100) yield deferToDatabase(self.create_event_type, name, description, level) mac_address = factory.make_mac_address() event_description = factory.make_name('event-description') yield eventloop.start() try: yield call_responder( Region(), SendEventMACAddress, { 'mac_address': mac_address, 'type_name': name, 'description': event_description, }) finally: yield eventloop.reset() self.assertThat( log.debug, MockCalledOnceWith( "Event '{type}: {description}' sent for non-existent node " "with MAC address '{mac}'.", type=name, description=event_description, mac=mac_address))
def test_send_event_mac_address_does_not_fail_if_unknown_type(self): name = factory.make_name('type_name') mac_address = factory.make_mac_address() description = factory.make_name('description') logger = self.useFixture(TwistedLoggerFixture()) yield eventloop.start() try: yield call_responder( Region(), SendEventMACAddress, { 'mac_address': mac_address, 'type_name': name, 'description': description, }) finally: yield eventloop.reset() # The log records the issue. FIXME: Why reject logs if the type is not # registered? Seems like the region should record all logs and figure # out how to present them. self.assertDocTestMatches( """\ Unhandled failure in database task. Traceback (most recent call last): ... provisioningserver.rpc.exceptions.NoSuchEventType: ... """, logger.output)
def test_send_event_mac_address_stores_event(self): name = factory.make_name('type_name') description = factory.make_name('description') level = random.randint(0, 100) yield deferToDatabase(self.create_event_type, name, description, level) interface = yield deferToDatabase(self.make_interface) mac_address = interface.mac_address event_description = factory.make_name('description') yield eventloop.start() try: response = yield call_responder( Region(), SendEventMACAddress, { 'mac_address': mac_address.get_raw(), 'type_name': name, 'description': event_description, }) finally: yield eventloop.reset() self.assertEqual({}, response) event = yield deferToDatabase(self.get_event, mac_address, name) self.expectThat(event.node.system_id, Equals(interface.node.system_id)) self.expectThat(event.description, Equals(event_description)) self.expectThat(event.type.name, Equals(name))
def test_send_event_logs_if_unknown_node(self): log = self.patch(events_module, 'log') name = factory.make_name('type_name') description = factory.make_name('description') level = random.randint(0, 100) yield deferToDatabase(self.create_event_type, name, description, level) system_id = factory.make_name('system_id') event_description = factory.make_name('event-description') yield eventloop.start() try: yield call_responder( Region(), SendEvent, { 'system_id': system_id, 'type_name': name, 'description': event_description, }) finally: yield eventloop.reset() self.assertThat( log.debug, MockCalledOnceWith( "Event '{type}: {description}' sent for " "non-existent node '{node_id}'.", type=name, description=event_description, node_id=system_id))
def test_send_event_stores_event(self): name = factory.make_name('type_name') description = factory.make_name('description') level = random.randint(0, 100) yield deferToDatabase(self.create_event_type, name, description, level) system_id = yield deferToDatabase(self.create_node) event_description = factory.make_name('description') yield eventloop.start() try: response = yield call_responder( Region(), SendEvent, { 'system_id': system_id, 'type_name': name, 'description': event_description, }) finally: yield eventloop.reset() self.assertEqual({}, response) event = yield deferToDatabase(self.get_event, system_id, name) self.expectThat(event.node.system_id, Equals(system_id)) self.expectThat(event.description, Equals(event_description)) self.expectThat(event.type.name, Equals(name))
def test_send_event_mac_address_stores_event_with_timestamp_received(self): # Use a random time in the recent past and coerce the responder to use # it as the time-stamp for the event. We'll check this later on. timestamp = datetime.now() - timedelta(seconds=randint(99, 99999)) self.patch(regionservice, "datetime").now.return_value = timestamp event_type = factory.make_name("type_name") yield deferToDatabase(self.create_event_type, event_type, "", 0) interface = yield deferToDatabase(self.make_interface) mac_address = interface.mac_address.get_raw() yield eventloop.start() try: yield call_responder( Region(), SendEventMACAddress, { "mac_address": mac_address, "type_name": event_type, "description": factory.make_name("description"), }, ) finally: yield eventloop.reset() event = yield deferToDatabase(self.get_event, mac_address, event_type) self.expectThat(event.created, Equals(timestamp))
def test_calls_update_services_in_database_thread(self): system_id = factory.make_name("system_id") services = [ { "name": factory.make_name("service"), "status": factory.make_name("status"), "status_info": factory.make_name("status_info"), } ] mock_deferToDatabase = self.patch(regionservice, "deferToDatabase") mock_deferToDatabase.return_value = succeed({}) yield eventloop.start() try: yield call_responder( Region(), UpdateServices, {"system_id": system_id, "services": services}, ) finally: yield eventloop.reset() self.assertThat( mock_deferToDatabase, MockCalledWith(update_services, system_id, services), )
def test_rpc_info_when_rpc_advertise_running(self): region = factory.make_RegionController() self.useFixture(MAASIDFixture(region.system_id)) region.owner = factory.make_admin() region.save() self.useFixture(RegionEventLoopFixture("rpc", "rpc-advertise")) eventloop.start().wait(5) self.addCleanup(lambda: eventloop.reset().wait(5)) getServiceNamed = eventloop.services.getServiceNamed @wait_for(5) @inlineCallbacks def wait_for_startup(): # Wait for the rpc and the rpc-advertise services to start. yield getServiceNamed("rpc").starting yield getServiceNamed("rpc-advertise").starting # Force an update, because it's very hard to track when the # first iteration of the rpc-advertise service has completed. yield getServiceNamed("rpc-advertise")._tryUpdate() wait_for_startup() response = self.client.get(reverse('rpc-info')) self.assertEqual("application/json", response["Content-Type"]) info = json.loads(response.content.decode("unicode_escape")) self.assertThat(info, KeysEqual("eventloops")) self.assertThat( info["eventloops"], MatchesDict({ # Each entry in the endpoints dict is a mapping from an # event loop to a list of (host, port) tuples. Each tuple is # a potential endpoint for connecting into that event loop. eventloop.loop.name: MatchesSetwise(*(MatchesListwise((Equals(addr), is_valid_port)) for addr in get_all_interface_addresses() if not IPAddress(addr).is_link_local() and not IPAddress(addr).is_loopback())), }))
def test__doesnt_raises_other_errors(self): uuid = factory.make_name("uuid") # Cause a random exception self.patch(leases_module, "update_lease").side_effect = (factory.make_exception()) yield eventloop.start() try: yield call_responder( Region(), UpdateLease, { "cluster_uuid": uuid, "action": "expiry", "mac": factory.make_mac_address(), "ip_family": "ipv4", "ip": factory.make_ipv4_address(), "timestamp": int(time.time()), }) finally: yield eventloop.reset()
def test_send_event_stores_event_with_timestamp_received(self): # Use a random time in the recent past and coerce the responder to use # it as the time-stamp for the event. We'll check this later on. timestamp = datetime.now() - timedelta(seconds=randint(99, 99999)) self.patch(regionservice, "datetime").now.return_value = timestamp event_type = factory.make_name('type_name') yield deferToDatabase(self.create_event_type, event_type, "", 0) system_id = yield deferToDatabase(self.create_node) yield eventloop.start() try: yield call_responder( Region(), SendEvent, { 'system_id': system_id, 'type_name': event_type, 'description': factory.make_name('description'), }) finally: yield eventloop.reset() event = yield deferToDatabase(self.get_event, system_id, event_type) self.expectThat(event.created, Equals(timestamp))
def start(self): return eventloop.start()