1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub struct ServerId(String);
12
13impl ServerId {
14 pub fn new(id: String) -> Self {
15 Self(id)
16 }
17
18 pub fn as_str(&self) -> &str {
19 &self.0
20 }
21}
22
23impl fmt::Display for ServerId {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "{}", self.0)
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31pub enum ServerType {
32 Master,
33 Worker,
34 Database,
35}
36
37impl fmt::Display for ServerType {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 ServerType::Master => write!(f, "master"),
41 ServerType::Worker => write!(f, "worker"),
42 ServerType::Database => write!(f, "database"),
43 }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub enum ServerStatus {
50 Running,
51 Stopped,
52 Starting,
53 Stopping,
54 Unknown,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ServerSpec {
60 name: String,
61 server_type: ServerType,
62 size: String,
63 location: String,
64 image: String,
65 ssh_keys: Vec<String>,
66 labels: Vec<(String, String)>,
67 attach_to_network: Option<String>, }
69
70impl ServerSpec {
71 pub fn new(
72 name: String,
73 server_type: ServerType,
74 size: String,
75 location: String,
76 image: String,
77 ) -> Self {
78 Self {
79 name,
80 server_type,
81 size,
82 location,
83 image,
84 ssh_keys: Vec::new(),
85 labels: Vec::new(),
86 attach_to_network: None,
87 }
88 }
89
90 pub fn with_ssh_keys(mut self, ssh_keys: Vec<String>) -> Self {
91 self.ssh_keys = ssh_keys;
92 self
93 }
94
95 pub fn with_labels(mut self, labels: Vec<(String, String)>) -> Self {
96 self.labels = labels;
97 self
98 }
99
100 pub fn with_network(mut self, network_name: String) -> Self {
101 self.attach_to_network = Some(network_name);
102 self
103 }
104
105 pub fn name(&self) -> &str {
106 &self.name
107 }
108
109 pub fn server_type(&self) -> &ServerType {
110 &self.server_type
111 }
112
113 pub fn size(&self) -> &str {
114 &self.size
115 }
116
117 pub fn location(&self) -> &str {
118 &self.location
119 }
120
121 pub fn image(&self) -> &str {
122 &self.image
123 }
124
125 pub fn ssh_keys(&self) -> &[String] {
126 &self.ssh_keys
127 }
128
129 pub fn labels(&self) -> &[(String, String)] {
130 &self.labels
131 }
132
133 pub fn network(&self) -> Option<&str> {
134 self.attach_to_network.as_deref()
135 }
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct Server {
141 id: ServerId,
142 spec: ServerSpec,
143 status: ServerStatus,
144 public_ipv4: Option<String>,
145 private_ipv4: Option<String>,
146}
147
148impl Server {
149 pub fn new(id: ServerId, spec: ServerSpec, status: ServerStatus) -> Self {
150 Self {
151 id,
152 spec,
153 status,
154 public_ipv4: None,
155 private_ipv4: None,
156 }
157 }
158
159 pub fn with_public_ipv4(mut self, ip: String) -> Self {
160 self.public_ipv4 = Some(ip);
161 self
162 }
163
164 pub fn with_private_ipv4(mut self, ip: String) -> Self {
165 self.private_ipv4 = Some(ip);
166 self
167 }
168
169 pub fn id(&self) -> &ServerId {
170 &self.id
171 }
172
173 pub fn spec(&self) -> &ServerSpec {
174 &self.spec
175 }
176
177 pub fn status(&self) -> &ServerStatus {
178 &self.status
179 }
180
181 pub fn public_ipv4(&self) -> Option<&str> {
182 self.public_ipv4.as_deref()
183 }
184
185 pub fn private_ipv4(&self) -> Option<&str> {
186 self.private_ipv4.as_deref()
187 }
188
189 pub fn name(&self) -> &str {
190 self.spec.name()
191 }
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
196pub struct NetworkId(String);
197
198impl NetworkId {
199 pub fn new(id: String) -> Self {
200 Self(id)
201 }
202
203 pub fn as_str(&self) -> &str {
204 &self.0
205 }
206}
207
208impl fmt::Display for NetworkId {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 write!(f, "{}", self.0)
211 }
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct SubnetSpec {
217 pub network_zone: String,
218 pub ip_range: String,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct NetworkSpec {
224 name: String,
225 ip_range: String,
226 subnets: Vec<SubnetSpec>,
227}
228
229impl NetworkSpec {
230 pub fn new(name: String, ip_range: String) -> Self {
231 Self {
232 name,
233 ip_range,
234 subnets: Vec::new(),
235 }
236 }
237
238 pub fn with_subnets(mut self, subnets: Vec<SubnetSpec>) -> Self {
239 self.subnets = subnets;
240 self
241 }
242
243 pub fn name(&self) -> &str {
244 &self.name
245 }
246
247 pub fn ip_range(&self) -> &str {
248 &self.ip_range
249 }
250
251 pub fn subnets(&self) -> &[SubnetSpec] {
252 &self.subnets
253 }
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct Network {
259 id: NetworkId,
260 spec: NetworkSpec,
261}
262
263impl Network {
264 pub fn new(id: NetworkId, spec: NetworkSpec) -> Self {
265 Self { id, spec }
266 }
267
268 pub fn id(&self) -> &NetworkId {
269 &self.id
270 }
271
272 pub fn spec(&self) -> &NetworkSpec {
273 &self.spec
274 }
275
276 pub fn name(&self) -> &str {
277 self.spec.name()
278 }
279}
280
281#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
283pub struct FirewallId(String);
284
285impl FirewallId {
286 pub fn new(id: String) -> Self {
287 Self(id)
288 }
289
290 pub fn as_str(&self) -> &str {
291 &self.0
292 }
293}
294
295impl fmt::Display for FirewallId {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 write!(f, "{}", self.0)
298 }
299}
300
301#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
303pub struct FirewallRule {
304 pub direction: String,
305 pub source_ips: Vec<String>,
306 pub destination_ips: Vec<String>,
307 pub protocol: String,
308 pub port: Option<String>,
309 pub description: Option<String>,
310}
311
312impl FirewallRule {
313 pub fn new(direction: String, protocol: String) -> Self {
314 Self {
315 direction,
316 source_ips: Vec::new(),
317 destination_ips: Vec::new(),
318 protocol,
319 port: None,
320 description: None,
321 }
322 }
323
324 pub fn with_source_ips(mut self, ips: Vec<String>) -> Self {
325 self.source_ips = ips;
326 self
327 }
328
329 pub fn with_port(mut self, port: String) -> Self {
330 self.port = Some(port);
331 self
332 }
333
334 pub fn with_description(mut self, desc: String) -> Self {
335 self.description = Some(desc);
336 self
337 }
338}
339
340#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct FirewallSpec {
343 name: String,
344 rules: Vec<FirewallRule>,
345 apply_to: Vec<String>,
346}
347
348impl FirewallSpec {
349 pub fn new(name: String) -> Self {
350 Self {
351 name,
352 rules: Vec::new(),
353 apply_to: Vec::new(),
354 }
355 }
356
357 pub fn with_rules(mut self, rules: Vec<FirewallRule>) -> Self {
358 self.rules = rules;
359 self
360 }
361
362 pub fn with_apply_to(mut self, apply_to: Vec<String>) -> Self {
363 self.apply_to = apply_to;
364 self
365 }
366
367 pub fn name(&self) -> &str {
368 &self.name
369 }
370
371 pub fn rules(&self) -> &[FirewallRule] {
372 &self.rules
373 }
374
375 pub fn apply_to(&self) -> &[String] {
376 &self.apply_to
377 }
378}
379
380#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct Firewall {
383 id: FirewallId,
384 spec: FirewallSpec,
385}
386
387impl Firewall {
388 pub fn new(id: FirewallId, spec: FirewallSpec) -> Self {
389 Self { id, spec }
390 }
391
392 pub fn id(&self) -> &FirewallId {
393 &self.id
394 }
395
396 pub fn spec(&self) -> &FirewallSpec {
397 &self.spec
398 }
399
400 pub fn name(&self) -> &str {
401 self.spec.name()
402 }
403}
404
405#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
407pub struct LoadBalancerId(String);
408
409impl LoadBalancerId {
410 pub fn new(id: String) -> Self {
411 Self(id)
412 }
413
414 pub fn as_str(&self) -> &str {
415 &self.0
416 }
417}
418
419impl fmt::Display for LoadBalancerId {
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 write!(f, "{}", self.0)
422 }
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize)]
427pub struct LoadBalancerSpec {
428 name: String,
429 load_balancer_type: String,
430 location: String,
431 algorithm: String,
432}
433
434impl LoadBalancerSpec {
435 pub fn new(name: String, load_balancer_type: String, location: String) -> Self {
436 Self {
437 name,
438 load_balancer_type,
439 location,
440 algorithm: "round_robin".to_string(),
441 }
442 }
443
444 pub fn with_algorithm(mut self, algorithm: String) -> Self {
445 self.algorithm = algorithm;
446 self
447 }
448
449 pub fn name(&self) -> &str {
450 &self.name
451 }
452
453 pub fn load_balancer_type(&self) -> &str {
454 &self.load_balancer_type
455 }
456
457 pub fn location(&self) -> &str {
458 &self.location
459 }
460
461 pub fn algorithm(&self) -> &str {
462 &self.algorithm
463 }
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct LoadBalancer {
469 id: LoadBalancerId,
470 spec: LoadBalancerSpec,
471 public_ipv4: Option<String>,
472}
473
474impl LoadBalancer {
475 pub fn new(id: LoadBalancerId, spec: LoadBalancerSpec) -> Self {
476 Self {
477 id,
478 spec,
479 public_ipv4: None,
480 }
481 }
482
483 pub fn with_public_ipv4(mut self, ip: String) -> Self {
484 self.public_ipv4 = Some(ip);
485 self
486 }
487
488 pub fn id(&self) -> &LoadBalancerId {
489 &self.id
490 }
491
492 pub fn spec(&self) -> &LoadBalancerSpec {
493 &self.spec
494 }
495
496 pub fn public_ipv4(&self) -> Option<&str> {
497 self.public_ipv4.as_deref()
498 }
499
500 pub fn name(&self) -> &str {
501 self.spec.name()
502 }
503}
504
505#[derive(Debug, Clone)]
507pub struct InfrastructureSpec {
508 pub network: NetworkSpec,
509 pub firewall: FirewallSpec,
510 pub loadbalancer: LoadBalancerSpec,
511 pub servers: Vec<ServerSpec>,
512}
513
514impl InfrastructureSpec {
515 pub fn new(
516 network: NetworkSpec,
517 firewall: FirewallSpec,
518 loadbalancer: LoadBalancerSpec,
519 servers: Vec<ServerSpec>,
520 ) -> Self {
521 Self {
522 network,
523 firewall,
524 loadbalancer,
525 servers,
526 }
527 }
528
529 pub fn network(&self) -> &NetworkSpec {
530 &self.network
531 }
532
533 pub fn firewall(&self) -> &FirewallSpec {
534 &self.firewall
535 }
536
537 pub fn loadbalancer(&self) -> &LoadBalancerSpec {
538 &self.loadbalancer
539 }
540
541 pub fn servers(&self) -> &[ServerSpec] {
542 &self.servers
543 }
544}
545
546#[derive(Debug, Clone, PartialEq, Eq)]
548pub enum DiffType {
549 Create,
550 Update,
551 Delete,
552 NoChange,
553}
554
555#[derive(Debug, Clone)]
557pub struct DiffItem {
558 resource_type: String,
559 resource_name: String,
560 diff_type: DiffType,
561 details: Vec<String>,
562}
563
564impl DiffItem {
565 pub fn new(resource_type: String, resource_name: String, diff_type: DiffType) -> Self {
566 Self {
567 resource_type,
568 resource_name,
569 diff_type,
570 details: Vec::new(),
571 }
572 }
573
574 pub fn with_details(mut self, details: Vec<String>) -> Self {
575 self.details = details;
576 self
577 }
578
579 pub fn resource_type(&self) -> &str {
580 &self.resource_type
581 }
582
583 pub fn resource_name(&self) -> &str {
584 &self.resource_name
585 }
586
587 pub fn diff_type(&self) -> &DiffType {
588 &self.diff_type
589 }
590
591 pub fn details(&self) -> &[String] {
592 &self.details
593 }
594}
595
596#[derive(Debug, Clone)]
598pub struct InfrastructureDiff {
599 items: Vec<DiffItem>,
600}
601
602impl InfrastructureDiff {
603 pub fn new(items: Vec<DiffItem>) -> Self {
604 Self { items }
605 }
606
607 pub fn items(&self) -> &[DiffItem] {
608 &self.items
609 }
610
611 pub fn has_changes(&self) -> bool {
612 self.items
613 .iter()
614 .any(|item| item.diff_type != DiffType::NoChange)
615 }
616
617 pub fn creates(&self) -> Vec<&DiffItem> {
618 self.items
619 .iter()
620 .filter(|item| item.diff_type == DiffType::Create)
621 .collect()
622 }
623
624 pub fn updates(&self) -> Vec<&DiffItem> {
625 self.items
626 .iter()
627 .filter(|item| item.diff_type == DiffType::Update)
628 .collect()
629 }
630
631 pub fn deletes(&self) -> Vec<&DiffItem> {
632 self.items
633 .iter()
634 .filter(|item| item.diff_type == DiffType::Delete)
635 .collect()
636 }
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize)]
641pub struct InfrastructureState {
642 pub servers: Vec<Server>,
643 pub networks: Vec<Network>,
644 pub firewalls: Vec<Firewall>,
645 pub load_balancers: Vec<LoadBalancer>,
646}
647
648impl InfrastructureState {
649 pub fn new() -> Self {
650 Self {
651 servers: Vec::new(),
652 networks: Vec::new(),
653 firewalls: Vec::new(),
654 load_balancers: Vec::new(),
655 }
656 }
657
658 pub fn is_empty(&self) -> bool {
659 self.servers.is_empty()
660 && self.networks.is_empty()
661 && self.firewalls.is_empty()
662 && self.load_balancers.is_empty()
663 }
664}
665
666impl Default for InfrastructureState {
667 fn default() -> Self {
668 Self::new()
669 }
670}