talos_api_rs/resources/
bootstrap.rs1use crate::api::machine::{
9 Bootstrap as ProtoBootstrap, BootstrapRequest as ProtoRequest,
10 BootstrapResponse as ProtoResponse,
11};
12
13#[derive(Debug, Clone, Copy, Default)]
32pub struct BootstrapRequest {
33 pub recover_etcd: bool,
36 pub recover_skip_hash_check: bool,
39}
40
41impl BootstrapRequest {
42 #[must_use]
44 pub fn new() -> Self {
45 Self::default()
46 }
47
48 #[must_use]
50 pub fn builder() -> BootstrapRequestBuilder {
51 BootstrapRequestBuilder::default()
52 }
53
54 #[must_use]
58 pub fn recovery() -> Self {
59 Self {
60 recover_etcd: true,
61 recover_skip_hash_check: false,
62 }
63 }
64
65 #[must_use]
69 pub fn recovery_skip_hash() -> Self {
70 Self {
71 recover_etcd: true,
72 recover_skip_hash_check: true,
73 }
74 }
75}
76
77impl From<BootstrapRequest> for ProtoRequest {
78 fn from(req: BootstrapRequest) -> Self {
79 ProtoRequest {
80 recover_etcd: req.recover_etcd,
81 recover_skip_hash_check: req.recover_skip_hash_check,
82 }
83 }
84}
85
86#[derive(Debug, Clone, Copy, Default)]
88pub struct BootstrapRequestBuilder {
89 recover_etcd: bool,
90 recover_skip_hash_check: bool,
91}
92
93impl BootstrapRequestBuilder {
94 #[must_use]
96 pub fn recover_etcd(mut self, recover: bool) -> Self {
97 self.recover_etcd = recover;
98 self
99 }
100
101 #[must_use]
103 pub fn recover_skip_hash_check(mut self, skip: bool) -> Self {
104 self.recover_skip_hash_check = skip;
105 self
106 }
107
108 #[must_use]
110 pub fn build(self) -> BootstrapRequest {
111 BootstrapRequest {
112 recover_etcd: self.recover_etcd,
113 recover_skip_hash_check: self.recover_skip_hash_check,
114 }
115 }
116}
117
118#[derive(Debug, Clone)]
120pub struct BootstrapResult {
121 pub node: Option<String>,
123}
124
125impl From<ProtoBootstrap> for BootstrapResult {
126 fn from(proto: ProtoBootstrap) -> Self {
127 Self {
128 node: proto.metadata.map(|m| m.hostname),
129 }
130 }
131}
132
133#[derive(Debug, Clone)]
135pub struct BootstrapResponse {
136 pub results: Vec<BootstrapResult>,
138}
139
140impl From<ProtoResponse> for BootstrapResponse {
141 fn from(proto: ProtoResponse) -> Self {
142 Self {
143 results: proto.messages.into_iter().map(Into::into).collect(),
144 }
145 }
146}
147
148impl BootstrapResponse {
149 #[must_use]
151 pub fn is_success(&self) -> bool {
152 !self.results.is_empty()
153 }
154
155 #[must_use]
157 pub fn first(&self) -> Option<&BootstrapResult> {
158 self.results.first()
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_bootstrap_request_new() {
168 let request = BootstrapRequest::new();
169 assert!(!request.recover_etcd);
170 assert!(!request.recover_skip_hash_check);
171 }
172
173 #[test]
174 fn test_bootstrap_request_recovery() {
175 let request = BootstrapRequest::recovery();
176 assert!(request.recover_etcd);
177 assert!(!request.recover_skip_hash_check);
178 }
179
180 #[test]
181 fn test_bootstrap_request_recovery_skip_hash() {
182 let request = BootstrapRequest::recovery_skip_hash();
183 assert!(request.recover_etcd);
184 assert!(request.recover_skip_hash_check);
185 }
186
187 #[test]
188 fn test_bootstrap_request_builder() {
189 let request = BootstrapRequest::builder()
190 .recover_etcd(true)
191 .recover_skip_hash_check(true)
192 .build();
193
194 assert!(request.recover_etcd);
195 assert!(request.recover_skip_hash_check);
196 }
197
198 #[test]
199 fn test_proto_conversion() {
200 let request = BootstrapRequest::builder()
201 .recover_etcd(true)
202 .recover_skip_hash_check(false)
203 .build();
204
205 let proto: ProtoRequest = request.into();
206 assert!(proto.recover_etcd);
207 assert!(!proto.recover_skip_hash_check);
208 }
209
210 #[test]
211 fn test_bootstrap_response_is_success() {
212 let response = BootstrapResponse {
213 results: vec![BootstrapResult {
214 node: Some("controlplane-1".to_string()),
215 }],
216 };
217 assert!(response.is_success());
218
219 let empty_response = BootstrapResponse { results: vec![] };
220 assert!(!empty_response.is_success());
221 }
222}