diff --git a/dsl/extdeps/bmc/types.dag b/dsl/extdeps/bmc/types.dag index eeab55ad414..38cf5af5507 100644 --- a/dsl/extdeps/bmc/types.dag +++ b/dsl/extdeps/bmc/types.dag @@ -122,6 +122,10 @@ type RedfishPrivilege = | PrivilegeConfigureComponents | PrivilegeConfigureSelf +type RedfishVirtualMediaSupport = + VirtualMediaSupported + | VirtualMediaUnsupported + fn redfish_boot_target_wire(t: RedfishBootSourceOverrideTarget) -> NonEmptyStr { match t { BootTargetNone => "None" diff --git a/dsl/extdeps/boards/asrock_rack.dag b/dsl/extdeps/boards/asrock_rack.dag index c2bd58f76f1..a2614987315 100644 --- a/dsl/extdeps/boards/asrock_rack.dag +++ b/dsl/extdeps/boards/asrock_rack.dag @@ -7,6 +7,7 @@ import std.baseboard { import std.bmc { OpenBmc } import std.types { NonEmptyStr } +import extdeps.bmc.types { RedfishVirtualMediaSupport, VirtualMediaUnsupported } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } @@ -25,3 +26,5 @@ data asrock_altrad8ud_1l2t_catalog: BaseboardCatalogRow = BaseboardCatalogRow { data asrock_altrad8ud_redfish_system_id: NonEmptyStr = "system" data asrock_altrad8ud_redfish_chassis_id: NonEmptyStr = "ALTRAD8UD_1L2T" + +data asrock_altrad8ud_virtual_media_support: RedfishVirtualMediaSupport = VirtualMediaUnsupported diff --git a/dsl/extdeps/os/ubuntu_autoinstall.dag b/dsl/extdeps/os/ubuntu_autoinstall.dag new file mode 100644 index 00000000000..29c301021d2 --- /dev/null +++ b/dsl/extdeps/os/ubuntu_autoinstall.dag @@ -0,0 +1,25 @@ +module extdeps.os.ubuntu_autoinstall + +import std.logic { Bool } +import std.types { Int } +import std.os.types { UbuntuDistribution } +import extdeps.uri { Uri, Https } +import extdeps.external_authority { ExternalAuthority } + +data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "canonical-subiquity.readthedocs-hosted.com/en/latest/reference/autoinstall-reference.html" + } +} + +type AutoinstallDeliveryMethod = + NoCloudNet { seed_url: Uri } + | NoCloudLocal + +type UbuntuAutoinstallPayload { + autoinstall_version: Int + delivery: AutoinstallDeliveryMethod + fully_automated: Bool + target_distribution: UbuntuDistribution +} diff --git a/dsl/extdeps/provisioning/network_boot.dag b/dsl/extdeps/provisioning/network_boot.dag new file mode 100644 index 00000000000..da2b3d27c1e --- /dev/null +++ b/dsl/extdeps/provisioning/network_boot.dag @@ -0,0 +1,57 @@ +module extdeps.provisioning.network_boot + +import std.types { NonEmptyStr } +import extdeps.toolchain.types { + Architecture, + X86_64, + X86, + Aarch64, + Arm, + Armv7, + Mips, + Mipsel, + Mips64, + Mips64el, + Riscv64, + Wasm32, +} +import extdeps.uri { Uri, Https } +import extdeps.external_authority { ExternalAuthority } + +data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "uefi.org/specs/UEFI/2.10/24_Network_Protocols_UDP_and_MTFTP.html" + } +} + +type ClientNetworkBootMode = + LegacyBiosPxe { tftp_root: Uri } + | UefiPxe { tftp_root: Uri } + | UefiHttpBoot + +type DhcpBootDirection = + NativeDhcpBootOptions + | ProxyDhcp + +fn network_uefi_bootloader_artifact(arch: Architecture) -> NonEmptyStr? { + match arch { + Aarch64 => Present { value: "grubnetaa64.efi" } + X86_64 => Present { value: "grubnetx64.efi" } + X86 => Absent + Arm => Absent + Armv7 => Absent + Mips => Absent + Mipsel => Absent + Mips64 => Absent + Mips64el => Absent + Riscv64 => Absent + Wasm32 => Absent + } +} + +type NetworkBootChain { + boot_mode: ClientNetworkBootMode + dhcp_direction: DhcpBootDirection + image_http_root: Uri +} diff --git a/dsl/gunbc/os_install.dag b/dsl/gunbc/os_install.dag new file mode 100644 index 00000000000..fc3ca970abd --- /dev/null +++ b/dsl/gunbc/os_install.dag @@ -0,0 +1,92 @@ +module gunbc.os_install + +import std.logic { Bool } +import std.os.types { OperatingSystemProduct, UbuntuOs, NobleNumbat2404Lts } +import extdeps.toolchain.types { Architecture, Aarch64 } +import extdeps.uri { Uri, Https } +import extdeps.provisioning.network_boot { + NetworkBootChain, + UefiHttpBoot, + DhcpBootDirection, + NativeDhcpBootOptions, + ProxyDhcp, +} +import extdeps.os.ubuntu_autoinstall { + UbuntuAutoinstallPayload, + NoCloudNet, +} +import extdeps.bmc.types { + RedfishBootSourceOverrideTarget, + BootTargetPxe, + RedfishBootSourceOverrideEnabled, + BootOverrideOnce, + RedfishResetType, + ResetForceRestart, +} + +type NetworkBootDelivery { + chain: NetworkBootChain + autoinstall: UbuntuAutoinstallPayload +} + +type LanInstallInfraSurvey { + existing_dhcp_configurable: Bool + dedicated_install_server_present: Bool +} + +fn survey_implied_dhcp_direction(survey: LanInstallInfraSurvey) -> DhcpBootDirection { + if survey.existing_dhcp_configurable { + NativeDhcpBootOptions + } else { + ProxyDhcp + } +} + +type Srv3OsInstallPlan { + os_target: OperatingSystemProduct + host_architecture: Architecture + lan_survey: LanInstallInfraSurvey + network_boot_delivery: NetworkBootDelivery + bmc_boot_target: RedfishBootSourceOverrideTarget + bmc_boot_enabled: RedfishBootSourceOverrideEnabled + post_stage_reset: RedfishResetType +} + +data srv3_lan_install_survey: LanInstallInfraSurvey = LanInstallInfraSurvey { + existing_dhcp_configurable: false, + dedicated_install_server_present: false, +} + +data srv3_network_boot_chain: NetworkBootChain = NetworkBootChain { + boot_mode: UefiHttpBoot, + dhcp_direction: survey_implied_dhcp_direction(survey: srv3_lan_install_survey), + image_http_root: Uri { + scheme: Https, + locator: "install.srv3.lan/ubuntu-24.04/", + }, +} + +data srv3_ubuntu_autoinstall: UbuntuAutoinstallPayload = UbuntuAutoinstallPayload { + autoinstall_version: 1, + delivery: NoCloudNet { + seed_url: Uri { + scheme: Https, + locator: "install.srv3.lan/ubuntu-24.04/autoinstall/", + }, + }, + fully_automated: true, + target_distribution: NobleNumbat2404Lts, +} + +data srv3_os_install_plan: Srv3OsInstallPlan = Srv3OsInstallPlan { + os_target: UbuntuOs { distro: NobleNumbat2404Lts }, + host_architecture: Aarch64, + lan_survey: srv3_lan_install_survey, + network_boot_delivery: NetworkBootDelivery { + chain: srv3_network_boot_chain, + autoinstall: srv3_ubuntu_autoinstall, + }, + bmc_boot_target: BootTargetPxe, + bmc_boot_enabled: BootOverrideOnce, + post_stage_reset: ResetForceRestart, +} diff --git a/dsl/test/claim/srv3_os_install_witness_test.dag b/dsl/test/claim/srv3_os_install_witness_test.dag new file mode 100644 index 00000000000..607649a23b7 --- /dev/null +++ b/dsl/test/claim/srv3_os_install_witness_test.dag @@ -0,0 +1,97 @@ +module test.claim.srv3_os_install + +import std.logic { Bool } +import std.os.types { UbuntuOs, WindowsOs, MacosOs, NobleNumbat2404Lts } +import extdeps.toolchain.types { X86_64, Riscv64 } +import extdeps.provisioning.network_boot { + network_uefi_bootloader_artifact, + NativeDhcpBootOptions, + ProxyDhcp, + UefiHttpBoot, + LegacyBiosPxe, + UefiPxe, +} +import extdeps.os.ubuntu_autoinstall { + NoCloudNet, + NoCloudLocal, +} +import gunbc.os_install { + LanInstallInfraSurvey, + survey_implied_dhcp_direction, + srv3_network_boot_chain, + srv3_os_install_plan, +} +import extdeps.bmc.types { + redfish_boot_target_wire, + redfish_boot_override_enabled_wire, + VirtualMediaSupported, + VirtualMediaUnsupported, +} +import extdeps.boards.asrock_rack { + asrock_altrad8ud_virtual_media_support, +} + +test fn srv3_bootloader_artifact_is_arch_grounded() -> Bool { + match network_uefi_bootloader_artifact(arch: srv3_os_install_plan.host_architecture) { + Present { value: a } => a == "grubnetaa64.efi" + Absent => false + } + && match network_uefi_bootloader_artifact(arch: X86_64) { + Present { value: x } => x == "grubnetx64.efi" + Absent => false + } + && match network_uefi_bootloader_artifact(arch: Riscv64) { + Present { value: _ } => false + Absent => true + } +} + +test fn srv3_chain_is_uefi_http_boot() -> Bool { + match srv3_network_boot_chain.boot_mode { + UefiHttpBoot => true + LegacyBiosPxe { tftp_root: _ } => false + UefiPxe { tftp_root: _ } => false + } +} + +test fn srv3_survey_forces_proxy_dhcp() -> Bool { + match srv3_network_boot_chain.dhcp_direction { + ProxyDhcp => true + NativeDhcpBootOptions => false + } + && match survey_implied_dhcp_direction( + survey: LanInstallInfraSurvey { + existing_dhcp_configurable: true, + dedicated_install_server_present: false, + } + ) { + ProxyDhcp => false + NativeDhcpBootOptions => true + } +} + +test fn srv3_board_has_no_virtual_media() -> Bool { + match asrock_altrad8ud_virtual_media_support { + VirtualMediaSupported => false + VirtualMediaUnsupported => true + } +} + +test fn srv3_plan_targets_ubuntu_2404_aarch64_pxe_once() -> Bool { + match srv3_os_install_plan.os_target { + UbuntuOs { distro: d } => + match d { + NobleNumbat2404Lts => true + } + WindowsOs { distro: _ } => false + MacosOs { distro: _ } => false + } + && redfish_boot_target_wire(t: srv3_os_install_plan.bmc_boot_target) == "Pxe" + && redfish_boot_override_enabled_wire(e: srv3_os_install_plan.bmc_boot_enabled) == "Once" + && srv3_os_install_plan.network_boot_delivery.autoinstall.fully_automated + && srv3_os_install_plan.network_boot_delivery.autoinstall.autoinstall_version == 1 + && match srv3_os_install_plan.network_boot_delivery.autoinstall.delivery { + NoCloudNet { seed_url: _ } => true + NoCloudLocal => false + } +}