Esempio n. 1
0
 def test__runs_popen_with_expected_parameters(self):
     popen = self.patch(scan_network_module.subprocess, "Popen")
     popen.return_value.poll = Mock()
     popen.return_value.poll.return_value = None
     popen.return_value.returncode = 0
     interface = factory.make_name("eth")
     ip = factory.make_ip_address(ipv6=False)
     params = PingParameters(interface, ip)
     run_ping(params)
     self.assertThat(
         popen,
         MockCalledOnceWith(
             get_ping_arguments(params),
             stderr=subprocess.DEVNULL,
             stdin=subprocess.DEVNULL,
             stdout=subprocess.DEVNULL,
             env=get_env_with_locale(),
         ),
     )
Esempio n. 2
0
 def test__sends_event_later(self):
     send_event = self.patch(tftp_module, "send_node_event_ip_address")
     ip = factory.make_ip_address()
     self.patch(tftp_module.tftp, "get_remote_address").return_value = (
         ip,
         sentinel.port,
     )
     clock = Clock()
     log_request(sentinel.filename, clock)
     self.assertThat(send_event, MockNotCalled())
     clock.advance(0.0)
     self.assertThat(
         send_event,
         MockCalledOnceWith(
             ip_address=ip,
             description=sentinel.filename,
             event_type=EVENT_TYPES.NODE_TFTP_REQUEST,
         ),
     )
Esempio n. 3
0
    def test__event_is_sent_to_region(self):
        protocol, connecting = self.patch_rpc_methods()
        self.addCleanup((yield connecting))

        ip_address = factory.make_ip_address()
        description = factory.make_name("description")
        event_name = random.choice(list(map_enum(EVENT_TYPES)))

        yield NodeEventHub().logByIP(event_name, ip_address, description)

        self.assertThat(
            protocol.SendEventIPAddress,
            MockCalledOnceWith(
                ANY,
                type_name=event_name,
                ip_address=ip_address,
                description=description,
            ),
        )
Esempio n. 4
0
    def test_modify_raises_when_omshell_fails(self):
        # If the call to omshell doesn't result in output containing the
        # magic string 'hardware-type' it means the set of commands
        # failed.

        server_address = factory.make_string()
        shared_key = factory.make_string()
        ip_address = factory.make_ip_address(ipv6=self.ipv6)
        mac_address = factory.make_mac_address()
        shell = Omshell(server_address, shared_key, ipv6=self.ipv6)

        # Fake a call that results in a failure with random output.
        random_output = factory.make_bytes()
        recorder = FakeMethod(result=(0, random_output))
        shell._run = recorder

        exc = self.assertRaises(ExternalProcessError, shell.modify, ip_address,
                                mac_address)
        self.assertEqual(random_output, exc.output)
Esempio n. 5
0
    def test_updates_cache_if_event_type_not_found(self):
        protocol, connecting = self.patch_rpc_methods(
            side_effect=[succeed({}), fail(NoSuchEventType())])
        self.addCleanup((yield connecting))

        ip_address = factory.make_ip_address()
        description = factory.make_name("description")
        event_name = random.choice(list(map_enum(EVENT_TYPES)))
        event_hub = NodeEventHub()

        # Fine the first time.
        yield event_hub.logByIP(event_name, ip_address, description)
        # The cache has been populated with the event name.
        self.assertThat(event_hub._types_registered, Equals({event_name}))
        # Second time it crashes.
        with ExpectedException(NoSuchEventType):
            yield event_hub.logByIP(event_name, ip_address, description)
        # The event has been removed from the cache.
        self.assertThat(event_hub._types_registered, HasLength(0))
Esempio n. 6
0
    def test_create_calls_omshell_correctly(self):
        server_address = factory.make_string()
        shared_key = factory.make_string()
        ip_address = factory.make_ip_address(ipv6=self.ipv6)
        mac_address = factory.make_mac_address()
        shell = Omshell(server_address, shared_key, ipv6=self.ipv6)

        # Instead of calling a real omshell, we'll just record the
        # parameters passed to Popen.
        recorder = FakeMethod(result=(0, b"hardware-type"))
        shell._run = recorder

        shell.create(ip_address, mac_address)

        expected_script = dedent("""\
            server {server}
            port {port}
            key omapi_key {key}
            connect
            new host
            set ip-address = {ip}
            set hardware-address = {mac}
            set hardware-type = 1
            set name = "{name}"
            create
            """)
        expected_script = expected_script.format(
            server=server_address,
            port=self.port,
            key=shared_key,
            ip=ip_address,
            mac=mac_address,
            name=mac_address.replace(":", "-"),
        )

        # Check that the 'stdin' arg contains the correct set of
        # commands.
        self.assertEqual(
            [1, (expected_script.encode("utf-8"), )],
            [recorder.call_count,
             recorder.extract_args()[0]],
        )
Esempio n. 7
0
 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)
     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))
Esempio n. 8
0
    def test_render_GET_400_when_no_local_addr(self):
        path = factory.make_name('path')
        ip = factory.make_ip_address()
        request = DummyRequest([path.encode('utf-8')])
        request.requestHeaders = Headers({
            'X-Forwarded-For': [ip],
            'X-Forwarded-Port': ['%s' % factory.pick_port()],
        })

        self.patch(http.log, 'info')
        mock_deferLater = self.patch(http, 'deferLater')
        mock_deferLater.side_effect = always_succeed_with(None)

        resource = http.HTTPBootResource()
        yield self.render_GET(resource, request)

        self.assertEquals(400, request.responseCode)
        self.assertEquals(
            b'Missing X-Server-Addr and X-Forwarded-For HTTP headers.',
            b''.join(request.written))
Esempio n. 9
0
 def test__write_local_and_forwarders(self):
     forwarders = [
         {
             'ip': factory.make_ip_address(),
             'name': factory.make_name('name')
         }
         for _ in range(3)
     ]
     config.write_config(True, forwarders)
     with self.syslog_path.open() as syslog_file:
         lines = [line.strip() for line in syslog_file.readlines()]
         self.assertIn(
             ':fromhost-ip, !isequal, "127.0.0.1" ?MAASenlist', lines)
         self.assertIn(
             ':fromhost-ip, !isequal, "127.0.0.1" ?MAASboot', lines)
         for host in forwarders:
             self.assertLinesContain(
                 'target="%s"' % host['ip'], lines)
             self.assertLinesContain(
                 'queue.filename="%s"' % host['name'], lines)
Esempio n. 10
0
    def test_failure_is_suppressed_if_node_not_found(self):
        protocol, connecting = self.patch_rpc_methods(
            side_effect=[fail(NoSuchNode())])
        self.addCleanup((yield connecting))

        ip_address = factory.make_ip_address()
        description = factory.make_name("description")
        event_name = random.choice(list(map_enum(EVENT_TYPES)))

        yield NodeEventHub().logByIP(event_name, ip_address, description)

        self.assertThat(
            protocol.SendEventIPAddress,
            MockCalledOnceWith(
                ANY,
                type_name=event_name,
                ip_address=ip_address,
                description=description,
            ),
        )
Esempio n. 11
0
 def test_raises_error_when_omshell_crashes(self):
     error_message = factory.make_name("error").encode("ascii")
     omshell = Mock()
     omshell.create.side_effect = ExternalProcessError(
         returncode=2, cmd=("omshell",), output=error_message)
     mac = factory.make_mac_address()
     ip = factory.make_ip_address()
     with FakeLogger("maas.dhcp") as logger:
         error = self.assertRaises(
             exceptions.CannotCreateHostMap, dhcp._create_host_map,
             omshell, mac, ip)
     # The CannotCreateHostMap exception includes a message describing the
     # problematic mapping.
     self.assertDocTestMatches(
         "Could not create host map for %s -> %s: ..." % (mac, ip),
         str(error))
     # A message is also written to the maas.dhcp logger that describes the
     # problematic mapping.
     self.assertDocTestMatches(
         "Could not create host map for %s -> %s: ..." % (mac, ip),
         logger.output)
Esempio n. 12
0
 def test__runs_nmap_e2e(self):
     ip = factory.make_ip_address(ipv6=False)
     # Force the use of `nmap` by ensuring it is reported as available.
     self.has_command_available_mock.return_value = True
     cidr = '%s/32' % ip
     slow = random.choice([True, False])
     args = ['eth0', cidr]
     if slow is True:
         args.append('--slow')
     self.run_command(*args)
     expected_params = NmapParameters(interface='eth0',
                                      cidr=cidr,
                                      slow=slow)
     self.assertThat(
         self.popen,
         MockCalledOnceWith(get_nmap_arguments(expected_params),
                            stderr=subprocess.DEVNULL,
                            stdin=subprocess.DEVNULL,
                            stdout=subprocess.DEVNULL,
                            env=select_c_utf8_locale(),
                            preexec_fn=os.setsid))
Esempio n. 13
0
    def test_render_GET_400_when_no_local_addr(self):
        path = factory.make_name("path")
        ip = factory.make_ip_address()
        request = DummyRequest([path.encode("utf-8")])
        request.requestHeaders = Headers({
            "X-Forwarded-For": [ip],
            "X-Forwarded-Port": ["%s" % factory.pick_port()],
        })

        self.patch(http.log, "info")
        mock_deferLater = self.patch(http, "deferLater")
        mock_deferLater.side_effect = always_succeed_with(None)

        resource = http.HTTPBootResource()
        yield self.render_GET(resource, request)

        self.assertEqual(400, request.responseCode)
        self.assertEqual(
            b"Missing X-Server-Addr and X-Forwarded-For HTTP headers.",
            b"".join(request.written),
        )
 def test_reports_neighbours_to_region(self):
     fixture = self.useFixture(MockLiveClusterToRegionRPCFixture())
     protocol, connecting = fixture.makeEventLoop(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,
         ),
     )
Esempio n. 15
0
    def test_render_GET_404_file_not_found(self):
        path = factory.make_name("path")
        ip = factory.make_ip_address()
        request = DummyRequest([path.encode("utf-8")])
        request.requestHeaders = Headers({
            "X-Server-Addr": ["192.168.1.1"],
            "X-Server-Port": ["5248"],
            "X-Forwarded-For": [ip],
            "X-Forwarded-Port": ["%s" % factory.pick_port()],
        })

        self.patch(http.log, "info")
        mock_deferLater = self.patch(http, "deferLater")
        mock_deferLater.side_effect = always_succeed_with(None)

        self.tftp.backend.get_reader.return_value = fail(FileNotFound(path))

        resource = http.HTTPBootResource()
        yield self.render_GET(resource, request)

        self.assertEqual(404, request.responseCode)
        self.assertEqual(b"", b"".join(request.written))
Esempio n. 16
0
    def test_render_GET_404_file_not_found(self):
        path = factory.make_name('path')
        ip = factory.make_ip_address()
        request = DummyRequest([path.encode('utf-8')])
        request.requestHeaders = Headers({
            'X-Server-Addr': ['192.168.1.1'],
            'X-Server-Port': ['5248'],
            'X-Forwarded-For': [ip],
            'X-Forwarded-Port': ['%s' % factory.pick_port()],
        })

        self.patch(http.log, 'info')
        mock_deferLater = self.patch(http, 'deferLater')
        mock_deferLater.side_effect = always_succeed_with(None)

        self.tftp.backend.get_reader.return_value = fail(FileNotFound(path))

        resource = http.HTTPBootResource()
        yield self.render_GET(resource, request)

        self.assertEquals(404, request.responseCode)
        self.assertEquals(b'', b''.join(request.written))
Esempio n. 17
0
 def test_raises_error_when_omshell_not_connected(self):
     error = ExternalProcessError(returncode=2,
                                  cmd=("omshell", ),
                                  output="")
     self.patch(ExternalProcessError, 'output_as_unicode', 'not connected.')
     omshell = Mock()
     omshell.create.side_effect = error
     mac = factory.make_mac_address()
     ip = factory.make_ip_address()
     with FakeLogger("maas.dhcp") as logger:
         error = self.assertRaises(exceptions.CannotCreateHostMap,
                                   dhcp._create_host_map, omshell, mac, ip)
     # The CannotCreateHostMap exception includes a message describing the
     # problematic mapping.
     self.assertDocTestMatches(
         "Could not create host map for %s -> %s: "
         "The DHCP server could not be reached." % (mac, ip), str(error))
     # A message is also written to the maas.dhcp logger that describes the
     # problematic mapping.
     self.assertDocTestMatches(
         "Could not create host map for %s -> %s: "
         "The DHCP server could not be reached." % (mac, ip), logger.output)
Esempio n. 18
0
    def test_render_GET_logs_node_event_with_original_path_ip(self):
        path = factory.make_name("path")
        ip = factory.make_ip_address()
        request = DummyRequest([path.encode("utf-8")])
        request.requestHeaders = Headers(
            {
                "X-Server-Addr": ["192.168.1.1"],
                "X-Server-Port": ["5248"],
                "X-Forwarded-For": [ip],
                "X-Forwarded-Port": ["%s" % factory.pick_port()],
            }
        )

        log_info = self.patch(http.log, "info")
        mock_deferLater = self.patch(http, "deferLater")
        mock_deferLater.side_effect = always_succeed_with(None)

        self.tftp.backend.get_reader.return_value = fail(AccessViolation())

        resource = http.HTTPBootResource()
        yield self.render_GET(resource, request)

        self.assertThat(
            log_info,
            MockCalledOnceWith(
                "{path} requested by {remoteHost}", path=path, remoteHost=ip
            ),
        )
        self.assertThat(
            mock_deferLater,
            MockCalledOnceWith(
                ANY,
                0,
                http.send_node_event_ip_address,
                event_type=EVENT_TYPES.NODE_HTTP_REQUEST,
                ip_address=ip,
                description=path,
            ),
        )
Esempio n. 19
0
 def test_host_diff_returns_removal_added_and_modify(self):
     (omapi_key, failover_peers, shared_networks, hosts, interfaces,
      global_dhcp_snippets) = self.make_args()
     state = dhcp.DHCPState(
         omapi_key, failover_peers, shared_networks, hosts, interfaces,
         global_dhcp_snippets)
     changed_hosts = copy.deepcopy(hosts)
     removed_host = changed_hosts.pop()
     modified_host = changed_hosts[0]
     modified_host["ip"] = factory.make_ip_address()
     added_host = make_host()
     changed_hosts.append(added_host)
     new_state = dhcp.DHCPState(
         omapi_key,
         copy.deepcopy(failover_peers),
         copy.deepcopy(shared_networks),
         changed_hosts,
         copy.deepcopy(interfaces),
         copy.deepcopy(global_dhcp_snippets))
     self.assertEqual(
         ([removed_host], [added_host], [modified_host]),
         new_state.host_diff(state))
Esempio n. 20
0
def make_host(hostname=None,
              interface_name=None,
              mac_address=None,
              ip=None,
              ipv6=False,
              dhcp_snippets=None):
    """Return a host entry for a subnet from network."""
    if hostname is None:
        hostname = factory.make_name("host")
    if interface_name is None:
        interface_name = factory.make_name("eth")
    if mac_address is None:
        mac_address = factory.make_mac_address()
    if ip is None:
        ip = factory.make_ip_address(ipv6=ipv6)
    if dhcp_snippets is None:
        dhcp_snippets = make_host_dhcp_snippets()
    return {
        "host": "%s-%s" % (hostname, interface_name),
        "mac": mac_address,
        "ip": ip,
        "dhcp_snippets": dhcp_snippets,
    }
Esempio n. 21
0
 def test_runs_nmap_single_threaded(self):
     ip = factory.make_ip_address(ipv6=False)
     # Force the use of `nmap` by ensuring it is reported as available.
     self.has_command_available_mock.return_value = True
     cidr = "%s/32" % ip
     slow = random.choice([True, False])
     args = ["--threads", "1", "eth0", cidr]
     if slow is True:
         args.append("--slow")
     self.run_command(*args)
     expected_params = NmapParameters(interface="eth0",
                                      cidr=cidr,
                                      slow=slow)
     self.assertThat(
         self.popen,
         MockCalledOnceWith(
             get_nmap_arguments(expected_params),
             stderr=subprocess.DEVNULL,
             stdin=subprocess.DEVNULL,
             stdout=subprocess.DEVNULL,
             env=get_env_with_locale(),
             preexec_fn=os.setsid,
         ),
     )
Esempio n. 22
0
    def test_writes_config_and_restarts_when_omapi_fails(self):
        write_file = self.patch_sudo_write_file()
        get_service_state = self.patch_getServiceState()
        get_service_state.return_value = ServiceState(SERVICE_STATE.ON,
                                                      "running")
        restart_service = self.patch_restartService()
        ensure_service = self.patch_ensureService()
        update_hosts = self.patch_update_hosts()
        update_hosts.side_effect = factory.make_exception()

        failover_peers = make_failover_peer_config()
        shared_network = make_shared_network()
        [shared_network] = fix_shared_networks_failover([shared_network],
                                                        [failover_peers])
        old_hosts = [make_host(dhcp_snippets=[]) for _ in range(3)]
        interface = make_interface()
        global_dhcp_snippets = make_global_dhcp_snippets()
        expected_config = factory.make_name("config")
        self.patch_get_config().return_value = expected_config

        dhcp_service = dhcp.service_monitor.getServiceByName(
            self.server.dhcp_service)
        on = self.patch_autospec(dhcp_service, "on")

        omapi_key = factory.make_name("omapi_key")
        old_state = dhcp.DHCPState(
            omapi_key,
            [failover_peers],
            [shared_network],
            old_hosts,
            [interface],
            global_dhcp_snippets,
        )
        dhcp._current_server_state[self.server.dhcp_service] = old_state

        new_hosts = copy.deepcopy(old_hosts)
        removed_host = new_hosts.pop()
        modified_host = new_hosts[0]
        modified_host["ip"] = factory.make_ip_address(
            ipv6=self.server.dhcp_service == "DHCPv6")
        added_host = make_host(dhcp_snippets=[])
        new_hosts.append(added_host)

        with FakeLogger("maas") as logger:
            yield self.configure(
                omapi_key,
                [failover_peers],
                [shared_network],
                new_hosts,
                [interface],
                global_dhcp_snippets,
            )

        self.assertThat(
            write_file,
            MockCallsMatch(
                call(
                    self.server.config_filename,
                    expected_config.encode("utf-8"),
                    mode=0o640,
                ),
                call(
                    self.server.interfaces_filename,
                    interface["name"].encode("utf-8"),
                    mode=0o640,
                ),
            ),
        )
        self.assertThat(on, MockCalledOnceWith())
        self.assertThat(
            get_service_state,
            MockCalledOnceWith(self.server.dhcp_service, now=True),
        )
        self.assertThat(restart_service,
                        MockCalledOnceWith(self.server.dhcp_service))
        self.assertThat(ensure_service,
                        MockCalledOnceWith(self.server.dhcp_service))
        self.assertThat(
            update_hosts,
            MockCalledOnceWith(ANY, [removed_host], [added_host],
                               [modified_host]),
        )
        self.assertEqual(
            dhcp._current_server_state[self.server.dhcp_service],
            dhcp.DHCPState(
                omapi_key,
                [failover_peers],
                [shared_network],
                new_hosts,
                [interface],
                global_dhcp_snippets,
            ),
        )
        self.assertDocTestMatches(
            "Failed to update all host maps. Restarting DHCPv... "
            "service to ensure host maps are in-sync.",
            logger.output,
        )
Esempio n. 23
0
    def test__writes_config_and_uses_omapi_to_update_hosts(self):
        write_file = self.patch_sudo_write_file()
        get_service_state = self.patch_getServiceState()
        get_service_state.return_value = ServiceState(SERVICE_STATE.ON,
                                                      "running")
        restart_service = self.patch_restartService()
        ensure_service = self.patch_ensureService()
        update_hosts = self.patch_update_hosts()

        failover_peers = make_failover_peer_config()
        shared_network = make_shared_network()
        [shared_network] = fix_shared_networks_failover([shared_network],
                                                        [failover_peers])
        old_hosts = [make_host(dhcp_snippets=[]) for _ in range(3)]
        interface = make_interface()
        global_dhcp_snippets = make_global_dhcp_snippets()
        expected_config = factory.make_name("config")
        self.patch_get_config().return_value = expected_config

        dhcp_service = dhcp.service_monitor.getServiceByName(
            self.server.dhcp_service)
        on = self.patch_autospec(dhcp_service, "on")

        omapi_key = factory.make_name("omapi_key")
        old_state = dhcp.DHCPState(
            omapi_key,
            [failover_peers],
            [shared_network],
            old_hosts,
            [interface],
            global_dhcp_snippets,
        )
        dhcp._current_server_state[self.server.dhcp_service] = old_state

        new_hosts = copy.deepcopy(old_hosts)
        removed_host = new_hosts.pop()
        modified_host = new_hosts[0]
        modified_host["ip"] = factory.make_ip_address()
        added_host = make_host(dhcp_snippets=[])
        new_hosts.append(added_host)

        yield self.configure(
            omapi_key,
            [failover_peers],
            [shared_network],
            new_hosts,
            [interface],
            global_dhcp_snippets,
        )

        self.assertThat(
            write_file,
            MockCallsMatch(
                call(
                    self.server.config_filename,
                    expected_config.encode("utf-8"),
                    mode=0o640,
                ),
                call(
                    self.server.interfaces_filename,
                    interface["name"].encode("utf-8"),
                    mode=0o640,
                ),
            ),
        )
        self.assertThat(on, MockCalledOnceWith())
        self.assertThat(
            get_service_state,
            MockCalledOnceWith(self.server.dhcp_service, now=True),
        )
        self.assertThat(restart_service, MockNotCalled())
        self.assertThat(ensure_service,
                        MockCalledOnceWith(self.server.dhcp_service))
        self.assertThat(
            update_hosts,
            MockCalledOnceWith(ANY, [removed_host], [added_host],
                               [modified_host]),
        )
        self.assertEquals(
            dhcp._current_server_state[self.server.dhcp_service],
            dhcp.DHCPState(
                omapi_key,
                [failover_peers],
                [shared_network],
                new_hosts,
                [interface],
                global_dhcp_snippets,
            ),
        )
Esempio n. 24
0
 def test_calls_omshell_create(self):
     omshell = Mock()
     mac = factory.make_mac_address()
     ip = factory.make_ip_address()
     dhcp._create_host_map(omshell, mac, ip)
     self.assertThat(omshell.create, MockCalledOnceWith(ip, mac))