Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions dsl/extdeps/bmc/http.dag
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority {

service redfish.Http {

operation GetServiceRoot {
input { bmc_host: NonEmptyStr }
output { body: String from "stdout", success: Bool from "exit_success" }
readonly
transport shell {
argv: ["curl", "-sS", "-k", "https://{bmc_host}/redfish/v1"]
}
exit {
0 => Unit
nonzero => String "redfish service root GET failed"
}
}

operation GetSystem {
input { bmc_host: NonEmptyStr, username: NonEmptyStr, password: NonEmptyStr }
output { body: String from "stdout", success: Bool from "exit_success" }
Expand Down Expand Up @@ -78,4 +91,40 @@ service redfish.Http {
nonzero => String "redfish thermal GET failed"
}
}

operation SetAccountPassword {
input { bmc_host: NonEmptyStr, netrc_file: NonEmptyStr, account_id: NonEmptyStr, request_body_file: NonEmptyStr }
output { body: String from "stdout", success: Bool from "exit_success" }
transport shell {
argv: ["curl", "-sS", "-k", "--netrc-file", "{netrc_file}", "-X", "PATCH", "-H", "Content-Type: application/json", "--data", "@{request_body_file}", "https://{bmc_host}/redfish/v1/AccountService/Accounts/{account_id}"]
}
exit {
0 => Unit
nonzero => String "redfish account password PATCH failed"
}
}

operation SetBootSourceOverride {
input { bmc_host: NonEmptyStr, netrc_file: NonEmptyStr, system_id: NonEmptyStr, request_body_file: NonEmptyStr }
output { body: String from "stdout", success: Bool from "exit_success" }
transport shell {
argv: ["curl", "-sS", "-k", "--netrc-file", "{netrc_file}", "-X", "PATCH", "-H", "Content-Type: application/json", "--data", "@{request_body_file}", "https://{bmc_host}/redfish/v1/Systems/{system_id}"]
}
exit {
0 => Unit
nonzero => String "redfish boot source override PATCH failed"
}
}

operation ResetSystem {
input { bmc_host: NonEmptyStr, netrc_file: NonEmptyStr, system_id: NonEmptyStr, request_body_file: NonEmptyStr }
output { body: String from "stdout", success: Bool from "exit_success" }
transport shell {
argv: ["curl", "-sS", "-k", "--netrc-file", "{netrc_file}", "-X", "POST", "-H", "Content-Type: application/json", "--data", "@{request_body_file}", "https://{bmc_host}/redfish/v1/Systems/{system_id}/Actions/ComputerSystem.Reset"]
}
exit {
0 => Unit
nonzero => String "redfish system reset POST failed"
}
}
}
66 changes: 66 additions & 0 deletions dsl/extdeps/bmc/types.dag
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,69 @@ type BmcGroundedHostObservations {
total_memory_bytes: ByteSize
power_consumed_watts: Watt?
}

type RedfishBootSourceOverrideTarget =
BootTargetNone
| BootTargetPxe
| BootTargetHdd
| BootTargetCd
| BootTargetUsb
| BootTargetBiosSetup
| BootTargetDiags

type RedfishBootSourceOverrideEnabled =
BootOverrideDisabled
| BootOverrideOnce
| BootOverrideContinuous

type RedfishResetType =
ResetForceOff
| ResetForceOn
| ResetForceRestart
| ResetGracefulRestart
| ResetGracefulShutdown
| ResetPowerCycle

type RedfishAccountRole =
AccountRoleAdministrator
| AccountRoleOperator
| AccountRoleReadOnly

fn redfish_boot_target_wire(t: RedfishBootSourceOverrideTarget) -> NonEmptyStr {
match t {
BootTargetNone => "None"
BootTargetPxe => "Pxe"
BootTargetHdd => "Hdd"
BootTargetCd => "Cd"
BootTargetUsb => "Usb"
BootTargetBiosSetup => "BiosSetup"
BootTargetDiags => "Diags"
}
}

fn redfish_boot_override_enabled_wire(e: RedfishBootSourceOverrideEnabled) -> NonEmptyStr {
match e {
BootOverrideDisabled => "Disabled"
BootOverrideOnce => "Once"
BootOverrideContinuous => "Continuous"
}
}

fn redfish_reset_type_wire(r: RedfishResetType) -> NonEmptyStr {
match r {
ResetForceOff => "ForceOff"
ResetForceOn => "ForceOn"
ResetForceRestart => "ForceRestart"
ResetGracefulRestart => "GracefulRestart"
ResetGracefulShutdown => "GracefulShutdown"
ResetPowerCycle => "PowerCycle"
}
}

fn redfish_account_role_wire(role: RedfishAccountRole) -> NonEmptyStr {
match role {
AccountRoleAdministrator => "Administrator"
AccountRoleOperator => "Operator"
AccountRoleReadOnly => "ReadOnly"
}
}
46 changes: 46 additions & 0 deletions dsl/gunbc/bmc_onboarding.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module gunbc.bmc_onboarding

import std.bmc { BmcEndpoint, Redfish }
import std.credentials { FactoryLogin, CredentialFlow, Stored }
import std.os.types { OperatingSystemProduct, UbuntuOs, NobleNumbat2404Lts }
import std.types { NonEmptyStr }
import extdeps.bmc.types { RedfishBootSourceOverrideTarget, BootTargetPxe, RedfishAccountRole, AccountRoleAdministrator }
import extdeps.bmc.openbmc { openbmc_factory_login }
import extdeps.boards.asrock_rack { asrock_altrad8ud_redfish_system_id }

type BmcOnboardingPhase =
FactoryDefault
| CredentialsRotated
| OsInstalled
| FabricJoined

fn bmc_onboarding_next_phase(phase: BmcOnboardingPhase) -> BmcOnboardingPhase? {
match phase {
FactoryDefault => Present { value: CredentialsRotated }
CredentialsRotated => Present { value: OsInstalled }
OsInstalled => Present { value: FabricJoined }
FabricJoined => Absent
}
}

type BmcOnboardingPlan {
bmc: BmcEndpoint
redfish_system_id: NonEmptyStr
factory_login: FactoryLogin
rotated_credential: CredentialFlow
rotated_account_role: RedfishAccountRole
os_target: OperatingSystemProduct
os_install_boot_target: RedfishBootSourceOverrideTarget
start_phase: BmcOnboardingPhase
}

data new_altra_onboarding_plan: BmcOnboardingPlan = BmcOnboardingPlan {
bmc: BmcEndpoint { host: "192.168.1.192", protocol: Redfish },
redfish_system_id: asrock_altrad8ud_redfish_system_id,
factory_login: openbmc_factory_login,
rotated_credential: Stored { secret_name: "bmc-srv3-admin" },
rotated_account_role: AccountRoleAdministrator,
os_target: UbuntuOs { distro: NobleNumbat2404Lts },
os_install_boot_target: BootTargetPxe,
start_phase: FactoryDefault,
}
26 changes: 26 additions & 0 deletions dsl/gunbc/tools/bmc_onboard_validate.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module gunbc.tools.bmc_onboard_validate

import extdeps.bmc.http
import gunbc.bmc_onboarding { new_altra_onboarding_plan }
import std.types { NonEmptyStr }
import std.resources { Network }
import std.process { ProcessExit, ExitSuccess, exit_failure }

func bmc_onboard_validate() -> ProcessExit
uses net: Network
{
let bmc_host = new_altra_onboarding_plan.bmc.host

root_resp = redfish.Http.GetServiceRoot(bmc_host: bmc_host)
if root_resp.success == false {
return exit_failure(reason: root_resp.body)
}

system_resp = redfish.Http.GetSystem(
bmc_host: bmc_host,
username: new_altra_onboarding_plan.factory_login.username,
password: new_altra_onboarding_plan.factory_login.published_password
)

return if system_resp.success { ExitSuccess } else { exit_failure(reason: system_resp.body) }
}
60 changes: 60 additions & 0 deletions dsl/test/claim/bmc_onboarding_lifecycle_witness_test.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module test.claim.bmc_onboarding_lifecycle

import std.logic { Bool }
import std.types { Int }
import std.credentials { Stored, Chained }
import std.os.types { UbuntuOs, WindowsOs, MacosOs, NobleNumbat2404Lts }
import gunbc.bmc_onboarding {
BmcOnboardingPhase,
FactoryDefault,
CredentialsRotated,
OsInstalled,
FabricJoined,
bmc_onboarding_next_phase,
new_altra_onboarding_plan,
}
import extdeps.bmc.types { BootTargetPxe, AccountRoleAdministrator, redfish_boot_target_wire, redfish_account_role_wire }

fn phase_tag(p: BmcOnboardingPhase) -> Int {
match p {
FactoryDefault => 0
CredentialsRotated => 1
OsInstalled => 2
FabricJoined => 3
}
}

fn next_tag(p: BmcOnboardingPhase) -> Int {
match bmc_onboarding_next_phase(phase: p) {
Present { value: q } => phase_tag(p: q)
Absent => -1
}
}

test fn bmc_onboarding_lifecycle_is_linear_dag() -> Bool {
next_tag(p: FactoryDefault) == 1
&& next_tag(p: CredentialsRotated) == 2
&& next_tag(p: OsInstalled) == 3
&& next_tag(p: FabricJoined) == -1
}

test fn new_altra_plan_starts_factory_default_at_192() -> Bool {
new_altra_onboarding_plan.bmc.host == "192.168.1.192"
&& phase_tag(p: new_altra_onboarding_plan.start_phase) == 0
&& match new_altra_onboarding_plan.rotated_credential {
Stored { secret_name: s } => s == "bmc-srv3-admin"
Chained { steps: _ } => false
}
&& match new_altra_onboarding_plan.os_target {
UbuntuOs { distro: d } =>
match d {
NobleNumbat2404Lts => true
}
WindowsOs { distro: _ } => false
MacosOs { distro: _ } => false
}
&& redfish_boot_target_wire(t: new_altra_onboarding_plan.os_install_boot_target) == "Pxe"
&& redfish_boot_target_wire(t: BootTargetPxe) == "Pxe"
&& redfish_account_role_wire(role: new_altra_onboarding_plan.rotated_account_role) == "Administrator"
&& redfish_account_role_wire(role: AccountRoleAdministrator) == "Administrator"
}