scl_lib/api_objects/
controller.rs1use crate::api_objects::{Error, MetaData, SclName, SclObject, TransitionError};
3use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "openapi")]
6use schemars::JsonSchema;
7
8#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
9#[cfg_attr(feature = "openapi", derive(JsonSchema))]
10#[serde(rename_all = "camelCase")]
11pub struct Controller {
12 #[serde(flatten)]
13 pub metadata: MetaData,
14 pub kind: ControllerKind,
15 #[serde(default)]
18 pub status: ControllerStatus,
19}
20
21impl Controller {
22 pub fn new(name: SclName, kind: ControllerKind) -> Self {
23 Controller {
24 metadata: MetaData::new(name),
25 kind,
26 status: ControllerStatus::default(),
27 }
28 }
29
30 pub fn update_last_interaction(&mut self) {
31 self.status.last_interaction = std::time::SystemTime::now()
32 .duration_since(std::time::UNIX_EPOCH)
33 .unwrap()
34 .as_secs()
35 .to_string();
36 }
37}
38
39impl SclObject for Controller {
40 const PREFIX: &'static str = "/controllers";
42
43 fn name(&self) -> &SclName {
44 &self.metadata.name
45 }
46
47 fn api_endpoint<'a>(
61 _sc: impl Into<Option<&'a str>>,
62 name: impl Into<Option<&'a str>>,
63 ) -> String {
64 if let Some(name) = name.into() {
65 format!("{}/{}", Self::PREFIX, name)
66 } else {
67 Self::PREFIX.into()
68 }
69 }
70
71 fn db_key<'a>(_sc: impl Into<Option<&'a str>>, name: impl Into<Option<&'a str>>) -> String {
85 if let Some(name) = name.into() {
86 format!("{}/{}", Self::PREFIX, name)
87 } else {
88 Self::PREFIX.into()
89 }
90 }
91
92 fn metadata(&self) -> &MetaData {
93 &self.metadata
94 }
95
96 fn metadata_mut(&mut self) -> &mut MetaData {
97 &mut self.metadata
98 }
99
100 fn referenced_db_keys(&self) -> Vec<String> {
101 vec![]
102 }
103
104 fn validate_fields_before_create(&self) -> Result<(), Error> {
105 self.metadata.validate_fields_before_create()
106 }
107
108 fn validate_fields_before_update(
109 current_db_state: &Self,
110 proposed_new_state: &Self,
111 ) -> Result<(), Error> {
112 MetaData::validate_fields_before_regular_update(
113 ¤t_db_state.metadata,
114 &proposed_new_state.metadata,
115 )?;
116
117 if current_db_state.kind != proposed_new_state.kind {
118 Err(TransitionError::Other("Field kind may not be changed!".to_string()).into())
119 } else {
120 Ok(())
121 }
122 }
123}
124
125#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
126#[cfg_attr(feature = "openapi", derive(JsonSchema))]
127#[serde(rename_all = "camelCase")]
128pub enum ControllerKind {
129 SchedulerController,
130 StorageController,
131 NetworkController,
132 VmController,
133}
134
135#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
136#[cfg_attr(feature = "openapi", derive(JsonSchema))]
137#[serde(rename_all = "camelCase")]
138pub struct ControllerStatus {
139 pub last_interaction: String, alive: bool,
141}
142
143#[cfg(test)]
144mod test {
145 use super::Controller;
146 use crate::api_objects::test::{
147 detect_invalid_metadata_create_mutations, detect_invalid_metadata_update_mutations,
148 parse_json_dir,
149 };
150 use crate::api_objects::{ControllerKind, ControllerStatus, MetaData, SclName, SclObject};
151 use std::path::Path;
152
153 #[test]
154 fn parse_sample_json() {
155 parse_json_dir::<Controller>(Path::new("../test/sample_json/controllers"));
156 }
157
158 fn example_controller() -> Controller {
159 Controller {
160 metadata: MetaData::new(SclName::try_from("example").unwrap()),
161 kind: ControllerKind::SchedulerController,
162 status: ControllerStatus {
163 last_interaction: "Never".to_string(),
164 alive: false,
165 },
166 }
167 }
168
169 #[test]
170 fn validate_fields_before_update() {
171 let current = example_controller();
172 let mut proposed = current.clone();
173 assert!(Controller::validate_fields_before_update(¤t, &proposed).is_ok());
174 proposed.kind = ControllerKind::NetworkController;
175 assert!(Controller::validate_fields_before_update(¤t, &proposed).is_err());
176 }
177
178 #[test]
179 fn detect_invalid_metadata_mutations() {
180 let t = example_controller();
181 detect_invalid_metadata_create_mutations(&t);
182 detect_invalid_metadata_update_mutations(&t);
183 }
184}