Skip to content
Merged
12 changes: 12 additions & 0 deletions dag/gunbc/host_effect.dag
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ type HostEffect =
ShellCommand { script: String }
| RedfishAction { action: RedfishSystemAction }
| ConvergePlan { policy: HostConverge }
| Srv3InstallReconcileObserve { include_git_meta: Bool }
| DurableApprovalGrantRecord
| DurableApprovalGrantRead
| Srv3InstallMediaFetch
| Srv3SeededInstallMediaRemaster
| Srv3SeededInstallMediaToolchainEnsure
| Srv3SolConsoleCapture
| Srv3BmcwebSessionLogin
| Srv3BmcwebTokenExtract
| Srv3NbdProxyServe
| Srv3BootOnceReadBackSleep
| Srv3ReceiptEmit { lines: List<String> }

type NodeControlPlane =
HostOs { node: ComputeHost }
Expand Down
80 changes: 65 additions & 15 deletions dag/gunbc/host_effect_realize.dag
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ module gunbc.host_effect_realize

import gunbc.host_effect {
HostEffect, ShellCommand, RedfishAction, ConvergePlan,
Srv3InstallReconcileObserve,
DurableApprovalGrantRecord,
DurableApprovalGrantRead,
Srv3InstallMediaFetch,
Srv3SeededInstallMediaRemaster,
Srv3SeededInstallMediaToolchainEnsure,
Srv3SolConsoleCapture,
Srv3BmcwebSessionLogin,
Srv3BmcwebTokenExtract,
Srv3NbdProxyServe,
Srv3BootOnceReadBackSleep,
Srv3ReceiptEmit,
NodeControlPlane, HostOs, BmcController,
Drive, OneShot, ConvergeLoop,
HostEffectIntent, HostEffectEvidence, ShellEffectApplied, ConvergePlanApplied,
Expand Down Expand Up @@ -32,6 +44,7 @@ import gunbc.ci_deploy_access {
deploy_access_check, deploy_access_check_observed,
deploy_access_decision_reason,
}
import gunbc.srv3_host_effect_script { srv3_host_effect_script_for }
import std.types { String, NonEmptyStr, List }

type ResolvedHostEffectCell =
Expand All @@ -50,27 +63,64 @@ fn converge_plan_identity_mismatch_reason(node: ComputeHost, policy: HostConverg
)
}

fn srv3_host_effect_script_resolution_failed_cell() -> ResolvedHostEffectCell {
IncompatibleCell { reason: "host_effect: srv3 typed effect script resolution failed; fail-closed" }
}

fn resolve_host_effect_cell(target: NodeControlPlane, effect: HostEffect) -> ResolvedHostEffectCell {
match target {
HostOs { node: n } =>
match effect {
ShellCommand { script: s } => ShellOnHost { node: n, script: s }
RedfishAction { action: _ } =>
IncompatibleCell { reason: "host_effect: RedfishAction is out-of-band (Redfish) and cannot target HostOs (in-band shell/systemd); target BmcController instead. Typed mismatch via total fold, DESIGN section 5." }
ConvergePlan { policy: p } =>
if n.identity != p.identity {
IncompatibleCell { reason: converge_plan_identity_mismatch_reason(node: n, policy: p) }
} else {
ConvergeOnHost { node: n, host_converge: p }
match srv3_host_effect_script_for(effect: effect) {
Present { value: script } => ShellOnHost { node: n, script: script }
Absent =>
match effect {
ShellCommand { script: s } => ShellOnHost { node: n, script: s }
RedfishAction { action: _ } =>
IncompatibleCell { reason: "host_effect: RedfishAction is out-of-band (Redfish) and cannot target HostOs (in-band shell/systemd); target BmcController instead. Typed mismatch via total fold, DESIGN section 5." }
ConvergePlan { policy: p } =>
if n.identity != p.identity {
IncompatibleCell { reason: converge_plan_identity_mismatch_reason(node: n, policy: p) }
} else {
ConvergeOnHost { node: n, host_converge: p }
}
Srv3InstallReconcileObserve { include_git_meta: _ } => srv3_host_effect_script_resolution_failed_cell()
DurableApprovalGrantRecord => srv3_host_effect_script_resolution_failed_cell()
DurableApprovalGrantRead => srv3_host_effect_script_resolution_failed_cell()
Srv3InstallMediaFetch => srv3_host_effect_script_resolution_failed_cell()
Srv3SeededInstallMediaRemaster => srv3_host_effect_script_resolution_failed_cell()
Srv3SeededInstallMediaToolchainEnsure => srv3_host_effect_script_resolution_failed_cell()
Srv3SolConsoleCapture => srv3_host_effect_script_resolution_failed_cell()
Srv3BmcwebSessionLogin => srv3_host_effect_script_resolution_failed_cell()
Srv3BmcwebTokenExtract => srv3_host_effect_script_resolution_failed_cell()
Srv3NbdProxyServe => srv3_host_effect_script_resolution_failed_cell()
Srv3BootOnceReadBackSleep => srv3_host_effect_script_resolution_failed_cell()
Srv3ReceiptEmit { lines: _ } => srv3_host_effect_script_resolution_failed_cell()
}
}
BmcController { node: n } =>
match effect {
ShellCommand { script: _ } =>
IncompatibleCell { reason: "host_effect: ShellCommand is in-band (shell/systemd) and cannot target BmcController (out-of-band Redfish only); target HostOs instead. Typed mismatch via total fold, DESIGN section 5." }
RedfishAction { action: a } => RedfishOnBmc { node: n, action: a }
ConvergePlan { policy: _ } =>
IncompatibleCell { reason: "host_effect: ConvergePlan is in-band (host OS converge) and cannot target BmcController (out-of-band Redfish only); target HostOs instead. Typed mismatch via total fold, DESIGN section 5." }
match srv3_host_effect_script_for(effect: effect) {
Present { value: _ } =>
IncompatibleCell { reason: "host_effect: srv3 shell effects are in-band (actuator host LocalShell) and cannot target BmcController (out-of-band Redfish only); target HostOs instead. Typed mismatch via total fold, DESIGN section 5." }
Absent =>
match effect {
ShellCommand { script: _ } =>
IncompatibleCell { reason: "host_effect: ShellCommand is in-band (shell/systemd) and cannot target BmcController (out-of-band Redfish only); target HostOs instead. Typed mismatch via total fold, DESIGN section 5." }
RedfishAction { action: a } => RedfishOnBmc { node: n, action: a }
ConvergePlan { policy: _ } =>
IncompatibleCell { reason: "host_effect: ConvergePlan is in-band (host OS converge) and cannot target BmcController (out-of-band Redfish only); target HostOs instead. Typed mismatch via total fold, DESIGN section 5." }
Srv3InstallReconcileObserve { include_git_meta: _ } => srv3_host_effect_script_resolution_failed_cell()
DurableApprovalGrantRecord => srv3_host_effect_script_resolution_failed_cell()
DurableApprovalGrantRead => srv3_host_effect_script_resolution_failed_cell()
Srv3InstallMediaFetch => srv3_host_effect_script_resolution_failed_cell()
Srv3SeededInstallMediaRemaster => srv3_host_effect_script_resolution_failed_cell()
Srv3SeededInstallMediaToolchainEnsure => srv3_host_effect_script_resolution_failed_cell()
Srv3SolConsoleCapture => srv3_host_effect_script_resolution_failed_cell()
Srv3BmcwebSessionLogin => srv3_host_effect_script_resolution_failed_cell()
Srv3BmcwebTokenExtract => srv3_host_effect_script_resolution_failed_cell()
Srv3NbdProxyServe => srv3_host_effect_script_resolution_failed_cell()
Srv3BootOnceReadBackSleep => srv3_host_effect_script_resolution_failed_cell()
Srv3ReceiptEmit { lines: _ } => srv3_host_effect_script_resolution_failed_cell()
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions dag/gunbc/srv3_actuate_shell_paths.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module gunbc.srv3_actuate_shell_paths

import std.types { String, NonEmptyStr }

data srv3_bmcweb_login_body_path: String = "/tmp/srv3_bmcweb_login_body.json"
data srv3_bmcweb_login_response_path: String = "/tmp/srv3_bmcweb_login_response.json"
data srv3_bmcweb_token_path: String = "/tmp/srv3_bmcweb_token"
data srv3_nbd_proxy_serve_script_path: String = "/tmp/srv3_nbd_proxy_serve.sh"
data srv3_sol_console_log_path: NonEmptyStr = "/var/lib/gunbc/logs/srv3-install-sol-console.log" as NonEmptyStr
172 changes: 172 additions & 0 deletions dag/gunbc/srv3_host_effect_apply.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
module gunbc.srv3_host_effect_apply

import gunbc.host_effect {
HostEffect,
NodeControlPlane,
HostOs,
HostEffectIntent,
HostEffectEvidence,
ShellEffectApplied,
ConvergePlanApplied,
Srv3InstallReconcileObserve,
DurableApprovalGrantRecord,
DurableApprovalGrantRead,
Srv3InstallMediaFetch,
Srv3SeededInstallMediaRemaster,
Srv3SeededInstallMediaToolchainEnsure,
Srv3SolConsoleCapture,
Srv3BmcwebSessionLogin,
Srv3BmcwebTokenExtract,
Srv3NbdProxyServe,
Srv3BootOnceReadBackSleep,
Srv3ReceiptEmit,
host_effect_read_evidence,
host_effect_identity_evidence,
LocalShell,
}
import gunbc.host_effect_realize { host_effect_apply }
import gunbc.os_install_actuator_selection { srv3_os_install_actuator_host }
import std.realization_reconcile {
Reconciliation,
Converged,
NotConverged,
reconciliation_converged,
}
import std.process { ProcessExit, ExitSuccess, exit_failure }
import std.types { String, List, Bool }

type Srv3TypedReceipt {
lines: List<String>
}

fn srv3_actuator_target() -> NodeControlPlane {
HostOs { node: srv3_os_install_actuator_host }
}

fn srv3_host_effect_apply(
effect: HostEffect,
) -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
host_effect_apply(
target: srv3_actuator_target(),
effect: effect,
evidence: host_effect_identity_evidence,
transport: LocalShell,
)
}

fn srv3_host_effect_observe_apply(
include_git_meta: Bool,
) -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(
effect: Srv3InstallReconcileObserve { include_git_meta: include_git_meta },
)
}

fn srv3_host_effect_observe_read_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
host_effect_apply(
target: srv3_actuator_target(),
effect: Srv3InstallReconcileObserve { include_git_meta: true },
evidence: host_effect_read_evidence,
transport: LocalShell,
)
}

fn srv3_durable_approval_grant_record_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: DurableApprovalGrantRecord)
}

fn srv3_durable_approval_grant_read_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
host_effect_apply(
target: srv3_actuator_target(),
effect: DurableApprovalGrantRead,
evidence: host_effect_read_evidence,
transport: LocalShell,
)
}

fn srv3_install_media_fetch_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3InstallMediaFetch)
}

fn srv3_seeded_install_media_toolchain_ensure_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3SeededInstallMediaToolchainEnsure)
}

fn srv3_seeded_install_media_remaster_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3SeededInstallMediaRemaster)
}

fn srv3_sol_console_capture_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3SolConsoleCapture)
}

fn srv3_bmcweb_session_login_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3BmcwebSessionLogin)
}

fn srv3_bmcweb_token_extract_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3BmcwebTokenExtract)
}

fn srv3_nbd_proxy_serve_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3NbdProxyServe)
}

fn srv3_boot_once_read_back_sleep_apply() -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3BootOnceReadBackSleep)
}

fn srv3_typed_receipt(receipt: Srv3TypedReceipt) -> Srv3TypedReceipt {
receipt
}

fn srv3_typed_receipt_from_lines(lines: List<String>) -> Srv3TypedReceipt {
Srv3TypedReceipt { lines: lines }
}

fn srv3_receipt_emit_apply(receipt: Srv3TypedReceipt) -> Reconciliation<HostEffectIntent, HostEffectEvidence> {
srv3_host_effect_apply(effect: Srv3ReceiptEmit { lines: receipt.lines })
}

fn srv3_shell_stdout_from_apply(
r: Reconciliation<HostEffectIntent, HostEffectEvidence>,
) -> String? {
match r {
Converged { evidence: e, applied: _ } =>
match e {
ShellEffectApplied { stdout: out, exit_code: _ } => Present { value: out }
ConvergePlanApplied { stdout: _, exit_code: _ } => none
}
NotConverged { reason: _, applied: _ } => none
}
}

fn srv3_reconciliation_failure_reason(
r: Reconciliation<HostEffectIntent, HostEffectEvidence>,
) -> String? {
match r {
Converged { evidence: _, applied: _ } => none
NotConverged { reason: why, applied: _ } => Present { value: why }
}
}

fn srv3_reconciliation_to_process_exit(
r: Reconciliation<HostEffectIntent, HostEffectEvidence>,
failure_prefix: String,
) -> ProcessExit {
if reconciliation_converged(r: r) {
ExitSuccess
} else {
match srv3_reconciliation_failure_reason(r: r) {
Present { value: why } => exit_failure(reason: concat(failure_prefix, why))
Absent => exit_failure(reason: concat(failure_prefix, "host_effect_apply failed"))
}
}
}

fn srv3_emit_typed_receipt(receipt: Srv3TypedReceipt) -> ProcessExit {
srv3_reconciliation_to_process_exit(
r: srv3_receipt_emit_apply(receipt: receipt),
failure_prefix: "srv3-receipt-emit: ",
)
}
Loading
Loading