Beispiel #1
0
    def test_remove_calls_omshell_correctly(self):
        server_address = factory.make_string()
        shared_key = factory.make_string()
        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"thing1\nthing2\nobj: <null>"))
        shell._run = recorder

        shell.remove(mac_address)

        expected_script = dedent("""\
            server {server}
            port {port}
            key omapi_key {key}
            connect
            new host
            set name = "{mac}"
            open
            remove
            """).format(
            server=server_address, port=self.port, key=shared_key,
            mac=mac_address.replace(':', '-'))
        expected_results = (expected_script.encode("utf-8"),)

        # Check that the 'stdin' arg contains the correct set of
        # commands.
        self.assertEqual(
            [expected_results], recorder.extract_args())
    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,
            enable_beaconing=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, topology_hints=None))
Beispiel #3
0
    def test_modify_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.modify(ip_address, mac_address)

        expected_script = dedent("""\
            server {server}
            key omapi_key {key}
            connect
            new host
            set name = "{name}"
            open
            set ip-address = {ip}
            set hardware-address = {mac}
            set hardware-type = 1
            update
            """)
        expected_script = expected_script.format(
            server=server_address, 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]])
    def test_processNotification_send_to_region(self):
        protocol, connecting = self.patch_rpc_UpdateLease()
        self.addCleanup((yield connecting))

        client = getRegionClient()
        rpc_service = MagicMock()
        rpc_service.getClientNow.return_value = defer.succeed(client)
        service = LeaseSocketService(rpc_service, reactor)

        # Notification to region.
        packet = {
            "action": "commit",
            "mac": factory.make_mac_address(),
            "ip_family": "ipv4",
            "ip": factory.make_ipv4_address(),
            "timestamp": int(time.time()),
            "lease_time": 30,
            "hostname": factory.make_name("host"),
        }
        yield service.processNotification(packet, clock=reactor)
        self.assertThat(
            protocol.UpdateLease,
            MockCalledOnceWith(
                protocol,
                cluster_uuid=client.localIdent,
                action=packet["action"],
                mac=packet["mac"],
                ip_family=packet["ip_family"],
                ip=packet["ip"],
                timestamp=packet["timestamp"],
                lease_time=packet["lease_time"],
                hostname=packet["hostname"],
            ),
        )
Beispiel #5
0
    def test__event_type_is_registered_on_first_call_only(self):
        protocol, connecting = self.patch_rpc_methods(side_effect=[{}, {}])
        self.addCleanup((yield connecting))

        mac_address = factory.make_mac_address()
        description = factory.make_name('description')
        event_name = random.choice(list(map_enum(EVENT_TYPES)))
        event_detail = EVENT_DETAILS[event_name]
        event_hub = NodeEventHub()

        # On the first call, the event type is registered before the log is
        # sent to the region.
        yield event_hub.logByMAC(event_name, mac_address, description)
        self.assertThat(
            protocol.RegisterEventType,
            MockCalledOnceWith(ANY,
                               name=event_name,
                               description=event_detail.description,
                               level=event_detail.level))
        self.assertThat(protocol.SendEventMACAddress, MockCalledOnce())

        # Reset RPC call handlers.
        protocol.RegisterEventType.reset_mock()
        protocol.SendEventMACAddress.reset_mock()

        # On the second call, the event type is known to be registered, so the
        # log is sent to the region immediately.
        yield event_hub.logByMAC(event_name, mac_address, description)
        self.assertThat(protocol.RegisterEventType, MockNotCalled())
        self.assertThat(protocol.SendEventMACAddress, MockCalledOnce())
Beispiel #6
0
 def test_create_succeeds_when_host_map_already_exists(self):
     # To omshell, creating the same host map twice is an error.  But
     # Omshell.create swallows the error and makes it look like
     # success.
     params = {
         "ip": factory.make_ip_address(ipv6=self.ipv6),
         "mac": factory.make_mac_address(),
         "hostname": factory.make_name("hostname"),
     }
     shell = Omshell(
         factory.make_name("server"),
         factory.make_name("key"),
         ipv6=self.ipv6,
     )
     # This is the kind of error output we get if a host map has
     # already been created.
     error_output = (dedent("""\
         obj: host
         ip-address = %(ip)s
         hardware-address = %(mac)s
         name = "%(hostname)s"
         >
         can't open object: I/O error
         obj: host
         ip-address = %(ip)s
         hardware-address = %(mac)s
         name = "%(hostname)s"
         """) % params)
     shell._run = Mock(return_value=(0, error_output.encode("ascii")))
     shell.create(params["ip"], params["mac"])
     # The test is that we get here without error.
     pass
Beispiel #7
0
 def test_format_bootif_makes_mac_address_lower(self):
     fake_mac = factory.make_mac_address("-")
     fake_mac = fake_mac.upper()
     self.assertEqual(
         "01-%s" % fake_mac.replace(":", "-").lower(),
         format_bootif(fake_mac),
     )
Beispiel #8
0
 def test_re_config_file_matches_classic_pxelinux_cfg(self):
     # The default config path is simply "pxelinux.cfg" (without
     # leading slash).  The regex matches this.
     mac = factory.make_mac_address("-").encode("ascii")
     match = re_config_file.match(b"ppc64el/pxelinux.cfg/01-%s" % mac)
     self.assertIsNotNone(match)
     self.assertEqual({"mac": mac}, match.groupdict())
Beispiel #9
0
    def test_logs_error_on_duplicate_macs(self):
        protocol, connecting = self.prepare_region_rpc()
        self.addCleanup((yield connecting))
        system_id = factory.make_name("system-id")
        maaslog = self.patch(provisioningserver.rpc.utils, "maaslog")

        uuid = "node-" + factory.make_UUID()
        macs = sorted(factory.make_mac_address() for _ in range(3))
        arch = factory.make_name("architecture")
        power_type = factory.make_name("power_type")
        power_parameters = {
            "power_address": factory.make_ipv4_address(),
            "power_user": factory.make_name("power_user"),
            "power_pass": factory.make_name("power_pass"),
            "power_control": None,
            "system_id": uuid,
        }

        protocol.CreateNode.side_effect = [
            defer.succeed({"system_id": system_id}),
            defer.fail(NodeAlreadyExists("Node already exists.")),
        ]

        yield create_node(macs, arch, power_type, power_parameters)
        yield create_node(macs, arch, power_type, power_parameters)
        self.assertThat(
            maaslog.error,
            MockCalledOnceWith(
                "A node with one of the mac addresses in %s already "
                "exists.",
                macs,
            ),
        )
Beispiel #10
0
    def _test_get_render_file(self, local, remote):
        # For paths matching PXEBootMethod.match_path, TFTPBackend.get_reader()
        # returns a Deferred that will yield a BytesReader.
        mac = factory.make_mac_address("-")
        config_path = compose_config_path(mac)
        backend = TFTPBackend(self.make_dir(), Mock())
        # python-tx-tftp sets up call context so that backends can discover
        # more about the environment in which they're running.
        call_context = {"local": local, "remote": remote}

        @partial(self.patch, backend, "get_boot_method_reader")
        def get_boot_method_reader(boot_method, params):
            params_json = json.dumps(params).encode("ascii")
            params_json_reader = BytesReader(params_json)
            return succeed(params_json_reader)

        reader = yield context.call(call_context, backend.get_reader,
                                    config_path)
        output = reader.read(10000).decode("ascii")
        # The addresses provided by python-tx-tftp in the call context are
        # passed over the wire as address:port strings.
        expected_params = {
            "mac": mac,
            "local_ip": call_context["local"][0],  # address only.
            "remote_ip": call_context["remote"][0],  # address only.
            "bios_boot_method": "pxe",
        }
        observed_params = json.loads(output)
        self.assertEqual(expected_params, observed_params)
Beispiel #11
0
 def test_interface_mac_vid(self):
     mac = factory.make_mac_address()
     vid = random.randint(1, 300)
     nic = DiscoveredMachineInterface(mac_address=mac, vid=vid)
     self.assertEqual(mac, nic.mac_address)
     self.assertEqual(vid, nic.vid)
     self.assertEqual([], nic.tags)
Beispiel #12
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,
    }
Beispiel #13
0
 def test_is_valid_returns_false_for_truncated_vlan(self):
     src_mac = factory.make_mac_address()
     dst_mac = factory.make_mac_address()
     ethertype = ETHERTYPE.ARP
     payload = factory.make_bytes(48)
     vid = random.randrange(4095)
     packet = make_ethernet_packet(
         dst_mac=dst_mac,
         src_mac=src_mac,
         ethertype=ethertype,
         payload=payload,
         vid=vid,
     )
     packet = packet[0:15]
     eth = Ethernet(packet)
     self.assertThat(eth.is_valid(), Equals(False))
Beispiel #14
0
    def test_probe_and_enlist_recs_probes_and_enlists_no_commission(self):
        user = factory.make_name("user")
        ip, port, username, password, node_id, context = self.make_context()
        domain = factory.make_name("domain")
        macs = [factory.make_mac_address() for _ in range(3)]
        mock_get_nodes = self.patch(RECSAPI, "get_nodes")
        mock_get_nodes.return_value = {node_id: {"macs": macs, "arch": "arm"}}
        self.patch(RECSAPI, "set_boot_source")
        mock_create_node = self.patch(recs_module, "create_node")
        mock_create_node.side_effect = asynchronous(lambda *args: node_id)
        mock_commission_node = self.patch(recs_module, "commission_node")

        yield deferToThread(
            probe_and_enlist_recs,
            user,
            ip,
            int(port),
            username,
            password,
            False,
            domain,
        )

        self.expectThat(
            mock_create_node,
            MockCalledOnceWith(macs, "armhf", "recs_box", context, domain),
        )
        self.expectThat(mock_commission_node, MockNotCalled())
Beispiel #15
0
 def test_machine(self):
     hostname = factory.make_name("hostname")
     cores = random.randint(1, 8)
     cpu_speed = random.randint(1000, 2000)
     memory = random.randint(4096, 8192)
     power_state = factory.make_name("unknown")
     interfaces = [
         DiscoveredMachineInterface(mac_address=factory.make_mac_address())
         for _ in range(3)
     ]
     block_devices = [
         DiscoveredMachineBlockDevice(
             model=factory.make_name("model"),
             serial=factory.make_name("serial"),
             size=random.randint(512, 1024),
         ) for _ in range(3)
     ]
     tags = [factory.make_name("tag") for _ in range(3)]
     machine = DiscoveredMachine(
         hostname=hostname,
         architecture="amd64/generic",
         cores=cores,
         cpu_speed=cpu_speed,
         memory=memory,
         power_state=power_state,
         interfaces=interfaces,
         block_devices=block_devices,
         tags=tags,
     )
     self.assertEqual(cores, machine.cores)
     self.assertEqual(cpu_speed, machine.cpu_speed)
     self.assertEqual(memory, machine.memory)
     self.assertEqual(interfaces, machine.interfaces)
     self.assertEqual(block_devices, machine.block_devices)
     self.assertEqual(tags, machine.tags)
Beispiel #16
0
    def test__issue_ipmi_chassis_config_with_power_boot_type(self):
        context = make_context()
        driver = IPMIPowerDriver()
        ip_address = factory.make_ipv4_address()
        find_ip_via_arp = self.patch(ipmi_module, 'find_ip_via_arp')
        find_ip_via_arp.return_value = ip_address
        power_change = "on"

        context['mac_address'] = factory.make_mac_address()
        context['power_address'] = random.choice((None, "", "   "))
        context['power_boot_type'] = IPMI_BOOT_TYPE.EFI

        self.patch_autospec(driver, "_issue_ipmi_chassis_config_command")
        self.patch_autospec(driver, "_issue_ipmipower_command")
        driver._issue_ipmi_command(power_change, **context)

        # The IP address is passed to _issue_ipmi_chassis_config_command.
        self.assertThat(
            driver._issue_ipmi_chassis_config_command,
            MockCalledOnceWith(
                ANY, power_change, ip_address,
                power_boot_type=IPMI_BOOT_TYPE.EFI))
        # The IP address is also within the command passed to
        # _issue_ipmi_chassis_config_command.
        self.assertThat(
            driver._issue_ipmi_chassis_config_command.call_args[0],
            Contains(ip_address))
        # The IP address is passed to _issue_ipmipower_command.
        self.assertThat(
            driver._issue_ipmipower_command,
            MockCalledOnceWith(ANY, power_change, ip_address))
Beispiel #17
0
    def test_probe_and_enlist_msftocs_probes_and_enlists(self):
        context = make_context()
        user = factory.make_name("user")
        system_id = factory.make_name("system_id")
        domain = factory.make_name("domain")
        macs = [factory.make_mac_address() for _ in range(3)]
        mock_get_blades = self.patch(MicrosoftOCSPowerDriver, "get_blades")
        mock_get_blades.return_value = {"%s" % context["blade_id"]: macs}
        self.patch(MicrosoftOCSPowerDriver, "set_next_boot_device")
        mock_create_node = self.patch(msftocs_module, "create_node")
        mock_create_node.side_effect = asynchronous(lambda *args: system_id)
        mock_commission_node = self.patch(msftocs_module, "commission_node")

        yield deferToThread(
            probe_and_enlist_msftocs,
            user,
            context["power_address"],
            int(context["power_port"]),
            context["power_user"],
            context["power_pass"],
            True,
            domain,
        )

        self.expectThat(
            mock_create_node,
            MockCalledOnceWith(macs, "amd64", "msftocs", context, domain),
        )
        self.expectThat(mock_commission_node,
                        MockCalledOnceWith(system_id, user))
Beispiel #18
0
    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.
            ),
        )
Beispiel #19
0
 def test_match_path_pxe_config_without_mac(self):
     method = S390XBootMethod()
     fake_mac = factory.make_mac_address("-")
     self.patch(s390x_module, "get_remote_mac").return_value = fake_mac
     config_path = b"s390x/pxelinux.cfg/default"
     params = method.match_path(None, config_path)
     expected = {"arch": "s390x", "mac": fake_mac}
     self.assertEqual(expected, params)
Beispiel #20
0
 def test_match_path_mac_dash(self):
     method = UEFIAMD64BootMethod()
     backend = random.choice(["http", "tftp"])
     mac = factory.make_mac_address().replace(":", "-")
     self.assertEqual(
         {"mac": mac},
         method.match_path(backend, f"/grub/grub.cfg-{mac}".encode()),
     )
Beispiel #21
0
 def test_get_reader_logs_node_event_with_mac_address(self):
     mac_address = factory.make_mac_address()
     self.patch(tftp_module, 'get_remote_mac').return_value = mac_address
     data = factory.make_string().encode("ascii")
     reader = yield self.get_reader(data)
     self.addCleanup(reader.finish)
     self.assertThat(tftp_module.log_request,
                     MockCalledOnceWith(mac_address, ANY))
Beispiel #22
0
 def test_get_node_info(self):
     method = WindowsPXEBootMethod()
     mac = factory.make_mac_address()
     self.patch(windows_module, "get_remote_mac").return_value = mac
     mock_request_node_info = self.patch(
         windows_module, "request_node_info_by_mac_address")
     method.get_node_info()
     self.assertThat(mock_request_node_info, MockCalledOnceWith(mac))
Beispiel #23
0
 def test_parses_non_vlan(self):
     src_mac = factory.make_mac_address()
     dst_mac = factory.make_mac_address()
     ethertype = ETHERTYPE.ARP
     payload = factory.make_bytes(48)
     eth = Ethernet(
         make_ethernet_packet(
             dst_mac=dst_mac,
             src_mac=src_mac,
             ethertype=ethertype,
             payload=payload,
         ))
     self.assertThat(eth.dst_mac, Equals(hex_str_to_bytes(dst_mac)))
     self.assertThat(eth.src_mac, Equals(hex_str_to_bytes(src_mac)))
     self.assertThat(eth.ethertype, Equals(ethertype))
     self.assertThat(eth.payload, Equals(payload))
     self.assertThat(eth.is_valid(), Equals(True))
Beispiel #24
0
def get_example_path_and_components() -> TFTPPathAndComponents:
    """Return a plausible path and its components.

    The path is intended to match `re_config_file`, and the components are
    the expected groups from a match.
    """
    mac = factory.make_mac_address("-")
    return compose_config_path(mac), {"mac": mac.encode("ascii")}
Beispiel #25
0
 def test_interface_mac_vid_tags(self):
     mac = factory.make_mac_address()
     vid = random.randint(1, 300)
     tags = [factory.make_name("tag") for _ in range(3)]
     nic = DiscoveredMachineInterface(mac_address=mac, vid=vid, tags=tags)
     self.assertEquals(mac, nic.mac_address)
     self.assertEquals(vid, nic.vid)
     self.assertEquals(tags, nic.tags)
Beispiel #26
0
 def test_get_ip_addr_json_returns_json(self):
     results = {
         factory.make_name("eth"): {"mac": factory.make_mac_address()}
     }
     patch_get_ip_addr = self.patch(ipaddr_module, "get_ip_addr")
     patch_get_ip_addr.return_value = results
     observed = get_ip_addr_json()
     self.assertIsInstance(observed, str)
     self.assertEquals(results, json.loads(observed))
Beispiel #27
0
    def test_match_path_static_file_clean_path(self):
        method = WindowsPXEBootMethod()
        mock_mac = factory.make_mac_address()
        mock_get_node_info = self.patch(windows_module, 'get_remote_mac')
        mock_get_node_info.return_value = mock_mac

        params = yield method.match_path(None, '\\Boot\\BCD')
        self.assertEqual(mock_mac, params['mac'])
        self.assertEqual('bcd', params['path'])
Beispiel #28
0
    def test_match_path_static_file_clean_path(self):
        method = WindowsPXEBootMethod()
        mock_mac = factory.make_mac_address()
        mock_get_node_info = self.patch(windows_module, "get_remote_mac")
        mock_get_node_info.return_value = mock_mac

        params = yield method.match_path(None, "\\Boot\\BCD")
        self.assertEqual(mock_mac, params["mac"])
        self.assertEqual("bcd", params["path"])
Beispiel #29
0
    def test_probe_and_enlist(self):
        node_id = make_node_id()
        node_list = NODE_LIST % node_id
        node_info = NODE_INFO % (node_id, self.product_name)
        node_macaddr = NODE_MACADDR % (
            node_id,
            factory.make_mac_address(),
            factory.make_mac_address(),
        )
        macs = re.findall(r":".join(["[0-9a-f]{2}"] * 6), node_macaddr)

        user = factory.make_name("user")
        host = factory.make_hostname("mscm")
        username = factory.make_name("user")
        password = factory.make_name("password")
        domain = factory.make_name("domain")
        system_id = factory.make_name("system_id")
        mscm_driver = self.patch(mscm_module, "MSCMPowerDriver").return_value
        mscm_driver.run_mscm_command.side_effect = (
            node_list,
            None,
            node_info,
            node_macaddr,
        )
        create_node = self.patch(mscm_module, "create_node")
        create_node.side_effect = asynchronous(lambda *args: system_id)
        commission_node = self.patch(mscm_module, "commission_node")
        params = {
            "power_address": host,
            "power_user": username,
            "power_pass": password,
            "node_id": node_id,
        }

        yield deferToThread(
            probe_and_enlist_mscm, user, host, username, password, True, domain
        )

        self.expectThat(
            create_node,
            MockCalledOnceWith(macs, self.arch, "mscm", params, domain),
        )
        self.expectThat(commission_node, MockCalledOnceWith(system_id, user))
Beispiel #30
0
    def test_set_boot_order_network(self):
        power_partition_name = factory.make_name("power_partition_name")
        mac_address = factory.make_mac_address()
        cpc = self.fake_session.hmc.cpcs.add(
            {
                "name": factory.make_name("cpc"),
                "dpm-enabled": True,
            }
        )
        partition = cpc.partitions.add(
            {
                "name": power_partition_name,
                "status": "terminated",
            }
        )
        partition.nics.add({"mac-address": factory.make_mac_address()})
        nic = partition.nics.add({"mac-address": mac_address})

        yield self.hmcz.set_boot_order(
            None,
            self.make_context(power_partition_name),
            [
                {
                    "id": random.randint(0, 100),
                    "name": factory.make_name("name"),
                    "mac_address": mac_address,
                    "vendor": factory.make_name("vendor"),
                    "product": factory.make_name("product"),
                }
            ]
            + [
                {
                    factory.make_name("key"): factory.make_name("value")
                    for _ in range(5)
                }
                for _ in range(5)
            ],
        )

        self.assertEqual(
            "network-adapter", partition.properties["boot-device"]
        )
        self.assertEqual(nic.uri, partition.properties["boot-network-device"])