pre_serve.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. //! Types for the `before_serve` configuration and `exec_aliases` table.
  2. //!
  3. //! Lives outside `config.rs` so the latter stays under the 500-line limit
  4. //! the project enforces (see AGENTS.md).
  5. use serde::Deserialize;
  6. /// Behaviour on a non-zero exit code for a [`PreServeCommand`].
  7. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Deserialize)]
  8. #[serde(rename_all = "lowercase")]
  9. pub enum OnFailure {
  10. #[default]
  11. Abort,
  12. Warn,
  13. Continue,
  14. }
  15. /// One entry in a `before_serve` / `after_stop` / `mods` block.
  16. ///
  17. /// Three mutually exclusive forms (untagged, so TOML picks by shape):
  18. /// - `Bare(String)` — a raw shell command, run as-is over SSH.
  19. /// - `Configured { command, on_failure }` — a raw shell command with an
  20. /// explicit `on_failure` policy.
  21. /// - `Script { script, on_failure }` — a built-in script referenced by
  22. /// alias (e.g. `stop_dgx_services`). The script body is baked into the
  23. /// binary at compile time (see [`crate::builtin_scripts`]) and uploaded
  24. /// + run via SSH on each node — no file copy from the operator's machine.
  25. ///
  26. /// Unknown aliases error at resolution time with the list of known ones.
  27. #[derive(Clone, Debug, Deserialize)]
  28. #[serde(untagged)]
  29. pub enum PreServeCommand {
  30. Bare(String),
  31. Configured {
  32. command: String,
  33. #[serde(default)]
  34. on_failure: OnFailure,
  35. },
  36. Script {
  37. script: String,
  38. #[serde(default)]
  39. on_failure: OnFailure,
  40. },
  41. }
  42. impl PreServeCommand {
  43. /// For `Bare`/`Configured`, the raw shell command. For `Script`, the
  44. /// alias (NOT the script body) — use [`resolve`] to get the body.
  45. pub fn command(&self) -> &str {
  46. match self {
  47. PreServeCommand::Bare(c) => c,
  48. PreServeCommand::Configured { command, .. } => command,
  49. PreServeCommand::Script { script, .. } => script,
  50. }
  51. }
  52. pub fn on_failure(&self) -> OnFailure {
  53. match self {
  54. PreServeCommand::Bare(_) => OnFailure::default(),
  55. PreServeCommand::Configured { on_failure, .. } => *on_failure,
  56. PreServeCommand::Script { on_failure, .. } => *on_failure,
  57. }
  58. }
  59. }
  60. #[derive(Clone, Debug, Default, Deserialize)]
  61. pub struct BeforeServeTable {
  62. #[serde(default)]
  63. pub commands: Vec<PreServeCommand>,
  64. }
  65. #[derive(Clone, Debug, Default, Deserialize)]
  66. pub struct ModsTable {
  67. #[serde(default)]
  68. pub commands: Vec<PreServeCommand>,
  69. }
  70. /// Distributed execution backend — `mp` or `ray`. Absent means single-node.
  71. #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
  72. #[serde(rename_all = "lowercase")]
  73. pub enum DistributedBackend {
  74. Mp,
  75. Ray,
  76. }
  77. /// Recipe arguments — either an inline TOML string (split by whitespace) or
  78. /// a `Vec<String>` list. Accepted in TOML as either:
  79. ///
  80. /// ```toml
  81. /// args = """
  82. /// --gpu-memory-utilization 0.90
  83. /// --max-model-len 262144
  84. /// """
  85. /// ```
  86. ///
  87. /// ```toml
  88. /// args = ["--gpu-memory-utilization", "0.90"]
  89. /// ```
  90. #[derive(Clone, Debug, Deserialize)]
  91. #[serde(untagged)]
  92. pub enum RecipeArgs {
  93. List(Vec<String>),
  94. Inline(String),
  95. }
  96. impl Default for RecipeArgs {
  97. fn default() -> Self {
  98. RecipeArgs::List(Vec::new())
  99. }
  100. }
  101. impl RecipeArgs {
  102. pub fn to_vec(&self) -> Vec<String> {
  103. match self {
  104. RecipeArgs::Inline(s) => s.split_whitespace().map(String::from).collect(),
  105. RecipeArgs::List(v) => v.clone(),
  106. }
  107. }
  108. /// Replace all occurrences of `placeholder` with `replacement` in each
  109. /// arg string. Used to substitute model path references (e.g.
  110. /// `{{mtp_draft}}`) with resolved HF cache paths per-node.
  111. pub fn substitute(&self, placeholder: &str, replacement: &str) -> RecipeArgs {
  112. match self {
  113. RecipeArgs::Inline(s) => RecipeArgs::Inline(s.replace(placeholder, replacement)),
  114. RecipeArgs::List(v) => RecipeArgs::List(
  115. v.iter()
  116. .map(|a| a.replace(placeholder, replacement))
  117. .collect(),
  118. ),
  119. }
  120. }
  121. }
  122. impl std::fmt::Display for DistributedBackend {
  123. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  124. match self {
  125. DistributedBackend::Mp => write!(f, "mp"),
  126. DistributedBackend::Ray => write!(f, "ray"),
  127. }
  128. }
  129. }