def test_pxeconfig_has_preseed_url_for_known_node(self): params = self.get_mac_params() node = MACAddress.objects.get(mac_address=params['mac']).node response = self.client.get(reverse('pxeconfig'), params) self.assertEqual( compose_preseed_url(node), json.loads(response.content)["preseed_url"])
def test__has_preseed_url_for_known_node(self): rack_controller = factory.make_RackController() local_ip = factory.make_ip_address() remote_ip = factory.make_ip_address() node = self.make_node(status=NODE_STATUS.DEPLOYING) mac = node.get_boot_interface().mac_address observed_config = get_config( rack_controller.system_id, local_ip, remote_ip, mac=mac) self.assertEqual( compose_preseed_url(node, rack_controller), observed_config["preseed_url"])
def test__has_preseed_url_for_known_node(self): rack_controller = factory.make_RackController(url='') local_ip = factory.make_ip_address() remote_ip = factory.make_ip_address() node = self.make_node(status=NODE_STATUS.DEPLOYING) mac = node.get_boot_interface().mac_address self.patch(boot_module, 'get_source_address').return_value = local_ip observed_config = get_config(rack_controller.system_id, local_ip, remote_ip, mac=mac) self.assertEqual( compose_preseed_url(node, rack_controller, default_region_ip=local_ip), observed_config["preseed_url"])
def get_config( system_id, local_ip, remote_ip, arch=None, subarch=None, mac=None, bios_boot_method=None): """Get the booting configration for the a machine. Returns a structure suitable for returning in the response for :py:class:`~provisioningserver.rpc.region.GetBootConfig`. Raises BootConfigNoResponse when booting machine should fail to next file. """ rack_controller = RackController.objects.get(system_id=system_id) region_ip = None if remote_ip is not None: region_ip = get_source_address(remote_ip) machine = get_node_from_mac_string(mac) # Fail with no response early so no extra work is performed. if machine is None and arch is None and mac is not None: # Request was pxelinux.cfg/01-<mac> for a machine MAAS does not know # about. So attempt fall back to pxelinux.cfg/default-<arch>-<subarch> # for arch detection. raise BootConfigNoResponse() if machine is not None: # Update the last interface, last access cluster IP address, and # the last used BIOS boot method. Only saving the fields that have # changed on the machine. update_fields = [] if (machine.boot_interface is None or machine.boot_interface.mac_address != mac): machine.boot_interface = PhysicalInterface.objects.get( mac_address=mac) update_fields.append("boot_interface") if (machine.boot_cluster_ip is None or machine.boot_cluster_ip != local_ip): machine.boot_cluster_ip = local_ip update_fields.append("boot_cluster_ip") if machine.bios_boot_method != bios_boot_method: machine.bios_boot_method = bios_boot_method update_fields.append("bios_boot_method") if len(update_fields) > 0: machine.save(update_fields=update_fields) # Update the VLAN of the boot interface to be the same VLAN for the # interface on the rack controller that the machine communicated with, # unless the VLAN is being relayed. rack_interface = rack_controller.interface_set.filter( ip_addresses__ip=local_ip).first() if (rack_interface is not None and machine.boot_interface.vlan != rack_interface.vlan): # Rack controller and machine is not on the same VLAN, with DHCP # relay this is possible. Lets ensure that the VLAN on the # interface is setup to relay through the identified VLAN. if not VLAN.objects.filter( id=machine.boot_interface.vlan_id, relay_vlan=rack_interface.vlan).exists(): # DHCP relay is not being performed for that VLAN. Set the VLAN # to the VLAN of the rack controller. machine.boot_interface.vlan = rack_interface.vlan machine.boot_interface.save() arch, subarch = machine.split_arch() preseed_url = compose_preseed_url( machine, rack_controller, default_region_ip=region_ip) hostname = machine.hostname domain = machine.domain.name purpose = machine.get_boot_purpose() # Log the request into the event log for that machine. if (machine.status == NODE_STATUS.ENTERING_RESCUE_MODE and purpose == 'commissioning'): event_log_pxe_request(machine, 'rescue') else: event_log_pxe_request(machine, purpose) # Get the correct operating system and series based on the purpose # of the booting machine. if purpose == "commissioning": osystem = Config.objects.get_config('commissioning_osystem') series = Config.objects.get_config('commissioning_distro_series') else: osystem = machine.get_osystem() series = machine.get_distro_series() if purpose == "xinstall" and osystem != "ubuntu": # Use only the commissioning osystem and series, for operating # systems other than Ubuntu. As Ubuntu supports HWE kernels, # and needs to use that kernel to perform the installation. osystem = Config.objects.get_config('commissioning_osystem') series = Config.objects.get_config( 'commissioning_distro_series') # Pre MAAS-1.9 the subarchitecture defined any kernel the machine # needed to be able to boot. This could be a hardware enablement # kernel(e.g hwe-t) or something like highbank. With MAAS-1.9 any # hardware enablement kernel must be specifed in the hwe_kernel field, # any other kernel, such as highbank, is still specifed as a # subarchitecture. Since Ubuntu does not support architecture specific # hardware enablement kernels(i.e a highbank hwe-t kernel on precise) # we give precedence to any kernel defined in the subarchitecture field if subarch == "generic" and machine.hwe_kernel: subarch = machine.hwe_kernel elif(subarch == "generic" and purpose == "commissioning" and machine.min_hwe_kernel): try: subarch = validate_hwe_kernel( None, machine.min_hwe_kernel, machine.architecture, osystem, series) except ValidationError: subarch = "no-such-kernel" # We don't care if the kernel opts is from the global setting or a tag, # just get the options _, effective_kernel_opts = machine.get_effective_kernel_options() # Add any extra options from a third party driver. use_driver = Config.objects.get_config('enable_third_party_drivers') if use_driver: driver = get_third_party_driver(machine) driver_kernel_opts = driver.get('kernel_opts', '') combined_opts = ('%s %s' % ( '' if effective_kernel_opts is None else effective_kernel_opts, driver_kernel_opts)).strip() if len(combined_opts): extra_kernel_opts = combined_opts else: extra_kernel_opts = None else: extra_kernel_opts = effective_kernel_opts kparams = BootResource.objects.get_kparams_for_node(machine) extra_kernel_opts = merge_kparams_with_extra(kparams, extra_kernel_opts) else: purpose = "commissioning" # enlistment preseed_url = compose_enlistment_preseed_url( rack_controller, default_region_ip=region_ip) hostname = 'maas-enlist' domain = 'local' osystem = Config.objects.get_config('commissioning_osystem') series = Config.objects.get_config('commissioning_distro_series') min_hwe_kernel = Config.objects.get_config('default_min_hwe_kernel') # When no architecture is defined for the enlisting machine select # the best boot resource for the operating system and series. If # none exists fallback to the default architecture. LP #1181334 if arch is None: resource = ( BootResource.objects.get_default_commissioning_resource( osystem, series)) if resource is None: arch = DEFAULT_ARCH else: arch, _ = resource.split_arch() # The subarch defines what kernel is booted. With MAAS 2.1 this changed # from hwe-<letter> to hwe-<version> or ga-<version>. Validation # converts between the two formats to make sure a bootable subarch is # selected. if subarch is None: min_hwe_kernel = validate_hwe_kernel( None, min_hwe_kernel, '%s/generic' % arch, osystem, series) else: min_hwe_kernel = validate_hwe_kernel( None, min_hwe_kernel, '%s/%s' % (arch, subarch), osystem, series) # If no hwe_kernel was found set the subarch to the default, 'generic.' if min_hwe_kernel is None: subarch = 'generic' else: subarch = min_hwe_kernel # Global kernel options for enlistment. extra_kernel_opts = Config.objects.get_config("kernel_opts") # Set the final boot purpose. if machine is None and arch == DEFAULT_ARCH: # If the machine is enlisting and the arch is the default arch (i386), # use the dedicated enlistment template which performs architecture # detection. boot_purpose = "enlist" elif purpose == 'poweroff': # In order to power the machine off, we need to get it booted in the # commissioning environment and issue a `poweroff` command. boot_purpose = 'commissioning' else: boot_purpose = purpose # Get the service address to the region for that given rack controller. server_host = get_maas_facing_server_host( rack_controller=rack_controller, default_region_ip=region_ip) kernel, initrd, boot_dtb = get_boot_filenames( arch, subarch, osystem, series) # Return the params to the rack controller. Include the system_id only # if the machine was known. params = { "arch": arch, "subarch": subarch, "osystem": osystem, "release": series, "kernel": kernel, "initrd": initrd, "boot_dtb": boot_dtb, "purpose": boot_purpose, "hostname": hostname, "domain": domain, "preseed_url": preseed_url, "fs_host": local_ip, "log_host": server_host, "extra_opts": '' if extra_kernel_opts is None else extra_kernel_opts, # As of MAAS 2.4 only HTTP boot is supported. This ensures MAAS 2.3 # rack controllers use HTTP boot as well. "http_boot": True, } if machine is not None: params["system_id"] = machine.system_id return params
def get_config( system_id, local_ip, remote_ip, arch=None, subarch=None, mac=None, bios_boot_method=None): """Get the booting configration for the a machine. Returns a structure suitable for returning in the response for :py:class:`~provisioningserver.rpc.region.GetBootConfig`. Raises BootConfigNoResponse when booting machine should fail to next file. """ rack_controller = RackController.objects.get(system_id=system_id) region_ip = None if remote_ip is not None: region_ip = get_source_address(remote_ip) machine = get_node_from_mac_string(mac) # Get the service address to the region for that given rack controller. server_host = get_maas_facing_server_host( rack_controller=rack_controller, default_region_ip=region_ip) # Fail with no response early so no extra work is performed. if machine is None and arch is None and mac is not None: # Request was pxelinux.cfg/01-<mac> for a machine MAAS does not know # about. So attempt fall back to pxelinux.cfg/default-<arch>-<subarch> # for arch detection. raise BootConfigNoResponse() configs = Config.objects.get_configs([ 'commissioning_osystem', 'commissioning_distro_series', 'enable_third_party_drivers', 'default_min_hwe_kernel', 'default_osystem', 'default_distro_series', 'kernel_opts', 'use_rack_proxy', 'maas_internal_domain', ]) if machine is not None: # Update the last interface, last access cluster IP address, and # the last used BIOS boot method. if (machine.boot_interface is None or machine.boot_interface.mac_address != mac): machine.boot_interface = PhysicalInterface.objects.get( mac_address=mac) if (machine.boot_cluster_ip is None or machine.boot_cluster_ip != local_ip): machine.boot_cluster_ip = local_ip if machine.bios_boot_method != bios_boot_method: machine.bios_boot_method = bios_boot_method # Reset the machine's status_expires whenever the boot_config is called # on a known machine. This allows a machine to take up to the maximum # timeout status to POST. machine.reset_status_expires() # Does nothing if the machine hasn't changed. machine.save() # Update the VLAN of the boot interface to be the same VLAN for the # interface on the rack controller that the machine communicated with, # unless the VLAN is being relayed. rack_interface = rack_controller.interface_set.filter( ip_addresses__ip=local_ip).select_related('vlan').first() if (rack_interface is not None and machine.boot_interface.vlan_id != rack_interface.vlan_id): # Rack controller and machine is not on the same VLAN, with DHCP # relay this is possible. Lets ensure that the VLAN on the # interface is setup to relay through the identified VLAN. if not VLAN.objects.filter( id=machine.boot_interface.vlan_id, relay_vlan=rack_interface.vlan_id).exists(): # DHCP relay is not being performed for that VLAN. Set the VLAN # to the VLAN of the rack controller. machine.boot_interface.vlan = rack_interface.vlan machine.boot_interface.save() arch, subarch = machine.split_arch() if configs['use_rack_proxy']: preseed_url = compose_preseed_url( machine, base_url=get_base_url_for_local_ip( local_ip, configs['maas_internal_domain'])) else: preseed_url = compose_preseed_url( machine, base_url=rack_controller.url, default_region_ip=region_ip) hostname = machine.hostname domain = machine.domain.name purpose = machine.get_boot_purpose() # Early out if the machine is booting local. if purpose == 'local': return { "system_id": machine.system_id, "arch": arch, "subarch": subarch, "osystem": machine.osystem, "release": machine.distro_series, "kernel": '', "initrd": '', "boot_dtb": '', "purpose": purpose, "hostname": hostname, "domain": domain, "preseed_url": preseed_url, "fs_host": local_ip, "log_host": server_host, "extra_opts": '', "http_boot": True, } # Log the request into the event log for that machine. if (machine.status in [ NODE_STATUS.ENTERING_RESCUE_MODE, NODE_STATUS.RESCUE_MODE] and purpose == 'commissioning'): event_log_pxe_request(machine, 'rescue') else: event_log_pxe_request(machine, purpose) osystem, series, subarch = get_boot_config_for_machine( machine, configs, purpose) # We don't care if the kernel opts is from the global setting or a tag, # just get the options _, effective_kernel_opts = machine.get_effective_kernel_options( default_kernel_opts=configs['kernel_opts']) # Add any extra options from a third party driver. use_driver = configs['enable_third_party_drivers'] if use_driver: driver = get_third_party_driver(machine) driver_kernel_opts = driver.get('kernel_opts', '') combined_opts = ('%s %s' % ( '' if effective_kernel_opts is None else effective_kernel_opts, driver_kernel_opts)).strip() if len(combined_opts): extra_kernel_opts = combined_opts else: extra_kernel_opts = None else: extra_kernel_opts = effective_kernel_opts kparams = BootResource.objects.get_kparams_for_node( machine, default_osystem=configs['default_osystem'], default_distro_series=configs['default_distro_series']) extra_kernel_opts = merge_kparams_with_extra(kparams, extra_kernel_opts) else: purpose = "commissioning" # enlistment if configs['use_rack_proxy']: preseed_url = compose_enlistment_preseed_url( base_url=get_base_url_for_local_ip( local_ip, configs['maas_internal_domain'])) else: preseed_url = compose_enlistment_preseed_url( rack_controller=rack_controller, default_region_ip=region_ip) hostname = 'maas-enlist' domain = 'local' osystem = configs['commissioning_osystem'] series = configs['commissioning_distro_series'] min_hwe_kernel = configs['default_min_hwe_kernel'] # When no architecture is defined for the enlisting machine select # the best boot resource for the operating system and series. If # none exists fallback to the default architecture. LP #1181334 if arch is None: resource = ( BootResource.objects.get_default_commissioning_resource( osystem, series)) if resource is None: arch = DEFAULT_ARCH else: arch, _ = resource.split_arch() # The subarch defines what kernel is booted. With MAAS 2.1 this changed # from hwe-<letter> to hwe-<version> or ga-<version>. Validation # converts between the two formats to make sure a bootable subarch is # selected. if subarch is None: min_hwe_kernel = validate_hwe_kernel( None, min_hwe_kernel, '%s/generic' % arch, osystem, series) else: min_hwe_kernel = validate_hwe_kernel( None, min_hwe_kernel, '%s/%s' % (arch, subarch), osystem, series) # If no hwe_kernel was found set the subarch to the default, 'generic.' if min_hwe_kernel is None: subarch = 'generic' else: subarch = min_hwe_kernel # Global kernel options for enlistment. extra_kernel_opts = configs["kernel_opts"] # Set the final boot purpose. if machine is None and arch == DEFAULT_ARCH: # If the machine is enlisting and the arch is the default arch (i386), # use the dedicated enlistment template which performs architecture # detection. boot_purpose = "enlist" elif purpose == 'poweroff': # In order to power the machine off, we need to get it booted in the # commissioning environment and issue a `poweroff` command. boot_purpose = 'commissioning' else: boot_purpose = purpose kernel, initrd, boot_dtb = get_boot_filenames( arch, subarch, osystem, series, commissioning_osystem=configs['commissioning_osystem'], commissioning_distro_series=configs['commissioning_distro_series']) # Return the params to the rack controller. Include the system_id only # if the machine was known. params = { "arch": arch, "subarch": subarch, "osystem": osystem, "release": series, "kernel": kernel, "initrd": initrd, "boot_dtb": boot_dtb, "purpose": boot_purpose, "hostname": hostname, "domain": domain, "preseed_url": preseed_url, "fs_host": local_ip, "log_host": server_host, "extra_opts": '' if extra_kernel_opts is None else extra_kernel_opts, # As of MAAS 2.4 only HTTP boot is supported. This ensures MAAS 2.3 # rack controllers use HTTP boot as well. "http_boot": True, } if machine is not None: params["system_id"] = machine.system_id return params
def get_config( system_id, local_ip, remote_ip, arch=None, subarch=None, mac=None, hardware_uuid=None, bios_boot_method=None, ): """Get the booting configration for a machine. Returns a structure suitable for returning in the response for :py:class:`~provisioningserver.rpc.region.GetBootConfig`. Raises BootConfigNoResponse when booting machine should fail to next file. """ rack_controller = RackController.objects.get(system_id=system_id) region_ip = None if remote_ip is not None: region_ip = get_source_address(remote_ip) machine = get_node_from_mac_or_hardware_uuid(mac, hardware_uuid) # Fail with no response early so no extra work is performed. if machine is None and arch is None and (mac or hardware_uuid): # PXELinux requests boot configuration in the following order: # 1. pxelinux.cfg/<hardware uuid> # 2. pxelinux.cfg/01-<mac> # 3. pxelinux.cfg/default-<arch>-<subarch> # If mac and/or hardware_uuid was given but no Node was found fail the # request so PXELinux will move onto the next request. raise BootConfigNoResponse() # Get all required configuration objects in a single query. configs = Config.objects.get_configs([ "commissioning_osystem", "commissioning_distro_series", "enable_third_party_drivers", "default_min_hwe_kernel", "default_osystem", "default_distro_series", "kernel_opts", "use_rack_proxy", "maas_internal_domain", "remote_syslog", "maas_syslog_port", ]) # Compute the syslog server. log_host, log_port = ( local_ip, (configs["maas_syslog_port"] if configs["maas_syslog_port"] else RSYSLOG_PORT), ) if configs["remote_syslog"]: log_host, log_port = splithost(configs["remote_syslog"]) if log_port is None: log_port = 514 # Fallback to default UDP syslog port. if machine is not None: # Update the last interface, last access cluster IP address, and # the last used BIOS boot method. if machine.boot_cluster_ip != local_ip: machine.boot_cluster_ip = local_ip if machine.bios_boot_method != bios_boot_method: machine.bios_boot_method = bios_boot_method try: machine.boot_interface = machine.interface_set.get( type=INTERFACE_TYPE.PHYSICAL, mac_address=mac) except ObjectDoesNotExist: # MAC is unknown or wasn't sent. Determine the boot_interface using # the boot_cluster_ip. subnet = Subnet.objects.get_best_subnet_for_ip(local_ip) boot_vlan = getattr(machine.boot_interface, "vlan", None) if subnet and subnet.vlan != boot_vlan: # This might choose the wrong interface, but we don't # have enough information to decide which interface is # the boot one. machine.boot_interface = machine.interface_set.filter( vlan=subnet.vlan).first() else: # Update the VLAN of the boot interface to be the same VLAN for the # interface on the rack controller that the machine communicated # with, unless the VLAN is being relayed. rack_interface = (rack_controller.interface_set.filter( ip_addresses__ip=local_ip).select_related("vlan").first()) if (rack_interface is not None and machine.boot_interface.vlan_id != rack_interface.vlan_id): # Rack controller and machine is not on the same VLAN, with # DHCP relay this is possible. Lets ensure that the VLAN on the # interface is setup to relay through the identified VLAN. if not VLAN.objects.filter( id=machine.boot_interface.vlan_id, relay_vlan=rack_interface.vlan_id, ).exists(): # DHCP relay is not being performed for that VLAN. Set the # VLAN to the VLAN of the rack controller. machine.boot_interface.vlan = rack_interface.vlan machine.boot_interface.save() # Reset the machine's status_expires whenever the boot_config is called # on a known machine. This allows a machine to take up to the maximum # timeout status to POST. machine.reset_status_expires() # Does nothing if the machine hasn't changed. machine.save() arch, subarch = machine.split_arch() if configs["use_rack_proxy"]: preseed_url = compose_preseed_url( machine, base_url=get_base_url_for_local_ip( local_ip, configs["maas_internal_domain"]), ) else: preseed_url = compose_preseed_url( machine, base_url=rack_controller.url, default_region_ip=region_ip, ) hostname = machine.hostname domain = machine.domain.name purpose = machine.get_boot_purpose() # Ephemeral deployments will have 'local' boot # purpose on power cycles. Set purpose back to # 'xinstall' so that the system can be re-deployed. if purpose == "local" and machine.ephemeral_deployment: purpose = "xinstall" # Early out if the machine is booting local. if purpose == "local": if machine.is_device: # Log that we are setting to local boot for a device. maaslog.warning( "Device %s with MAC address %s is PXE booting; " "instructing the device to boot locally." % (machine.hostname, mac)) # Set the purpose to 'local-device' so we can log a message # on the rack. purpose = "local-device" return { "system_id": machine.system_id, "arch": arch, "subarch": subarch, "osystem": machine.osystem, "release": machine.distro_series, "kernel": "", "initrd": "", "boot_dtb": "", "purpose": purpose, "hostname": hostname, "domain": domain, "preseed_url": preseed_url, "fs_host": local_ip, "log_host": log_host, "log_port": log_port, "extra_opts": "", "http_boot": True, } # Log the request into the event log for that machine. if (machine.status in [NODE_STATUS.ENTERING_RESCUE_MODE, NODE_STATUS.RESCUE_MODE] and purpose == "commissioning"): event_log_pxe_request(machine, "rescue") else: event_log_pxe_request(machine, purpose) osystem, series, subarch = get_boot_config_for_machine( machine, configs, purpose) # We don't care if the kernel opts is from the global setting or a tag, # just get the options _, effective_kernel_opts = machine.get_effective_kernel_options( default_kernel_opts=configs["kernel_opts"]) # Add any extra options from a third party driver. use_driver = configs["enable_third_party_drivers"] if use_driver: driver = get_third_party_driver(machine) driver_kernel_opts = driver.get("kernel_opts", "") combined_opts = ("%s %s" % ( "" if effective_kernel_opts is None else effective_kernel_opts, driver_kernel_opts, )).strip() if len(combined_opts): extra_kernel_opts = combined_opts else: extra_kernel_opts = None else: extra_kernel_opts = effective_kernel_opts kparams = BootResource.objects.get_kparams_for_node( machine, default_osystem=configs["default_osystem"], default_distro_series=configs["default_distro_series"], ) extra_kernel_opts = merge_kparams_with_extra(kparams, extra_kernel_opts) else: purpose = "commissioning" # enlistment if configs["use_rack_proxy"]: preseed_url = compose_enlistment_preseed_url( base_url=get_base_url_for_local_ip( local_ip, configs["maas_internal_domain"])) else: preseed_url = compose_enlistment_preseed_url( rack_controller=rack_controller, default_region_ip=region_ip) hostname = "maas-enlist" domain = "local" osystem = configs["commissioning_osystem"] series = configs["commissioning_distro_series"] min_hwe_kernel = configs["default_min_hwe_kernel"] # When no architecture is defined for the enlisting machine select # the best boot resource for the operating system and series. If # none exists fallback to the default architecture. LP #1181334 if arch is None: resource = BootResource.objects.get_default_commissioning_resource( osystem, series) if resource is None: arch = DEFAULT_ARCH else: arch, _ = resource.split_arch() # The subarch defines what kernel is booted. With MAAS 2.1 this changed # from hwe-<letter> to hwe-<version> or ga-<version>. Validation # converts between the two formats to make sure a bootable subarch is # selected. if subarch is None: min_hwe_kernel = validate_hwe_kernel(None, min_hwe_kernel, "%s/generic" % arch, osystem, series) else: min_hwe_kernel = validate_hwe_kernel( None, min_hwe_kernel, "%s/%s" % (arch, subarch), osystem, series, ) # If no hwe_kernel was found set the subarch to the default, 'generic.' if min_hwe_kernel is None: subarch = "generic" else: subarch = min_hwe_kernel # Global kernel options for enlistment. extra_kernel_opts = configs["kernel_opts"] boot_purpose = get_final_boot_purpose(machine, arch, purpose) kernel, initrd, boot_dtb = get_boot_filenames( arch, subarch, osystem, series, commissioning_osystem=configs["commissioning_osystem"], commissioning_distro_series=configs["commissioning_distro_series"], ) # Return the params to the rack controller. Include the system_id only # if the machine was known. params = { "arch": arch, "subarch": subarch, "osystem": osystem, "release": series, "kernel": kernel, "initrd": initrd, "boot_dtb": boot_dtb, "purpose": boot_purpose, "hostname": hostname, "domain": domain, "preseed_url": preseed_url, "fs_host": local_ip, "log_host": log_host, "log_port": log_port, "extra_opts": "" if extra_kernel_opts is None else extra_kernel_opts, # As of MAAS 2.4 only HTTP boot is supported. This ensures MAAS 2.3 # rack controllers use HTTP boot as well. "http_boot": True, } if machine is not None: params["system_id"] = machine.system_id return params
def test_compose_preseed_url_returns_absolute_link(self): self.assertThat( compose_preseed_url(factory.make_node()), StartsWith('http://'))
def test_compose_preseed_url_links_to_preseed_for_node(self): node = factory.make_node() response = self.client.get(compose_preseed_url(node)) self.assertEqual( (httplib.OK, get_preseed(node)), (response.status_code, response.content))
def test_pxeconfig_has_preseed_url_for_known_node(self): params = self.get_mac_params() node = MACAddress.objects.get(mac_address=params['mac']).node response = self.client.get(reverse('pxeconfig'), params) self.assertEqual(compose_preseed_url(node), json.loads(response.content)["preseed_url"])
def test_compose_preseed_url_returns_absolute_link(self): self.assertThat(compose_preseed_url(factory.make_node()), StartsWith('http://'))
def test_compose_preseed_url_links_to_preseed_for_node(self): node = factory.make_node() response = self.client.get(compose_preseed_url(node)) self.assertEqual((httplib.OK, get_preseed(node)), (response.status_code, response.content))